PSCI: Use a single mailbox for warm reset for FVP and Juno
authorSandrine Bailleux <sandrine.bailleux@arm.com>
Fri, 10 Jul 2015 15:49:31 +0000 (16:49 +0100)
committerAchin Gupta <achin.gupta@arm.com>
Thu, 13 Aug 2015 22:48:06 +0000 (23:48 +0100)
Since there is a unique warm reset entry point, the FVP and Juno
port can use a single mailbox instead of maintaining one per core.
The mailbox gets programmed only once when plat_setup_psci_ops()
is invoked during PSCI initialization. This means mailbox is not
zeroed out during wakeup.

Change-Id: Ieba032a90b43650f970f197340ebb0ce5548d432

docs/porting-guide.md
include/plat/arm/css/common/css_def.h
plat/arm/board/fvp/aarch64/fvp_helpers.S
plat/arm/board/fvp/fvp_def.h
plat/arm/board/fvp/fvp_pm.c
plat/arm/css/common/aarch64/css_helpers.S
plat/arm/css/common/css_pm.c

index 0f10fd46ab829f427b6874666cf4e4e85d1272db..81cbe1be0677b7cd7881e75e93e1f9dd8bb74f3b 100644 (file)
@@ -468,9 +468,6 @@ return value indicates that the CPU is the primary CPU.
 This function is called before any access to data is made by the firmware, in
 order to carry out any essential memory initialization.
 
-The ARM FVP port uses this function to initialize the mailbox memory used for
-providing the warm-boot entry-point addresses.
-
 
 ### Function: plat_get_rotpk_info()
 
index 268438ff69404a86a5790ebff9f70a64a534d06e..e3dd2b0f5099a65a9d9e9a751fc0aa862bd136de 100644 (file)
@@ -39,8 +39,7 @@
  *************************************************************************/
 #define MHU_PAYLOAD_CACHED             0
 
-#define TRUSTED_MAILBOXES_BASE         ARM_TRUSTED_SRAM_BASE
-#define TRUSTED_MAILBOX_SHIFT          4
+#define TRUSTED_MAILBOX_BASE           ARM_TRUSTED_SRAM_BASE
 
 #define NSROM_BASE                     0x1f000000
 #define NSROM_SIZE                     0x00001000
index 2787ee674d3da939c445d67c0f17a5f2c4cd5d7d..9cf3c73c6bab2f7f53c6d73bd7a32427a9387b09 100644 (file)
@@ -96,29 +96,30 @@ cb_panic:
        b       cb_panic
 endfunc plat_secondary_cold_boot_setup
 
-
-       /* -----------------------------------------------------
+       /* ---------------------------------------------------------------------
         * unsigned long plat_get_my_entrypoint (void);
         *
-        * Main job of this routine is to distinguish between
-        * a cold and warm boot on the current CPU.
-        * On a cold boot the secondaries first wait for the
-        * platform to be initialized after which they are
-        * hotplugged in. The primary proceeds to perform the
-        * platform initialization.
-        * On a warm boot, each cpu jumps to the address in its
-        * mailbox.
+        * Main job of this routine is to distinguish between a cold and warm
+        * boot. On FVP, this information can be queried from the power
+        * controller. The Power Control SYS Status Register (PSYSR) indicates
+        * the wake-up reason for the CPU.
+        *
+        * For a cold boot, return 0.
+        * For a warm boot, read the mailbox and return the address it contains.
         *
-        * TODO: Not a good idea to save lr in a temp reg
         * TODO: PSYSR is a common register and should be
         *      accessed using locks. Since its not possible
         *      to use locks immediately after a cold reset
         *      we are relying on the fact that after a cold
         *      reset all cpus will read the same WK field
-        * -----------------------------------------------------
+        * ---------------------------------------------------------------------
         */
 func plat_get_my_entrypoint
