rockchip: clear the power mode status via M0

Due to the PMU design, the PMU may not clear the WAKEUP bit after
wakeup, therefore, the state machine at the power mode may enter
the infinite loop during WFI.

There is a solution that we can use the M0 to monitor the WAKEUP
bit and clear it during power mode, then the state machine will be
recovered immediately. Then, the DUT can exit the WFI normally.

Change-Id: I303628553b728c214bf2d436bd3122032b5e669c
Signed-off-by: Xing Zheng <zhengxing@rock-chips.com>
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 4ae766c..8d3f482 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -48,6 +48,7 @@
 #include <pwm.h>
 #include <soc.h>
 #include <bl31.h>
+#include <rk3399m0.h>
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
@@ -840,8 +841,6 @@
 		       BIT(PMU_SCU_PD_EN) |
 		       BIT(PMU_CCI_PD_EN) |
 		       BIT(PMU_CLK_CORE_SRC_GATE_EN) |
-		       BIT(PMU_PERILP_PD_EN) |
-		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
 		       BIT(PMU_ALIVE_USE_LF) |
 		       BIT(PMU_SREF0_ENTER_EN) |
 		       BIT(PMU_SREF1_ENTER_EN) |
@@ -1058,6 +1057,38 @@
 	}
 }
 
+static void m0_clock_init(void)
+{
+	/* enable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0x0, 0x2f, 0));
+
+	/* switch the parent to xin24M and div == 1 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0,
+		      BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8));
+
+	/* start M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x0, 0x24, 0));
+
+	/* gating disable for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, BIT_WITH_WMSK(1));
+}
+
+static void m0_reset(void)
+{
+	/* stop M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x24, 0x24, 0));
+
+	/* recover gating bit for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, WMSK_BIT(1));
+
+	/* disable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0x2f, 0x2f, 0));
+}
+
 static int sys_pwr_domain_suspend(void)
 {
 	uint32_t wait_cnt = 0;
@@ -1071,12 +1102,12 @@
 		    BIT(PMU_CLR_CCIM0) |
 		    BIT(PMU_CLR_CCIM1) |
 		    BIT(PMU_CLR_CENTER) |
-		    BIT(PMU_CLR_PERILP) |
-		    BIT(PMU_CLR_PMU) |
-		    BIT(PMU_CLR_PERILPM0) |
 		    BIT(PMU_CLR_GIC));
 
 	sys_slp_config();
+
+	m0_clock_init();
+
 	pmu_sgrf_rst_hld();
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
@@ -1111,6 +1142,7 @@
 	disable_dvfs_plls();
 	disable_pwms();
 	disable_nodvfs_plls();
+
 	suspend_apio();
 	suspend_gpio();
 
@@ -1186,12 +1218,12 @@
 				BIT(PMU_CLR_CCIM0) |
 				BIT(PMU_CLR_CCIM1) |
 				BIT(PMU_CLR_CENTER) |
-				BIT(PMU_CLR_PERILP) |
-				BIT(PMU_CLR_PMU) |
 				BIT(PMU_CLR_GIC));
 
 	plat_rockchip_gic_cpuif_enable();
 
+	m0_reset();
+
 	return 0;
 }
 
@@ -1236,42 +1268,6 @@
 	while (1)
 		;
 }
-static void __dead2 sys_pwr_down_wfi(const psci_power_state_t *target_state)
-{
-	uint32_t wakeup_status;
-
-	/*
-	 * Check wakeup status and abort suspend early if we see a wakeup
-	 * event.
-	 *
-	 * NOTE: technically I we're supposed to just execute a wfi here and
-	 * we'll either execute a normal suspend/resume or the wfi will be
-	 * treated as a no-op if a wake event was present and caused an abort
-	 * of the suspend/resume.  For some reason that's not happening and if
-	 * we execute the wfi while a wake event is pending then the whole
-	 * system wedges.
-	 *
-	 * Until the above is solved this extra check prevents system wedges in
-	 * most cases but there is still a small race condition between checking
-	 * PMU_WAKEUP_STATUS and executing wfi.  If a wake event happens in
-	 * there then we will die.
-	 */
-	wakeup_status = mmio_read_32(PMU_BASE + PMU_WAKEUP_STATUS);
-	if (wakeup_status) {
-		WARN("early wake, will not enter power mode.\n");
-
-		mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, 0);
-
-		disable_mmu_icache_el3();
-		bl31_warm_entrypoint();
-
-		while (1)
-			;
-	} else {
-		/* Enter WFI */
-		psci_power_down_wfi();
-	}
-}
 
 static struct rockchip_pm_ops_cb pm_ops = {
 	.cores_pwr_dm_on = cores_pwr_domain_on,
@@ -1287,7 +1283,6 @@
 	.sys_pwr_dm_resume = sys_pwr_domain_resume,
 	.sys_gbl_soft_reset = soc_soft_reset,
 	.system_off = soc_system_off,
-	.sys_pwr_down_wfi = sys_pwr_down_wfi,
 };
 
 void plat_rockchip_pmu_init(void)