From: Wang Dongsheng <dongsheng.w...@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.w...@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@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@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@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@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to