-       mov     x9, x30 // lr
+       /* ---------------------------------------------------------------------
+        * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
+        * WakeRequest signal" then it is a warm boot.
+        * ---------------------------------------------------------------------
+        */
        mrs     x2, mpidr_el1
        ldr     x1, =PWRC_BASE
        str     w2, [x1, #PSYSR_OFF]
@@ -128,46 +129,41 @@ func plat_get_my_entrypoint
        beq     warm_reset
        cmp     w2, #WKUP_GICREQ
        beq     warm_reset
+
+       /* Cold reset */
        mov     x0, #0
-       b       exit
+       ret
+
 warm_reset:
-       /* ---------------------------------------------
-        * A per-cpu mailbox is maintained in the tru-
-        * sted DRAM. Its flushed out of the caches
-        * after every update using normal memory so
-        * its safe to read it here with SO attributes
-        * ---------------------------------------------
+       /* ---------------------------------------------------------------------
+        * A mailbox is maintained in the trusted SRAM. It is flushed out of the
+        * caches after every update using normal memory so it is safe to read
+        * it here with SO attributes.
+        * ---------------------------------------------------------------------
         */
-       ldr     x10, =MBOX_BASE
-       bl      plat_my_core_pos
-       lsl     x0, x0, #ARM_CACHE_WRITEBACK_SHIFT
-       ldr     x0, [x10, x0]
+       mov_imm x0, MBOX_BASE
+       ldr     x0, [x0]
        cbz     x0, _panic
-exit:
-       ret     x9
-_panic:        b       _panic
+       ret
+
+       /* ---------------------------------------------------------------------
+        * The power controller indicates this is a warm reset but the mailbox
+        * is empty. This should never happen!
+        * ---------------------------------------------------------------------
+        */
+_panic:
+       b       _panic
 endfunc plat_get_my_entrypoint
 
 
-       /* -----------------------------------------------------
+       /* ---------------------------------------------------------------------
         * void platform_mem_init (void);
         *
-        * Zero out the mailbox registers in the shared memory.
-        * The mmu is turned off right now and only the primary can
-        * ever execute this code. Secondaries will read the
-        * mailboxes using SO accesses. In short, BL31 will
-        * update the mailboxes after mapping the tzdram as
-        * normal memory. It will flush its copy after update.
-        * BL1 will always read the mailboxes with the MMU off
-        * -----------------------------------------------------
+        * Nothing to do on FVP, the Trusted SRAM is available straight away
+        * after reset.
+        * ---------------------------------------------------------------------
         */
 func platform_mem_init
-       ldr     x0, =MBOX_BASE
-       mov     w1, #PLATFORM_CORE_COUNT
-loop:
-       str     xzr, [x0], #CACHE_WRITEBACK_GRANULE
-       subs    w1, w1, #1
-       b.gt    loop
        ret
 endfunc platform_mem_init
 
index 842a287b5ea20d67b27e73256aba11691c79bb4e..692948150bc8c1fb1ed0acac1e6aee3c119f28d3 100644 (file)
 
 /* Entrypoint mailboxes */
 #define MBOX_BASE                      ARM_SHARED_RAM_BASE
-#define MBOX_SIZE                      0x200
 
 
 #endif /* __FVP_DEF_H__ */
index 56d65029259089e277d30a0e5c859bee88126035..8be51054b22dc117d79383a287c04330695c3294 100644 (file)
 #include "fvp_def.h"
 #include "fvp_private.h"
 
-unsigned long wakeup_address;
-
-typedef volatile struct mailbox {
-       unsigned long value __aligned(CACHE_WRITEBACK_GRANULE);
-} mailbox_t;
 
 #if ARM_RECOM_STATE_ID_ENC
 /*
@@ -74,16 +69,11 @@ const unsigned int arm_pm_idle_states[] = {
  * Private FVP function to program the mailbox for a cpu before it is released
  * from reset.
  ******************************************************************************/
-static void fvp_program_mailbox(uint64_t mpidr, uint64_t address)
+static void fvp_program_mailbox(uintptr_t address)
 {
-       uint64_t linear_id;
-       mailbox_t *fvp_mboxes;
-
-       linear_id = plat_arm_calc_core_pos(mpidr);
-       fvp_mboxes = (mailbox_t *)MBOX_BASE;
-       fvp_mboxes[linear_id].value = address;
-       flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
-                          sizeof(unsigned long));
+       uintptr_t *mailbox = (void *) MBOX_BASE;
+       *mailbox = address;
+       flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox));
 }
 
 /*******************************************************************************
@@ -150,9 +140,7 @@ int fvp_pwr_domain_on(u_register_t mpidr)
                psysr = fvp_pwrc_read_psysr(mpidr);
        } while (psysr & PSYSR_AFF_L0);
 
-       fvp_program_mailbox(mpidr, wakeup_address);
        fvp_pwrc_write_pponr(mpidr);
-
        return rc;
 }
 
@@ -200,9 +188,6 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
        /* Get the mpidr for this cpu */
        mpidr = read_mpidr_el1();
 
-       /* Program the jump address for the this cpu */
-       fvp_program_mailbox(mpidr, wakeup_address);
-
        /* Program the power controller to enable wakeup interrupts. */
        fvp_pwrc_set_wen(mpidr);
 
@@ -254,9 +239,6 @@ void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
         */
        fvp_pwrc_clr_wen(mpidr);
 
-       /* Zero the jump address in the mailbox for this cpu */
-       fvp_program_mailbox(mpidr, 0);
-
        /* Enable the gic cpu interface */
        arm_gic_cpuif_setup();
 
@@ -332,9 +314,8 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
                                const plat_psci_ops_t **psci_ops)
 {
        *psci_ops = &fvp_plat_psci_ops;
-       wakeup_address = sec_entrypoint;
 
-       flush_dcache_range((unsigned long)&wakeup_address,
-                               sizeof(wakeup_address));
+       /* Program the jump address */
+       fvp_program_mailbox(sec_entrypoint);
        return 0;
 }
