summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ranjani.vaidyanathan@nxp.com>2022-02-04 14:05:26 -0600
committerRanjani Vaidyanathan <ranjani.vaidyanathan@nxp.com>2022-02-11 16:14:53 -0600
commit15e8ff164a8becfddb76cba2c68eeeae684cb398 (patch)
treee3489cad0abd88ee163aed27b3064e8dc87791b1
parent2a26786460edd4f0ec3111e7027c93c57fc572c1 (diff)
LF-5427 plat:imx8 Fix missed SCU wakeup interrupts
Handle corner cases of early of wakeup interrupts. Monitor the status of OS MU interrupt in the IRQSTR as the last step in the suspend process. If an MU interrupt is pending, switch the wakeup source to be irqsteer so that the core can woken up by the SCFW after wfi is executed. Signed-off-by: Ranjani Vaidyanathan <ranjani.vaidyanathan@nxp.com> (cherry picked from commit c3acc399cfd8db878d6078456092ca3f63fd070b)
-rw-r--r--plat/imx/imx8dxl/imx8dxl_psci.c39
-rw-r--r--plat/imx/imx8qm/imx8qm_psci.c42
-rw-r--r--plat/imx/imx8qx/imx8qx_psci.c39
3 files changed, 92 insertions, 28 deletions
diff --git a/plat/imx/imx8dxl/imx8dxl_psci.c b/plat/imx/imx8dxl/imx8dxl_psci.c
index 6e6a6ad6..764c536f 100644
--- a/plat/imx/imx8dxl/imx8dxl_psci.c
+++ b/plat/imx/imx8dxl/imx8dxl_psci.c
@@ -18,6 +18,8 @@
#include "../../common/sci/imx8_mu.h"
+#define IRQSTR_PLAT_OS_MU_IRQ 119
+
const static int ap_core_index[PLATFORM_CORE_COUNT] = {
SC_R_A35_0, SC_R_A35_1
};
@@ -40,12 +42,6 @@ static void imx_enable_irqstr_wakeup(void)
irq_mask = dist_ctx->gicd_isenabler[i];
mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x2c - 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)
@@ -128,6 +124,11 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
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])) {
+ uint32_t irqstr_mu_reg = (IRQSTR_PLAT_OS_MU_IRQ / 32) - 1;
+ uint32_t irqstr_mu_mask = (1 << (IRQSTR_PLAT_OS_MU_IRQ % 32));
+ uint32_t irqstr_mu_status, reg;
+ bool irqstr_mu_wakeup = false;
+
plat_gic_cpuif_disable();
/* save gic context */
@@ -152,12 +153,32 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
/* 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())
+
+ 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);
+ SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+ /*
+ * Check to see if the MU interrupt is pending in the IRQSTR_SCU2
+ * If interrupt is pending it implies the wakeup interrupt triggered
+ * during suspend process and we should wakeup. Changing the wakeup src
+ * to SC_PM_WAKE_SRC_IRQSTEER will ensure the AP core wakes up as soon
+ * as WFI is executed.
+ */
+ reg = mmio_read_32(IMX_WUP_IRQSTR_BASE + 0x2c - 4 * irqstr_mu_reg);
+ mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x2c - 4 * irqstr_mu_reg, reg | irqstr_mu_mask);
+ irqstr_mu_status = mmio_read_32(IMX_WUP_IRQSTR_BASE + 0x8c - 4 * irqstr_mu_reg);
+ if (irqstr_mu_status & irqstr_mu_mask)
+ irqstr_mu_wakeup = true;
else
+ mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x2c - 4 * irqstr_mu_reg, reg);
+
+ /* set IRQSTR low power mode. IRQSTR is already in ON state at this point*/
+ if (imx_is_wakeup_src_irqsteer() || irqstr_mu_wakeup) {
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
- SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+ SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+ } else
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
}
diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c
index 65cad5b0..befc1abb 100644
--- a/plat/imx/imx8qm/imx8qm_psci.c
+++ b/plat/imx/imx8qm/imx8qm_psci.c
@@ -26,7 +26,10 @@
#define SYSTEM_PWR_STATE(state) \
((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
-const static int ap_core_index[PLATFORM_CORE_COUNT] = {
+
+#define IRQSTR_PLAT_OS_MU_IRQ 209
+
+const static int ap_core_index[PLATFORM_CLUSTER0_CORE_COUNT + PLATFORM_CLUSTER1_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,
};
@@ -49,12 +52,6 @@ static void imx_enable_irqstr_wakeup(void)
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)
@@ -157,6 +154,11 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
}
if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+ uint32_t irqstr_mu_reg = (IRQSTR_PLAT_OS_MU_IRQ / 32) - 1;
+ uint32_t irqstr_mu_mask = (1 << (IRQSTR_PLAT_OS_MU_IRQ % 32));
+ uint32_t irqstr_mu_status, reg;
+ bool irqstr_mu_wakeup = false;
+
plat_gic_cpuif_disable();
/* save gic context */
@@ -195,14 +197,34 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
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())
+
+ 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);
+ SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+ /*
+ * Check to see if the MU interrupt is pending in the IRQSTR_SCU2
+ * If interrupt is pending it implies the wakeup interrupt triggered
+ * during suspend process and we should wakeup. Changing the wakeup src
+ * to SC_PM_WAKE_SRC_IRQSTEER will ensure the AP core wakes up as soon
+ * as WFI is executed.
+ */
+ reg = mmio_read_32(IMX_WUP_IRQSTR_BASE + 0x3c - 4 * irqstr_mu_reg);
+ mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 4 * irqstr_mu_reg, reg | irqstr_mu_mask);
+ irqstr_mu_status = mmio_read_32(IMX_WUP_IRQSTR_BASE + 0xbc - 4 * irqstr_mu_reg);
+ if (irqstr_mu_status & irqstr_mu_mask)
+ irqstr_mu_wakeup = true;
else
+ mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 4 * irqstr_mu_reg, reg);
+
+ /* set IRQSTR low power mode. IRQSTR is already in ON state at this point*/
+ if (imx_is_wakeup_src_irqsteer() || irqstr_mu_wakeup) {
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
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);
+ SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+ } else
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
}
diff --git a/plat/imx/imx8qx/imx8qx_psci.c b/plat/imx/imx8qx/imx8qx_psci.c
index 24a46f7a..1926044f 100644
--- a/plat/imx/imx8qx/imx8qx_psci.c
+++ b/plat/imx/imx8qx/imx8qx_psci.c
@@ -18,6 +18,8 @@
#include "../../common/sci/imx8_mu.h"
+#define IRQSTR_PLAT_OS_MU_IRQ 209
+
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
};
@@ -40,12 +42,6 @@ static void imx_enable_irqstr_wakeup(void)
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)
@@ -128,6 +124,11 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
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])) {
+ uint32_t irqstr_mu_reg = (IRQSTR_PLAT_OS_MU_IRQ / 32) - 1;
+ uint32_t irqstr_mu_mask = (1 << (IRQSTR_PLAT_OS_MU_IRQ % 32));
+ uint32_t irqstr_mu_status, reg;
+ bool irqstr_mu_wakeup = false;
+
plat_gic_cpuif_disable();
/* save gic context */
@@ -152,12 +153,32 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
/* 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())
+
+ 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);
+ SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+ /*
+ * Check to see if the MU interrupt is pending in the IRQSTR_SCU2
+ * If interrupt is pending it implies the wakeup interrupt triggered
+ * during suspend process and we should wakeup. Changing the wakeup src
+ * to SC_PM_WAKE_SRC_IRQSTEER will ensure the AP core wakes up as soon
+ * as WFI is executed.
+ */
+ reg = mmio_read_32(IMX_WUP_IRQSTR_BASE + 0x3c - 4 * irqstr_mu_reg);
+ mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 4 * irqstr_mu_reg, reg | irqstr_mu_mask);
+ irqstr_mu_status = mmio_read_32(IMX_WUP_IRQSTR_BASE + 0xbc - 4 * irqstr_mu_reg);
+ if (irqstr_mu_status & irqstr_mu_mask)
+ irqstr_mu_wakeup = true;
else
+ mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 4 * irqstr_mu_reg, reg);
+
+ /* set IRQSTR low power mode. IRQSTR is already in ON state at this point*/
+ if (imx_is_wakeup_src_irqsteer() || irqstr_mu_wakeup) {
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
- SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+ SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+ } else
+ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
}