Commit 804040d1 authored by Sandrine Bailleux's avatar Sandrine Bailleux Committed by Achin Gupta
Browse files

PSCI: Use a single mailbox for warm reset for FVP and Juno

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
Showing with 64 additions and 116 deletions
+64 -116
...@@ -468,9 +468,6 @@ return value indicates that the CPU is the primary CPU. ...@@ -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 This function is called before any access to data is made by the firmware, in
order to carry out any essential memory initialization. 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() ### Function: plat_get_rotpk_info()
......
...@@ -39,8 +39,7 @@ ...@@ -39,8 +39,7 @@
*************************************************************************/ *************************************************************************/
#define MHU_PAYLOAD_CACHED 0 #define MHU_PAYLOAD_CACHED 0
#define TRUSTED_MAILBOXES_BASE ARM_TRUSTED_SRAM_BASE #define TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE
#define TRUSTED_MAILBOX_SHIFT 4
#define NSROM_BASE 0x1f000000 #define NSROM_BASE 0x1f000000
#define NSROM_SIZE 0x00001000 #define NSROM_SIZE 0x00001000
......
...@@ -96,29 +96,30 @@ cb_panic: ...@@ -96,29 +96,30 @@ cb_panic:
b cb_panic b cb_panic
endfunc plat_secondary_cold_boot_setup endfunc plat_secondary_cold_boot_setup
/* ---------------------------------------------------------------------
/* -----------------------------------------------------
* unsigned long plat_get_my_entrypoint (void); * unsigned long plat_get_my_entrypoint (void);
* *
* Main job of this routine is to distinguish between * Main job of this routine is to distinguish between a cold and warm
* a cold and warm boot on the current CPU. * boot. On FVP, this information can be queried from the power
* On a cold boot the secondaries first wait for the * controller. The Power Control SYS Status Register (PSYSR) indicates
* platform to be initialized after which they are * the wake-up reason for the CPU.
* hotplugged in. The primary proceeds to perform the *
* platform initialization. * For a cold boot, return 0.
* On a warm boot, each cpu jumps to the address in its * For a warm boot, read the mailbox and return the address it contains.
* mailbox.
* *
* TODO: Not a good idea to save lr in a temp reg
* TODO: PSYSR is a common register and should be * TODO: PSYSR is a common register and should be
* accessed using locks. Since its not possible * accessed using locks. Since its not possible
* to use locks immediately after a cold reset * to use locks immediately after a cold reset
* we are relying on the fact that after a cold * we are relying on the fact that after a cold
* reset all cpus will read the same WK field * reset all cpus will read the same WK field
* ----------------------------------------------------- * ---------------------------------------------------------------------
*/ */
func plat_get_my_entrypoint 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 mrs x2, mpidr_el1
ldr x1, =PWRC_BASE ldr x1, =PWRC_BASE
str w2, [x1, #PSYSR_OFF] str w2, [x1, #PSYSR_OFF]
...@@ -128,46 +129,41 @@ func plat_get_my_entrypoint ...@@ -128,46 +129,41 @@ func plat_get_my_entrypoint
beq warm_reset beq warm_reset
cmp w2, #WKUP_GICREQ cmp w2, #WKUP_GICREQ
beq warm_reset beq warm_reset
/* Cold reset */
mov x0, #0 mov x0, #0
b exit ret
warm_reset: warm_reset:
/* --------------------------------------------- /* ---------------------------------------------------------------------
* A per-cpu mailbox is maintained in the tru- * A mailbox is maintained in the trusted SRAM. It is flushed out of the
* sted DRAM. Its flushed out of the caches * caches after every update using normal memory so it is safe to read
* after every update using normal memory so * it here with SO attributes.
* its safe to read it here with SO attributes * ---------------------------------------------------------------------
* ---------------------------------------------
*/ */
ldr x10, =MBOX_BASE mov_imm x0, MBOX_BASE
bl plat_my_core_pos ldr x0, [x0]
lsl x0, x0, #ARM_CACHE_WRITEBACK_SHIFT
ldr x0, [x10, x0]
cbz x0, _panic cbz x0, _panic
exit: ret
ret x9
_panic: b _panic /* ---------------------------------------------------------------------
* 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 endfunc plat_get_my_entrypoint
/* ----------------------------------------------------- /* ---------------------------------------------------------------------
* void platform_mem_init (void); * void platform_mem_init (void);
* *
* Zero out the mailbox registers in the shared memory. * Nothing to do on FVP, the Trusted SRAM is available straight away
* The mmu is turned off right now and only the primary can * after reset.
* 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
* -----------------------------------------------------
*/ */
func platform_mem_init 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 ret
endfunc platform_mem_init endfunc platform_mem_init
......
...@@ -139,7 +139,6 @@ ...@@ -139,7 +139,6 @@
/* Entrypoint mailboxes */ /* Entrypoint mailboxes */
#define MBOX_BASE ARM_SHARED_RAM_BASE #define MBOX_BASE ARM_SHARED_RAM_BASE
#define MBOX_SIZE 0x200
#endif /* __FVP_DEF_H__ */ #endif /* __FVP_DEF_H__ */
...@@ -43,11 +43,6 @@ ...@@ -43,11 +43,6 @@
#include "fvp_def.h" #include "fvp_def.h"
#include "fvp_private.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 #if ARM_RECOM_STATE_ID_ENC
/* /*
...@@ -74,16 +69,11 @@ const unsigned int arm_pm_idle_states[] = { ...@@ -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 * Private FVP function to program the mailbox for a cpu before it is released
* from reset. * 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; uintptr_t *mailbox = (void *) MBOX_BASE;
mailbox_t *fvp_mboxes; *mailbox = address;
flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox));
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));
} }
/******************************************************************************* /*******************************************************************************
...@@ -150,9 +140,7 @@ int fvp_pwr_domain_on(u_register_t mpidr) ...@@ -150,9 +140,7 @@ int fvp_pwr_domain_on(u_register_t mpidr)
psysr = fvp_pwrc_read_psysr(mpidr); psysr = fvp_pwrc_read_psysr(mpidr);
} while (psysr & PSYSR_AFF_L0); } while (psysr & PSYSR_AFF_L0);
fvp_program_mailbox(mpidr, wakeup_address);
fvp_pwrc_write_pponr(mpidr); fvp_pwrc_write_pponr(mpidr);
return rc; return rc;
} }
...@@ -200,9 +188,6 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) ...@@ -200,9 +188,6 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
/* Get the mpidr for this cpu */ /* Get the mpidr for this cpu */
mpidr = read_mpidr_el1(); 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. */ /* Program the power controller to enable wakeup interrupts. */
fvp_pwrc_set_wen(mpidr); fvp_pwrc_set_wen(mpidr);
...@@ -254,9 +239,6 @@ void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state) ...@@ -254,9 +239,6 @@ void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
*/ */
fvp_pwrc_clr_wen(mpidr); 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 */ /* Enable the gic cpu interface */
arm_gic_cpuif_setup(); arm_gic_cpuif_setup();
...@@ -332,9 +314,8 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, ...@@ -332,9 +314,8 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops) const plat_psci_ops_t **psci_ops)
{ {
*psci_ops = &fvp_plat_psci_ops; *psci_ops = &fvp_plat_psci_ops;
wakeup_address = sec_entrypoint;
flush_dcache_range((unsigned long)&wakeup_address, /* Program the jump address */
sizeof(wakeup_address)); fvp_program_mailbox(sec_entrypoint);
return 0; return 0;
} }
...@@ -53,28 +53,24 @@ cb_panic: ...@@ -53,28 +53,24 @@ cb_panic:
b cb_panic b cb_panic
endfunc plat_secondary_cold_boot_setup endfunc plat_secondary_cold_boot_setup
/* ----------------------------------------------------- /* ---------------------------------------------------------------------
* unsigned long plat_get_my_entrypoint (void); * unsigned long plat_get_my_entrypoint (void);
* *
* Main job of this routine is to distinguish between * Main job of this routine is to distinguish between a cold and a warm
* a cold and warm boot on the current CPU. * boot. On CSS platforms, this distinction is based on the contents of
* On a cold boot the secondaries first wait for the * the Trusted Mailbox. It is initialised to zero by the SCP before the
* platform to be initialized after which they are * AP cores are released from reset. Therefore, a zero mailbox means
* hotplugged in. The primary proceeds to perform the * it's a cold reset.
* platform initialization.
* On a warm boot, each cpu jumps to the address in its
* mailbox.
* *
* 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 func plat_get_my_entrypoint
mov x9, x30 // lr mov_imm x0, TRUSTED_MAILBOX_BASE
bl plat_my_core_pos ldr x0, [x0]
ldr x1, =TRUSTED_MAILBOXES_BASE ret
lsl x0, x0, #TRUSTED_MAILBOX_SHIFT
ldr x0, [x1, x0]
ret x9
endfunc plat_get_my_entrypoint endfunc plat_get_my_entrypoint
/* ----------------------------------------------------------- /* -----------------------------------------------------------
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include <psci.h> #include <psci.h>
#include "css_scpi.h" #include "css_scpi.h"
unsigned long wakeup_address;
#if ARM_RECOM_STATE_ID_ENC #if ARM_RECOM_STATE_ID_ENC
/* /*
...@@ -68,15 +67,11 @@ const unsigned int arm_pm_idle_states[] = { ...@@ -68,15 +67,11 @@ const unsigned int arm_pm_idle_states[] = {
* Private function to program the mailbox for a cpu before it is released * Private function to program the mailbox for a cpu before it is released
* from reset. * 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; uintptr_t *mailbox = (void *) TRUSTED_MAILBOX_BASE;
uint64_t mbox; *mailbox = address;
flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox));
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));
} }
/******************************************************************************* /*******************************************************************************
...@@ -89,12 +84,6 @@ int css_pwr_domain_on(u_register_t mpidr) ...@@ -89,12 +84,6 @@ int css_pwr_domain_on(u_register_t mpidr)
* SCP takes care of powering up parent power domains so we * SCP takes care of powering up parent power domains so we
* only need to care about level 0 * 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_set_css_power_state(mpidr, scpi_power_on, 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) ...@@ -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? */ /* todo: Is this setup only needed after a cold boot? */
arm_gic_pcpu_distif_setup(); 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) ...@@ -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] == assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
ARM_LOCAL_STATE_OFF); 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); css_power_down_common(target_state);
} }
...@@ -297,8 +278,7 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, ...@@ -297,8 +278,7 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
{ {
*psci_ops = &css_ops; *psci_ops = &css_ops;
wakeup_address = sec_entrypoint; /* Setup mailbox with entry point. */
flush_dcache_range((unsigned long)&wakeup_address, css_program_mailbox(sec_entrypoint);
sizeof(wakeup_address));
return 0; return 0;
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment