rockchip: support the suspend/resume for rk3399

This patch adds to support the suspend/resume for rk3399 SoCs.

Signed-off-by: Shengfei xu <xsf@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 351de7d..1493a4d 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -47,6 +47,8 @@
 static struct psram_data_t *psram_sleep_cfg =
 	(struct psram_data_t *)PSRAM_DT_BASE;
 
+static uint32_t cpu_warm_boot_addr;
+
 /*
  * There are two ways to powering on or off on core.
  * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
@@ -63,6 +65,53 @@
 #endif
 ;/* coheront */
 
+void rk3399_flash_l2_b(void)
+{
+	uint32_t wait_cnt = 0;
+
+	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B));
+	dsb();
+
+	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) &
+		 BIT(L2_FLUSHDONE_CLUSTER_B))) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			WARN("%s:reg %x,wait\n", __func__,
+			     mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
+	}
+
+	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B));
+}
+
+static void pmu_scu_b_pwrdn(void)
+{
+	uint32_t wait_cnt = 0;
+
+	if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) &
+	     (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) !=
+	     (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) {
+		ERROR("%s: not all cpus is off\n", __func__);
+		return;
+	}
+
+	rk3399_flash_l2_b();
+
+	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
+
+	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) &
+		 BIT(STANDBY_BY_WFIL2_CLUSTER_B))) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
+			      mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
+	}
+}
+
+static void pmu_scu_b_pwrup(void)
+{
+	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
+}
+
 void plat_rockchip_pmusram_prepare(void)
 {
 	uint32_t *sram_dst, *sram_src;
@@ -128,6 +177,7 @@
 
 		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
 			      BIT(core_pm_sft_wakeup_en));
+		dsb();
 	}
 
 	return 0;
@@ -160,6 +210,7 @@
 			core_pm_value |= BIT(core_pm_int_wakeup_en);
 		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
 			      core_pm_value);
+		dsb();
 	}
 
 	return 0;
@@ -220,9 +271,6 @@
 {
 	uint32_t cpu_id = plat_my_core_pos();
 
-	cpuson_flags[cpu_id] = 0;
-	cpuson_entry_point[cpu_id] = 0;
-
 	/* Disable core_pm */
 	mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE);
 
@@ -233,9 +281,6 @@
 {
 	uint32_t cpu_id = plat_my_core_pos();
 
-	cpuson_flags[cpu_id] = 0;
-	cpuson_entry_point[cpu_id] = 0;
-
 	/* Disable core_pm */
 	mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE);
 
@@ -246,33 +291,92 @@
 {
 	uint32_t slp_mode_cfg = 0;
 
-	slp_mode_cfg = PMU_PWR_MODE_EN |
-				   PMU_CPU0_PD_EN |
-				   PMU_L2_FLUSH_EN |
-				   PMU_L2_IDLE_EN |
-				   PMU_SCU_PD_EN |
-				   PMU_CLK_CORE_SRC_GATE_EN;
+	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
+		      BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) |
+		      BIT_WITH_WMSK(PMU_CLR_QREQ_CCI500_HW) |
+		      BIT_WITH_WMSK(PMU_QGATING_CCI500_CFG));
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      BIT_WITH_WMSK(PMU_CLR_CORE_L_HW) |
+		      BIT_WITH_WMSK(PMU_CLR_CORE_L_2GIC_HW) |
+		      BIT_WITH_WMSK(PMU_CLR_GIC2_CORE_L_HW));
+
+	mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1A_IOMUX,
+		      BIT_WITH_WMSK(AP_PWROFF));
+
+	slp_mode_cfg = BIT(PMU_PWR_MODE_EN) |
+		       BIT(PMU_POWER_OFF_REQ_CFG) |
+		       BIT(PMU_CPU0_PD_EN) |
+		       BIT(PMU_L2_FLUSH_EN) |
+		       BIT(PMU_L2_IDLE_EN) |
+		       BIT(PMU_SCU_PD_EN);
+
 	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, PMU_CLUSTER_L_WKUP_EN);
 	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, PMU_CLUSTER_B_WKUP_EN);
 	mmio_clrbits_32(PMU_BASE + PMU_WKUP_CFG4, PMU_GPIO_WKUP_EN);
