diff options
-rw-r--r-- | plat/imx/common/imx8_psci.c | 46 | ||||
-rw-r--r-- | plat/imx/common/imx8_topology.c | 3 | ||||
-rw-r--r-- | plat/imx/common/include/plat_imx8.h | 6 | ||||
-rw-r--r-- | plat/imx/imx8qm/imx8qm_psci.c | 106 | ||||
-rw-r--r-- | plat/imx/imx8qm/platform.mk | 1 | ||||
-rw-r--r-- | plat/imx/imx8qx/imx8qx_psci.c | 60 | ||||
-rw-r--r-- | plat/imx/imx8qx/include/platform_def.h | 2 | ||||
-rw-r--r-- | plat/imx/imx8qx/platform.mk | 2 |
8 files changed, 194 insertions, 32 deletions
diff --git a/plat/imx/common/imx8_psci.c b/plat/imx/common/imx8_psci.c new file mode 100644 index 00000000..22a531bf --- /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 <arch.h> +#include <arch_helpers.h> +#include <debug.h> +#include <plat_imx8.h> +#include <sci/sci.h> +#include <stdbool.h> + +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 bcb7d59f..64145c4c 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 27d4c376..a333bfbe 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 <gicv3.h> +#include <psci.h> 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 b9b794be..c37c39c4 100644 --- a/plat/imx/imx8qm/imx8qm_psci.c +++ b/plat/imx/imx8qm/imx8qm_psci.c @@ -15,17 +15,18 @@ #include <sci/sci.h> #include <stdbool.h> +#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 c295e14b..022ad990 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 47233dc8..f1df267a 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 2cd14009..8c861746 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 c16ce6e6..06766189 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 \ |