1379 lines
42 KiB
C
1379 lines
42 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/suspend.h>
|
|
#include <linux/mfd/syscon.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/fiq_glue.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/suspend.h>
|
|
#include <dt-bindings/suspend/rockchip-rv1106.h>
|
|
#include <linux/irqchip/arm-gic.h>
|
|
#include <linux/rockchip/rockchip_pm_config.h>
|
|
|
|
#include "rkpm_gicv2.h"
|
|
#include "rkpm_helpers.h"
|
|
#include "rkpm_uart.h"
|
|
#include "rockchip_hptimer.h"
|
|
#include "rv1106_pm.h"
|
|
|
|
#define RV1106_PM_REG_REGION_MEM_SIZE SZ_4K
|
|
|
|
#define CRU_PVTPLL0_CON0_L 0x00
|
|
#define CRU_PVTPLL0_CON0_H 0x04
|
|
#define CRU_PVTPLL0_CON1_L 0x08
|
|
#define CRU_PVTPLL0_CON1_H 0x0c
|
|
#define CRU_PVTPLL0_CON2_L 0x10
|
|
#define CRU_PVTPLL0_CON2_H 0x14
|
|
#define CRU_PVTPLL0_CON3_L 0x18
|
|
#define CRU_PVTPLL0_CON3_H 0x1c
|
|
|
|
#define CRU_PVTPLL1_CON0_L 0x30
|
|
#define CRU_PVTPLL1_CON0_H 0x34
|
|
#define CRU_PVTPLL1_CON1_L 0x38
|
|
#define CRU_PVTPLL1_CON1_H 0x3c
|
|
#define CRU_PVTPLL1_CON2_L 0x40
|
|
#define CRU_PVTPLL1_CON2_H 0x44
|
|
#define CRU_PVTPLL1_CON3_L 0x48
|
|
#define CRU_PVTPLL1_CON3_H 0x4c
|
|
|
|
enum {
|
|
RV1106_GPIO_PULL_NONE,
|
|
RV1106_GPIO_PULL_UP,
|
|
RV1106_GPIO_PULL_DOWN,
|
|
RV1106_GPIO_PULL_UP_DOWN,
|
|
};
|
|
|
|
struct rockchip_pm_data {
|
|
const struct platform_suspend_ops *ops;
|
|
int (*init)(struct device_node *np);
|
|
};
|
|
|
|
struct rv1106_sleep_ddr_data {
|
|
u32 cru_gate_con[RV1106_CRU_GATE_CON_NUM];
|
|
u32 pmucru_gate_con[RV1106_PMUCRU_GATE_CON_NUM];
|
|
u32 pericru_gate_con[RV1106_PERICRU_GATE_CON_NUM];
|
|
u32 npucru_gate_con[RV1106_NPUCRU_GATE_CON_NUM];
|
|
u32 venccru_gate_con[RV1106_VENCCRU_GATE_CON_NUM];
|
|
u32 vicru_gate_con[RV1106_VICRU_GATE_CON_NUM];
|
|
u32 vocru_gate_con[RV1106_VOCRU_GATE_CON_NUM];
|
|
|
|
u32 ddrgrf_con1, ddrgrf_con2, ddrgrf_con3, ddrc_pwrctrl, ddrc_dfilpcfg0;
|
|
u32 pmucru_sel_con7;
|
|
u32 pmugrf_soc_con0, pmugrf_soc_con1, pmugrf_soc_con4, pmugrf_soc_con5;
|
|
u32 ioc0_1a_iomux_l, ioc1_1a_iomux_l;
|
|
u32 gpio0a_iomux_l, gpio0a_iomux_h, gpio0a0_pull;
|
|
u32 gpio0_ddr_l, gpio0_ddr_h;
|
|
u32 pmu_wkup_int_st, gpio0_int_st;
|
|
u32 sleep_clk_freq_hz;
|
|
};
|
|
|
|
static struct rv1106_sleep_ddr_data ddr_data;
|
|
|
|
static const struct rk_sleep_config *slp_cfg;
|
|
|
|
static void __iomem *pmucru_base;
|
|
static void __iomem *cru_base;
|
|
static void __iomem *pvtpllcru_base;
|
|
static void __iomem *pericru_base;
|
|
static void __iomem *vicru_base;
|
|
static void __iomem *npucru_base;
|
|
static void __iomem *corecru_base;
|
|
static void __iomem *venccru_base;
|
|
static void __iomem *vocru_base;
|
|
|
|
static void __iomem *perigrf_base;
|
|
static void __iomem *vencgrf_base;
|
|
static void __iomem *npugrf_base;
|
|
static void __iomem *pmugrf_base;
|
|
static void __iomem *ddrgrf_base;
|
|
static void __iomem *coregrf_base;
|
|
static void __iomem *vigrf_base;
|
|
static void __iomem *vogrf_base;
|
|
static void __iomem *perisgrf_base;
|
|
static void __iomem *visgrf_base;
|
|
static void __iomem *npusgrf_base;
|
|
static void __iomem *coresgrf_base;
|
|
static void __iomem *vencsgrf_base;
|
|
static void __iomem *vosgrf_base;
|
|
static void __iomem *pmusgrf_base;
|
|
|
|
static void __iomem *pmupvtm_base;
|
|
static void __iomem *uartdbg_base;
|
|
static void __iomem *pmu_base;
|
|
static void __iomem *gicd_base;
|
|
static void __iomem *gicc_base;
|
|
static void __iomem *hptimer_base;
|
|
static void __iomem *firewall_ddr_base;
|
|
static void __iomem *firewall_syssram_base;
|
|
static void __iomem *pmu_base;
|
|
static void __iomem *nstimer_base;
|
|
static void __iomem *stimer_base;
|
|
static void __iomem *wdt_ns_base;
|
|
static void __iomem *wdt_s_base;
|
|
static void __iomem *mbox_base;
|
|
static void __iomem *ddrc_base;
|
|
static void __iomem *ioc_base[5];
|
|
static void __iomem *gpio_base[5];
|
|
static void __iomem *rv1106_bootram_base;
|
|
|
|
#define WMSK_VAL 0xffff0000
|
|
|
|
static struct reg_region vd_core_reg_rgns[] = {
|
|
/* core_cru */
|
|
{ REG_REGION(0x300, 0x310, 4, &corecru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x804, 4, &corecru_base, WMSK_VAL)},
|
|
|
|
/* core_sgrf */
|
|
{ REG_REGION(0x004, 0x014, 4, &coresgrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &coresgrf_base, 0)},
|
|
{ REG_REGION(0x020, 0x030, 4, &coresgrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x040, 0x040, 4, &coresgrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x044, 0x044, 4, &coresgrf_base, 0)},
|
|
|
|
/* core grf */
|
|
{ REG_REGION(0x004, 0x004, 4, &coregrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x008, 0x010, 4, &coregrf_base, 0)},
|
|
{ REG_REGION(0x024, 0x028, 4, &coregrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &coregrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x02c, 0x02c, 4, &coregrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x038, 0x03c, 4, &coregrf_base, WMSK_VAL)},
|
|
};
|
|
|
|
static struct reg_region vd_log_reg_rgns[] = {
|
|
/* firewall_ddr */
|
|
{ REG_REGION(0x000, 0x03c, 4, &firewall_ddr_base, 0)},
|
|
{ REG_REGION(0x040, 0x06c, 4, &firewall_ddr_base, 0)},
|
|
{ REG_REGION(0x0f0, 0x0f0, 4, &firewall_ddr_base, 0)},
|
|
|
|
/* firewall_sram */
|
|
{ REG_REGION(0x000, 0x01c, 4, &firewall_syssram_base, 0)},
|
|
{ REG_REGION(0x040, 0x054, 4, &firewall_syssram_base, 0)},
|
|
{ REG_REGION(0x0f0, 0x0f0, 4, &firewall_syssram_base, 0)},
|
|
|
|
/* cru */
|
|
{ REG_REGION(0x000, 0x004, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x008, 0x008, 4, &cru_base, 0)},
|
|
{ REG_REGION(0x00c, 0x010, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x020, 0x024, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x028, 0x028, 4, &cru_base, 0)},
|
|
{ REG_REGION(0x02c, 0x030, 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, 0x310, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x314, 0x34c, 8, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x318, 0x350, 8, &cru_base, 0)},
|
|
{ REG_REGION(0x354, 0x360, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x364, 0x37c, 8, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x368, 0x380, 8, &cru_base, 0)},
|
|
{ REG_REGION(0x384, 0x384, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x80c, 4, &cru_base, WMSK_VAL)},
|
|
{ REG_REGION(0xc00, 0xc00, 4, &cru_base, 0)},
|
|
{ REG_REGION(0xc10, 0xc10, 4, &cru_base, 0)},
|
|
{ REG_REGION(0xc14, 0xc28, 4, &cru_base, WMSK_VAL)},
|
|
|
|
/* npu_cru */
|
|
{ REG_REGION(0x300, 0x300, 4, &npucru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x804, 4, &npucru_base, WMSK_VAL)},
|
|
|
|
/* npu_sgrf */
|
|
{ REG_REGION(0x004, 0x014, 4, &npusgrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &npusgrf_base, 0)},
|
|
|
|
/* peri_cru */
|
|
{ REG_REGION(0x304, 0x32c, 4, &pericru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x81c, 4, &pericru_base, WMSK_VAL)},
|
|
|
|
/* peri_grf */
|
|
{ REG_REGION(0x000, 0x004, 4, &perigrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x090, 0x094, 4, &perigrf_base, WMSK_VAL)},
|
|
|
|
/* peri_sgrf */
|
|
{ REG_REGION(0x004, 0x014, 4, &perisgrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &perisgrf_base, 0)},
|
|
{ REG_REGION(0x020, 0x030, 4, &perisgrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x080, 0x0a4, 4, &perisgrf_base, WMSK_VAL)},
|
|
{ REG_REGION(0x0b8, 0x0bc, 4, &perisgrf_base, WMSK_VAL)},
|
|
|
|
/* vi_cru */
|
|
{ REG_REGION(0x300, 0x30c, 4, &vicru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x808, 4, &vicru_base, WMSK_VAL)},
|
|
|
|
/* vi_sgrf */
|
|
{ REG_REGION(0x004, 0x014, 4, &visgrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &visgrf_base, 0)},
|
|
|
|
/* vo_cru */
|
|
{ REG_REGION(0x300, 0x30c, 4, &vocru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x80c, 4, &vocru_base, WMSK_VAL)},
|
|
|
|
/* vo_sgrf */
|
|
{ REG_REGION(0x004, 0x014, 4, &vosgrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &vosgrf_base, 0)},
|
|
{ REG_REGION(0x018, 0x018, 4, &vosgrf_base, WMSK_VAL)},
|
|
|
|
/* vepu_cru */
|
|
{ REG_REGION(0x300, 0x304, 4, &venccru_base, WMSK_VAL)},
|
|
{ REG_REGION(0x800, 0x808, 4, &venccru_base, WMSK_VAL)},
|
|
|
|
/* vepu_sgrf */
|
|
{ REG_REGION(0x004, 0x014, 4, &vencsgrf_base, 0)},
|
|
{ REG_REGION(0x000, 0x000, 4, &vencsgrf_base, 0)},
|
|
|
|
/* gpio1_ioc */
|
|
{ REG_REGION(0x000, 0x018, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x080, 0x0b4, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x180, 0x18c, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x1c0, 0x1cc, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x200, 0x20c, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x240, 0x24c, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x280, 0x28c, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x2c0, 0x2cc, 4, &ioc_base[1], WMSK_VAL)},
|
|
{ REG_REGION(0x2f4, 0x2f4, 4, &ioc_base[1], WMSK_VAL)},
|
|
|
|
/* gpio2_ioc */
|
|
{ REG_REGION(0x020, 0x028, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x0c0, 0x0d0, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x190, 0x194, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x1d0, 0x1d4, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x210, 0x214, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x250, 0x254, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x290, 0x294, 4, &ioc_base[2], WMSK_VAL)},
|
|
{ REG_REGION(0x2d0, 0x2d4, 4, &ioc_base[2], WMSK_VAL)},
|
|
|
|
/* gpio3_ioc */
|
|
{ REG_REGION(0x040, 0x058, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x100, 0x10c, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x128, 0x134, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x1a0, 0x1ac, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x1e0, 0x1ec, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x220, 0x22c, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x260, 0x26c, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x2a0, 0x2ac, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x2e0, 0x2ec, 4, &ioc_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x2f4, 0x2f4, 4, &ioc_base[3], WMSK_VAL)},
|
|
|
|
/* gpio1~3 */
|
|
{ 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(0x010, 0x014, 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)},
|
|
{ REG_REGION(0x010, 0x014, 4, &gpio_base[2], WMSK_VAL)},
|
|
|
|
{ REG_REGION(0x000, 0x00c, 4, &gpio_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x018, 0x044, 4, &gpio_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x048, 0x048, 4, &gpio_base[3], 0)},
|
|
{ REG_REGION(0x060, 0x064, 4, &gpio_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x100, 0x108, 4, &gpio_base[3], WMSK_VAL)},
|
|
{ REG_REGION(0x010, 0x014, 4, &gpio_base[3], WMSK_VAL)},
|
|
|
|
/* NS TIMER 6 channel */
|
|
{ REG_REGION(0x00, 0x04, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x10, 0x10, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x20, 0x24, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x30, 0x30, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x40, 0x44, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x50, 0x50, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x60, 0x64, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x70, 0x70, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x80, 0x84, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0x90, 0x90, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0xa0, 0xa4, 4, &nstimer_base, 0)},
|
|
{ REG_REGION(0xb0, 0xb0, 4, &nstimer_base, 0)},
|
|
|
|
/* S TIMER0 2 channel */
|
|
{ REG_REGION(0x00, 0x04, 4, &stimer_base, 0)},
|
|
{ REG_REGION(0x10, 0x10, 4, &stimer_base, 0)},
|
|
{ REG_REGION(0x20, 0x24, 4, &stimer_base, 0)},
|
|
{ REG_REGION(0x30, 0x30, 4, &stimer_base, 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)},
|
|
};
|
|
|
|
static int is_rv1103, is_rv1106;
|
|
|
|
#define PLL_LOCKED_TIMEOUT 600000U
|
|
|
|
static void pm_pll_wait_lock(u32 pll_id)
|
|
{
|
|
int delay = PLL_LOCKED_TIMEOUT;
|
|
|
|
if (readl_relaxed(cru_base + RV1106_CRU_PLL_CON(pll_id, 1)) & CRU_PLLCON1_PWRDOWN)
|
|
return;
|
|
|
|
while (delay-- >= 0) {
|
|
if (readl_relaxed(cru_base + RV1106_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');
|
|
}
|
|
}
|
|
|
|
struct plat_gicv2_dist_ctx_t gicd_ctx_save;
|
|
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)
|
|
{
|
|
if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP))
|
|
writel_relaxed(0x3, gicd_base + GIC_DIST_CTRL);
|
|
else
|
|
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 RV1106_DUMP_GPIO_INTEN(id) \
|
|
do { \
|
|
rkpm_printstr("GPIO"); \
|
|
rkpm_printdec(id); \
|
|
rkpm_printstr(": "); \
|
|
rkpm_printhex(readl_relaxed(gpio_base[id] + RV1106_GPIO_INT_EN_L)); \
|
|
rkpm_printch(' '); \
|
|
rkpm_printhex(readl_relaxed(gpio_base[id] + RV1106_GPIO_INT_EN_H)); \
|
|
rkpm_printch(' '); \
|
|
rkpm_printhex(readl_relaxed(gpio_base[id] + RV1106_GPIO_INT_MASK_L)); \
|
|
rkpm_printch(' '); \
|
|
rkpm_printhex(readl_relaxed(gpio_base[id] + RV1106_GPIO_INT_MASK_H)); \
|
|
rkpm_printch(' '); \
|
|
rkpm_printhex(readl_relaxed(gpio_base[id] + RV1106_GPIO_INT_STATUS)); \
|
|
rkpm_printch(' '); \
|
|
rkpm_printhex(readl_relaxed(gpio_base[id] + RV1106_GPIO_INT_RAWSTATUS));\
|
|
rkpm_printch('\n'); \
|
|
} while (0)
|
|
|
|
static void rv1106_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(RV1106_PMU_WAKEUP_GPIO_INT_EN)) {
|
|
rkpm_printstr("GPIO0 interrupt wakeup:");
|
|
rkpm_printhex(ddr_data.gpio0_int_st);
|
|
rkpm_printch('\n');
|
|
}
|
|
|
|
if (pmu_int_st & BIT(RV1106_PMU_WAKEUP_SDMMC_EN))
|
|
rkpm_printstr("PWM detect wakeup\n");
|
|
|
|
if (pmu_int_st & BIT(RV1106_PMU_WAKEUP_SDIO_EN))
|
|
rkpm_printstr("GMAC interrupt wakeup\n");
|
|
|
|
if (pmu_int_st & BIT(RV1106_PMU_WAKEUP_TIMER_EN))
|
|
rkpm_printstr("TIMER interrupt wakeup\n");
|
|
|
|
if (pmu_int_st & BIT(RV1106_PMU_WAKEUP_USBDEV_EN))
|
|
rkpm_printstr("USBDEV detect wakeup\n");
|
|
|
|
if (pmu_int_st & BIT(RV1106_PMU_WAKEUP_TIMEOUT_EN))
|
|
rkpm_printstr("TIMEOUT interrupt wakeup\n");
|
|
|
|
rkpm_printch('\n');
|
|
}
|
|
|
|
static void rv1106_dbg_irq_prepare(void)
|
|
{
|
|
RV1106_DUMP_GPIO_INTEN(0);
|
|
}
|
|
|
|
static void rv1106_dbg_irq_finish(void)
|
|
{
|
|
rv1106_dbg_pmu_wkup_src();
|
|
}
|
|
|
|
static inline u32 rv1106_l2_config(void)
|
|
{
|
|
u32 l2ctlr;
|
|
|
|
asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (l2ctlr));
|
|
return l2ctlr;
|
|
}
|
|
|
|
static void __init rv1106_config_bootdata(void)
|
|
{
|
|
rkpm_bootdata_cpusp = RV1106_PMUSRAM_BASE + (SZ_8K - 8);
|
|
rkpm_bootdata_cpu_code = __pa_symbol(cpu_resume);
|
|
|
|
rkpm_bootdata_l2ctlr_f = 1;
|
|
rkpm_bootdata_l2ctlr = rv1106_l2_config();
|
|
}
|
|
|
|
static void writel_clrset_bits(u32 clr, u32 set, void __iomem *addr)
|
|
{
|
|
u32 val = readl_relaxed(addr);
|
|
|
|
val &= ~clr;
|
|
val |= set;
|
|
writel_relaxed(val, addr);
|
|
}
|
|
|
|
static void gic_irq_en(int irq)
|
|
{
|
|
writel_clrset_bits(0xff << irq % 4 * 8, 0x1 << irq % 4 * 8,
|
|
gicd_base + GIC_DIST_TARGET + (irq >> 2 << 2));
|
|
writel_clrset_bits(0xff << irq % 4 * 8, 0xa0 << irq % 4 * 8,
|
|
gicd_base + GIC_DIST_PRI + (irq >> 2 << 2));
|
|
writel_clrset_bits(0x3 << irq % 16 * 2, 0x1 << irq % 16 * 2,
|
|
gicd_base + GIC_DIST_CONFIG + (irq >> 4 << 2));
|
|
writel_clrset_bits(BIT(irq % 32), BIT(irq % 32),
|
|
gicd_base + GIC_DIST_IGROUP + (irq >> 5 << 2));
|
|
|
|
dsb(sy);
|
|
writel_relaxed(0x1 << irq % 32, gicd_base + GIC_DIST_ENABLE_SET + (irq >> 5 << 2));
|
|
dsb(sy);
|
|
}
|
|
|
|
static int is_hpmcu_mbox_int(void)
|
|
{
|
|
return !!(readl(mbox_base + RV1106_MBOX_B2A_STATUS) & BIT(0));
|
|
}
|
|
|
|
static void hpmcu_start(void)
|
|
{
|
|
/* enable hpmcu mailbox AP irq */
|
|
gic_irq_en(RV1106_HPMCU_MBOX_IRQ_AP);
|
|
|
|
/* tell hpmcu that we are currently in system wake up. */
|
|
writel(RV1106_SYS_IS_WKUP, pmu_base + RV1106_PMU_SYS_REG(0));
|
|
|
|
/* set the mcu uncache area, usually set the devices address */
|
|
writel(0xff000, coregrf_base + RV1106_COREGRF_CACHE_PERI_ADDR_START);
|
|
writel(0xffc00, coregrf_base + RV1106_COREGRF_CACHE_PERI_ADDR_END);
|
|
/* Reset the hp mcu */
|
|
writel(0x1e001e, corecru_base + RV1106_COERCRU_SFTRST_CON(1));
|
|
/* set the mcu addr */
|
|
writel(RV1106_HPMCU_BOOT_ADDR,
|
|
coresgrf_base + RV1106_CORESGRF_HPMCU_BOOTADDR);
|
|
dsb(sy);
|
|
|
|
/* release the mcu */
|
|
writel(0x1e0000, corecru_base + RV1106_COERCRU_SFTRST_CON(1));
|
|
dsb(sy);
|
|
}
|
|
|
|
static int hpmcu_fast_wkup(void)
|
|
{
|
|
u32 cmd;
|
|
|
|
hpmcu_start();
|
|
|
|
while (1) {
|
|
rkpm_printstr("-s-\n");
|
|
dsb(sy);
|
|
wfi();
|
|
rkpm_printstr("-w-\n");
|
|
|
|
if (is_hpmcu_mbox_int()) {
|
|
rkpm_printstr("-h-mbox-\n");
|
|
/* clear system wake up state */
|
|
writel(0, pmu_base + RV1106_PMU_SYS_REG(0));
|
|
writel(BIT(0), mbox_base + RV1106_MBOX_B2A_STATUS);
|
|
break;
|
|
}
|
|
}
|
|
|
|
cmd = readl(mbox_base + RV1106_MBOX_B2A_CMD_0);
|
|
if (cmd == RV1106_MBOX_CMD_AP_SUSPEND)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void clock_suspend(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < RV1106_CRU_GATE_CON_NUM; i++) {
|
|
ddr_data.cru_gate_con[i] =
|
|
readl_relaxed(cru_base + RV1106_CRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, cru_base + RV1106_CRU_GATE_CON(i));
|
|
}
|
|
|
|
for (i = 0; i < RV1106_PMUCRU_GATE_CON_NUM; i++) {
|
|
ddr_data.pmucru_gate_con[i] =
|
|
readl_relaxed(pmucru_base + RV1106_PMUCRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, pmucru_base + RV1106_PMUCRU_GATE_CON(i));
|
|
}
|
|
|
|
for (i = 0; i < RV1106_PERICRU_GATE_CON_NUM; i++) {
|
|
ddr_data.pericru_gate_con[i] =
|
|
readl_relaxed(pericru_base + RV1106_PERICRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, pericru_base + RV1106_PERICRU_GATE_CON(i));
|
|
}
|
|
|
|
for (i = 0; i < RV1106_NPUCRU_GATE_CON_NUM; i++) {
|
|
ddr_data.npucru_gate_con[i] =
|
|
readl_relaxed(npucru_base + RV1106_NPUCRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, npucru_base + RV1106_NPUCRU_GATE_CON(i));
|
|
}
|
|
|
|
for (i = 0; i < RV1106_VENCCRU_GATE_CON_NUM; i++) {
|
|
ddr_data.venccru_gate_con[i] =
|
|
readl_relaxed(venccru_base + RV1106_VENCCRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, venccru_base + RV1106_VENCCRU_GATE_CON(i));
|
|
}
|
|
|
|
for (i = 0; i < RV1106_VICRU_GATE_CON_NUM; i++) {
|
|
ddr_data.vicru_gate_con[i] =
|
|
readl_relaxed(vicru_base + RV1106_VICRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, vicru_base + RV1106_VICRU_GATE_CON(i));
|
|
}
|
|
|
|
for (i = 0; i < RV1106_VOCRU_GATE_CON_NUM; i++) {
|
|
ddr_data.vocru_gate_con[i] =
|
|
readl_relaxed(vocru_base + RV1106_VOCRU_GATE_CON(i));
|
|
writel_relaxed(0xffff0000, vocru_base + RV1106_VOCRU_GATE_CON(i));
|
|
}
|
|
}
|
|
|
|
static void clock_resume(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < RV1106_CRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.cru_gate_con[i]),
|
|
cru_base + RV1106_CRU_GATE_CON(i));
|
|
|
|
for (i = 0; i < RV1106_PMUCRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmucru_gate_con[i]),
|
|
pmucru_base + RV1106_PMUCRU_GATE_CON(i));
|
|
|
|
for (i = 0; i < RV1106_PERICRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.pericru_gate_con[i]),
|
|
pericru_base + RV1106_PERICRU_GATE_CON(i));
|
|
|
|
for (i = 0; i < RV1106_NPUCRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.npucru_gate_con[i]),
|
|
npucru_base + RV1106_NPUCRU_GATE_CON(i));
|
|
|
|
for (i = 0; i < RV1106_VENCCRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.venccru_gate_con[i]),
|
|
venccru_base + RV1106_VENCCRU_GATE_CON(i));
|
|
|
|
for (i = 0; i < RV1106_VICRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.vicru_gate_con[i]),
|
|
vicru_base + RV1106_VICRU_GATE_CON(i));
|
|
|
|
for (i = 0; i < RV1106_VOCRU_GATE_CON_NUM; i++)
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.vocru_gate_con[i]),
|
|
vocru_base + RV1106_VOCRU_GATE_CON(i));
|
|
}
|
|
|
|
static void pvtm_32k_config(void)
|
|
{
|
|
u64 value, pvtm_freq_hz;
|
|
int pvtm_div;
|
|
u32 pvtm_div_freq_hz;
|
|
|
|
ddr_data.pmucru_sel_con7 =
|
|
readl_relaxed(pmucru_base + RV1106_PMUCRU_CLKSEL_CON(7));
|
|
|
|
if (slp_cfg->mode_config & RKPM_SLP_32K_EXT) {
|
|
writel_relaxed(BITS_WITH_WMASK(0x3, 0x3, 14),
|
|
pmugrf_base + RV1106_PMUGRF_SOC_CON(1));
|
|
writel_relaxed(BITS_WITH_WMASK(0x1, 0x3, 0),
|
|
pmucru_base + RV1106_PMUCRU_CLKSEL_CON(7));
|
|
ddr_data.sleep_clk_freq_hz = 32768;
|
|
} else {
|
|
writel_relaxed(BITS_WITH_WMASK(0, 0x3, 0),
|
|
pmupvtm_base + RV1106_PVTM_CON(2));
|
|
writel_relaxed(RV1106_PVTM_CALC_CNT,
|
|
pmupvtm_base + RV1106_PVTM_CON(1));
|
|
writel_relaxed(BITS_WITH_WMASK(0, 0x1, PVTM_START),
|
|
pmupvtm_base + RV1106_PVTM_CON(0));
|
|
dsb();
|
|
|
|
writel_relaxed(BITS_WITH_WMASK(0, 0x7, PVTM_OSC_SEL),
|
|
pmupvtm_base + RV1106_PVTM_CON(0));
|
|
writel_relaxed(BITS_WITH_WMASK(1, 0x1, PVTM_OSC_EN),
|
|
pmupvtm_base + RV1106_PVTM_CON(0));
|
|
writel_relaxed(BITS_WITH_WMASK(1, 0x1, PVTM_RND_SEED_EN),
|
|
pmupvtm_base + RV1106_PVTM_CON(0));
|
|
dsb();
|
|
|
|
writel_relaxed(BITS_WITH_WMASK(1, 0x1, PVTM_START),
|
|
pmupvtm_base + RV1106_PVTM_CON(0));
|
|
dsb();
|
|
|
|
while (readl_relaxed(pmupvtm_base + RV1106_PVTM_STATUS(1)) < 30)
|
|
;
|
|
|
|
dsb();
|
|
|
|
while (!readl_relaxed(pmupvtm_base + RV1106_PVTM_STATUS(0)) & 0x1)
|
|
;
|
|
|
|
value = (readl_relaxed(pmupvtm_base + RV1106_PVTM_STATUS(1)));
|
|
pvtm_freq_hz = (value * 24000000 + RV1106_PVTM_CALC_CNT / 2);
|
|
pvtm_freq_hz = div_u64(pvtm_freq_hz, RV1106_PVTM_CALC_CNT);
|
|
|
|
pvtm_div = ((u32)pvtm_freq_hz + RV1106_PVTM_TARGET_FREQ / 2) /
|
|
RV1106_PVTM_TARGET_FREQ - 1;
|
|
if (pvtm_div > 0xfff)
|
|
pvtm_div = 0xfff;
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(pvtm_div),
|
|
pmugrf_base + RV1106_PMUGRF_SOC_CON(3));
|
|
|
|
/* select 32k source */
|
|
writel_relaxed(BITS_WITH_WMASK(0x2, 0x3, 0),
|
|
pmucru_base + RV1106_PMUCRU_CLKSEL_CON(7));
|
|
|
|
pvtm_div_freq_hz = (u32)pvtm_freq_hz / (pvtm_div + 1);
|
|
ddr_data.sleep_clk_freq_hz = pvtm_div_freq_hz;
|
|
|
|
rkpm_printstr("pvtm freq (hz):");
|
|
rkpm_printdec(pvtm_freq_hz);
|
|
rkpm_printch('-');
|
|
rkpm_printdec(pvtm_div_freq_hz);
|
|
rkpm_printch('\n');
|
|
}
|
|
|
|
rkpm_printstr("sleep freq (hz):");
|
|
rkpm_printdec(ddr_data.sleep_clk_freq_hz);
|
|
rkpm_printch('\n');
|
|
}
|
|
|
|
static void pvtm_32k_config_restore(void)
|
|
{
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmucru_sel_con7),
|
|
pmucru_base + RV1106_PMUCRU_CLKSEL_CON(7));
|
|
|
|
if (rk_hptimer_get_mode(hptimer_base) == RK_HPTIMER_SOFT_ADJUST_MODE)
|
|
rk_hptimer_do_soft_adjust_no_wait(hptimer_base,
|
|
24000000,
|
|
ddr_data.sleep_clk_freq_hz);
|
|
}
|
|
|
|
static void ddr_sleep_config(void)
|
|
{
|
|
u32 val;
|
|
|
|
ddr_data.ddrc_pwrctrl = readl_relaxed(ddrc_base + 0x30);
|
|
ddr_data.ddrgrf_con1 = readl_relaxed(ddrgrf_base + RV1106_DDRGRF_CON(1));
|
|
ddr_data.ddrgrf_con2 = readl_relaxed(ddrgrf_base + RV1106_DDRGRF_CON(2));
|
|
ddr_data.ddrgrf_con3 = readl_relaxed(ddrgrf_base + RV1106_DDRGRF_CON(3));
|
|
ddr_data.ddrc_dfilpcfg0 = readl_relaxed(ddrc_base + 0x198);
|
|
ddr_data.pmugrf_soc_con0 = readl_relaxed(pmugrf_base + RV1106_PMUGRF_SOC_CON(0));
|
|
|
|
val = readl_relaxed(ddrc_base + 0x30);
|
|
writel_relaxed(val & ~(BIT(0) | BIT(1)), ddrc_base + 0x30);
|
|
|
|
/* disable ddr auto gt */
|
|
writel_relaxed(BITS_WITH_WMASK(0x12, 0x1f, 0), ddrgrf_base + RV1106_DDRGRF_CON(1));
|
|
|
|
writel_relaxed(BITS_WITH_WMASK(0x3ff, 0x3ff, 0), ddrgrf_base + RV1106_DDRGRF_CON(2));
|
|
|
|
/* ddr low power request by pmu */
|
|
writel_relaxed(BITS_WITH_WMASK(0x3, 0x3, 8), ddrgrf_base + RV1106_DDRGRF_CON(3));
|
|
|
|
while ((readl_relaxed(ddrc_base + 0x4) & 0x7) != 0x1)
|
|
continue;
|
|
|
|
val = readl_relaxed(ddrc_base + 0x198) & ~(0xf << 12 | 0xf << 4);
|
|
val |= (0xa << 12 | 0xa << 4);
|
|
writel_relaxed(val, ddrc_base + 0x198);
|
|
|
|
val = readl_relaxed(ddrc_base + 0x198) | BIT(8) | BIT(0);
|
|
writel_relaxed(val, ddrc_base + 0x198);
|
|
|
|
/* ddr io ret by pmu */
|
|
writel_relaxed(BITS_WITH_WMASK(0x0, 0x7, 9), pmugrf_base + RV1106_PMUGRF_SOC_CON(0));
|
|
}
|
|
|
|
static void ddr_sleep_config_restore(void)
|
|
{
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.ddrgrf_con3),
|
|
ddrgrf_base + RV1106_DDRGRF_CON(3));
|
|
}
|
|
|
|
static void pmu_sleep_config(void)
|
|
{
|
|
u32 clk_freq_khz = 32;
|
|
u32 pmu_wkup_con, pmu_pwr_con, pmu_scu_con, pmu_ddr_con;
|
|
u32 pmu_bus_idle_con, pmu_cru_con[2], pmu_pll_con;
|
|
|
|
ddr_data.pmugrf_soc_con1 = readl_relaxed(pmugrf_base + RV1106_PMUGRF_SOC_CON(1));
|
|
ddr_data.pmugrf_soc_con4 = readl_relaxed(pmugrf_base + RV1106_PMUGRF_SOC_CON(4));
|
|
ddr_data.pmugrf_soc_con5 = readl_relaxed(pmugrf_base + RV1106_PMUGRF_SOC_CON(5));
|
|
ddr_data.ioc1_1a_iomux_l = readl_relaxed(ioc_base[1] + 0);
|
|
|
|
pmu_wkup_con =
|
|
/* BIT(RV1106_PMU_WAKEUP_CPU_INT_EN) | */
|
|
BIT(RV1106_PMU_WAKEUP_GPIO_INT_EN) |
|
|
0;
|
|
if (IS_ENABLED(CONFIG_RV1106_PMU_WAKEUP_TIMEOUT))
|
|
pmu_wkup_con |= BIT(RV1106_PMU_WAKEUP_TIMEOUT_EN);
|
|
|
|
pmu_pwr_con =
|
|
BIT(RV1106_PMU_PWRMODE_EN) |
|
|
/* BIT(RV1106_PMU_BUS_BYPASS) | */
|
|
/* BIT(RV1106_PMU_DDR_BYPASS) | */
|
|
/* BIT(RV1106_PMU_CRU_BYPASS) | */
|
|
0;
|
|
|
|
pmu_scu_con =
|
|
BIT(RV1106_PMU_SCU_INT_MASK_ENA) |
|
|
BIT(RV1106_PMU_CPU_INT_MASK_ENA) |
|
|
0;
|
|
|
|
pmu_bus_idle_con =
|
|
BIT(RV1106_PMU_IDLE_REQ_MSCH) |
|
|
BIT(RV1106_PMU_IDLE_REQ_DDR) |
|
|
BIT(RV1106_PMU_IDLE_REQ_NPU) |
|
|
BIT(RV1106_PMU_IDLE_REQ_NPU_ACLK) |
|
|
BIT(RV1106_PMU_IDLE_REQ_VI) |
|
|
BIT(RV1106_PMU_IDLE_REQ_VO) |
|
|
BIT(RV1106_PMU_IDLE_REQ_PERI) |
|
|
BIT(RV1106_PMU_IDLE_REQ_CRU) |
|
|
BIT(RV1106_PMU_IDLE_REQ_CPU) |
|
|
BIT(RV1106_PMU_IDLE_REQ_VENC_COM) |
|
|
BIT(RV1106_PMU_IDLE_REQ_VEPU) |
|
|
0;
|
|
|
|
pmu_cru_con[0] =
|
|
BIT(RV1106_PMU_ALIVE_32K_ENA) |
|
|
BIT(RV1106_PMU_OSC_DIS_ENA) |
|
|
BIT(RV1106_PMU_WAKEUP_RST_ENA) |
|
|
BIT(RV1106_PMU_INPUT_CLAMP_ENA) |
|
|
/* BIT(RV1106_PMU_ALIVE_OSC_ENA) | */
|
|
BIT(RV1106_PMU_POWER_OFF_ENA) |
|
|
0;
|
|
|
|
pmu_cru_con[1] =
|
|
/* BIT(RV1106_PMU_VI_CLK_SRC_GATE_ENA) | */
|
|
/* BIT(RV1106_PMU_VO_CLK_SRC_GATE_ENA) | */
|
|
/* BIT(RV1106_PMU_VENC_CLK_SRC_GATE_ENA) | */
|
|
/* BIT(RV1106_PMU_NPU_CLK_SRC_GATE_ENA) | */
|
|
/* BIT(RV1106_PMU_DDR_CLK_SRC_CATE_ENA) | */
|
|
/* BIT(RV1106_PMU_PERI_CLK_SRC_GATE_ENA) | */
|
|
/* BIT(RV1106_PMU_CORE_CLK_SRC_GATE_ENA) | */
|
|
/* BIT(RV1106_PMU_CRU_CLK_SRC_GATE_ENA) | */
|
|
0;
|
|
|
|
pmu_ddr_con =
|
|
BIT(RV1106_PMU_DDR_SREF_C_ENA) |
|
|
#if !RV1106_WAKEUP_TO_SYSTEM_RESET
|
|
BIT(RV1106_PMU_DDRIO_RET_ENA) |
|
|
#endif
|
|
BIT(RV1106_PMU_DDRCTL_C_AUTO_GATING_ENA) |
|
|
BIT(RV1106_PMU_MSCH_AUTO_GATING_ENA) |
|
|
BIT(RV1106_PMU_DDR_SREF_A_ENA) |
|
|
BIT(RV1106_PMU_DDRCTL_A_AUTO_GATING_ENA) |
|
|
0;
|
|
|
|
pmu_pll_con =
|
|
BIT(RV1106_PMU_APLL_PD_ENA) |
|
|
BIT(RV1106_PMU_DPLL_PD_ENA) |
|
|
BIT(RV1106_PMU_CPLL_PD_ENA) |
|
|
BIT(RV1106_PMU_GPLL_PD_ENA) |
|
|
0;
|
|
|
|
/* pmu_debug */
|
|
writel_relaxed(0xffffff01, pmu_base + RV1106_PMU_INFO_TX_CON);
|
|
writel_relaxed(BITS_WITH_WMASK(0x1, 0xf, 4), ioc_base[1] + 0);
|
|
|
|
/* pmu count */
|
|
writel_relaxed(clk_freq_khz * 10, pmu_base + RV1106_PMU_OSC_STABLE_CNT);
|
|
writel_relaxed(clk_freq_khz * 5, pmu_base + RV1106_PMU_PMIC_STABLE_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(12000, pmu_base + RV1106_PMU_WAKEUP_RSTCLR_CNT);
|
|
writel_relaxed(12000, pmu_base + RV1106_PMU_PLL_LOCK_CNT);
|
|
writel_relaxed(24000 * 2, pmu_base + RV1106_PMU_PWM_SWITCH_CNT);
|
|
|
|
/* pmu reset hold */
|
|
writel_relaxed(0xffffffff, pmugrf_base + RV1106_PMUGRF_SOC_CON(4));
|
|
writel_relaxed(0xffffff47, pmugrf_base + RV1106_PMUGRF_SOC_CON(5));
|
|
|
|
writel_relaxed(0x00010001, pmu_base + RV1106_PMU_INT_MASK_CON);
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_scu_con), pmu_base + RV1106_PMU_SCU_PWR_CON);
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_cru_con[0]), pmu_base + RV1106_PMU_CRU_PWR_CON0);
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_cru_con[1]), pmu_base + RV1106_PMU_CRU_PWR_CON1);
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_bus_idle_con), pmu_base + RV1106_PMU_BIU_IDLE_CON);
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_ddr_con), pmu_base + RV1106_PMU_DDR_PWR_CON);
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_pll_con), pmu_base + RV1106_PMU_PLLPD_CON);
|
|
writel_relaxed(pmu_wkup_con, pmu_base + RV1106_PMU_WAKEUP_INT_CON);
|
|
writel_relaxed(WITH_16BITS_WMSK(pmu_pwr_con), pmu_base + RV1106_PMU_PWR_CON);
|
|
|
|
#if RV1106_WAKEUP_TO_SYSTEM_RESET
|
|
writel_relaxed(0, pmugrf_base + RV1106_PMUGRF_OS_REG(9));
|
|
/* Use PMUGRF_OS_REG10 to save wakeup source */
|
|
writel_relaxed(0, pmugrf_base + RV1106_PMUGRF_OS_REG(10));
|
|
#else
|
|
writel_relaxed(PMU_SUSPEND_MAGIC, pmugrf_base + RV1106_PMUGRF_OS_REG(9));
|
|
#endif
|
|
}
|
|
|
|
static void pmu_sleep_restore(void)
|
|
{
|
|
ddr_data.pmu_wkup_int_st = readl_relaxed(pmu_base + RV1106_PMU_WAKEUP_INT_ST);
|
|
ddr_data.gpio0_int_st = readl_relaxed(gpio_base[0] + RV1106_GPIO_INT_STATUS);
|
|
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_INFO_TX_CON);
|
|
writel_relaxed(0x00010000, pmu_base + RV1106_PMU_INT_MASK_CON);
|
|
writel_relaxed(0x00000000, pmu_base + RV1106_PMU_WAKEUP_INT_CON);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_PWR_CON);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_BIU_IDLE_CON);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_DDR_PWR_CON);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_SCU_PWR_CON);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_PLLPD_CON);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_CRU_PWR_CON0);
|
|
writel_relaxed(0xffff0000, pmu_base + RV1106_PMU_CRU_PWR_CON1);
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.ioc1_1a_iomux_l),
|
|
ioc_base[1] + 0);
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con1),
|
|
pmugrf_base + RV1106_PMUGRF_SOC_CON(1));
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con4),
|
|
pmugrf_base + RV1106_PMUGRF_SOC_CON(4));
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.pmugrf_soc_con5),
|
|
pmugrf_base + RV1106_PMUGRF_SOC_CON(5));
|
|
}
|
|
|
|
static void soc_sleep_config(void)
|
|
{
|
|
ddr_data.ioc0_1a_iomux_l = readl_relaxed(ioc_base[0] + 0);
|
|
|
|
rkpm_printch('a');
|
|
|
|
pvtm_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');
|
|
|
|
pvtm_32k_config_restore();
|
|
rkpm_printch('a');
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.ioc0_1a_iomux_l),
|
|
ioc_base[0] + 0);
|
|
}
|
|
|
|
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;
|
|
|
|
if (pin_id < 4)
|
|
writel_relaxed(BITS_WITH_WMASK(func, 0xf, sft), ioc_base[0] + 0);
|
|
else
|
|
writel_relaxed(BITS_WITH_WMASK(func, 0xf, sft), ioc_base[0] + 4);
|
|
}
|
|
|
|
static void gpio0_set_pull(u32 pin_id, int pull)
|
|
{
|
|
u32 sft = (pin_id % 8) << 1;
|
|
|
|
writel_relaxed(BITS_WITH_WMASK(pull, 0x3, sft), ioc_base[0] + 0x38);
|
|
}
|
|
|
|
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] + RV1106_GPIO_SWPORT_DDR_L);
|
|
else
|
|
writel_relaxed(BITS_WITH_WMASK(out, 0x1, sft),
|
|
gpio_base[0] + RV1106_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] + RV1106_GPIO_SWPORT_DR_L);
|
|
else
|
|
writel_relaxed(BITS_WITH_WMASK(lvl, 0x1, sft),
|
|
gpio_base[0] + RV1106_GPIO_SWPORT_DR_H);
|
|
}
|
|
|
|
static void gpio_config(void)
|
|
{
|
|
u32 iomux, dir, lvl, pull, id;
|
|
u32 cfg, i;
|
|
|
|
if (slp_cfg == NULL)
|
|
return;
|
|
|
|
ddr_data.gpio0a_iomux_l = readl_relaxed(ioc_base[0] + 0);
|
|
ddr_data.gpio0a_iomux_h = readl_relaxed(ioc_base[0] + 0x4);
|
|
ddr_data.gpio0a0_pull = readl_relaxed(ioc_base[0] + 0x38);
|
|
ddr_data.gpio0_ddr_l = readl_relaxed(gpio_base[0] + RV1106_GPIO_SWPORT_DDR_L);
|
|
ddr_data.gpio0_ddr_h = readl_relaxed(gpio_base[0] + RV1106_GPIO_SWPORT_DDR_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 (is_rv1106 && id == 3) {
|
|
/* gpio0_a3, pullnone */
|
|
gpio0_set_iomux(3, 1);
|
|
gpio0_set_pull(3, RV1106_GPIO_PULL_NONE);
|
|
continue;
|
|
}
|
|
|
|
if (is_rv1103 && id == 4) {
|
|
/* gpio0_a4, pullnone */
|
|
gpio0_set_iomux(4, 1);
|
|
gpio0_set_pull(4, RV1106_GPIO_PULL_NONE);
|
|
continue;
|
|
}
|
|
|
|
if (iomux == RKPM_IO_CFG_IOMUX_GPIO_VAL) {
|
|
if (dir == RKPM_IO_CFG_GPIO_DIR_INPUT_VAL)
|
|
gpio0_set_lvl(id, lvl);
|
|
|
|
gpio0_set_direct(id, dir);
|
|
}
|
|
|
|
gpio0_set_iomux(id, iomux);
|
|
gpio0_set_pull(id, pull);
|
|
}
|
|
}
|
|
|
|
static void gpio_restore(void)
|
|
{
|
|
if (slp_cfg == NULL)
|
|
return;
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l), ioc_base[0] + 0);
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h), ioc_base[0] + 0x4);
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0a0_pull), ioc_base[0] + 0x38);
|
|
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0_ddr_l),
|
|
gpio_base[0] + RV1106_GPIO_SWPORT_DDR_L);
|
|
writel_relaxed(WITH_16BITS_WMSK(ddr_data.gpio0_ddr_h),
|
|
gpio_base[0] + RV1106_GPIO_SWPORT_DDR_H);
|
|
}
|
|
|
|
static struct uart_debug_ctx debug_port_save;
|
|
static u32 cru_mode;
|
|
static u32 pvtpll0_length, pvtpll1_length;
|
|
|
|
static void pvtpllcru_save(void)
|
|
{
|
|
pvtpll0_length = readl_relaxed(pvtpllcru_base + CRU_PVTPLL0_CON0_H);
|
|
pvtpll1_length = readl_relaxed(pvtpllcru_base + CRU_PVTPLL1_CON0_H);
|
|
}
|
|
|
|
static void pvtpllcru_restore(void)
|
|
{
|
|
writel_relaxed(0x00030000, pvtpllcru_base + CRU_PVTPLL0_CON0_L);
|
|
writel_relaxed(0x007f0000 | pvtpll0_length, pvtpllcru_base + CRU_PVTPLL0_CON0_H);
|
|
writel_relaxed(0xffff0018, pvtpllcru_base + CRU_PVTPLL0_CON1_L);
|
|
writel_relaxed(0xffff0004, pvtpllcru_base + CRU_PVTPLL0_CON2_H);
|
|
writel_relaxed(0x00030003, pvtpllcru_base + CRU_PVTPLL0_CON0_L);
|
|
|
|
writel_relaxed(0x00030000, pvtpllcru_base + CRU_PVTPLL1_CON0_L);
|
|
writel_relaxed(0x007f0000 | pvtpll1_length, pvtpllcru_base + CRU_PVTPLL1_CON0_H);
|
|
writel_relaxed(0xffff0018, pvtpllcru_base + CRU_PVTPLL1_CON1_L);
|
|
writel_relaxed(0xffff0004, pvtpllcru_base + CRU_PVTPLL1_CON2_H);
|
|
writel_relaxed(0x00030003, pvtpllcru_base + CRU_PVTPLL1_CON0_L);
|
|
}
|
|
|
|
static void vd_log_regs_save(void)
|
|
{
|
|
cru_mode = readl_relaxed(cru_base + 0x280);
|
|
|
|
rkpm_printch('a');
|
|
|
|
gic400_save();
|
|
rkpm_printch('b');
|
|
|
|
pvtpllcru_save();
|
|
rkpm_reg_rgn_save(vd_core_reg_rgns, ARRAY_SIZE(vd_core_reg_rgns));
|
|
rkpm_printch('c');
|
|
rkpm_reg_rgn_save(vd_log_reg_rgns, ARRAY_SIZE(vd_log_reg_rgns));
|
|
rkpm_printch('d');
|
|
|
|
rkpm_uart_debug_save(uartdbg_base, &debug_port_save);
|
|
rkpm_printch('e');
|
|
}
|
|
|
|
static void vd_log_regs_restore(void)
|
|
{
|
|
rkpm_uart_debug_restore(uartdbg_base, &debug_port_save);
|
|
|
|
/* slow mode */
|
|
writel_relaxed(0x003f0000, cru_base + 0x280);
|
|
|
|
rkpm_reg_rgn_restore(vd_core_reg_rgns, ARRAY_SIZE(vd_core_reg_rgns));
|
|
rkpm_reg_rgn_restore(vd_log_reg_rgns, ARRAY_SIZE(vd_log_reg_rgns));
|
|
pvtpllcru_restore();
|
|
|
|
/* wait lock */
|
|
pm_pll_wait_lock(RV1106_APLL_ID);
|
|
pm_pll_wait_lock(RV1106_CPLL_ID);
|
|
pm_pll_wait_lock(RV1106_GPLL_ID);
|
|
|
|
/* restore mode */
|
|
writel_relaxed(WITH_16BITS_WMSK(cru_mode), cru_base + 0x280);
|
|
|
|
gic400_restore();
|
|
|
|
writel_relaxed(0xffff0000, pmugrf_base + RV1106_PMUGRF_SOC_CON(4));
|
|
writel_relaxed(0xffff0000, pmugrf_base + RV1106_PMUGRF_SOC_CON(5));
|
|
|
|
if (readl_relaxed(wdt_ns_base + RV1106_WDT_CR) & 0x1)
|
|
writel_relaxed(0x76, wdt_ns_base + RV1106_WDT_CRR);
|
|
|
|
if (readl_relaxed(wdt_s_base + RV1106_WDT_CR) & 0x1)
|
|
writel_relaxed(0x76, wdt_s_base + RV1106_WDT_CRR);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
static int rockchip_lpmode_enter(unsigned long arg)
|
|
{
|
|
flush_cache_all();
|
|
|
|
cpu_do_idle();
|
|
|
|
#if RV1106_WAKEUP_TO_SYSTEM_RESET
|
|
/* If reaches here, it means wakeup source cames before cpu enter wfi.
|
|
* So we should do system reset if RV1106_WAKEUP_TO_SYSTEM_RESET.
|
|
*/
|
|
writel_relaxed(0x000c000c, cru_base + RV1106_CRU_GLB_RST_CON);
|
|
writel_relaxed(0xffff0000, pmugrf_base + RV1106_PMUGRF_SOC_CON(4));
|
|
writel_relaxed(0xffff0000, pmugrf_base + RV1106_PMUGRF_SOC_CON(5));
|
|
dsb(sy);
|
|
writel_relaxed(0xfdb9, cru_base + RV1106_CRU_GLB_SRST_FST);
|
|
#endif
|
|
|
|
rkpm_printstr("Failed to suspend\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int rv1106_suspend_enter(suspend_state_t state)
|
|
{
|
|
rkpm_printstr("rv1106 enter sleep\n");
|
|
|
|
slp_cfg = rockchip_get_cur_sleep_config();
|
|
|
|
local_fiq_disable();
|
|
|
|
rv1106_dbg_irq_prepare();
|
|
|
|
rkpm_printch('-');
|
|
|
|
RE_ENTER_SLEEP:
|
|
clock_suspend();
|
|
rkpm_printch('0');
|
|
|
|
soc_sleep_config();
|
|
rkpm_printch('1');
|
|
|
|
plls_suspend();
|
|
rkpm_printch('2');
|
|
|
|
gpio_config();
|
|
rkpm_printch('3');
|
|
|
|
vd_log_regs_save();
|
|
rkpm_regs_rgn_dump();
|
|
rkpm_printch('4');
|
|
|
|
rkpm_printstr("-WFI-");
|
|
cpu_suspend(0, rockchip_lpmode_enter);
|
|
|
|
rkpm_printch('4');
|
|
|
|
vd_log_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');
|
|
|
|
clock_resume();
|
|
rkpm_printch('-');
|
|
|
|
/* Check whether it's time_out wakeup */
|
|
if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP)) {
|
|
if (hpmcu_fast_wkup()) {
|
|
rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save);
|
|
goto RE_ENTER_SLEEP;
|
|
} else {
|
|
rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save);
|
|
rkpm_gicv2_cpu_restore(gicd_base, gicc_base, &gicc_ctx_save);
|
|
}
|
|
}
|
|
|
|
if (rk_hptimer_get_mode(hptimer_base) == RK_HPTIMER_SOFT_ADJUST_MODE) {
|
|
if (rk_hptimer_wait_mode(hptimer_base,
|
|
RK_HPTIMER_SOFT_ADJUST_MODE))
|
|
rkpm_printstr("WARN: can't wait hptimer soft adjust mode!\n");
|
|
}
|
|
|
|
fiq_glue_resume();
|
|
|
|
rv1106_dbg_irq_finish();
|
|
|
|
local_fiq_enable();
|
|
rkpm_printstr("rv1106 exit sleep\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __init rv1106_suspend_init(struct device_node *np)
|
|
{
|
|
void __iomem *dev_reg_base;
|
|
|
|
if (of_machine_is_compatible("rockchip,rv1103"))
|
|
is_rv1103 = 1;
|
|
else if (of_machine_is_compatible("rockchip,rv1106"))
|
|
is_rv1106 = 1;
|
|
|
|
dev_reg_base = ioremap(RV1106_DEV_REG_BASE, RV1106_DEV_REG_SIZE);
|
|
if (dev_reg_base)
|
|
pr_info("%s map dev_reg 0x%x -> 0x%x\n",
|
|
__func__, RV1106_DEV_REG_BASE, (u32)dev_reg_base);
|
|
else
|
|
pr_err("%s: can't map dev_reg(0x%x)\n", __func__, RV1106_DEV_REG_BASE);
|
|
|
|
gicd_base = dev_reg_base + RV1106_GIC_OFFSET + 0x1000;
|
|
gicc_base = dev_reg_base + RV1106_GIC_OFFSET + 0x2000;
|
|
|
|
hptimer_base = dev_reg_base + RV1106_HPTIMER_OFFSET;
|
|
|
|
firewall_ddr_base = dev_reg_base + RV1106_FW_DDR_OFFSET;
|
|
firewall_syssram_base = dev_reg_base + RV1106_FW_SRAM_OFFSET;
|
|
|
|
nstimer_base = dev_reg_base + RV1106_NSTIMER_OFFSET;
|
|
stimer_base = dev_reg_base + RV1106_STIMER_OFFSET;
|
|
|
|
wdt_ns_base = dev_reg_base + RV1106_WDTNS_OFFSET;
|
|
wdt_s_base = dev_reg_base + RV1106_WDTS_OFFSET;
|
|
|
|
pmu_base = dev_reg_base + RV1106_PMU_OFFSET;
|
|
uartdbg_base = dev_reg_base + RV1106_UART2_OFFSET;
|
|
pmupvtm_base = dev_reg_base + RV1106_PMUPVTM_OFFSET;
|
|
pmusgrf_base = dev_reg_base + RV1106_PMUSGRF_OFFSET;
|
|
ddrc_base = dev_reg_base + RV1106_DDRC_OFFSET;
|
|
|
|
perigrf_base = dev_reg_base + RV1106_PERIGRF_OFFSET;
|
|
vencgrf_base = dev_reg_base + RV1106_VENCGRF_OFFSET;
|
|
npugrf_base = dev_reg_base + RV1106_NPUGRF_OFFSET;
|
|
pmugrf_base = dev_reg_base + RV1106_PMUGRF_OFFSET;
|
|
ddrgrf_base = dev_reg_base + RV1106_DDRGRF_OFFSET;
|
|
coregrf_base = dev_reg_base + RV1106_COREGRF_OFFSET;
|
|
vigrf_base = dev_reg_base + RV1106_VIGRF_OFFSET;
|
|
vogrf_base = dev_reg_base + RV1106_VOGRF_OFFSET;
|
|
|
|
perisgrf_base = dev_reg_base + RV1106_PERISGRF_OFFSET;
|
|
visgrf_base = dev_reg_base + RV1106_VIGRF_OFFSET;
|
|
npusgrf_base = dev_reg_base + RV1106_NPUSGRF_OFFSET;
|
|
coresgrf_base = dev_reg_base + RV1106_CORESGRF_OFFSET;
|
|
vencsgrf_base = dev_reg_base + RV1106_VENCSGRF_OFFSET;
|
|
vosgrf_base = dev_reg_base + RV1106_VOSGRF_OFFSET;
|
|
pmusgrf_base = dev_reg_base + RV1106_PMUSGRF_OFFSET;
|
|
|
|
pmucru_base = dev_reg_base + RV1106_PMUCRU_OFFSET;
|
|
cru_base = dev_reg_base + RV1106_CRU_OFFSET;
|
|
pvtpllcru_base = dev_reg_base + RV1106_PVTPLLCRU_OFFSET;
|
|
pericru_base = dev_reg_base + RV1106_PERICRU_OFFSET;
|
|
vicru_base = dev_reg_base + RV1106_VICRU_OFFSET;
|
|
npucru_base = dev_reg_base + RV1106_NPUCRU_OFFSET;
|
|
corecru_base = dev_reg_base + RV1106_CORECRU_OFFSET;
|
|
venccru_base = dev_reg_base + RV1106_VENCCRU_OFFSET;
|
|
vocru_base = dev_reg_base + RV1106_VOCRU_OFFSET;
|
|
mbox_base = dev_reg_base + RV1106_MBOX_OFFSET;
|
|
|
|
ioc_base[0] = dev_reg_base + RV1106_GPIO0IOC_OFFSET;
|
|
ioc_base[1] = dev_reg_base + RV1106_GPIO1IOC_OFFSET;
|
|
ioc_base[2] = dev_reg_base + RV1106_GPIO2IOC_OFFSET;
|
|
ioc_base[3] = dev_reg_base + RV1106_GPIO3IOC_OFFSET;
|
|
ioc_base[4] = dev_reg_base + RV1106_GPIO4IOC_OFFSET;
|
|
|
|
gpio_base[0] = dev_reg_base + RV1106_GPIO0_OFFSET;
|
|
gpio_base[1] = dev_reg_base + RV1106_GPIO1_OFFSET;
|
|
gpio_base[2] = dev_reg_base + RV1106_GPIO2_OFFSET;
|
|
gpio_base[3] = dev_reg_base + RV1106_GPIO3_OFFSET;
|
|
gpio_base[4] = dev_reg_base + RV1106_GPIO4_OFFSET;
|
|
|
|
rv1106_bootram_base = dev_reg_base + RV1106_PMUSRAM_OFFSET;
|
|
|
|
rv1106_config_bootdata();
|
|
|
|
/* copy resume code and data to bootsram */
|
|
memcpy(rv1106_bootram_base, rockchip_slp_cpu_resume,
|
|
rv1106_bootram_sz + 0x50);
|
|
|
|
/* remap */
|
|
#if RV1106_WAKEUP_TO_SYSTEM_RESET
|
|
writel_relaxed(BITS_WITH_WMASK(1, 0x1, 10), pmusgrf_base + RV1106_PMUSGRF_SOC_CON(1));
|
|
#else
|
|
writel_relaxed(BITS_WITH_WMASK(0, 0x1, 10), pmusgrf_base + RV1106_PMUSGRF_SOC_CON(1));
|
|
#endif
|
|
/* biu auto con */
|
|
writel_relaxed(0x07ff07ff, pmu_base + RV1106_PMU_BIU_AUTO_CON);
|
|
|
|
/* gpio0_a3 activelow, gpio0_a4 active high, select sleep func */
|
|
writel_relaxed(BITS_WITH_WMASK(0x5, 0x7, 0),
|
|
pmugrf_base + RV1106_PMUGRF_SOC_CON(1));
|
|
|
|
rkpm_region_mem_init(RV1106_PM_REG_REGION_MEM_SIZE);
|
|
rkpm_reg_rgns_init();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct platform_suspend_ops rv1106_suspend_ops = {
|
|
.enter = rv1106_suspend_enter,
|
|
.valid = suspend_valid_only_mem,
|
|
};
|
|
|
|
static const struct rockchip_pm_data rv1106_pm_data __initconst = {
|
|
.ops = &rv1106_suspend_ops,
|
|
.init = rv1106_suspend_init,
|
|
};
|
|
|
|
/****************************************************************************/
|
|
static const struct of_device_id rockchip_pmu_of_device_ids[] __initconst = {
|
|
{
|
|
.compatible = "rockchip,rv1106-pmu",
|
|
.data = &rv1106_pm_data,
|
|
},
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
void __init rockchip_suspend_init(void)
|
|
{
|
|
const struct rockchip_pm_data *pm_data;
|
|
const struct of_device_id *match;
|
|
struct device_node *np;
|
|
int ret;
|
|
|
|
np = of_find_matching_node_and_match(NULL, rockchip_pmu_of_device_ids,
|
|
&match);
|
|
if (!match) {
|
|
pr_err("Failed to find PMU node\n");
|
|
return;
|
|
}
|
|
pm_data = (struct rockchip_pm_data *)match->data;
|
|
|
|
if (pm_data->init) {
|
|
ret = pm_data->init(np);
|
|
|
|
if (ret) {
|
|
pr_err("%s: matches init error %d\n", __func__, ret);
|
|
return;
|
|
}
|
|
}
|
|
|
|
suspend_set_ops(pm_data->ops);
|
|
}
|