aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2008-08-19 04:08:40 -0400
committerTony Lindgren <tony@atomide.com>2008-08-19 04:08:40 -0400
commitad67ef6848a1608b0430003e11e7af1ce706e341 (patch)
treef55151e3cc4b4739f13a074af6e7f43e7e6be2d1 /arch/arm
parent1fca25427482387689fa27594c992a961d98768f (diff)
ARM: OMAP2: Powerdomain: Add base OMAP2/3 powerdomain code
This patch creates an interface to the powerdomain registers in the PRM/CM modules on OMAP2/3. This interface is intended to be used by PM code, e.g., pm.c; not by device drivers directly. Each powerdomain will be defined in later patches as static structures. Also defined are dependencies between powerdomains, used for adding and removing PM_WKDEP and CM_SLEEPDEP bits. The powerdomain structures are linked into a list at boot by pwrdm_register(), similar to the OMAP clock code. The patch adds a Kconfig option, CONFIG_OMAP_DEBUG_POWERDOMAIN, which when enabled will emit verbose debug messages via pr_debug(). Signed-off-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/Makefile2
-rw-r--r--arch/arm/mach-omap2/clock34xx.c27
-rw-r--r--arch/arm/mach-omap2/powerdomain.c909
-rw-r--r--arch/arm/plat-omap/Kconfig12
-rw-r--r--arch/arm/plat-omap/include/mach/powerdomain.h139
5 files changed, 1078 insertions, 11 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 93ee990618ef..1001d42048e9 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -4,7 +4,7 @@
4 4
5# Common support 5# Common support
6obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \ 6obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \
7 devices.o serial.o gpmc.o timer-gp.o 7 devices.o serial.o gpmc.o timer-gp.o powerdomain.o
8 8
9obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o 9obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
10 10
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 3ff74952f835..dff7a72fefc9 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -62,11 +62,14 @@ static void omap3_dpll_recalc(struct clk *clk)
62static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits) 62static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits)
63{ 63{
64 const struct dpll_data *dd; 64 const struct dpll_data *dd;
65 u32 v;
65 66
66 dd = clk->dpll_data; 67 dd = clk->dpll_data;
67 68
68 cm_rmw_reg_bits(dd->enable_mask, clken_bits << __ffs(dd->enable_mask), 69 v = __raw_readl(dd->control_reg);
69 dd->control_reg); 70 v &= ~dd->enable_mask;
71 v |= clken_bits << __ffs(dd->enable_mask);
72 __raw_writel(v, dd->control_reg);
70} 73}
71 74
72/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ 75/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
@@ -82,7 +85,7 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
82 state <<= dd->idlest_bit; 85 state <<= dd->idlest_bit;
83 idlest_mask = 1 << dd->idlest_bit; 86 idlest_mask = 1 << dd->idlest_bit;
84 87
85 while (((cm_read_reg(dd->idlest_reg) & idlest_mask) != state) && 88 while (((__raw_readl(dd->idlest_reg) & idlest_mask) != state) &&
86 i < MAX_DPLL_WAIT_TRIES) { 89 i < MAX_DPLL_WAIT_TRIES) {
87 i++; 90 i++;
88 udelay(1); 91 udelay(1);
@@ -285,7 +288,7 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk)
285 288
286 dd = clk->dpll_data; 289 dd = clk->dpll_data;
287 290
288 v = cm_read_reg(dd->autoidle_reg); 291 v = __raw_readl(dd->autoidle_reg);
289 v &= dd->autoidle_mask; 292 v &= dd->autoidle_mask;
290 v >>= __ffs(dd->autoidle_mask); 293 v >>= __ffs(dd->autoidle_mask);
291 294
@@ -304,6 +307,7 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk)
304static void omap3_dpll_allow_idle(struct clk *clk) 307static void omap3_dpll_allow_idle(struct clk *clk)
305{ 308{
306 const struct dpll_data *dd; 309 const struct dpll_data *dd;
310 u32 v;
307 311
308 if (!clk || !clk->dpll_data) 312 if (!clk || !clk->dpll_data)
309 return; 313 return;
@@ -315,9 +319,10 @@ static void omap3_dpll_allow_idle(struct clk *clk)
315 * by writing 0x5 instead of 0x1. Add some mechanism to 319 * by writing 0x5 instead of 0x1. Add some mechanism to
316 * optionally enter this mode. 320 * optionally enter this mode.
317 */ 321 */
318 cm_rmw_reg_bits(dd->autoidle_mask, 322 v = __raw_readl(dd->autoidle_reg);
319 DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask), 323 v &= ~dd->autoidle_mask;
320 dd->autoidle_reg); 324 v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
325 __raw_writel(v, dd->autoidle_reg);
321} 326}
322 327
323/** 328/**
@@ -329,15 +334,17 @@ static void omap3_dpll_allow_idle(struct clk *clk)
329static void omap3_dpll_deny_idle(struct clk *clk) 334static void omap3_dpll_deny_idle(struct clk *clk)
330{ 335{
331 const struct dpll_data *dd; 336 const struct dpll_data *dd;
337 u32 v;
332 338
333 if (!clk || !clk->dpll_data) 339 if (!clk || !clk->dpll_data)
334 return; 340 return;
335 341
336 dd = clk->dpll_data; 342 dd = clk->dpll_data;
337 343
338 cm_rmw_reg_bits(dd->autoidle_mask, 344 v = __raw_readl(dd->autoidle_reg);
339 DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask), 345 v &= ~dd->autoidle_mask;
340 dd->autoidle_reg); 346 v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
347 __raw_writel(v, dd->autoidle_reg);
341} 348}
342 349
343/* Clock control for DPLL outputs */ 350/* Clock control for DPLL outputs */
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
new file mode 100644
index 000000000000..1ec003832ef8
--- /dev/null
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -0,0 +1,909 @@
1/*
2 * OMAP powerdomain control
3 *
4 * Copyright (C) 2007-2008 Texas Instruments, Inc.
5 * Copyright (C) 2007-2008 Nokia Corporation
6 *
7 * Written by Paul Walmsley
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#ifdef CONFIG_OMAP_DEBUG_POWERDOMAIN
14# define DEBUG
15#endif
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/types.h>
20#include <linux/delay.h>
21#include <linux/spinlock.h>
22#include <linux/list.h>
23#include <linux/errno.h>
24#include <linux/err.h>
25#include <linux/io.h>
26
27#include <asm/atomic.h>
28
29#include "cm.h"
30#include "cm-regbits-34xx.h"
31#include "prm.h"
32#include "prm-regbits-34xx.h"
33
34#include <mach/cpu.h>
35#include <mach/powerdomain.h>
36
37/* pwrdm_list contains all registered struct powerdomains */
38static LIST_HEAD(pwrdm_list);
39
40/*
41 * pwrdm_rwlock protects pwrdm_list add and del ops - also reused to
42 * protect pwrdm_clkdms[] during clkdm add/del ops
43 */
44static DEFINE_RWLOCK(pwrdm_rwlock);
45
46
47/* Private functions */
48
49static u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
50{
51 u32 v;
52
53 v = prm_read_mod_reg(domain, idx);
54 v &= mask;
55 v >>= __ffs(mask);
56
57 return v;
58}
59
60static struct powerdomain *_pwrdm_lookup(const char *name)
61{
62 struct powerdomain *pwrdm, *temp_pwrdm;
63
64 pwrdm = NULL;
65
66 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
67 if (!strcmp(name, temp_pwrdm->name)) {
68 pwrdm = temp_pwrdm;
69 break;
70 }
71 }
72
73 return pwrdm;
74}
75
76/* _pwrdm_deps_lookup - look up the specified powerdomain in a pwrdm list */
77static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
78 struct pwrdm_dep *deps)
79{
80 struct pwrdm_dep *pd;
81
82 if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip))
83 return ERR_PTR(-EINVAL);
84
85 for (pd = deps; pd; pd++) {
86
87 if (!omap_chip_is(pd->omap_chip))
88 continue;
89
90 if (!pd->pwrdm && pd->pwrdm_name)
91 pd->pwrdm = pwrdm_lookup(pd->pwrdm_name);
92
93 if (pd->pwrdm == pwrdm)
94 break;
95
96 }
97
98 if (!pd)
99 return ERR_PTR(-ENOENT);
100
101 return pd->pwrdm;
102}
103
104
105/* Public functions */
106
107/**
108 * pwrdm_init - set up the powerdomain layer
109 *
110 * Loop through the list of powerdomains, registering all that are
111 * available on the current CPU. If pwrdm_list is supplied and not
112 * null, all of the referenced powerdomains will be registered. No
113 * return value.
114 */
115void pwrdm_init(struct powerdomain **pwrdm_list)
116{
117 struct powerdomain **p = NULL;
118
119 if (pwrdm_list)
120 for (p = pwrdm_list; *p; p++)
121 pwrdm_register(*p);
122}
123
124/**
125 * pwrdm_register - register a powerdomain
126 * @pwrdm: struct powerdomain * to register
127 *
128 * Adds a powerdomain to the internal powerdomain list. Returns
129 * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
130 * already registered by the provided name, or 0 upon success.
131 */
132int pwrdm_register(struct powerdomain *pwrdm)
133{
134 unsigned long flags;
135 int ret = -EINVAL;
136
137 if (!pwrdm)
138 return -EINVAL;
139
140 if (!omap_chip_is(pwrdm->omap_chip))
141 return -EINVAL;
142
143 write_lock_irqsave(&pwrdm_rwlock, flags);
144 if (_pwrdm_lookup(pwrdm->name)) {
145 ret = -EEXIST;
146 goto pr_unlock;
147 }
148
149 list_add(&pwrdm->node, &pwrdm_list);
150
151 pr_debug("powerdomain: registered %s\n", pwrdm->name);
152 ret = 0;
153
154pr_unlock:
155 write_unlock_irqrestore(&pwrdm_rwlock, flags);
156
157 return ret;
158}
159
160/**
161 * pwrdm_unregister - unregister a powerdomain
162 * @pwrdm: struct powerdomain * to unregister
163 *
164 * Removes a powerdomain from the internal powerdomain list. Returns
165 * -EINVAL if pwrdm argument is NULL.
166 */
167int pwrdm_unregister(struct powerdomain *pwrdm)
168{
169 unsigned long flags;
170
171 if (!pwrdm)
172 return -EINVAL;
173
174 write_lock_irqsave(&pwrdm_rwlock, flags);
175 list_del(&pwrdm->node);
176 write_unlock_irqrestore(&pwrdm_rwlock, flags);
177
178 pr_debug("powerdomain: unregistered %s\n", pwrdm->name);
179
180 return 0;
181}
182
183/**
184 * pwrdm_lookup - look up a powerdomain by name, return a pointer
185 * @name: name of powerdomain
186 *
187 * Find a registered powerdomain by its name. Returns a pointer to the
188 * struct powerdomain if found, or NULL otherwise.
189 */
190struct powerdomain *pwrdm_lookup(const char *name)
191{
192 struct powerdomain *pwrdm;
193 unsigned long flags;
194
195 if (!name)
196 return NULL;
197
198 read_lock_irqsave(&pwrdm_rwlock, flags);
199 pwrdm = _pwrdm_lookup(name);
200 read_unlock_irqrestore(&pwrdm_rwlock, flags);
201
202 return pwrdm;
203}
204
205/**
206 * pwrdm_for_each - call function on each registered clockdomain
207 * @fn: callback function *
208 *
209 * Call the supplied function for each registered powerdomain. The
210 * callback function can return anything but 0 to bail out early from
211 * the iterator. The callback function is called with the pwrdm_rwlock
212 * held for reading, so no powerdomain structure manipulation
213 * functions should be called from the callback, although hardware
214 * powerdomain control functions are fine. Returns the last return
215 * value of the callback function, which should be 0 for success or
216 * anything else to indicate failure; or -EINVAL if the function
217 * pointer is null.
218 */
219int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm))
220{
221 struct powerdomain *temp_pwrdm;
222 unsigned long flags;
223 int ret = 0;
224
225 if (!fn)
226 return -EINVAL;
227
228 read_lock_irqsave(&pwrdm_rwlock, flags);
229 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
230 ret = (*fn)(temp_pwrdm);
231 if (ret)
232 break;
233 }
234 read_unlock_irqrestore(&pwrdm_rwlock, flags);
235
236 return ret;
237}
238
239/**
240 * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1
241 * @pwrdm1: wake this struct powerdomain * up (dependent)
242 * @pwrdm2: when this struct powerdomain * wakes up (source)
243 *
244 * When the powerdomain represented by pwrdm2 wakes up (due to an
245 * interrupt), wake up pwrdm1. Implemented in hardware on the OMAP,
246 * this feature is designed to reduce wakeup latency of the dependent
247 * powerdomain. Returns -EINVAL if presented with invalid powerdomain
248 * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
249 * 0 upon success.
250 */
251int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
252{
253 struct powerdomain *p;
254
255 if (!pwrdm1)
256 return -EINVAL;
257
258 p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
259 if (IS_ERR(p)) {
260 pr_debug("powerdomain: hardware cannot set/clear wake up of "
261 "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
262 return IS_ERR(p);
263 }
264
265 pr_debug("powerdomain: hardware will wake up %s when %s wakes up\n",
266 pwrdm1->name, pwrdm2->name);
267
268 prm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
269 pwrdm1->prcm_offs, PM_WKDEP);
270
271 return 0;
272}
273
274/**
275 * pwrdm_del_wkdep - remove a wakeup dependency from pwrdm2 to pwrdm1
276 * @pwrdm1: wake this struct powerdomain * up (dependent)
277 * @pwrdm2: when this struct powerdomain * wakes up (source)
278 *
279 * Remove a wakeup dependency that causes pwrdm1 to wake up when pwrdm2
280 * wakes up. Returns -EINVAL if presented with invalid powerdomain
281 * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
282 * 0 upon success.
283 */
284int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
285{
286 struct powerdomain *p;
287
288 if (!pwrdm1)
289 return -EINVAL;
290
291 p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
292 if (IS_ERR(p)) {
293 pr_debug("powerdomain: hardware cannot set/clear wake up of "
294 "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
295 return IS_ERR(p);
296 }
297
298 pr_debug("powerdomain: hardware will no longer wake up %s after %s "
299 "wakes up\n", pwrdm1->name, pwrdm2->name);
300
301 prm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
302 pwrdm1->prcm_offs, PM_WKDEP);
303
304 return 0;
305}
306
307/**
308 * pwrdm_read_wkdep - read wakeup dependency state from pwrdm2 to pwrdm1
309 * @pwrdm1: wake this struct powerdomain * up (dependent)
310 * @pwrdm2: when this struct powerdomain * wakes up (source)
311 *
312 * Return 1 if a hardware wakeup dependency exists wherein pwrdm1 will be
313 * awoken when pwrdm2 wakes up; 0 if dependency is not set; -EINVAL
314 * if either powerdomain pointer is invalid; or -ENOENT if the hardware
315 * is incapable.
316 *
317 * REVISIT: Currently this function only represents software-controllable
318 * wakeup dependencies. Wakeup dependencies fixed in hardware are not
319 * yet handled here.
320 */
321int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
322{
323 struct powerdomain *p;
324
325 if (!pwrdm1)
326 return -EINVAL;
327
328 p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
329 if (IS_ERR(p)) {
330 pr_debug("powerdomain: hardware cannot set/clear wake up of "
331 "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
332 return IS_ERR(p);
333 }
334
335 return prm_read_mod_bits_shift(pwrdm1->prcm_offs, PM_WKDEP,
336 (1 << pwrdm2->dep_bit));
337}
338
339/**
340 * pwrdm_add_sleepdep - add a sleep dependency from pwrdm2 to pwrdm1
341 * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
342 * @pwrdm2: when this struct powerdomain * is active (source)
343 *
344 * Prevent pwrdm1 from automatically going inactive (and then to
345 * retention or off) if pwrdm2 is still active. Returns -EINVAL if
346 * presented with invalid powerdomain pointers or called on a machine
347 * that does not support software-configurable hardware sleep dependencies,
348 * -ENOENT if the specified dependency cannot be set in hardware, or
349 * 0 upon success.
350 */
351int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
352{
353 struct powerdomain *p;
354
355 if (!pwrdm1)
356 return -EINVAL;
357
358 if (!cpu_is_omap34xx())
359 return -EINVAL;
360
361 p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
362 if (IS_ERR(p)) {
363 pr_debug("powerdomain: hardware cannot set/clear sleep "
364 "dependency affecting %s from %s\n", pwrdm1->name,
365 pwrdm2->name);
366 return IS_ERR(p);
367 }
368
369 pr_debug("powerdomain: will prevent %s from sleeping if %s is active\n",
370 pwrdm1->name, pwrdm2->name);
371
372 cm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
373 pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
374
375 return 0;
376}
377
378/**
379 * pwrdm_del_sleepdep - remove a sleep dependency from pwrdm2 to pwrdm1
380 * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
381 * @pwrdm2: when this struct powerdomain * is active (source)
382 *
383 * Allow pwrdm1 to automatically go inactive (and then to retention or
384 * off), independent of the activity state of pwrdm2. Returns -EINVAL
385 * if presented with invalid powerdomain pointers or called on a machine
386 * that does not support software-configurable hardware sleep dependencies,
387 * -ENOENT if the specified dependency cannot be cleared in hardware, or
388 * 0 upon success.
389 */
390int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
391{
392 struct powerdomain *p;
393
394 if (!pwrdm1)
395 return -EINVAL;
396
397 if (!cpu_is_omap34xx())
398 return -EINVAL;
399
400 p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
401 if (IS_ERR(p)) {
402 pr_debug("powerdomain: hardware cannot set/clear sleep "
403 "dependency affecting %s from %s\n", pwrdm1->name,
404 pwrdm2->name);
405 return IS_ERR(p);
406 }
407
408 pr_debug("powerdomain: will no longer prevent %s from sleeping if "
409 "%s is active\n", pwrdm1->name, pwrdm2->name);
410
411 cm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
412 pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
413
414 return 0;
415}
416
417/**
418 * pwrdm_read_sleepdep - read sleep dependency state from pwrdm2 to pwrdm1
419 * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
420 * @pwrdm2: when this struct powerdomain * is active (source)
421 *
422 * Return 1 if a hardware sleep dependency exists wherein pwrdm1 will
423 * not be allowed to automatically go inactive if pwrdm2 is active;
424 * 0 if pwrdm1's automatic power state inactivity transition is independent
425 * of pwrdm2's; -EINVAL if either powerdomain pointer is invalid or called
426 * on a machine that does not support software-configurable hardware sleep
427 * dependencies; or -ENOENT if the hardware is incapable.
428 *
429 * REVISIT: Currently this function only represents software-controllable
430 * sleep dependencies. Sleep dependencies fixed in hardware are not
431 * yet handled here.
432 */
433int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
434{
435 struct powerdomain *p;
436
437 if (!pwrdm1)
438 return -EINVAL;
439
440 if (!cpu_is_omap34xx())
441 return -EINVAL;
442
443 p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
444 if (IS_ERR(p)) {
445 pr_debug("powerdomain: hardware cannot set/clear sleep "
446 "dependency affecting %s from %s\n", pwrdm1->name,
447 pwrdm2->name);
448 return IS_ERR(p);
449 }
450
451 return prm_read_mod_bits_shift(pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP,
452 (1 << pwrdm2->dep_bit));
453}
454
455/**
456 * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
457 * @pwrdm: struct powerdomain *
458 *
459 * Return the number of controllable memory banks in powerdomain pwrdm,
460 * starting with 1. Returns -EINVAL if the powerdomain pointer is null.
461 */
462int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
463{
464 if (!pwrdm)
465 return -EINVAL;
466
467 return pwrdm->banks;
468}
469
470/**
471 * pwrdm_set_next_pwrst - set next powerdomain power state
472 * @pwrdm: struct powerdomain * to set
473 * @pwrst: one of the PWRDM_POWER_* macros
474 *
475 * Set the powerdomain pwrdm's next power state to pwrst. The powerdomain
476 * may not enter this state immediately if the preconditions for this state
477 * have not been satisfied. Returns -EINVAL if the powerdomain pointer is
478 * null or if the power state is invalid for the powerdomin, or returns 0
479 * upon success.
480 */
481int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
482{
483 if (!pwrdm)
484 return -EINVAL;
485
486 if (!(pwrdm->pwrsts & (1 << pwrst)))
487 return -EINVAL;
488
489 pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
490 pwrdm->name, pwrst);
491
492 prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
493 (pwrst << OMAP_POWERSTATE_SHIFT),
494 pwrdm->prcm_offs, PM_PWSTCTRL);
495
496 return 0;
497}
498
499/**
500 * pwrdm_read_next_pwrst - get next powerdomain power state
501 * @pwrdm: struct powerdomain * to get power state
502 *
503 * Return the powerdomain pwrdm's next power state. Returns -EINVAL
504 * if the powerdomain pointer is null or returns the next power state
505 * upon success.
506 */
507int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
508{
509 if (!pwrdm)
510 return -EINVAL;
511
512 return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
513 OMAP_POWERSTATE_MASK);
514}
515
516/**
517 * pwrdm_read_pwrst - get current powerdomain power state
518 * @pwrdm: struct powerdomain * to get power state
519 *
520 * Return the powerdomain pwrdm's current power state. Returns -EINVAL
521 * if the powerdomain pointer is null or returns the current power state
522 * upon success.
523 */
524int pwrdm_read_pwrst(struct powerdomain *pwrdm)
525{
526 if (!pwrdm)
527 return -EINVAL;
528
529 return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
530 OMAP_POWERSTATEST_MASK);
531}
532
533/**
534 * pwrdm_read_prev_pwrst - get previous powerdomain power state
535 * @pwrdm: struct powerdomain * to get previous power state
536 *
537 * Return the powerdomain pwrdm's previous power state. Returns -EINVAL
538 * if the powerdomain pointer is null or returns the previous power state
539 * upon success.
540 */
541int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
542{
543 if (!pwrdm)
544 return -EINVAL;
545
546 return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
547 OMAP3430_LASTPOWERSTATEENTERED_MASK);
548}
549
550/**
551 * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
552 * @pwrdm: struct powerdomain * to set
553 * @pwrst: one of the PWRDM_POWER_* macros
554 *
555 * Set the next power state that the logic portion of the powerdomain
556 * pwrdm will enter when the powerdomain enters retention. This will
557 * be either RETENTION or OFF, if supported. Returns -EINVAL if the
558 * powerdomain pointer is null or the target power state is not not
559 * supported, or returns 0 upon success.
560 */
561int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
562{
563 if (!pwrdm)
564 return -EINVAL;
565
566 if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
567 return -EINVAL;
568
569 pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
570 pwrdm->name, pwrst);
571
572 /*
573 * The register bit names below may not correspond to the
574 * actual names of the bits in each powerdomain's register,
575 * but the type of value returned is the same for each
576 * powerdomain.
577 */
578 prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE,
579 (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)),
580 pwrdm->prcm_offs, PM_PWSTCTRL);
581
582 return 0;
583}
584
585/**
586 * pwrdm_set_mem_onst - set memory power state while powerdomain ON
587 * @pwrdm: struct powerdomain * to set
588 * @bank: memory bank number to set (0-3)
589 * @pwrst: one of the PWRDM_POWER_* macros
590 *
591 * Set the next power state that memory bank x of the powerdomain
592 * pwrdm will enter when the powerdomain enters the ON state. Bank
593 * will be a number from 0 to 3, and represents different types of
594 * memory, depending on the powerdomain. Returns -EINVAL if the
595 * powerdomain pointer is null or the target power state is not not
596 * supported for this memory bank, -EEXIST if the target memory bank
597 * does not exist or is not controllable, or returns 0 upon success.
598 */
599int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
600{
601 u32 m;
602
603 if (!pwrdm)
604 return -EINVAL;
605
606 if (pwrdm->banks < (bank + 1))
607 return -EEXIST;
608
609 if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
610 return -EINVAL;
611
612 pr_debug("powerdomain: setting next memory powerstate for domain %s "
613 "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
614
615 /*
616 * The register bit names below may not correspond to the
617 * actual names of the bits in each powerdomain's register,
618 * but the type of value returned is the same for each
619 * powerdomain.
620 */
621 switch (bank) {
622 case 0:
623 m = OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK;
624 break;
625 case 1:
626 m = OMAP3430_L1FLATMEMONSTATE_MASK;
627 break;
628 case 2:
629 m = OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK;
630 break;
631 case 3:
632 m = OMAP3430_L2FLATMEMONSTATE_MASK;
633 break;
634 default:
635 WARN_ON(1); /* should never happen */
636 return -EEXIST;
637 }
638
639 prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
640 pwrdm->prcm_offs, PM_PWSTCTRL);
641
642 return 0;
643}
644
645/**
646 * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
647 * @pwrdm: struct powerdomain * to set
648 * @bank: memory bank number to set (0-3)
649 * @pwrst: one of the PWRDM_POWER_* macros
650 *
651 * Set the next power state that memory bank x of the powerdomain
652 * pwrdm will enter when the powerdomain enters the RETENTION state.
653 * Bank will be a number from 0 to 3, and represents different types
654 * of memory, depending on the powerdomain. pwrst will be either
655 * RETENTION or OFF, if supported. Returns -EINVAL if the powerdomain
656 * pointer is null or the target power state is not not supported for
657 * this memory bank, -EEXIST if the target memory bank does not exist
658 * or is not controllable, or returns 0 upon success.
659 */
660int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
661{
662 u32 m;
663
664 if (!pwrdm)
665 return -EINVAL;
666
667 if (pwrdm->banks < (bank + 1))
668 return -EEXIST;
669
670 if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
671 return -EINVAL;
672
673 pr_debug("powerdomain: setting next memory powerstate for domain %s "
674 "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
675
676 /*
677 * The register bit names below may not correspond to the
678 * actual names of the bits in each powerdomain's register,
679 * but the type of value returned is the same for each
680 * powerdomain.
681 */
682 switch (bank) {
683 case 0:
684 m = OMAP3430_SHAREDL1CACHEFLATRETSTATE;
685 break;
686 case 1:
687 m = OMAP3430_L1FLATMEMRETSTATE;
688 break;
689 case 2:
690 m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
691 break;
692 case 3:
693 m = OMAP3430_L2FLATMEMRETSTATE;
694 break;
695 default:
696 WARN_ON(1); /* should never happen */
697 return -EEXIST;
698 }
699
700 prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
701 PM_PWSTCTRL);
702
703 return 0;
704}
705
706/**
707 * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
708 * @pwrdm: struct powerdomain * to get current logic retention power state
709 *
710 * Return the current power state that the logic portion of
711 * powerdomain pwrdm will enter
712 * Returns -EINVAL if the powerdomain pointer is null or returns the
713 * current logic retention power state upon success.
714 */
715int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
716{
717 if (!pwrdm)
718 return -EINVAL;
719
720 return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
721 OMAP3430_LOGICSTATEST);
722}
723
724/**
725 * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
726 * @pwrdm: struct powerdomain * to get previous logic power state
727 *
728 * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
729 * if the powerdomain pointer is null or returns the previous logic
730 * power state upon success.
731 */
732int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
733{
734 if (!pwrdm)
735 return -EINVAL;
736
737 /*
738 * The register bit names below may not correspond to the
739 * actual names of the bits in each powerdomain's register,
740 * but the type of value returned is the same for each
741 * powerdomain.
742 */
743 return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
744 OMAP3430_LASTLOGICSTATEENTERED);
745}
746
747/**
748 * pwrdm_read_mem_pwrst - get current memory bank power state
749 * @pwrdm: struct powerdomain * to get current memory bank power state
750 * @bank: memory bank number (0-3)
751 *
752 * Return the powerdomain pwrdm's current memory power state for bank
753 * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
754 * the target memory bank does not exist or is not controllable, or
755 * returns the current memory power state upon success.
756 */
757int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
758{
759 u32 m;
760
761 if (!pwrdm)
762 return -EINVAL;
763
764 if (pwrdm->banks < (bank + 1))
765 return -EEXIST;
766
767 /*
768 * The register bit names below may not correspond to the
769 * actual names of the bits in each powerdomain's register,
770 * but the type of value returned is the same for each
771 * powerdomain.
772 */
773 switch (bank) {
774 case 0:
775 m = OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK;
776 break;
777 case 1:
778 m = OMAP3430_L1FLATMEMSTATEST_MASK;
779 break;
780 case 2:
781 m = OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK;
782 break;
783 case 3:
784 m = OMAP3430_L2FLATMEMSTATEST_MASK;
785 break;
786 default:
787 WARN_ON(1); /* should never happen */
788 return -EEXIST;
789 }
790
791 return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, m);
792}
793
794/**
795 * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
796 * @pwrdm: struct powerdomain * to get previous memory bank power state
797 * @bank: memory bank number (0-3)
798 *
799 * Return the powerdomain pwrdm's previous memory power state for bank
800 * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
801 * the target memory bank does not exist or is not controllable, or
802 * returns the previous memory power state upon success.
803 */
804int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
805{
806 u32 m;
807
808 if (!pwrdm)
809 return -EINVAL;
810
811 if (pwrdm->banks < (bank + 1))
812 return -EEXIST;
813
814 /*
815 * The register bit names below may not correspond to the
816 * actual names of the bits in each powerdomain's register,
817 * but the type of value returned is the same for each
818 * powerdomain.
819 */
820 switch (bank) {
821 case 0:
822 m = OMAP3430_LASTMEM1STATEENTERED_MASK;
823 break;
824 case 1:
825 m = OMAP3430_LASTMEM2STATEENTERED_MASK;
826 break;
827 case 2:
828 m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
829 break;
830 case 3:
831 m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
832 break;
833 default:
834 WARN_ON(1); /* should never happen */
835 return -EEXIST;
836 }
837
838 return prm_read_mod_bits_shift(pwrdm->prcm_offs,
839 OMAP3430_PM_PREPWSTST, m);
840}
841
842/**
843 * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
844 * @pwrdm: struct powerdomain * to clear
845 *
846 * Clear the powerdomain's previous power state register. Clears the
847 * entire register, including logic and memory bank previous power states.
848 * Returns -EINVAL if the powerdomain pointer is null, or returns 0 upon
849 * success.
850 */
851int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
852{
853 if (!pwrdm)
854 return -EINVAL;
855
856 /*
857 * XXX should get the powerdomain's current state here;
858 * warn & fail if it is not ON.
859 */
860
861 pr_debug("powerdomain: clearing previous power state reg for %s\n",
862 pwrdm->name);
863
864 prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
865
866 return 0;
867}
868
869/**
870 * pwrdm_wait_transition - wait for powerdomain power transition to finish
871 * @pwrdm: struct powerdomain * to wait for
872 *
873 * If the powerdomain pwrdm is in the process of a state transition,
874 * spin until it completes the power transition, or until an iteration
875 * bailout value is reached. Returns -EINVAL if the powerdomain
876 * pointer is null, -EAGAIN if the bailout value was reached, or
877 * returns 0 upon success.
878 */
879int pwrdm_wait_transition(struct powerdomain *pwrdm)
880{
881 u32 c = 0;
882
883 if (!pwrdm)
884 return -EINVAL;
885
886 /*
887 * REVISIT: pwrdm_wait_transition() may be better implemented
888 * via a callback and a periodic timer check -- how long do we expect
889 * powerdomain transitions to take?
890 */
891
892 /* XXX Is this udelay() value meaningful? */
893 while ((prm_read_mod_reg(pwrdm->prcm_offs, PM_PWSTST) &
894 OMAP_INTRANSITION) &&
895 (c++ < PWRDM_TRANSITION_BAILOUT))
896 udelay(1);
897
898 if (c >= PWRDM_TRANSITION_BAILOUT) {
899 printk(KERN_ERR "powerdomain: waited too long for "
900 "powerdomain %s to complete transition\n", pwrdm->name);
901 return -EAGAIN;
902 }
903
904 pr_debug("powerdomain: completed transition in %d loops\n", c);
905
906 return 0;
907}
908
909
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index b917206ee906..e815fa35f7f4 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -29,6 +29,18 @@ config OMAP_DEBUG_LEDS
29 depends on OMAP_DEBUG_DEVICES 29 depends on OMAP_DEBUG_DEVICES
30 default y if LEDS || LEDS_OMAP_DEBUG 30 default y if LEDS || LEDS_OMAP_DEBUG
31 31
32config OMAP_DEBUG_POWERDOMAIN
33 bool "Emit debug messages from powerdomain layer"
34 depends on ARCH_OMAP2 || ARCH_OMAP3
35 default n
36 help
37 Say Y here if you want to compile in powerdomain layer
38 debugging messages for OMAP2/3. These messages can
39 provide more detail as to why some powerdomain calls
40 may be failing, and will also emit a descriptive message
41 for every powerdomain register write. However, the
42 extra detail costs some memory.
43
32config OMAP_RESET_CLOCKS 44config OMAP_RESET_CLOCKS
33 bool "Reset unused clocks during boot" 45 bool "Reset unused clocks during boot"
34 depends on ARCH_OMAP 46 depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
new file mode 100644
index 000000000000..c8f52c6f8b7e
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/powerdomain.h
@@ -0,0 +1,139 @@
1/*
2 * OMAP2/3 powerdomain control
3 *
4 * Copyright (C) 2007-8 Texas Instruments, Inc.
5 * Copyright (C) 2007-8 Nokia Corporation
6 *
7 * Written by Paul Walmsley
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#ifndef ASM_ARM_ARCH_OMAP_POWERDOMAIN
15#define ASM_ARM_ARCH_OMAP_POWERDOMAIN
16
17#include <linux/types.h>
18#include <linux/list.h>
19
20#include <asm/atomic.h>
21
22#include <mach/cpu.h>
23
24
25/* Powerdomain basic power states */
26#define PWRDM_POWER_OFF 0x0
27#define PWRDM_POWER_RET 0x1
28#define PWRDM_POWER_INACTIVE 0x2
29#define PWRDM_POWER_ON 0x3
30
31/* Powerdomain allowable state bitfields */
32#define PWRSTS_OFF_ON ((1 << PWRDM_POWER_OFF) | \
33 (1 << PWRDM_POWER_ON))
34
35#define PWRSTS_OFF_RET ((1 << PWRDM_POWER_OFF) | \
36 (1 << PWRDM_POWER_RET))
37
38#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
39
40
41/*
42 * Number of memory banks that are power-controllable. On OMAP3430, the
43 * maximum is 4.
44 */
45#define PWRDM_MAX_MEM_BANKS 4
46
47/* XXX A completely arbitrary number. What is reasonable here? */
48#define PWRDM_TRANSITION_BAILOUT 100000
49
50struct powerdomain;
51
52/* Encodes dependencies between powerdomains - statically defined */
53struct pwrdm_dep {
54
55 /* Powerdomain name */
56 const char *pwrdm_name;
57
58 /* Powerdomain pointer - resolved by the powerdomain code */
59 struct powerdomain *pwrdm;
60
61 /* Flags to mark OMAP chip restrictions, etc. */
62 const struct omap_chip_id omap_chip;
63
64};
65
66struct powerdomain {
67
68 /* Powerdomain name */
69 const char *name;
70
71 /* the address offset from CM_BASE/PRM_BASE */
72 const s16 prcm_offs;
73
74 /* Used to represent the OMAP chip types containing this pwrdm */
75 const struct omap_chip_id omap_chip;
76
77 /* Bit shift of this powerdomain's PM_WKDEP/CM_SLEEPDEP bit */
78 const u8 dep_bit;
79
80 /* Powerdomains that can be told to wake this powerdomain up */
81 struct pwrdm_dep *wkdep_srcs;
82
83 /* Powerdomains that can be told to keep this pwrdm from inactivity */
84 struct pwrdm_dep *sleepdep_srcs;
85
86 /* Possible powerdomain power states */
87 const u8 pwrsts;
88
89 /* Possible logic power states when pwrdm in RETENTION */
90 const u8 pwrsts_logic_ret;
91
92 /* Number of software-controllable memory banks in this powerdomain */
93 const u8 banks;
94
95 /* Possible memory bank pwrstates when pwrdm in RETENTION */
96 const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
97
98 /* Possible memory bank pwrstates when pwrdm is ON */
99 const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
100
101 struct list_head node;
102
103};
104
105
106void pwrdm_init(struct powerdomain **pwrdm_list);
107
108int pwrdm_register(struct powerdomain *pwrdm);
109int pwrdm_unregister(struct powerdomain *pwrdm);
110struct powerdomain *pwrdm_lookup(const char *name);
111
112int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm));
113
114int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
115int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
116int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
117int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
118int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
119int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
120
121int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
122
123int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
124int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
125int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
126int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
127
128int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
129int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
130int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
131
132int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
133int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
134int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
135int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
136
137int pwrdm_wait_transition(struct powerdomain *pwrdm);
138
139#endif