summaryrefslogtreecommitdiff
path: root/plat/imx/imx8qm/imx8qm_psci.c
diff options
context:
space:
mode:
authorBai Ping <ping.bai@nxp.com>2018-04-10 16:50:04 +0800
committerAbel Vesa <abel.vesa@nxp.com>2018-06-11 10:33:03 +0300
commitca803a791056da5a2acdf7118bbacf0f119e6433 (patch)
treea85572db92f4b8e46bdbf15611f2efc47d07ef3b /plat/imx/imx8qm/imx8qm_psci.c
parent02871d54a6beda8bb0c09e43aacfd138bd5fe35a (diff)
plat: imx: add gic save/restore for imx8qm/qxp
In order to save power when AP side is suspend, the DBLOG need to be put into low power mode. GIC need to be power off to save power. before GIC power off, we need to save the GIC setting, then after resume, we need to restore the gic setting. irqsteer need to be used to wakeup the AP side when wakeup interrupt is pending for AP side. Signed-off-by: Bai Ping <ping.bai@nxp.com>
Diffstat (limited to 'plat/imx/imx8qm/imx8qm_psci.c')
-rw-r--r--plat/imx/imx8qm/imx8qm_psci.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c
index d96a6cde..65ec8989 100644
--- a/plat/imx/imx8qm/imx8qm_psci.c
+++ b/plat/imx/imx8qm/imx8qm_psci.c
@@ -33,12 +33,15 @@
#include <arch_helpers.h>
#include <cci.h>
#include <debug.h>
+#include <gicv3.h>
+#include <mmio.h>
#include <plat_imx8.h>
#include <psci.h>
#include <sci/sci.h>
extern sc_ipc_t ipc_handle;
-extern void mdelay(uint32_t msec);
+/* save gic dist/redist context when GIC is poewr down */
+static struct plat_gic_ctx imx_gicv3_ctx;
const unsigned char imx_power_domain_tree_desc[] =
{
@@ -61,6 +64,27 @@ static unsigned int a53_cpu_on_number __section("tzfw_coherent_mem");
static unsigned int a72_cpu_on_number __section("tzfw_coherent_mem");
#endif
+static void imx_enable_irqstr_wakeup(void)
+{
+ uint32_t irq_mask;
+ gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
+
+ /* enable the irqsteer to handle wakeup irq */
+ mmio_write_32(IMX_WUP_IRQSTR, 0x1);
+ for (int i = 0; i < 15; i++) {
+ irq_mask = dist_ctx->gicd_isenabler[i];
+ mmio_write_32(IMX_WUP_IRQSTR + 0x3c - 0x4 * i, irq_mask);
+ }
+}
+
+static void imx_disable_irqstr_wakeup(void)
+{
+ /* disable the irqsteer */
+ mmio_write_32(IMX_WUP_IRQSTR, 0x0);
+ for (int i = 0; i < 16; i ++)
+ mmio_write_32(IMX_WUP_IRQSTR + 0x4 + 0x4 * i, 0x0);
+}
+
int imx_pwr_domain_on(u_register_t mpidr)
{
int ret = PSCI_E_SUCCESS;
@@ -201,17 +225,24 @@ void imx_domain_suspend(const psci_power_state_t *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_LP);
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
+ /* Put IRQSTR in STBY mode */
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
if (cluster_id == 0) {
sc_pm_set_cpu_resume_addr(ipc_handle, ap_core_index[cpu_id], 0x080000000);
- sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_OFF);
+ 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_set_cpu_resume_addr(ipc_handle, ap_core_index[cpu_id + 4], 0x080000000);
- sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id + 4], SC_PM_PW_MODE_OFF);
+ sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + 4], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
}
}
@@ -222,15 +253,21 @@ void imx_domain_suspend_finish(const psci_power_state_t *target_state)
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
if (cluster_id == 0)
- 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);
else
- sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id + 4], SC_PM_PW_MODE_ON);
+ sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + 4], SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
- /* Put GIC back to high power mode. */
+ /* Put GIC/IRQSTR back to high power mode. */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, 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();
}
@@ -297,10 +334,10 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
/* 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_LP);
- 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_LP);
- 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_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;
}