From: 黄涛 Date: Mon, 10 Mar 2014 11:03:15 +0000 (+0800) Subject: ARM: rockchip: rk3288 support cpu on/off X-Git-Tag: firefly_0821_release~6162 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e6c0fa354640f4f56a115fcda704af82e5c9a054;p=firefly-linux-kernel-4.4.55.git ARM: rockchip: rk3288 support cpu on/off --- diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 4ff977f7d7e9..b913ba5e19dc 100755 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -54,6 +54,12 @@ <0xffc02000 0x1000>; }; + sram: sram@ff710000 { + compatible = "mmio-sram"; + reg = <0xff710000 0x8000>; /* 32k */ + map-exec; + }; + timer { compatible = "arm,armv7-timer"; interrupts = , diff --git a/arch/arm/mach-rockchip/common.c b/arch/arm/mach-rockchip/common.c index 5a381733bc59..cdeef164941c 100644 --- a/arch/arm/mach-rockchip/common.c +++ b/arch/arm/mach-rockchip/common.c @@ -184,6 +184,7 @@ static inline const char *boot_mode_name(u32 mode) case BOOT_MODE_REBOOT: return "REBOOT"; case BOOT_MODE_PANIC: return "PANIC"; case BOOT_MODE_WATCHDOG: return "WATCHDOG"; + case BOOT_MODE_TSADC: return "TSADC"; default: return ""; } } diff --git a/arch/arm/mach-rockchip/common.h b/arch/arm/mach-rockchip/common.h index b16901ef2c39..31b00d6479cb 100644 --- a/arch/arm/mach-rockchip/common.h +++ b/arch/arm/mach-rockchip/common.h @@ -29,6 +29,7 @@ extern int rockchip_cpu_disable(unsigned int cpu); #define BOOT_MODE_REBOOT 6 #define BOOT_MODE_PANIC 7 #define BOOT_MODE_WATCHDOG 8 +#define BOOT_MODE_TSADC 9 extern int rockchip_boot_mode(void); extern void __init rockchip_boot_mode_init(u32 flag, u32 mode); diff --git a/arch/arm/mach-rockchip/iomap.h b/arch/arm/mach-rockchip/iomap.h index fe9b26614844..af834fad8419 100644 --- a/arch/arm/mach-rockchip/iomap.h +++ b/arch/arm/mach-rockchip/iomap.h @@ -9,6 +9,7 @@ #define RK_CRU_VIRT RK_IO_ADDRESS(0x00000000) #define RK_GRF_VIRT RK_IO_ADDRESS(0x00010000) +#define RK_SGRF_VIRT (RK_GRF_VIRT + 0x1000) #define RK_PMU_VIRT RK_IO_ADDRESS(0x00020000) #define RK_ROM_VIRT RK_IO_ADDRESS(0x00030000) #define RK_EFUSE_VIRT RK_IO_ADDRESS(0x00040000) diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 64c0c2574c33..ce2be6cde566 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -110,14 +110,12 @@ static int __init rockchip_smp_prepare_bootram(void) return 0; } -static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) +static void __init rockchip_a9_smp_prepare_cpus(unsigned int max_cpus) { - void __iomem *scu_base_addr = NULL; - struct device_node *node; + void __iomem *scu_base_addr; unsigned int i, cpu; - if (scu_a9_has_base()) - scu_base_addr = ioremap(scu_a9_get_base(), 0x100); + scu_base_addr = ioremap(scu_a9_get_base(), 0x100); if (!scu_base_addr) { pr_err("%s: could not map scu registers\n", __func__); @@ -127,12 +125,6 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) if (rockchip_smp_prepare_bootram()) return; - node = of_find_compatible_node(NULL, NULL, "rockchip,pmu"); - if (!node) { - pr_err("%s: could not find pmu dt node\n", __func__); - return; - } - /* * While the number of cpus is gathered from dt, also get the number * of cores from the scu to verify this value when booting the cores. @@ -153,6 +145,12 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) iounmap(scu_base_addr); } +static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) +{ + if (scu_a9_has_base()) + return rockchip_a9_smp_prepare_cpus(max_cpus); +} + struct smp_operations rockchip_smp_ops __initdata = { .smp_prepare_cpus = rockchip_smp_prepare_cpus, .smp_boot_secondary = rockchip_boot_secondary, diff --git a/arch/arm/mach-rockchip/pmu.h b/arch/arm/mach-rockchip/pmu.h index 3e03a974130f..df55d96e8f45 100644 --- a/arch/arm/mach-rockchip/pmu.h +++ b/arch/arm/mach-rockchip/pmu.h @@ -77,6 +77,7 @@ enum pmu_power_domain { PD_CPU_3, PD_CS, PD_GPU, + PD_HEVC, PD_PERI, PD_SCU, PD_VIDEO, @@ -89,8 +90,10 @@ enum pmu_idle_req { IDLE_REQ_BP2AP, IDLE_REQ_BUS, IDLE_REQ_CORE, + IDLE_REQ_CPUP, IDLE_REQ_DMA, IDLE_REQ_GPU, + IDLE_REQ_HEVC, IDLE_REQ_PERI, IDLE_REQ_VIDEO, IDLE_REQ_VIO, diff --git a/arch/arm/mach-rockchip/rk3188.c b/arch/arm/mach-rockchip/rk3188.c index e03253cf64c3..0d3b8c74af06 100644 --- a/arch/arm/mach-rockchip/rk3188.c +++ b/arch/arm/mach-rockchip/rk3188.c @@ -110,7 +110,7 @@ static bool rk3188_pmu_power_domain_is_on(enum pmu_power_domain pd) return !(readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_ST) & BIT(pmu_pd_map[pd])); } -static noinline void do_pmu_set_power_domain(enum pmu_power_domain domain, bool on) +static noinline void rk3188_do_pmu_set_power_domain(enum pmu_power_domain domain, bool on) { u8 pd = pmu_pd_map[domain]; u32 val = readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_CON); @@ -228,7 +228,7 @@ static int rk3188_pmu_set_power_domain(enum pmu_power_domain pd, bool on) rk3188_pmu_set_idle_request(IDLE_REQ_GPU, true); } } - do_pmu_set_power_domain(pd, on); + rk3188_do_pmu_set_power_domain(pd, on); if (on) { /* if power up, idle request release to NIU */ if (pd == PD_VIO) { diff --git a/arch/arm/mach-rockchip/rk3288.c b/arch/arm/mach-rockchip/rk3288.c index f1050c65c2d6..d7fac3150ea0 100644 --- a/arch/arm/mach-rockchip/rk3288.c +++ b/arch/arm/mach-rockchip/rk3288.c @@ -45,7 +45,7 @@ static struct map_desc rk3288_io_desc[] __initdata = { RK3288_DEVICE(CRU), RK3288_DEVICE(GRF), - RK_DEVICE(RK_GRF_VIRT + RK3288_GRF_SIZE, RK3288_SGRF_PHYS, RK3288_SGRF_SIZE), + RK3288_DEVICE(SGRF), RK3288_DEVICE(PMU), RK3288_DEVICE(ROM), RK3288_DEVICE(EFUSE), @@ -69,16 +69,19 @@ static void __init rk3288_boot_mode_init(void) { u32 flag = readl_relaxed(RK_PMU_VIRT + RK3288_PMU_SYS_REG0); u32 mode = readl_relaxed(RK_PMU_VIRT + RK3288_PMU_SYS_REG1); + u32 rst_st = readl_relaxed(RK_CRU_VIRT + RK3288_CRU_GLB_RST_ST); - if (flag == (SYS_KERNRL_REBOOT_FLAG | BOOT_RECOVER)) { + if (flag == (SYS_KERNRL_REBOOT_FLAG | BOOT_RECOVER)) mode = BOOT_MODE_RECOVERY; - } + if (rst_st & ((1 << 4) | (1 << 5))) + mode = BOOT_MODE_WATCHDOG; + else if (rst_st & ((1 << 2) | (1 << 3))) + mode = BOOT_MODE_TSADC; rockchip_boot_mode_init(flag, mode); -#ifdef CONFIG_RK29_WATCHDOG - writel_relaxed(BOOT_MODE_WATCHDOG, RK_PMU_VIRT + RK3288_PMU_SYS_REG1); -#endif } +extern void secondary_startup(void); + static void __init rk3288_dt_map_io(void) { iotable_init(rk3288_io_desc, ARRAY_SIZE(rk3288_io_desc)); @@ -89,21 +92,117 @@ static void __init rk3288_dt_map_io(void) /* rkpwm is used instead of old pwm */ //writel_relaxed(0x00010001, RK_GRF_VIRT + RK3288_GRF_SOC_CON2); + /* enable fast boot */ + writel_relaxed(0x01000100, RK_SGRF_VIRT + RK3288_SGRF_SOC_CON0); + writel_relaxed(virt_to_phys(secondary_startup), RK_SGRF_VIRT + RK3288_SGRF_FAST_BOOT_ADDR); + rk3288_boot_mode_init(); } +static const u8 pmu_st_map[] = { + [PD_CPU_0] = 0, + [PD_CPU_1] = 1, + [PD_CPU_2] = 2, + [PD_CPU_3] = 3, + [PD_BUS] = 5, + [PD_PERI] = 6, + [PD_VIO] = 7, + [PD_VIDEO] = 8, + [PD_GPU] = 9, + [PD_HEVC] = 10, + [PD_SCU] = 11, +}; + static bool rk3288_pmu_power_domain_is_on(enum pmu_power_domain pd) { - return true; + /* 1'b0: power on, 1'b1: power off */ + return !(readl_relaxed(RK_PMU_VIRT + RK3288_PMU_PWRDN_ST) & BIT(pmu_st_map[pd])); } +static DEFINE_SPINLOCK(pmu_idle_lock); + +static const u8 pmu_idle_map[] = { + [IDLE_REQ_BUS] = 0, + [IDLE_REQ_PERI] = 1, + [IDLE_REQ_GPU] = 2, + [IDLE_REQ_VIDEO] = 3, + [IDLE_REQ_VIO] = 4, + [IDLE_REQ_CORE] = 5, + [IDLE_REQ_ALIVE] = 6, + [IDLE_REQ_DMA] = 7, + [IDLE_REQ_CPUP] = 8, + [IDLE_REQ_HEVC] = 9, +}; + static int rk3288_pmu_set_idle_request(enum pmu_idle_req req, bool idle) { + u32 bit = pmu_idle_map[req]; + u32 idle_mask = BIT(bit) | BIT(bit + 16); + u32 idle_target = (idle << bit) | (idle << (bit + 16)); + u32 mask = BIT(bit); + u32 val; + unsigned long flags; + + spin_lock_irqsave(&pmu_idle_lock, flags); + val = readl_relaxed(RK_PMU_VIRT + RK3288_PMU_IDLE_REQ); + if (idle) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, RK_PMU_VIRT + RK3288_PMU_IDLE_REQ); + dsb(); + + while ((readl_relaxed(RK_PMU_VIRT + RK3288_PMU_IDLE_ST) & idle_mask) != idle_target) + ; + spin_unlock_irqrestore(&pmu_idle_lock, flags); + return 0; } +static const u8 pmu_pd_map[] = { + [PD_CPU_0] = 0, + [PD_CPU_1] = 1, + [PD_CPU_2] = 2, + [PD_CPU_3] = 3, + [PD_BUS] = 5, + [PD_PERI] = 6, + [PD_VIO] = 7, + [PD_VIDEO] = 8, + [PD_GPU] = 9, + [PD_SCU] = 11, + [PD_HEVC] = 14, +}; + +static DEFINE_SPINLOCK(pmu_pd_lock); + +static noinline void rk3288_do_pmu_set_power_domain(enum pmu_power_domain domain, bool on) +{ + u8 pd = pmu_pd_map[domain]; + u32 val = readl_relaxed(RK_PMU_VIRT + RK3288_PMU_PWRDN_CON); + if (on) + val &= ~BIT(pd); + else + val |= BIT(pd); + writel_relaxed(val, RK_PMU_VIRT + RK3288_PMU_PWRDN_CON); + dsb(); + + while ((readl_relaxed(RK_PMU_VIRT + RK3288_PMU_PWRDN_ST) & BIT(pmu_st_map[domain])) == on) + ; +} + static int rk3288_pmu_set_power_domain(enum pmu_power_domain pd, bool on) { + unsigned long flags; + + spin_lock_irqsave(&pmu_pd_lock, flags); + if (rk3288_pmu_power_domain_is_on(pd) == on) { + spin_unlock_irqrestore(&pmu_pd_lock, flags); + return 0; + } + + rk3288_do_pmu_set_power_domain(pd, on); + + spin_unlock_irqrestore(&pmu_pd_lock, flags); return 0; }