From: eric miao <eric.miao@marvell.com>
Date: Mon, 28 Jan 2008 23:00:02 +0000 (+0000)
Subject: [ARM] pxa: add preliminary suspend/resume code for pxa3xx
X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=c4d1fb627ff3072;p=GitHub%2FLineageOS%2FG12%2Fandroid_kernel_amlogic_linux-4.9.git

[ARM] pxa: add preliminary suspend/resume code for pxa3xx

1. clear RDH bit after resuming back from D3, otherwise, the multi function
   pins will retain the low power state

2. save/restore essential system registers

Signed-off-by: eric miao <eric.miao@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---

diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c
index 6ce35041c7ed..f5809adce298 100644
--- a/arch/arm/mach-pxa/mfp.c
+++ b/arch/arm/mach-pxa/mfp.c
@@ -22,6 +22,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/mfp.h>
 #include <asm/arch/mfp-pxa3xx.h>
+#include <asm/arch/pxa3xx-regs.h>
 
 /* mfp_spin_lock is used to ensure that MFP register configuration
  * (most likely a read-modify-write operation) is atomic, and that
@@ -223,6 +224,14 @@ static int pxa3xx_mfp_resume(struct sys_device *d)
 		struct pxa3xx_mfp_pin *p = &mfp_table[pin];
 		__mfp_config_run(p);
 	}
+
+	/* clear RDH bit when MFP settings are restored
+	 *
+	 * NOTE: the last 3 bits DxS are write-1-to-clear so carefully
+	 * preserve them here in case they will be referenced later
+	 */
+	ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index d0b2afd4368a..e47e67c11afe 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -40,6 +40,7 @@
 #define RO_CLK		60000000
 
 #define ACCR_D0CS	(1 << 26)
+#define ACCR_PCCE	(1 << 11)
 
 /* crystal frequency to static memory controller multiplier (SMCFS) */
 static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
@@ -204,7 +205,6 @@ static struct clk pxa3xx_clks[] = {
 };
 
 #ifdef CONFIG_PM
-#define SLEEP_SAVE_SIZE	4
 
 #define ISRAM_START	0x5c000000
 #define ISRAM_SIZE	SZ_256K
