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
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,
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.
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;
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) |
suspend_apio();
suspend_gpio();
suspend_uart();
-
+ grf_register_save();
+ cru_register_save();
+ wdt_register_save();
sram_save();
+ plat_rockchip_save_gpio();
+
return 0;
}
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();
plat_rockchip_gic_cpuif_enable();
m0_stop();
+ restore_usbphy();
+
ddr_prepare_for_sys_resume();
return 0;