ARM: rockchip: support cpu hotplug and basic PM
author黄涛 <huangtao@rock-chips.com>
Thu, 20 Feb 2014 08:05:27 +0000 (16:05 +0800)
committer黄涛 <huangtao@rock-chips.com>
Thu, 20 Feb 2014 08:12:16 +0000 (16:12 +0800)
arch/arm/mach-rockchip/Makefile
arch/arm/mach-rockchip/common.h
arch/arm/mach-rockchip/hotplug.c [new file with mode: 0644]
arch/arm/mach-rockchip/platsmp.c
arch/arm/mach-rockchip/pm.c [new file with mode: 0644]
arch/arm/mach-rockchip/rk3188.c

index 30fc2ae939d4352b35a77c203aed8b2fbddd83e7..ef6b797b6a207e44fa54f6499b5aa7a170c8a99b 100755 (executable)
@@ -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
index e4fec0bd0233b711c46bbccaacc91ef1ccb07ee4..994004a50611cd1cb3eeb61dfbb5f37a205046ea 100644 (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
diff --git a/arch/arm/mach-rockchip/hotplug.c b/arch/arm/mach-rockchip/hotplug.c
new file mode 100644 (file)
index 0000000..cfd1627
--- /dev/null
@@ -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;
+}
index fb31bb47ff65595fff30a0282148539351824e72..64c0c2574c336cd017bc18dd50f01838369dd6dc 100644 (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
 };
diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c
new file mode 100644 (file)
index 0000000..03cf7b9
--- /dev/null
@@ -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);
+}
index d6e5ffd02d2bb0895f11cf078cfc15078bdf0f8b..c9d6c7f677b2f2b775da2627c3220f7fbdb7d2e8 100644 (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