diff options
author | Antonio Niño Díaz <antonio.ninodiaz@arm.com> | 2019-01-30 09:52:48 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-30 09:52:48 +0000 |
commit | 44b935c09c1f23e8e090097bc594fe07e1f3efef (patch) | |
tree | 332944b4da900fb65c818ae84aecb4d74a8b6737 | |
parent | 7d3884000d671ece18788791de875229f983f079 (diff) | |
parent | e6cf7a468e18143672219caaa7bb0e143833d6a6 (diff) | |
download | arm-trusted-firmware-44b935c09c1f23e8e090097bc594fe07e1f3efef.tar.gz |
Merge pull request #1789 from Anson-Huang/lpm
Add power optimization for i.MX8QM/i.MX8QX
-rw-r--r-- | plat/imx/common/imx8_psci.c | 18 | ||||
-rw-r--r-- | plat/imx/common/include/plat_imx8.h | 7 | ||||
-rw-r--r-- | plat/imx/common/plat_imx8_gic.c | 16 | ||||
-rw-r--r-- | plat/imx/common/sci/imx8_mu.c | 15 | ||||
-rw-r--r-- | plat/imx/common/sci/imx8_mu.h | 1 | ||||
-rw-r--r-- | plat/imx/imx8qm/imx8qm_bl31_setup.c | 10 | ||||
-rw-r--r-- | plat/imx/imx8qm/imx8qm_psci.c | 290 | ||||
-rw-r--r-- | plat/imx/imx8qm/include/platform_def.h | 10 | ||||
-rw-r--r-- | plat/imx/imx8qm/include/sec_rsrc.h | 6 | ||||
-rw-r--r-- | plat/imx/imx8qx/imx8qx_bl31_setup.c | 10 | ||||
-rw-r--r-- | plat/imx/imx8qx/imx8qx_psci.c | 158 | ||||
-rw-r--r-- | plat/imx/imx8qx/include/platform_def.h | 9 | ||||
-rw-r--r-- | plat/imx/imx8qx/include/sec_rsrc.h | 4 |
13 files changed, 444 insertions, 110 deletions
diff --git a/plat/imx/common/imx8_psci.c b/plat/imx/common/imx8_psci.c index 588d8b4e2..91d33705d 100644 --- a/plat/imx/common/imx8_psci.c +++ b/plat/imx/common/imx8_psci.c @@ -32,8 +32,22 @@ void __dead2 imx_system_reset(void) int imx_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { - /* TODO */ - return PSCI_E_INVALID_PARAMS; + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + int pwr_type = psci_get_pstate_type(power_state); + int state_id = psci_get_pstate_id(power_state); + + if (pwr_lvl > PLAT_MAX_PWR_LVL) + return PSCI_E_INVALID_PARAMS; + + if (pwr_type == PSTATE_TYPE_POWERDOWN) { + req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; + if (!state_id) + req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_RET_STATE; + else + req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_OFF_STATE; + } + + return PSCI_E_SUCCESS; } void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) diff --git a/plat/imx/common/include/plat_imx8.h b/plat/imx/common/include/plat_imx8.h index 952ad5302..be99b970f 100644 --- a/plat/imx/common/include/plat_imx8.h +++ b/plat/imx/common/include/plat_imx8.h @@ -10,6 +10,11 @@ #include <drivers/arm/gicv3.h> #include <lib/psci/psci.h> +struct plat_gic_ctx { + gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT]; + gicv3_dist_ctx_t dist_ctx; +}; + unsigned int plat_calc_core_pos(uint64_t mpidr); void imx_mailbox_init(uintptr_t base_addr); void plat_gic_driver_init(void); @@ -24,5 +29,7 @@ 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); bool imx_is_wakeup_src_irqsteer(void); +void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx); +void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx); #endif /* PLAT_IMX8_H */ diff --git a/plat/imx/common/plat_imx8_gic.c b/plat/imx/common/plat_imx8_gic.c index aec0b6c9b..27c525b72 100644 --- a/plat/imx/common/plat_imx8_gic.c +++ b/plat/imx/common/plat_imx8_gic.c @@ -73,3 +73,19 @@ void plat_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } + +void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx) +{ + /* save the gic rdist/dist context */ + for (int i = 0; i < PLATFORM_CORE_COUNT; i++) + gicv3_rdistif_save(i, &ctx->rdist_ctx[i]); + gicv3_distif_save(&ctx->dist_ctx); +} + +void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx) +{ + /* restore the gic rdist/dist context */ + gicv3_distif_init_restore(&ctx->dist_ctx); + for (int i = 0; i < PLATFORM_CORE_COUNT; i++) + gicv3_rdistif_init_restore(i, &ctx->rdist_ctx[i]); +} diff --git a/plat/imx/common/sci/imx8_mu.c b/plat/imx/common/sci/imx8_mu.c index 26d9bdfef..66e956d8a 100644 --- a/plat/imx/common/sci/imx8_mu.c +++ b/plat/imx/common/sci/imx8_mu.c @@ -8,6 +8,21 @@ #include "imx8_mu.h" +void MU_Resume(uint32_t base) +{ + uint32_t reg, i; + + reg = mmio_read_32(base + MU_ACR_OFFSET1); + /* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */ + reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1 + | MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1); + mmio_write_32(base + MU_ACR_OFFSET1, reg); + + /* Enable all RX interrupts */ + for (i = 0; i < MU_RR_COUNT; i++) + MU_EnableRxFullInt(base, i); +} + void MU_EnableRxFullInt(uint32_t base, uint32_t index) { uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1); diff --git a/plat/imx/common/sci/imx8_mu.h b/plat/imx/common/sci/imx8_mu.h index 8c7887728..edcac7bf3 100644 --- a/plat/imx/common/sci/imx8_mu.h +++ b/plat/imx/common/sci/imx8_mu.h @@ -33,3 +33,4 @@ void MU_SendMessage(uint32_t base, uint32_t regIndex, uint32_t msg); void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg); void MU_EnableGeneralInt(uint32_t base, uint32_t index); void MU_EnableRxFullInt(uint32_t base, uint32_t index); +void MU_Resume(uint32_t base); diff --git a/plat/imx/imx8qm/imx8qm_bl31_setup.c b/plat/imx/imx8qm/imx8qm_bl31_setup.c index a00695cc3..c76de6461 100644 --- a/plat/imx/imx8qm/imx8qm_bl31_setup.c +++ b/plat/imx/imx8qm/imx8qm_bl31_setup.c @@ -49,11 +49,7 @@ const static int imx8qm_cci_map[] = { }; static const mmap_region_t imx_mmap[] = { - MAP_REGION_FLAT(IMX_BOOT_UART_BASE, IMX_BOOT_UART_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(SC_IPC_BASE, SC_IPC_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(PLAT_GICD_BASE, PLAT_GICD_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(PLAT_GICR_BASE, PLAT_GICR_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(PLAT_CCI_BASE, PLAT_CCI_SIZE, MT_DEVICE | MT_RW), + MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW), {0} }; @@ -324,6 +320,10 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, /* turn on MU1 for non-secure OS/Hypervisor */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON); + /* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); + sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); + mmio_write_32(IMX_GPT_LPCG_BASE, mmio_read_32(IMX_GPT_LPCG_BASE) | (1 << 25)); /* * create new partition for non-secure OS/Hypervisor diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c index 833048dcf..bdba37c6e 100644 --- a/plat/imx/imx8qm/imx8qm_psci.c +++ b/plat/imx/imx8qm/imx8qm_psci.c @@ -17,6 +17,8 @@ #include <plat_imx8.h> #include <sci/sci.h> +#include "../../common/sci/imx8_mu.h" + #define CORE_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL0]) #define CLUSTER_PWR_STATE(state) \ @@ -29,44 +31,70 @@ const static int ap_core_index[PLATFORM_CORE_COUNT] = { SC_R_A53_3, SC_R_A72_0, SC_R_A72_1, }; +/* save gic dist/redist context when GIC is poewr down */ +static struct plat_gic_ctx imx_gicv3_ctx; +static unsigned int gpt_lpcg, gpt_reg[2]; + +static void imx_enable_irqstr_wakeup(void) +{ + uint32_t irq_mask; + gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; + + /* put IRQSTR into ON mode */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); + + /* enable the irqsteer to handle wakeup irq */ + mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1); + for (int i = 0; i < 15; i++) { + irq_mask = dist_ctx->gicd_isenabler[i]; + mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask); + } + + /* set IRQSTR low power mode */ + if (imx_is_wakeup_src_irqsteer()) + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY); + else + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); +} + +static void imx_disable_irqstr_wakeup(void) +{ + /* put IRQSTR into ON from STBY mode */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); + + /* disable the irqsteer */ + mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0); + for (int i = 0; i < 16; i++) + mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0); + + /* put IRQSTR into OFF mode */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); +} + int imx_pwr_domain_on(u_register_t mpidr) { int ret = PSCI_E_SUCCESS; - unsigned int cluster_id, cpu_id; - - cluster_id = MPIDR_AFFLVL1_VAL(mpidr); - cpu_id = MPIDR_AFFLVL0_VAL(mpidr); - - printf("imx_pwr_domain_on cluster_id %d, cpu_id %d\n", cluster_id, cpu_id); - - if (cluster_id == 0) { - 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); - ret = PSCI_E_INTERN_FAIL; - } - - if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id], - true, BL31_BASE) != SC_ERR_NONE) { - ERROR("boot cluster0 core %d failed!\n", cpu_id); - ret = PSCI_E_INTERN_FAIL; - } - } else { - 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); - ret = PSCI_E_INTERN_FAIL; - } - - if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id + 4], - true, BL31_BASE) != SC_ERR_NONE) { - ERROR("boot cluster1 core %d failed!\n", cpu_id); - ret = PSCI_E_INTERN_FAIL; - } + unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); + unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); + + sc_pm_set_resource_power_mode(ipc_handle, cluster_id == 0 ? + SC_R_A53 : SC_R_A72, SC_PM_PW_MODE_ON); + + if (cluster_id == 1) + sc_pm_req_low_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 + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_ON) != SC_ERR_NONE) { + ERROR("core %d power on failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id); + ret = PSCI_E_INTERN_FAIL; + } + + if (sc_pm_cpu_start(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + true, BL31_BASE) != SC_ERR_NONE) { + ERROR("boot core %d failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id); + ret = PSCI_E_INTERN_FAIL; } return ret; @@ -91,11 +119,14 @@ void imx_pwr_domain_off(const psci_power_state_t *target_state) 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)); + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE); + + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { + cci_disable_snoop_dvm_reqs(cluster_id); + if (cluster_id == 1) + sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); + } printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id); } @@ -105,24 +136,148 @@ void imx_domain_suspend(const psci_power_state_t *target_state) unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); - plat_gic_cpuif_disable(); + if (is_local_state_off(CORE_PWR_STATE(target_state))) { + plat_gic_cpuif_disable(); + sc_pm_set_cpu_resume(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + true, BL31_BASE); + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); + } else { + dsb(); + write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); + isb(); + } - cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { + cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + if (cluster_id == 1) + sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); + } - 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); + if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { + plat_gic_cpuif_disable(); + + /* save gic context */ + plat_gic_save(cpu_id, &imx_gicv3_ctx); + /* enable the irqsteer for wakeup */ + imx_enable_irqstr_wakeup(); + + cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + + /* Put GIC in LP mode. */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF); + /* Save GPT clock and registers, then turn off its power */ + gpt_lpcg = mmio_read_32(IMX_GPT_LPCG_BASE); + gpt_reg[0] = mmio_read_32(IMX_GPT_BASE); + gpt_reg[1] = mmio_read_32(IMX_GPT_BASE + 0x4); + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, 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_A72, SC_PM_PW_MODE_OFF); + sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); + + 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_OFF); + 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_OFF); + 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_OFF); + 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_OFF); + 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_OFF); + 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_OFF); + sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); + + sc_pm_set_cpu_resume(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + true, BL31_BASE); + if (imx_is_wakeup_src_irqsteer()) + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER); + else + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU); + } } void imx_domain_suspend_finish(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); - cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + /* check the system level status */ + if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { + MU_Resume(SC_IPC_BASE); - plat_gic_cpuif_enable(); + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); + + /* Put GIC/IRQSTR back to high power mode. */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON); + + /* Turn GPT power and restore its clock and registers */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); + sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); + mmio_write_32(IMX_GPT_BASE, gpt_reg[0]); + mmio_write_32(IMX_GPT_BASE + 0x4, gpt_reg[1]); + mmio_write_32(IMX_GPT_LPCG_BASE, gpt_lpcg); + + sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); + sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); + sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); + + 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_ON); + 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_ON); + 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_ON); + 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_ON); + 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_ON); + 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_ON); + sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); + + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + + /* restore gic context */ + plat_gic_restore(cpu_id, &imx_gicv3_ctx); + /* disable the irqsteer wakeup */ + imx_disable_irqstr_wakeup(); + + plat_gic_cpuif_enable(); + } + + /* check the cluster level power status */ + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); + if (cluster_id == 1) + sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); + } + + /* check the core level power status */ + if (is_local_state_off(CORE_PWR_STATE(target_state))) { + sc_pm_set_cpu_resume(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + false, BL31_BASE); + sc_pm_req_cpu_low_power_mode(ipc_handle, + ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], + SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); + plat_gic_cpuif_enable(); + } else { + write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); + isb(); + } } int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) @@ -149,26 +304,23 @@ 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 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); + /* make sure system sources power ON in low power mode by default */ + sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); + sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); + sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); + + 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_ON); + 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_ON); + 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_ON); + 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_ON); + 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_ON); + 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_ON); return 0; } diff --git a/plat/imx/imx8qm/include/platform_def.h b/plat/imx/imx8qm/include/platform_def.h index 1d0bdf9a7..946be7659 100644 --- a/plat/imx/imx8qm/include/platform_def.h +++ b/plat/imx/imx8qm/include/platform_def.h @@ -36,22 +36,22 @@ #define BL31_LIMIT 0x80020000 #define PLAT_GICD_BASE 0x51a00000 -#define PLAT_GICD_SIZE 0x10000 #define PLAT_GICR_BASE 0x51b00000 -#define PLAT_GICR_SIZE 0xc0000 #define PLAT_CCI_BASE 0x52090000 -#define PLAT_CCI_SIZE 0x10000 #define CLUSTER0_CCI_SLVAE_IFACE 3 #define CLUSTER1_CCI_SLVAE_IFACE 4 #define IMX_BOOT_UART_BASE 0x5a060000 -#define IMX_BOOT_UART_SIZE 0x1000 #define IMX_BOOT_UART_BAUDRATE 115200 #define IMX_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE #define PLAT__CRASH_UART_CLK_IN_HZ 24000000 #define IMX_CONSOLE_BAUDRATE 115200 #define SC_IPC_BASE 0x5d1b0000 -#define SC_IPC_SIZE 0x10000 +#define IMX_GPT_LPCG_BASE 0x5d540000 +#define IMX_GPT_BASE 0x5d140000 +#define IMX_WUP_IRQSTR_BASE 0x51090000 +#define IMX_REG_BASE 0x50000000 +#define IMX_REG_SIZE 0x10000000 #define COUNTER_FREQUENCY 8000000 /* 8MHz */ diff --git a/plat/imx/imx8qm/include/sec_rsrc.h b/plat/imx/imx8qm/include/sec_rsrc.h index a623cd3f1..d16d05128 100644 --- a/plat/imx/imx8qm/include/sec_rsrc.h +++ b/plat/imx/imx8qm/include/sec_rsrc.h @@ -19,12 +19,14 @@ sc_rsrc_t secure_rsrcs[] = { SC_R_GIC_SMMU, SC_R_CCI, SC_R_SYSTEM, - SC_R_IRQSTR_SCU2 + SC_R_IRQSTR_SCU2, + SC_R_GPT_0 }; /* resources that have register access for non-secure domain */ sc_rsrc_t ns_access_allowed[] = { SC_R_GIC, SC_R_GIC_SMMU, - SC_R_CCI + SC_R_CCI, + SC_R_GPT_0 }; diff --git a/plat/imx/imx8qx/imx8qx_bl31_setup.c b/plat/imx/imx8qx/imx8qx_bl31_setup.c index c90794a89..bfe405284 100644 --- a/plat/imx/imx8qx/imx8qx_bl31_setup.c +++ b/plat/imx/imx8qx/imx8qx_bl31_setup.c @@ -44,10 +44,7 @@ static entry_point_info_t bl33_image_ep_info; (SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT)) static const mmap_region_t imx_mmap[] = { - MAP_REGION_FLAT(IMX_BOOT_UART_BASE, IMX_BOOT_UART_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(SC_IPC_BASE, SC_IPC_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(PLAT_GICD_BASE, PLAT_GICD_SIZE, MT_DEVICE | MT_RW), - MAP_REGION_FLAT(PLAT_GICR_BASE, PLAT_GICR_SIZE, MT_DEVICE | MT_RW), + MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW), {0} }; @@ -281,6 +278,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, /* Turn on MU1 for non-secure OS/Hypervisor */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON); + /* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); + sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); + mmio_write_32(IMX_GPT0_LPCG_BASE, mmio_read_32(IMX_GPT0_LPCG_BASE) | (1 << 25)); + /* * create new partition for non-secure OS/Hypervisor * uses global structs defined in sec_rsrc.h diff --git a/plat/imx/imx8qx/imx8qx_psci.c b/plat/imx/imx8qx/imx8qx_psci.c index 94c2e2b1e..aab3a2dae 100644 --- a/plat/imx/imx8qx/imx8qx_psci.c +++ b/plat/imx/imx8qx/imx8qx_psci.c @@ -16,10 +16,52 @@ #include <plat_imx8.h> #include <sci/sci.h> +#include "../../common/sci/imx8_mu.h" + 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 }; +/* save gic dist/redist context when GIC is power down */ +static struct plat_gic_ctx imx_gicv3_ctx; +static unsigned int gpt_lpcg, gpt_reg[2]; + +static void imx_enable_irqstr_wakeup(void) +{ + uint32_t irq_mask; + gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; + + /* put IRQSTR into ON mode */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); + + /* enable the irqsteer to handle wakeup irq */ + mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1); + for (int i = 0; i < 15; i++) { + irq_mask = dist_ctx->gicd_isenabler[i]; + mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask); + } + + /* set IRQSTR low power mode */ + if (imx_is_wakeup_src_irqsteer()) + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY); + else + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); +} + +static void imx_disable_irqstr_wakeup(void) +{ + /* Put IRQSTEER back to ON mode */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); + + /* disable the irqsteer */ + mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0); + for (int i = 0; i < 16; i++) + mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0); + + /* Put IRQSTEER into OFF mode */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); +} + int imx_pwr_domain_on(u_register_t mpidr) { int ret = PSCI_E_SUCCESS; @@ -71,11 +113,52 @@ 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(); + if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) { + plat_gic_cpuif_disable(); + sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, 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); + } else { + dsb(); + write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); + isb(); + } - 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); + if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1])) + sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); + + if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) { + plat_gic_cpuif_disable(); + + /* save gic context */ + plat_gic_save(cpu_id, &imx_gicv3_ctx); + /* enable the irqsteer for wakeup */ + imx_enable_irqstr_wakeup(); + + /* Save GPT clock and registers, then turn off its power */ + gpt_lpcg = mmio_read_32(IMX_GPT0_LPCG_BASE); + gpt_reg[0] = mmio_read_32(IMX_GPT0_BASE); + gpt_reg[1] = mmio_read_32(IMX_GPT0_BASE + 0x4); + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF); + + sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); + 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_OFF); + 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_OFF); + 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_OFF); + + /* Put GIC in OFF mode. */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF); + sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE); + if (imx_is_wakeup_src_irqsteer()) + sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER); + else + sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU); + } } void imx_domain_suspend_finish(const psci_power_state_t *target_state) @@ -83,10 +166,51 @@ 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); + if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) { + MU_Resume(SC_IPC_BASE); - plat_gic_cpuif_enable(); + sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON); + sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); + + /* Put GIC back to high power mode. */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON); + + /* restore gic context */ + plat_gic_restore(cpu_id, &imx_gicv3_ctx); + + /* Turn on GPT power and restore its clock and registers */ + sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); + sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); + mmio_write_32(IMX_GPT0_BASE, gpt_reg[0]); + mmio_write_32(IMX_GPT0_BASE + 0x4, gpt_reg[1]); + mmio_write_32(IMX_GPT0_LPCG_BASE, gpt_lpcg); + + sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); + 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_ON); + 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_ON); + 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_ON); + + /* disable the irqsteer wakeup */ + imx_disable_irqstr_wakeup(); + + plat_gic_cpuif_enable(); + } + + if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1])) + sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); + + if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) { + sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], + SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); + plat_gic_cpuif_enable(); + } else { + write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); + isb(); + } } static const plat_psci_ops_t imx_plat_psci_ops = { @@ -108,17 +232,15 @@ 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); + /* make sure system sources power ON in low power mode by default */ + sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); + + 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_ON); + 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_ON); + 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_ON); return 0; } diff --git a/plat/imx/imx8qx/include/platform_def.h b/plat/imx/imx8qx/include/platform_def.h index 1239340d0..3a3fac86f 100644 --- a/plat/imx/imx8qx/include/platform_def.h +++ b/plat/imx/imx8qx/include/platform_def.h @@ -37,18 +37,19 @@ #define MAX_MMAP_REGIONS 8 #define PLAT_GICD_BASE 0x51a00000 -#define PLAT_GICD_SIZE 0x10000 #define PLAT_GICR_BASE 0x51b00000 -#define PLAT_GICR_SIZE 0xc0000 #define IMX_BOOT_UART_BASE 0x5a060000 -#define IMX_BOOT_UART_SIZE 0x1000 #define IMX_BOOT_UART_BAUDRATE 115200 #define IMX_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE #define PLAT__CRASH_UART_CLK_IN_HZ 24000000 #define IMX_CONSOLE_BAUDRATE 115200 #define SC_IPC_BASE 0x5d1b0000 -#define SC_IPC_SIZE 0x10000 +#define IMX_GPT0_LPCG_BASE 0x5d540000 +#define IMX_GPT0_BASE 0x5d140000 +#define IMX_WUP_IRQSTR_BASE 0x51090000 +#define IMX_REG_BASE 0x50000000 +#define IMX_REG_SIZE 0x10000000 #define COUNTER_FREQUENCY 8000000 diff --git a/plat/imx/imx8qx/include/sec_rsrc.h b/plat/imx/imx8qx/include/sec_rsrc.h index 37c9f6637..b7fe0e811 100644 --- a/plat/imx/imx8qx/include/sec_rsrc.h +++ b/plat/imx/imx8qx/include/sec_rsrc.h @@ -14,10 +14,12 @@ sc_rsrc_t secure_rsrcs[] = { SC_R_A35_3, SC_R_GIC, SC_R_SYSTEM, - SC_R_IRQSTR_SCU2 + SC_R_IRQSTR_SCU2, + SC_R_GPT_0 }; /* resources that have register access for non-secure domain */ sc_rsrc_t ns_access_allowed[] = { SC_R_GIC, + SC_R_GPT_0 }; |