diff options
Diffstat (limited to 'arch/arm/mach-at91/pm.c')
-rw-r--r-- | arch/arm/mach-at91/pm.c | 165 |
1 files changed, 149 insertions, 16 deletions
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index a67defd50438..39733b6992aa 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c | |||
@@ -26,12 +26,135 @@ | |||
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 | |||
85 | |||
86 | /* | ||
87 | * Show the reason for the previous system reset. | ||
88 | */ | ||
89 | #if defined(AT91_SHDWC) | ||
90 | |||
91 | #include <asm/arch/at91_rstc.h> | ||
92 | #include <asm/arch/at91_shdwc.h> | ||
93 | |||
94 | static void __init show_reset_status(void) | ||
95 | { | ||
96 | static char reset[] __initdata = "reset"; | ||
97 | |||
98 | static char general[] __initdata = "general"; | ||
99 | static char wakeup[] __initdata = "wakeup"; | ||
100 | static char watchdog[] __initdata = "watchdog"; | ||
101 | static char software[] __initdata = "software"; | ||
102 | static char user[] __initdata = "user"; | ||
103 | static char unknown[] __initdata = "unknown"; | ||
104 | |||
105 | static char signal[] __initdata = "signal"; | ||
106 | static char rtc[] __initdata = "rtc"; | ||
107 | static char rtt[] __initdata = "rtt"; | ||
108 | static char restore[] __initdata = "power-restored"; | ||
109 | |||
110 | char *reason, *r2 = reset; | ||
111 | u32 reset_type, wake_type; | ||
112 | |||
113 | reset_type = at91_sys_read(AT91_RSTC_SR) & AT91_RSTC_RSTTYP; | ||
114 | wake_type = at91_sys_read(AT91_SHDW_SR); | ||
115 | |||
116 | switch (reset_type) { | ||
117 | case AT91_RSTC_RSTTYP_GENERAL: | ||
118 | reason = general; | ||
119 | break; | ||
120 | case AT91_RSTC_RSTTYP_WAKEUP: | ||
121 | /* board-specific code enabled the wakeup sources */ | ||
122 | reason = wakeup; | ||
123 | |||
124 | /* "wakeup signal" */ | ||
125 | if (wake_type & AT91_SHDW_WAKEUP0) | ||
126 | r2 = signal; | ||
127 | else { | ||
128 | r2 = reason; | ||
129 | if (wake_type & AT91_SHDW_RTTWK) /* rtt wakeup */ | ||
130 | reason = rtt; | ||
131 | else if (wake_type & AT91_SHDW_RTCWK) /* rtc wakeup */ | ||
132 | reason = rtc; | ||
133 | else if (wake_type == 0) /* power-restored wakeup */ | ||
134 | reason = restore; | ||
135 | else /* unknown wakeup */ | ||
136 | reason = unknown; | ||
137 | } | ||
138 | break; | ||
139 | case AT91_RSTC_RSTTYP_WATCHDOG: | ||
140 | reason = watchdog; | ||
141 | break; | ||
142 | case AT91_RSTC_RSTTYP_SOFTWARE: | ||
143 | reason = software; | ||
144 | break; | ||
145 | case AT91_RSTC_RSTTYP_USER: | ||
146 | reason = user; | ||
147 | break; | ||
148 | default: | ||
149 | reason = unknown; | ||
150 | break; | ||
151 | } | ||
152 | pr_info("AT91: Starting after %s %s\n", reason, r2); | ||
153 | } | ||
154 | #else | ||
155 | static void __init show_reset_status(void) {} | ||
156 | #endif | ||
157 | |||
35 | 158 | ||
36 | static int at91_pm_valid_state(suspend_state_t state) | 159 | static int at91_pm_valid_state(suspend_state_t state) |
37 | { | 160 | { |
@@ -125,6 +248,11 @@ EXPORT_SYMBOL(at91_suspend_entering_slow_clock); | |||
125 | 248 | ||
126 | static void (*slow_clock)(void); | 249 | static void (*slow_clock)(void); |
127 | 250 | ||
251 | #ifdef CONFIG_AT91_SLOW_CLOCK | ||
252 | extern void at91_slow_clock(void); | ||
253 | extern u32 at91_slow_clock_sz; | ||
254 | #endif | ||
255 | |||
128 | 256 | ||
129 | static int at91_pm_enter(suspend_state_t state) | 257 | static int at91_pm_enter(suspend_state_t state) |
130 | { | 258 | { |
@@ -158,11 +286,14 @@ static int at91_pm_enter(suspend_state_t state) | |||
158 | * turning off the main oscillator; reverse on wakeup. | 286 | * turning off the main oscillator; reverse on wakeup. |
159 | */ | 287 | */ |
160 | if (slow_clock) { | 288 | if (slow_clock) { |
289 | #ifdef CONFIG_AT91_SLOW_CLOCK | ||
290 | /* copy slow_clock handler to SRAM, and call it */ | ||
291 | memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz); | ||
292 | #endif | ||
161 | slow_clock(); | 293 | slow_clock(); |
162 | break; | 294 | break; |
163 | } else { | 295 | } else { |
164 | /* DEVELOPMENT ONLY */ | 296 | 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 */ | 297 | /* FALLTHROUGH leaving master clock alone */ |
167 | } | 298 | } |
168 | 299 | ||
@@ -175,13 +306,15 @@ static int at91_pm_enter(suspend_state_t state) | |||
175 | case PM_SUSPEND_STANDBY: | 306 | case PM_SUSPEND_STANDBY: |
176 | /* | 307 | /* |
177 | * NOTE: the Wait-for-Interrupt instruction needs to be | 308 | * NOTE: the Wait-for-Interrupt instruction needs to be |
178 | * in icache so the SDRAM stays in self-refresh mode until | 309 | * in icache so no SDRAM accesses are needed until the |
179 | * the wakeup IRQ occurs. | 310 | * wakeup IRQ occurs and self-refresh is terminated. |
180 | */ | 311 | */ |
181 | asm("b 1f; .align 5; 1:"); | 312 | asm("b 1f; .align 5; 1:"); |
182 | asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ | 313 | asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ |
183 | at91_sys_write(AT91_SDRAMC_SRR, 1); /* self-refresh mode */ | 314 | sdram_selfrefresh_enable(); |
184 | /* fall though to next state */ | 315 | asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ |
316 | sdram_selfrefresh_disable(); | ||
317 | break; | ||
185 | 318 | ||
186 | case PM_SUSPEND_ON: | 319 | case PM_SUSPEND_ON: |
187 | asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ | 320 | asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ |
@@ -196,6 +329,7 @@ static int at91_pm_enter(suspend_state_t state) | |||
196 | at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); | 329 | at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); |
197 | 330 | ||
198 | error: | 331 | error: |
332 | sdram_selfrefresh_disable(); | ||
199 | target_state = PM_SUSPEND_ON; | 333 | target_state = PM_SUSPEND_ON; |
200 | at91_irq_resume(); | 334 | at91_irq_resume(); |
201 | at91_gpio_resume(); | 335 | at91_gpio_resume(); |
@@ -220,21 +354,20 @@ static struct platform_suspend_ops at91_pm_ops ={ | |||
220 | 354 | ||
221 | static int __init at91_pm_init(void) | 355 | static int __init at91_pm_init(void) |
222 | { | 356 | { |
223 | printk("AT91: Power Management\n"); | 357 | #ifdef CONFIG_AT91_SLOW_CLOCK |
224 | 358 | 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 | 359 | #endif |
232 | 360 | ||
233 | /* Disable SDRAM low-power mode. Cannot be used with self-refresh. */ | 361 | pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : "")); |
362 | |||
363 | #ifdef CONFIG_ARCH_AT91RM9200 | ||
364 | /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */ | ||
234 | at91_sys_write(AT91_SDRAMC_LPR, 0); | 365 | at91_sys_write(AT91_SDRAMC_LPR, 0); |
366 | #endif | ||
235 | 367 | ||
236 | suspend_set_ops(&at91_pm_ops); | 368 | suspend_set_ops(&at91_pm_ops); |
237 | 369 | ||
370 | show_reset_status(); | ||
238 | return 0; | 371 | return 0; |
239 | } | 372 | } |
240 | arch_initcall(at91_pm_init); | 373 | arch_initcall(at91_pm_init); |