+
 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg);
+
+	mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_24M_CNT_MS(5));
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_MS(2));
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_MS(2));
+	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_24M_CNT_MS(2));
+	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_24M_CNT_MS(2));
 }
 
 static int sys_pwr_domain_suspend(void)
 {
 	sys_slp_config();
 	plls_suspend();
-	psram_sleep_cfg->sys_mode = PMU_SYS_SLP_MODE;
 	pmu_sgrf_rst_hld();
+
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
+		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+
+	pmu_scu_b_pwrdn();
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
+		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) |
+		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_GIC2_CORE_B_SW));
+	dsb();
+	mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
+
 	return 0;
 }
 
 static int sys_pwr_domain_resume(void)
 {
-	pmu_sgrf_rst_hld_release();
-	psram_sleep_cfg->sys_mode = PMU_SYS_ON_MODE;
+	pmu_sgrf_rst_hld();
+
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
+		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+
 	plls_resume();
 
+	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
+		      WMSK_BIT(PMU_CLR_PREQ_CCI500_HW) |
+		      WMSK_BIT(PMU_CLR_QREQ_CCI500_HW) |
+		      WMSK_BIT(PMU_QGATING_CCI500_CFG));
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      WMSK_BIT(PMU_CLR_CORE_L_HW) |
+		      WMSK_BIT(PMU_CLR_CORE_L_2GIC_HW) |
+		      WMSK_BIT(PMU_CLR_GIC2_CORE_L_HW));
+
+	mmio_clrbits_32(PMU_BASE + PMU_PWRDN_CON,
+			BIT(PMU_SCU_B_PWRDWN_EN));
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
+		      WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_SW) |
+		      WMSK_BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW));
+
+	pmu_scu_b_pwrup();
+
+	plat_rockchip_gic_cpuif_enable();
 	return 0;
 }
 
@@ -294,19 +398,24 @@
 	rockchip_pd_lock_init();
 	plat_setup_rockchip_pm_ops(&pm_ops);
 
+	/* register requires 32bits mode, switch it to 32 bits */
+	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
+
 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
 		cpuson_flags[cpu] = 0;
 
-	psram_sleep_cfg->sys_mode = PMU_SYS_ON_MODE;
-
+	psram_sleep_cfg->ddr_func = 0x00;
+	psram_sleep_cfg->ddr_data = 0x00;
+	psram_sleep_cfg->ddr_flag = 0x00;
 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
 
 	/* cpu boot from pmusram */
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 
 	nonboot_cpus_off();
+
 	INFO("%s(%d): pd status %x\n", __func__, __LINE__,
 	     mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
 }
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
index 053b6ee..d5ff8ce 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -341,6 +341,25 @@
 
 	PMU_DDRCTL1_C_SYSREQ_CFG = 12,
 	PMU_DDR1_IO_RET_CFG,
+	DBG_PWRUP_B0_CFG = 15,
+
+	DBG_NOPWERDWN_L0_EN,
+	DBG_NOPWERDWN_L1_EN,
+	DBG_NOPWERDWN_L2_EN,
+	DBG_NOPWERDWN_L3_EN,
+
+	DBG_PWRUP_REQ_L_EN = 20,
+	CLUSTER_L_CLK_SRC_GATING_CFG,
+	L2_FLUSH_REQ_CLUSTER_L,
+	ACINACTM_CLUSTER_L_CFG,
+
+	DBG_NO_PWERDWN_B0_EN,
+	DBG_NO_PWERDWN_B1_EN,
+
+	DBG_PWRUP_REQ_B_EN = 28,
+	CLUSTER_B_CLK_SRC_GATING_CFG,
+	L2_FLUSH_REQ_CLUSTER_B,
+	ACINACTM_CLUSTER_B_CFG,
 };
 
 enum pmu_int_con {
@@ -638,12 +657,100 @@
 	PMU_IDLE_ACK_SDIOAUDIO,
 };
 
