From 8d7cf6f006d2a38ee7cceace5dc588adb0101bd8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 20 Feb 2014 16:05:27 +0800 Subject: [PATCH] ARM: rockchip: support cpu hotplug and basic PM --- arch/arm/mach-rockchip/Makefile | 2 + arch/arm/mach-rockchip/common.h | 5 ++ arch/arm/mach-rockchip/hotplug.c | 97 ++++++++++++++++++++++++++++++++ arch/arm/mach-rockchip/platsmp.c | 5 ++ arch/arm/mach-rockchip/pm.c | 17 ++++++ arch/arm/mach-rockchip/rk3188.c | 1 + 6 files changed, 127 insertions(+) create mode 100644 arch/arm/mach-rockchip/hotplug.c create mode 100644 arch/arm/mach-rockchip/pm.c diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index 30fc2ae939d4..ef6b797b6a20 100755 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -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 diff --git a/arch/arm/mach-rockchip/common.h b/arch/arm/mach-rockchip/common.h index e4fec0bd0233..994004a50611 100644 --- a/arch/arm/mach-rockchip/common.h +++ b/arch/arm/mach-rockchip/common.h @@ -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 diff --git a/arch/arm/mach-rockchip/hotplug.c b/arch/arm/mach-rockchip/hotplug.c new file mode 100644 index 000000000000..cfd1627588cd --- /dev/null +++ b/arch/arm/mach-rockchip/hotplug.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include + +#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; +} diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index fb31bb47ff65..64c0c2574c33 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -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 }; diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c new file mode 100644 index 000000000000..03cf7b9efc8b --- /dev/null +++ b/arch/arm/mach-rockchip/pm.c @@ -0,0 +1,17 @@ +#include + +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); +} diff --git a/arch/arm/mach-rockchip/rk3188.c b/arch/arm/mach-rockchip/rk3188.c index d6e5ffd02d2b..c9d6c7f677b2 100644 --- a/arch/arm/mach-rockchip/rk3188.c +++ b/arch/arm/mach-rockchip/rk3188.c @@ -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 -- 2.34.1