diff options
-rw-r--r-- | bl1/aarch64/bl1_exceptions.S | 2 | ||||
-rw-r--r-- | bl1/bl1_main.c | 26 | ||||
-rw-r--r-- | bl31/bl31_main.c | 4 | ||||
-rw-r--r-- | common/bl_common.c | 24 | ||||
-rw-r--r-- | docs/user-guide.md | 47 | ||||
-rw-r--r-- | include/common/bl_common.h | 2 | ||||
-rw-r--r-- | include/plat/arm/common/arm_def.h | 8 | ||||
-rw-r--r-- | include/plat/arm/common/plat_arm.h | 10 | ||||
-rw-r--r-- | include/plat/arm/css/common/css_pm.h | 1 | ||||
-rw-r--r-- | plat/arm/board/fvp/include/platform_def.h | 6 | ||||
-rw-r--r-- | plat/arm/board/juno/include/platform_def.h | 8 | ||||
-rw-r--r-- | plat/arm/board/juno/juno_pm.c | 78 | ||||
-rw-r--r-- | plat/arm/board/juno/platform.mk | 8 | ||||
-rw-r--r-- | plat/arm/common/aarch64/arm_common.c | 17 | ||||
-rw-r--r-- | plat/arm/common/arm_bl31_setup.c | 11 | ||||
-rw-r--r-- | plat/arm/common/arm_pm.c | 22 | ||||
-rw-r--r-- | plat/arm/css/common/css_pm.c | 85 | ||||
-rw-r--r-- | plat/arm/css/common/css_topology.c | 24 | ||||
-rw-r--r-- | plat/arm/soc/common/soc_css.mk | 2 |
19 files changed, 320 insertions, 65 deletions
diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S index ef390d46..0bd04857 100644 --- a/bl1/aarch64/bl1_exceptions.S +++ b/bl1/aarch64/bl1_exceptions.S @@ -195,7 +195,7 @@ func smc_handler64 b.ne unexpected_sync_exception mov x0, x20 - bl display_boot_progress + bl bl1_print_bl31_ep_info ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] msr elr_el3, x0 diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c index 50cf4e0d..f62f31d5 100644 --- a/bl1/bl1_main.c +++ b/bl1/bl1_main.c @@ -57,6 +57,9 @@ static void __dead2 bl1_run_bl2(entry_point_info_t *bl2_ep) write_spsr_el3(bl2_ep->spsr); write_elr_el3(bl2_ep->pc); + NOTICE("BL1: Booting BL2\n"); + print_entry_point_info(bl2_ep); + eret(bl2_ep->args.arg0, bl2_ep->args.arg1, bl2_ep->args.arg2, @@ -190,31 +193,18 @@ void bl1_main(void) bl1_plat_set_bl2_ep_info(&bl2_image_info, &bl2_ep); bl2_ep.args.arg1 = (unsigned long)bl2_tzram_layout; - NOTICE("BL1: Booting BL2\n"); - INFO("BL1: BL2 address = 0x%llx\n", - (unsigned long long) bl2_ep.pc); - INFO("BL1: BL2 spsr = 0x%x\n", bl2_ep.spsr); - VERBOSE("BL1: BL2 memory layout address = 0x%llx\n", - (unsigned long long) bl2_tzram_layout); - bl1_run_bl2(&bl2_ep); return; } /******************************************************************************* - * Temporary function to print the fact that BL2 has done its job and BL31 is - * about to be loaded. This is needed as long as printfs cannot be used + * Function called just before handing over to BL31 to inform the user about + * the boot progress. In debug mode, also print details about the BL31 image's + * execution context. ******************************************************************************/ -void display_boot_progress(entry_point_info_t *bl31_ep_info) +void bl1_print_bl31_ep_info(const entry_point_info_t *bl31_ep_info) { NOTICE("BL1: Booting BL3-1\n"); - INFO("BL1: BL3-1 address = 0x%llx\n", - (unsigned long long)bl31_ep_info->pc); - INFO("BL1: BL3-1 spsr = 0x%llx\n", - (unsigned long long)bl31_ep_info->spsr); - INFO("BL1: BL3-1 params address = 0x%llx\n", - (unsigned long long)bl31_ep_info->args.arg0); - INFO("BL1: BL3-1 plat params address = 0x%llx\n", - (unsigned long long)bl31_ep_info->args.arg1); + print_entry_point_info(bl31_ep_info); } diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index a244a5cc..9abc395b 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -149,9 +149,7 @@ void bl31_prepare_next_image_entry(void) INFO("BL3-1: Preparing for EL3 exit to %s world\n", (image_type == SECURE) ? "secure" : "normal"); - INFO("BL3-1: Next image address = 0x%llx\n", - (unsigned long long) next_image_info->pc); - INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info->spsr); + print_entry_point_info(next_image_info); cm_init_my_context(next_image_info); cm_prepare_el3_exit(image_type); } diff --git a/common/bl_common.c b/common/bl_common.c index aeda69aa..0eeef83f 100644 --- a/common/bl_common.c +++ b/common/bl_common.c @@ -352,3 +352,27 @@ int load_auth_image(meminfo_t *mem_layout, return 0; } + +/******************************************************************************* + * Print the content of an entry_point_info_t structure. + ******************************************************************************/ +void print_entry_point_info(const entry_point_info_t *ep_info) +{ + INFO("Entry point address = 0x%llx\n", + (unsigned long long) ep_info->pc); + INFO("SPSR = 0x%lx\n", (unsigned long) ep_info->spsr); + +#define PRINT_IMAGE_ARG(n) \ + VERBOSE("Argument #" #n " = 0x%llx\n", \ + (unsigned long long) ep_info->args.arg##n) + + PRINT_IMAGE_ARG(0); + PRINT_IMAGE_ARG(1); + PRINT_IMAGE_ARG(2); + PRINT_IMAGE_ARG(3); + PRINT_IMAGE_ARG(4); + PRINT_IMAGE_ARG(5); + PRINT_IMAGE_ARG(6); + PRINT_IMAGE_ARG(7); +#undef PRINT_IMAGE_ARG +} diff --git a/docs/user-guide.md b/docs/user-guide.md index 8f271cf0..7987d10e 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -1084,6 +1084,52 @@ Please refer to the [Juno Software Guide] to: * Install and run the Juno binaries on the board * Obtain any other Juno software information +### Testing SYSTEM SUSPEND on Juno + +The SYSTEM SUSPEND is a PSCI API which can be used to implement system suspend +to RAM. For more details refer to section 5.16 of [PSCI]. The [Linaro releases] +contains the required SCP and motherboard firmware support for this feature on +Juno. The mainline linux kernel does not yet have support for this feature on +Juno but it is queued to be merged in v4.4. Till that becomes available, the +feature can be tested by using a custom kernel built from the following repo: + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git + cd linux + git checkout firmware/psci-1.0 + +Configure the linux kernel: + + export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-linux-gnu- + make ARCH=arm64 defconfig + +The feature is tested conveniently by using the RTC. Enable the RTC driver in +menuconfig + + make ARCH=arm64 menuconfig + +The PL031 RTC driver can be enabled at the following location in menuconfig + + ARM AMBA PL031 RTC + | Location: + | -> Device Drivers + | -> Real Time Clock + +Build the kernel + + make ARCH=arm64 Image -j8 + +Replace the kernel image in `SOFTWARE/` directory of Juno with the `Image` from +arch/arm64/boot/ of the linux directory as explained in the +[Juno Software Guide]. + +Reset the board and wait for it to boot. At the shell prompt issue the +following command: + + echo +10 > /sys/class/rtc/rtc1/wakealarm + echo -n mem > /sys/power/state + +The Juno board should suspend to RAM and then wakeup after 10 seconds due to +wakeup interrupt from RTC. - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1098,4 +1144,5 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._ [DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php [mbedTLS Repository]: https://github.com/ARMmbed/mbedtls.git [Porting Guide]: ./porting-guide.md +[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)" [Trusted Board Boot]: trusted-board-boot.md diff --git a/include/common/bl_common.h b/include/common/bl_common.h index c687b354..c9a7a3da 100644 --- a/include/common/bl_common.h +++ b/include/common/bl_common.h @@ -242,6 +242,8 @@ extern const char version_string[]; void reserve_mem(uint64_t *free_base, size_t *free_size, uint64_t addr, size_t size); +void print_entry_point_info(const entry_point_info_t *ep_info); + #endif /*__ASSEMBLY__*/ #endif /* __BL_COMMON_H__ */ diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h index c236970a..452c3856 100644 --- a/include/plat/arm/common/arm_def.h +++ b/include/plat/arm/common/arm_def.h @@ -44,7 +44,8 @@ /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define ARM_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL -#define ARM_CLUSTER_COUNT 2ull +#define ARM_CLUSTER_COUNT 2 +#define ARM_SYSTEM_COUNT 1 #define ARM_CACHE_WRITEBACK_SHIFT 6 @@ -54,6 +55,7 @@ */ #define ARM_PWR_LVL0 MPIDR_AFFLVL0 #define ARM_PWR_LVL1 MPIDR_AFFLVL1 +#define ARM_PWR_LVL2 MPIDR_AFFLVL2 /* * Macros for local power states in ARM platforms encoded by State-ID field @@ -179,10 +181,6 @@ #define ADDR_SPACE_SIZE (1ull << 32) -#define PLAT_NUM_PWR_DOMAINS (ARM_CLUSTER_COUNT + \ - PLATFORM_CORE_COUNT) -#define PLAT_MAX_PWR_LVL ARM_PWR_LVL1 - /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index ad41f4f0..044e18ef 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -35,6 +35,7 @@ #include <cassert.h> #include <cpu_data.h> #include <stdint.h> +#include <xlat_tables.h> /* @@ -123,6 +124,11 @@ void arm_configure_mmu_el3(unsigned long total_base, (((lvl1_state) << ARM_LOCAL_PSTATE_WIDTH) | \ arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) +/* Make composite power state parameter till power level 2 */ +#define arm_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \ + (((lvl2_state) << (ARM_LOCAL_PSTATE_WIDTH * 2)) | \ + arm_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type)) + #endif /* __ARM_RECOM_STATE_ID_ENC__ */ @@ -135,10 +141,14 @@ void arm_io_setup(void); /* Security utility functions */ void arm_tzc_setup(void); +/* Systimer utility function */ +void arm_configure_sys_timer(void); + /* PM utility functions */ int arm_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); int arm_validate_ns_entrypoint(uintptr_t entrypoint); +void arm_system_pwr_domain_resume(void); /* Topology utility function */ int arm_check_mpidr(u_register_t mpidr); diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h index c19df92b..ea6a5d25 100644 --- a/include/plat/arm/css/common/css_pm.h +++ b/include/plat/arm/css/common/css_pm.h @@ -44,5 +44,6 @@ void css_pwr_domain_suspend_finish( void __dead2 css_system_off(void); void __dead2 css_system_reset(void); void css_cpu_standby(plat_local_state_t cpu_state); +void css_get_sys_suspend_power_state(psci_power_state_t *req_state); #endif /* __CSS_PM_H__ */ diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index 840676ce..9ada6b2a 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -38,9 +38,13 @@ #include <v2m_def.h> #include "../fvp_def.h" +/* Required platform porting definitions */ +#define PLAT_NUM_PWR_DOMAINS (ARM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) +#define PLAT_MAX_PWR_LVL ARM_PWR_LVL1 /* - * Most platform porting definitions provided by included headers + * Other platform porting definitions are provided by included headers */ /* diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h index ba93254a..39283c56 100644 --- a/plat/arm/board/juno/include/platform_def.h +++ b/plat/arm/board/juno/include/platform_def.h @@ -41,9 +41,13 @@ #include <v2m_def.h> #include "../juno_def.h" - +/* Juno supports system power domain */ +#define PLAT_MAX_PWR_LVL ARM_PWR_LVL2 +#define PLAT_NUM_PWR_DOMAINS (ARM_SYSTEM_COUNT + \ + ARM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) /* - * Most platform porting definitions provided by included headers + * Other platform porting definitions are provided by included headers */ /* diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c new file mode 100644 index 00000000..4b956d2c --- /dev/null +++ b/plat/arm/board/juno/juno_pm.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, 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 <css_pm.h> +#include <plat_arm.h> + +/* + * Custom `validate_power_state` handler for Juno. According to PSCI + * Specification, interrupts targeted to cores in PSCI CPU SUSPEND should + * be able to resume it. On Juno, when the system power domain is suspended, + * the GIC is also powered down. The SCP resumes the final core to be suspend + * when an external wake-up event is received. But the other cores cannot be + * woken up by a targeted interrupt, because GIC doesn't forward these + * interrupts to the SCP. Due to this hardware limitation, we down-grade PSCI + * CPU SUSPEND requests targeted to the system power domain level + * to cluster power domain level. + * + * The system power domain suspend on Juno is only supported only via + * PSCI SYSTEM SUSPEND API. + */ +static int juno_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int rc; + rc = arm_validate_power_state(power_state, req_state); + + /* + * Ensure that the system power domain level is never suspended + * via PSCI CPU SUSPEND API. Currently system suspend is only + * supported via PSCI SYSTEM SUSPEND API. + */ + req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN; + return rc; +} + +/******************************************************************************* + * 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 = { + .pwr_domain_on = css_pwr_domain_on, + .pwr_domain_on_finish = css_pwr_domain_on_finish, + .pwr_domain_off = css_pwr_domain_off, + .cpu_standby = css_cpu_standby, + .pwr_domain_suspend = css_pwr_domain_suspend, + .pwr_domain_suspend_finish = css_pwr_domain_suspend_finish, + .system_off = css_system_off, + .system_reset = css_system_reset, + .validate_power_state = juno_validate_power_state, + .validate_ns_entrypoint = arm_validate_ns_entrypoint, + .get_sys_suspend_power_state = css_get_sys_suspend_power_state +}; diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk index b80cfb30..b711f3d5 100644 --- a/plat/arm/board/juno/platform.mk +++ b/plat/arm/board/juno/platform.mk @@ -33,12 +33,16 @@ PLAT_INCLUDES := -Iplat/arm/board/juno/include PLAT_BL_COMMON_SOURCES := plat/arm/board/juno/aarch64/juno_helpers.S BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \ - lib/cpus/aarch64/cortex_a57.S + lib/cpus/aarch64/cortex_a57.S \ + lib/cpus/aarch64/cortex_a72.S BL2_SOURCES += plat/arm/board/juno/juno_security.c \ BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ - lib/cpus/aarch64/cortex_a57.S + lib/cpus/aarch64/cortex_a57.S \ + lib/cpus/aarch64/cortex_a72.S \ + plat/arm/board/juno/juno_pm.c \ + plat/arm/board/juno/juno_security.c # Enable workarounds for selected Cortex-A57 erratas. ERRATA_A57_806969 := 0 diff --git a/plat/arm/common/aarch64/arm_common.c b/plat/arm/common/aarch64/arm_common.c index 48b4ac80..42641837 100644 --- a/plat/arm/common/aarch64/arm_common.c +++ b/plat/arm/common/aarch64/arm_common.c @@ -32,6 +32,7 @@ #include <cci.h> #include <mmio.h> #include <plat_arm.h> +#include <platform_def.h> #include <xlat_tables.h> @@ -142,3 +143,19 @@ void arm_cci_init(void) { cci_init(PLAT_ARM_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); } + +/******************************************************************************* + * Configures access to the system counter timer module. + ******************************************************************************/ +void arm_configure_sys_timer(void) +{ + unsigned int reg_val; + + reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT); + reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT); + reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT); + mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_ARM_NSTIMER_FRAME_ID), reg_val); + + reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID)); + mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val); +} diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c index 899463ee..923c333c 100644 --- a/plat/arm/common/arm_bl31_setup.c +++ b/plat/arm/common/arm_bl31_setup.c @@ -40,7 +40,6 @@ #include <mmio.h> #include <plat_arm.h> #include <platform.h> -#include <platform_def.h> /* @@ -197,8 +196,6 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, ******************************************************************************/ void arm_bl31_platform_setup(void) { - unsigned int reg_val; - /* Initialize the gic cpu and distributor interfaces */ plat_arm_gic_init(); arm_gic_setup(); @@ -217,13 +214,7 @@ void arm_bl31_platform_setup(void) CNTCR_FCREQ(0) | CNTCR_EN); /* Allow access to the System counter timer module */ - reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT); - reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT); - reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT); - mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_ARM_NSTIMER_FRAME_ID), reg_val); - - reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID)); - mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val); + arm_configure_sys_timer(); /* Initialize power controller before setting up topology */ plat_arm_pwrc_setup(); diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c index 2497588f..d13d2683 100644 --- a/plat/arm/common/arm_pm.c +++ b/plat/arm/common/arm_pm.c @@ -30,7 +30,9 @@ #include <arch_helpers.h> #include <arm_def.h> +#include <arm_gic.h> #include <assert.h> +#include <console.h> #include <errno.h> #include <plat_arm.h> #include <platform_def.h> @@ -148,6 +150,26 @@ int arm_validate_ns_entrypoint(uintptr_t entrypoint) return PSCI_E_INVALID_ADDRESS; } +/****************************************************************************** + * 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 + * resume in arm_bl31_platform_setup(). + *****************************************************************************/ +void arm_system_pwr_domain_resume(void) +{ + console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, + ARM_CONSOLE_BAUDRATE); + + /* Assert system power domain is available on the platform */ + assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); + + arm_gic_setup(); + plat_arm_security_setup(); + + arm_configure_sys_timer(); +} + /******************************************************************************* * Private function to program the mailbox for a cpu before it is released * from reset. This function assumes that the Trusted mail box base is within diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c index c0c615b9..3f468570 100644 --- a/plat/arm/css/common/css_pm.c +++ b/plat/arm/css/common/css_pm.c @@ -31,6 +31,7 @@ #include <arch_helpers.h> #include <assert.h> #include <arm_gic.h> +#include <cassert.h> #include <cci.h> #include <css_pm.h> #include <debug.h> @@ -51,18 +52,30 @@ * The table must be terminated by a NULL entry. */ const unsigned int arm_pm_idle_states[] = { - /* State-id - 0x01 */ - arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, - ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), - /* State-id - 0x02 */ - arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, - ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), - /* State-id - 0x22 */ - arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, - ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), + /* State-id - 0x001 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, + ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), + /* State-id - 0x002 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, + ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), + /* State-id - 0x022 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, + ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), +#if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1 + /* State-id - 0x222 */ + arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, + ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), +#endif 0, }; -#endif +#endif /* __ARM_RECOM_STATE_ID_ENC__ */ + +/* + * All the power management helpers in this file assume at least cluster power + * level is supported. + */ +CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, + assert_max_pwr_lvl_supported_mismatch); /******************************************************************************* * Handler called when a power domain is about to be turned on. The @@ -90,6 +103,16 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); + if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { + /* + * Perform system initialization if woken up from system + * suspend. + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL2] == + ARM_LOCAL_STATE_OFF) + arm_system_pwr_domain_resume(); + } + /* * Perform the common cluster specific operations i.e enable coherency * if this cluster was off. @@ -98,6 +121,18 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) ARM_LOCAL_STATE_OFF) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); + + if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { + /* + * Skip GIC CPU interface and per-CPU Distributor interface + * setups if woken up from system suspend as it is done as + * part of css_system_pwr_domain_resume(). + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL2] == + ARM_LOCAL_STATE_OFF) + return; + } + /* Enable the gic cpu interface */ arm_gic_cpuif_setup(); @@ -114,10 +149,21 @@ 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 */ arm_gic_cpuif_deactivate(); + if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) { + /* + * Check if power down at system power domain level is + * requested. + */ + if (target_state->pwr_domain_state[ARM_PWR_LVL2] == + ARM_LOCAL_STATE_OFF) + system_state = scpi_power_retention; + } + /* Cluster is to be turned off, so disable coherency */ if (target_state->pwr_domain_state[ARM_PWR_LVL1] == ARM_LOCAL_STATE_OFF) { @@ -132,7 +178,7 @@ static void css_power_down_common(const psci_power_state_t *target_state) scpi_set_css_power_state(read_mpidr_el1(), scpi_power_off, cluster_state, - scpi_power_on); + system_state); } /******************************************************************************* @@ -246,6 +292,23 @@ void css_cpu_standby(plat_local_state_t cpu_state) } /******************************************************************************* + * Handler called to return the 'req_state' for system suspend. + ******************************************************************************/ +void css_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + unsigned int i; + + /* + * System Suspend is supported only if the system power domain node + * is implemented. + */ + assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); + + for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; +} + +/******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform will take care of registering the handlers with PSCI. ******************************************************************************/ diff --git a/plat/arm/css/common/css_topology.c b/plat/arm/css/common/css_topology.c index 381e786b..03f81e61 100644 --- a/plat/arm/css/common/css_topology.c +++ b/plat/arm/css/common/css_topology.c @@ -31,26 +31,28 @@ #include <plat_arm.h> /* - * On ARM platforms, by default the cluster power level is treated as the + * On ARM CSS platforms, by default, the system power level is treated as the * highest. The first entry in the power domain descriptor specifies the - * number of cluster power domains i.e. 2. + * number of system power domains i.e. 1. */ -#define CSS_PWR_DOMAINS_AT_MAX_PWR_LVL ARM_CLUSTER_COUNT +#define CSS_PWR_DOMAINS_AT_MAX_PWR_LVL ARM_SYSTEM_COUNT /* - * The CSS power domain tree descriptor. The cluster power domains are - * arranged so that when the PSCI generic code creates the power domain tree, - * the indices of the CPU power domain nodes it allocates match the linear - * indices returned by plat_core_pos_by_mpidr() i.e. - * CLUSTER1 CPUs are allocated indices from 0 to 3 and the higher indices for - * CLUSTER0 CPUs. + * The CSS power domain tree descriptor for dual cluster CSS platforms. + * The cluster power domains are arranged so that when the PSCI generic + * code creates the power domain tree, the indices of the CPU power + * domain nodes it allocates match the linear indices returned by + * plat_core_pos_by_mpidr() i.e. CLUSTER1 CPUs are allocated indices + * from 0 to 3 and the higher indices for CLUSTER0 CPUs. */ const unsigned char arm_power_domain_tree_desc[] = { /* No of root nodes */ CSS_PWR_DOMAINS_AT_MAX_PWR_LVL, - /* No of children for the first node */ + /* No of children for the root node */ + ARM_CLUSTER_COUNT, + /* No of children for the first cluster node */ PLAT_ARM_CLUSTER1_CORE_COUNT, - /* No of children for the second node */ + /* No of children for the second cluster node */ PLAT_ARM_CLUSTER0_CORE_COUNT }; diff --git a/plat/arm/soc/common/soc_css.mk b/plat/arm/soc/common/soc_css.mk index fd51b7f8..d8a99a8c 100644 --- a/plat/arm/soc/common/soc_css.mk +++ b/plat/arm/soc/common/soc_css.mk @@ -37,4 +37,4 @@ PLAT_INCLUDES += -Iinclude/plat/arm/soc/common/ BL2_SOURCES += plat/arm/soc/common/soc_css_security.c -#BL31_SOURCES += +BL31_SOURCES += plat/arm/soc/common/soc_css_security.c |