ARM: rockchip: rk3288 support cpu on/off

This commit is contained in:
黄涛
2014-03-10 19:03:15 +08:00
parent e3e8445fd7
commit e6c0fa3546
8 changed files with 129 additions and 20 deletions

View File

@@ -54,6 +54,12 @@
<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)>,

View 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 "";
}
}

View 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);

View 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)

View 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,

View 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,

View 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) {

View 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;
}