diff options
author | Andrew Victor <linux@maxim.org.za> | 2008-04-02 16:50:16 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-04-04 04:52:22 -0400 |
commit | f5d0f4574fe1584891b5167fb0ba42974af13e49 (patch) | |
tree | 4fccf8d0b0945ac8e161bfbf2996428a87cf6fda /arch/arm/mach-at91 | |
parent | a3da12229f4f9bee2ed66ac34a54a4e8b74bcbcb (diff) |
[ARM] 4906/1: [AT91] SAM9/CAP9 basic power-management
Basic power-management (suspend-to-ram) support for Atmel SAM9 and
CAP9 processors.
Based on comments & patches from Anti Sullin and David Brownell.
Signed-off-by: Andrew Victor <linux@maxim.org.za>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-at91')
-rw-r--r-- | arch/arm/mach-at91/pm.c | 91 |
1 files changed, 75 insertions, 16 deletions
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index a67defd50438..77d9669810ed 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c | |||
@@ -26,12 +26,62 @@ | |||
26 | #include <asm/mach-types.h> | 26 | #include <asm/mach-types.h> |
27 | 27 | ||
28 | #include <asm/arch/at91_pmc.h> | 28 | #include <asm/arch/at91_pmc.h> |
29 | #include <asm/arch/at91rm9200_mc.h> | ||
30 | #include <asm/arch/gpio.h> | 29 | #include <asm/arch/gpio.h> |
31 | #include <asm/arch/cpu.h> | 30 | #include <asm/arch/cpu.h> |
32 | 31 | ||
33 | #include "generic.h" | 32 | #include "generic.h" |
34 | 33 | ||
34 | #ifdef CONFIG_ARCH_AT91RM9200 | ||
35 | #include <asm/arch/at91rm9200_mc.h> | ||
36 | |||
37 | /* | ||
38 | * The AT91RM9200 goes into self-refresh mode with this command, and will | ||
39 | * terminate self-refresh automatically on the next SDRAM access. | ||
40 | */ | ||
41 | #define sdram_selfrefresh_enable() at91_sys_write(AT91_SDRAMC_SRR, 1) | ||
42 | #define sdram_selfrefresh_disable() do {} while (0) | ||
43 | |||
44 | #elif defined(CONFIG_ARCH_AT91CAP9) | ||
45 | #include <asm/arch/at91cap9_ddrsdr.h> | ||
46 | |||
47 | static u32 saved_lpr; | ||
48 | |||
49 | static inline void sdram_selfrefresh_enable(void) | ||
50 | { | ||
51 | u32 lpr; | ||
52 | |||
53 | saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR); | ||
54 | |||
55 | lpr = saved_lpr & ~AT91_DDRSDRC_LPCB; | ||
56 | at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH); | ||
57 | } | ||
58 | |||
59 | #define sdram_selfrefresh_disable() at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr) | ||
60 | |||
61 | #else | ||
62 | #include <asm/arch/at91sam9_sdramc.h> | ||
63 | |||
64 | static u32 saved_lpr; | ||
65 | |||
66 | static inline void sdram_selfrefresh_enable(void) | ||
67 | { | ||
68 | u32 lpr; | ||
69 | |||
70 | saved_lpr = at91_sys_read(AT91_SDRAMC_LPR); | ||
71 | |||
72 | lpr = saved_lpr & ~AT91_SDRAMC_LPCB; | ||
73 | at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH); | ||
74 | } | ||
75 | |||
76 | #define sdram_selfrefresh_disable() at91_sys_write(AT91_SDRAMC_LPR, saved_lpr) | ||
77 | |||
78 | /* | ||
79 | * FIXME: The AT91SAM9263 has a second EBI controller which may have | ||
80 | * additional SDRAM. pm_slowclock.S will require a similar fix. | ||
81 | */ | ||
82 | |||
83 | #endif | ||
84 | |||
35 | 85 | ||
36 | static int at91_pm_valid_state(suspend_state_t state) | 86 | static int at91_pm_valid_state(suspend_state_t state) |
37 | { | 87 | { |
@@ -125,6 +175,11 @@ EXPORT_SYMBOL(at91_suspend_entering_slow_clock); | |||
125 | 175 | ||
126 | static void (*slow_clock)(void); | 176 | static void (*slow_clock)(void); |
127 | 177 | ||
178 | #ifdef CONFIG_AT91_SLOW_CLOCK | ||
179 | extern void at91_slow_clock(void); | ||
180 | extern u32 at91_slow_clock_sz; | ||
181 | #endif | ||
182 | |||
128 | 183 | ||
129 | static int at91_pm_enter(suspend_state_t state) | 184 | static int at91_pm_enter(suspend_state_t state) |
130 | { | 185 | { |
@@ -158,11 +213,14 @@ static int at91_pm_enter(suspend_state_t state) | |||
158 | * turning off the main oscillator; reverse on wakeup. | 213 | * turning off the main oscillator; reverse on wakeup. |
159 | */ | 214 | */ |
160 | if (slow_clock) { | 215 | if (slow_clock) { |
216 | #ifdef CONFIG_AT91_SLOW_CLOCK | ||
217 | /* copy slow_clock handler to SRAM, and call it */ | ||
218 | memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz); | ||
219 | #endif | ||
161 | slow_clock(); | 220 | slow_clock(); |
162 | break; | 221 | break; |
163 | } else { | 222 | } else { |
164 | /* DEVELOPMENT ONLY */ | 223 | pr_info("AT91: PM - no slow clock mode enabled ...\n"); |
165 | pr_info("AT91: PM - no slow clock mode yet ...\n"); | ||
166 | /* FALLTHROUGH leaving master clock alone */ | 224 | /* FALLTHROUGH leaving master clock alone */ |
167 | } | 225 | } |
168 | 226 | ||
@@ -175,13 +233,15 @@ static int at91_pm_enter(suspend_state_t state) | |||
175 | case PM_SUSPEND_STANDBY: | 233 | case PM_SUSPEND_STANDBY: |
176 | /* | 234 | /* |
177 | * NOTE: the Wait-for-Interrupt instruction needs to be | 235 | * NOTE: the Wait-for-Interrupt instruction needs to be |
178 | * in icache so the SDRAM stays in self-refresh mode until | 236 | * in icache so no SDRAM accesses are needed until the |
179 | * the wakeup IRQ occurs. | 237 | * wakeup IRQ occurs and self-refresh is terminated. |
180 | */ | 238 | */ |
181 | asm("b 1f; .align 5; 1:"); | 239 | asm("b 1f; .align 5; 1:"); |
182 | asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ | 240 | asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ |
183 | at91_sys_write(AT91_SDRAMC_SRR, 1); /* self-refresh mode */ | 241 | sdram_selfrefresh_enable(); |
184 | /* fall though to next state */ | 242 | asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ |
243 | sdram_selfrefresh_disable(); | ||
244 | break; | ||
185 | 245 | ||
186 | case PM_SUSPEND_ON: | 246 | case PM_SUSPEND_ON: |
187 | asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ | 247 | asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ |
@@ -196,6 +256,7 @@ static int at91_pm_enter(suspend_state_t state) | |||
196 | at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); | 256 | at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); |
197 | 257 | ||
198 | error: | 258 | error: |
259 | sdram_selfrefresh_disable(); | ||
199 | target_state = PM_SUSPEND_ON; | 260 | target_state = PM_SUSPEND_ON; |
200 | at91_irq_resume(); | 261 | at91_irq_resume(); |
201 | at91_gpio_resume(); | 262 | at91_gpio_resume(); |
@@ -220,18 +281,16 @@ static struct platform_suspend_ops at91_pm_ops ={ | |||
220 | 281 | ||
221 | static int __init at91_pm_init(void) | 282 | static int __init at91_pm_init(void) |
222 | { | 283 | { |
223 | printk("AT91: Power Management\n"); | 284 | #ifdef CONFIG_AT91_SLOW_CLOCK |
224 | 285 | slow_clock = (void *) (AT91_IO_VIRT_BASE - at91_slow_clock_sz); | |
225 | #ifdef CONFIG_AT91_PM_SLOW_CLOCK | ||
226 | /* REVISIT allocations of SRAM should be dynamically managed. | ||
227 | * FIQ handlers and other components will want SRAM/TCM too... | ||
228 | */ | ||
229 | slow_clock = (void *) (AT91_VA_BASE_SRAM + (3 * SZ_4K)); | ||
230 | memcpy(slow_clock, at91rm9200_slow_clock, at91rm9200_slow_clock_sz); | ||
231 | #endif | 286 | #endif |
232 | 287 | ||
233 | /* Disable SDRAM low-power mode. Cannot be used with self-refresh. */ | 288 | pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : "")); |
289 | |||
290 | #ifdef CONFIG_ARCH_AT91RM9200 | ||
291 | /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */ | ||
234 | at91_sys_write(AT91_SDRAMC_LPR, 0); | 292 | at91_sys_write(AT91_SDRAMC_LPR, 0); |
293 | #endif | ||
235 | 294 | ||
236 | suspend_set_ops(&at91_pm_ops); | 295 | suspend_set_ops(&at91_pm_ops); |
237 | 296 | ||