diff options
-rw-r--r-- | bl31/bl31_main.c | 6 | ||||
-rw-r--r-- | docs/firmware-design.md | 9 | ||||
-rw-r--r-- | include/bl31/services/psci.h | 1 | ||||
-rw-r--r-- | include/drivers/arm/pl011.h | 16 | ||||
-rw-r--r-- | lib/aarch64/xlat_tables.c | 2 | ||||
-rw-r--r-- | services/std_svc/psci/psci_entry.S | 18 | ||||
-rw-r--r-- | services/std_svc/psci/psci_main.c | 48 | ||||
-rw-r--r-- | tools/fip_create/fip_create.c | 2 |
8 files changed, 72 insertions, 30 deletions
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index 1dc0a7a0..ff7caf1d 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -168,9 +168,15 @@ void bl31_prepare_next_image_entry() assert(next_image_info); scr = read_scr(); + scr &= ~SCR_NS_BIT; if (image_type == NON_SECURE) scr |= SCR_NS_BIT; + scr &= ~SCR_RW_BIT; + if ((next_image_info->spsr & (1 << MODE_RW_SHIFT)) == + (MODE_RW_64 << MODE_RW_SHIFT)) + scr |= SCR_RW_BIT; + /* * Tell the context mgmt. library to ensure that SP_EL3 points to * the right context to exit from EL3 correctly. diff --git a/docs/firmware-design.md b/docs/firmware-design.md index a40ddac5..76c27f72 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -219,6 +219,15 @@ access to access controlled components. On the Base FVP a TrustZone controller abstraction layer is initialized which is used to load further bootloader images. +#### BL3-0 (System Control Processor Firmware) image load + +Some systems have a separate System Control Processor (SCP) for power, clock, +reset and system control. BL2 loads the optional BL3-0 image from platform +storage into a platform-specific region of secure memory. The subsequent +handling of BL3-0 is platform specific. Typically the image is transferred into +SCP memory using a platform-specific protocol. The SCP executes BL3-0 and +signals to the Application Processor (AP) for BL2 execution to continue. + #### BL3-1 (EL3 Runtime Firmware) image load BL2 loads the BL3-1 image from platform storage into a platform-specific address diff --git a/include/bl31/services/psci.h b/include/bl31/services/psci.h index 570fe5b8..b6e272c3 100644 --- a/include/bl31/services/psci.h +++ b/include/bl31/services/psci.h @@ -190,6 +190,7 @@ extern void psci_system_reset(void); extern int psci_cpu_on(unsigned long, unsigned long, unsigned long); +extern void __dead2 psci_power_down_wfi(void); extern void psci_aff_on_finish_entry(void); extern void psci_aff_suspend_finish_entry(void); extern void psci_register_spd_pm_hook(const spd_pm_ops_t *); diff --git a/include/drivers/arm/pl011.h b/include/drivers/arm/pl011.h index 12549206..281330e4 100644 --- a/include/drivers/arm/pl011.h +++ b/include/drivers/arm/pl011.h @@ -107,32 +107,32 @@ * Pl011 CPU interface accessors for writing registers ******************************************************************************/ -static inline void pl011_write_ibrd(unsigned int base, unsigned int val) +static inline void pl011_write_ibrd(unsigned long base, unsigned int val) { mmio_write_32(base + UARTIBRD, val); } -static inline void pl011_write_fbrd(unsigned int base, unsigned int val) +static inline void pl011_write_fbrd(unsigned long base, unsigned int val) { mmio_write_32(base + UARTFBRD, val); } -static inline void pl011_write_lcr_h(unsigned int base, unsigned int val) +static inline void pl011_write_lcr_h(unsigned long base, unsigned int val) { mmio_write_32(base + UARTLCR_H, val); } -static inline void pl011_write_ecr(unsigned int base, unsigned int val) +static inline void pl011_write_ecr(unsigned long base, unsigned int val) { mmio_write_32(base + UARTECR, val); } -static inline void pl011_write_cr(unsigned int base, unsigned int val) +static inline void pl011_write_cr(unsigned long base, unsigned int val) { mmio_write_32(base + UARTCR, val); } -static inline void pl011_write_dr(unsigned int base, unsigned int val) +static inline void pl011_write_dr(unsigned long base, unsigned int val) { mmio_write_32(base + UARTDR, val); } @@ -141,12 +141,12 @@ static inline void pl011_write_dr(unsigned int base, unsigned int val) * Pl011 CPU interface accessors for reading registers ******************************************************************************/ -static inline unsigned int pl011_read_fr(unsigned int base) +static inline unsigned int pl011_read_fr(unsigned long base) { return mmio_read_32(base + UARTFR); } -static inline unsigned int pl011_read_dr(unsigned int base) +static inline unsigned int pl011_read_dr(unsigned long base) { return mmio_read_32(base + UARTDR); } diff --git a/lib/aarch64/xlat_tables.c b/lib/aarch64/xlat_tables.c index 6e04f65d..48b07149 100644 --- a/lib/aarch64/xlat_tables.c +++ b/lib/aarch64/xlat_tables.c @@ -173,7 +173,7 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base, unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) * XLAT_TABLE_ENTRIES_SHIFT; unsigned level_size = 1 << level_size_shift; - unsigned level_index_mask = XLAT_TABLE_ENTRIES_MASK << level_size_shift; + unsigned long level_index_mask = XLAT_TABLE_ENTRIES_MASK << level_size_shift; assert(level <= 3); diff --git a/services/std_svc/psci/psci_entry.S b/services/std_svc/psci/psci_entry.S index 256c538d..3d0181a8 100644 --- a/services/std_svc/psci/psci_entry.S +++ b/services/std_svc/psci/psci_entry.S @@ -37,6 +37,7 @@ .globl psci_aff_suspend_finish_entry .globl __psci_cpu_off .globl __psci_cpu_suspend + .globl psci_power_down_wfi /* ----------------------------------------------------- * This cpu has been physically powered up. Depending @@ -120,9 +121,6 @@ func __psci_cpu_off mrs x0, mpidr_el1 bl platform_set_coherent_stack bl psci_cpu_off - mov x1, #PSCI_E_SUCCESS - cmp x0, x1 - b.eq final_wfi mov sp, x19 ldp x19, x20, [sp,#0] add sp, sp, #0x10 @@ -144,9 +142,6 @@ func __psci_cpu_suspend mov x1, x21 mov x2, x22 bl psci_cpu_suspend - mov x1, #PSCI_E_SUCCESS - cmp x0, x1 - b.eq final_wfi mov sp, x19 ldp x21, x22, [sp,#0x10] ldp x19, x20, [sp,#0] @@ -154,7 +149,16 @@ func __psci_cpu_suspend func_epilogue ret -func final_wfi + /* -------------------------------------------- + * This function is called to indicate to the + * power controller that it is safe to power + * down this cpu. It should not exit the wfi + * and will be released from reset upon power + * up. 'wfi_spill' is used to catch erroneous + * exits from wfi. + * -------------------------------------------- + */ +func psci_power_down_wfi dsb sy // ensure write buffer empty wfi wfi_spill: diff --git a/services/std_svc/psci/psci_main.c b/services/std_svc/psci/psci_main.c index 1bcf2166..c0866fb6 100644 --- a/services/std_svc/psci/psci_main.c +++ b/services/std_svc/psci/psci_main.c @@ -90,23 +90,37 @@ int psci_cpu_suspend(unsigned int power_state, if (target_afflvl > MPIDR_MAX_AFFLVL) return PSCI_E_INVALID_PARAMS; + /* Determine the 'state type' in the 'power_state' parameter */ pstate_type = psci_get_pstate_type(power_state); + + /* + * Ensure that we have a platform specific handler for entering + * a standby state. + */ if (pstate_type == PSTATE_TYPE_STANDBY) { - if (psci_plat_pm_ops->affinst_standby) - rc = psci_plat_pm_ops->affinst_standby(power_state); - else + if (!psci_plat_pm_ops->affinst_standby) return PSCI_E_INVALID_PARAMS; - } else { - mpidr = read_mpidr(); - rc = psci_afflvl_suspend(mpidr, - entrypoint, - context_id, - power_state, - MPIDR_AFFLVL0, - target_afflvl); + + rc = psci_plat_pm_ops->affinst_standby(power_state); + assert(rc == PSCI_E_INVALID_PARAMS || rc == PSCI_E_SUCCESS); + return rc; } - assert(rc == PSCI_E_INVALID_PARAMS || rc == PSCI_E_SUCCESS); + /* + * Do what is needed to enter the power down state. Upon success, + * enter the final wfi which will power down this cpu else return + * an error. + */ + mpidr = read_mpidr(); + rc = psci_afflvl_suspend(mpidr, + entrypoint, + context_id, + power_state, + MPIDR_AFFLVL0, + target_afflvl); + if (rc == PSCI_E_SUCCESS) + psci_power_down_wfi(); + assert(rc == PSCI_E_INVALID_PARAMS); return rc; } @@ -127,10 +141,18 @@ int psci_cpu_off(void) rc = psci_afflvl_off(mpidr, MPIDR_AFFLVL0, target_afflvl); /* + * Check if all actions needed to safely power down this cpu have + * successfully completed. Enter a wfi loop which will allow the + * power controller to physically power down this cpu. + */ + if (rc == PSCI_E_SUCCESS) + psci_power_down_wfi(); + + /* * The only error cpu_off can return is E_DENIED. So check if that's * indeed the case. */ - assert (rc == PSCI_E_SUCCESS || rc == PSCI_E_DENIED); + assert (rc == PSCI_E_DENIED); return rc; } diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c index c97204ab..d1802b7f 100644 --- a/tools/fip_create/fip_create.c +++ b/tools/fip_create/fip_create.c @@ -53,7 +53,7 @@ uuid_t uuid_null = {0}; * const char* format_type_str[] = { "RAW", "ELF", "PIC" }; */ -/* Currently only BL2 and BL31 images are supported. */ +/* The images used depends on the platform. */ static entry_lookup_list_t toc_entry_lookup_list[] = { { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2, "bl2", NULL, FLAG_FILENAME }, |