Browse Source

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
pull/361/head
Sandrine Bailleux 9 years ago
committed by Achin Gupta
parent
commit
804040d106
  1. 3
      docs/porting-guide.md
  2. 3
      include/plat/arm/css/common/css_def.h
  3. 80
      plat/arm/board/fvp/aarch64/fvp_helpers.S
  4. 1
      plat/arm/board/fvp/fvp_def.h
  5. 31
      plat/arm/board/fvp/fvp_pm.c
  6. 30
      plat/arm/css/common/aarch64/css_helpers.S
  7. 32
      plat/arm/css/common/css_pm.c

3
docs/porting-guide.md

@ -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()

3
include/plat/arm/css/common/css_def.h

@ -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

80
plat/arm/board/fvp/aarch64/fvp_helpers.S

@ -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

1
plat/arm/board/fvp/fvp_def.h

@ -139,7 +139,6 @@
/* Entrypoint mailboxes */
#define MBOX_BASE ARM_SHARED_RAM_BASE
#define MBOX_SIZE 0x200
#endif /* __FVP_DEF_H__ */

31
plat/arm/board/fvp/fvp_pm.c

@ -43,11 +43,6 @@
#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;
}

30
plat/arm/css/common/aarch64/css_helpers.S

@ -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
/* -----------------------------------------------------------

32
plat/arm/css/common/css_pm.c

@ -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;
}

Loading…
Cancel
Save