From 2ae2bc1582c92df3da1ac9d962ffdcf8f96d7c1b Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Wed, 26 Jul 2023 19:11:46 +0800 Subject: [PATCH] ARM: rockchip: rv1106: sleep: support hpmcu fast wakeup Signed-off-by: XiaoDong Huang Change-Id: I4a34e33fd267a54c4df0a5b158e28837e3a28051 --- arch/arm/mach-rockchip/rv1106_pm.c | 104 ++++++++++++++++++++++++++++- arch/arm/mach-rockchip/rv1106_pm.h | 19 ++++++ 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-rockchip/rv1106_pm.c b/arch/arm/mach-rockchip/rv1106_pm.c index a4d1c0fbb3d4..8725c4efd27a 100644 --- a/arch/arm/mach-rockchip/rv1106_pm.c +++ b/arch/arm/mach-rockchip/rv1106_pm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "rkpm_gicv2.h" #include "rkpm_helpers.h" @@ -91,6 +92,7 @@ static void __iomem *firewall_syssram_base; static void __iomem *pmu_base; static void __iomem *nstimer_base; static void __iomem *stimer_base; +static void __iomem *mbox_base; static void __iomem *ddrc_base; static void __iomem *ioc_base[5]; static void __iomem *gpio_base[5]; @@ -309,7 +311,10 @@ static void gic400_save(void) static void gic400_restore(void) { - rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save); + 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); } @@ -410,6 +415,87 @@ static void __init rv1106_config_bootdata(void) 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; @@ -616,10 +702,11 @@ static void pmu_sleep_config(void) ddr_data.ioc1_1a_iomux_l = readl_relaxed(ioc_base[1] + 0); pmu_wkup_con = - /* BIT(RV1106_PMU_WAKEUP_TIMEROUT_EN) | */ /* BIT(RV1106_PMU_WAKEUP_CPU_INT_EN) | */ BIT(RV1106_PMU_WAKEUP_GPIO_INT_EN) | 0; + if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP)) + pmu_wkup_con |= BIT(RV1106_PMU_WAKEUP_TIMEROUT_EN); pmu_pwr_con = BIT(RV1106_PMU_PWRMODE_EN) | @@ -964,6 +1051,7 @@ static int rv1106_suspend_enter(suspend_state_t state) rkpm_printch('-'); +RE_ENTER_SLEEP: clock_suspend(); rkpm_printch('0'); @@ -1001,6 +1089,17 @@ static int rv1106_suspend_enter(suspend_state_t state) clock_resume(); rkpm_printch('-'); + /* Check whether it's time_out wakeup */ + if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP) && ddr_data.pmu_wkup_int_st == 0) { + 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); + } + } + fiq_glue_resume(); rv1106_dbg_irq_finish(); @@ -1062,6 +1161,7 @@ static int __init rv1106_suspend_init(struct device_node *np) 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; diff --git a/arch/arm/mach-rockchip/rv1106_pm.h b/arch/arm/mach-rockchip/rv1106_pm.h index 0afd51e95cd9..61c3f9816d02 100644 --- a/arch/arm/mach-rockchip/rv1106_pm.h +++ b/arch/arm/mach-rockchip/rv1106_pm.h @@ -7,6 +7,7 @@ #define __MACH_ROCKCHIP_RV1106_PM_H #define RV1106_WAKEUP_TO_SYSTEM_RESET 0 +#define RV1106_HPMCU_FAST_WKUP_TIMEOUT 2000 /* ms */ #define RV1106_PERIGRF_OFFSET 0x0 #define RV1106_VENCGRF_OFFSET 0x10000 @@ -54,6 +55,7 @@ #define RV1106_NSTIMER_OFFSET 0x580000 #define RV1106_STIMER_OFFSET 0x590000 +#define RV1106_MBOX_OFFSET 0x5c0000 #define RV1106_PMUSRAM_OFFSET 0x670000 #define RV1106_DDRC_OFFSET 0x800000 #define RV1106_FW_DDR_OFFSET 0x900000 @@ -101,6 +103,7 @@ #define RV1106_CORECRU_GATE_CON(i) (0x800 + (i) * 4) #define RV1106_COERCRU_CLKSEL_CON(i) (0x300 + (i) * 4) #define RV1106_CORECRU_GATE_CON_NUM 2 +#define RV1106_COERCRU_SFTRST_CON(i) (0xa00 + (i) * 4) /* grf */ #define RV1106_PMUGRF_SOC_CON(i) ((i) * 4) @@ -110,6 +113,11 @@ #define RV1106_DDRGRF_CON(i) ((i) * 0x4) +#define RV1106_CORESGRF_HPMCU_BOOTADDR 0x44 + +#define RV1106_COREGRF_CACHE_PERI_ADDR_START 0x24 +#define RV1106_COREGRF_CACHE_PERI_ADDR_END 0x28 + /* pvmt */ #define RV1106_PVTM_CON(i) (0x4 + (i) * 4) #define RV1106_PVTM_INTEN 0x70 @@ -177,6 +185,17 @@ #define PMU_SUSPEND_MAGIC 0x02468ace #define PMU_RESUME_MAGIC 0x13579bdf +/* mcu */ +#define RV1106_MBOX_B2A_STATUS 0x2c +#define RV1106_MBOX_B2A_CMD_0 0x30 + +#define RV1106_HPMCU_MBOX_IRQ_AP 33 + +#define RV1106_HPMCU_BOOT_ADDR 0x40000 +#define RV1106_MBOX_CMD_AP_SUSPEND 0x12345600 +#define RV1106_MBOX_CMD_AP_RESUME 0x12345601 +#define RV1106_SYS_IS_WKUP 0x87654300 + #ifndef __ASSEMBLER__ extern unsigned long rkpm_bootdata_cpusp; extern unsigned long rkpm_bootdata_cpu_code;