/* * linux/arch/unicore32/kernel/sleep.S * * Code specific to PKUnity SoC and UniCore ISA * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/linkage.h> #include <asm/assembler.h> #include <mach/hardware.h> .text pkunity_cpu_save_cp: @ get coprocessor registers movc r3, p0.c7, #0 @ PID movc r4, p0.c2, #0 @ translation table base addr movc r5, p0.c1, #0 @ control reg @ store them plus current virtual stack ptr on stack mov r6, sp stm.w (r3 - r6), [sp-] mov pc, lr pkunity_cpu_save_sp: @ preserve phys address of stack mov r0, sp stw.w lr, [sp+], #-4 b.l sleep_phys_sp ldw r1, =sleep_save_sp stw r0, [r1] ldw.w pc, [sp]+, #4 /* * puv3_cpu_suspend() * * Forces CPU into sleep state. * * r0 = value for PWRMODE M field for desired sleep state */ ENTRY(puv3_cpu_suspend) stm.w (r16 - r27, lr), [sp-] @ save registers on stack stm.w (r4 - r15), [sp-] @ save registers on stack #ifdef CONFIG_UNICORE_FPU_F64 sfm.w (f0 - f7 ), [sp-] sfm.w (f8 - f15), [sp-] sfm.w (f16 - f23), [sp-] sfm.w (f24 - f31), [sp-] cff r4, s31 stm.w (r4), [sp-] #endif b.l pkunity_cpu_save_cp b.l pkunity_cpu_save_sp @ clean data cache mov r1, #0 movc p0.c5, r1, #14 nop nop nop nop @ DDR2 BaseAddr ldw r0, =(PKUNITY_DDR2CTRL_BASE) @ PM BaseAddr ldw r1, =(PKUNITY_PM_BASE) @ set PLL_SYS_CFG reg, 275 movl r6, #0x00002401 stw r6, [r1+], #0x18 @ set PLL_DDR_CFG reg, 66MHz movl r6, #0x00100c00 stw r6, [r1+], #0x1c @ set wake up source movl r8, #0x800001ff @ epip4d stw r8, [r1+], #0xc @ set PGSR movl r5, #0x40000 stw r5, [r1+], #0x10 @ prepare DDR2 refresh settings ldw r5, [r0+], #0x24 or r5, r5, #0x00000001 @ prepare PMCR for PLL changing movl r6, #0xc @ prepare for closing PLL movl r7, #0x1 @ prepare sleep mode mov r8, #0x1 @ movl r0, 0x11111111 @ put_word_ocd r0 b pkunity_cpu_do_suspend .ltorg .align 5 pkunity_cpu_do_suspend: b 101f @ put DDR2 into self-refresh 100: stw r5, [r0+], #0x24 @ change PLL stw r6, [r1] b 1f .ltorg .align 5 101: b 102f @ wait for PLL changing complete 1: ldw r6, [r1+], #0x44 csub.a r6, #0x1 bne 1b b 2f .ltorg .align 5 102: b 100b @ close PLL 2: stw r7, [r1+], #0x4 @ enter sleep mode stw r8, [r1] 3: b 3b /* * puv3_cpu_resume() * * entry point from bootloader into kernel during resume * * Note: Yes, part of the following code is located into the .data section. * This is to allow sleep_save_sp to be accessed with a relative load * while we can't rely on any MMU translation. We could have put * sleep_save_sp in the .text section as well, but some setups might * insist on it to be truly read-only. */ .data .align 5 ENTRY(puv3_cpu_resume) @ movl r0, 0x20202020 @ put_word_ocd r0 ldw r0, sleep_save_sp @ stack phys addr ldw r2, =resume_after_mmu @ its absolute virtual address ldm (r3 - r6), [r0]+ @ CP regs + virt stack ptr mov sp, r6 @ CP regs + virt stack ptr mov r1, #0 movc p0.c6, r1, #6 @ invalidate I & D TLBs movc p0.c5, r1, #28 @ invalidate I & D caches, BTB movc p0.c7, r3, #0 @ PID movc p0.c2, r4, #0 @ translation table base addr movc p0.c1, r5, #0 @ control reg, turn on mmu nop jump r2 nop nop nop nop nop sleep_save_sp: .word 0 @ preserve stack phys ptr here .text resume_after_mmu: @ movl r0, 0x30303030 @ put_word_ocd r0 #ifdef CONFIG_UNICORE_FPU_F64 lfm.w (f0 - f7 ), [sp]+ lfm.w (f8 - f15), [sp]+ lfm.w (f16 - f23), [sp]+ lfm.w (f24 - f31), [sp]+ ldm.w (r4), [sp]+ ctf r4, s31 #endif ldm.w (r4 - r15), [sp]+ @ restore registers from stack ldm.w (r16 - r27, pc), [sp]+ @ return to caller