summaryrefslogtreecommitdiff
path: root/plat/imx/imx8qxp
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/imx8qxp
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/imx8qxp')
-rw-r--r--plat/imx/imx8qxp/imx8qxp_bl31_setup.c3
-rw-r--r--plat/imx/imx8qxp/imx8qxp_psci.c52
-rw-r--r--plat/imx/imx8qxp/include/platform_def.h1
-rw-r--r--plat/imx/imx8qxp/platform.mk2
4 files changed, 53 insertions, 5 deletions
diff --git a/plat/imx/imx8qxp/imx8qxp_bl31_setup.c b/plat/imx/imx8qxp/imx8qxp_bl31_setup.c
index 0044d113..d4c4ddcd 100644
--- a/plat/imx/imx8qxp/imx8qxp_bl31_setup.c
+++ b/plat/imx/imx8qxp/imx8qxp_bl31_setup.c
@@ -346,6 +346,9 @@ void bl31_plat_arch_setup(void)
MT_DEVICE | MT_RW);
// mmap_add_region(IMX_GPT0_BASE, IMX_GPT0_BASE, 0x10000,
// MT_DEVICE | MT_RW);
+ mmap_add_region(IMX_WUP_IRQSTR, IMX_WUP_IRQSTR, 0x10000,
+ MT_DEVICE | MT_RW);
+
#if USE_COHERENT_MEM
mmap_add_region(BL31_COHERENT_RAM_BASE, BL31_COHERENT_RAM_BASE,
BL31_COHERENT_RAM_LIMIT - BL31_COHERENT_RAM_BASE,
diff --git a/plat/imx/imx8qxp/imx8qxp_psci.c b/plat/imx/imx8qxp/imx8qxp_psci.c
index 64e00780..1c00c61b 100644
--- a/plat/imx/imx8qxp/imx8qxp_psci.c
+++ b/plat/imx/imx8qxp/imx8qxp_psci.c
@@ -32,6 +32,8 @@
#include <arch.h>
#include <arch_helpers.h>
#include <debug.h>
+#include <gicv3.h>
+#include <mmio.h>
#include <plat_imx8.h>
#include <psci.h>
#include <sci/sci.h>
@@ -39,6 +41,9 @@
extern sc_ipc_t ipc_handle;
extern void mdelay(uint32_t msec);
+/* save gic dist/redist context when GIC is power down */
+static struct plat_gic_ctx imx_gicv3_ctx;
+
const unsigned char imx_power_domain_tree_desc[] =
{
/* number of root nodes */
@@ -52,6 +57,27 @@ 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
};
+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);
+}
+
plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
const plat_local_state_t *target_state,
unsigned int ncpu)
@@ -167,11 +193,18 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
plat_gic_cpuif_disable();
- /* Put GIC in LP mode. */
- sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_LP);
+ /* save gic context */
+ plat_gic_save(cpu_id, &imx_gicv3_ctx);
+ /* enable the irqsteer for wakeup */
+ imx_enable_irqstr_wakeup();
+
+ /* Put GIC in OFF mode. */
+ 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);
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);
}
void imx_domain_suspend_finish(const psci_power_state_t *target_state)
@@ -180,9 +213,18 @@ void imx_domain_suspend_finish(const psci_power_state_t *target_state)
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);
+ 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);
+ /* Put IRQSTEER back to high power mode */
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+ /* restore gic context */
+ plat_gic_restore(cpu_id, &imx_gicv3_ctx);
+ /* disable the irqsteer wakeup */
+ imx_disable_irqstr_wakeup();
+
plat_gic_cpuif_enable();
}
@@ -238,8 +280,8 @@ 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_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_LP);
- 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);
+ 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/imx8qxp/include/platform_def.h b/plat/imx/imx8qxp/include/platform_def.h
index 7955e60f..57a351da 100644
--- a/plat/imx/imx8qxp/include/platform_def.h
+++ b/plat/imx/imx8qxp/include/platform_def.h
@@ -66,6 +66,7 @@
#define MAX_XLAT_TABLES 8
#define MAX_MMAP_REGIONS 8
+#define IMX_WUP_IRQSTR 0x51090000
#define IMX_BOOT_UART_BASE 0x5a060000
#define IMX_BOOT_UART_BAUDRATE 115200
#define IMX_BOOT_UART_CLK_IN_HZ 24000000
diff --git a/plat/imx/imx8qxp/platform.mk b/plat/imx/imx8qxp/platform.mk
index bf0a0a84..47ced36c 100644
--- a/plat/imx/imx8qxp/platform.mk
+++ b/plat/imx/imx8qxp/platform.mk
@@ -33,6 +33,8 @@ PLAT_INCLUDES := -Iplat/imx/imx8qxp/include \
-Iplat/imx/common/include \
PLAT_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \
+ drivers/arm/gic/v3/arm_gicv3_common.c \
+ drivers/arm/gic/v3/gic500.c \
drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/common/gic_common.c \
plat/common/plat_gicv3.c \