diff options
20 files changed, 356 insertions, 176 deletions
diff --git a/common/bl_common.c b/common/bl_common.c index 193e972c..15d5bdee 100644 --- a/common/bl_common.c +++ b/common/bl_common.c @@ -315,14 +315,9 @@ exit: return io_result; } -/******************************************************************************* - * Generic function to load and authenticate an image. The image is actually - * loaded by calling the 'load_image()' function. Therefore, it returns the - * same error codes if the loading operation failed, or -EAUTH if the - * authentication failed. In addition, this function uses recursion to - * authenticate the parent images up to the root of trust. - ******************************************************************************/ -int load_auth_image(unsigned int image_id, image_info_t *image_data) +static int load_auth_image_internal(unsigned int image_id, + image_info_t *image_data, + int is_parent_image) { int rc; @@ -332,7 +327,7 @@ int load_auth_image(unsigned int image_id, image_info_t *image_data) /* Use recursion to authenticate parent images */ rc = auth_mod_get_parent_id(image_id, &parent_id); if (rc == 0) { - rc = load_auth_image(parent_id, image_data); + rc = load_auth_image_internal(parent_id, image_data, 1); if (rc != 0) { return rc; } @@ -351,6 +346,7 @@ int load_auth_image(unsigned int image_id, image_info_t *image_data) (void *)image_data->image_base, image_data->image_size); if (rc != 0) { + /* Authentication error, zero memory and flush it right away. */ memset((void *)image_data->image_base, 0x00, image_data->image_size); flush_dcache_range(image_data->image_base, @@ -362,13 +358,29 @@ int load_auth_image(unsigned int image_id, image_info_t *image_data) * File has been successfully loaded and authenticated. * Flush the image to main memory so that it can be executed later by * any CPU, regardless of cache and MMU state. + * Do it only for child images, not for the parents (certificates). */ - flush_dcache_range(image_data->image_base, image_data->image_size); + if (!is_parent_image) { + flush_dcache_range(image_data->image_base, + image_data->image_size); + } #endif /* TRUSTED_BOARD_BOOT */ return 0; } +/******************************************************************************* + * Generic function to load and authenticate an image. The image is actually + * loaded by calling the 'load_image()' function. Therefore, it returns the + * same error codes if the loading operation failed, or -EAUTH if the + * authentication failed. In addition, this function uses recursion to + * authenticate the parent images up to the root of trust. + ******************************************************************************/ +int load_auth_image(unsigned int image_id, image_info_t *image_data) +{ + return load_auth_image_internal(image_id, image_data, 0); +} + #else /* LOAD_IMAGE_V2 */ /******************************************************************************* @@ -494,18 +506,12 @@ exit: return io_result; } -/******************************************************************************* - * Generic function to load and authenticate an image. The image is actually - * loaded by calling the 'load_image()' function. Therefore, it returns the - * same error codes if the loading operation failed, or -EAUTH if the - * authentication failed. In addition, this function uses recursion to - * authenticate the parent images up to the root of trust. - ******************************************************************************/ -int load_auth_image(meminfo_t *mem_layout, - unsigned int image_id, - uintptr_t image_base, - image_info_t *image_data, - entry_point_info_t *entry_point_info) +static int load_auth_image_internal(meminfo_t *mem_layout, + unsigned int image_id, + uintptr_t image_base, + image_info_t *image_data, + entry_point_info_t *entry_point_info, + int is_parent_image) { int rc; @@ -515,8 +521,8 @@ int load_auth_image(meminfo_t *mem_layout, /* Use recursion to authenticate parent images */ rc = auth_mod_get_parent_id(image_id, &parent_id); if (rc == 0) { - rc = load_auth_image(mem_layout, parent_id, image_base, - image_data, NULL); + rc = load_auth_image_internal(mem_layout, parent_id, image_base, + image_data, NULL, 1); if (rc != 0) { return rc; } @@ -536,6 +542,7 @@ int load_auth_image(meminfo_t *mem_layout, (void *)image_data->image_base, image_data->image_size); if (rc != 0) { + /* Authentication error, zero memory and flush it right away. */ memset((void *)image_data->image_base, 0x00, image_data->image_size); flush_dcache_range(image_data->image_base, @@ -546,13 +553,34 @@ int load_auth_image(meminfo_t *mem_layout, * File has been successfully loaded and authenticated. * Flush the image to main memory so that it can be executed later by * any CPU, regardless of cache and MMU state. + * Do it only for child images, not for the parents (certificates). */ - flush_dcache_range(image_data->image_base, image_data->image_size); + if (!is_parent_image) { + flush_dcache_range(image_data->image_base, + image_data->image_size); + } #endif /* TRUSTED_BOARD_BOOT */ return 0; } +/******************************************************************************* + * Generic function to load and authenticate an image. The image is actually + * loaded by calling the 'load_image()' function. Therefore, it returns the + * same error codes if the loading operation failed, or -EAUTH if the + * authentication failed. In addition, this function uses recursion to + * authenticate the parent images up to the root of trust. + ******************************************************************************/ +int load_auth_image(meminfo_t *mem_layout, + unsigned int image_id, + uintptr_t image_base, + image_info_t *image_data, + entry_point_info_t *entry_point_info) +{ + return load_auth_image_internal(mem_layout, image_id, image_base, + image_data, entry_point_info, 0); +} + #endif /* LOAD_IMAGE_V2 */ /******************************************************************************* diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S index 21ed7ab8..5b735283 100644 --- a/drivers/arm/pl011/aarch32/pl011_console.S +++ b/drivers/arm/pl011/aarch32/pl011_console.S @@ -118,15 +118,15 @@ func console_core_putc 1: /* Check if the transmit FIFO is full */ ldr r2, [r1, #UARTFR] - tst r2, #PL011_UARTFR_TXFF_BIT - beq 1b + tst r2, #PL011_UARTFR_TXFF + bne 1b mov r2, #0xD str r2, [r1, #UARTDR] 2: /* Check if the transmit FIFO is full */ ldr r2, [r1, #UARTFR] - tst r2, #PL011_UARTFR_TXFF_BIT - beq 2b + tst r2, #PL011_UARTFR_TXFF + bne 2b str r0, [r1, #UARTDR] bx lr putc_error: @@ -149,8 +149,8 @@ func console_core_getc 1: /* Check if the receive FIFO is empty */ ldr r1, [r0, #UARTFR] - tst r1, #PL011_UARTFR_RXFE_BIT - beq 1b + tst r1, #PL011_UARTFR_RXFE + bne 1b ldr r1, [r0, #UARTDR] mov r0, r1 bx lr diff --git a/include/drivers/emmc.h b/include/drivers/emmc.h index 5f78dcef..4bd73284 100644 --- a/include/drivers/emmc.h +++ b/include/drivers/emmc.h @@ -131,21 +131,21 @@ typedef struct emmc_ops { } emmc_ops_t; typedef struct emmc_csd { - unsigned char not_used: 1; - unsigned char crc: 7; - unsigned char ecc: 2; - unsigned char file_format: 2; - unsigned char tmp_write_protect: 1; - unsigned char perm_write_protect: 1; - unsigned char copy: 1; - unsigned char file_format_grp: 1; - - unsigned short reserved_1: 5; - unsigned short write_bl_partial: 1; - unsigned short write_bl_len: 4; - unsigned short r2w_factor: 3; - unsigned short default_ecc: 2; - unsigned short wp_grp_enable: 1; + unsigned int not_used: 1; + unsigned int crc: 7; + unsigned int ecc: 2; + unsigned int file_format: 2; + unsigned int tmp_write_protect: 1; + unsigned int perm_write_protect: 1; + unsigned int copy: 1; + unsigned int file_format_grp: 1; + + unsigned int reserved_1: 5; + unsigned int write_bl_partial: 1; + unsigned int write_bl_len: 4; + unsigned int r2w_factor: 3; + unsigned int default_ecc: 2; + unsigned int wp_grp_enable: 1; unsigned int wp_grp_size: 5; unsigned int erase_grp_mult: 5; diff --git a/include/lib/aarch32/smcc_macros.S b/include/lib/aarch32/smcc_macros.S index c80c3e47..4d329f5d 100644 --- a/include/lib/aarch32/smcc_macros.S +++ b/include/lib/aarch32/smcc_macros.S @@ -109,7 +109,13 @@ msr spsr_und, r9 msr sp_und, r10 msr lr_und, r11 - msr spsr, r12 + /* + * Use the `_fsxc` suffix explicitly to instruct the assembler + * to update all the 32 bits of SPSR. Else, by default, the + * assembler assumes `_fc` suffix which only modifies + * f->[31:24] and c->[7:0] bits of SPSR. + */ + msr spsr_fsxc, r12 /* Restore the rest of the general purpose registers */ ldm r0, {r0-r12} diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index 29fcffec..bc32e40f 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -220,4 +220,7 @@ int plat_arm_get_alt_image_source( unsigned int plat_arm_calc_core_pos(u_register_t mpidr); const mmap_region_t *plat_arm_get_mmap(void); +/* Allow platform to override psci_pm_ops during runtime */ +const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops); + #endif /* __PLAT_ARM_H__ */ diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h index 4a6ca816..489275e9 100644 --- a/include/plat/arm/css/common/css_pm.h +++ b/include/plat/arm/css/common/css_pm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,6 +35,12 @@ #include <psci.h> #include <types.h> +/* Macros to read the CSS power domain state */ +#define CSS_CORE_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL0] +#define CSS_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL1] +#define CSS_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\ + (state)->pwr_domain_state[ARM_PWR_LVL2] : 0) + int css_pwr_domain_on(u_register_t mpidr); void css_pwr_domain_on_finish(const psci_power_state_t *target_state); void css_pwr_domain_off(const psci_power_state_t *target_state); diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 66c0c3df..139f7131 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -327,7 +327,7 @@ static int fvp_node_hw_state(u_register_t target_cpu, * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ -const plat_psci_ops_t plat_arm_psci_pm_ops = { +plat_psci_ops_t plat_arm_psci_pm_ops = { .cpu_standby = fvp_cpu_standby, .pwr_domain_on = fvp_pwr_domain_on, .pwr_domain_off = fvp_pwr_domain_off, diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c index c355d94d..c0fa628e 100644 --- a/plat/arm/board/juno/juno_pm.c +++ b/plat/arm/board/juno/juno_pm.c @@ -76,7 +76,7 @@ static int juno_translate_power_state_by_mpidr(u_register_t mpidr, * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform will take care of registering the handlers with PSCI. ******************************************************************************/ -const plat_psci_ops_t plat_arm_psci_pm_ops = { +plat_psci_ops_t plat_arm_psci_pm_ops = { .pwr_domain_on = css_pwr_domain_on, .pwr_domain_on_finish = css_pwr_domain_on_finish, .pwr_domain_off = css_pwr_domain_off, diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c index 1e756a9e..d2e682d4 100644 --- a/plat/arm/common/arm_pm.c +++ b/plat/arm/common/arm_pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,8 +38,11 @@ #include <platform_def.h> #include <psci.h> +/* Allow ARM Standard platforms to override this function */ +#pragma weak plat_arm_psci_override_pm_ops + /* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */ -extern const plat_psci_ops_t plat_arm_psci_pm_ops; +extern plat_psci_ops_t plat_arm_psci_pm_ops; #if ARM_RECOM_STATE_ID_ENC extern unsigned int arm_pm_idle_states[]; @@ -151,6 +154,14 @@ int arm_validate_ns_entrypoint(uintptr_t entrypoint) } /****************************************************************************** + * Default definition on ARM standard platforms to override the plat_psci_ops. + *****************************************************************************/ +const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) +{ + return ops; +} + +/****************************************************************************** * Helper function to resume the platform from system suspend. Reinitialize * the system components which are not in the Always ON power domain. * TODO: Unify the platform setup when waking up from cold boot and system @@ -201,7 +212,7 @@ void arm_program_trusted_mailbox(uintptr_t address) int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { - *psci_ops = &plat_arm_psci_pm_ops; + *psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops); /* Setup mailbox with entry point. */ arm_program_trusted_mailbox(sec_entrypoint); diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk index 65e125ea..86ba6df5 100644 --- a/plat/arm/css/common/css_common.mk +++ b/plat/arm/css/common/css_common.mk @@ -41,18 +41,18 @@ PLAT_BL_COMMON_SOURCES += plat/arm/css/common/aarch64/css_helpers.S BL1_SOURCES += plat/arm/css/common/css_bl1_setup.c BL2_SOURCES += plat/arm/css/common/css_bl2_setup.c \ - plat/arm/css/common/css_mhu.c \ - plat/arm/css/common/css_scpi.c + plat/arm/css/drivers/scpi/css_mhu.c \ + plat/arm/css/drivers/scpi/css_scpi.c BL2U_SOURCES += plat/arm/css/common/css_bl2u_setup.c \ - plat/arm/css/common/css_mhu.c \ - plat/arm/css/common/css_scpi.c - -BL31_SOURCES += plat/arm/css/common/css_mhu.c \ - plat/arm/css/common/css_pm.c \ - plat/arm/css/common/css_scpi.c \ - plat/arm/css/common/css_topology.c - + plat/arm/css/drivers/scpi/css_mhu.c \ + plat/arm/css/drivers/scpi/css_scpi.c + +BL31_SOURCES += plat/arm/css/common/css_pm.c \ + plat/arm/css/common/css_topology.c \ + plat/arm/css/drivers/scp/css_pm_scpi.c \ + plat/arm/css/drivers/scpi/css_mhu.c \ + plat/arm/css/drivers/scpi/css_scpi.c ifneq (${RESET_TO_BL31},0) $(error "Using BL31 as the reset vector is not supported on CSS platforms. \ diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index 7607f617..d4dd0af7 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -37,13 +37,7 @@ #include <plat_arm.h> #include <platform.h> #include <platform_def.h> -#include "css_scpi.h" - -/* Macros to read the CSS power domain state */ -#define CSS_CORE_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL0] -#define CSS_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL1] -#define CSS_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\ - (state)->pwr_domain_state[ARM_PWR_LVL2] : 0) +#include "../drivers/scp/css_scp.h" /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */ #pragma weak plat_arm_psci_pm_ops @@ -87,12 +81,7 @@ CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, ******************************************************************************/ 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 - */ - scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, - scpi_power_on); + css_scp_on(mpidr); return PSCI_E_SUCCESS; } @@ -140,30 +129,12 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) ******************************************************************************/ static void css_power_down_common(const psci_power_state_t *target_state) { - uint32_t cluster_state = scpi_power_on; - uint32_t system_state = scpi_power_on; - /* Prevent interrupts from spuriously waking up this cpu */ plat_arm_gic_cpuif_disable(); - /* Check if power down at system power domain level is requested */ - if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) - system_state = scpi_power_retention; - /* Cluster is to be turned off, so disable coherency */ - if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) { + if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) plat_arm_interconnect_exit_coherency(); - cluster_state = scpi_power_off; - } - - /* - * Ask the SCP to power down the appropriate components depending upon - * their state. - */ - scpi_set_css_power_state(read_mpidr_el1(), - scpi_power_off, - cluster_state, - system_state); } /******************************************************************************* @@ -174,6 +145,7 @@ void css_pwr_domain_off(const psci_power_state_t *target_state) { assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); css_power_down_common(target_state); + css_scp_off(target_state); } /******************************************************************************* @@ -191,6 +163,7 @@ void css_pwr_domain_suspend(const psci_power_state_t *target_state) assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); css_power_down_common(target_state); + css_scp_suspend(target_state); } /******************************************************************************* @@ -222,34 +195,12 @@ void css_pwr_domain_suspend_finish( ******************************************************************************/ void __dead2 css_system_off(void) { - uint32_t response; - - /* Send the power down request to the SCP */ - response = scpi_sys_power_state(scpi_system_shutdown); - - if (response != SCP_OK) { - ERROR("CSS System Off: SCP error %u.\n", response); - panic(); - } - wfi(); - ERROR("CSS System Off: operation not handled.\n"); - panic(); + css_scp_sys_shutdown(); } void __dead2 css_system_reset(void) { - uint32_t response; - - /* Send the system reset request to the SCP */ - response = scpi_sys_power_state(scpi_system_reboot); - - if (response != SCP_OK) { - ERROR("CSS System Reset: SCP error %u.\n", response); - panic(); - } - wfi(); - ERROR("CSS System Reset: operation not handled.\n"); - panic(); + css_scp_sys_reboot(); } /******************************************************************************* @@ -303,43 +254,14 @@ void css_get_sys_suspend_power_state(psci_power_state_t *req_state) ******************************************************************************/ int css_node_hw_state(u_register_t mpidr, unsigned int power_level) { - int rc, element; - unsigned int cpu_state, cluster_state; - - /* - * The format of 'power_level' is implementation-defined, but 0 must - * mean a CPU. We also allow 1 to denote the cluster - */ - if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1) - return PSCI_E_INVALID_PARAMS; - - /* Query SCP */ - rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state); - if (rc != 0) - return PSCI_E_INVALID_PARAMS; - - /* Map power states of CPU and cluster to expected PSCI return codes */ - if (power_level == ARM_PWR_LVL0) { - /* - * The CPU state returned by SCP is an 8-bit bit mask - * corresponding to each CPU in the cluster - */ - element = mpidr & MPIDR_AFFLVL_MASK; - return CSS_CPU_PWR_STATE(cpu_state, element) == - CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF; - } else { - assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON || - cluster_state == CSS_CLUSTER_PWR_STATE_OFF); - return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON : - HW_OFF; - } + return css_scp_get_power_state(mpidr, power_level); } /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform will take care of registering the handlers with PSCI. ******************************************************************************/ -const plat_psci_ops_t plat_arm_psci_pm_ops = { +plat_psci_ops_t plat_arm_psci_pm_ops = { .pwr_domain_on = css_pwr_domain_on, .pwr_domain_on_finish = css_pwr_domain_on_finish, .pwr_domain_off = css_pwr_domain_off, diff --git a/plat/arm/css/common/css_scp_bootloader.c b/plat/arm/css/common/css_scp_bootloader.c index d3f671e2..049afe4e 100644 --- a/plat/arm/css/common/css_scp_bootloader.c +++ b/plat/arm/css/common/css_scp_bootloader.c @@ -34,9 +34,9 @@ #include <debug.h> #include <platform.h> #include <stdint.h> -#include "css_mhu.h" +#include "../drivers/scpi/css_mhu.h" +#include "../drivers/scpi/css_scpi.h" #include "css_scp_bootloader.h" -#include "css_scpi.h" /* ID of the MHU slot used for the BOM protocol */ #define BOM_MHU_SLOT_ID 0 diff --git a/plat/arm/css/drivers/scp/css_pm_scpi.c b/plat/arm/css/drivers/scp/css_pm_scpi.c new file mode 100644 index 00000000..e22504d1 --- /dev/null +++ b/plat/arm/css/drivers/scp/css_pm_scpi.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <css_pm.h> +#include <debug.h> +#include "../scpi/css_scpi.h" +#include "css_scp.h" + +/* + * This file implements the SCP power management functions using SCPI protocol. + */ + +/* + * Helper function to inform power down state to SCP. + */ +void css_scp_suspend(const psci_power_state_t *target_state) +{ + uint32_t cluster_state = scpi_power_on; + uint32_t system_state = scpi_power_on; + + /* Check if power down at system power domain level is requested */ + if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) + system_state = scpi_power_retention; + + /* Cluster is to be turned off, so disable coherency */ + if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) + cluster_state = scpi_power_off; + + /* + * Ask the SCP to power down the appropriate components depending upon + * their state. + */ + scpi_set_css_power_state(read_mpidr_el1(), + scpi_power_off, + cluster_state, + system_state); +} + +/* + * Helper function to turn off a CPU power domain and its parent power domains + * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we + * call the suspend helper here. + */ +void css_scp_off(const psci_power_state_t *target_state) +{ + css_scp_suspend(target_state); +} + +/* + * Helper function to turn ON a CPU power domain and its parent power domains + * if applicable. + */ +void css_scp_on(u_register_t mpidr) +{ + /* + * SCP takes care of powering up parent power domains so we + * only need to care about level 0 + */ + scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, + scpi_power_on); +} + +/* + * Helper function to get the power state of a power domain node as reported + * by the SCP. + */ +int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) +{ + int rc, element; + unsigned int cpu_state, cluster_state; + + /* + * The format of 'power_level' is implementation-defined, but 0 must + * mean a CPU. We also allow 1 to denote the cluster + */ + if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1) + return PSCI_E_INVALID_PARAMS; + + /* Query SCP */ + rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state); + if (rc != 0) + return PSCI_E_INVALID_PARAMS; + + /* Map power states of CPU and cluster to expected PSCI return codes */ + if (power_level == ARM_PWR_LVL0) { + /* + * The CPU state returned by SCP is an 8-bit bit mask + * corresponding to each CPU in the cluster + */ + element = mpidr & MPIDR_AFFLVL_MASK; + return CSS_CPU_PWR_STATE(cpu_state, element) == + CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF; + } else { + assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON || + cluster_state == CSS_CLUSTER_PWR_STATE_OFF); + return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON : + HW_OFF; + } +} + +/* + * Helper function to shutdown the system via SCPI. + */ +void __dead2 css_scp_sys_shutdown(void) +{ + uint32_t response; + + /* Send the power down request to the SCP */ + response = scpi_sys_power_state(scpi_system_shutdown); + + if (response != SCP_OK) { + ERROR("CSS System Off: SCP error %u.\n", response); + panic(); + } + wfi(); + ERROR("CSS System Off: operation not handled.\n"); + panic(); +} + +/* + * Helper function to reset the system via SCPI. + */ +void __dead2 css_scp_sys_reboot(void) +{ + uint32_t response; + + /* Send the system reset request to the SCP */ + response = scpi_sys_power_state(scpi_system_reboot); + + if (response != SCP_OK) { + ERROR("CSS System Reset: SCP error %u.\n", response); + panic(); + } + wfi(); + ERROR("CSS System Reset: operation not handled.\n"); + panic(); +} diff --git a/plat/arm/css/drivers/scp/css_scp.h b/plat/arm/css/drivers/scp/css_scp.h new file mode 100644 index 00000000..a12798b6 --- /dev/null +++ b/plat/arm/css/drivers/scp/css_scp.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CSS_SCP_H__ +#define __CSS_SCP_H__ + +#include <psci.h> + +void css_scp_suspend(const psci_power_state_t *target_state); +void css_scp_off(const psci_power_state_t *target_state); +void css_scp_on(u_register_t mpidr); +int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level); +void __dead2 css_scp_sys_shutdown(void); +void __dead2 css_scp_sys_reboot(void); + +#endif /* __CSS_SCP_H__ */ diff --git a/plat/arm/css/common/css_mhu.c b/plat/arm/css/drivers/scpi/css_mhu.c index 265d6c25..302286fc 100644 --- a/plat/arm/css/common/css_mhu.c +++ b/plat/arm/css/drivers/scpi/css_mhu.c @@ -33,8 +33,8 @@ #include <bakery_lock.h> #include <css_def.h> #include <mmio.h> -#include <platform_def.h> #include <plat_arm.h> +#include <platform_def.h> #include "css_mhu.h" /* SCP MHU secure channel registers */ diff --git a/plat/arm/css/common/css_mhu.h b/plat/arm/css/drivers/scpi/css_mhu.h index 2175cdf9..6973a140 100644 --- a/plat/arm/css/common/css_mhu.h +++ b/plat/arm/css/drivers/scpi/css_mhu.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/plat/arm/css/common/css_scpi.c b/plat/arm/css/drivers/scpi/css_scpi.c index 90a8939d..f419abd0 100644 --- a/plat/arm/css/common/css_scpi.c +++ b/plat/arm/css/drivers/scpi/css_scpi.c @@ -63,9 +63,11 @@ static void scpi_secure_message_start(void) static void scpi_secure_message_send(size_t payload_size) { - /* Ensure that any write to the SCPI payload area is seen by SCP before + /* + * Ensure that any write to the SCPI payload area is seen by SCP before * we write to the MHU register. If these 2 writes were reordered by - * the CPU then SCP would read stale payload data */ + * the CPU then SCP would read stale payload data + */ dmbst(); mhu_secure_message_send(SCPI_MHU_SLOT_ID); @@ -86,9 +88,11 @@ static void scpi_secure_message_receive(scpi_cmd_t *cmd) panic(); } - /* Ensure that any read to the SCPI payload area is done after reading + /* + * Ensure that any read to the SCPI payload area is done after reading * the MHU register. If these 2 reads were reordered then the CPU would - * read invalid payload data */ + * read invalid payload data + */ dmbld(); memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); @@ -137,8 +141,9 @@ int scpi_wait_ready(void) return status == SCP_OK ? 0 : -1; } -void scpi_set_css_power_state(unsigned mpidr, scpi_power_state_t cpu_state, - scpi_power_state_t cluster_state, scpi_power_state_t css_state) +void scpi_set_css_power_state(unsigned int mpidr, + scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, + scpi_power_state_t css_state) { scpi_cmd_t *cmd; uint32_t state = 0; diff --git a/plat/arm/css/common/css_scpi.h b/plat/arm/css/drivers/scpi/css_scpi.h index 1fb55e4d..d1e7cba4 100644 --- a/plat/arm/css/common/css_scpi.h +++ b/plat/arm/css/drivers/scpi/css_scpi.h @@ -122,7 +122,7 @@ typedef enum { } scpi_system_state_t; extern int scpi_wait_ready(void); -extern void scpi_set_css_power_state(unsigned mpidr, +extern void scpi_set_css_power_state(unsigned int mpidr, scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, scpi_power_state_t css_state); diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S index 069d96d0..802e1fe6 100644 --- a/plat/common/aarch32/platform_helpers.S +++ b/plat/common/aarch32/platform_helpers.S @@ -31,27 +31,12 @@ #include <arch.h> #include <asm_macros.S> - .weak plat_my_core_pos .weak plat_reset_handler .weak plat_disable_acp .weak platform_mem_init .weak plat_panic_handler /* ----------------------------------------------------- - * int plat_my_core_pos(void); - * With this function: CorePos = (ClusterId * 4) + - * CoreId - * ----------------------------------------------------- - */ -func plat_my_core_pos - ldcopr r0, MPIDR - and r1, r0, #MPIDR_CPU_MASK - and r0, r0, #MPIDR_CLUSTER_MASK - add r0, r1, r0, LSR #6 - bx lr -endfunc plat_my_core_pos - - /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. * ----------------------------------------------------- diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c index 4c688caa..78a68ba0 100644 --- a/services/spd/trusty/trusty.c +++ b/services/spd/trusty/trusty.c @@ -236,7 +236,12 @@ static int32_t trusty_init(void) int reg_width = GET_RW(read_ctx_reg(get_el3state_ctx(&ctx->cpu_ctx), CTX_SPSR_EL3)); + /* + * Get information about the Trusty image. Its absence is a critical + * failure. + */ ep_info = bl31_plat_get_next_image_ep_info(SECURE); + assert(ep_info); cm_el1_sysregs_context_save(NON_SECURE); |