ARM: rockchip: support cpu hotplug and basic PM

This commit is contained in:
黄涛
2014-02-20 16:05:27 +08:00
parent 59a7266118
commit 8d7cf6f006
6 changed files with 127 additions and 0 deletions

View File

@@ -1,9 +1,11 @@
obj-y += common.o
obj-y += cpu.o
obj-y += rk3188.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_RK_FPGA) += fpga.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
obj-$(CONFIG_CPU_FREQ) += rk3188-cpufreq.o
obj-$(CONFIG_DVFS) += dvfs.o

View File

@@ -4,6 +4,10 @@
extern unsigned long rockchip_boot_fn;
extern struct smp_operations rockchip_smp_ops;
extern int rockchip_cpu_kill(unsigned int cpu);
extern void rockchip_cpu_die(unsigned int cpu);
extern int rockchip_cpu_disable(unsigned int cpu);
#define BOOT_MODE_NORMAL 0
#define BOOT_MODE_FACTORY2 1
#define BOOT_MODE_RECOVERY 2
@@ -17,5 +21,6 @@ extern struct smp_operations rockchip_smp_ops;
extern int rockchip_boot_mode(void);
extern void __init rockchip_boot_mode_init(u32 flag, u32 mode);
extern void rockchip_restart_get_boot_mode(const char *cmd, u32 *flag, u32 *mode);
extern void __init rockchip_suspend_init(void);
#endif

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2012-2014 ROCKCHIP, Inc.
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <linux/delay.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
#include <asm/smp_plat.h>
#include <asm/system.h>
#include "common.h"
#include "pmu.h"
static cpumask_t dead_cpus;
int rockchip_cpu_kill(unsigned int cpu)
{
int k;
/* this function is running on another CPU than the offline target,
* here we need wait for shutdown code in platform_cpu_die() to
* finish before asking SoC-specific code to power off the CPU core.
*/
for (k = 0; k < 1000; k++) {
if (cpumask_test_cpu(cpu, &dead_cpus)) {
mdelay(1);
rockchip_pmu_ops.set_power_domain(PD_CPU_0 + cpu, false);
return 1;
}
mdelay(1);
}
return 0;
}
/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
*/
void rockchip_cpu_die(unsigned int cpu)
{
unsigned int v;
/* hardware shutdown code running on the CPU that is being offlined */
flush_cache_all();
dsb();
/* notify platform_cpu_kill() that hardware shutdown is finished */
cpumask_set_cpu(cpu, &dead_cpus);
flush_cache_louis();
asm volatile(
" mcr p15, 0, %1, c7, c5, 0\n"
" mcr p15, 0, %1, c7, c10, 4\n"
/*
* Turn off coherency
*/
" mrc p15, 0, %0, c1, c0, 1\n"
" bic %0, %0, %3\n" // clear ACTLR.SMP | ACTLR.FW
" mcr p15, 0, %0, c1, c0, 1\n"
" mrc p15, 0, %0, c1, c0, 0\n"
" bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v)
: "r" (0), "Ir" (CR_C), "Ir" ((1 << 6) | (1 << 0))
: "cc");
/* wait for SoC code in platform_cpu_kill() to shut off CPU core
* power. CPU bring up starts from the reset vector.
*/
while (1) {
dsb();
wfi();
}
}
int rockchip_cpu_disable(unsigned int cpu)
{
cpumask_clear_cpu(cpu, &dead_cpus);
/*
* we don't allow CPU 0 to be shutdown (it is still too special
* e.g. clock tick interrupts)
*/
return cpu == 0 ? -EPERM : 0;
}

View File

@@ -156,4 +156,9 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
struct smp_operations rockchip_smp_ops __initdata = {
.smp_prepare_cpus = rockchip_smp_prepare_cpus,
.smp_boot_secondary = rockchip_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_kill = rockchip_cpu_kill,
.cpu_die = rockchip_cpu_die,
.cpu_disable = rockchip_cpu_disable,
#endif
};

View File

@@ -0,0 +1,17 @@
#include <linux/suspend.h>
static int rockchip_suspend_enter(suspend_state_t state)
{
cpu_do_idle();
return 0;
}
static const struct platform_suspend_ops rockchip_suspend_ops = {
.valid = suspend_valid_only_mem,
.enter = rockchip_suspend_enter,
};
void __init rockchip_suspend_init(void)
{
suspend_set_ops(&rockchip_suspend_ops);
}

View File

@@ -329,6 +329,7 @@ DT_MACHINE_START(RK3188_DT, "RK30board")
.map_io = rk3188_dt_map_io,
.init_time = rk3188_dt_init_timer,
.dt_compat = rk3188_dt_compat,
.init_late = rockchip_suspend_init,
.restart = rk3188_restart,
MACHINE_END