Merge branch develop-3.10
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / rk312x.c
index ebc519ad929c29b644b30623f68fce32ce685537..91255c901ca1abc4c5c0348b4694df725a095ac9 100755 (executable)
@@ -1,6 +1,4 @@
 /*
- * Device Tree support for Rockchip RK3288
- *
  * Copyright (C) 2014 ROCKCHIP, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,6 +23,7 @@
 #include <linux/of_platform.h>
 #include <linux/rockchip/common.h>
 #include <linux/rockchip/cpu.h>
+#include <linux/rockchip/cpu_axi.h>
 #include <linux/rockchip/cru.h>
 #include <linux/rockchip/dvfs.h>
 #include <linux/rockchip/grf.h>
 #include <asm/cputype.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include "cpu_axi.h"
 #include "loader.h"
+#include "rk3126b.h"
 #define CPU 312x
 #include "sram.h"
 #include "pm.h"
 #include "pm-rk312x.c"
+#include <linux/rockchip/cpu.h>
 #define RK312X_DEVICE(name) \
        { \
                .virtual        = (unsigned long) RK_##name##_VIRT, \
@@ -68,6 +68,7 @@ static struct map_desc rk312x_io_desc[] __initdata = {
        RK312X_DEVICE(PMU),
        RK312X_DEVICE(EFUSE),
        RK312X_DEVICE(TIMER),
+       RK312X_DEVICE(CPU_AXI_BUS),
        RK_DEVICE(RK_DEBUG_UART_VIRT, RK312X_UART2_PHYS, RK312X_UART_SIZE),
        RK_DEVICE(RK_DDR_VIRT, RK312X_DDR_PCTL_PHYS, RK312X_DDR_PCTL_SIZE),
        RK_DEVICE(RK_DDR_VIRT + RK312X_DDR_PCTL_SIZE, RK312X_DDR_PHY_PHYS, RK312X_DDR_PHY_SIZE),
@@ -78,7 +79,23 @@ static struct map_desc rk312x_io_desc[] __initdata = {
        RK_DEVICE(RK_GIC_VIRT, RK312X_GIC_DIST_PHYS, RK312X_GIC_DIST_SIZE),
        RK_DEVICE(RK_GIC_VIRT + RK312X_GIC_DIST_SIZE, RK312X_GIC_CPU_PHYS, RK312X_GIC_CPU_SIZE),
        RK_DEVICE(RK312X_IMEM_VIRT, RK312X_IMEM_PHYS, RK312X_IMEM_SIZE),
+       RK_DEVICE(RK_PWM_VIRT, RK312X_PWM_PHYS, RK312X_PWM_SIZE),
 };
+
+static void __init rk312x_boot_mode_init(void)
+{
+       u32 flag = readl_relaxed(RK_PMU_VIRT + RK312X_PMU_SYS_REG0);
+       u32 mode = readl_relaxed(RK_PMU_VIRT + RK312X_PMU_SYS_REG1);
+       u32 rst_st = readl_relaxed(RK_CRU_VIRT + RK312X_CRU_GLB_RST_ST);
+
+       if (flag == (SYS_KERNRL_REBOOT_FLAG | BOOT_RECOVER))
+               mode = BOOT_MODE_RECOVERY;
+       if (rst_st & ((1 << 2) | (1 << 3)))
+               mode = BOOT_MODE_WATCHDOG;
+
+       rockchip_boot_mode_init(flag, mode);
+}
+
 static void usb_uart_init(void)
 {
 #ifdef CONFIG_RK_USB_UART
@@ -103,10 +120,18 @@ static void usb_uart_init(void)
 
 static void __init rk312x_dt_map_io(void)
 {
+       u32 v;
+
        iotable_init(rk312x_io_desc, ARRAY_SIZE(rk312x_io_desc));
        debug_ll_io_init();
        usb_uart_init();
 
+       /* pmu reset by second global soft reset */
+       v = readl_relaxed(RK_CRU_VIRT + RK312X_CRU_GLB_CNT_TH);
+       v &= ~(3 << 12);
+       v |= 1 << 12;
+       writel_relaxed(v, RK_CRU_VIRT + RK312X_CRU_GLB_CNT_TH);
+
        /* enable timer5 for core */
        writel_relaxed(0, RK312X_TIMER5_VIRT + 0x10);
        dsb();
@@ -115,6 +140,11 @@ static void __init rk312x_dt_map_io(void)
        dsb();
        writel_relaxed(1, RK312X_TIMER5_VIRT + 0x10);
        dsb();
