aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-at91/pm.c
diff options
context:
space:
mode:
authorAndrew Victor <linux@maxim.org.za>2008-04-02 16:50:16 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-04-04 04:52:22 -0400
commitf5d0f4574fe1584891b5167fb0ba42974af13e49 (patch)
tree4fccf8d0b0945ac8e161bfbf2996428a87cf6fda /arch/arm/mach-at91/pm.c
parenta3da12229f4f9bee2ed66ac34a54a4e8b74bcbcb (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/pm.c')
-rw-r--r--arch/arm/mach-at91/pm.c91
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
47static u32 saved_lpr;
48
49static 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
64static u32 saved_lpr;
65
66static 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
36static int at91_pm_valid_state(suspend_state_t state) 86static int at91_pm_valid_state(suspend_state_t state)
37{ 87{
@@ -125,6 +175,11 @@ EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
125 175
126static void (*slow_clock)(void); 176static void (*slow_clock)(void);
127 177
178#ifdef CONFIG_AT91_SLOW_CLOCK
179extern void at91_slow_clock(void);
180extern u32 at91_slow_clock_sz;
181#endif
182
128 183
129static int at91_pm_enter(suspend_state_t state) 184static 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
198error: 258error:
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
221static int __init at91_pm_init(void) 282static 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