diff --git a/plat/imx/imx8qx/imx8qx_bl31_setup.c b/plat/imx/imx8qx/imx8qx_bl31_setup.c index c90794a..bfe4052 100644 --- a/plat/imx/imx8qx/imx8qx_bl31_setup.c +++ b/plat/imx/imx8qx/imx8qx_bl31_setup.c @@ -44,10 +44,7 @@ (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 @@ /* 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 94c2e2b..aab3a2d 100644 --- a/plat/imx/imx8qx/imx8qx_psci.c +++ b/plat/imx/imx8qx/imx8qx_psci.c @@ -16,10 +16,52 @@ #include #include +#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 @@ 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 @@ 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 @@ 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); + /* 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); - /* 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); + 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 1239340..3a3fac8 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 37c9f66..b7fe0e8 100644 --- a/plat/imx/imx8qx/include/sec_rsrc.h +++ b/plat/imx/imx8qx/include/sec_rsrc.h @@ -14,10 +14,12 @@ 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 };