+       writel_relaxed(0x80000000, RK_CRU_VIRT + RK312X_CRU_MISC_CON);
+       dsb();
+
+       rk312x_boot_mode_init();
+       rockchip_efuse_init();
 }
 
 static void __init rk3126_dt_map_io(void)
@@ -122,6 +152,9 @@ static void __init rk3126_dt_map_io(void)
        rockchip_soc_id = ROCKCHIP_SOC_RK3126;
 
        rk312x_dt_map_io();
+
+       if (readl_relaxed(RK_GRF_VIRT + RK312X_GRF_CHIP_TAG) == 0x3136)
+               rockchip_soc_id = ROCKCHIP_SOC_RK3126B;
 }
 
 static void __init rk3128_dt_map_io(void)
@@ -149,13 +182,14 @@ static int rk312x_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);
 
        spin_lock_irqsave(&pmu_idle_lock, flags);
        val = pmu_readl(RK312X_PMU_IDLE_REQ);
        if (idle)
-               val |= idle_mask;
+               val |= mask;
        else
-               val &= ~idle_mask;
+               val &= ~mask;
        pmu_writel(val, RK312X_PMU_IDLE_REQ);
        dsb();
 
@@ -176,7 +210,6 @@ static const u8 pmu_st_map[] = {
        [PD_VIO] = 3,
 };
 
