summaryrefslogtreecommitdiff
path: root/plat/imx/imx8m/imx8mq/imx8mq_psci.c
diff options
context:
space:
mode:
authorJacky Bai <ping.bai@nxp.com>2020-01-08 16:56:01 +0800
committerJacky Bai <ping.bai@nxp.com>2020-02-09 20:58:49 +0800
commit7fd86e0b33cc8ded9c5d95c8c85a74133aaea0ca (patch)
treed9b3b149da80025fa8124a1fd6bf587abc644ad5 /plat/imx/imx8m/imx8mq/imx8mq_psci.c
parente73e454d11dab13a87b6068a24509a1f118ac812 (diff)
plat: imx8mq: Add workaround code for ERR11171 on imx8mq
This new workaround takes advantage of the per core IMR registers in GPC in order to unmask the IRQ0, still generated by the 12bit in IOMUX_GPR register (which now remains always set), so it can only wake up one core at the time. Also, this entire workaround has now been moved here in TF-A, allowing the kernel side to be minimal. Another advantage this workaround brings is the removal of the 50us delay (which was necessary before in gic_raise_softirq in kernel) by allowing the core that is waking up to mask his own IRQ0 in the suspend finish callback. One important change here is the way the cores are woken up in dram_dvfs_handler. Since the wake up mechanism has changed from asserting the 12th bit in IOMUX_GPR and leaving the IMR1 1st bit on for each core to exactly the reverse, that is, leaving the IOMUX_GPR 12th bit always set and then masking/unmasking the IMR1 1st bit for each independent core, we need to use the imx_gpc_core_wake to wake up the cores. Also, the 50us udelay is moved to TF-A (inside imx_pwr_domain_off) from kernel (gic_raise_softirq), since the new cpuidle workaround does not need it in order to clean the IOMUX_GPC 12bit. For now, the udelay seems to be still needed in order to delay the affinity info OFF for the dying core. This is something that needs further investigation. Signed-off-by: Abel Vesa <abel.vesa@nxp.com> Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Diffstat (limited to 'plat/imx/imx8m/imx8mq/imx8mq_psci.c')
-rw-r--r--plat/imx/imx8m/imx8mq/imx8mq_psci.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_psci.c b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
index 78a6ea70..2d7befe2 100644
--- a/plat/imx/imx8m/imx8mq/imx8mq_psci.c
+++ b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
@@ -9,6 +9,7 @@
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
+#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
@@ -40,6 +41,19 @@ int imx_validate_power_state(unsigned int power_state,
return PSCI_E_SUCCESS;
}
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint64_t mpidr = read_mpidr_el1();
+ unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+ plat_gic_cpuif_disable();
+ imx_set_cpu_pwr_off(core_id);
+
+ /* TODO: Find out why this is still
+ * needed in order not to break suspend */
+ udelay(50);
+}
+
void imx_domain_suspend(const psci_power_state_t *target_state)
{
uint64_t base_addr = BL31_BASE;
@@ -88,6 +102,8 @@ void imx_domain_suspend_finish(const psci_power_state_t *target_state)
/* check the core level power status */
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+ /* mark this core as awake by masking IRQ0 */
+ imx_gpc_set_a53_core_awake(core_id);
/* clear the core lpm setting */
imx_set_cpu_lpm(core_id, false);
/* enable the gic cpu interface */