aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-08 22:36:59 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-08 22:36:59 -0500
commit56d8adc5695a8d3f070c8498d532389580af5611 (patch)
treebbcb6c38506af002e94e64df8ab1540e6aba7825 /arch
parentf4b98415953dcf85bac4ea0a2264a3ead4a7bcc4 (diff)
parentee2ffd8bbb2170f9b52fc8ff4aebe9702e0de651 (diff)
Merge remote branch 'jwb/next' into next
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Kconfig13
-rw-r--r--arch/powerpc/boot/dts/canyonlands.dts31
-rw-r--r--arch/powerpc/boot/dts/kilauea.dts9
-rw-r--r--arch/powerpc/configs/40x/kilauea_defconfig5
-rw-r--r--arch/powerpc/configs/44x/canyonlands_defconfig3
-rw-r--r--arch/powerpc/platforms/44x/Makefile5
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/ppc4xx_cpm.c346
8 files changed, 387 insertions, 26 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 06d742c3fbcf..e16b4988f825 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -212,7 +212,7 @@ config ARCH_HIBERNATION_POSSIBLE
212config ARCH_SUSPEND_POSSIBLE 212config ARCH_SUSPEND_POSSIBLE
213 def_bool y 213 def_bool y
214 depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ 214 depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
215 PPC_85xx || PPC_86xx || PPC_PSERIES 215 PPC_85xx || PPC_86xx || PPC_PSERIES || 44x || 40x
216 216
217config PPC_DCR_NATIVE 217config PPC_DCR_NATIVE
218 bool 218 bool
@@ -598,13 +598,11 @@ config EXTRA_TARGETS
598 598
599 If unsure, leave blank 599 If unsure, leave blank
600 600
601if !44x || BROKEN
602config ARCH_WANTS_FREEZER_CONTROL 601config ARCH_WANTS_FREEZER_CONTROL
603 def_bool y 602 def_bool y
604 depends on ADB_PMU 603 depends on ADB_PMU
605 604
606source kernel/power/Kconfig 605source kernel/power/Kconfig
607endif
608 606
609config SECCOMP 607config SECCOMP
610 bool "Enable seccomp to safely compute untrusted bytecode" 608 bool "Enable seccomp to safely compute untrusted bytecode"
@@ -685,6 +683,15 @@ config FSL_PMC
685 Freescale MPC85xx/MPC86xx power management controller support 683 Freescale MPC85xx/MPC86xx power management controller support
686 (suspend/resume). For MPC83xx see platforms/83xx/suspend.c 684 (suspend/resume). For MPC83xx see platforms/83xx/suspend.c
687 685
686config PPC4xx_CPM
687 bool
688 default y
689 depends on SUSPEND && (44x || 40x)
690 help
691 PPC4xx Clock Power Management (CPM) support (suspend/resume).
692 It also enables support for two different idle states (idle-wait
693 and idle-doze).
694
688config 4xx_SOC 695config 4xx_SOC
689 bool 696 bool
690 697
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index a30370396250..5b27a4b74b79 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -105,6 +105,15 @@
105 dcr-reg = <0x00c 0x002>; 105 dcr-reg = <0x00c 0x002>;
106 }; 106 };
107 107
108 CPM0: cpm {
109 compatible = "ibm,cpm";
110 dcr-access-method = "native";
111 dcr-reg = <0x160 0x003>;
112 unused-units = <0x00000100>;
113 idle-doze = <0x02000000>;
114 standby = <0xfeff791d>;
115 };
116
108 L2C0: l2c { 117 L2C0: l2c {
109 compatible = "ibm,l2-cache-460ex", "ibm,l2-cache"; 118 compatible = "ibm,l2-cache-460ex", "ibm,l2-cache";
110 dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */ 119 dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */
@@ -270,28 +279,6 @@
270 interrupts = <0x1 0x4>; 279 interrupts = <0x1 0x4>;
271 }; 280 };
272 281
273 UART2: serial@ef600500 {
274 device_type = "serial";
275 compatible = "ns16550";
276 reg = <0xef600500 0x00000008>;
277 virtual-reg = <0xef600500>;
278 clock-frequency = <0>; /* Filled in by U-Boot */
279 current-speed = <0>; /* Filled in by U-Boot */
280 interrupt-parent = <&UIC1>;
281 interrupts = <28 0x4>;
282 };
283
284 UART3: serial@ef600600 {
285 device_type = "serial";
286 compatible = "ns16550";
287 reg = <0xef600600 0x00000008>;
288 virtual-reg = <0xef600600>;
289 clock-frequency = <0>; /* Filled in by U-Boot */
290 current-speed = <0>; /* Filled in by U-Boot */
291 interrupt-parent = <&UIC1>;
292 interrupts = <29 0x4>;
293 };
294
295 IIC0: i2c@ef600700 { 282 IIC0: i2c@ef600700 {
296 compatible = "ibm,iic-460ex", "ibm,iic"; 283 compatible = "ibm,iic-460ex", "ibm,iic";
297 reg = <0xef600700 0x00000014>; 284 reg = <0xef600700 0x00000014>;
diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts
index 083e68eeaca4..89edb16649c3 100644
--- a/arch/powerpc/boot/dts/kilauea.dts
+++ b/arch/powerpc/boot/dts/kilauea.dts
@@ -82,6 +82,15 @@
82 interrupt-parent = <&UIC0>; 82 interrupt-parent = <&UIC0>;
83 }; 83 };
84 84
85 CPM0: cpm {
86 compatible = "ibm,cpm";
87 dcr-access-method = "native";
88 dcr-reg = <0x0b0 0x003>;
89 unused-units = <0x00000000>;
90 idle-doze = <0x02000000>;
91 standby = <0xe3e74800>;
92 };
93
85 plb { 94 plb {
86 compatible = "ibm,plb-405ex", "ibm,plb4"; 95 compatible = "ibm,plb-405ex", "ibm,plb4";
87 #address-cells = <1>; 96 #address-cells = <1>;
diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig
index 4e19ee7ce4ee..34b8c1a1e752 100644
--- a/arch/powerpc/configs/40x/kilauea_defconfig
+++ b/arch/powerpc/configs/40x/kilauea_defconfig
@@ -12,6 +12,8 @@ CONFIG_MODULES=y
12CONFIG_MODULE_UNLOAD=y 12CONFIG_MODULE_UNLOAD=y
13# CONFIG_BLK_DEV_BSG is not set 13# CONFIG_BLK_DEV_BSG is not set
14CONFIG_KILAUEA=y 14CONFIG_KILAUEA=y
15CONFIG_NO_HZ=y
16CONFIG_HIGH_RES_TIMERS=y
15# CONFIG_WALNUT is not set 17# CONFIG_WALNUT is not set
16CONFIG_SPARSE_IRQ=y 18CONFIG_SPARSE_IRQ=y
17CONFIG_PCI=y 19CONFIG_PCI=y
@@ -42,6 +44,9 @@ CONFIG_MTD_PHYSMAP_OF=y
42CONFIG_MTD_NAND=y 44CONFIG_MTD_NAND=y
43CONFIG_MTD_NAND_NDFC=y 45CONFIG_MTD_NAND_NDFC=y
44CONFIG_PROC_DEVICETREE=y 46CONFIG_PROC_DEVICETREE=y
47CONFIG_PM=y
48CONFIG_SUSPEND=y
49CONFIG_PPC4xx_CPM=y
45CONFIG_BLK_DEV_RAM=y 50CONFIG_BLK_DEV_RAM=y
46CONFIG_BLK_DEV_RAM_SIZE=35000 51CONFIG_BLK_DEV_RAM_SIZE=35000
47# CONFIG_MISC_DEVICES is not set 52# CONFIG_MISC_DEVICES is not set
diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig
index 45c64d818b2a..17e4dd98eed7 100644
--- a/arch/powerpc/configs/44x/canyonlands_defconfig
+++ b/arch/powerpc/configs/44x/canyonlands_defconfig
@@ -42,6 +42,9 @@ CONFIG_MTD_PHYSMAP_OF=y
42CONFIG_MTD_NAND=y 42CONFIG_MTD_NAND=y
43CONFIG_MTD_NAND_NDFC=y 43CONFIG_MTD_NAND_NDFC=y
44CONFIG_PROC_DEVICETREE=y 44CONFIG_PROC_DEVICETREE=y
45CONFIG_PM=y
46CONFIG_SUSPEND=y
47CONFIG_PPC4xx_CPM=y
45CONFIG_BLK_DEV_RAM=y 48CONFIG_BLK_DEV_RAM=y
46CONFIG_BLK_DEV_RAM_SIZE=35000 49CONFIG_BLK_DEV_RAM_SIZE=35000
47# CONFIG_MISC_DEVICES is not set 50# CONFIG_MISC_DEVICES is not set
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 82ff326e0795..c04d16df8488 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -1,4 +1,7 @@
1obj-$(CONFIG_44x) := misc_44x.o idle.o 1obj-$(CONFIG_44x) += misc_44x.o
2ifneq ($(CONFIG_PPC4xx_CPM),y)
3obj-$(CONFIG_44x) += idle.o
4endif
2obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o 5obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o
3obj-$(CONFIG_EBONY) += ebony.o 6obj-$(CONFIG_EBONY) += ebony.o
4obj-$(CONFIG_SAM440EP) += sam440ep.o 7obj-$(CONFIG_SAM440EP) += sam440ep.o
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 0bef9dacb64e..9c2973479142 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o
41ifeq ($(CONFIG_PCI),y) 41ifeq ($(CONFIG_PCI),y)
42obj-$(CONFIG_4xx) += ppc4xx_pci.o 42obj-$(CONFIG_4xx) += ppc4xx_pci.o
43endif 43endif
44obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o
44obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o 45obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o
45 46
46obj-$(CONFIG_CPM) += cpm_common.o 47obj-$(CONFIG_CPM) += cpm_common.o
diff --git a/arch/powerpc/sysdev/ppc4xx_cpm.c b/arch/powerpc/sysdev/ppc4xx_cpm.c
new file mode 100644
index 000000000000..73b86cc5ea74
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_cpm.c
@@ -0,0 +1,346 @@
1/*
2 * PowerPC 4xx Clock and Power Management
3 *
4 * Copyright (C) 2010, Applied Micro Circuits Corporation
5 * Victor Gallardo (vgallardo@apm.com)
6 *
7 * Based on arch/powerpc/platforms/44x/idle.c:
8 * Jerone Young <jyoung5@us.ibm.com>
9 * Copyright 2008 IBM Corp.
10 *
11 * Based on arch/powerpc/sysdev/fsl_pmc.c:
12 * Anton Vorontsov <avorontsov@ru.mvista.com>
13 * Copyright 2009 MontaVista Software, Inc.
14 *
15 * See file CREDITS for list of people who contributed to this
16 * project.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License as
20 * published by the Free Software Foundation; either version 2 of
21 * the License, or (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31 * MA 02111-1307 USA
32 */
33
34#include <linux/kernel.h>
35#include <linux/of_platform.h>
36#include <linux/sysfs.h>
37#include <linux/cpu.h>
38#include <linux/suspend.h>
39#include <asm/dcr.h>
40#include <asm/dcr-native.h>
41#include <asm/machdep.h>
42
43#define CPM_ER 0
44#define CPM_FR 1
45#define CPM_SR 2
46
47#define CPM_IDLE_WAIT 0
48#define CPM_IDLE_DOZE 1
49
50struct cpm {
51 dcr_host_t dcr_host;
52 unsigned int dcr_offset[3];
53 unsigned int powersave_off;
54 unsigned int unused;
55 unsigned int idle_doze;
56 unsigned int standby;
57 unsigned int suspend;
58};
59
60static struct cpm cpm;
61
62struct cpm_idle_mode {
63 unsigned int enabled;
64 const char *name;
65};
66
67static struct cpm_idle_mode idle_mode[] = {
68 [CPM_IDLE_WAIT] = { 1, "wait" }, /* default */
69 [CPM_IDLE_DOZE] = { 0, "doze" },
70};
71
72static unsigned int cpm_set(unsigned int cpm_reg, unsigned int mask)
73{
74 unsigned int value;
75
76 /* CPM controller supports 3 different types of sleep interface
77 * known as class 1, 2 and 3. For class 1 units, they are
78 * unconditionally put to sleep when the corresponding CPM bit is
79 * set. For class 2 and 3 units this is not case; if they can be
80 * put to to sleep, they will. Here we do not verify, we just
81 * set them and expect them to eventually go off when they can.
82 */
83 value = dcr_read(cpm.dcr_host, cpm.dcr_offset[cpm_reg]);
84 dcr_write(cpm.dcr_host, cpm.dcr_offset[cpm_reg], value | mask);
85
86 /* return old state, to restore later if needed */
87 return value;
88}
89
90static void cpm_idle_wait(void)
91{
92 unsigned long msr_save;
93
94 /* save off initial state */
95 msr_save = mfmsr();
96 /* sync required when CPM0_ER[CPU] is set */
97 mb();
98 /* set wait state MSR */
99 mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE);
100 isync();
101 /* return to initial state */
102 mtmsr(msr_save);
103 isync();
104}
105
106static void cpm_idle_sleep(unsigned int mask)
107{
108 unsigned int er_save;
109
110 /* update CPM_ER state */
111 er_save = cpm_set(CPM_ER, mask);
112
113 /* go to wait state so that CPM0_ER[CPU] can take effect */
114 cpm_idle_wait();
115
116 /* restore CPM_ER state */
117 dcr_write(cpm.dcr_host, cpm.dcr_offset[CPM_ER], er_save);
118}
119
120static void cpm_idle_doze(void)
121{
122 cpm_idle_sleep(cpm.idle_doze);
123}
124
125static void cpm_idle_config(int mode)
126{
127 int i;
128
129 if (idle_mode[mode].enabled)
130 return;
131
132 for (i = 0; i < ARRAY_SIZE(idle_mode); i++)
133 idle_mode[i].enabled = 0;
134
135 idle_mode[mode].enabled = 1;
136}
137
138static ssize_t cpm_idle_show(struct kobject *kobj,
139 struct kobj_attribute *attr, char *buf)
140{
141 char *s = buf;
142 int i;
143
144 for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
145 if (idle_mode[i].enabled)
146 s += sprintf(s, "[%s] ", idle_mode[i].name);
147 else
148 s += sprintf(s, "%s ", idle_mode[i].name);
149 }
150
151 *(s-1) = '\n'; /* convert the last space to a newline */
152
153 return s - buf;
154}
155
156static ssize_t cpm_idle_store(struct kobject *kobj,
157 struct kobj_attribute *attr,
158 const char *buf, size_t n)
159{
160 int i;
161 char *p;
162 int len;
163
164 p = memchr(buf, '\n', n);
165 len = p ? p - buf : n;
166
167 for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
168 if (strncmp(buf, idle_mode[i].name, len) == 0) {
169 cpm_idle_config(i);
170 return n;
171 }
172 }
173
174 return -EINVAL;
175}
176
177static struct kobj_attribute cpm_idle_attr =
178 __ATTR(idle, 0644, cpm_idle_show, cpm_idle_store);
179
180static void cpm_idle_config_sysfs(void)
181{
182 struct sys_device *sys_dev;
183 unsigned long ret;
184
185 sys_dev = get_cpu_sysdev(0);
186
187 ret = sysfs_create_file(&sys_dev->kobj,
188 &cpm_idle_attr.attr);
189 if (ret)
190 printk(KERN_WARNING
191 "cpm: failed to create idle sysfs entry\n");
192}
193
194static void cpm_idle(void)
195{
196 if (idle_mode[CPM_IDLE_DOZE].enabled)
197 cpm_idle_doze();
198 else
199 cpm_idle_wait();
200}
201
202static int cpm_suspend_valid(suspend_state_t state)
203{
204 switch (state) {
205 case PM_SUSPEND_STANDBY:
206 return !!cpm.standby;
207 case PM_SUSPEND_MEM:
208 return !!cpm.suspend;
209 default:
210 return 0;
211 }
212}
213
214static void cpm_suspend_standby(unsigned int mask)
215{
216 unsigned long tcr_save;
217
218 /* disable decrement interrupt */
219 tcr_save = mfspr(SPRN_TCR);
220 mtspr(SPRN_TCR, tcr_save & ~TCR_DIE);
221
222 /* go to sleep state */
223 cpm_idle_sleep(mask);
224
225 /* restore decrement interrupt */
226 mtspr(SPRN_TCR, tcr_save);
227}
228
229static int cpm_suspend_enter(suspend_state_t state)
230{
231 switch (state) {
232 case PM_SUSPEND_STANDBY:
233 cpm_suspend_standby(cpm.standby);
234 break;
235 case PM_SUSPEND_MEM:
236 cpm_suspend_standby(cpm.suspend);
237 break;
238 }
239
240 return 0;
241}
242
243static struct platform_suspend_ops cpm_suspend_ops = {
244 .valid = cpm_suspend_valid,
245 .enter = cpm_suspend_enter,
246};
247
248static int cpm_get_uint_property(struct device_node *np,
249 const char *name)
250{
251 int len;
252 const unsigned int *prop = of_get_property(np, name, &len);
253
254 if (prop == NULL || len < sizeof(u32))
255 return 0;
256
257 return *prop;
258}
259
260static int __init cpm_init(void)
261{
262 struct device_node *np;
263 int dcr_base, dcr_len;
264 int ret = 0;
265
266 if (!cpm.powersave_off) {
267 cpm_idle_config(CPM_IDLE_WAIT);
268 ppc_md.power_save = &cpm_idle;
269 }
270
271 np = of_find_compatible_node(NULL, NULL, "ibm,cpm");
272 if (!np) {
273 ret = -EINVAL;
274 goto out;
275 }
276
277 dcr_base = dcr_resource_start(np, 0);
278 dcr_len = dcr_resource_len(np, 0);
279
280 if (dcr_base == 0 || dcr_len == 0) {
281 printk(KERN_ERR "cpm: could not parse dcr property for %s\n",
282 np->full_name);
283 ret = -EINVAL;
284 goto out;
285 }
286
287 cpm.dcr_host = dcr_map(np, dcr_base, dcr_len);
288
289 if (!DCR_MAP_OK(cpm.dcr_host)) {
290 printk(KERN_ERR "cpm: failed to map dcr property for %s\n",
291 np->full_name);
292 ret = -EINVAL;
293 goto out;
294 }
295
296 /* All 4xx SoCs with a CPM controller have one of two
297 * different order for the CPM registers. Some have the
298 * CPM registers in the following order (ER,FR,SR). The
299 * others have them in the following order (SR,ER,FR).
300 */
301
302 if (cpm_get_uint_property(np, "er-offset") == 0) {
303 cpm.dcr_offset[CPM_ER] = 0;
304 cpm.dcr_offset[CPM_FR] = 1;
305 cpm.dcr_offset[CPM_SR] = 2;
306 } else {
307 cpm.dcr_offset[CPM_ER] = 1;
308 cpm.dcr_offset[CPM_FR] = 2;
309 cpm.dcr_offset[CPM_SR] = 0;
310 }
311
312 /* Now let's see what IPs to turn off for the following modes */
313
314 cpm.unused = cpm_get_uint_property(np, "unused-units");
315 cpm.idle_doze = cpm_get_uint_property(np, "idle-doze");
316 cpm.standby = cpm_get_uint_property(np, "standby");
317 cpm.suspend = cpm_get_uint_property(np, "suspend");
318
319 /* If some IPs are unused let's turn them off now */
320
321 if (cpm.unused) {
322 cpm_set(CPM_ER, cpm.unused);
323 cpm_set(CPM_FR, cpm.unused);
324 }
325
326 /* Now let's export interfaces */
327
328 if (!cpm.powersave_off && cpm.idle_doze)
329 cpm_idle_config_sysfs();
330
331 if (cpm.standby || cpm.suspend)
332 suspend_set_ops(&cpm_suspend_ops);
333out:
334 if (np)
335 of_node_put(np);
336 return ret;
337}
338
339late_initcall(cpm_init);
340
341static int __init cpm_powersave_off(char *arg)
342{
343 cpm.powersave_off = 1;
344 return 0;
345}
346__setup("powersave=off", cpm_powersave_off);