@@ -212,25 +212,29 @@ static struct clk pxa3xx_clks[] = {
 static void __iomem *sram;
 static unsigned long wakeup_src;
 
-static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
-{
-	pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
+#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
 
-	if (CKENA & (1 << CKEN_USBH)) {
-		printk(KERN_ERR "PM: USB host clock not stopped?\n");
-		CKENA &= ~(1 << CKEN_USBH);
-	}
-//	CKENA |= 1 << (CKEN_ISC & 31);
+enum {	SLEEP_SAVE_START = 0,
+	SLEEP_SAVE_CKENA,
+	SLEEP_SAVE_CKENB,
+	SLEEP_SAVE_ACCR,
 
-	/*
-	 * Low power modes require the HSIO2 clock to be enabled.
-	 */
-	CKENB |= 1 << (CKEN_HSIO2 & 31);
+	SLEEP_SAVE_SIZE,
+};
+
+static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
+{
+	SAVE(CKENA);
+	SAVE(CKENB);
+	SAVE(ACCR);
 }
 
 static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
 {
-	CKENB &= ~(1 << (CKEN_HSIO2 & 31));
+	RESTORE(ACCR);
+	RESTORE(CKENA);
+	RESTORE(CKENB);
 }
 
 /*
@@ -266,6 +270,46 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode)
 	printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
 }
 
+/*
+ * NOTE:  currently, the OBM (OEM Boot Module) binary comes along with
+ * PXA3xx development kits assumes that the resuming process continues
+ * with the address stored within the first 4 bytes of SDRAM. The PSPR
+ * register is used privately by BootROM and OBM, and _must_ be set to
+ * 0x5c014000 for the moment.
+ */
+static void pxa3xx_cpu_pm_suspend(void)
+{
+	volatile unsigned long *p = (volatile void *)0xc0000000;
+	unsigned long saved_data = *p;
+
+	extern void pxa3xx_cpu_suspend(void);
+	extern void pxa3xx_cpu_resume(void);
+
+	/* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
+	CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
+	CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
+
+	/* clear and setup wakeup source */
+	AD3SR = ~0;
+	AD3ER = wakeup_src;
+	ASCR = ASCR;
+	ARSR = ARSR;
+
+	PCFR |= (1u << 13);			/* L1_DIS */
+	PCFR &= ~((1u << 12) | (1u << 1));	/* L0_EN | SL_ROD */
+
+	PSPR = 0x5c014000;
+
+	/* overwrite with the resume address */
+	*p = virt_to_phys(pxa3xx_cpu_resume);
+
+	pxa3xx_cpu_suspend();
+
+	*p = saved_data;
+
+	AD3ER = 0;
+}
+
 static void pxa3xx_cpu_pm_enter(suspend_state_t state)
 {
 	/*
@@ -280,6 +324,7 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state)
 		break;
 
 	case PM_SUSPEND_MEM:
+		pxa3xx_cpu_pm_suspend();
 		break;
 	}
 }
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
index 14bb4a93ea52..784716eb7fc5 100644
--- a/arch/arm/mach-pxa/sleep.S
+++ b/arch/arm/mach-pxa/sleep.S
@@ -50,6 +50,108 @@ pxa_cpu_save_sp:
 	str	r0, [r1]
 	ldr	pc, [sp], #4
 
+#ifdef CONFIG_PXA3xx
+/*
+ * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4)
+ *
+ * NOTE:  unfortunately, pxa_cpu_save_cp can not be reused here since
+ * the auxiliary control register address is different between pxa3xx
+ * and pxa{25x,27x}
+ */
+
+ENTRY(pxa3xx_cpu_suspend)
+
+#ifndef CONFIG_IWMMXT
+	mra	r2, r3, acc0
+#endif
+	stmfd	sp!, {r2 - r12, lr}	@ save registers on stack
+
+	mrc	p14, 0, r3, c6, c0, 0		@ clock configuration, for turbo mode
+	mrc	p15, 0, r4, c15, c1, 0		@ CP access reg
+	mrc	p15, 0, r5, c13, c0, 0		@ PID
+	mrc 	p15, 0, r6, c3, c0, 0		@ domain ID
+	mrc 	p15, 0, r7, c2, c0, 0		@ translation table base addr
+	mrc	p15, 0, r8, c1, c0, 1           @ auxiliary control reg
+	mrc 	p15, 0, r9, c1, c0, 0		@ control reg
+
+	bic	r3, r3, #2			@ clear frequency change bit
+
+	@ store them plus current virtual stack ptr on stack
+	mov	r10, sp
+	stmfd	sp!, {r3 - r10}
+
+	@ store physical address of stack pointer
+	mov	r0, sp
+	bl	sleep_phys_sp
+	ldr	r1, =sleep_save_sp
+	str	r0, [r1]
+
+	@ clean data cache
+	bl	xsc3_flush_kern_cache_all
+
+	mov	r0, #0x06		@ S2D3C4 mode
+	mcr	p14, 0, r0, c7, c0, 0	@ enter sleep
+
+20:	b	20b			@ waiting for sleep
+
+	.data
+	.align 5
+/*
+ * pxa3xx_cpu_resume
+ */
+
+ENTRY(pxa3xx_cpu_resume)
+
+	mov	r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE	@ set SVC, irqs off
+	msr	cpsr_c, r0
+
+	ldr	r0, sleep_save_sp		@ stack phys addr
+	ldmfd	r0, {r3 - r9, sp}		@ CP regs + virt stack ptr
+
+	mov	r1, #0
+	mcr	p15, 0, r1, c7, c7, 0		@ invalidate I & D caches, BTB
+	mcr	p15, 0, r1, c7, c10, 4		@ drain write (&fill) buffer
+	mcr	p15, 0, r1, c7, c5, 4		@ flush prefetch buffer
+	mcr	p15, 0, r1, c8, c7, 0   	@ invalidate I & D TLBs
+
+	mcr	p14, 0, r3, c6, c0, 0		@ clock configuration, turbo mode.
+	mcr	p15, 0, r4, c15, c1, 0		@ CP access reg
+	mcr	p15, 0, r5, c13, c0, 0		@ PID
+	mcr 	p15, 0, r6, c3, c0, 0		@ domain ID
+	mcr 	p15, 0, r7, c2, c0, 0		@ translation table base addr
+	mcr	p15, 0, r8, c1, c0, 1           @ auxiliary control reg
+
+	@ temporarily map resume_turn_on_mmu into the page table,
+	@ otherwise prefetch abort occurs after MMU is turned on
+	mov	r1, r7
+	bic	r1, r1, #0x00ff
+	bic	r1, r1, #0x3f00
+	ldr	r2, =0x542e
+
+	adr	r3, resume_turn_on_mmu
+	mov	r3, r3, lsr #20
+	orr	r4, r2, r3, lsl #20
+	ldr	r5, [r1, r3, lsl #2]
+	str     r4, [r1, r3, lsl #2]
+
+	@ Mapping page table address in the page table
+	mov	r6, r1, lsr #20
+	orr	r7, r2, r6, lsl #20
+	ldr	r8, [r1, r6, lsl #2]
+	str	r7, [r1, r6, lsl #2]
+
+	ldr	r2, =pxa3xx_resume_after_mmu	@ absolute virtual address
+	b	resume_turn_on_mmu		@ cache align execution
+
+	.text
+pxa3xx_resume_after_mmu:
+	/* restore the temporary mapping */
+	str	r5, [r1, r3, lsl #2]
+	str	r8, [r1, r6, lsl #2]
+	b	resume_after_mmu
+
+#endif /* CONFIG_PXA3xx */
+
 #ifdef CONFIG_PXA27x
 /*
  * pxa27x_cpu_suspend()
diff --git a/include/asm-arm/arch-pxa/pxa3xx-regs.h b/include/asm-arm/arch-pxa/pxa3xx-regs.h
index 66d54119757c..8e1b3ead827f 100644
--- a/include/asm-arm/arch-pxa/pxa3xx-regs.h
+++ b/include/asm-arm/arch-pxa/pxa3xx-regs.h
@@ -12,6 +12,19 @@
 
 #ifndef __ASM_ARCH_PXA3XX_REGS_H
 #define __ASM_ARCH_PXA3XX_REGS_H
+/*
+ * Service Power Management Unit (MPMU)
+ */
+#define PMCR		__REG(0x40F50000)	/* Power Manager Control Register */
+#define PSR		__REG(0x40F50004)	/* Power Manager S2 Status Register */
+#define PSPR		__REG(0x40F50008)	/* Power Manager Scratch Pad Register */
+#define PCFR		__REG(0x40F5000C)	/* Power Manager General Configuration Register */
+#define PWER		__REG(0x40F50010)	/* Power Manager Wake-up Enable Register */
+#define PWSR		__REG(0x40F50014)	/* Power Manager Wake-up Status Register */
+#define PECR		__REG(0x40F50018)	/* Power Manager EXT_WAKEUP[1:0] Control Register */
+#define DCDCSR		__REG(0x40F50080)	/* DC-DC Controller Status Register */
+#define PVCR		__REG(0x40F50100)	/* Power Manager Voltage Change Control Register */
+#define PCMD(x)		__REG(0x40F50110 + ((x) << 2))
 
 /*
  * Slave Power Managment Unit