// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2024 Rockchip Electronics Co., Ltd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rkpm_gicv2.h" #include "rkpm_helpers.h" #include "rkpm_uart.h" #include "rockchip_hptimer.h" #include "rv1103b_pm.h" #define RV1103B_PM_REG_REGION_MEM_SIZE SZ_4K enum { RV1103B_GPIO_PULL_NONE, RV1103B_GPIO_PULL_UP, RV1103B_GPIO_PULL_DOWN, RV1103B_GPIO_PULL_UP_DOWN, }; struct rockchip_pm_data { const struct platform_suspend_ops *ops; int (*init)(struct device_node *np); }; struct rv1103b_sleep_ddr_data { u32 entered_pmu_fsm; u32 cru_gate_con[RV1103B_CRU_GATE_CON_NUM]; u32 pmu0cru_gate_con[RV1103B_PMU0CRU_GATE_CON_NUM]; u32 pmu1cru_gate_con[RV1103B_PMU1CRU_GATE_CON_NUM]; u32 pericru_gate_con[RV1103B_PERICRU_GATE_CON_NUM]; u32 npucru_gate_con[RV1103B_NPUCRU_GATE_CON_NUM]; u32 venccru_gate_con[RV1103B_VENCCRU_GATE_CON_NUM]; u32 vicru_gate_con[RV1103B_VICRU_GATE_CON_NUM]; u32 corecru_gate_con[RV1103B_CORECRU_GATE_CON_NUM]; u32 ddrgrf_con1, ddrgrf_con5, ddrgrf_con8; u32 pmugrf_soc_con0, pmugrf_soc_con4, pmugrf_soc_con5, pmugrf_soc_con6; u32 gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l, gpio0b_iomux_h; u32 gpio0a_pull, gpio0b_pull; u32 gpio0_ddr_l, gpio0_ddr_h, gpio0_dr_l, gpio0_dr_h; u32 pmu_wkup_int_st, gpio0_int_st; }; static struct rv1103b_sleep_ddr_data ddr_data; static struct rk_sleep_config slp_cfg; static void __iomem *pericru_base; static void __iomem *venccru_base; static void __iomem *npucru_base; static void __iomem *vicru_base; static void __iomem *corecru_base; static void __iomem *ddrcru_base; static void __iomem *cru_base; static void __iomem *pmu0cru_base; static void __iomem *pmu1cru_base; static void __iomem *vencgrf_base; static void __iomem *npugrf_base; static void __iomem *vigrf_base; static void __iomem *coregrf_base; static void __iomem *ddrc_base; static void __iomem *ddrgrf_base; static void __iomem *perigrf_base; static void __iomem *pmugrf_base; static void __iomem *ioc3_base; static void __iomem *ioc47_base; static void __iomem *ioc6_base; static void __iomem *ioc0_base; static void __iomem *ioc1_base; static void __iomem *gpio_base[3]; static void __iomem *perisgrf_base; static void __iomem *pmusgrf_base; static void __iomem *qos_cpu_base; static void __iomem *qos_crypto_base; static void __iomem *qos_dcf_base; static void __iomem *qos_decom_base; static void __iomem *qos_dma2ddr_base; static void __iomem *qos_mac_base; static void __iomem *qos_mcu_base; static void __iomem *qos_rga2e_rd_base; static void __iomem *qos_rga2e_wr_base; static void __iomem *qos_rkdma_base; static void __iomem *qos_sdmmc1_base; static void __iomem *qos_usb_base; static void __iomem *qos_emmc_base; static void __iomem *qos_fspi_base; static void __iomem *qos_isp_base; static void __iomem *qos_sdmmc0_base; static void __iomem *qos_vicap_base; static void __iomem *qos_npu_base; static void __iomem *qos_rkvdec_base; static void __iomem *qos_fspi_pmu_base; static void __iomem *qos_lpmcu_base; static void __iomem *qos_spi2ahb_base; static void __iomem *gicd_base; static void __iomem *gicc_base; static void __iomem *pvtpll_core_base; static void __iomem *pvtpll_isp_base; static void __iomem *pvtpll_vepu_base; static void __iomem *pvtpll_npu_base; static void __iomem *hptimer_base; static void __iomem *pmu_base; static void __iomem *i2c0_base; static void __iomem *uartdbg_base; static void __iomem *pwm0_base; static void __iomem *lpmcu_mbox_base; static void __iomem *wdt_ns_base; static void __iomem *wdt_s_base; static void __iomem *nstimer_base[6]; static void __iomem *stimer_base[2]; static void __iomem *fw_ddr_base; static void __iomem *syssram_base; static void __iomem *pmusram_base; #define WMSK_VAL 0xffff0000 static struct reg_region vd_core_reg_rgns[] = { /* core_cru */ { REG_REGION(0x300, 0x308, 4, &corecru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x804, 4, &corecru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa04, 4, &corecru_base, WMSK_VAL)}, { REG_REGION(0xd00, 0xd00, 4, &corecru_base, 0)}, { REG_REGION(0xd04, 0xd04, 4, &corecru_base, WMSK_VAL)}, /* npu_cru */ { REG_REGION(0x300, 0x308, 4, &npucru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x800, 4, &npucru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa00, 4, &npucru_base, WMSK_VAL)}, /* core_grf */ { REG_REGION(0x000, 0x000, 4, &coregrf_base, WMSK_VAL)}, { REG_REGION(0x004, 0x004, 4, &coregrf_base, 0)}, /* npu_grf */ { REG_REGION(0x000, 0x000, 4, &npugrf_base, 0)}, /* qos */ { REG_REGION(0x08, 0x18, 4, &qos_cpu_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_npu_base, 0)}, }; static struct reg_region vd_log_reg_rgns[] = { /* firewall_ddr */ { REG_REGION(0x000, 0x01c, 4, &fw_ddr_base, 0)}, { REG_REGION(0x040, 0x060, 4, &fw_ddr_base, 0)}, { REG_REGION(0x0f0, 0x0f0, 4, &fw_ddr_base, 0)}, /* cru */ { REG_REGION(0x040, 0x044, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x048, 0x048, 4, &cru_base, 0)}, { REG_REGION(0x04c, 0x050, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x060, 0x064, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x068, 0x068, 4, &cru_base, 0)}, { REG_REGION(0x06c, 0x070, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x140, 0x1bc, 4, &cru_base, 0)}, /* { REG_REGION(0x280, 0x280, 4, &cru_base, WMSK_VAL)}, */ { REG_REGION(0x300, 0x308, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x314, 0x314, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x328, 0x330, 4, &cru_base, 0)}, { REG_REGION(0x350, 0x350, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x354, 0x354, 4, &cru_base, 0)}, { REG_REGION(0x378, 0x3a4, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x818, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa00, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0xd00, 0xd10, 8, &cru_base, 0)}, { REG_REGION(0xd04, 0xd14, 8, &cru_base, WMSK_VAL)}, { REG_REGION(0xd18, 0xd20, 4, &cru_base, WMSK_VAL)}, { REG_REGION(0xc00, 0xc00, 4, &cru_base, 0)}, { REG_REGION(0xc10, 0xc10, 4, &cru_base, 0)}, { REG_REGION(0xcc0, 0xcc0, 4, &cru_base, 0)}, /* peri_cru */ { REG_REGION(0x300, 0x30c, 4, &pericru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x82c, 4, &pericru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa2c, 4, &pericru_base, WMSK_VAL)}, { REG_REGION(0xc08, 0xc08, 4, &pericru_base, WMSK_VAL)}, /* peri_grf */ { REG_REGION(0x000, 0x00c, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x020, 0x034, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x050, 0x05c, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x070, 0x078, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x080, 0x090, 4, &perigrf_base, 0)}, { REG_REGION(0x0a0, 0x0a4, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x0b0, 0x0b4, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x100, 0x108, 4, &perigrf_base, WMSK_VAL)}, { REG_REGION(0x110, 0x11c, 4, &perigrf_base, 0)}, { REG_REGION(0x200, 0x210, 4, &perigrf_base, 0)}, { REG_REGION(0x214, 0x214, 4, &perigrf_base, WMSK_VAL)}, /* peri_sgrf */ { REG_REGION(0x008, 0x00c, 4, &perisgrf_base, WMSK_VAL)}, { REG_REGION(0x018, 0x018, 4, &perisgrf_base, WMSK_VAL)}, { REG_REGION(0x020, 0x03c, 4, &perisgrf_base, WMSK_VAL)}, { REG_REGION(0x080, 0x080, 4, &perisgrf_base, 0)}, /* vi_cru */ { REG_REGION(0x300, 0x300, 4, &vicru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x808, 4, &vicru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa04, 4, &vicru_base, WMSK_VAL)}, { REG_REGION(0xc08, 0xc08, 4, &vicru_base, WMSK_VAL)}, /* vepu_cru */ { REG_REGION(0x300, 0x308, 4, &venccru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x800, 4, &venccru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa00, 4, &venccru_base, WMSK_VAL)}, /* gpio1~2 */ { REG_REGION(0x000, 0x00c, 4, &gpio_base[1], WMSK_VAL)}, { REG_REGION(0x018, 0x044, 4, &gpio_base[1], WMSK_VAL)}, { REG_REGION(0x048, 0x048, 4, &gpio_base[1], 0)}, { REG_REGION(0x060, 0x064, 4, &gpio_base[1], WMSK_VAL)}, { REG_REGION(0x100, 0x108, 4, &gpio_base[1], WMSK_VAL)}, { REG_REGION(0x000, 0x00c, 4, &gpio_base[2], WMSK_VAL)}, { REG_REGION(0x018, 0x044, 4, &gpio_base[2], WMSK_VAL)}, { REG_REGION(0x048, 0x048, 4, &gpio_base[2], 0)}, { REG_REGION(0x060, 0x064, 4, &gpio_base[2], WMSK_VAL)}, { REG_REGION(0x100, 0x108, 4, &gpio_base[2], WMSK_VAL)}, /* vccio3_ioc */ { REG_REGION(0x020, 0x024, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x140, 0x148, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x210, 0x210, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x310, 0x310, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x410, 0x410, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x510, 0x510, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x610, 0x610, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x710, 0x710, 4, &ioc3_base, WMSK_VAL)}, { REG_REGION(0x800, 0x800, 4, &ioc3_base, WMSK_VAL)}, /* vccio47_ioc */ { REG_REGION(0x024, 0x03c, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x14c, 0x160, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x210, 0x218, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x310, 0x318, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x410, 0x418, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x510, 0x518, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x610, 0x618, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x710, 0x718, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x800, 0x808, 4, &ioc47_base, WMSK_VAL)}, { REG_REGION(0x80c, 0x80c, 4, &ioc47_base, 0)}, { REG_REGION(0x810, 0x810, 4, &ioc47_base, WMSK_VAL)}, /* vccio6_ioc */ { REG_REGION(0x040, 0x048, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x180, 0x194, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x220, 0x224, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x320, 0x324, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x420, 0x424, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x520, 0x524, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x620, 0x624, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x720, 0x724, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x800, 0x804, 4, &ioc6_base, WMSK_VAL)}, { REG_REGION(0x80c, 0x810, 4, &ioc6_base, WMSK_VAL)}, /* gpio1~2 int en */ { REG_REGION(0x010, 0x014, 4, &gpio_base[1], WMSK_VAL)}, { REG_REGION(0x010, 0x014, 4, &gpio_base[2], WMSK_VAL)}, /* NS TIMER 6 channel */ { REG_REGION(0x00, 0x04, 4, &nstimer_base[0], 0)}, { REG_REGION(0x10, 0x10, 4, &nstimer_base[0], 0)}, { REG_REGION(0x20, 0x24, 4, &nstimer_base[1], 0)}, { REG_REGION(0x30, 0x30, 4, &nstimer_base[1], 0)}, { REG_REGION(0x40, 0x44, 4, &nstimer_base[2], 0)}, { REG_REGION(0x50, 0x50, 4, &nstimer_base[2], 0)}, { REG_REGION(0x60, 0x64, 4, &nstimer_base[3], 0)}, { REG_REGION(0x70, 0x70, 4, &nstimer_base[3], 0)}, { REG_REGION(0x80, 0x84, 4, &nstimer_base[4], 0)}, { REG_REGION(0x90, 0x90, 4, &nstimer_base[4], 0)}, { REG_REGION(0xa0, 0xa4, 4, &nstimer_base[5], 0)}, { REG_REGION(0xb0, 0xb0, 4, &nstimer_base[5], 0)}, /* S TIMER0 2 channel */ { REG_REGION(0x00, 0x04, 4, &stimer_base[0], 0)}, { REG_REGION(0x10, 0x10, 4, &stimer_base[0], 0)}, { REG_REGION(0x20, 0x24, 4, &stimer_base[1], 0)}, { REG_REGION(0x30, 0x30, 4, &stimer_base[1], 0)}, /* wdt_ns */ { REG_REGION(0x04, 0x04, 4, &wdt_ns_base, 0)}, { REG_REGION(0x00, 0x00, 4, &wdt_ns_base, 0)}, /* wdt_s */ { REG_REGION(0x04, 0x04, 4, &wdt_s_base, 0)}, { REG_REGION(0x00, 0x00, 4, &wdt_s_base, 0)}, /* qos */ { REG_REGION(0x08, 0x18, 4, &qos_crypto_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_dcf_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_decom_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_dma2ddr_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_mac_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_mcu_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_rga2e_rd_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_rga2e_wr_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_rkdma_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_sdmmc1_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_usb_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_emmc_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_fspi_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_isp_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_sdmmc0_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_vicap_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_rkvdec_base, 0)}, }; static struct reg_region pd_pmu1_reg_rgns[] = { /* pmu1_cru */ { REG_REGION(0x300, 0x300, 4, &pmu1cru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x804, 4, &pmu1cru_base, WMSK_VAL)}, { REG_REGION(0xa00, 0xa04, 4, &pmu1cru_base, WMSK_VAL)}, { REG_REGION(0xc08, 0xc08, 4, &pmu1cru_base, WMSK_VAL)}, /* pmu1_ioc */ { REG_REGION(0x008, 0x00c, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x110, 0x118, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x204, 0x204, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x304, 0x304, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x404, 0x404, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x504, 0x504, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x604, 0x604, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x704, 0x704, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x800, 0x804, 4, &ioc1_base, WMSK_VAL)}, { REG_REGION(0x808, 0x808, 4, &ioc1_base, 0)}, /* qos */ { REG_REGION(0x08, 0x18, 4, &qos_fspi_pmu_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_lpmcu_base, 0)}, { REG_REGION(0x08, 0x18, 4, &qos_spi2ahb_base, 0)}, }; static struct reg_region pvtpll_core_reg_rgns[] = { { REG_REGION(0x020, 0x024, 4, &pvtpll_core_base, WMSK_VAL)}, { REG_REGION(0x020, 0x024, 4, &pvtpll_npu_base, WMSK_VAL)}, }; static struct reg_region pvtpll_logic_reg_rgns[] = { { REG_REGION(0x020, 0x024, 4, &pvtpll_vepu_base, WMSK_VAL)}, { REG_REGION(0x020, 0x024, 4, &pvtpll_isp_base, WMSK_VAL)}, }; #define PLL_LOCKED_TIMEOUT 600000U static void pm_pll_wait_lock(u32 pll_id) { int delay = PLL_LOCKED_TIMEOUT; if (readl_relaxed(cru_base + RV1103B_CRU_PLL_CON(pll_id, 1)) & CRU_PLLCON1_PWRDOWN) return; while (delay-- >= 0) { if (readl_relaxed(cru_base + RV1103B_CRU_PLL_CON(pll_id, 1)) & CRU_PLLCON1_LOCK_STATUS) break; rkpm_raw_udelay(1); } if (delay <= 0) { rkpm_printstr("Can't wait pll lock: "); rkpm_printhex(pll_id); rkpm_printch('\n'); } } static struct plat_gicv2_dist_ctx_t gicd_ctx_save; static struct plat_gicv2_cpu_ctx_t gicc_ctx_save; static void gic400_save(void) { rkpm_gicv2_cpu_save(gicd_base, gicc_base, &gicc_ctx_save); rkpm_gicv2_dist_save(gicd_base, &gicd_ctx_save); } static void gic400_restore(void) { rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save); rkpm_gicv2_cpu_restore(gicd_base, gicc_base, &gicc_ctx_save); } static void uart_wrtie_byte(uint8_t byte) { writel_relaxed(byte, uartdbg_base + 0x0); while (!(readl_relaxed(uartdbg_base + 0x14) & 0x40)) ; } void rkpm_printch(int c) { if (c == '\n') uart_wrtie_byte('\r'); uart_wrtie_byte(c); } #define RV1103B_DUMP_GPIO_INTEN(id) \ do { \ rkpm_printstr("GPIO"); \ rkpm_printdec(id); \ rkpm_printstr(": "); \ rkpm_printhex(readl_relaxed(gpio_base[id] + RV1103B_GPIO_INT_EN_L)); \ rkpm_printch(' '); \ rkpm_printhex(readl_relaxed(gpio_base[id] + RV1103B_GPIO_INT_EN_H)); \ rkpm_printch(' '); \ rkpm_printhex(readl_relaxed(gpio_base[id] + RV1103B_GPIO_INT_MASK_L)); \ rkpm_printch(' '); \ rkpm_printhex(readl_relaxed(gpio_base[id] + RV1103B_GPIO_INT_MASK_H)); \ rkpm_printch(' '); \ rkpm_printhex(readl_relaxed(gpio_base[id] + RV1103B_GPIO_INT_STATUS)); \ rkpm_printch(' '); \ rkpm_printhex(readl_relaxed(gpio_base[id] + RV1103B_GPIO_INT_RAWSTATUS));\ rkpm_printch('\n'); \ } while (0) static void rv1103b_dbg_sleep_enter_info(void) { static u32 sleep_cnt; u32 cfg = slp_cfg.mode_config; rkpm_printstr("enter:"); rkpm_printhex(cfg); rkpm_printstr(", "); rkpm_printhex(slp_cfg.wakeup_config); rkpm_printstr(", "); rkpm_printdec(++sleep_cnt); rkpm_printch('\n'); if (cfg & RKPM_SLP_ARMPD) rkpm_printstr("armpd\n"); if (cfg & RKPM_SLP_ARMOFF) rkpm_printstr("armoff\n"); if (cfg & RKPM_SLP_ARMOFF_LOGOFF) rkpm_printstr("logoff\n"); if (cfg & RKPM_SLP_ARMOFF_PMUOFF) rkpm_printstr("pmuoff\n"); if (cfg & RKPM_SLP_PMU_HW_PLLS_PD) rkpm_printstr("hw_plls_pd\n"); if (cfg & RKPM_SLP_PMU_PMUALIVE_32K) rkpm_printstr("pmualive_32k\n"); if (cfg & RKPM_SLP_PMU_DIS_OSC) rkpm_printstr("dis_osc\n"); if (cfg & RKPM_SLP_32K_EXT) rkpm_printstr("32k ext\n"); if (cfg & RKPM_SLP_TIME_OUT_WKUP) rkpm_printstr("timeout wkup\n"); if (cfg & RKPM_SLP_PMU_DBG) rkpm_printstr("pmu debug\n"); if (cfg & RKPM_SLP_LP_PR) rkpm_printstr("LP_PR\n"); } static void rv1103b_dbg_pmu_wkup_src(void) { u32 pmu_int_st = ddr_data.pmu_wkup_int_st; rkpm_printstr("wake up status:"); rkpm_printhex(pmu_int_st); rkpm_printch('\n'); if (pmu_int_st) rkpm_printstr("wake up information:\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_GPIO_INT)) { rkpm_printstr("GPIO0 wakeup:"); rkpm_printhex(ddr_data.gpio0_int_st); rkpm_printch('\n'); } if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_SDMMC0)) rkpm_printstr("SDMMC wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_SDIO)) rkpm_printstr("SDIO wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_USBDEV)) rkpm_printstr("USBDEV wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_UART0)) rkpm_printstr("UART0 wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_PWM0)) rkpm_printstr("PWM0 wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_TIMER)) rkpm_printstr("TIMER wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_HPTIMER)) rkpm_printstr("HPTIMER wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_SYS_INT)) rkpm_printstr("SYS_INT wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_AOV)) rkpm_printstr("AOV wakeup\n"); if (pmu_int_st & BIT(RV1103B_PMU_WAKEUP_TIMEOUT)) rkpm_printstr("TIMEOUT wakeup\n"); rkpm_printch('\n'); } static void rv1103b_dbg_irq_prepare(void) { RV1103B_DUMP_GPIO_INTEN(0); } static void rv1103b_dbg_irq_finish(void) { rv1103b_dbg_pmu_wkup_src(); } static inline u32 rv1103b_l2_config(void) { u32 l2ctlr; asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (l2ctlr)); return l2ctlr; } static void __init rv1103b_config_bootdata(void) { rkpm_bootdata_cpusp = RV1103B_PMUSRAM_BASE + (SZ_8K - 8); rkpm_bootdata_cpu_code = __pa_symbol(cpu_resume); rkpm_bootdata_l2ctlr_f = 1; rkpm_bootdata_l2ctlr = rv1103b_l2_config(); } static void clock_suspend(void) { int i; for (i = 0; i < RV1103B_CRU_GATE_CON_NUM; i++) { ddr_data.cru_gate_con[i] = readl_relaxed(cru_base + RV1103B_CRU_GATE_CON(i)); writel_relaxed(0xffff0000, cru_base + RV1103B_CRU_GATE_CON(i)); } for (i = 0; i < RV1103B_PMU0CRU_GATE_CON_NUM; i++) { ddr_data.pmu0cru_gate_con[i] = readl_relaxed(pmu0cru_base + RV1103B_PMU0CRU_GATE_CON(i)); writel_relaxed(0xffff0000, pmu0cru_base + RV1103B_PMU0CRU_GATE_CON(i)); } for (i = 0; i < RV1103B_PMU1CRU_GATE_CON_NUM; i++) { ddr_data.pmu1cru_gate_con[i] = readl_relaxed(pmu1cru_base + RV1103B_PMU1CRU_GATE_CON(i)); writel_relaxed(0xffff0000, pmu1cru_base + RV1103B_PMU1CRU_GATE_CON(i)); } for (i = 0; i < RV1103B_PERICRU_GATE_CON_NUM; i++) { ddr_data.pericru_gate_con[i] = readl_relaxed(pericru_base + RV1103B_PERICRU_GATE_CON(i)); writel_relaxed(0xffff0000, pericru_base + RV1103B_PERICRU_GATE_CON(i)); } for (i = 0; i < RV1103B_NPUCRU_GATE_CON_NUM; i++) { ddr_data.npucru_gate_con[i] = readl_relaxed(npucru_base + RV1103B_NPUCRU_GATE_CON(i)); writel_relaxed(0xffff0000, npucru_base + RV1103B_NPUCRU_GATE_CON(i)); } for (i = 0; i < RV1103B_VENCCRU_GATE_CON_NUM; i++) { ddr_data.venccru_gate_con[i] = readl_relaxed(venccru_base + RV1103B_VENCCRU_GATE_CON(i)); writel_relaxed(0xffff0000, venccru_base + RV1103B_VENCCRU_GATE_CON(i)); } for (i = 0; i < RV1103B_VICRU_GATE_CON_NUM; i++) { ddr_data.vicru_gate_con[i] = readl_relaxed(vicru_base + RV1103B_VICRU_GATE_CON(i)); writel_relaxed(0xffff0000, vicru_base + RV1103B_VICRU_GATE_CON(i)); } for (i = 0; i < RV1103B_CORECRU_GATE_CON_NUM; i++) { ddr_data.corecru_gate_con[i] = readl_relaxed(corecru_base + RV1103B_CORECRU_GATE_CON(i)); writel_relaxed(0xffff0000, corecru_base + RV1103B_CORECRU_GATE_CON(i)); } } static void clock_resume(void) { int i; for (i = 0; i < RV1103B_CRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.cru_gate_con[i]), cru_base + RV1103B_CRU_GATE_CON(i)); for (i = 0; i < RV1103B_PMU0CRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmu0cru_gate_con[i]), pmu0cru_base + RV1103B_PMU0CRU_GATE_CON(i)); for (i = 0; i < RV1103B_PMU1CRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmu1cru_gate_con[i]), pmu1cru_base + RV1103B_PMU1CRU_GATE_CON(i)); for (i = 0; i < RV1103B_PERICRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.pericru_gate_con[i]), pericru_base + RV1103B_PERICRU_GATE_CON(i)); for (i = 0; i < RV1103B_NPUCRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.npucru_gate_con[i]), npucru_base + RV1103B_NPUCRU_GATE_CON(i)); for (i = 0; i < RV1103B_VENCCRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.venccru_gate_con[i]), venccru_base + RV1103B_VENCCRU_GATE_CON(i)); for (i = 0; i < RV1103B_VICRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.vicru_gate_con[i]), vicru_base + RV1103B_VICRU_GATE_CON(i)); for (i = 0; i < RV1103B_CORECRU_GATE_CON_NUM; i++) writel_relaxed(WITH_16BITS_WMSK(ddr_data.corecru_gate_con[i]), corecru_base + RV1103B_CORECRU_GATE_CON(i)); } static void sleep_32k_config(void) { if (slp_cfg.mode_config & RKPM_SLP_32K_EXT) { /* deepslow select clk_32k_rtc */ writel_relaxed(BITS_WITH_WMASK(0x1, 0x3, 0), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); } else if ((slp_cfg.mode_config & RKPM_SLP_LP_PR) == 0) { /* 125M * (16 / 61035) = 32.768k */ writel_relaxed(0x0010ee6b, pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(1)); /* select rc_osc_io */ writel_relaxed(BITS_WITH_WMASK(0x1, 0x1, 2), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); /* deepslow select xin_rc_div */ writel_relaxed(BITS_WITH_WMASK(0x0, 0x3, 0), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); /* enable rc_osc */ writel_relaxed(BITS_WITH_WMASK(0x1, 0x7, 0), pmugrf_base + RV1103B_PMUGRF_SOC_CON(7)); } } static void sleep_32k_config_restore(void) { /* if no ext-32k, select osc_div_32k */ if ((slp_cfg.mode_config & RKPM_SLP_32K_EXT) == 0) { writel_relaxed(BITS_WITH_WMASK(0x0, 0x1, 2), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); writel_relaxed(BITS_WITH_WMASK(0x0, 0x3, 0), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); } } static void ddr_sleep_config(void) { u32 val; ddr_data.ddrgrf_con1 = readl_relaxed(ddrgrf_base + RV1103B_DDRGRF_CON(1)); ddr_data.ddrgrf_con5 = readl_relaxed(ddrgrf_base + RV1103B_DDRGRF_CON(5)); ddr_data.ddrgrf_con8 = readl_relaxed(ddrgrf_base + RV1103B_DDRGRF_CON(8)); ddr_data.pmugrf_soc_con0 = readl_relaxed(pmugrf_base + RV1103B_PMUGRF_SOC_CON(0)); /* PWRCTL, disable auto powerdown and auto selfref */ val = readl_relaxed(ddrc_base + 0x30); writel_relaxed(val & ~(BIT(0) | BIT(1)), ddrc_base + 0x30); /* disable ddrc_aclk_auto_gate and biu_clk_auto_gate */ writel_relaxed(BITS_WITH_WMASK(0x0, 0x3, 9), ddrgrf_base + RV1103B_DDRGRF_CON(1)); /* disable ddrc_axi/core/apb/syscreq/pdsrlp_cg_en */ writel_relaxed(BITS_WITH_WMASK(0x0, 0x1ff, 0), ddrgrf_base + RV1103B_DDRGRF_CON(1)); /* csysreq_ddrc_pmu, the hardware low power request signal by pmu */ writel_relaxed(BITS_WITH_WMASK(0x1, 0x1, 3), ddrgrf_base + RV1103B_DDRGRF_CON(5)); /* csysreq_aclk_cpu/npvd/vi_pmu enable */ writel_relaxed(BITS_WITH_WMASK(0x7, 0x7, 4), ddrgrf_base + RV1103B_DDRGRF_CON(8)); /* STAT, waiting operating_mode to Normal */ while ((readl_relaxed(ddrc_base + 0x4) & 0x7) != 0x1) continue; /* ddr io_ret and io_hz by pmu */ writel_relaxed(BITS_WITH_WMASK(0x0, 0xf, 9), pmugrf_base + RV1103B_PMUGRF_SOC_CON(0)); } static void ddr_sleep_config_restore(void) { writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con0), pmugrf_base + RV1103B_PMUGRF_SOC_CON(0)); writel_relaxed(WITH_16BITS_WMSK(ddr_data.ddrgrf_con1), ddrgrf_base + RV1103B_DDRGRF_CON(1)); writel_relaxed(WITH_16BITS_WMSK(ddr_data.ddrgrf_con8), ddrgrf_base + RV1103B_DDRGRF_CON(8)); writel_relaxed(WITH_16BITS_WMSK(ddr_data.ddrgrf_con5), ddrgrf_base + RV1103B_DDRGRF_CON(5)); } static void suspend_workaround_timeout_wkup(void) { int wkup; u32 delta_cnt; if (ddr_data.entered_pmu_fsm) return; wkup = readl_relaxed(pmu_base + RV1103B_PMU1_WAKEUP_INT_CON); if ((wkup & BIT(RV1103B_PMU_WAKEUP_TIMEOUT)) == 0) return; wkup = (wkup & ~BIT(RV1103B_PMU_WAKEUP_TIMEOUT)) | BIT(RV1103B_PMU_WAKEUP_HPTIMER); writel_relaxed(wkup, pmu_base + RV1103B_PMU1_WAKEUP_INT_CON); delta_cnt = readl_relaxed(pmu_base + RV1103B_PMU1_WAKEUP_TIMEOUT); if (slp_cfg.mode_config & RKPM_SLP_PMU_PMUALIVE_32K) delta_cnt = delta_cnt / 32 * 24000; rk_hptimer_v2_config_sleep_timeout_int(hptimer_base, delta_cnt); } static void resume_workaround_timeout_wkup(void) { if (ddr_data.entered_pmu_fsm) return; /* resume from pmu_fsm */ if (ddr_data.pmu_wkup_int_st) ddr_data.entered_pmu_fsm = 1; rk_hptimer_v2_disable_int(hptimer_base, RK_HPTIMER_V2_INT_32K_REACH); rk_hptimer_v2_clear_int_st(hptimer_base, RK_HPTIMER_V2_INT_32K_REACH); } static void pmu_sleep_config(void) { u32 clk_freq_khz = 32; u32 pmu0_pwr_con; u32 pmu1_wkup_con, pmu1_pwr_con, pmu1_scu_con, pmu1_ddr_con; u32 pmu2_bus_idle_con, pmu1_cru_con[2], pmu1_pll_con; u32 cfg = slp_cfg.mode_config; ddr_data.pmugrf_soc_con4 = readl_relaxed(pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); ddr_data.pmugrf_soc_con5 = readl_relaxed(pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); ddr_data.pmugrf_soc_con6 = readl_relaxed(pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); pmu0_pwr_con = 0; pmu1_wkup_con = slp_cfg.wakeup_config; if (readl_relaxed(pmu_base + RV1103B_PMU1_WAKEUP_TIMEOUT) != 0) pmu1_wkup_con |= BIT(RV1103B_PMU_WAKEUP_TIMEOUT); pmu1_pwr_con = BIT(RV1103B_PMU_PWRMODE1_EN) | /* BIT(RV1103B_PMU_SCU_BYPASS) | */ /* BIT(RV1103B_PMU_BUS_BYPASS) | */ /* BIT(RV1103B_PMU_DDR_BYPASS) | */ /* BIT(RV1103B_PMU_PWRGT_BYPASS) | */ /* BIT(RV1103B_PMU_CRU_BYPASS) | */ BIT(RV1103B_PMU_PDPMU1_BYPASS) | /* BIT(RV1103B_PMU_WFI_BYPASS) | */ BIT(RV1103B_PMU_SLP_CNT_EN) | 0; pmu1_scu_con = BIT(RV1103B_PMU_SCU_L2_FLUSH) | BIT(RV1103B_PMU_SCU_L2_IDLE) | BIT(RV1103B_PMU_SCU_PWRDN) | BIT(RV1103B_PMU_SCU_PWROFF) | BIT(RV1103B_PMU_CLST_CPU_PD) | BIT(RV1103B_PMU_SCU_VOL_GT) | BIT(RV1103B_PMU_CLST_CLK_SRC_GT) | 0; pmu2_bus_idle_con = BIT(RV1103B_PMU_IDLE_REQ_MSCH) | BIT(RV1103B_PMU_IDLE_REQ_DDRC) | BIT(RV1103B_PMU_IDLE_REQ_PERI) | BIT(RV1103B_PMU_IDLE_REQ_VEPU) | BIT(RV1103B_PMU_IDLE_REQ_VI) | BIT(RV1103B_PMU_IDLE_REQ_CRU) | 0; pmu1_cru_con[0] = BIT(RV1103B_PMU_WAKEUP_RST) | BIT(RV1103B_PMU_INPUT_CLAMP) | BIT(RV1103B_PMU_ALIVE_OSC_EN) | BIT(RV1103B_PMU_POWER_OFF) | /* BIT(RV1103B_PMU_PWM_SWITCH) | */ /* BIT(RV1103B_PMU_GPIO_IOE) | */ /* BIT(RV1103B_PMU_PWM_SWITCH_IOUT) | */ BIT(RV1103B_PMU_OFF_IO) | /* BIT(RV1103B_PWM_CLK_GT_PLL) | */ /* BIT(RV1103B_PWM_CLK_GT_OSC) | */ 0; pmu1_cru_con[1] = /* BIT(RV1103B_PMU_PERI_CLK_SRC_GT) | */ /* BIT(RV1103B_PMU_VENC_CLK_SRC_GT) | */ /* BIT(RV1103B_PMU_VI_CLK_SRC_GT) | */ /* BIT(RV1103B_PMU_NPU_CLK_SRC_GT) | */ /* BIT(RV1103B_PMU_CORE_CLK_SRC_GT) | */ /* BIT(RV1103B_PMU_DDR_CLK_SRC_GT) | */ 0; pmu1_ddr_con = BIT(RV1103B_PMU_DDR_SREF_C) | BIT(RV1103B_PMU_DDR_SREF_A) | BIT(RV1103B_PMU_DDRIO_RETON_ENTER) | /* BIT(RV1103B_PMU_DDRIO_RETON_EXIT) | */ BIT(RV1103B_PMU_DDRIO_RSTIOV_ENTER) | /* BIT(RV1103B_PMU_DDRIO_RSTIOV_EXIT) | */ BIT(RV1103B_PMU_DDRCTL_A_AUTO_GATING) | BIT(RV1103B_PMU_DDRCTL_C_AUTO_GATING) | BIT(RV1103B_PMU_DDRPHY_AUTO_GATING) | BIT(RV1103B_PMU_DDRIO_HZ_ENTER) | /* BIT(RV1103B_PMU_DDRIO_HZ_EXIT) | */ 0; pmu1_pll_con = BIT(RV1103B_PMU_DPLL_PD) | BIT(RV1103B_PMU_GPLL_PD) | 0; if (cfg & RKPM_SLP_PMU_PMUALIVE_32K) { pmu1_cru_con[0] |= BIT(RV1103B_PMU_ALIVE_32K) | 0; clk_freq_khz = 32; } else { clk_freq_khz = 24000; } if (cfg & RKPM_SLP_PMU_DIS_OSC) { pmu1_cru_con[0] |= BIT(RV1103B_PMU_OSC_DIS) | 0; } if (cfg & RKPM_SLP_TIME_OUT_WKUP) { writel_relaxed(clk_freq_khz * 1000, pmu_base + RV1103B_PMU1_WAKEUP_TIMEOUT); pmu1_wkup_con |= BIT(RV1103B_PMU_WAKEUP_TIMEOUT); } if (cfg & RKPM_SLP_ARMPD) { pmu1_pwr_con &= ~(BIT(RV1103B_PMU_SLP_CNT_EN) | 0); pmu1_cru_con[0] &= ~(BIT(RV1103B_PMU_WAKEUP_RST) | BIT(RV1103B_PMU_INPUT_CLAMP) | BIT(RV1103B_PMU_POWER_OFF) | 0); pmu1_ddr_con = BIT(RV1103B_PMU_DDR_SREF_C) | BIT(RV1103B_PMU_DDR_SREF_A) | 0; /* resume from pmusram */ writel_relaxed(BITS_WITH_WMASK(2, 0x3, 10), pmusgrf_base + RV1103B_PMUSGRF_SOC_CON(1)); } else if (cfg & RKPM_SLP_ARMOFF) { pmu1_cru_con[0] &= ~(BIT(RV1103B_PMU_WAKEUP_RST) | BIT(RV1103B_PMU_INPUT_CLAMP) | 0); /* resume from pmusram */ writel_relaxed(BITS_WITH_WMASK(2, 0x3, 10), pmusgrf_base + RV1103B_PMUSGRF_SOC_CON(1)); } else if (cfg & RKPM_SLP_ARMOFF_LOGOFF) { /* pmu reset hold */ /* except lpmcu */ writel_relaxed(0xffff3fff, pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); /* except lpmcu */ writel_relaxed(0x007f007e, pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); writel_relaxed(0xffffffff, pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); /* resume from pmusram */ writel_relaxed(BITS_WITH_WMASK(0, 0x3, 10), pmusgrf_base + RV1103B_PMUSGRF_SOC_CON(1)); } else if (cfg & RKPM_SLP_ARMOFF_PMUOFF) { pmu1_pwr_con &= ~(BIT(RV1103B_PMU_PDPMU1_BYPASS) | 0); pmu0_pwr_con |= BIT(RV1103B_PMU_PWRMODE0_EN) | /* BIT(RV1103B_PMU1_PWR_BYPASS) | */ BIT(RV1103B_PMU1_BUS_BYPASS) | BIT(RV1103B_PMU1_PWRGT_EN) | BIT(RV1103B_PMU1_BUS_IDLE_EN) | BIT(RV1103B_PMU1_BUS_AUTO) | 0; /* pmu reset hold */ /* except lpmcu */ writel_relaxed(0xffff3fff, pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); /* except lpmcu */ writel_relaxed(0x007f007e, pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); /* resume from bootrom */ writel_relaxed(BITS_WITH_WMASK(0, 0x3, 10), pmusgrf_base + RV1103B_PMUSGRF_SOC_CON(1)); } if (cfg & RKPM_SLP_LP_PR) { writel_relaxed(0, pmugrf_base + RV1103B_PMUGRF_OS_REG(2)); writel_relaxed(0, pmugrf_base + RV1103B_PMUGRF_OS_REG(3)); writel_relaxed(0xffffffff, pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); writel_relaxed(0x00ff00ff, pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); writel_relaxed(0xffffffff, pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); pmu1_pwr_con &= ~(BIT(RV1103B_PMU_DDR_BYPASS) | 0); } /* pmu count */ writel_relaxed(clk_freq_khz * 4, pmu_base + RV1103B_PMU1_OSC_STABLE_CNT); writel_relaxed(clk_freq_khz * 6, pmu_base + RV1103B_PMU1_PMIC_STABLE_CNT); writel_relaxed(clk_freq_khz * 15, pmu_base + RV1103B_PMU1_SLEEP_CNT); /* Pmu's clk has switched to 24M back When pmu FSM counts * the follow counters, so we should use 24M to calculate * these counters. */ writel_relaxed(0, pmu_base + RV1103B_PMU1_WAKEUP_RST_CLR_CNT); writel_relaxed(1200, pmu_base + RV1103B_PMU1_PLL_LOCK_CNT); writel_relaxed(24000 * 2, pmu_base + RV1103B_PMU1_PWM_SWITCH_CNT); writel_relaxed(0, pmu_base + RV1103B_PMU2_SCU_STABLE_CNT); writel_relaxed(0, pmu_base + RV1103B_PMU2_SCU_PWRUP_CNT); writel_relaxed(0, pmu_base + RV1103B_PMU2_SCU_PWRDN_CNT); writel_relaxed(0, pmu_base + RV1103B_PMU2_SCU_VOLUP_CNT); writel_relaxed(0, pmu_base + RV1103B_PMU2_SCU_VOLDN_CNT); writel_relaxed(0x00010001, pmu_base + RV1103B_PMU1_INT_MASK_CON); writel_relaxed(WITH_16BITS_WMSK(pmu1_scu_con), pmu_base + RV1103B_PMU2_SCU_PWR_CON); writel_relaxed(0x003f003f, pmu_base + RV1103B_PMU2_CLUSTER_IDLE_CON); writel_relaxed(0xffff0000 | BIT(RV1103B_CPU_AUTO_INT_MSK), pmu_base + RV1103B_PMU2_CPU_AUTO_PWR_CON); writel_relaxed(0xffff0000 | BIT(RV1103B_SCU_AUTO_INT_MSK), pmu_base + RV1103B_PMU2_SCU_AUTO_PWR_CON); writel_relaxed(WITH_16BITS_WMSK(pmu1_cru_con[0]), pmu_base + RV1103B_PMU1_CRU_PWR_CON(0)); writel_relaxed(WITH_16BITS_WMSK(pmu1_cru_con[1]), pmu_base + RV1103B_PMU1_CRU_PWR_CON(1)); writel_relaxed(WITH_16BITS_WMSK(pmu2_bus_idle_con), pmu_base + RV1103B_PMU2_BUS_IDLE_CON); writel_relaxed(WITH_16BITS_WMSK(pmu1_ddr_con), pmu_base + RV1103B_PMU1_DDR_PWR_CON); writel_relaxed(WITH_16BITS_WMSK(pmu1_pll_con), pmu_base + RV1103B_PMU1_PLLPD_CON); writel_relaxed(pmu1_wkup_con, pmu_base + RV1103B_PMU1_WAKEUP_INT_CON); writel_relaxed(WITH_16BITS_WMSK(pmu1_pwr_con), pmu_base + RV1103B_PMU1_PWR_CON); writel_relaxed(WITH_16BITS_WMSK(pmu0_pwr_con), pmu_base + RV1103B_PMU0_PWR_CON); #if RV1103B_WAKEUP_TO_SYSTEM_RESET writel_relaxed(0, pmugrf_base + RV1103B_PMUGRF_OS_REG(9)); /* Use PMUGRF_OS_REG10 to save wakeup source */ writel_relaxed(0, pmugrf_base + RV1103B_PMUGRF_OS_REG(10)); #else writel_relaxed(__pa_symbol(cpu_resume), pmugrf_base + RV1103B_PMUGRF_OS_REG(9)); #endif suspend_workaround_timeout_wkup(); } static void pmu_sleep_restore(void) { ddr_data.pmu_wkup_int_st = readl_relaxed(pmu_base + RV1103B_PMU1_WAKEUP_INT_ST); ddr_data.gpio0_int_st = readl_relaxed(gpio_base[0] + RV1103B_GPIO_INT_STATUS); resume_workaround_timeout_wkup(); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU0_PWR_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU0_INFO_TX_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_INT_MASK_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU2_SCU_PWR_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU2_CLUSTER_IDLE_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU2_CPU_AUTO_PWR_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU2_SCU_AUTO_PWR_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_CRU_PWR_CON(0)); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_CRU_PWR_CON(1)); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU2_BUS_IDLE_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_DDR_PWR_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_PLLPD_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_WAKEUP_INT_CON); writel_relaxed(0xffff0000, pmu_base + RV1103B_PMU1_PWR_CON); /* pmu reset hold */ writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con4), pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con5), pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con6), pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); } static void soc_sleep_config(void) { rkpm_printch('a'); if (slp_cfg.mode_config & RKPM_SLP_PMU_PMUALIVE_32K) sleep_32k_config(); rkpm_printch('b'); ddr_sleep_config(); rkpm_printch('c'); pmu_sleep_config(); rkpm_printch('d'); } static void soc_sleep_restore(void) { rkpm_printch('d'); pmu_sleep_restore(); rkpm_printch('c'); ddr_sleep_config_restore(); rkpm_printch('b'); if (slp_cfg.mode_config & RKPM_SLP_PMU_PMUALIVE_32K) sleep_32k_config_restore(); rkpm_printch('a'); } static void plls_suspend(void) { } static void plls_resume(void) { } static void gpio0_set_iomux(u32 pin_id, u32 func) { u32 sft = pin_id % 4 << 2; u32 offset = pin_id / 4 << 2; if (pin_id < 8) writel_relaxed(BITS_WITH_WMASK(func, 0xf, sft), ioc0_base + offset); else if (pin_id < 16) writel_relaxed(BITS_WITH_WMASK(func, 0xf, sft), ioc1_base + offset); } static void gpio0_set_pull(u32 pin_id, int pull) { u32 sft = pin_id % 8 << 1; if (pin_id < 8) writel_relaxed(BITS_WITH_WMASK(pull, 0x3, sft), ioc0_base + 0x200); else if (pin_id < 16) writel_relaxed(BITS_WITH_WMASK(pull, 0x3, sft), ioc1_base + 0x204); } static void gpio0_set_direct(u32 pin_id, int out) { u32 sft = pin_id % 16; if (pin_id < 16) writel_relaxed(BITS_WITH_WMASK(out, 0x1, sft), gpio_base[0] + RV1103B_GPIO_SWPORT_DDR_L); else writel_relaxed(BITS_WITH_WMASK(out, 0x1, sft), gpio_base[0] + RV1103B_GPIO_SWPORT_DDR_H); } static void gpio0_set_lvl(u32 pin_id, int lvl) { u32 sft = pin_id % 16; if (pin_id < 16) writel_relaxed(BITS_WITH_WMASK(lvl, 0x1, sft), gpio_base[0] + RV1103B_GPIO_SWPORT_DR_L); else writel_relaxed(BITS_WITH_WMASK(lvl, 0x1, sft), gpio_base[0] + RV1103B_GPIO_SWPORT_DR_H); } static void gpio_config(void) { u32 iomux, dir, lvl, pull, id; u32 cfg, i; ddr_data.gpio0a_iomux_l = readl_relaxed(ioc0_base + 0); ddr_data.gpio0a_iomux_h = readl_relaxed(ioc0_base + 0x4); ddr_data.gpio0b_iomux_l = readl_relaxed(ioc1_base + 0x8); ddr_data.gpio0b_iomux_h = readl_relaxed(ioc1_base + 0xc); ddr_data.gpio0a_pull = readl_relaxed(ioc0_base + 0x200); ddr_data.gpio0b_pull = readl_relaxed(ioc1_base + 0x204); ddr_data.gpio0_ddr_l = readl_relaxed(gpio_base[0] + RV1103B_GPIO_SWPORT_DDR_L); ddr_data.gpio0_ddr_h = readl_relaxed(gpio_base[0] + RV1103B_GPIO_SWPORT_DDR_H); ddr_data.gpio0_dr_l = readl_relaxed(gpio_base[0] + RV1103B_GPIO_SWPORT_DR_L); ddr_data.gpio0_dr_h = readl_relaxed(gpio_base[0] + RV1103B_GPIO_SWPORT_DR_H); for (i = 0; i < slp_cfg.sleep_io_config_cnt; i++) { cfg = slp_cfg.sleep_io_config[i]; iomux = RKPM_IO_CFG_GET_IOMUX(cfg); dir = RKPM_IO_CFG_GET_GPIO_DIR(cfg); lvl = RKPM_IO_CFG_GET_GPIO_LVL(cfg); pull = RKPM_IO_CFG_GET_PULL(cfg); id = RKPM_IO_CFG_GET_ID(cfg); if (iomux == RKPM_IO_CFG_IOMUX_GPIO_VAL) { if (dir == RKPM_IO_CFG_GPIO_DIR_OUTPUT_VAL) gpio0_set_lvl(id, lvl); gpio0_set_direct(id, dir); } gpio0_set_iomux(id, iomux); gpio0_set_pull(id, pull); } /* pmu_debug */ if (slp_cfg.mode_config & RKPM_SLP_PMU_DBG) { writel_relaxed(0x01ff01ff, pmu_base + RV1103B_PMU0_INFO_TX_CON); writel_relaxed(BITS_WITH_WMASK(0x5, 0xf, 4), ioc1_base + 0x8); /* gpio0_b1 */ } } static void gpio_restore(void) { writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0_ddr_l), gpio_base[0] + RV1103B_GPIO_SWPORT_DDR_L); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0_ddr_h), gpio_base[0] + RV1103B_GPIO_SWPORT_DDR_H); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0_dr_l), gpio_base[0] + RV1103B_GPIO_SWPORT_DR_L); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0_dr_h), gpio_base[0] + RV1103B_GPIO_SWPORT_DR_H); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l), ioc0_base + 0); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h), ioc0_base + 0x4); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l), ioc1_base + 0x8); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_h), ioc1_base + 0xc); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0a_pull), ioc0_base + 0x200); writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0b_pull), ioc1_base + 0x204); } static struct uart_debug_ctx debug_port_save; static u32 cru_mode; static void pvtpll_core_suspend(void) { rkpm_reg_rgn_save(pvtpll_core_reg_rgns, ARRAY_SIZE(pvtpll_core_reg_rgns)); } static void pvtpll_core_resume(void) { rkpm_reg_rgn_restore(pvtpll_core_reg_rgns, ARRAY_SIZE(pvtpll_core_reg_rgns)); rkpm_raw_udelay(1); } static void pvtpll_logic_suspend(void) { rkpm_reg_rgn_save(pvtpll_logic_reg_rgns, ARRAY_SIZE(pvtpll_logic_reg_rgns)); } static void pvtpll_logic_resume(void) { rkpm_reg_rgn_restore(pvtpll_logic_reg_rgns, ARRAY_SIZE(pvtpll_logic_reg_rgns)); rkpm_raw_udelay(1); } static void vd_core_regs_save(void) { rkpm_printch('a'); pvtpll_core_suspend(); rkpm_printch('b'); rkpm_reg_rgn_save(vd_core_reg_rgns, ARRAY_SIZE(vd_core_reg_rgns)); rkpm_printch('c'); gic400_save(); rkpm_printch('d'); } static void vd_core_regs_restore(void) { u32 mode = readl_relaxed(cru_base + 0x280); rkpm_printch('a'); gic400_restore(); rkpm_printch('b'); /* slow mode */ writel_relaxed(0x00030000, cru_base + 0x280); rkpm_printch('c'); pvtpll_core_resume(); rkpm_printch('d'); rkpm_reg_rgn_restore(vd_core_reg_rgns, ARRAY_SIZE(vd_core_reg_rgns)); rkpm_printch('e'); /* restore mode */ writel_relaxed(WITH_16BITS_WMSK(mode), cru_base + 0x280); rkpm_printch('f'); } static void vd_log_regs_save(void) { cru_mode = readl_relaxed(cru_base + 0x280); rkpm_printch('a'); pvtpll_logic_suspend(); rkpm_printch('b'); rkpm_reg_rgn_save(vd_log_reg_rgns, ARRAY_SIZE(vd_log_reg_rgns)); rkpm_printch('c'); rkpm_uart_debug_save(uartdbg_base, &debug_port_save); rkpm_printch('d'); } static void vd_log_regs_restore(void) { rkpm_printch('a'); rkpm_uart_debug_restore(uartdbg_base, &debug_port_save); rkpm_printch('b'); /* slow mode */ writel_relaxed(0x00030000, cru_base + 0x280); rkpm_printch('c'); pvtpll_logic_resume(); rkpm_printch('d'); rkpm_reg_rgn_restore(vd_log_reg_rgns, ARRAY_SIZE(vd_log_reg_rgns)); rkpm_printch('e'); /* wait lock */ pm_pll_wait_lock(RV1103B_GPLL_ID); /* restore mode */ writel_relaxed(WITH_16BITS_WMSK(cru_mode), cru_base + 0x280); rkpm_printch('f'); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); if (readl_relaxed(wdt_ns_base + RV1103B_WDT_CR) & 0x1) writel_relaxed(0x76, wdt_ns_base + RV1103B_WDT_CRR); if (readl_relaxed(wdt_s_base + RV1103B_WDT_CR) & 0x1) writel_relaxed(0x76, wdt_s_base + RV1103B_WDT_CRR); } static void pd_pmu1_regs_save(void) { rkpm_printch('a'); rkpm_reg_rgn_save(pd_pmu1_reg_rgns, ARRAY_SIZE(pd_pmu1_reg_rgns)); rkpm_printch('b'); } static void pd_pmu1_regs_restore(void) { rkpm_printch('a'); rkpm_reg_rgn_restore(pd_pmu1_reg_rgns, ARRAY_SIZE(pd_pmu1_reg_rgns)); rkpm_printch('b'); } static void hptimer_init(void) { if (rk_hptimer_get_mode(hptimer_base) == RK_HPTIMER_HARD_ADJUST_MODE) return; /* deepslow select osc_div_32k */ writel_relaxed(BITS_WITH_WMASK(0x0, 0x1, 2), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); writel_relaxed(BITS_WITH_WMASK(0x0, 0x3, 0), pmu0cru_base + RV1103B_PMU0CRU_CLKSEL_CON(0)); rk_hptimer_v2_mode_init(hptimer_base, RK_HPTIMER_HARD_ADJUST_MODE, 24000000); } static void hptimer_suspend(void) { int mode = rk_hptimer_get_mode(hptimer_base); if ((slp_cfg.mode_config & RKPM_SLP_PMU_PMUALIVE_32K) && mode == RK_HPTIMER_SOFT_ADJUST_MODE) writel_relaxed(BITS_WITH_WMASK(0x1, 0x1, 8), pmusgrf_base + RV1103B_PMUSGRF_SOC_CON(0)); } static void hptimer_resume(void) { int mode = rk_hptimer_get_mode(hptimer_base); writel_relaxed(BITS_WITH_WMASK(0x0, 0x1, 8), pmusgrf_base + RV1103B_PMUSGRF_SOC_CON(0)); if (slp_cfg.mode_config & RKPM_SLP_PMU_PMUALIVE_32K) { if (mode == RK_HPTIMER_HARD_ADJUST_MODE) rk_hptimer_v2_do_hard_adjust_no_wait(hptimer_base); else if (mode == RK_HPTIMER_SOFT_ADJUST_MODE) rk_hptimer_v2_do_soft_adjust_no_wait(hptimer_base, 24000000, 32768); } } static void rkpm_reg_rgns_init(void) { rkpm_alloc_region_mem(vd_core_reg_rgns, ARRAY_SIZE(vd_core_reg_rgns)); rkpm_alloc_region_mem(vd_log_reg_rgns, ARRAY_SIZE(vd_log_reg_rgns)); rkpm_alloc_region_mem(pd_pmu1_reg_rgns, ARRAY_SIZE(pd_pmu1_reg_rgns)); rkpm_alloc_region_mem(pvtpll_core_reg_rgns, ARRAY_SIZE(pvtpll_core_reg_rgns)); rkpm_alloc_region_mem(pvtpll_logic_reg_rgns, ARRAY_SIZE(pvtpll_logic_reg_rgns)); } static void rkpm_regs_rgn_dump(void) { return; rkpm_dump_reg_rgns(vd_core_reg_rgns, ARRAY_SIZE(vd_core_reg_rgns)); rkpm_dump_reg_rgns(vd_log_reg_rgns, ARRAY_SIZE(vd_log_reg_rgns)); rkpm_dump_reg_rgns(pd_pmu1_reg_rgns, ARRAY_SIZE(pd_pmu1_reg_rgns)); rkpm_dump_reg_rgns(pvtpll_core_reg_rgns, ARRAY_SIZE(pvtpll_core_reg_rgns)); rkpm_dump_reg_rgns(pvtpll_logic_reg_rgns, ARRAY_SIZE(pvtpll_logic_reg_rgns)); } static int rockchip_lpmode_enter(unsigned long arg) { flush_cache_all(); cpu_do_idle(); #if RV1103B_WAKEUP_TO_SYSTEM_RESET /* If reaches here, it means wakeup source cames before cpu enter wfi. * So we should do system reset if RV1103B_WAKEUP_TO_SYSTEM_RESET. */ writel_relaxed(0x000c000c, cru_base + RV1103B_CRU_GLB_RST_CON); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(4)); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(5)); writel_relaxed(0xffff0000, pmugrf_base + RV1103B_PMUGRF_SOC_CON(6)); dsb(sy); writel_relaxed(0xfdb9, cru_base + RV1103B_CRU_GLB_SRST_FST); rkpm_power_down_wfi(); #endif rkpm_printstr("Failed to suspend\n"); return 1; } static int rv1103b_suspend_enter(suspend_state_t state) { const struct rk_sleep_config *config = rockchip_get_cur_sleep_config(); u32 mode_cfg; if (config != NULL) memcpy(&slp_cfg, config, sizeof(slp_cfg)); mode_cfg = slp_cfg.mode_config; rv1103b_dbg_sleep_enter_info(); local_fiq_disable(); rv1103b_dbg_irq_prepare(); rkpm_printch('-'); clock_suspend(); rkpm_printch('0'); soc_sleep_config(); rkpm_printch('1'); plls_suspend(); rkpm_printch('2'); gpio_config(); rkpm_printch('3'); vd_core_regs_save(); rkpm_printch('4'); if (mode_cfg & (RKPM_SLP_ARMOFF_LOGOFF | RKPM_SLP_ARMOFF_PMUOFF)) vd_log_regs_save(); rkpm_printch('5'); if (mode_cfg & RKPM_SLP_ARMOFF_PMUOFF) pd_pmu1_regs_save(); rkpm_printch('6'); hptimer_suspend(); rkpm_regs_rgn_dump(); rkpm_printstr("-WFI-"); cpu_suspend(0, rockchip_lpmode_enter); hptimer_resume(); rkpm_printch('6'); if (mode_cfg & RKPM_SLP_ARMOFF_PMUOFF) pd_pmu1_regs_restore(); rkpm_printch('5'); if (mode_cfg & (RKPM_SLP_ARMOFF_LOGOFF | RKPM_SLP_ARMOFF_PMUOFF)) vd_log_regs_restore(); rkpm_printch('4'); vd_core_regs_restore(); rkpm_printch('3'); rkpm_regs_rgn_dump(); gpio_restore(); rkpm_printch('2'); plls_resume(); rkpm_printch('1'); soc_sleep_restore(); rkpm_printch('0'); if ((rk_hptimer_get_mode(hptimer_base) != RK_HPTIMER_NORM_MODE) && (slp_cfg.mode_config & RKPM_SLP_PMU_PMUALIVE_32K)) rk_hptimer_v2_wait_sync(hptimer_base); clock_resume(); rkpm_printch('-'); fiq_glue_resume(); rv1103b_dbg_irq_finish(); local_fiq_enable(); rkpm_printstr("exit sleep\n"); return 0; } static void rv1103b_set_sleep_mode_default(void) { slp_cfg.mode_config = RKPM_SLP_ARMOFF_LOGOFF | RKPM_SLP_32K_EXT | RKPM_SLP_PMU_PMUALIVE_32K | RKPM_SLP_PMU_DIS_OSC | /* RKPM_SLP_TIME_OUT_WKUP | */ RKPM_SLP_PMU_DBG | 0; slp_cfg.sleep_debug_en = 1; slp_cfg.wakeup_config = RKPM_GPIO0_WKUP_EN | /* RKPM_SYS_INT_WKUP_EN | */ /* RKPM_AOV_WKUP_EN | */ 0; } static int __init rv1103b_suspend_init(void) { void __iomem *dev_reg_base; dev_reg_base = ioremap(RV1103B_DEV_REG_BASE, RV1103B_DEV_REG_SIZE); if (dev_reg_base) pr_info("%s map dev_reg 0x%x -> 0x%x\n", __func__, RV1103B_DEV_REG_BASE, (u32)dev_reg_base); else pr_err("%s: can't map dev_reg(0x%x)\n", __func__, RV1103B_DEV_REG_BASE); pericru_base = dev_reg_base + RV1103B_PERICRU_OFFSET; venccru_base = dev_reg_base + RV1103B_VENCCRU_OFFSET; npucru_base = dev_reg_base + RV1103B_NPUCRU_OFFSET; vicru_base = dev_reg_base + RV1103B_VICRU_OFFSET; corecru_base = dev_reg_base + RV1103B_CORECRU_OFFSET; ddrcru_base = dev_reg_base + RV1103B_DDRCRU_OFFSET; cru_base = dev_reg_base + RV1103B_TOPCRU_OFFSET; pmu0cru_base = dev_reg_base + RV1103B_PMU0CRU_OFFSET; pmu1cru_base = dev_reg_base + RV1103B_PMU1CRU_OFFSET; vencgrf_base = dev_reg_base + RV1103B_VENCGRF_OFFSET; npugrf_base = dev_reg_base + RV1103B_NPUGRF_OFFSET; vigrf_base = dev_reg_base + RV1103B_VIGRF_OFFSET; coregrf_base = dev_reg_base + RV1103B_COREGRF_OFFSET; ddrc_base = dev_reg_base + RV1103B_DDRC_OFFSET; ddrgrf_base = dev_reg_base + RV1103B_DDRGRF_OFFSET; perigrf_base = dev_reg_base + RV1103B_PERIGRF_OFFSET; pmugrf_base = dev_reg_base + RV1103B_PMUGRF_OFFSET; ioc3_base = dev_reg_base + RV1103B_IOC3_OFFSET; ioc47_base = dev_reg_base + RV1103B_IOC47_OFFSET; ioc6_base = dev_reg_base + RV1103B_IOC6_OFFSET; ioc0_base = dev_reg_base + RV1103B_IOC0_OFFSET; ioc1_base = dev_reg_base + RV1103B_IOC1_OFFSET; gpio_base[0] = dev_reg_base + RV1103B_GPIO0_OFFSET; gpio_base[1] = dev_reg_base + RV1103B_GPIO1_OFFSET; gpio_base[2] = dev_reg_base + RV1103B_GPIO2_OFFSET; perisgrf_base = dev_reg_base + RV1103B_PERISGRF_OFFSET; pmusgrf_base = dev_reg_base + RV1103B_PMUSGRF_OFFSET; qos_cpu_base = dev_reg_base + 0x310000; qos_crypto_base = dev_reg_base + 0x320000; qos_dcf_base = dev_reg_base + 0x320100; qos_decom_base = dev_reg_base + 0x320200; qos_dma2ddr_base = dev_reg_base + 0x320300; qos_mac_base = dev_reg_base + 0x320400; qos_mcu_base = dev_reg_base + 0x320500; qos_rga2e_rd_base = dev_reg_base + 0x320600; qos_rga2e_wr_base = dev_reg_base + 0x320700; qos_rkdma_base = dev_reg_base + 0x320800; qos_sdmmc1_base = dev_reg_base + 0x320900; qos_usb_base = dev_reg_base + 0x320a00; qos_emmc_base = dev_reg_base + 0x330000; qos_fspi_base = dev_reg_base + 0x330100; qos_isp_base = dev_reg_base + 0x330200; qos_sdmmc0_base = dev_reg_base + 0x330300; qos_vicap_base = dev_reg_base + 0x330400; qos_npu_base = dev_reg_base + 0x340000; qos_rkvdec_base = dev_reg_base + 0x350000; qos_fspi_pmu_base = dev_reg_base + 0x360000; qos_lpmcu_base = dev_reg_base + 0x360100; qos_spi2ahb_base = dev_reg_base + 0x360200; gicd_base = dev_reg_base + RV1103B_GIC_OFFSET + 0x1000; gicc_base = dev_reg_base + RV1103B_GIC_OFFSET + 0x2000; pvtpll_core_base = dev_reg_base + RV1103B_PVTPLL_CORE_OFFSET; pvtpll_isp_base = dev_reg_base + RV1103B_PVTPLL_ISP_OFFSET; pvtpll_vepu_base = dev_reg_base + RV1103B_PVTPLL_VEPU_OFFSET; pvtpll_npu_base = dev_reg_base + RV1103B_PVTPLL_NPU_OFFSET; hptimer_base = dev_reg_base + RV1103B_HPTIMER_OFFSET; pmu_base = dev_reg_base + RV1103B_PMU_OFFSET; i2c0_base = dev_reg_base + RV1103B_I2C0_OFFSET; uartdbg_base = dev_reg_base + RV1103B_UART0_OFFSET; pwm0_base = dev_reg_base + RV1103B_PWM0_OFFSET; wdt_ns_base = dev_reg_base + RV1103B_WDTNS_OFFSET; wdt_s_base = dev_reg_base + RV1103B_WDTS_OFFSET; nstimer_base[0] = dev_reg_base + RV1103B_NSTIMER_OFFSET; nstimer_base[1] = dev_reg_base + RV1103B_NSTIMER_OFFSET + 0x1000; nstimer_base[2] = dev_reg_base + RV1103B_NSTIMER_OFFSET + 0x2000; nstimer_base[3] = dev_reg_base + RV1103B_NSTIMER_OFFSET + 0x3000; nstimer_base[4] = dev_reg_base + RV1103B_NSTIMER_OFFSET + 0x4000; nstimer_base[5] = dev_reg_base + RV1103B_NSTIMER_OFFSET + 0x5000; stimer_base[0] = dev_reg_base + RV1103B_STIMER_OFFSET; stimer_base[1] = dev_reg_base + RV1103B_STIMER_OFFSET + 0x1000; fw_ddr_base = dev_reg_base + RV1103B_FW_DDR_OFFSET; syssram_base = dev_reg_base + RV1103B_SYSSRAM_OFFSET; pmusram_base = dev_reg_base + RV1103B_PMUSRAM_OFFSET; lpmcu_mbox_base = dev_reg_base + RV1103B_LPMCU_MBOX_OFFSET; hptimer_init(); rv1103b_set_sleep_mode_default(); rv1103b_config_bootdata(); /* copy resume code and data to pmusram */ memcpy(pmusram_base, rockchip_slp_cpu_resume, rv1103b_bootram_sz + 0x50); /* biu auto con */ writel_relaxed(0x003f003f, pmu_base + RV1103B_PMU2_NOC_AUTO_CON); /* gpio0_a3 activelow, gpio0_a4 active high, select sleep func */ writel_relaxed(BITS_WITH_WMASK(0x10, 0x3f, 0), pmugrf_base + RV1103B_PMUGRF_SOC_CON(1)); /* PMU_WAKEUP_TIMEOUT_CNT = 0, disable TIMEOUT_WAKEUP by default */ writel_relaxed(0x0, pmu_base + RV1103B_PMU1_WAKEUP_TIMEOUT); rkpm_region_mem_init(RV1103B_PM_REG_REGION_MEM_SIZE); rkpm_reg_rgns_init(); return 0; } static const struct platform_suspend_ops rv1103b_suspend_ops = { .enter = rv1103b_suspend_enter, .valid = suspend_valid_only_mem, }; void __init rockchip_suspend_init(void) { rv1103b_suspend_init(); suspend_set_ops(&rv1103b_suspend_ops); }