[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