diff options
Diffstat (limited to 'arch/arm/mach-s3c2410/sleep.S')
-rw-r--r-- | arch/arm/mach-s3c2410/sleep.S | 151 |
1 files changed, 30 insertions, 121 deletions
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S index 2018c2e1dcc5..9179a1024588 100644 --- a/arch/arm/mach-s3c2410/sleep.S +++ b/arch/arm/mach-s3c2410/sleep.S | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/sleep.S | 1 | /* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -34,126 +34,35 @@ | |||
34 | #include <asm/arch/regs-mem.h> | 34 | #include <asm/arch/regs-mem.h> |
35 | #include <asm/arch/regs-serial.h> | 35 | #include <asm/arch/regs-serial.h> |
36 | 36 | ||
37 | /* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not | 37 | /* s3c2410_cpu_suspend |
38 | * reset the UART configuration, only enable if you really need this! | ||
39 | */ | ||
40 | //#define CONFIG_DEBUG_RESUME | ||
41 | |||
42 | .text | ||
43 | |||
44 | /* s3c2410_cpu_save | ||
45 | * | ||
46 | * save enough of the CPU state to allow us to re-start | ||
47 | * pm.c code. as we store items like the sp/lr, we will | ||
48 | * end up returning from this function when the cpu resumes | ||
49 | * so the return value is set to mark this. | ||
50 | * | ||
51 | * This arangement means we avoid having to flush the cache | ||
52 | * from this code. | ||
53 | * | ||
54 | * entry: | ||
55 | * r0 = pointer to save block | ||
56 | * | ||
57 | * exit: | ||
58 | * r0 = 0 => we stored everything | ||
59 | * 1 => resumed from sleep | ||
60 | */ | ||
61 | |||
62 | ENTRY(s3c2410_cpu_save) | ||
63 | stmfd sp!, { r4 - r12, lr } | ||
64 | |||
65 | @@ store co-processor registers | ||
66 | |||
67 | mrc p15, 0, r4, c15, c1, 0 @ CP access register | ||
68 | mrc p15, 0, r5, c13, c0, 0 @ PID | ||
69 | mrc p15, 0, r6, c3, c0, 0 @ Domain ID | ||
70 | mrc p15, 0, r7, c2, c0, 0 @ translation table base address | ||
71 | mrc p15, 0, r8, c1, c0, 0 @ control register | ||
72 | |||
73 | stmia r0, { r4 - r13 } | ||
74 | |||
75 | mov r0, #0 | ||
76 | ldmfd sp, { r4 - r12, pc } | ||
77 | |||
78 | @@ return to the caller, after having the MMU | ||
79 | @@ turned on, this restores the last bits from the | ||
80 | @@ stack | ||
81 | resume_with_mmu: | ||
82 | mov r0, #1 | ||
83 | ldmfd sp!, { r4 - r12, pc } | ||
84 | |||
85 | .ltorg | ||
86 | |||
87 | @@ the next bits sit in the .data segment, even though they | ||
88 | @@ happen to be code... the s3c2410_sleep_save_phys needs to be | ||
89 | @@ accessed by the resume code before it can restore the MMU. | ||
90 | @@ This means that the variable has to be close enough for the | ||
91 | @@ code to read it... since the .text segment needs to be RO, | ||
92 | @@ the data segment can be the only place to put this code. | ||
93 | |||
94 | .data | ||
95 | |||
96 | .global s3c2410_sleep_save_phys | ||
97 | s3c2410_sleep_save_phys: | ||
98 | .word 0 | ||
99 | |||
100 | /* s3c2410_cpu_resume | ||
101 | * | 38 | * |
102 | * resume code entry for bootloader to call | 39 | * put the cpu into sleep mode |
103 | * | ||
104 | * we must put this code here in the data segment as we have no | ||
105 | * other way of restoring the stack pointer after sleep, and we | ||
106 | * must not write to the code segment (code is read-only) | ||
107 | */ | 40 | */ |
108 | 41 | ||
109 | ENTRY(s3c2410_cpu_resume) | 42 | ENTRY(s3c2410_cpu_suspend) |
110 | mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE | 43 | @@ prepare cpu to sleep |
111 | msr cpsr_c, r0 | 44 | |
112 | 45 | ldr r4, =S3C2410_REFRESH | |
113 | @@ load UART to allow us to print the two characters for | 46 | ldr r5, =S3C24XX_MISCCR |
114 | @@ resume debug | 47 | ldr r6, =S3C2410_CLKCON |
115 | 48 | ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB) | |
116 | mov r2, #S3C24XX_PA_UART & 0xff000000 | 49 | ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB) |
117 | orr r2, r2, #S3C24XX_PA_UART & 0xff000 | 50 | ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB) |
118 | 51 | ||
119 | #if 0 | 52 | orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command |
120 | /* SMDK2440 LED set */ | 53 | orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals |
121 | mov r14, #S3C24XX_PA_GPIO | 54 | orr r9, r9, #S3C2410_CLKCON_POWER @ power down command |
122 | ldr r12, [ r14, #0x54 ] | 55 | |
123 | bic r12, r12, #3<<4 | 56 | teq pc, #0 @ first as a trial-run to load cache |
124 | orr r12, r12, #1<<7 | 57 | bl s3c2410_do_sleep |
125 | str r12, [ r14, #0x54 ] | 58 | teq r0, r0 @ now do it for real |
126 | #endif | 59 | b s3c2410_do_sleep @ |
127 | 60 | ||
128 | #ifdef CONFIG_DEBUG_RESUME | 61 | @@ align next bit of code to cache line |
129 | mov r3, #'L' | 62 | .align 8 |
130 | strb r3, [ r2, #S3C2410_UTXH ] | 63 | s3c2410_do_sleep: |
131 | 1001: | 64 | streq r7, [ r4 ] @ SDRAM sleep command |
132 | ldrb r14, [ r3, #S3C2410_UTRSTAT ] | 65 | streq r8, [ r5 ] @ SDRAM power-down config |
133 | tst r14, #S3C2410_UTRSTAT_TXE | 66 | streq r9, [ r6 ] @ CPU sleep |
134 | beq 1001b | 67 | 1: beq 1b |
135 | #endif /* CONFIG_DEBUG_RESUME */ | 68 | mov pc, r14 |
136 | |||
137 | mov r1, #0 | ||
138 | mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs | ||
139 | mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches | ||
140 | |||
141 | ldr r0, s3c2410_sleep_save_phys @ address of restore block | ||
142 | ldmia r0, { r4 - r13 } | ||
143 | |||
144 | mcr p15, 0, r4, c15, c1, 0 @ CP access register | ||
145 | mcr p15, 0, r5, c13, c0, 0 @ PID | ||
146 | mcr p15, 0, r6, c3, c0, 0 @ Domain ID | ||
147 | mcr p15, 0, r7, c2, c0, 0 @ translation table base | ||
148 | |||
149 | #ifdef CONFIG_DEBUG_RESUME | ||
150 | mov r3, #'R' | ||
151 | strb r3, [ r2, #S3C2410_UTXH ] | ||
152 | #endif | ||
153 | |||
154 | ldr r2, =resume_with_mmu | ||
155 | mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc | ||
156 | nop @ second-to-last before mmu | ||
157 | mov pc, r2 @ go back to virtual address | ||
158 | |||
159 | .ltorg | ||