rockchip/rk3399: save and restore pd_alive register

pd_alive control cru, grf, timer, gpio and wdt, when
turn off logic power rail, these register value will
back to reset value, we need to save them value in suspend
and restore them when resuem, since timer will reinitial
in kernel, so it not need to save/restore.

Change-Id: I0fc2a011d3cdc04b66ffbf728e769eb28b51ee38
Signed-off-by: Lin Huang <hl@rock-chips.com>
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index 290811a..5456773 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -90,6 +90,8 @@
 struct gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count);
 struct apio_info *plat_get_rockchip_suspend_apio(void);
 void plat_rockchip_gpio_init(void);
+void plat_rockchip_save_gpio(void);
+void plat_rockchip_restore_gpio(void);
 
 int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint);
 int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl,
diff --git a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
index d5a2660..e74c4d9 100644
--- a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
+++ b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
@@ -22,10 +22,29 @@
 	GPIO4_BASE,
 };
 
+struct {
+	uint32_t swporta_dr;
+	uint32_t swporta_ddr;
+	uint32_t inten;
+	uint32_t intmask;
+	uint32_t inttype_level;
+	uint32_t int_polarity;
+	uint32_t debounce;
+	uint32_t ls_sync;
+} store_gpio[3];
+
+static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
+
 #define SWPORTA_DR	0x00
 #define SWPORTA_DDR	0x04
-#define EXT_PORTA	0x50
+#define INTEN		0x30
+#define INTMASK		0x34
+#define INTTYPE_LEVEL	0x38
+#define INT_POLARITY	0x3c
+#define DEBOUNCE	0x48
+#define LS_SYNC		0x60
 
+#define EXT_PORTA	0x50
 #define PMU_GPIO_PORT0	0
 #define PMU_GPIO_PORT1	1
 #define GPIO_PORT2	2
@@ -290,6 +309,99 @@
 	gpio_put_clock(gpio, clock_state);
 }
 
