mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
ARM: rockchip: rk3288 support cpu on/off
This commit is contained in:
@@ -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)>,
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user