[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>
diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S
index 434a6ab..167412e 100644
--- a/arch/arm/mach-pxa/standby.S
+++ b/arch/arm/mach-pxa/standby.S
@@ -32,3 +32,83 @@
 	mov	pc, lr
 
 #endif
+
+#ifdef CONFIG_PXA3xx
+
+#define MDCNFG		0x0000
+#define MDCNFG_DMCEN	(1 << 30)
+#define DDR_HCAL	0x0060
+#define DDR_HCAL_HCRNG	0x1f
+#define DDR_HCAL_HCPROG	(1 << 28)
+#define DDR_HCAL_HCEN	(1 << 31)
+#define DMCIER		0x0070
+#define DMCIER_EDLP	(1 << 29)
+#define DMCISR		0x0078
+#define RCOMP		0x0100
+#define RCOMP_SWEVAL	(1 << 31)
+
+ENTRY(pm_enter_standby_start)
+	mov	r1, #0xf6000000		@ DMEMC_REG_BASE (MDCNFG)
+	add	r1, r1, #0x00100000
+
+	/*
+	 * Preload the TLB entry for accessing the dynamic memory
+	 * controller registers.  Note that page table lookups will
+	 * fail until the dynamic memory controller has been
+	 * reinitialised - and that includes MMU page table walks.
+	 * This also means that only the dynamic memory controller
+	 * can be reliably accessed in the code following standby.
+	 */
+	ldr	r2, [r1]		@ Dummy read MDCNFG
+
+	mcr	p14, 0, r0, c7, c0, 0
+	.rept	8
+	nop
+	.endr
+
+	ldr	r0, [r1, #DDR_HCAL]	@ Clear (and wait for) HCEN
+	bic	r0, r0, #DDR_HCAL_HCEN
+	str	r0, [r1, #DDR_HCAL]
+1:	ldr	r0, [r1, #DDR_HCAL]
+	tst	r0, #DDR_HCAL_HCEN
+	bne	1b
+
+	ldr	r0, [r1, #RCOMP]	@ Initiate RCOMP
+	orr	r0, r0, #RCOMP_SWEVAL
+	str	r0, [r1, #RCOMP]
+
+	mov	r0, #~0			@ Clear interrupts
+	str	r0, [r1, #DMCISR]
+
+	ldr	r0, [r1, #DMCIER]	@ set DMIER[EDLP]
+	orr	r0, r0, #DMCIER_EDLP
+	str	r0, [r1, #DMCIER]
+
+	ldr	r0, [r1, #DDR_HCAL]	@ clear HCRNG, set HCPROG, HCEN
+	bic	r0, r0, #DDR_HCAL_HCRNG
+	orr	r0, r0, #DDR_HCAL_HCEN | DDR_HCAL_HCPROG
+	str	r0, [r1, #DDR_HCAL]
+
+1:	ldr	r0, [r1, #DMCISR]
+	tst	r0, #DMCIER_EDLP
+	beq	1b
+
+	ldr	r0, [r1, #MDCNFG]	@ set MDCNFG[DMCEN]
+	orr	r0, r0, #MDCNFG_DMCEN
+	str	r0, [r1, #MDCNFG]
+1:	ldr	r0, [r1, #MDCNFG]
+	tst	r0, #MDCNFG_DMCEN
+	beq	1b
+
+	ldr	r0, [r1, #DDR_HCAL]	@ set DDR_HCAL[HCRNG]
+	orr	r0, r0, #2 @ HCRNG
+	str	r0, [r1, #DDR_HCAL]
+
+	ldr	r0, [r1, #DMCIER]	@ Clear the interrupt
+	bic	r0, r0, #0x20000000
+	str	r0, [r1, #DMCIER]
+
+	mov	pc, lr
+ENTRY(pm_enter_standby_end)
+
+#endif