-#if 1
 static noinline void rk312x_do_pmu_set_power_domain(enum pmu_power_domain domain
        , bool on)
 {
@@ -193,13 +226,23 @@ static noinline void rk312x_do_pmu_set_power_domain(enum pmu_power_domain domain
        while ((pmu_readl(RK312X_PMU_PWRDN_ST) & BIT(pmu_st_map[domain])) == on)
                ;
 }
-#endif
+
 static bool rk312x_pmu_power_domain_is_on(enum pmu_power_domain pd)
 {
        /*1"b0: power on, 1'b1: power off*/
        return !(pmu_readl(RK312X_PMU_PWRDN_ST) & BIT(pmu_st_map[pd]));
 }
 static DEFINE_SPINLOCK(pmu_pd_lock);
+static u32 rga_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+static u32 ebc_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+static u32 iep_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+static u32 lcdc0_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+static u32 vip0_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+static u32 gpu_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+static u32 video_qos[RK312X_CPU_AXI_QOS_NUM_REGS];
+
+#define SAVE_QOS(array, NAME) RK312X_CPU_AXI_SAVE_QOS(array, RK312X_CPU_AXI_##NAME##_QOS_VIRT)
+#define RESTORE_QOS(array, NAME) RK312X_CPU_AXI_RESTORE_QOS(array, RK312X_CPU_AXI_##NAME##_QOS_VIRT)
 
 static int rk312x_pmu_set_power_domain(enum pmu_power_domain pd, bool on)
 {
@@ -209,23 +252,41 @@ static int rk312x_pmu_set_power_domain(enum pmu_power_domain pd, bool on)
        if (rk312x_pmu_power_domain_is_on(pd) == on)
                goto out;
        if (!on) {
-               if (pd == PD_GPU)
+               if (pd == PD_GPU) {
+                       SAVE_QOS(gpu_qos, GPU);
                        rk312x_pmu_set_idle_request(IDLE_REQ_GPU, true);
-               else if (pd == PD_VIO)
+               } else if (pd == PD_VIO) {
+                       SAVE_QOS(rga_qos, VIO_RGA);
+                       if (!soc_is_rk3126b())
+                               SAVE_QOS(ebc_qos, VIO_EBC);
+                       SAVE_QOS(iep_qos, VIO_IEP);
+                       SAVE_QOS(lcdc0_qos, VIO_LCDC0);
+                       SAVE_QOS(vip0_qos, VIO_VIP0);
                        rk312x_pmu_set_idle_request(IDLE_REQ_VIO, true);
-               else if (pd == PD_VIDEO)
+               } else if (pd == PD_VIDEO) {
+                       SAVE_QOS(video_qos, VIDEO);
                        rk312x_pmu_set_idle_request(IDLE_REQ_VIDEO, true);
+               }
        }
 
        rk312x_do_pmu_set_power_domain(pd, on);
 
        if (on) {
-               if (pd == PD_GPU)
+               if (pd == PD_GPU) {
                        rk312x_pmu_set_idle_request(IDLE_REQ_GPU, false);
-               else if (pd == PD_VIO)
+                       RESTORE_QOS(gpu_qos, GPU);
+               } else if (pd == PD_VIO) {
                        rk312x_pmu_set_idle_request(IDLE_REQ_VIO, false);
-               else if (pd == PD_VIDEO)
+                       RESTORE_QOS(rga_qos, VIO_RGA);
+                       if (!soc_is_rk3126b())
+                               RESTORE_QOS(ebc_qos, VIO_EBC);
+                       RESTORE_QOS(iep_qos, VIO_IEP);
+                       RESTORE_QOS(lcdc0_qos, VIO_LCDC0);
+                       RESTORE_QOS(vip0_qos, VIO_VIP0);
+               } else if (pd == PD_VIDEO) {
                        rk312x_pmu_set_idle_request(IDLE_REQ_VIDEO, false);
+                       RESTORE_QOS(video_qos, VIDEO);
+               }
        }
 out:
        spin_unlock_irqrestore(&pmu_pd_lock, flags);
@@ -245,31 +306,31 @@ static int rk312x_sys_set_power_domain(enum pmu_power_domain pd, bool on)
        }
        for (i = 0; i < RK312X_CRU_CLKGATES_CON_CNT; i++)
                cru_writel(0xffff0000, RK312X_CRU_CLKGATES_CON(i));
-       if (0) {
-               if (on) {
+
+       if (on) {
 #ifdef CONFIG_SMP
-                       if (pd >= PD_CPU_1 && pd <= PD_CPU_3) {
-                               writel_relaxed(0x20000 << (pd - PD_CPU_1),
-                                              RK_CRU_VIRT + RK312X_CRU_SOFTRSTS_CON(0));
-                               dsb();
-                               udelay(10);
-                               writel_relaxed(virt_to_phys(secondary_startup),
-                                              RK312X_IMEM_VIRT + 8);
-                               writel_relaxed(0xDEADBEAF, RK312X_IMEM_VIRT + 4);
-                               dsb_sev();
-                       }
+               if (pd >= PD_CPU_1 && pd <= PD_CPU_3) {
+                       writel_relaxed(0x20000 << (pd - PD_CPU_1),
+                                      RK_CRU_VIRT + RK312X_CRU_SOFTRSTS_CON(0));
+                       dsb();
+                       udelay(10);
+                       writel_relaxed(virt_to_phys(secondary_startup),
+                                      RK312X_IMEM_VIRT + 8);
+                       writel_relaxed(0xDEADBEAF, RK312X_IMEM_VIRT + 4);
+                       dsb_sev();
+               }
 #endif
        } else {
 #ifdef CONFIG_SMP
-                       if (pd >= PD_CPU_1 && pd <= PD_CPU_3) {
-                               writel_relaxed(0x20002 << (pd - PD_CPU_1),
-                                              RK_CRU_VIRT + RK312X_CRU_SOFTRSTS_CON(0));
-                               dsb();
-                       }
-#endif
+               if (pd >= PD_CPU_1 && pd <= PD_CPU_3) {
+                       writel_relaxed(0x20002 << (pd - PD_CPU_1),
+                                      RK_CRU_VIRT + RK312X_CRU_SOFTRSTS_CON(0));
+                       dsb();
                }
+#endif
        }
-       if ((pd == PD_GPU) || (pd == PD_VIDEO) || (pd == PD_VIO))
+
+       if (((pd == PD_GPU) || (pd == PD_VIO) || (pd == PD_VIDEO)))
                ret = rk312x_pmu_set_power_domain(pd, on);
 
        for (i = 0; i < RK312X_CRU_CLKGATES_CON_CNT; i++) {
@@ -292,17 +353,61 @@ static void __init rk312x_dt_init_timer(void)
 
 static void __init rk312x_reserve(void)
 {
+       /* reserve memory for uboot */
+       rockchip_uboot_mem_reserve();
+
        /* reserve memory for ION */
        rockchip_ion_reserve();
 }
+
 #ifdef CONFIG_PM
-static void __init rk321x_init_suspend(void);
+static u32 rk_pmu_pwrdn_st;
+
+static void rk_pm_soc_pd_suspend(void)
+{
+       rk_pmu_pwrdn_st = pmu_readl(RK312X_PMU_PWRDN_ST);
+       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_GPU])))
+               rk312x_sys_set_power_domain(PD_GPU, false);
+
+       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIO])))
+               rk312x_sys_set_power_domain(PD_VIO, false);
+
+       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIDEO])))
+               rk312x_sys_set_power_domain(PD_VIDEO, false);
+}
+
+static void rk_pm_soc_pd_resume(void)
+{
+       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIDEO])))
+               rk312x_sys_set_power_domain(PD_VIDEO, true);
+
+       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIO])))
+               rk312x_sys_set_power_domain(PD_VIO, true);
+
+       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_GPU])))
+               rk312x_sys_set_power_domain(PD_GPU, true);
+}
+
+static void __init rk312x_init_suspend(void)
+{
+       pr_info("%s\n", __func__);
+       rkpm_pie_init();
+       rk312x_suspend_init();
+}
 #endif