+enum pmu_cci500_con {
+	PMU_PREQ_CCI500_CFG_SW = 0,
+	PMU_CLR_PREQ_CCI500_HW,
+	PMU_PSTATE_CCI500_0,
+	PMU_PSTATE_CCI500_1,
+
+	PMU_PSTATE_CCI500_2,
+	PMU_QREQ_CCI500_CFG_SW,
+	PMU_CLR_QREQ_CCI500_HW,
+	PMU_QGATING_CCI500_CFG,
+
+	PMU_PREQ_CCI500_CFG_SW_WMSK = 16,
+	PMU_CLR_PREQ_CCI500_HW_WMSK,
+	PMU_PSTATE_CCI500_0_WMSK,
+	PMU_PSTATE_CCI500_1_WMSK,
+
+	PMU_PSTATE_CCI500_2_WMSK,
+	PMU_QREQ_CCI500_CFG_SW_WMSK,
+	PMU_CLR_QREQ_CCI500_HW_WMSK,
+	PMU_QGATING_CCI500_CFG_WMSK,
+};
+
+enum pmu_adb400_con {
+	PMU_PWRDWN_REQ_CXCS_SW = 0,
+	PMU_PWRDWN_REQ_CORE_L_SW,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW,
+
+	PMU_PWRDWN_REQ_CORE_B_SW,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW,
+
+	PMU_CLR_CXCS_HW = 8,
+	PMU_CLR_CORE_L_HW,
+	PMU_CLR_CORE_L_2GIC_HW,
+	PMU_CLR_GIC2_CORE_L_HW,
+
+	PMU_CLR_CORE_B_HW,
+	PMU_CLR_CORE_B_2GIC_HW,
+	PMU_CLR_GIC2_CORE_B_HW,
+
+	PMU_PWRDWN_REQ_CXCS_SW_WMSK = 16,
+	PMU_PWRDWN_REQ_CORE_L_SW_WMSK,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_WMSK,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_WMSK,
+
+	PMU_PWRDWN_REQ_CORE_B_SW_WMSK,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_WMSK,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_WMSK,
+
+	PMU_CLR_CXCS_HW_WMSK = 24,
+	PMU_CLR_CORE_L_HW_WMSK,
+	PMU_CLR_CORE_L_2GIC_HW_WMSK,
+	PMU_CLR_GIC2_CORE_L_HW_WMSK,
+
+	PMU_CLR_CORE_B_HW_WMSK,
+	PMU_CLR_CORE_B_2GIC_HW_WMSK,
+	PMU_CLR_GIC2_CORE_B_HW_WMSK,
+};
+
+enum pmu_adb400_st {
+	PMU_PWRDWN_REQ_CXCS_SW_ST = 0,
+	PMU_PWRDWN_REQ_CORE_L_SW_ST,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_ST,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_ST,
+
+	PMU_PWRDWN_REQ_CORE_B_SW_ST,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST,
+
+	PMU_CLR_CXCS_HW_ST = 8,
+	PMU_CLR_CORE_L_HW_ST,
+	PMU_CLR_CORE_L_2GIC_HW_ST,
+	PMU_CLR_GIC2_CORE_L_HW_ST,
+
+	PMU_CLR_CORE_B_HW_ST,
+	PMU_CLR_CORE_B_2GIC_HW_ST,
+	PMU_CLR_GIC2_CORE_B_HW_ST,
+};
+
 enum pmu_pwrdn_con1 {
 	PMU_VD_SCU_L_PWRDN_EN = 0,
 	PMU_VD_SCU_B_PWRDN_EN,
 	PMU_VD_CENTER_PWRDN_EN,
 };
 
+enum pmu_core_pwr_st {
+	L2_FLUSHDONE_CLUSTER_L = 0,
+	STANDBY_BY_WFIL2_CLUSTER_L,
+
+	L2_FLUSHDONE_CLUSTER_B = 10,
+	STANDBY_BY_WFIL2_CLUSTER_B,
+};
+
 #define PMU_WKUP_CFG0		0x00
 #define PMU_WKUP_CFG1		0x04
 #define PMU_WKUP_CFG2		0x08
@@ -701,9 +808,12 @@
 #define PMU_NOC_AUTO_ENA	0xd8
 #define PMU_PWRDN_CON1		0xdc
 
+#define PMUGRF_GPIO1A_IOMUX	0x10
+#define AP_PWROFF		0x0a
 #define CORES_PM_DISABLE	0x0
 
 #define PD_CTR_LOOP		500
 #define CHK_CPU_LOOP		500
