aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2008-01-07 17:18:30 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-01-26 10:07:56 -0500
commit7b5dea12346f98b0624e00ef585246bfec8b0959 (patch)
treea0a04aa5101b716915e7256fca79d8db0d7fbe07
parenta10476d4ca52039a9240ac26376e15308b748b19 (diff)
[ARM] pxa: Add PXA3 standby code hooked into the IRQ wake scheme
Wakeup sources on PXA3 are enabled at two levels. First, the MFP configuration has to be set to enable which edges a specific pin will trigger a wakeup. The pin also has to be routed to a functional unit. Lastly, the functional unit must be enabled as a wakeup source in the appropriate AD*ER registers (AD2D0ER for standby resume.) This doesn't fit well with the IRQ wake scheme - we currently do a best effort conversion from IRQ numbers to functional unit wake enable bits. For instance, there's several USB client related enable bits but there's no corresponding IRQs to determine which you'd want. Conversely, there's a single enable bit covering several functional units. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c223
-rw-r--r--arch/arm/mach-pxa/standby.S80
-rw-r--r--include/asm-arm/arch-pxa/pxa3xx-regs.h86
3 files changed, 389 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index fcb2359b3867..0b2a15ed3999 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -19,6 +19,7 @@
19#include <linux/pm.h> 19#include <linux/pm.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/irq.h> 21#include <linux/irq.h>
22#include <linux/io.h>
22 23
23#include <asm/hardware.h> 24#include <asm/hardware.h>
24#include <asm/arch/pxa3xx-regs.h> 25#include <asm/arch/pxa3xx-regs.h>
@@ -201,6 +202,225 @@ static struct clk pxa3xx_clks[] = {
201 PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev), 202 PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
202}; 203};
203 204
205#ifdef CONFIG_PM
206#define SLEEP_SAVE_SIZE 4
207
208#define ISRAM_START 0x5c000000
209#define ISRAM_SIZE SZ_256K
210
211static void __iomem *sram;
212static unsigned long wakeup_src;
213
214static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
215{
216 pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
217
218 if (CKENA & (1 << CKEN_USBH)) {
219 printk(KERN_ERR "PM: USB host clock not stopped?\n");
220 CKENA &= ~(1 << CKEN_USBH);
221 }
222// CKENA |= 1 << (CKEN_ISC & 31);
223
224 /*
225 * Low power modes require the HSIO2 clock to be enabled.
226 */
227 CKENB |= 1 << (CKEN_HSIO2 & 31);
228}
229
230static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
231{
232 CKENB &= ~(1 << (CKEN_HSIO2 & 31));
233}
234
235/*
236 * Enter a standby mode (S0D1C2 or S0D2C2). Upon wakeup, the dynamic
237 * memory controller has to be reinitialised, so we place some code
238 * in the SRAM to perform this function.
239 *
240 * We disable FIQs across the standby - otherwise, we might receive a
241 * FIQ while the SDRAM is unavailable.
242 */
243static void pxa3xx_cpu_standby(unsigned int pwrmode)
244{
245 extern const char pm_enter_standby_start[], pm_enter_standby_end[];
246 void (*fn)(unsigned int) = (void __force *)(sram + 0x8000);
247
248 memcpy_toio(sram + 0x8000, pm_enter_standby_start,
249 pm_enter_standby_end - pm_enter_standby_start);
250
251 AD2D0SR = ~0;
252 AD2D1SR = ~0;
253 AD2D0ER = wakeup_src;
254 AD2D1ER = 0;
255 ASCR = ASCR;
256 ARSR = ARSR;
257
258 local_fiq_disable();
259 fn(pwrmode);
260 local_fiq_enable();
261
262 AD2D0ER = 0;
263 AD2D1ER = 0;
264
265 printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
266}
267
268static void pxa3xx_cpu_pm_enter(suspend_state_t state)
269{
270 /*
271 * Don't sleep if no wakeup sources are defined
272 */
273 if (wakeup_src == 0)
274 return;
275
276 switch (state) {
277 case PM_SUSPEND_STANDBY:
278 pxa3xx_cpu_standby(PXA3xx_PM_S0D2C2);
279 break;
280
281 case PM_SUSPEND_MEM:
282 break;
283 }
284}
285
286static int pxa3xx_cpu_pm_valid(suspend_state_t state)
287{
288 return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
289}
290
291static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = {
292 .save_size = SLEEP_SAVE_SIZE,
293 .save = pxa3xx_cpu_pm_save,
294 .restore = pxa3xx_cpu_pm_restore,
295 .valid = pxa3xx_cpu_pm_valid,
296 .enter = pxa3xx_cpu_pm_enter,
297};
298
299static void __init pxa3xx_init_pm(void)
300{
301 sram = ioremap(ISRAM_START, ISRAM_SIZE);
302 if (!sram) {
303 printk(KERN_ERR "Unable to map ISRAM: disabling standby/suspend\n");
304 return;
305 }
306
307 /*
308 * Since we copy wakeup code into the SRAM, we need to ensure
309 * that it is preserved over the low power modes. Note: bit 8
310 * is undocumented in the developer manual, but must be set.
311 */
312 AD1R |= ADXR_L2 | ADXR_R0;
313 AD2R |= ADXR_L2 | ADXR_R0;
314 AD3R |= ADXR_L2 | ADXR_R0;
315
316 /*
317 * Clear the resume enable registers.
318 */
319 AD1D0ER = 0;
320 AD2D0ER = 0;
321 AD2D1ER = 0;
322 AD3ER = 0;
323
324 pxa_cpu_pm_fns = &pxa3xx_cpu_pm_fns;
325}
326
327static int pxa3xx_set_wake(unsigned int irq, unsigned int on)
328{
329 unsigned long flags, mask = 0;
330
331 switch (irq) {
332 case IRQ_SSP3:
333 mask = ADXER_MFP_WSSP3;
334 break;
335 case IRQ_MSL:
336 mask = ADXER_WMSL0;
337 break;
338 case IRQ_USBH2:
339 case IRQ_USBH1:
340 mask = ADXER_WUSBH;
341 break;
342 case IRQ_KEYPAD:
343 mask = ADXER_WKP;
344 break;
345 case IRQ_AC97:
346 mask = ADXER_MFP_WAC97;
347 break;
348 case IRQ_USIM:
349 mask = ADXER_WUSIM0;
350 break;
351 case IRQ_SSP2:
352 mask = ADXER_MFP_WSSP2;
353 break;
354 case IRQ_I2C:
355 mask = ADXER_MFP_WI2C;
356 break;
357 case IRQ_STUART:
358 mask = ADXER_MFP_WUART3;
359 break;
360 case IRQ_BTUART:
361 mask = ADXER_MFP_WUART2;
362 break;
363 case IRQ_FFUART:
364 mask = ADXER_MFP_WUART1;
365 break;
366 case IRQ_MMC:
367 mask = ADXER_MFP_WMMC1;
368 break;
369 case IRQ_SSP:
370 mask = ADXER_MFP_WSSP1;
371 break;
372 case IRQ_RTCAlrm:
373 mask = ADXER_WRTC;
374 break;
375 case IRQ_SSP4:
376 mask = ADXER_MFP_WSSP4;
377 break;
378 case IRQ_TSI:
379 mask = ADXER_WTSI;
380 break;
381 case IRQ_USIM2:
382 mask = ADXER_WUSIM1;
383 break;
384 case IRQ_MMC2:
385 mask = ADXER_MFP_WMMC2;
386 break;
387 case IRQ_NAND:
388 mask = ADXER_MFP_WFLASH;
389 break;
390 case IRQ_USB2:
391 mask = ADXER_WUSB2;
392 break;
393 case IRQ_WAKEUP0:
394 mask = ADXER_WEXTWAKE0;
395 break;
396 case IRQ_WAKEUP1:
397 mask = ADXER_WEXTWAKE1;
398 break;
399 case IRQ_MMC3:
400 mask = ADXER_MFP_GEN12;
401 break;
402 }
403
404 local_irq_save(flags);
405 if (on)
406 wakeup_src |= mask;
407 else
408 wakeup_src &= ~mask;
409 local_irq_restore(flags);
410
411 return 0;
412}
413
414static void pxa3xx_init_irq_pm(void)
415{
416 pxa_init_irq_set_wake(pxa3xx_set_wake);
417}
418
419#else
420static inline void pxa3xx_init_pm(void) {}
421static inline void pxa3xx_init_irq_pm(void) {}
422#endif
423
204void __init pxa3xx_init_irq(void) 424void __init pxa3xx_init_irq(void)
205{ 425{
206 /* enable CP6 access */ 426 /* enable CP6 access */
@@ -212,6 +432,7 @@ void __init pxa3xx_init_irq(void)
212 pxa_init_irq_low(); 432 pxa_init_irq_low();
213 pxa_init_irq_high(); 433 pxa_init_irq_high();
214 pxa_init_irq_gpio(128); 434 pxa_init_irq_gpio(128);
435 pxa3xx_init_irq_pm();
215} 436}
216 437
217/* 438/*
@@ -241,6 +462,8 @@ static int __init pxa3xx_init(void)
241 if ((ret = pxa_init_dma(32))) 462 if ((ret = pxa_init_dma(32)))
242 return ret; 463 return ret;
243 464
465 pxa3xx_init_pm();
466
244 return platform_add_devices(devices, ARRAY_SIZE(devices)); 467 return platform_add_devices(devices, ARRAY_SIZE(devices));
245 } 468 }
246 return 0; 469 return 0;
diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S
index 434a6ab0eca5..167412e6bec8 100644
--- a/arch/arm/mach-pxa/standby.S
+++ b/arch/arm/mach-pxa/standby.S
@@ -32,3 +32,83 @@ ENTRY(pxa_cpu_standby)
32 mov pc, lr 32 mov pc, lr
33 33
34#endif 34#endif
35
36#ifdef CONFIG_PXA3xx
37
38#define MDCNFG 0x0000
39#define MDCNFG_DMCEN (1 << 30)
40#define DDR_HCAL 0x0060
41#define DDR_HCAL_HCRNG 0x1f
42#define DDR_HCAL_HCPROG (1 << 28)
43#define DDR_HCAL_HCEN (1 << 31)
44#define DMCIER 0x0070
45#define DMCIER_EDLP (1 << 29)
46#define DMCISR 0x0078
47#define RCOMP 0x0100
48#define RCOMP_SWEVAL (1 << 31)
49
50ENTRY(pm_enter_standby_start)
51 mov r1, #0xf6000000 @ DMEMC_REG_BASE (MDCNFG)
52 add r1, r1, #0x00100000
53
54 /*
55 * Preload the TLB entry for accessing the dynamic memory
56 * controller registers. Note that page table lookups will
57 * fail until the dynamic memory controller has been
58 * reinitialised - and that includes MMU page table walks.
59 * This also means that only the dynamic memory controller
60 * can be reliably accessed in the code following standby.
61 */
62 ldr r2, [r1] @ Dummy read MDCNFG
63
64 mcr p14, 0, r0, c7, c0, 0
65 .rept 8
66 nop
67 .endr
68
69 ldr r0, [r1, #DDR_HCAL] @ Clear (and wait for) HCEN
70 bic r0, r0, #DDR_HCAL_HCEN
71 str r0, [r1, #DDR_HCAL]
721: ldr r0, [r1, #DDR_HCAL]
73 tst r0, #DDR_HCAL_HCEN
74 bne 1b
75
76 ldr r0, [r1, #RCOMP] @ Initiate RCOMP
77 orr r0, r0, #RCOMP_SWEVAL
78 str r0, [r1, #RCOMP]
79
80 mov r0, #~0 @ Clear interrupts
81 str r0, [r1, #DMCISR]
82
83 ldr r0, [r1, #DMCIER] @ set DMIER[EDLP]
84 orr r0, r0, #DMCIER_EDLP
85 str r0, [r1, #DMCIER]
86
87 ldr r0, [r1, #DDR_HCAL] @ clear HCRNG, set HCPROG, HCEN
88 bic r0, r0, #DDR_HCAL_HCRNG
89 orr r0, r0, #DDR_HCAL_HCEN | DDR_HCAL_HCPROG
90 str r0, [r1, #DDR_HCAL]
91
921: ldr r0, [r1, #DMCISR]
93 tst r0, #DMCIER_EDLP
94 beq 1b
95
96 ldr r0, [r1, #MDCNFG] @ set MDCNFG[DMCEN]
97 orr r0, r0, #MDCNFG_DMCEN
98 str r0, [r1, #MDCNFG]
991: ldr r0, [r1, #MDCNFG]
100 tst r0, #MDCNFG_DMCEN
101 beq 1b
102
103 ldr r0, [r1, #DDR_HCAL] @ set DDR_HCAL[HCRNG]
104 orr r0, r0, #2 @ HCRNG
105 str r0, [r1, #DDR_HCAL]
106
107 ldr r0, [r1, #DMCIER] @ Clear the interrupt
108 bic r0, r0, #0x20000000
109 str r0, [r1, #DMCIER]
110
111 mov pc, lr
112ENTRY(pm_enter_standby_end)
113
114#endif
diff --git a/include/asm-arm/arch-pxa/pxa3xx-regs.h b/include/asm-arm/arch-pxa/pxa3xx-regs.h
index 3900a0ca0bc0..66d54119757c 100644
--- a/include/asm-arm/arch-pxa/pxa3xx-regs.h
+++ b/include/asm-arm/arch-pxa/pxa3xx-regs.h
@@ -14,6 +14,92 @@
14#define __ASM_ARCH_PXA3XX_REGS_H 14#define __ASM_ARCH_PXA3XX_REGS_H
15 15
16/* 16/*
17 * Slave Power Managment Unit
18 */
19#define ASCR __REG(0x40f40000) /* Application Subsystem Power Status/Configuration */
20#define ARSR __REG(0x40f40004) /* Application Subsystem Reset Status */
21#define AD3ER __REG(0x40f40008) /* Application Subsystem Wake-Up from D3 Enable */
22#define AD3SR __REG(0x40f4000c) /* Application Subsystem Wake-Up from D3 Status */
23#define AD2D0ER __REG(0x40f40010) /* Application Subsystem Wake-Up from D2 to D0 Enable */
24#define AD2D0SR __REG(0x40f40014) /* Application Subsystem Wake-Up from D2 to D0 Status */
25#define AD2D1ER __REG(0x40f40018) /* Application Subsystem Wake-Up from D2 to D1 Enable */
26#define AD2D1SR __REG(0x40f4001c) /* Application Subsystem Wake-Up from D2 to D1 Status */
27#define AD1D0ER __REG(0x40f40020) /* Application Subsystem Wake-Up from D1 to D0 Enable */
28#define AD1D0SR __REG(0x40f40024) /* Application Subsystem Wake-Up from D1 to D0 Status */
29#define AGENP __REG(0x40f4002c) /* Application Subsystem General Purpose */
30#define AD3R __REG(0x40f40030) /* Application Subsystem D3 Configuration */
31#define AD2R __REG(0x40f40034) /* Application Subsystem D2 Configuration */
32#define AD1R __REG(0x40f40038) /* Application Subsystem D1 Configuration */
33
34/*
35 * Application Subsystem Configuration bits.
36 */
37#define ASCR_RDH (1 << 31)
38#define ASCR_D1S (1 << 2)
39#define ASCR_D2S (1 << 1)
40#define ASCR_D3S (1 << 0)
41
42/*
43 * Application Reset Status bits.
44 */
45#define ARSR_GPR (1 << 3)
46#define ARSR_LPMR (1 << 2)
47#define ARSR_WDT (1 << 1)
48#define ARSR_HWR (1 << 0)
49
50/*
51 * Application Subsystem Wake-Up bits.
52 */
53#define ADXER_WRTC (1 << 31) /* RTC */
54#define ADXER_WOST (1 << 30) /* OS Timer */
55#define ADXER_WTSI (1 << 29) /* Touchscreen */
56#define ADXER_WUSBH (1 << 28) /* USB host */
57#define ADXER_WUSB2 (1 << 26) /* USB client 2.0 */
58#define ADXER_WMSL0 (1 << 24) /* MSL port 0*/
59#define ADXER_WDMUX3 (1 << 23) /* USB EDMUX3 */
60#define ADXER_WDMUX2 (1 << 22) /* USB EDMUX2 */
61#define ADXER_WKP (1 << 21) /* Keypad */
62#define ADXER_WUSIM1 (1 << 20) /* USIM Port 1 */
63#define ADXER_WUSIM0 (1 << 19) /* USIM Port 0 */
64#define ADXER_WOTG (1 << 16) /* USBOTG input */
65#define ADXER_MFP_WFLASH (1 << 15) /* MFP: Data flash busy */
66#define ADXER_MFP_GEN12 (1 << 14) /* MFP: MMC3/GPIO/OST inputs */
67#define ADXER_MFP_WMMC2 (1 << 13) /* MFP: MMC2 */
68#define ADXER_MFP_WMMC1 (1 << 12) /* MFP: MMC1 */
69#define ADXER_MFP_WI2C (1 << 11) /* MFP: I2C */
70#define ADXER_MFP_WSSP4 (1 << 10) /* MFP: SSP4 */
71#define ADXER_MFP_WSSP3 (1 << 9) /* MFP: SSP3 */
72#define ADXER_MFP_WMAXTRIX (1 << 8) /* MFP: matrix keypad */
73#define ADXER_MFP_WUART3 (1 << 7) /* MFP: UART3 */
74#define ADXER_MFP_WUART2 (1 << 6) /* MFP: UART2 */
75#define ADXER_MFP_WUART1 (1 << 5) /* MFP: UART1 */
76#define ADXER_MFP_WSSP2 (1 << 4) /* MFP: SSP2 */
77#define ADXER_MFP_WSSP1 (1 << 3) /* MFP: SSP1 */
78#define ADXER_MFP_WAC97 (1 << 2) /* MFP: AC97 */
79#define ADXER_WEXTWAKE1 (1 << 1) /* External Wake 1 */
80#define ADXER_WEXTWAKE0 (1 << 0) /* External Wake 0 */
81
82/*
83 * AD3R/AD2R/AD1R bits. R2-R5 are only defined for PXA320.
84 */
85#define ADXR_L2 (1 << 8)
86#define ADXR_R5 (1 << 5)
87#define ADXR_R4 (1 << 4)
88#define ADXR_R3 (1 << 3)
89#define ADXR_R2 (1 << 2)
90#define ADXR_R1 (1 << 1)
91#define ADXR_R0 (1 << 0)
92
93/*
94 * Values for PWRMODE CP15 register
95 */
96#define PXA3xx_PM_S3D4C4 0x07 /* aka deep sleep */
97#define PXA3xx_PM_S2D3C4 0x06 /* aka sleep */
98#define PXA3xx_PM_S0D2C2 0x03 /* aka standby */
99#define PXA3xx_PM_S0D1C2 0x02 /* aka LCD refresh */
100#define PXA3xx_PM_S0D0C1 0x01
101
102/*
17 * Application Subsystem Clock 103 * Application Subsystem Clock
18 */ 104 */
19#define ACCR __REG(0x41340000) /* Application Subsystem Clock Configuration Register */ 105#define ACCR __REG(0x41340000) /* Application Subsystem Clock Configuration Register */