123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- /* sleep.S: power saving mode entry
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Woodhouse (dwmw2@infradead.org)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
- #include <linux/sys.h>
- #include <linux/linkage.h>
- #include <asm/setup.h>
- #include <asm/segment.h>
- #include <asm/page.h>
- #include <asm/ptrace.h>
- #include <asm/errno.h>
- #include <asm/cache.h>
- #include <asm/spr-regs.h>
- #define __addr_MASK 0xfeff9820 /* interrupt controller mask */
- #define __addr_FR55X_DRCN 0xfeff0218 /* Address of DRCN register */
- #define FR55X_DSTS_OFFSET -4 /* Offset from DRCN to DSTS */
- #define FR55X_SDRAMC_DSTS_SSI 0x00000002 /* indicates that the SDRAM is in self-refresh mode */
- #define __addr_FR4XX_DRCN 0xfe000430 /* Address of DRCN register */
- #define FR4XX_DSTS_OFFSET -8 /* Offset from DRCN to DSTS */
- #define FR4XX_SDRAMC_DSTS_SSI 0x00000001 /* indicates that the SDRAM is in self-refresh mode */
- #define SDRAMC_DRCN_SR 0x00000001 /* transition SDRAM into self-refresh mode */
- .section .bss
- .balign 8
- .globl __sleep_save_area
- __sleep_save_area:
- .space 16
- .text
- .balign 4
- .macro li v r
- sethi.p %hi(\v),\r
- setlo %lo(\v),\r
- .endm
- #ifdef CONFIG_PM
- ###############################################################################
- #
- # CPU suspension routine
- # - void frv_cpu_suspend(unsigned long pdm_mode)
- #
- ###############################################################################
- .globl frv_cpu_suspend
- .type frv_cpu_suspend,@function
- frv_cpu_suspend:
- #----------------------------------------------------
- # save hsr0, psr, isr, and lr for resume code
- #----------------------------------------------------
- li __sleep_save_area,gr11
- movsg hsr0,gr4
- movsg psr,gr5
- movsg isr,gr6
- movsg lr,gr7
- stdi gr4,@(gr11,#0)
- stdi gr6,@(gr11,#8)
- # store the return address from sleep in GR14, and its complement in GR13 as a check
- li __ramboot_resume,gr14
- #ifdef CONFIG_MMU
- # Resume via RAMBOOT# will turn MMU off, so bootloader needs a physical address.
- sethi.p %hi(__page_offset),gr13
- setlo %lo(__page_offset),gr13
- sub gr14,gr13,gr14
- #endif
- not gr14,gr13
- #----------------------------------------------------
- # preload and lock into icache that code which may have to run
- # when dram is in self-refresh state.
- #----------------------------------------------------
- movsg hsr0, gr3
- li HSR0_ICE,gr4
- or gr3,gr4,gr3
- movgs gr3,hsr0
- or gr3,gr8,gr7 // add the sleep bits for later
- li #__icache_lock_start,gr3
- li #__icache_lock_end,gr4
- 1: icpl gr3,gr0,#1
- addi gr3,#L1_CACHE_BYTES,gr3
- cmp gr4,gr3,icc0
- bhi icc0,#0,1b
- # disable exceptions
- movsg psr,gr8
- andi.p gr8,#~PSR_PIL,gr8
- andi gr8,~PSR_ET,gr8
- movgs gr8,psr
- ori gr8,#PSR_ET,gr8
- srli gr8,#28,gr4
- subicc gr4,#3,gr0,icc0
- beq icc0,#0,1f
- # FR4xx
- li __addr_FR4XX_DRCN,gr4
- li FR4XX_SDRAMC_DSTS_SSI,gr5
- li FR4XX_DSTS_OFFSET,gr6
- bra __icache_lock_start
- 1:
- # FR5xx
- li __addr_FR55X_DRCN,gr4
- li FR55X_SDRAMC_DSTS_SSI,gr5
- li FR55X_DSTS_OFFSET,gr6
- bra __icache_lock_start
- .size frv_cpu_suspend, .-frv_cpu_suspend
- #
- # the final part of the sleep sequence...
- # - we want it to be be cacheline aligned so we can lock it into the icache easily
- # On entry: gr7 holds desired hsr0 sleep value
- # gr8 holds desired psr sleep value
- #
- .balign L1_CACHE_BYTES
- .type __icache_lock_start,@function
- __icache_lock_start:
- #----------------------------------------------------
- # put SDRAM in self-refresh mode
- #----------------------------------------------------
- # Flush all data in the cache using the DCEF instruction.
- dcef @(gr0,gr0),#1
- # Stop DMAC transfer
- # Execute dummy load from SDRAM
- ldi @(gr11,#0),gr11
- # put the SDRAM into self-refresh mode
- ld @(gr4,gr0),gr11
- ori gr11,#SDRAMC_DRCN_SR,gr11
- st gr11,@(gr4,gr0)
- membar
- # wait for SDRAM to reach self-refresh mode
- 1: ld @(gr4,gr6),gr11
- andcc gr11,gr5,gr11,icc0
- beq icc0,#0,1b
- # Set the GPIO register so that the IRQ[3:0] pins become valid, as required.
- # Set the clock mode (CLKC register) as required.
- # - At this time, also set the CLKC register P0 bit.
- # Set the HSR0 register PDM field.
- movgs gr7,hsr0
- # Execute NOP 32 times.
- .rept 32
- nop
- .endr
- #if 0 // Fujitsu recommend to skip this and will update docs.
- # Release the interrupt mask setting of the MASK register of the
- # interrupt controller if necessary.
- sti gr10,@(gr9,#0)
- membar
- #endif
- # Set the PSR register ET bit to 1 to enable interrupts.
- movgs gr8,psr
- ###################################################
- # this is only reached if waking up via interrupt
- ###################################################
- # Execute NOP 32 times.
- .rept 32
- nop
- .endr
- #----------------------------------------------------
- # wake SDRAM from self-refresh mode
- #----------------------------------------------------
- ld @(gr4,gr0),gr11
- andi gr11,#~SDRAMC_DRCN_SR,gr11
- st gr11,@(gr4,gr0)
- membar
- 2:
- ld @(gr4,gr6),gr11 // Wait for it to come back...
- andcc gr11,gr5,gr0,icc0
- bne icc0,0,2b
- # wait for the SDRAM to stabilise
- li 0x0100000,gr3
- 3: subicc gr3,#1,gr3,icc0
- bne icc0,#0,3b
- # now that DRAM is back, this is the end of the code which gets
- # locked in icache.
- __icache_lock_end:
- .size __icache_lock_start, .-__icache_lock_start
- # Fall-through to the RAMBOOT# wakeup path
- ###############################################################################
- #
- # resume from suspend re-entry point reached via RAMBOOT# and bootloader
- #
- ###############################################################################
- __ramboot_resume:
- #----------------------------------------------------
- # restore hsr0, psr, isr, and leave saved lr in gr7
- #----------------------------------------------------
- li __sleep_save_area,gr11
- #ifdef CONFIG_MMU
- movsg hsr0,gr4
- sethi.p %hi(HSR0_EXMMU),gr3
- setlo %lo(HSR0_EXMMU),gr3
- andcc gr3,gr4,gr0,icc0
- bne icc0,#0,2f
- # need to use physical address
- sethi.p %hi(__page_offset),gr3
- setlo %lo(__page_offset),gr3
- sub gr11,gr3,gr11
- # flush all tlb entries
- setlos #64,gr4
- setlos.p #PAGE_SIZE,gr5
- setlos #0,gr6
- 1:
- tlbpr gr6,gr0,#6,#0
- subicc.p gr4,#1,gr4,icc0
- add gr6,gr5,gr6
- bne icc0,#2,1b
- # need a temporary mapping for the current physical address we are
- # using between time MMU is enabled and jump to virtual address is
- # made.
- sethi.p %hi(0x00000000),gr4
- setlo %lo(0x00000000),gr4 ; physical address
- setlos #xAMPRx_L|xAMPRx_M|xAMPRx_SS_256Mb|xAMPRx_S_KERNEL|xAMPRx_V,gr5
- or gr4,gr5,gr5
- movsg cxnr,gr13
- or gr4,gr13,gr4
- movgs gr4,iamlr1 ; mapped from real address 0
- movgs gr5,iampr1 ; cached kernel memory at 0x00000000
- 2:
- #endif
- lddi @(gr11,#0),gr4 ; hsr0, psr
- lddi @(gr11,#8),gr6 ; isr, lr
- movgs gr4,hsr0
- bar
- #ifdef CONFIG_MMU
- sethi.p %hi(1f),gr11
- setlo %lo(1f),gr11
- jmpl @(gr11,gr0)
- 1:
- movgs gr0,iampr1 ; get rid of temporary mapping
- #endif
- movgs gr5,psr
- movgs gr6,isr
- #----------------------------------------------------
- # unlock the icache which was locked before going to sleep
- #----------------------------------------------------
- li __icache_lock_start,gr3
- li __icache_lock_end,gr4
- 1: icul gr3
- addi gr3,#L1_CACHE_BYTES,gr3
- cmp gr4,gr3,icc0
- bhi icc0,#0,1b
- #----------------------------------------------------
- # back to business as usual
- #----------------------------------------------------
- jmpl @(gr7,gr0) ;
- #endif /* CONFIG_PM */
- ###############################################################################
- #
- # CPU core sleep mode routine
- #
- ###############################################################################
- .globl frv_cpu_core_sleep
- .type frv_cpu_core_sleep,@function
- frv_cpu_core_sleep:
- # Preload into icache.
- li #__core_sleep_icache_lock_start,gr3
- li #__core_sleep_icache_lock_end,gr4
- 1: icpl gr3,gr0,#1
- addi gr3,#L1_CACHE_BYTES,gr3
- cmp gr4,gr3,icc0
- bhi icc0,#0,1b
- bra __core_sleep_icache_lock_start
- .balign L1_CACHE_BYTES
- __core_sleep_icache_lock_start:
- # (1) Set the PSR register ET bit to 0 to disable interrupts.
- movsg psr,gr8
- andi.p gr8,#~(PSR_PIL),gr8
- andi gr8,#~(PSR_ET),gr4
- movgs gr4,psr
- #if 0 // Fujitsu recommend to skip this and will update docs.
- # (2) Set '1' to all bits in the MASK register of the interrupt
- # controller and mask interrupts.
- sethi.p %hi(__addr_MASK),gr9
- setlo %lo(__addr_MASK),gr9
- sethi.p %hi(0xffff0000),gr4
- setlo %lo(0xffff0000),gr4
- ldi @(gr9,#0),gr10
- sti gr4,@(gr9,#0)
- #endif
- # (3) Flush all data in the cache using the DCEF instruction.
- dcef @(gr0,gr0),#1
- # (4) Execute the memory barrier instruction
- membar
- # (5) Set the GPIO register so that the IRQ[3:0] pins become valid, as required.
- # (6) Set the clock mode (CLKC register) as required.
- # - At this time, also set the CLKC register P0 bit.
- # (7) Set the HSR0 register PDM field to 001 .
- movsg hsr0,gr4
- ori gr4,HSR0_PDM_CORE_SLEEP,gr4
- movgs gr4,hsr0
- # (8) Execute NOP 32 times.
- .rept 32
- nop
- .endr
- #if 0 // Fujitsu recommend to skip this and will update docs.
- # (9) Release the interrupt mask setting of the MASK register of the
- # interrupt controller if necessary.
- sti gr10,@(gr9,#0)
- membar
- #endif
- # (10) Set the PSR register ET bit to 1 to enable interrupts.
- movgs gr8,psr
- __core_sleep_icache_lock_end:
- # Unlock from icache
- li __core_sleep_icache_lock_start,gr3
- li __core_sleep_icache_lock_end,gr4
- 1: icul gr3
- addi gr3,#L1_CACHE_BYTES,gr3
- cmp gr4,gr3,icc0
- bhi icc0,#0,1b
- bralr
- .size frv_cpu_core_sleep, .-frv_cpu_core_sleep
|