+#define MAX_WAIT_CONUT		1000
 
 #endif /* __PMU_H__ */
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
index f8d66c2..5b7613d 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.c
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -55,6 +55,9 @@
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(RK3399_UART2_BASE, RK3399_UART2_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUGRF_BASE, PMUGRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+
 	{ 0 }
 };
 
@@ -313,12 +316,13 @@
 {
 	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
 		      CRU_PMU_SGRF_RST_RLS);
+
+	mmio_clrbits_32(CRU_BASE + CRU_GLB_RST_CON,
+			CRU_PMU_WDTRST_MSK | CRU_PMU_FIRST_SFTRST_MSK);
 }
 
 void  __dead2 soc_global_soft_reset(void)
 {
-	uint32_t temp_val;
-
 	set_pll_slow_mode(VPLL_ID);
 	set_pll_slow_mode(NPLL_ID);
 	set_pll_slow_mode(GPLL_ID);
@@ -326,9 +330,9 @@
 	set_pll_slow_mode(PPLL_ID);
 	set_pll_slow_mode(ABPLL_ID);
 	set_pll_slow_mode(ALPLL_ID);
-	temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON) |
-		   PMU_RST_BY_FIRST_SFT;
-	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val);
+
+	dsb();
+
 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
 
 	/*
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index 9100d02..e48f2f0 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -52,14 +52,16 @@
 #define NO_PLL_BYPASS			(0x00)
 #define NO_PLL_PWRDN			(0x00)
 
-#define PLL_SLOW_MODE			BITS_WITH_WMASK(PLL_MODE_MSK,\
-						SLOW_MODE, PLL_MODE_SHIFT)
-#define PLL_BYPASS_MODE			BITS_WITH_WMASK(PLL_BYPASS_MSK,\
-						PLL_BYPASS, PLL_BYPASS_SHIFT)
-#define PLL_NO_BYPASS_MODE		BITS_WITH_WMASK(PLL_BYPASS_MSK,\
-						NO_PLL_BYPASS, PLL_BYPASS_SHIFT)
-#define PLL_NOMAL_MODE			BITS_WITH_WMASK(PLL_MODE_MSK,\
-						NORMAL_MODE, PLL_MODE_SHIFT)
+#define PLL_SLOW_MODE		BITS_WITH_WMASK(SLOW_MODE,\
+						PLL_MODE_MSK, PLL_MODE_SHIFT)
+#define PLL_BYPASS_MODE		BITS_WITH_WMASK(PLL_BYPASS,\
+						PLL_BYPASS_MSK,\
+						PLL_BYPASS_SHIFT)
+#define PLL_NO_BYPASS_MODE	BITS_WITH_WMASK(NO_PLL_BYPASS,\
+						PLL_BYPASS_MSK,\
+						PLL_BYPASS_SHIFT)
+#define PLL_NOMAL_MODE		BITS_WITH_WMASK(NORMAL_MODE,\
+						PLL_MODE_MSK, PLL_MODE_SHIFT)
 
 #define PLL_CON_COUNT			0x06
 #define CRU_CLKSEL_COUNT		0x108
@@ -100,6 +102,9 @@
 	uint32_t cru_clksel_con[CRU_CLKSEL_COUNT];
 };
 
+#define CYCL_24M_CNT_US(us)	(24 * us)
+#define CYCL_24M_CNT_MS(ms)	(ms * CYCL_24M_CNT_US(1000))
+
 /**************************************************
  * secure timer
  **************************************************/
@@ -155,6 +160,13 @@
 #define CRU_PMU_SGRF_RST_HOLD		BIT_WITH_WMSK(6)
 /* reset hold release*/
 #define CRU_PMU_SGRF_RST_RLS		WMSK_BIT(6)
+
+#define CRU_PMU_WDTRST_MSK		(0x1 << 4)
+#define CRU_PMU_WDTRST_EN		0x0
+
+#define CRU_PMU_FIRST_SFTRST_MSK	(0x3 << 2)
+#define CRU_PMU_FIRST_SFTRST_EN		0x0
+
 /**************************************************
  * sgrf reg, offset
  **************************************************/