[U-Boot] [PATCH] powerpc/fsl: support low power boot for e500 and later

Dongsheng Wang dongsheng.wang at freescale.com
Thu Jan 15 07:04:32 CET 2015


From: Wang Dongsheng <dongsheng.wang at freescale.com>

low power boot means u-boot will put non-boot cpus into a low power
status. Non-boot cpus don't need any more spin wait. e500, e500v2 will
going to DOZE status. e500mc, e5500, e6500rev1 will going to PW10 state.
e6500rev2 will going to PW20 state.

e500/e500v2 will be kicked up by MPIC-IPI, e500mc later will be kicked up
by doorbell.

This feature tested on:
POWER UP TEST:
P1022DS(e500v2),96k times.
P4080(e500mc),  110k times.
T1024(e5500),   83k times.
T4240(e6500),   150k times.

CPU HOTPLUG TEST:
P1022DS(e500v2),1.4 million times.
P4080(e500mc),  1.8 million times.
T1024(e5500),   1.3 million times.
T4240(e6500),   1.1 million times.

Signed-off-by: Wang Dongsheng <dongsheng.wang at freescale.com>

diff --git a/arch/powerpc/cpu/mpc85xx/release.S b/arch/powerpc/cpu/mpc85xx/release.S
index a2c0ad4..a97a1b6 100644
--- a/arch/powerpc/cpu/mpc85xx/release.S
+++ b/arch/powerpc/cpu/mpc85xx/release.S
@@ -297,10 +297,15 @@ __secondary_start_page:
 	mtspr	SPRN_MAS7,r11
 	tlbwe
 
+	li	r6, 0
+
 	/*
 	 * __bootpg_addr has the address of __second_half_boot_page
 	 * jump there in AS=1 space with cache enabled
 	 */
+	.align 6
+	.global jump_half_boot_page
+jump_half_boot_page:
 	lis	r13,toreset(__bootpg_addr)@h
 	ori	r13,r13,toreset(__bootpg_addr)@l
 	lwz	r11,0(r13)
@@ -371,6 +376,9 @@ __second_half_boot_page:
 	 * };
 	 * we pad this struct to 64 bytes so each entry is in its own cacheline
 	 */
+	cmpwi   r6, 1
+	beq	3f
+
 	li	r3,0
 	li	r8,1
 	mfspr	r4,SPRN_PIR
@@ -402,7 +410,132 @@ __second_half_boot_page:
 #endif
 	lwz	r4,ENTRY_ADDR_LOWER(r10)
 	andi.	r11,r4,1
