diff options
Diffstat (limited to 'arch/frv/kernel/sleep.S')
-rw-r--r-- | arch/frv/kernel/sleep.S | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/arch/frv/kernel/sleep.S b/arch/frv/kernel/sleep.S new file mode 100644 index 000000000000..e6079b8cac60 --- /dev/null +++ b/arch/frv/kernel/sleep.S @@ -0,0 +1,374 @@ +/* sleep.S: power saving mode entry + * + * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. + * Written by David Woodhouse (dwmw2@redhat.com) + * + * 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/config.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 |