diff --git a/plat/imx/common/imx8_psci.c b/plat/imx/common/imx8_psci.c new file mode 100644 index 0000000000000000000000000000000000000000..22a531bf8313b449d279eddbc7914c23542e9483 --- /dev/null +++ b/plat/imx/common/imx8_psci.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +void __dead2 imx_system_off(void) +{ + sc_pm_set_sys_power_mode(ipc_handle, SC_PM_PW_MODE_OFF); + wfi(); + ERROR("power off failed.\n"); + panic(); +} + +void __dead2 imx_system_reset(void) +{ + sc_pm_reset(ipc_handle, SC_PM_RESET_TYPE_BOARD); + wfi(); + ERROR("system reset failed.\n"); + panic(); +} + +int imx_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + /* TODO */ + return PSCI_E_INVALID_PARAMS; +} + +void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + unsigned int i; + + /* CPU & cluster off, system in retention */ + for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE; +} + diff --git a/plat/imx/common/imx8_topology.c b/plat/imx/common/imx8_topology.c index bcb7d59f041fffb9db3f81a11c258c4f9bfc62b8..64145c4ca89744d9a0b5c79c86882a734967206e 100644 --- a/plat/imx/common/imx8_topology.c +++ b/plat/imx/common/imx8_topology.c @@ -11,7 +11,8 @@ const unsigned char imx_power_domain_tree_desc[] = { PWR_DOMAIN_AT_MAX_LVL, PLATFORM_CLUSTER_COUNT, - PLATFORM_CORE_COUNT, + PLATFORM_CLUSTER0_CORE_COUNT, + PLATFORM_CLUSTER1_CORE_COUNT, }; const unsigned char *plat_get_power_domain_tree_desc(void) diff --git a/plat/imx/common/include/plat_imx8.h b/plat/imx/common/include/plat_imx8.h index 27d4c376e697edc74899ea7010c01ca9be0fed1e..a333bfbe11202a1f4a752ed12a1bdf3661e1c526 100644 --- a/plat/imx/common/include/plat_imx8.h +++ b/plat/imx/common/include/plat_imx8.h @@ -8,6 +8,7 @@ #define __PLAT_IMX8_H__ #include +#include unsigned int plat_calc_core_pos(uint64_t mpidr); void imx_mailbox_init(uintptr_t base_addr); @@ -17,4 +18,9 @@ void plat_gic_cpuif_enable(void); void plat_gic_cpuif_disable(void); void plat_gic_pcpu_init(void); +void __dead2 imx_system_off(void); +void __dead2 imx_system_reset(void); +int imx_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state); +void imx_get_sys_suspend_power_state(psci_power_state_t *req_state); #endif /*__PLAT_IMX8_H__ */ diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c index b9b794becb6e84a17e5ce911d707252ed9b5c90b..c37c39c40313bdf06b09cee00706ede526066edf 100644 --- a/plat/imx/imx8qm/imx8qm_psci.c +++ b/plat/imx/imx8qm/imx8qm_psci.c @@ -15,17 +15,18 @@ #include #include +#define CORE_PWR_STATE(state) \ + ((state)->pwr_domain_state[MPIDR_AFFLVL0]) +#define CLUSTER_PWR_STATE(state) \ + ((state)->pwr_domain_state[MPIDR_AFFLVL1]) +#define SYSTEM_PWR_STATE(state) \ + ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) + const static int ap_core_index[PLATFORM_CORE_COUNT] = { SC_R_A53_0, SC_R_A53_1, SC_R_A53_2, SC_R_A53_3, SC_R_A72_0, SC_R_A72_1, }; -/* need to enable USE_COHERENT_MEM to avoid coherence issue */ -#if USE_COHERENT_MEM -static unsigned int a53_cpu_on_number __section("tzfw_coherent_mem"); -static unsigned int a72_cpu_on_number __section("tzfw_coherent_mem"); -#endif - int imx_pwr_domain_on(u_register_t mpidr) { int ret = PSCI_E_SUCCESS; @@ -37,9 +38,8 @@ int imx_pwr_domain_on(u_register_t mpidr) tf_printf("imx_pwr_domain_on cluster_id %d, cpu_id %d\n", cluster_id, cpu_id); if (cluster_id == 0) { - if (a53_cpu_on_number == 0) - sc_pm_set_resource_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); - + sc_pm_set_resource_power_mode(ipc_handle, SC_R_A53, + SC_PM_PW_MODE_ON); if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON) != SC_ERR_NONE) { ERROR("cluster0 core %d power on failed!\n", cpu_id); @@ -52,9 +52,8 @@ int imx_pwr_domain_on(u_register_t mpidr) ret = PSCI_E_INTERN_FAIL; } } else { - if (a72_cpu_on_number == 0) - sc_pm_set_resource_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); - + sc_pm_set_resource_power_mode(ipc_handle, SC_R_A72, + SC_PM_PW_MODE_ON); if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id + 4], SC_PM_PW_MODE_ON) != SC_ERR_NONE) { ERROR(" cluster1 core %d power on failed!\n", cpu_id); @@ -74,17 +73,56 @@ int imx_pwr_domain_on(u_register_t mpidr) void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint64_t mpidr = read_mpidr_el1(); - unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); - if (cluster_id == 0 && a53_cpu_on_number++ == 0) - cci_enable_snoop_dvm_reqs(0); - if (cluster_id == 1 && a72_cpu_on_number++ == 0) - cci_enable_snoop_dvm_reqs(1); + if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); plat_gic_pcpu_init(); plat_gic_cpuif_enable(); } +void imx_pwr_domain_off(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); + unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); + + plat_gic_cpuif_disable(); + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + cluster_id * 4], + SC_PM_PW_MODE_OFF, + SC_PM_WAKE_SRC_NONE); + if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) + cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + tf_printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id); +} + +void imx_domain_suspend(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); + unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); + + plat_gic_cpuif_disable(); + + cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + + sc_pm_set_cpu_resume_addr(ipc_handle, + ap_core_index[cpu_id + cluster_id * 4], BL31_BASE); + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + cluster_id * 4], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); +} + +void imx_domain_suspend_finish(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + + plat_gic_cpuif_enable(); +} + int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) { return PSCI_E_SUCCESS; @@ -93,22 +131,42 @@ int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) static const plat_psci_ops_t imx_plat_psci_ops = { .pwr_domain_on = imx_pwr_domain_on, .pwr_domain_on_finish = imx_pwr_domain_on_finish, + .pwr_domain_off = imx_pwr_domain_off, + .pwr_domain_suspend = imx_domain_suspend, + .pwr_domain_suspend_finish = imx_domain_suspend_finish, + .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, + .validate_power_state = imx_validate_power_state, .validate_ns_entrypoint = imx_validate_ns_entrypoint, + .system_off = imx_system_off, + .system_reset = imx_system_reset, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { - uint64_t mpidr = read_mpidr_el1(); - unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); - imx_mailbox_init(sec_entrypoint); *psci_ops = &imx_plat_psci_ops; - if (cluster_id == 0) - a53_cpu_on_number++; - else - a72_cpu_on_number++; + /* Request low power mode for cluster/cci, only need to do once */ + sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); + sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF); + sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); + + /* Request RUN and LP modes for DDR, system interconnect etc. */ + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, + SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, + SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, + SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, + SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, + SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, + SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, + SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, + SC_PM_PW_MODE_STBY); return 0; } diff --git a/plat/imx/imx8qm/platform.mk b/plat/imx/imx8qm/platform.mk index c295e14bfd3c3ab56a4c6508844a3e7d2b6a18d6..022ad9902a85646bb30a715660bc033d01146f23 100644 --- a/plat/imx/imx8qm/platform.mk +++ b/plat/imx/imx8qm/platform.mk @@ -21,6 +21,7 @@ BL31_SOURCES += plat/imx/common/lpuart_console.S \ plat/imx/imx8qm/imx8qm_bl31_setup.c \ plat/imx/imx8qm/imx8qm_psci.c \ plat/imx/common/imx8_topology.c \ + plat/imx/common/imx8_psci.c \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ lib/cpus/aarch64/cortex_a53.S \ diff --git a/plat/imx/imx8qx/imx8qx_psci.c b/plat/imx/imx8qx/imx8qx_psci.c index 47233dc8d00e5146f77e6f8e618ace4d2d258a55..f1df267a814c912df1537681d1a054e52dff5c73 100644 --- a/plat/imx/imx8qx/imx8qx_psci.c +++ b/plat/imx/imx8qx/imx8qx_psci.c @@ -18,13 +18,6 @@ const static int ap_core_index[PLATFORM_CORE_COUNT] = { SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3 }; -plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, - const plat_local_state_t *target_state, - unsigned int ncpu) -{ - return 0; -} - int imx_pwr_domain_on(u_register_t mpidr) { int ret = PSCI_E_SUCCESS; @@ -60,10 +53,51 @@ int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) return PSCI_E_SUCCESS; } +void imx_pwr_domain_off(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); + + plat_gic_cpuif_disable(); + sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE); + tf_printf("turn off core:%d\n", cpu_id); +} + +void imx_domain_suspend(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); + + plat_gic_cpuif_disable(); + + sc_pm_set_cpu_resume_addr(ipc_handle, ap_core_index[cpu_id], BL31_BASE); + sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); +} + +void imx_domain_suspend_finish(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); + + sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_ON); + + plat_gic_cpuif_enable(); +} + static const plat_psci_ops_t imx_plat_psci_ops = { .pwr_domain_on = imx_pwr_domain_on, .pwr_domain_on_finish = imx_pwr_domain_on_finish, .validate_ns_entrypoint = imx_validate_ns_entrypoint, + .system_off = imx_system_off, + .system_reset = imx_system_reset, + .pwr_domain_off = imx_pwr_domain_off, + .pwr_domain_suspend = imx_domain_suspend, + .pwr_domain_suspend_finish = imx_domain_suspend_finish, + .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, + .validate_power_state = imx_validate_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, @@ -72,5 +106,17 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, imx_mailbox_init(sec_entrypoint); *psci_ops = &imx_plat_psci_ops; + /* Request low power mode for A35 cluster, only need to do once */ + sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); + + /* Request RUN and LP modes for DDR, system interconnect etc. */ + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, + SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, + SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); + sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, + SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, + SC_PM_PW_MODE_STBY); + return 0; } diff --git a/plat/imx/imx8qx/include/platform_def.h b/plat/imx/imx8qx/include/platform_def.h index 2cd140097db141777b5fd9d9b9e385c201dd8613..8c86174695104ff974f3eb970d215bd3f9a857cf 100644 --- a/plat/imx/imx8qx/include/platform_def.h +++ b/plat/imx/imx8qx/include/platform_def.h @@ -17,6 +17,8 @@ #define PLATFORM_MAX_CPU_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CORE_COUNT 4 +#define PLATFORM_CLUSTER0_CORE_COUNT 4 +#define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PWR_DOMAIN_AT_MAX_LVL 1 #define PLAT_MAX_PWR_LVL 2 diff --git a/plat/imx/imx8qx/platform.mk b/plat/imx/imx8qx/platform.mk index c16ce6e603d3c8a9a2a65c4db9d314ea8251f1aa..067661890bee70b5a30db9c21cf9aad1b4a6e093 100644 --- a/plat/imx/imx8qx/platform.mk +++ b/plat/imx/imx8qx/platform.mk @@ -20,6 +20,8 @@ BL31_SOURCES += plat/imx/common/lpuart_console.S \ plat/imx/imx8qx/imx8qx_bl31_setup.c \ plat/imx/imx8qx/imx8qx_psci.c \ plat/imx/common/imx8_topology.c \ + plat/imx/common/imx8_psci.c \ + plat/common/plat_psci_common.c \ lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/cpus/aarch64/cortex_a35.S \