+void plat_rockchip_save_gpio(void)
+{
+	int i;
+	uint32_t cru_gate_save;
+
+	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
+
+	/*
+	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
+	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
+	 * and we do not care gpio0 and gpio1 clock gate, since we never
+	 * gating them
+	 */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+	/*
+	 * since gpio0, gpio1 are pmugpio, they will keep ther value
+	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
+	 * register value
+	 */
+	for (i = 2; i < 5; i++) {
+		store_gpio[i - 2].swporta_dr =
+			mmio_read_32(gpio_port[i] + SWPORTA_DR);
+		store_gpio[i - 2].swporta_ddr =
+			mmio_read_32(gpio_port[i] + SWPORTA_DDR);
+		store_gpio[i - 2].inten =
+			mmio_read_32(gpio_port[i] + INTEN);
+		store_gpio[i - 2].intmask =
+			mmio_read_32(gpio_port[i] + INTMASK);
+		store_gpio[i - 2].inttype_level =
+			mmio_read_32(gpio_port[i] + INTTYPE_LEVEL);
+		store_gpio[i - 2].int_polarity =
+			mmio_read_32(gpio_port[i] + INT_POLARITY);
+		store_gpio[i - 2].debounce =
+			mmio_read_32(gpio_port[i] + DEBOUNCE);
+		store_gpio[i - 2].ls_sync =
+			mmio_read_32(gpio_port[i] + LS_SYNC);
+	}
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			cru_gate_save | REG_SOC_WMSK);
+
+	/*
+	 * gpio0, gpio1 in pmuiomux, they will keep ther value
+	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
+	 * iomux register value
+	 */
+	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
+		store_grf_gpio[i] =
+			mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
+}
+
+void plat_rockchip_restore_gpio(void)
+{
+	int i;
+	uint32_t cru_gate_save;
+
+	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
+		      REG_SOC_WMSK | store_grf_gpio[i]);
+
+	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
+
+	/*
+	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
+	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
+	 * and we do not care gpio0 and gpio1 clock gate, since we never
+	 * gating them
+	 */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+	for (i = 2; i < 5; i++) {
+		mmio_write_32(gpio_port[i] + SWPORTA_DR,
+				store_gpio[i - 2].swporta_dr);
+		mmio_write_32(gpio_port[i] + SWPORTA_DDR,
+				store_gpio[i - 2].swporta_ddr);
+		mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten);
+		mmio_write_32(gpio_port[i] + INTMASK,
+				store_gpio[i - 2].intmask);
+		mmio_write_32(gpio_port[i] + INTTYPE_LEVEL,
+				store_gpio[i - 2].inttype_level);
+		mmio_write_32(gpio_port[i] + INT_POLARITY,
+				store_gpio[i - 2].int_polarity);
+		mmio_write_32(gpio_port[i] + DEBOUNCE,
+				store_gpio[i - 2].debounce);
+		mmio_write_32(gpio_port[i] + LS_SYNC,
+				store_gpio[i - 2].ls_sync);
+	}
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			cru_gate_save | REG_SOC_WMSK);
+}
+
 const gpio_ops_t rk3399_gpio_ops = {
 	.get_direction = get_direction,
 	.set_direction = set_direction,
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index d97b046..7f246c2 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -32,6 +32,19 @@
 
 static uint32_t cpu_warm_boot_addr;
 static char store_sram[SRAM_BIN_LIMIT + SRAM_TEXT_LIMIT + SRAM_DATA_LIMIT];
+static uint32_t store_cru[CRU_SDIO0_CON1 / 4];
+static uint32_t store_usbphy0[7];
+static uint32_t store_usbphy1[7];
+static uint32_t store_grf_io_vsel;
+static uint32_t store_grf_soc_con0;
+static uint32_t store_grf_soc_con1;
+static uint32_t store_grf_soc_con2;
+static uint32_t store_grf_soc_con3;
+static uint32_t store_grf_soc_con4;
+static uint32_t store_grf_soc_con7;
+static uint32_t store_grf_ddrc_con[4];
+static uint32_t store_wdt0[2];
+static uint32_t store_wdt1[2];
 
 /*
  * There are two ways to powering on or off on core.
@@ -1132,6 +1145,161 @@
 	mmio_write_32(PLAT_RK_UART_BASE + UART_MCR, uart_save.uart_mcr);
 }
 
+void save_usbphy(void)
+{
+	store_usbphy0[0] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL0);
+	store_usbphy0[1] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL2);
+	store_usbphy0[2] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL3);
+	store_usbphy0[3] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL12);
+	store_usbphy0[4] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL13);
+	store_usbphy0[5] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL15);
+	store_usbphy0[6] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL16);
+
+	store_usbphy1[0] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL0);
+	store_usbphy1[1] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL2);
+	store_usbphy1[2] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL3);
+	store_usbphy1[3] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL12);
+	store_usbphy1[4] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL13);
+	store_usbphy1[5] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL15);
+	store_usbphy1[6] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL16);
+}
+
+void restore_usbphy(void)
+{
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL0,
+		      REG_SOC_WMSK | store_usbphy0[0]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL2,
+		      REG_SOC_WMSK | store_usbphy0[1]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL3,
+		      REG_SOC_WMSK | store_usbphy0[2]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL12,
+		      REG_SOC_WMSK | store_usbphy0[3]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL13,
+		      REG_SOC_WMSK | store_usbphy0[4]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL15,
+		      REG_SOC_WMSK | store_usbphy0[5]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL16,
+		      REG_SOC_WMSK | store_usbphy0[6]);
+
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL0,
+		      REG_SOC_WMSK | store_usbphy1[0]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL2,
+		      REG_SOC_WMSK | store_usbphy1[1]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL3,
+		      REG_SOC_WMSK | store_usbphy1[2]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL12,
+		      REG_SOC_WMSK | store_usbphy1[3]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL13,
+		      REG_SOC_WMSK | store_usbphy1[4]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL15,
+		      REG_SOC_WMSK | store_usbphy1[5]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL16,
+		      REG_SOC_WMSK | store_usbphy1[6]);
+}
+
+void grf_register_save(void)
+{
+	int i;
+
+	store_grf_soc_con0 = mmio_read_32(GRF_BASE + GRF_SOC_CON(0));
+	store_grf_soc_con1 = mmio_read_32(GRF_BASE + GRF_SOC_CON(1));
+	store_grf_soc_con2 = mmio_read_32(GRF_BASE + GRF_SOC_CON(2));
+	store_grf_soc_con3 = mmio_read_32(GRF_BASE + GRF_SOC_CON(3));
+	store_grf_soc_con4 = mmio_read_32(GRF_BASE + GRF_SOC_CON(4));
+	store_grf_soc_con7 = mmio_read_32(GRF_BASE + GRF_SOC_CON(7));
+
+	for (i = 0; i < 4; i++)
+		store_grf_ddrc_con[i] =
+			mmio_read_32(GRF_BASE + GRF_DDRC0_CON0 + i * 4);
+
+	store_grf_io_vsel = mmio_read_32(GRF_BASE + GRF_IO_VSEL);
+}
+
+void grf_register_restore(void)
+{
+	int i;
+
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(0),
+		      REG_SOC_WMSK | store_grf_soc_con0);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(1),
+		      REG_SOC_WMSK | store_grf_soc_con1);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(2),
+		      REG_SOC_WMSK | store_grf_soc_con2);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(3),
+		      REG_SOC_WMSK | store_grf_soc_con3);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(4),
+		      REG_SOC_WMSK | store_grf_soc_con4);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(7),
+		      REG_SOC_WMSK | store_grf_soc_con7);
+
+	for (i = 0; i < 4; i++)
+		mmio_write_32(GRF_BASE + GRF_DDRC0_CON0 + i * 4,
+			      REG_SOC_WMSK | store_grf_ddrc_con[i]);
+
+	mmio_write_32(GRF_BASE + GRF_IO_VSEL, REG_SOC_WMSK | store_grf_io_vsel);
+}
+
+void cru_register_save(void)
+{
+	int i;
+
+	for (i = 0; i <= CRU_SDIO0_CON1; i = i + 4)
+		store_cru[i / 4] = mmio_read_32(CRU_BASE + i);
+}
+
+void cru_register_restore(void)
+{
+	int i;
+
+	for (i = 0; i <= CRU_SDIO0_CON1; i = i + 4) {
+
+		/*
+		 * since DPLL, CRU_CLKSEL_CON6 have been restore in
+		 * dmc_resume, ABPLL will resote later, so skip them
+		 */
+		if ((i == CRU_CLKSEL_CON6) ||
+		    (i >= CRU_PLL_CON(ABPLL_ID, 0) &&
+		     i <= CRU_PLL_CON(DPLL_ID, 5)))
+			continue;
+
+		if ((i == CRU_PLL_CON(ALPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(CPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(GPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(NPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(VPLL_ID, 2)))
+			mmio_write_32(CRU_BASE + i, store_cru[i / 4]);
+		/*
+		 * CRU_GLB_CNT_TH and CRU_CLKSEL_CON97~CRU_CLKSEL_CON107
+		 * not need do high 16bit mask
+		 */
+		else if ((i > 0x27c && i < 0x2b0) || (i == 0x508))
+			mmio_write_32(CRU_BASE + i, store_cru[i / 4]);
+		else
+			mmio_write_32(CRU_BASE + i,
+				      REG_SOC_WMSK | store_cru[i / 4]);
+	}
+}
+
+void wdt_register_save(void)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		store_wdt0[i] = mmio_read_32(WDT0_BASE + i * 4);
+		store_wdt1[i] = mmio_read_32(WDT1_BASE + i * 4);
+	}
+}
+
+void wdt_register_restore(void)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		mmio_write_32(WDT0_BASE + i * 4, store_wdt0[i]);
+		mmio_write_32(WDT1_BASE + i * 4, store_wdt1[i]);
+	}
+}
+
 int rockchip_soc_sys_pwr_dm_suspend(void)
 {
 	uint32_t wait_cnt = 0;
@@ -1141,6 +1309,9 @@
 	dmc_suspend();
 	pmu_scu_b_pwrdn();
 
+	/* need to save usbphy before shutdown PERIHP PD */
+	save_usbphy();
+
 	pmu_power_domains_suspend();
 	set_hw_idle(BIT(PMU_CLR_CENTER1) |
 		    BIT(PMU_CLR_ALIVE) |
@@ -1196,8 +1367,12 @@
 	suspend_apio();
 	suspend_gpio();
 	suspend_uart();
-
+	grf_register_save();
+	cru_register_save();
+	wdt_register_save();
 	sram_save();
+	plat_rockchip_save_gpio();
+
 	return 0;
 }
 
@@ -1206,6 +1381,10 @@
 	uint32_t wait_cnt = 0;
 	uint32_t status = 0;
 
+	plat_rockchip_restore_gpio();
+	wdt_register_restore();
+	cru_register_restore();
+	grf_register_restore();
 	resume_uart();
 	resume_apio();
 	resume_gpio();
@@ -1285,6 +1464,8 @@
 	plat_rockchip_gic_cpuif_enable();
 	m0_stop();
 
+	restore_usbphy();
+
 	ddr_prepare_for_sys_resume();
 
 	return 0;
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index 9680bea..c418337 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -189,14 +189,35 @@
 #define PWM_ENABLE			(1 << 0)
 
 /* grf reg offset */
+#define GRF_USBPHY0_CTRL0	0x4480
+#define GRF_USBPHY0_CTRL2	0x4488
+#define GRF_USBPHY0_CTRL3	0x448c
+#define GRF_USBPHY0_CTRL12	0x44b0
+#define GRF_USBPHY0_CTRL13	0x44b4
+#define GRF_USBPHY0_CTRL15	0x44bc
+#define GRF_USBPHY0_CTRL16	0x44c0
+
+#define GRF_USBPHY1_CTRL0	0x4500
+#define GRF_USBPHY1_CTRL2	0x4508
+#define GRF_USBPHY1_CTRL3	0x450c
+#define GRF_USBPHY1_CTRL12	0x4530
+#define GRF_USBPHY1_CTRL13	0x4534
+#define GRF_USBPHY1_CTRL15	0x453c
+#define GRF_USBPHY1_CTRL16	0x4540
+
+#define GRF_GPIO2A_IOMUX	0xe000
+#define GRF_GPIO2D_HE		0xe18c
 #define GRF_DDRC0_CON0		0xe380
 #define GRF_DDRC0_CON1		0xe384
 #define GRF_DDRC1_CON0		0xe388
 #define GRF_DDRC1_CON1		0xe38c
 #define GRF_SOC_CON_BASE	0xe200
 #define GRF_SOC_CON(n)		(GRF_SOC_CON_BASE + (n) * 4)
+#define GRF_IO_VSEL		0xe640
 
+#define CRU_CLKSEL_CON0		0x0100
 #define CRU_CLKSEL_CON6		0x0118
+#define CRU_SDIO0_CON1		0x058c
 #define PMUCRU_CLKSEL_CON0	0x0080
 #define PMUCRU_CLKGATE_CON2	0x0108
 #define PMUCRU_SOFTRST_CON0	0x0110
diff --git a/plat/rockchip/rk3399/include/shared/addressmap_shared.h b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
index fe23e56..dc5c8d5 100644
--- a/plat/rockchip/rk3399/include/shared/addressmap_shared.h
+++ b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
@@ -40,6 +40,9 @@
 #define GPIO2_BASE		(MMIO_BASE + 0x07780000)
 #define GPIO3_BASE		(MMIO_BASE + 0x07788000)
 #define GPIO4_BASE		(MMIO_BASE + 0x07790000)
+#define WDT1_BASE		(MMIO_BASE + 0x07840000)
+#define WDT0_BASE		(MMIO_BASE + 0x07848000)
+#define TIMER_BASE		(MMIO_BASE + 0x07850000)
 #define STIME_BASE		(MMIO_BASE + 0x07860000)
 #define SRAM_BASE		(MMIO_BASE + 0x078C0000)
 #define SERVICE_NOC_0_BASE	(MMIO_BASE + 0x07A50000)