index a8c558b67477ff652cc5b42c90793399978e025d..478d5cf2baf8f2e0cafe73b29191a85c2a6b25b3 100644 (file)
@@ -53,28 +53,24 @@ cb_panic:
        b       cb_panic
 endfunc plat_secondary_cold_boot_setup
 
-       /* -----------------------------------------------------
+       /* ---------------------------------------------------------------------
         * unsigned long plat_get_my_entrypoint (void);
         *
-        * Main job of this routine is to distinguish between
-        * a cold and warm boot on the current CPU.
-        * On a cold boot the secondaries first wait for the
-        * platform to be initialized after which they are
-        * hotplugged in. The primary proceeds to perform the
-        * platform initialization.
-        * On a warm boot, each cpu jumps to the address in its
-        * mailbox.
+        * Main job of this routine is to distinguish between a cold and a warm
+        * boot. On CSS platforms, this distinction is based on the contents of
+        * the Trusted Mailbox. It is initialised to zero by the SCP before the
+        * AP cores are released from reset. Therefore, a zero mailbox means
+        * it's a cold reset.
         *
-        * TODO: Not a good idea to save lr in a temp reg
-        * -----------------------------------------------------
+        * This functions returns the contents of the mailbox, i.e.:
+        *  - 0 for a cold boot;
+        *  - the warm boot entrypoint for a warm boot.
+        * ---------------------------------------------------------------------
         */
 func plat_get_my_entrypoint
-       mov     x9, x30 // lr
-       bl      plat_my_core_pos
-       ldr     x1, =TRUSTED_MAILBOXES_BASE
-       lsl     x0, x0, #TRUSTED_MAILBOX_SHIFT
-       ldr     x0, [x1, x0]
-       ret     x9
+       mov_imm x0, TRUSTED_MAILBOX_BASE
+       ldr     x0, [x0]
+       ret
 endfunc plat_get_my_entrypoint
 
        /* -----------------------------------------------------------
index 49c364d5c279b239b7d08c6d929a66d62b53649b..435ed2aa660c94d00fef13d57d76ba889184bcee 100644 (file)
@@ -41,7 +41,6 @@
 #include <psci.h>
 #include "css_scpi.h"
 
-unsigned long wakeup_address;
 
 #if ARM_RECOM_STATE_ID_ENC
 /*
@@ -68,15 +67,11 @@ const unsigned int arm_pm_idle_states[] = {
  * Private function to program the mailbox for a cpu before it is released
  * from reset.
  ******************************************************************************/
-static void css_program_mailbox(uint64_t mpidr, uint64_t address)
+static void css_program_mailbox(uintptr_t address)
 {
-       uint64_t linear_id;
-       uint64_t mbox;
-
-       linear_id = plat_arm_calc_core_pos(mpidr);
-       mbox = TRUSTED_MAILBOXES_BASE + (linear_id << TRUSTED_MAILBOX_SHIFT);
-       *((uint64_t *) mbox) = address;
-       flush_dcache_range(mbox, sizeof(mbox));
+       uintptr_t *mailbox = (void *) TRUSTED_MAILBOX_BASE;
+       *mailbox = address;
+       flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox));
 }
 
 /*******************************************************************************
@@ -89,12 +84,6 @@ int css_pwr_domain_on(u_register_t mpidr)
         * SCP takes care of powering up parent power domains so we
         * only need to care about level 0
         */
-
-       /*
-        * Setup mailbox with address for CPU entrypoint when it next powers up
-        */
-       css_program_mailbox(mpidr, wakeup_address);
-
        scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
                                 scpi_power_on);
 
@@ -124,9 +113,6 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
 
        /* todo: Is this setup only needed after a cold boot? */
        arm_gic_pcpu_distif_setup();
-
-       /* Clear the mailbox for this cpu. */
-       css_program_mailbox(read_mpidr_el1(), 0);
 }
 
 /*******************************************************************************
@@ -188,11 +174,6 @@ static void css_pwr_domain_suspend(const psci_power_state_t *target_state)
        assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
                                                ARM_LOCAL_STATE_OFF);
 
-       /*
-        * Setup mailbox with address for CPU entrypoint when it next powers up.
-        */
-       css_program_mailbox(read_mpidr_el1(), wakeup_address);
-
        css_power_down_common(target_state);
 }
 
@@ -297,8 +278,7 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
 {
        *psci_ops = &css_ops;
 
-       wakeup_address = sec_entrypoint;
-       flush_dcache_range((unsigned long)&wakeup_address,
-                               sizeof(wakeup_address));
+       /* Setup mailbox with entry point. */
+       css_program_mailbox(sec_entrypoint);
        return 0;
 }