ARM: rockchip: rk3288 support cpu on/off
author黄涛 <huangtao@rock-chips.com>
Mon, 10 Mar 2014 11:03:15 +0000 (19:03 +0800)
committer黄涛 <huangtao@rock-chips.com>
Mon, 10 Mar 2014 11:03:15 +0000 (19:03 +0800)
arch/arm/boot/dts/rk3288.dtsi
arch/arm/mach-rockchip/common.c
arch/arm/mach-rockchip/common.h
arch/arm/mach-rockchip/iomap.h
arch/arm/mach-rockchip/platsmp.c
arch/arm/mach-rockchip/pmu.h
arch/arm/mach-rockchip/rk3188.c
arch/arm/mach-rockchip/rk3288.c

index 4ff977f7d7e97b29dcd72afbea032ad1dce242b9..b913ba5e19dc78e81954291e3b15e64323c304d8 100755 (executable)
                      <0xffc02000 0x1000>;
        };
 
+       sram: sram@ff710000 {
+               compatible = "mmio-sram";
+               reg = <0xff710000 0x8000>; /* 32k */
+               map-exec;
+       };
+
        timer {
                compatible = "arm,armv7-timer";
                interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
index 5a381733bc5911391733ffb1dcea28511825f9ae..cdeef164941c9f8356a2546756f708a07198ac10 100644 (file)
@@ -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 "";
        }
 }
index b16901ef2c39285883d2c84d71178eee41f46dc0..31b00d6479cbe7b728c6f8e4e4a00c3c12fa8bec 100644 (file)
@@ -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);
index fe9b26614844c288aa7c66873ee10e6c0581089f..af834fad84191d3dfbbde08217c60d3c58b8f6c6 100644 (file)
@@ -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)
index 64c0c2574c336cd017bc18dd50f01838369dd6dc..ce2be6cde566a7b5174d92677e17a3dfce8d1021 100644 (file)
@@ -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,
index 3e03a974130f6f1d5c8c0ec40f796354198d45ff..df55d96e8f458bccd414b81fda271a8bd52abff6 100644 (file)
@@ -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,
index e03253cf64c3f30fe539252e3d6a44f40820b5fe..0d3b8c74af063b1abeeb0dc684f39889b471a77b 100644 (file)
@@ -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) {
index f1050c65c2d6e5e7fccae1f81075fb363eb1f79b..d7fac3150ea0fb8ad57cae037d217ce687930f54 100644 (file)
@@ -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;
 }