blob: 411361f97eda6d336cbce5ef56b737eb8ca09f40 [file] [log] [blame]
Paul Walmsleyad67ef62008-08-19 11:08:40 +03001/*
2 * OMAP powerdomain control
3 *
4 * Copyright (C) 2007-2008 Texas Instruments, Inc.
Paul Walmsley55ed9692010-01-26 20:12:59 -07005 * Copyright (C) 2007-2009 Nokia Corporation
Paul Walmsleyad67ef62008-08-19 11:08:40 +03006 *
7 * Written by Paul Walmsley
8 *
Abhijit Pagare3a759f02010-01-26 20:12:53 -07009 * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
10 *
Paul Walmsleyad67ef62008-08-19 11:08:40 +030011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
Paul Walmsley33903eb2009-12-08 16:33:10 -070015#undef DEBUG
Paul Walmsleyad67ef62008-08-19 11:08:40 +030016
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"
Abhijit Pagare3a759f02010-01-26 20:12:53 -070031#include "cm-regbits-44xx.h"
Paul Walmsleyad67ef62008-08-19 11:08:40 +030032#include "prm.h"
33#include "prm-regbits-34xx.h"
Abhijit Pagare3a759f02010-01-26 20:12:53 -070034#include "prm-regbits-44xx.h"
Paul Walmsleyad67ef62008-08-19 11:08:40 +030035
Tony Lindgrence491cf2009-10-20 09:40:47 -070036#include <plat/cpu.h>
37#include <plat/powerdomain.h>
38#include <plat/clockdomain.h>
Paul Walmsley55ed9692010-01-26 20:12:59 -070039#include <plat/prcm.h>
Paul Walmsleyad67ef62008-08-19 11:08:40 +030040
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +030041#include "pm.h"
42
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +030043enum {
44 PWRDM_STATE_NOW = 0,
45 PWRDM_STATE_PREV,
46};
47
Abhijit Pagare3a759f02010-01-26 20:12:53 -070048/* Variable holding value of the CPU dependent PWRSTCTRL Register Offset */
49static u16 pwrstctrl_reg_offs;
50
51/* Variable holding value of the CPU dependent PWRSTST Register Offset */
52static u16 pwrstst_reg_offs;
53
54/* OMAP3 and OMAP4 specific register bit initialisations
55 * Notice that the names here are not according to each power
56 * domain but the bit mapping used applies to all of them
57 */
58
59/* OMAP3 and OMAP4 Memory Onstate Masks (common across all power domains) */
60#define OMAP_MEM0_ONSTATE_MASK OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK
61#define OMAP_MEM1_ONSTATE_MASK OMAP3430_L1FLATMEMONSTATE_MASK
62#define OMAP_MEM2_ONSTATE_MASK OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK
63#define OMAP_MEM3_ONSTATE_MASK OMAP3430_L2FLATMEMONSTATE_MASK
64#define OMAP_MEM4_ONSTATE_MASK OMAP4430_OCP_NRET_BANK_ONSTATE_MASK
65
66/* OMAP3 and OMAP4 Memory Retstate Masks (common across all power domains) */
67#define OMAP_MEM0_RETSTATE_MASK OMAP3430_SHAREDL1CACHEFLATRETSTATE
68#define OMAP_MEM1_RETSTATE_MASK OMAP3430_L1FLATMEMRETSTATE
69#define OMAP_MEM2_RETSTATE_MASK OMAP3430_SHAREDL2CACHEFLATRETSTATE
70#define OMAP_MEM3_RETSTATE_MASK OMAP3430_L2FLATMEMRETSTATE
71#define OMAP_MEM4_RETSTATE_MASK OMAP4430_OCP_NRET_BANK_RETSTATE_MASK
72
73/* OMAP3 and OMAP4 Memory Status bits */
74#define OMAP_MEM0_STATEST_MASK OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK
75#define OMAP_MEM1_STATEST_MASK OMAP3430_L1FLATMEMSTATEST_MASK
76#define OMAP_MEM2_STATEST_MASK OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK
77#define OMAP_MEM3_STATEST_MASK OMAP3430_L2FLATMEMSTATEST_MASK
78#define OMAP_MEM4_STATEST_MASK OMAP4430_OCP_NRET_BANK_STATEST_MASK
79
Paul Walmsleyad67ef62008-08-19 11:08:40 +030080/* pwrdm_list contains all registered struct powerdomains */
81static LIST_HEAD(pwrdm_list);
82
Paul Walmsleyad67ef62008-08-19 11:08:40 +030083/* Private functions */
84
Paul Walmsleyad67ef62008-08-19 11:08:40 +030085static struct powerdomain *_pwrdm_lookup(const char *name)
86{
87 struct powerdomain *pwrdm, *temp_pwrdm;
88
89 pwrdm = NULL;
90
91 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
92 if (!strcmp(name, temp_pwrdm->name)) {
93 pwrdm = temp_pwrdm;
94 break;
95 }
96 }
97
98 return pwrdm;
99}
100
Paul Walmsleye909d622010-01-26 20:13:00 -0700101/**
102 * _pwrdm_register - register a powerdomain
103 * @pwrdm: struct powerdomain * to register
104 *
105 * Adds a powerdomain to the internal powerdomain list. Returns
106 * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
107 * already registered by the provided name, or 0 upon success.
108 */
109static int _pwrdm_register(struct powerdomain *pwrdm)
110{
111 int i;
112
113 if (!pwrdm)
114 return -EINVAL;
115
116 if (!omap_chip_is(pwrdm->omap_chip))
117 return -EINVAL;
118
119 if (_pwrdm_lookup(pwrdm->name))
120 return -EEXIST;
121
122 list_add(&pwrdm->node, &pwrdm_list);
123
124 /* Initialize the powerdomain's state counter */
125 for (i = 0; i < 4; i++)
126 pwrdm->state_counter[i] = 0;
127
128 pwrdm_wait_transition(pwrdm);
129 pwrdm->state = pwrdm_read_pwrst(pwrdm);
130 pwrdm->state_counter[pwrdm->state] = 1;
131
132 pr_debug("powerdomain: registered %s\n", pwrdm->name);
133
134 return 0;
135}
136
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300137static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
138{
139
140 int prev;
141 int state;
142
143 if (pwrdm == NULL)
144 return -EINVAL;
145
146 state = pwrdm_read_pwrst(pwrdm);
147
148 switch (flag) {
149 case PWRDM_STATE_NOW:
150 prev = pwrdm->state;
151 break;
152 case PWRDM_STATE_PREV:
153 prev = pwrdm_read_prev_pwrst(pwrdm);
154 if (pwrdm->state != prev)
155 pwrdm->state_counter[prev]++;
156 break;
157 default:
158 return -EINVAL;
159 }
160
161 if (state != prev)
162 pwrdm->state_counter[state]++;
163
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +0300164 pm_dbg_update_time(pwrdm, prev);
165
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300166 pwrdm->state = state;
167
168 return 0;
169}
170
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +0300171static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300172{
173 pwrdm_clear_all_prev_pwrst(pwrdm);
174 _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
175 return 0;
176}
177
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +0300178static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300179{
180 _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
181 return 0;
182}
183
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300184/* Public functions */
185
186/**
187 * pwrdm_init - set up the powerdomain layer
188 *
189 * Loop through the list of powerdomains, registering all that are
190 * available on the current CPU. If pwrdm_list is supplied and not
191 * null, all of the referenced powerdomains will be registered. No
192 * return value.
193 */
194void pwrdm_init(struct powerdomain **pwrdm_list)
195{
196 struct powerdomain **p = NULL;
197
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700198 if (cpu_is_omap24xx() | cpu_is_omap34xx()) {
199 pwrstctrl_reg_offs = OMAP2_PM_PWSTCTRL;
200 pwrstst_reg_offs = OMAP2_PM_PWSTST;
201 } else if (cpu_is_omap44xx()) {
202 pwrstctrl_reg_offs = OMAP4_PM_PWSTCTRL;
203 pwrstst_reg_offs = OMAP4_PM_PWSTST;
204 } else {
205 printk(KERN_ERR "Power Domain struct not supported for " \
206 "this CPU\n");
207 return;
208 }
209
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300210 if (pwrdm_list) {
Paul Walmsleye909d622010-01-26 20:13:00 -0700211 for (p = pwrdm_list; *p; p++)
212 _pwrdm_register(*p);
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300213 }
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300214}
215
216/**
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300217 * pwrdm_lookup - look up a powerdomain by name, return a pointer
218 * @name: name of powerdomain
219 *
220 * Find a registered powerdomain by its name. Returns a pointer to the
221 * struct powerdomain if found, or NULL otherwise.
222 */
223struct powerdomain *pwrdm_lookup(const char *name)
224{
225 struct powerdomain *pwrdm;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300226
227 if (!name)
228 return NULL;
229
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300230 pwrdm = _pwrdm_lookup(name);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300231
232 return pwrdm;
233}
234
235/**
Paul Walmsleye909d622010-01-26 20:13:00 -0700236 * pwrdm_for_each - call function on each registered clockdomain
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300237 * @fn: callback function *
238 *
239 * Call the supplied function for each registered powerdomain. The
240 * callback function can return anything but 0 to bail out early from
Artem Bityutskiyee894b12009-10-01 10:01:55 +0300241 * the iterator. Returns the last return value of the callback function, which
242 * should be 0 for success or anything else to indicate failure; or -EINVAL if
243 * the function pointer is null.
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300244 */
Paul Walmsleye909d622010-01-26 20:13:00 -0700245int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
246 void *user)
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300247{
248 struct powerdomain *temp_pwrdm;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300249 int ret = 0;
250
251 if (!fn)
252 return -EINVAL;
253
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300254 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +0300255 ret = (*fn)(temp_pwrdm, user);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300256 if (ret)
257 break;
258 }
Artem Bityutskiyee894b12009-10-01 10:01:55 +0300259
260 return ret;
261}
262
263/**
Paul Walmsley8420bb12008-08-19 11:08:44 +0300264 * pwrdm_add_clkdm - add a clockdomain to a powerdomain
265 * @pwrdm: struct powerdomain * to add the clockdomain to
266 * @clkdm: struct clockdomain * to associate with a powerdomain
267 *
268 * Associate the clockdomain 'clkdm' with a powerdomain 'pwrdm'. This
269 * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if
270 * presented with invalid pointers; -ENOMEM if memory could not be allocated;
271 * or 0 upon success.
272 */
273int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
274{
Paul Walmsley8420bb12008-08-19 11:08:44 +0300275 int i;
276 int ret = -EINVAL;
277
278 if (!pwrdm || !clkdm)
279 return -EINVAL;
280
281 pr_debug("powerdomain: associating clockdomain %s with powerdomain "
282 "%s\n", clkdm->name, pwrdm->name);
283
Paul Walmsley8420bb12008-08-19 11:08:44 +0300284 for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
285 if (!pwrdm->pwrdm_clkdms[i])
286 break;
287#ifdef DEBUG
288 if (pwrdm->pwrdm_clkdms[i] == clkdm) {
289 ret = -EINVAL;
290 goto pac_exit;
291 }
292#endif
293 }
294
295 if (i == PWRDM_MAX_CLKDMS) {
296 pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
297 "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
298 WARN_ON(1);
299 ret = -ENOMEM;
300 goto pac_exit;
301 }
302
303 pwrdm->pwrdm_clkdms[i] = clkdm;
304
305 ret = 0;
306
307pac_exit:
Paul Walmsley8420bb12008-08-19 11:08:44 +0300308 return ret;
309}
310
311/**
312 * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
313 * @pwrdm: struct powerdomain * to add the clockdomain to
314 * @clkdm: struct clockdomain * to associate with a powerdomain
315 *
316 * Dissociate the clockdomain 'clkdm' from the powerdomain
317 * 'pwrdm'. Returns -EINVAL if presented with invalid pointers;
318 * -ENOENT if the clkdm was not associated with the powerdomain, or 0
319 * upon success.
320 */
321int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
322{
Paul Walmsley8420bb12008-08-19 11:08:44 +0300323 int ret = -EINVAL;
324 int i;
325
326 if (!pwrdm || !clkdm)
327 return -EINVAL;
328
329 pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
330 "%s\n", clkdm->name, pwrdm->name);
331
Paul Walmsley8420bb12008-08-19 11:08:44 +0300332 for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
333 if (pwrdm->pwrdm_clkdms[i] == clkdm)
334 break;
335
336 if (i == PWRDM_MAX_CLKDMS) {
337 pr_debug("powerdomain: clkdm %s not associated with pwrdm "
338 "%s ?!\n", clkdm->name, pwrdm->name);
339 ret = -ENOENT;
340 goto pdc_exit;
341 }
342
343 pwrdm->pwrdm_clkdms[i] = NULL;
344
345 ret = 0;
346
347pdc_exit:
Paul Walmsley8420bb12008-08-19 11:08:44 +0300348 return ret;
349}
350
351/**
352 * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
353 * @pwrdm: struct powerdomain * to iterate over
354 * @fn: callback function *
355 *
356 * Call the supplied function for each clockdomain in the powerdomain
357 * 'pwrdm'. The callback function can return anything but 0 to bail
Paul Walmsleye909d622010-01-26 20:13:00 -0700358 * out early from the iterator. Returns -EINVAL if presented with
359 * invalid pointers; or passes along the last return value of the
360 * callback function, which should be 0 for success or anything else
361 * to indicate failure.
Paul Walmsley8420bb12008-08-19 11:08:44 +0300362 */
363int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
364 int (*fn)(struct powerdomain *pwrdm,
365 struct clockdomain *clkdm))
366{
Paul Walmsley8420bb12008-08-19 11:08:44 +0300367 int ret = 0;
368 int i;
369
370 if (!fn)
371 return -EINVAL;
372
Paul Walmsley8420bb12008-08-19 11:08:44 +0300373 for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
374 ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
375
Paul Walmsley8420bb12008-08-19 11:08:44 +0300376 return ret;
377}
378
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300379/**
380 * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
381 * @pwrdm: struct powerdomain *
382 *
383 * Return the number of controllable memory banks in powerdomain pwrdm,
384 * starting with 1. Returns -EINVAL if the powerdomain pointer is null.
385 */
386int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
387{
388 if (!pwrdm)
389 return -EINVAL;
390
391 return pwrdm->banks;
392}
393
394/**
395 * pwrdm_set_next_pwrst - set next powerdomain power state
396 * @pwrdm: struct powerdomain * to set
397 * @pwrst: one of the PWRDM_POWER_* macros
398 *
399 * Set the powerdomain pwrdm's next power state to pwrst. The powerdomain
400 * may not enter this state immediately if the preconditions for this state
401 * have not been satisfied. Returns -EINVAL if the powerdomain pointer is
402 * null or if the power state is invalid for the powerdomin, or returns 0
403 * upon success.
404 */
405int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
406{
407 if (!pwrdm)
408 return -EINVAL;
409
410 if (!(pwrdm->pwrsts & (1 << pwrst)))
411 return -EINVAL;
412
413 pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
414 pwrdm->name, pwrst);
415
416 prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
417 (pwrst << OMAP_POWERSTATE_SHIFT),
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700418 pwrdm->prcm_offs, pwrstctrl_reg_offs);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300419
420 return 0;
421}
422
423/**
424 * pwrdm_read_next_pwrst - get next powerdomain power state
425 * @pwrdm: struct powerdomain * to get power state
426 *
427 * Return the powerdomain pwrdm's next power state. Returns -EINVAL
428 * if the powerdomain pointer is null or returns the next power state
429 * upon success.
430 */
431int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
432{
433 if (!pwrdm)
434 return -EINVAL;
435
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700436 return prm_read_mod_bits_shift(pwrdm->prcm_offs,
437 pwrstctrl_reg_offs, OMAP_POWERSTATE_MASK);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300438}
439
440/**
441 * pwrdm_read_pwrst - get current powerdomain power state
442 * @pwrdm: struct powerdomain * to get power state
443 *
444 * Return the powerdomain pwrdm's current power state. Returns -EINVAL
445 * if the powerdomain pointer is null or returns the current power state
446 * upon success.
447 */
448int pwrdm_read_pwrst(struct powerdomain *pwrdm)
449{
450 if (!pwrdm)
451 return -EINVAL;
452
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700453 return prm_read_mod_bits_shift(pwrdm->prcm_offs,
454 pwrstst_reg_offs, OMAP_POWERSTATEST_MASK);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300455}
456
457/**
458 * pwrdm_read_prev_pwrst - get previous powerdomain power state
459 * @pwrdm: struct powerdomain * to get previous power state
460 *
461 * Return the powerdomain pwrdm's previous power state. Returns -EINVAL
462 * if the powerdomain pointer is null or returns the previous power state
463 * upon success.
464 */
465int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
466{
467 if (!pwrdm)
468 return -EINVAL;
469
470 return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
471 OMAP3430_LASTPOWERSTATEENTERED_MASK);
472}
473
474/**
475 * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
476 * @pwrdm: struct powerdomain * to set
477 * @pwrst: one of the PWRDM_POWER_* macros
478 *
479 * Set the next power state that the logic portion of the powerdomain
480 * pwrdm will enter when the powerdomain enters retention. This will
481 * be either RETENTION or OFF, if supported. Returns -EINVAL if the
482 * powerdomain pointer is null or the target power state is not not
483 * supported, or returns 0 upon success.
484 */
485int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
486{
487 if (!pwrdm)
488 return -EINVAL;
489
490 if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
491 return -EINVAL;
492
493 pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
494 pwrdm->name, pwrst);
495
496 /*
497 * The register bit names below may not correspond to the
498 * actual names of the bits in each powerdomain's register,
499 * but the type of value returned is the same for each
500 * powerdomain.
501 */
502 prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE,
503 (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)),
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700504 pwrdm->prcm_offs, pwrstctrl_reg_offs);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300505
506 return 0;
507}
508
509/**
510 * pwrdm_set_mem_onst - set memory power state while powerdomain ON
511 * @pwrdm: struct powerdomain * to set
512 * @bank: memory bank number to set (0-3)
513 * @pwrst: one of the PWRDM_POWER_* macros
514 *
515 * Set the next power state that memory bank x of the powerdomain
516 * pwrdm will enter when the powerdomain enters the ON state. Bank
517 * will be a number from 0 to 3, and represents different types of
518 * memory, depending on the powerdomain. Returns -EINVAL if the
519 * powerdomain pointer is null or the target power state is not not
520 * supported for this memory bank, -EEXIST if the target memory bank
521 * does not exist or is not controllable, or returns 0 upon success.
522 */
523int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
524{
525 u32 m;
526
527 if (!pwrdm)
528 return -EINVAL;
529
530 if (pwrdm->banks < (bank + 1))
531 return -EEXIST;
532
533 if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
534 return -EINVAL;
535
536 pr_debug("powerdomain: setting next memory powerstate for domain %s "
537 "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
538
539 /*
540 * The register bit names below may not correspond to the
541 * actual names of the bits in each powerdomain's register,
542 * but the type of value returned is the same for each
543 * powerdomain.
544 */
545 switch (bank) {
546 case 0:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700547 m = OMAP_MEM0_ONSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300548 break;
549 case 1:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700550 m = OMAP_MEM1_ONSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300551 break;
552 case 2:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700553 m = OMAP_MEM2_ONSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300554 break;
555 case 3:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700556 m = OMAP_MEM3_ONSTATE_MASK;
557 break;
558 case 4:
559 m = OMAP_MEM4_ONSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300560 break;
561 default:
562 WARN_ON(1); /* should never happen */
563 return -EEXIST;
564 }
565
566 prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700567 pwrdm->prcm_offs, pwrstctrl_reg_offs);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300568
569 return 0;
570}
571
572/**
573 * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
574 * @pwrdm: struct powerdomain * to set
575 * @bank: memory bank number to set (0-3)
576 * @pwrst: one of the PWRDM_POWER_* macros
577 *
578 * Set the next power state that memory bank x of the powerdomain
579 * pwrdm will enter when the powerdomain enters the RETENTION state.
580 * Bank will be a number from 0 to 3, and represents different types
581 * of memory, depending on the powerdomain. pwrst will be either
582 * RETENTION or OFF, if supported. Returns -EINVAL if the powerdomain
583 * pointer is null or the target power state is not not supported for
584 * this memory bank, -EEXIST if the target memory bank does not exist
585 * or is not controllable, or returns 0 upon success.
586 */
587int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
588{
589 u32 m;
590
591 if (!pwrdm)
592 return -EINVAL;
593
594 if (pwrdm->banks < (bank + 1))
595 return -EEXIST;
596
597 if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
598 return -EINVAL;
599
600 pr_debug("powerdomain: setting next memory powerstate for domain %s "
601 "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
602
603 /*
604 * The register bit names below may not correspond to the
605 * actual names of the bits in each powerdomain's register,
606 * but the type of value returned is the same for each
607 * powerdomain.
608 */
609 switch (bank) {
610 case 0:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700611 m = OMAP_MEM0_RETSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300612 break;
613 case 1:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700614 m = OMAP_MEM1_RETSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300615 break;
616 case 2:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700617 m = OMAP_MEM2_RETSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300618 break;
619 case 3:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700620 m = OMAP_MEM3_RETSTATE_MASK;
621 break;
622 case 4:
623 m = OMAP_MEM4_RETSTATE_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300624 break;
625 default:
626 WARN_ON(1); /* should never happen */
627 return -EEXIST;
628 }
629
630 prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700631 pwrstctrl_reg_offs);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300632
633 return 0;
634}
635
636/**
637 * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
638 * @pwrdm: struct powerdomain * to get current logic retention power state
639 *
640 * Return the current power state that the logic portion of
641 * powerdomain pwrdm will enter
642 * Returns -EINVAL if the powerdomain pointer is null or returns the
643 * current logic retention power state upon success.
644 */
645int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
646{
647 if (!pwrdm)
648 return -EINVAL;
649
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700650 return prm_read_mod_bits_shift(pwrdm->prcm_offs,
651 pwrstst_reg_offs, OMAP3430_LOGICSTATEST);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300652}
653
654/**
655 * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
656 * @pwrdm: struct powerdomain * to get previous logic power state
657 *
658 * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
659 * if the powerdomain pointer is null or returns the previous logic
660 * power state upon success.
661 */
662int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
663{
664 if (!pwrdm)
665 return -EINVAL;
666
667 /*
668 * The register bit names below may not correspond to the
669 * actual names of the bits in each powerdomain's register,
670 * but the type of value returned is the same for each
671 * powerdomain.
672 */
673 return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
674 OMAP3430_LASTLOGICSTATEENTERED);
675}
676
677/**
678 * pwrdm_read_mem_pwrst - get current memory bank power state
679 * @pwrdm: struct powerdomain * to get current memory bank power state
680 * @bank: memory bank number (0-3)
681 *
682 * Return the powerdomain pwrdm's current memory power state for bank
683 * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
684 * the target memory bank does not exist or is not controllable, or
685 * returns the current memory power state upon success.
686 */
687int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
688{
689 u32 m;
690
691 if (!pwrdm)
692 return -EINVAL;
693
694 if (pwrdm->banks < (bank + 1))
695 return -EEXIST;
696
Thara Gopinath3863c742009-12-08 16:33:15 -0700697 if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
698 bank = 1;
699
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300700 /*
701 * The register bit names below may not correspond to the
702 * actual names of the bits in each powerdomain's register,
703 * but the type of value returned is the same for each
704 * powerdomain.
705 */
706 switch (bank) {
707 case 0:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700708 m = OMAP_MEM0_STATEST_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300709 break;
710 case 1:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700711 m = OMAP_MEM1_STATEST_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300712 break;
713 case 2:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700714 m = OMAP_MEM2_STATEST_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300715 break;
716 case 3:
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700717 m = OMAP_MEM3_STATEST_MASK;
718 break;
719 case 4:
720 m = OMAP_MEM4_STATEST_MASK;
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300721 break;
722 default:
723 WARN_ON(1); /* should never happen */
724 return -EEXIST;
725 }
726
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700727 return prm_read_mod_bits_shift(pwrdm->prcm_offs,
728 pwrstst_reg_offs, m);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300729}
730
731/**
732 * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
733 * @pwrdm: struct powerdomain * to get previous memory bank power state
734 * @bank: memory bank number (0-3)
735 *
736 * Return the powerdomain pwrdm's previous memory power state for bank
737 * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
738 * the target memory bank does not exist or is not controllable, or
739 * returns the previous memory power state upon success.
740 */
741int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
742{
743 u32 m;
744
745 if (!pwrdm)
746 return -EINVAL;
747
748 if (pwrdm->banks < (bank + 1))
749 return -EEXIST;
750
Thara Gopinath3863c742009-12-08 16:33:15 -0700751 if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
752 bank = 1;
753
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300754 /*
755 * The register bit names below may not correspond to the
756 * actual names of the bits in each powerdomain's register,
757 * but the type of value returned is the same for each
758 * powerdomain.
759 */
760 switch (bank) {
761 case 0:
762 m = OMAP3430_LASTMEM1STATEENTERED_MASK;
763 break;
764 case 1:
765 m = OMAP3430_LASTMEM2STATEENTERED_MASK;
766 break;
767 case 2:
768 m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
769 break;
770 case 3:
771 m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
772 break;
773 default:
774 WARN_ON(1); /* should never happen */
775 return -EEXIST;
776 }
777
778 return prm_read_mod_bits_shift(pwrdm->prcm_offs,
779 OMAP3430_PM_PREPWSTST, m);
780}
781
782/**
783 * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
784 * @pwrdm: struct powerdomain * to clear
785 *
786 * Clear the powerdomain's previous power state register. Clears the
787 * entire register, including logic and memory bank previous power states.
788 * Returns -EINVAL if the powerdomain pointer is null, or returns 0 upon
789 * success.
790 */
791int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
792{
793 if (!pwrdm)
794 return -EINVAL;
795
796 /*
797 * XXX should get the powerdomain's current state here;
798 * warn & fail if it is not ON.
799 */
800
801 pr_debug("powerdomain: clearing previous power state reg for %s\n",
802 pwrdm->name);
803
804 prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
805
806 return 0;
807}
808
809/**
Paul Walmsley0b7cbfb2008-06-25 18:09:37 -0600810 * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
811 * @pwrdm: struct powerdomain *
812 *
813 * Enable automatic context save-and-restore upon power state change
814 * for some devices in a powerdomain. Warning: this only affects a
815 * subset of devices in a powerdomain; check the TRM closely. Returns
816 * -EINVAL if the powerdomain pointer is null or if the powerdomain
817 * does not support automatic save-and-restore, or returns 0 upon
818 * success.
819 */
820int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
821{
822 if (!pwrdm)
823 return -EINVAL;
824
825 if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
826 return -EINVAL;
827
828 pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
829 pwrdm->name);
830
831 prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700832 pwrdm->prcm_offs, pwrstctrl_reg_offs);
Paul Walmsley0b7cbfb2008-06-25 18:09:37 -0600833
834 return 0;
835}
836
837/**
838 * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
839 * @pwrdm: struct powerdomain *
840 *
841 * Disable automatic context save-and-restore upon power state change
842 * for some devices in a powerdomain. Warning: this only affects a
843 * subset of devices in a powerdomain; check the TRM closely. Returns
844 * -EINVAL if the powerdomain pointer is null or if the powerdomain
845 * does not support automatic save-and-restore, or returns 0 upon
846 * success.
847 */
848int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
849{
850 if (!pwrdm)
851 return -EINVAL;
852
853 if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
854 return -EINVAL;
855
856 pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
857 pwrdm->name);
858
859 prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0,
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700860 pwrdm->prcm_offs, pwrstctrl_reg_offs);
Paul Walmsley0b7cbfb2008-06-25 18:09:37 -0600861
862 return 0;
863}
864
865/**
866 * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
867 * @pwrdm: struct powerdomain *
868 *
869 * Returns 1 if powerdomain 'pwrdm' supports hardware save-and-restore
870 * for some devices, or 0 if it does not.
871 */
872bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
873{
874 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
875}
876
877/**
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300878 * pwrdm_wait_transition - wait for powerdomain power transition to finish
879 * @pwrdm: struct powerdomain * to wait for
880 *
881 * If the powerdomain pwrdm is in the process of a state transition,
882 * spin until it completes the power transition, or until an iteration
883 * bailout value is reached. Returns -EINVAL if the powerdomain
884 * pointer is null, -EAGAIN if the bailout value was reached, or
885 * returns 0 upon success.
886 */
887int pwrdm_wait_transition(struct powerdomain *pwrdm)
888{
889 u32 c = 0;
890
891 if (!pwrdm)
892 return -EINVAL;
893
894 /*
895 * REVISIT: pwrdm_wait_transition() may be better implemented
896 * via a callback and a periodic timer check -- how long do we expect
897 * powerdomain transitions to take?
898 */
899
900 /* XXX Is this udelay() value meaningful? */
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700901 while ((prm_read_mod_reg(pwrdm->prcm_offs, pwrstst_reg_offs) &
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300902 OMAP_INTRANSITION) &&
903 (c++ < PWRDM_TRANSITION_BAILOUT))
Abhijit Pagare3a759f02010-01-26 20:12:53 -0700904 udelay(1);
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300905
Roel Kluin26870692009-06-19 19:08:30 -0600906 if (c > PWRDM_TRANSITION_BAILOUT) {
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300907 printk(KERN_ERR "powerdomain: waited too long for "
908 "powerdomain %s to complete transition\n", pwrdm->name);
909 return -EAGAIN;
910 }
911
912 pr_debug("powerdomain: completed transition in %d loops\n", c);
913
914 return 0;
915}
916
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300917int pwrdm_state_switch(struct powerdomain *pwrdm)
918{
919 return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
920}
921
922int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
923{
924 if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) {
925 pwrdm_wait_transition(clkdm->pwrdm.ptr);
926 return pwrdm_state_switch(clkdm->pwrdm.ptr);
927 }
928
929 return -EINVAL;
930}
931int pwrdm_clk_state_switch(struct clk *clk)
932{
933 if (clk != NULL && clk->clkdm != NULL)
934 return pwrdm_clkdm_state_switch(clk->clkdm);
935 return -EINVAL;
936}
937
938int pwrdm_pre_transition(void)
939{
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +0300940 pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300941 return 0;
942}
943
944int pwrdm_post_transition(void)
945{
Peter 'p2' De Schrijver6199ab22008-10-15 18:13:49 +0300946 pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
Peter 'p2' De Schrijverba20bb12008-10-15 17:48:43 +0300947 return 0;
948}
Paul Walmsleyad67ef62008-08-19 11:08:40 +0300949