+
 static void __init rk312x_init_late(void)
 {
 #ifdef CONFIG_PM
-       rk321x_init_suspend();
+       rockchip_suspend_init();
+       if (soc_is_rk3126b())
+               rk3126b_init_suspend();
+       else
+               rk312x_init_suspend();
+       rkpm_set_ops_pwr_dmns(rk_pm_soc_pd_suspend, rk_pm_soc_pd_resume);
 #endif
+       if (rockchip_jtag_enabled)
+               clk_prepare_enable(clk_get_sys(NULL, "clk_jtag"));
 }
 
 static void rk312x_restart(char mode, const char *cmd)
@@ -311,12 +416,15 @@ static void rk312x_restart(char mode, const char *cmd)
 
        rockchip_restart_get_boot_mode(cmd, &boot_flag, &boot_mode);
 
-       writel_relaxed(boot_flag, RK_GRF_VIRT + RK312X_GRF_OS_REG4);    // for loader
-       writel_relaxed(boot_mode, RK_GRF_VIRT + RK312X_GRF_OS_REG5);    // for linux
+       /* for loader */
+       writel_relaxed(boot_flag, RK_PMU_VIRT + RK312X_PMU_SYS_REG0);
+       /* for linux */
+       writel_relaxed(boot_mode, RK_PMU_VIRT + RK312X_PMU_SYS_REG1);
+
        dsb();
 
        /* pll enter slow mode */
-       writel_relaxed(0x30110000, RK_CRU_VIRT + RK312X_CRU_MODE_CON);
+       writel_relaxed(0x11010000, RK_CRU_VIRT + RK312X_CRU_MODE_CON);
        dsb();
        writel_relaxed(0xeca8, RK_CRU_VIRT + RK312X_CRU_GLB_SRST_SND_VALUE);
        dsb();
@@ -352,6 +460,8 @@ static int __init rk312x_pie_init(void)
 
        if (!cpu_is_rk312x())
                return 0;
+       if (soc_is_rk3126b())
+               return 0;
 
        err = rockchip_pie_init();
        if (err)
@@ -371,39 +481,18 @@ static int __init rk312x_pie_init(void)
        return 0;
 }
 arch_initcall(rk312x_pie_init);
-#ifdef CONFIG_PM
-static u32 rk_pmu_pwrdn_st;
-static inline void rk_pm_soc_pd_suspend(void)
-{
-       pmu_writel(0x00, RK312X_PMU_IDLE_REQ);
-       rk_pmu_pwrdn_st = pmu_readl(RK312X_PMU_PWRDN_ST);
-
-       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_GPU])))
-               rk312x_sys_set_power_domain(PD_GPU, false);
 
-       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIO])))
-               rk312x_sys_set_power_domain(PD_VIO, false);
-
-       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIDEO])))
-               rk312x_sys_set_power_domain(PD_VIDEO, false);
-       pmu_writel(0x00, RK312X_PMU_IDLE_REQ);
-}
-static inline void rk_pm_soc_pd_resume(void)
+#include "ddr_rk3126.c"
+static int __init rk312x_ddr_init(void)
 {
-       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIDEO])))
-               rk312x_sys_set_power_domain(PD_VIDEO, true);
-
-       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_VIO])))
-               rk312x_sys_set_power_domain(PD_VIO, true);
+       if (soc_is_rk3128() || soc_is_rk3126()) {
+               ddr_change_freq = _ddr_change_freq;
+               ddr_round_rate = _ddr_round_rate;
+               ddr_set_auto_self_refresh = _ddr_set_auto_self_refresh;
+               ddr_bandwidth_get = _ddr_bandwidth_get;
+               ddr_init(DDR3_DEFAULT, 0);
+       }
 
-       if (!(rk_pmu_pwrdn_st & BIT(pmu_st_map[PD_GPU])))
-               rk312x_sys_set_power_domain(PD_GPU, true);
-}
-static void __init rk321x_init_suspend(void)
-{
-       pr_info("%s\n", __func__);
-       rockchip_suspend_init();
-       rk312x_suspend_init();
-       rkpm_set_ops_pwr_dmns(rk_pm_soc_pd_suspend, rk_pm_soc_pd_resume);
+       return 0;
 }
-#endif
+arch_initcall_sync(rk312x_ddr_init);