-	bne	3b
+	beq	6f
+
+	li	r6, 0
+	addi	r6, r6, 1
+
+	/* External Interrupt exception. */
+	lis	r7, toreset(jump_half_boot_page)@h
+	mtspr	SPRN_IVPR, r7
+	li	r7, toreset(jump_half_boot_page)@l
+
+#ifdef	CONFIG_E500MC
+	/* e500MC, e5500, e6500 will use doorbell to send ipi signal */
+	mtspr	SPRN_IVOR36, r7
+#endif
+
+	/*
+	 * For e500mc later:
+	 * EE will open in low power state, IVOR4 make sure we can ACK
+	 * trash interrupt and keep we can loop in wait state again until
+	 * the desired interrupt coming.
+	 *
+	 * e500, e500v2:
+	 * Kernel will use MPCI to send ipi signal, so we must set IVOR4.
+	 */
+	mtspr	SPRN_IVOR4, r7
+
+	isync
+
+#ifdef	CONFIG_E500MC
+	/* PW20 & AltiVec idle feature only exists for E6500 */
+	mfspr   r0, SPRN_PVR
+	rlwinm  r11, r0, 16, 16, 31
+	lis     r12, 0
+	ori     r12, r12, PVR_VER_E6500 at l
+	cmpw    r11, r12
+	bne     5f
+
+	/* Fix erratum, e6500 rev1 does not support PW20 & AltiVec idle */
+	rlwinm  r11, r0, 0, 16, 31
+	cmpwi   r11, 0x20
+	blt     5f
+
+#define PW20_WAIT_IDLE_BIT	50 /* 1ms, TB frequency is 41.66MHZ */
+	/* Core Enter PW20 State */
+	mfspr   r7, SPRN_PWRMGTCR0
+	/* Set PW20_WAIT bit, enable pw20 state*/
+	ori     r7, r7, PWRMGTCR0_PW20_WAIT
+	li      r9, PW20_WAIT_IDLE_BIT
+	/* Set Automatic PW20 Core Idle Count */
+	rlwimi  r7, r9, PWRMGTCR0_PW20_ENT_SHIFT, PWRMGTCR0_PW20_ENT
+	mtspr   SPRN_PWRMGTCR0, r7
+
+#define AV_WAIT_IDLE_BIT	50 /* 1ms, TB frequency is 41.66MHZ */
+	/* Let Altivec Enter Idle State */
+	mfspr   r7, SPRN_PWRMGTCR0
+	/* Enable Altivec Idle */
+	oris    r7, r7, PWRMGTCR0_AV_IDLE_PD_EN at h
+	li      r9, AV_WAIT_IDLE_BIT
+	/* Set Automatic AltiVec Idle Count */
+	rlwimi  r7, r9, PWRMGTCR0_AV_IDLE_CNT_SHIFT, PWRMGTCR0_AV_IDLE_CNT
+	mtspr   SPRN_PWRMGTCR0, r7
+
+5:
+	/*
+	 * Set all of cpu PIR-ID is 0, wait kernel send doorbell or MPIC-IPI
+	 * signal.
+	 *
+	 * When kernel kick one of cpus, all cpus will be wakenup. To make
+	 * sure that only the target cpu is effected, other cpus (by checking
+	 * spin_table->addr_l) should go back to low power state.
+	 *
+	 * U-boot has renumber the cpu PIR Why we need to set all of PIR to
+	 * the same value?
+	 * A: Before kernel kicking cpu, the doorbell message was not configured
+	 * for target cpu(cpu_messages->data). If we try to send a
+	 * non-configured message to target cpu, it cannot correctly receive
+	 * doorbell interrput. So SET ALL OF CPU'S PIR to the same value to
+	 * let all cpus catch the interrupt.
+	 *
+	 * Why set PIR to zero?
+	 * A: U-boot cannot know how many cpus will be kicked up(Kernel allow us
+	 * to configure NR_CPUS) and IPI is a per_cpu variable, u-boot cannot
+	 * set a appropriate PIR for every cpu, but the boot cpu(CPU0) always be
+	 * there. So set PIR is zero as a default PIR ID for each CPUs.
+	 */
+
+	li	r7, 0
+	mtspr	SPRN_PIR, r7
+
+	wrteei  1
+	wait
+#else
+	li	r5, 0
+	lis	r5, HID0_DOZE at h
+	mfspr	r7, SPRN_HID0
+	rlwinm	r7, r7, 0, ~(HID0_DOZE | HID0_NAP | HID0_SLEEP)
+	or	r7, r7, r5
+	isync
+	mtspr	SPRN_HID0, r7
+	isync
+
+	mfmsr	r7
+	oris	r7, r7, MSR_WE at h
+	ori	r7, r7, MSR_EE
+	msync
+	mtmsr	r7
+	isync
+5:	bl	5b
+#endif
+6:
+	wrteei	0
+
+	/*
+	 * If proxy mode enable in MPIC, Read EPR to ACK INTERRUPT
+	 * Or proxy mode disable, Kernel will read MPIC to ACK INTERRUPT.
+	 */
+	mfspr	r7, SPRN_EPR
+
+	/* Wait EOI finish */
+7:
+	lwz	r7, ENTRY_PIR(r10)
+	andi.	r7, r7, 0xffff
+	bne	8f
+	bl	7b
+8:
+
 	isync
 
 	/* get the upper bits of the addr */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 2ed51b1..4d49317 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -482,6 +482,7 @@
 #define SPRN_GIVOR8	0x1bb	/* Guest Interrupt Vector Offset Register 8 */
 #define SPRN_GIVOR13	0x1bc	/* Guest Interrupt Vector Offset Register 13 */
 #define SPRN_GIVOR14	0x1bd	/* Guest Interrupt Vector Offset Register 14 */
+#define SPRN_EPR	0x2be	/* External Proxy Register */
 
 /* e500 definitions */
 #define SPRN_L1CFG0	0x203	/* L1 Cache Configuration Register 0 */
@@ -565,6 +566,13 @@
 #define SPRN_BBTAR	0x202	/* Branch Buffer Target Address Register */
 #define SPRN_PID1	0x279	/* Process ID Register 1 */
 #define SPRN_PID2	0x27a	/* Process ID Register 2 */
+#define SPRN_PWRMGTCR0  0x3fb	/* Power management control register 0 */
+#define   PWRMGTCR0_PW20_WAIT		(1 << 14) /* PW20 state enable bit */
+#define   PWRMGTCR0_PW20_ENT_SHIFT	8
+#define   PWRMGTCR0_PW20_ENT		0x3f00
+#define   PWRMGTCR0_AV_IDLE_PD_EN	(1 << 22) /* Altivec idle enable */
+#define   PWRMGTCR0_AV_IDLE_CNT_SHIFT	16
+#define   PWRMGTCR0_AV_IDLE_CNT		0x3f0000
 #define SPRN_MCSR	0x23c	/* Machine Check Syndrome register */
 #define SPRN_MCAR	0x23d	/* Machine Check Address register */
 #define MCSR_MCS	0x80000000	/* Machine Check Summary */
-- 
2.1.0.27.g96db324



More information about the U-Boot mailing list