aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 15:05:15 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 15:05:15 -0500
commitd027db132b395dabfac208e52a7e510e441bb9d2 (patch)
tree24b055b2385f9848e77e646ce475991d8675c3c4 /drivers/cpuidle
parentd01e4afdbb65e030fd6f1f96c30a558e2eb0f279 (diff)
parent5faf7cbb848da827f6ea1458b5a1c26a44e7510a (diff)
Merge tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC updates from Olof Johansson: "This contains the bulk of new SoC development for this merge window. Two new platforms have been added, the sunxi platforms (Allwinner A1x SoCs) by Maxime Ripard, and a generic Broadcom platform for a new series of ARMv7 platforms from them, where the hope is that we can keep the platform code generic enough to have them all share one mach directory. The new Broadcom platform is contributed by Christian Daudt. Highbank has grown support for Calxeda's next generation of hardware, ECX-2000. clps711x has seen a lot of cleanup from Alexander Shiyan, and he's also taken on maintainership of the platform. Beyond this there has been a bunch of work from a number of people on converting more platforms to IRQ domains, pinctrl conversion, cleanup and general feature enablement across most of the active platforms." Fix up trivial conflicts as per Olof. * tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (174 commits) mfd: vexpress-sysreg: Remove LEDs code irqchip: irq-sunxi: Add terminating entry for sunxi_irq_dt_ids clocksource: sunxi_timer: Add terminating entry for sunxi_timer_dt_ids irq: versatile: delete dangling variable ARM: sunxi: add missing include for mdelay() ARM: EXYNOS: Avoid early use of of_machine_is_compatible() ARM: dts: add node for PL330 MDMA1 controller for exynos4 ARM: EXYNOS: Add support for secondary CPU bring-up on Exynos4412 ARM: EXYNOS: add UART3 to DEBUG_LL ports ARM: S3C24XX: Add clkdev entry for camif-upll clock ARM: SAMSUNG: Add s3c24xx/s3c64xx CAMIF GPIO setup helpers ARM: sunxi: Add missing sun4i.dtsi file pinctrl: samsung: Do not initialise statics to 0 ARM i.MX6: remove gate_mask from pllv3 ARM i.MX6: Fix ethernet PLL clocks ARM i.MX6: rename PLLs according to datasheet ARM i.MX6: Add pwm support ARM i.MX51: Add pwm support ARM i.MX53: Add pwm support ARM: mx5: Replace clk_register_clkdev with clock DT lookup ...
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/Kconfig10
-rw-r--r--drivers/cpuidle/Makefile2
-rw-r--r--drivers/cpuidle/cpuidle-calxeda.c161
3 files changed, 173 insertions, 0 deletions
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 234ae651b38f..c4cc27e5c8a5 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -30,3 +30,13 @@ config CPU_IDLE_GOV_MENU
30 30
31config ARCH_NEEDS_CPU_IDLE_COUPLED 31config ARCH_NEEDS_CPU_IDLE_COUPLED
32 def_bool n 32 def_bool n
33
34if CPU_IDLE
35
36config CPU_IDLE_CALXEDA
37 bool "CPU Idle Driver for Calxeda processors"
38 depends on ARCH_HIGHBANK
39 help
40 Select this to enable cpuidle on Calxeda processors.
41
42endif
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 38c8f69f30cf..03ee87482c71 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -4,3 +4,5 @@
4 4
5obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ 5obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
6obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o 6obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
7
8obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c
new file mode 100644
index 000000000000..e1aab38c5a8d
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-calxeda.c
@@ -0,0 +1,161 @@
1/*
2 * Copyright 2012 Calxeda, Inc.
3 *
4 * Based on arch/arm/plat-mxc/cpuidle.c:
5 * Copyright 2012 Freescale Semiconductor, Inc.
6 * Copyright 2012 Linaro Ltd.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/cpuidle.h>
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/of.h>
25#include <linux/time.h>
26#include <linux/delay.h>
27#include <linux/suspend.h>
28#include <asm/cpuidle.h>
29#include <asm/proc-fns.h>
30#include <asm/smp_scu.h>
31#include <asm/suspend.h>
32#include <asm/cacheflush.h>
33#include <asm/cp15.h>
34
35extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
36extern void *scu_base_addr;
37
38static struct cpuidle_device __percpu *calxeda_idle_cpuidle_devices;
39
40static inline unsigned int get_auxcr(void)
41{
42 unsigned int val;
43 asm("mrc p15, 0, %0, c1, c0, 1 @ get AUXCR" : "=r" (val) : : "cc");
44 return val;
45}
46
47static inline void set_auxcr(unsigned int val)
48{
49 asm volatile("mcr p15, 0, %0, c1, c0, 1 @ set AUXCR"
50 : : "r" (val) : "cc");
51 isb();
52}
53
54static noinline void calxeda_idle_restore(void)
55{
56 set_cr(get_cr() | CR_C);
57 set_auxcr(get_auxcr() | 0x40);
58 scu_power_mode(scu_base_addr, SCU_PM_NORMAL);
59}
60
61static int calxeda_idle_finish(unsigned long val)
62{
63 /* Already flushed cache, but do it again as the outer cache functions
64 * dirty the cache with spinlocks */
65 flush_cache_all();
66
67 set_auxcr(get_auxcr() & ~0x40);
68 set_cr(get_cr() & ~CR_C);
69
70 scu_power_mode(scu_base_addr, SCU_PM_DORMANT);
71
72 cpu_do_idle();
73
74 /* Restore things if we didn't enter power-gating */
75 calxeda_idle_restore();
76 return 1;
77}
78
79static int calxeda_pwrdown_idle(struct cpuidle_device *dev,
80 struct cpuidle_driver *drv,
81 int index)
82{
83 highbank_set_cpu_jump(smp_processor_id(), cpu_resume);
84 cpu_suspend(0, calxeda_idle_finish);
85 return index;
86}
87
88static void calxeda_idle_cpuidle_devices_uninit(void)
89{
90 int i;
91 struct cpuidle_device *dev;
92
93 for_each_possible_cpu(i) {
94 dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, i);
95 cpuidle_unregister_device(dev);
96 }
97
98 free_percpu(calxeda_idle_cpuidle_devices);
99}
100
101static struct cpuidle_driver calxeda_idle_driver = {
102 .name = "calxeda_idle",
103 .en_core_tk_irqen = 1,
104 .states = {
105 ARM_CPUIDLE_WFI_STATE,
106 {
107 .name = "PG",
108 .desc = "Power Gate",
109 .flags = CPUIDLE_FLAG_TIME_VALID,
110 .exit_latency = 30,
111 .power_usage = 50,
112 .target_residency = 200,
113 .enter = calxeda_pwrdown_idle,
114 },
115 },
116 .state_count = 2,
117};
118
119static int __init calxeda_cpuidle_init(void)
120{
121 int cpu_id;
122 int ret;
123 struct cpuidle_device *dev;
124 struct cpuidle_driver *drv = &calxeda_idle_driver;
125
126 if (!of_machine_is_compatible("calxeda,highbank"))
127 return -ENODEV;
128
129 ret = cpuidle_register_driver(drv);
130 if (ret)
131 return ret;
132
133 calxeda_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
134 if (calxeda_idle_cpuidle_devices == NULL) {
135 ret = -ENOMEM;
136 goto unregister_drv;
137 }
138
139 /* initialize state data for each cpuidle_device */
140 for_each_possible_cpu(cpu_id) {
141 dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, cpu_id);
142 dev->cpu = cpu_id;
143 dev->state_count = drv->state_count;
144
145 ret = cpuidle_register_device(dev);
146 if (ret) {
147 pr_err("Failed to register cpu %u, error: %d\n",
148 cpu_id, ret);
149 goto uninit;
150 }
151 }
152
153 return 0;
154
155uninit:
156 calxeda_idle_cpuidle_devices_uninit();
157unregister_drv:
158 cpuidle_unregister_driver(drv);
159 return ret;
160}
161module_init(calxeda_cpuidle_init);