OMAP2/3: PRM/CM: prefix OMAP2 PRM/CM functions with "omap2_"
[linux-block.git] / arch / arm / mach-omap2 / powerdomain.c
CommitLineData
ad67ef68
PW
1/*
2 * OMAP powerdomain control
3 *
4 * Copyright (C) 2007-2008 Texas Instruments, Inc.
55ed9694 5 * Copyright (C) 2007-2009 Nokia Corporation
ad67ef68
PW
6 *
7 * Written by Paul Walmsley
3a759f09 8 * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
4788da26 9 * State counting code by Tero Kristo <tero.kristo@nokia.com>
3a759f09 10 *
ad67ef68
PW
11 * 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 */
33903eb5 15#undef DEBUG
ad67ef68
PW
16
17#include <linux/kernel.h>
ad67ef68 18#include <linux/types.h>
ad67ef68
PW
19#include <linux/list.h>
20#include <linux/errno.h>
9b7fc907 21#include <linux/string.h>
59fb659b
PW
22#include "cm2xxx_3xxx.h"
23#include "cm44xx.h"
24#include "prm2xxx_3xxx.h"
d198b514 25#include "prm44xx.h"
ad67ef68 26
ce491cf8
TL
27#include <plat/cpu.h>
28#include <plat/powerdomain.h>
29#include <plat/clockdomain.h>
55ed9694 30#include <plat/prcm.h>
ad67ef68 31
6199ab26
PDS
32#include "pm.h"
33
ba20bb12
PDS
34enum {
35 PWRDM_STATE_NOW = 0,
36 PWRDM_STATE_PREV,
37};
38
3a759f09 39
ad67ef68
PW
40/* pwrdm_list contains all registered struct powerdomains */
41static LIST_HEAD(pwrdm_list);
42
3b1e8b21
RN
43static struct pwrdm_ops *arch_pwrdm;
44
ad67ef68
PW
45/* Private functions */
46
ad67ef68
PW
47static struct powerdomain *_pwrdm_lookup(const char *name)
48{
49 struct powerdomain *pwrdm, *temp_pwrdm;
50
51 pwrdm = NULL;
52
53 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
54 if (!strcmp(name, temp_pwrdm->name)) {
55 pwrdm = temp_pwrdm;
56 break;
57 }
58 }
59
60 return pwrdm;
61}
62
e909d62a
PW
63/**
64 * _pwrdm_register - register a powerdomain
65 * @pwrdm: struct powerdomain * to register
66 *
67 * Adds a powerdomain to the internal powerdomain list. Returns
68 * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
69 * already registered by the provided name, or 0 upon success.
70 */
71static int _pwrdm_register(struct powerdomain *pwrdm)
72{
73 int i;
74
75 if (!pwrdm)
76 return -EINVAL;
77
78 if (!omap_chip_is(pwrdm->omap_chip))
79 return -EINVAL;
80
81 if (_pwrdm_lookup(pwrdm->name))
82 return -EEXIST;
83
84 list_add(&pwrdm->node, &pwrdm_list);
85
86 /* Initialize the powerdomain's state counter */
cf57aa7c 87 for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
e909d62a
PW
88 pwrdm->state_counter[i] = 0;
89
cde08f81
TG
90 pwrdm->ret_logic_off_counter = 0;
91 for (i = 0; i < pwrdm->banks; i++)
92 pwrdm->ret_mem_off_counter[i] = 0;
93
e909d62a
PW
94 pwrdm_wait_transition(pwrdm);
95 pwrdm->state = pwrdm_read_pwrst(pwrdm);
96 pwrdm->state_counter[pwrdm->state] = 1;
97
98 pr_debug("powerdomain: registered %s\n", pwrdm->name);
99
100 return 0;
101}
102
cde08f81
TG
103static void _update_logic_membank_counters(struct powerdomain *pwrdm)
104{
105 int i;
106 u8 prev_logic_pwrst, prev_mem_pwrst;
107
108 prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
109 if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
110 (prev_logic_pwrst == PWRDM_POWER_OFF))
111 pwrdm->ret_logic_off_counter++;
112
113 for (i = 0; i < pwrdm->banks; i++) {
114 prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
115
116 if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
117 (prev_mem_pwrst == PWRDM_POWER_OFF))
118 pwrdm->ret_mem_off_counter[i]++;
119 }
120}
121
ba20bb12
PDS
122static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
123{
124
125 int prev;
126 int state;
127
128 if (pwrdm == NULL)
129 return -EINVAL;
130
131 state = pwrdm_read_pwrst(pwrdm);
132
133 switch (flag) {
134 case PWRDM_STATE_NOW:
135 prev = pwrdm->state;
136 break;
137 case PWRDM_STATE_PREV:
138 prev = pwrdm_read_prev_pwrst(pwrdm);
139 if (pwrdm->state != prev)
140 pwrdm->state_counter[prev]++;
cde08f81
TG
141 if (prev == PWRDM_POWER_RET)
142 _update_logic_membank_counters(pwrdm);
ba20bb12
PDS
143 break;
144 default:
145 return -EINVAL;
146 }
147
148 if (state != prev)
149 pwrdm->state_counter[state]++;
150
6199ab26
PDS
151 pm_dbg_update_time(pwrdm, prev);
152
ba20bb12
PDS
153 pwrdm->state = state;
154
155 return 0;
156}
157
6199ab26 158static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
ba20bb12
PDS
159{
160 pwrdm_clear_all_prev_pwrst(pwrdm);
161 _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
162 return 0;
163}
164
6199ab26 165static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
ba20bb12
PDS
166{
167 _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
168 return 0;
169}
170
ad67ef68
PW
171/* Public functions */
172
173/**
174 * pwrdm_init - set up the powerdomain layer
f0271d65 175 * @pwrdm_list: array of struct powerdomain pointers to register
3b1e8b21 176 * @custom_funcs: func pointers for arch specfic implementations
ad67ef68 177 *
f0271d65
PW
178 * Loop through the array of powerdomains @pwrdm_list, registering all
179 * that are available on the current CPU. If pwrdm_list is supplied
180 * and not null, all of the referenced powerdomains will be
181 * registered. No return value. XXX pwrdm_list is not really a
182 * "list"; it is an array. Rename appropriately.
ad67ef68 183 */
3b1e8b21 184void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs)
ad67ef68
PW
185{
186 struct powerdomain **p = NULL;
187
3b1e8b21
RN
188 if (!custom_funcs)
189 WARN(1, "powerdomain: No custom pwrdm functions registered\n");
190 else
191 arch_pwrdm = custom_funcs;
192
ba20bb12 193 if (pwrdm_list) {
e909d62a
PW
194 for (p = pwrdm_list; *p; p++)
195 _pwrdm_register(*p);
ad67ef68 196 }
ad67ef68
PW
197}
198
199/**
200 * pwrdm_lookup - look up a powerdomain by name, return a pointer
201 * @name: name of powerdomain
202 *
f0271d65
PW
203 * Find a registered powerdomain by its name @name. Returns a pointer
204 * to the struct powerdomain if found, or NULL otherwise.
ad67ef68
PW
205 */
206struct powerdomain *pwrdm_lookup(const char *name)
207{
208 struct powerdomain *pwrdm;
ad67ef68
PW
209
210 if (!name)
211 return NULL;
212
ad67ef68 213 pwrdm = _pwrdm_lookup(name);
ad67ef68
PW
214
215 return pwrdm;
216}
217
218/**
e909d62a 219 * pwrdm_for_each - call function on each registered clockdomain
ad67ef68
PW
220 * @fn: callback function *
221 *
f0271d65
PW
222 * Call the supplied function @fn for each registered powerdomain.
223 * The callback function @fn can return anything but 0 to bail out
224 * early from the iterator. Returns the last return value of the
225 * callback function, which should be 0 for success or anything else
226 * to indicate failure; or -EINVAL if the function pointer is null.
ad67ef68 227 */
e909d62a
PW
228int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
229 void *user)
ad67ef68
PW
230{
231 struct powerdomain *temp_pwrdm;
ad67ef68
PW
232 int ret = 0;
233
234 if (!fn)
235 return -EINVAL;
236
ad67ef68 237 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
6199ab26 238 ret = (*fn)(temp_pwrdm, user);
ad67ef68
PW
239 if (ret)
240 break;
241 }
ee894b18
AB
242
243 return ret;
244}
245
8420bb13
PW
246/**
247 * pwrdm_add_clkdm - add a clockdomain to a powerdomain
248 * @pwrdm: struct powerdomain * to add the clockdomain to
249 * @clkdm: struct clockdomain * to associate with a powerdomain
250 *
f0271d65 251 * Associate the clockdomain @clkdm with a powerdomain @pwrdm. This
8420bb13
PW
252 * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if
253 * presented with invalid pointers; -ENOMEM if memory could not be allocated;
254 * or 0 upon success.
255 */
256int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
257{
8420bb13
PW
258 int i;
259 int ret = -EINVAL;
260
261 if (!pwrdm || !clkdm)
262 return -EINVAL;
263
264 pr_debug("powerdomain: associating clockdomain %s with powerdomain "
265 "%s\n", clkdm->name, pwrdm->name);
266
8420bb13
PW
267 for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
268 if (!pwrdm->pwrdm_clkdms[i])
269 break;
270#ifdef DEBUG
271 if (pwrdm->pwrdm_clkdms[i] == clkdm) {
272 ret = -EINVAL;
273 goto pac_exit;
274 }
275#endif
276 }
277
278 if (i == PWRDM_MAX_CLKDMS) {
279 pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
280 "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
281 WARN_ON(1);
282 ret = -ENOMEM;
283 goto pac_exit;
284 }
285
286 pwrdm->pwrdm_clkdms[i] = clkdm;
287
288 ret = 0;
289
290pac_exit:
8420bb13
PW
291 return ret;
292}
293
294/**
295 * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
296 * @pwrdm: struct powerdomain * to add the clockdomain to
297 * @clkdm: struct clockdomain * to associate with a powerdomain
298 *
f0271d65
PW
299 * Dissociate the clockdomain @clkdm from the powerdomain
300 * @pwrdm. Returns -EINVAL if presented with invalid pointers; -ENOENT
301 * if @clkdm was not associated with the powerdomain, or 0 upon
302 * success.
8420bb13
PW
303 */
304int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
305{
8420bb13
PW
306 int ret = -EINVAL;
307 int i;
308
309 if (!pwrdm || !clkdm)
310 return -EINVAL;
311
312 pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
313 "%s\n", clkdm->name, pwrdm->name);
314
8420bb13
PW
315 for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
316 if (pwrdm->pwrdm_clkdms[i] == clkdm)
317 break;
318
319 if (i == PWRDM_MAX_CLKDMS) {
320 pr_debug("powerdomain: clkdm %s not associated with pwrdm "
321 "%s ?!\n", clkdm->name, pwrdm->name);
322 ret = -ENOENT;
323 goto pdc_exit;
324 }
325
326 pwrdm->pwrdm_clkdms[i] = NULL;
327
328 ret = 0;
329
330pdc_exit:
8420bb13
PW
331 return ret;
332}
333
334/**
335 * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
336 * @pwrdm: struct powerdomain * to iterate over
337 * @fn: callback function *
338 *
f0271d65
PW
339 * Call the supplied function @fn for each clockdomain in the powerdomain
340 * @pwrdm. The callback function can return anything but 0 to bail
e909d62a
PW
341 * out early from the iterator. Returns -EINVAL if presented with
342 * invalid pointers; or passes along the last return value of the
343 * callback function, which should be 0 for success or anything else
344 * to indicate failure.
8420bb13
PW
345 */
346int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
347 int (*fn)(struct powerdomain *pwrdm,
348 struct clockdomain *clkdm))
349{
8420bb13
PW
350 int ret = 0;
351 int i;
352
353 if (!fn)
354 return -EINVAL;
355
8420bb13
PW
356 for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
357 ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
358
8420bb13
PW
359 return ret;
360}
361
ad67ef68
PW
362/**
363 * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
364 * @pwrdm: struct powerdomain *
365 *
f0271d65 366 * Return the number of controllable memory banks in powerdomain @pwrdm,
ad67ef68
PW
367 * starting with 1. Returns -EINVAL if the powerdomain pointer is null.
368 */
369int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
370{
371 if (!pwrdm)
372 return -EINVAL;
373
374 return pwrdm->banks;
375}
376
377/**
378 * pwrdm_set_next_pwrst - set next powerdomain power state
379 * @pwrdm: struct powerdomain * to set
380 * @pwrst: one of the PWRDM_POWER_* macros
381 *
f0271d65 382 * Set the powerdomain @pwrdm's next power state to @pwrst. The powerdomain
ad67ef68
PW
383 * may not enter this state immediately if the preconditions for this state
384 * have not been satisfied. Returns -EINVAL if the powerdomain pointer is
385 * null or if the power state is invalid for the powerdomin, or returns 0
386 * upon success.
387 */
388int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
389{
f327e07b
RN
390 int ret = -EINVAL;
391
ad67ef68
PW
392 if (!pwrdm)
393 return -EINVAL;
394
395 if (!(pwrdm->pwrsts & (1 << pwrst)))
396 return -EINVAL;
397
398 pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
399 pwrdm->name, pwrst);
400
f327e07b
RN
401 if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst)
402 ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
ad67ef68 403
f327e07b 404 return ret;
ad67ef68
PW
405}
406
407/**
408 * pwrdm_read_next_pwrst - get next powerdomain power state
409 * @pwrdm: struct powerdomain * to get power state
410 *
f0271d65 411 * Return the powerdomain @pwrdm's next power state. Returns -EINVAL
ad67ef68
PW
412 * if the powerdomain pointer is null or returns the next power state
413 * upon success.
414 */
415int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
416{
f327e07b
RN
417 int ret = -EINVAL;
418
ad67ef68
PW
419 if (!pwrdm)
420 return -EINVAL;
421
f327e07b
RN
422 if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst)
423 ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
424
425 return ret;
ad67ef68
PW
426}
427
428/**
429 * pwrdm_read_pwrst - get current powerdomain power state
430 * @pwrdm: struct powerdomain * to get power state
431 *
f0271d65 432 * Return the powerdomain @pwrdm's current power state. Returns -EINVAL
ad67ef68
PW
433 * if the powerdomain pointer is null or returns the current power state
434 * upon success.
435 */
436int pwrdm_read_pwrst(struct powerdomain *pwrdm)
437{
f327e07b
RN
438 int ret = -EINVAL;
439
ad67ef68
PW
440 if (!pwrdm)
441 return -EINVAL;
442
f327e07b
RN
443 if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
444 ret = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
445
446 return ret;
ad67ef68
PW
447}
448
449/**
450 * pwrdm_read_prev_pwrst - get previous powerdomain power state
451 * @pwrdm: struct powerdomain * to get previous power state
452 *
f0271d65 453 * Return the powerdomain @pwrdm's previous power state. Returns -EINVAL
ad67ef68
PW
454 * if the powerdomain pointer is null or returns the previous power state
455 * upon success.
456 */
457int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
458{
f327e07b
RN
459 int ret = -EINVAL;
460
ad67ef68
PW
461 if (!pwrdm)
462 return -EINVAL;
463
f327e07b
RN
464 if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst)
465 ret = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
466
467 return ret;
ad67ef68
PW
468}
469
470/**
471 * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
472 * @pwrdm: struct powerdomain * to set
473 * @pwrst: one of the PWRDM_POWER_* macros
474 *
f0271d65
PW
475 * Set the next power state @pwrst that the logic portion of the
476 * powerdomain @pwrdm will enter when the powerdomain enters retention.
477 * This will be either RETENTION or OFF, if supported. Returns
478 * -EINVAL if the powerdomain pointer is null or the target power
479 * state is not not supported, or returns 0 upon success.
ad67ef68
PW
480 */
481int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
482{
12627578 483 int ret = -EINVAL;
2bc4ef71 484
ad67ef68
PW
485 if (!pwrdm)
486 return -EINVAL;
487
488 if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
489 return -EINVAL;
490
491 pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
492 pwrdm->name, pwrst);
493
12627578
RN
494 if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
495 ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, pwrst);
ad67ef68 496
12627578 497 return ret;
ad67ef68
PW
498}
499
500/**
501 * pwrdm_set_mem_onst - set memory power state while powerdomain ON
502 * @pwrdm: struct powerdomain * to set
503 * @bank: memory bank number to set (0-3)
504 * @pwrst: one of the PWRDM_POWER_* macros
505 *
f0271d65
PW
506 * Set the next power state @pwrst that memory bank @bank of the
507 * powerdomain @pwrdm will enter when the powerdomain enters the ON
508 * state. @bank will be a number from 0 to 3, and represents different
509 * types of memory, depending on the powerdomain. Returns -EINVAL if
510 * the powerdomain pointer is null or the target power state is not
511 * not supported for this memory bank, -EEXIST if the target memory
512 * bank does not exist or is not controllable, or returns 0 upon
513 * success.
ad67ef68
PW
514 */
515int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
516{
9b7fc907 517 int ret = -EINVAL;
ad67ef68
PW
518
519 if (!pwrdm)
520 return -EINVAL;
521
522 if (pwrdm->banks < (bank + 1))
523 return -EEXIST;
524
525 if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
526 return -EINVAL;
527
528 pr_debug("powerdomain: setting next memory powerstate for domain %s "
529 "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
530
9b7fc907
RN
531 if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
532 ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
ad67ef68 533
9b7fc907 534 return ret;
ad67ef68
PW
535}
536
537/**
538 * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
539 * @pwrdm: struct powerdomain * to set
540 * @bank: memory bank number to set (0-3)
541 * @pwrst: one of the PWRDM_POWER_* macros
542 *
f0271d65
PW
543 * Set the next power state @pwrst that memory bank @bank of the
544 * powerdomain @pwrdm will enter when the powerdomain enters the
545 * RETENTION state. Bank will be a number from 0 to 3, and represents
546 * different types of memory, depending on the powerdomain. @pwrst
547 * will be either RETENTION or OFF, if supported. Returns -EINVAL if
548 * the powerdomain pointer is null or the target power state is not
549 * not supported for this memory bank, -EEXIST if the target memory
550 * bank does not exist or is not controllable, or returns 0 upon
551 * success.
ad67ef68
PW
552 */
553int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
554{
9b7fc907 555 int ret = -EINVAL;
ad67ef68
PW
556
557 if (!pwrdm)
558 return -EINVAL;
559
560 if (pwrdm->banks < (bank + 1))
561 return -EEXIST;
562
563 if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
564 return -EINVAL;
565
566 pr_debug("powerdomain: setting next memory powerstate for domain %s "
567 "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
568
9b7fc907
RN
569 if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
570 ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
ad67ef68 571
9b7fc907 572 return ret;
ad67ef68
PW
573}
574
575/**
576 * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
577 * @pwrdm: struct powerdomain * to get current logic retention power state
578 *
f0271d65
PW
579 * Return the power state that the logic portion of powerdomain @pwrdm
580 * will enter when the powerdomain enters retention. Returns -EINVAL
581 * if the powerdomain pointer is null or returns the logic retention
582 * power state upon success.
ad67ef68
PW
583 */
584int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
585{
12627578
RN
586 int ret = -EINVAL;
587
ad67ef68
PW
588 if (!pwrdm)
589 return -EINVAL;
590
12627578
RN
591 if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst)
592 ret = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
593
594 return ret;
ad67ef68
PW
595}
596
597/**
598 * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
599 * @pwrdm: struct powerdomain * to get previous logic power state
600 *
f0271d65
PW
601 * Return the powerdomain @pwrdm's previous logic power state. Returns
602 * -EINVAL if the powerdomain pointer is null or returns the previous
603 * logic power state upon success.
ad67ef68
PW
604 */
605int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
606{
12627578
RN
607 int ret = -EINVAL;
608
ad67ef68
PW
609 if (!pwrdm)
610 return -EINVAL;
611
12627578
RN
612 if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst)
613 ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
614
615 return ret;
ad67ef68
PW
616}
617
1e3d0d2b
TG
618/**
619 * pwrdm_read_logic_retst - get next powerdomain logic power state
620 * @pwrdm: struct powerdomain * to get next logic power state
621 *
622 * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
623 * if the powerdomain pointer is null or returns the next logic
624 * power state upon success.
625 */
626int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
627{
12627578
RN
628 int ret = -EINVAL;
629
1e3d0d2b
TG
630 if (!pwrdm)
631 return -EINVAL;
632
12627578
RN
633 if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst)
634 ret = arch_pwrdm->pwrdm_read_logic_retst(pwrdm);
635
636 return ret;
1e3d0d2b
TG
637}
638
ad67ef68
PW
639/**
640 * pwrdm_read_mem_pwrst - get current memory bank power state
641 * @pwrdm: struct powerdomain * to get current memory bank power state
642 * @bank: memory bank number (0-3)
643 *
f0271d65
PW
644 * Return the powerdomain @pwrdm's current memory power state for bank
645 * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
ad67ef68
PW
646 * the target memory bank does not exist or is not controllable, or
647 * returns the current memory power state upon success.
648 */
649int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
650{
9b7fc907 651 int ret = -EINVAL;
ad67ef68
PW
652
653 if (!pwrdm)
9b7fc907 654 return ret;
ad67ef68
PW
655
656 if (pwrdm->banks < (bank + 1))
9b7fc907 657 return ret;
ad67ef68 658
3863c74b
TG
659 if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
660 bank = 1;
661
9b7fc907
RN
662 if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
663 ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
ad67ef68 664
9b7fc907 665 return ret;
ad67ef68
PW
666}
667
668/**
669 * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
670 * @pwrdm: struct powerdomain * to get previous memory bank power state
671 * @bank: memory bank number (0-3)
672 *
f0271d65
PW
673 * Return the powerdomain @pwrdm's previous memory power state for
674 * bank @bank. Returns -EINVAL if the powerdomain pointer is null,
675 * -EEXIST if the target memory bank does not exist or is not
676 * controllable, or returns the previous memory power state upon
677 * success.
ad67ef68
PW
678 */
679int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
680{
9b7fc907 681 int ret = -EINVAL;
ad67ef68
PW
682
683 if (!pwrdm)
9b7fc907 684 return ret;
ad67ef68
PW
685
686 if (pwrdm->banks < (bank + 1))
9b7fc907 687 return ret;
ad67ef68 688
3863c74b
TG
689 if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
690 bank = 1;
691
9b7fc907
RN
692 if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
693 ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
ad67ef68 694
9b7fc907 695 return ret;
ad67ef68
PW
696}
697
1e3d0d2b
TG
698/**
699 * pwrdm_read_mem_retst - get next memory bank power state
700 * @pwrdm: struct powerdomain * to get mext memory bank power state
701 * @bank: memory bank number (0-3)
702 *
703 * Return the powerdomain pwrdm's next memory power state for bank
704 * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
705 * the target memory bank does not exist or is not controllable, or
706 * returns the next memory power state upon success.
707 */
708int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
709{
9b7fc907 710 int ret = -EINVAL;
1e3d0d2b
TG
711
712 if (!pwrdm)
9b7fc907 713 return ret;
1e3d0d2b
TG
714
715 if (pwrdm->banks < (bank + 1))
9b7fc907 716 return ret;
1e3d0d2b 717
9b7fc907
RN
718 if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
719 ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
1e3d0d2b 720
9b7fc907 721 return ret;
1e3d0d2b
TG
722}
723
ad67ef68
PW
724/**
725 * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
726 * @pwrdm: struct powerdomain * to clear
727 *
f0271d65
PW
728 * Clear the powerdomain's previous power state register @pwrdm.
729 * Clears the entire register, including logic and memory bank
730 * previous power states. Returns -EINVAL if the powerdomain pointer
731 * is null, or returns 0 upon success.
ad67ef68
PW
732 */
733int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
734{
9b7fc907
RN
735 int ret = -EINVAL;
736
ad67ef68 737 if (!pwrdm)
9b7fc907 738 return ret;
ad67ef68
PW
739
740 /*
741 * XXX should get the powerdomain's current state here;
742 * warn & fail if it is not ON.
743 */
744
745 pr_debug("powerdomain: clearing previous power state reg for %s\n",
746 pwrdm->name);
747
9b7fc907
RN
748 if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
749 ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
ad67ef68 750
9b7fc907 751 return ret;
ad67ef68
PW
752}
753
0b7cbfb5
PW
754/**
755 * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
756 * @pwrdm: struct powerdomain *
757 *
758 * Enable automatic context save-and-restore upon power state change
f0271d65
PW
759 * for some devices in the powerdomain @pwrdm. Warning: this only
760 * affects a subset of devices in a powerdomain; check the TRM
761 * closely. Returns -EINVAL if the powerdomain pointer is null or if
762 * the powerdomain does not support automatic save-and-restore, or
763 * returns 0 upon success.
0b7cbfb5
PW
764 */
765int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
766{
9b7fc907
RN
767 int ret = -EINVAL;
768
0b7cbfb5 769 if (!pwrdm)
9b7fc907 770 return ret;
0b7cbfb5
PW
771
772 if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
9b7fc907 773 return ret;
0b7cbfb5
PW
774
775 pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
776 pwrdm->name);
777
9b7fc907
RN
778 if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
779 ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
0b7cbfb5 780
9b7fc907 781 return ret;
0b7cbfb5
PW
782}
783
784/**
785 * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
786 * @pwrdm: struct powerdomain *
787 *
788 * Disable automatic context save-and-restore upon power state change
f0271d65
PW
789 * for some devices in the powerdomain @pwrdm. Warning: this only
790 * affects a subset of devices in a powerdomain; check the TRM
791 * closely. Returns -EINVAL if the powerdomain pointer is null or if
792 * the powerdomain does not support automatic save-and-restore, or
793 * returns 0 upon success.
0b7cbfb5
PW
794 */
795int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
796{
9b7fc907
RN
797 int ret = -EINVAL;
798
0b7cbfb5 799 if (!pwrdm)
9b7fc907 800 return ret;
0b7cbfb5
PW
801
802 if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
9b7fc907 803 return ret;
0b7cbfb5
PW
804
805 pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
806 pwrdm->name);
807
9b7fc907
RN
808 if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
809 ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
0b7cbfb5 810
9b7fc907 811 return ret;
0b7cbfb5
PW
812}
813
814/**
815 * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
816 * @pwrdm: struct powerdomain *
817 *
f0271d65 818 * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore
0b7cbfb5
PW
819 * for some devices, or 0 if it does not.
820 */
821bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
822{
823 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
824}
825
90dbc7b0
RN
826/**
827 * pwrdm_set_lowpwrstchange - Request a low power state change
828 * @pwrdm: struct powerdomain *
829 *
830 * Allows a powerdomain to transtion to a lower power sleep state
831 * from an existing sleep state without waking up the powerdomain.
832 * Returns -EINVAL if the powerdomain pointer is null or if the
833 * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0
834 * upon success.
835 */
836int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
837{
9b7fc907
RN
838 int ret = -EINVAL;
839
90dbc7b0
RN
840 if (!pwrdm)
841 return -EINVAL;
842
843 if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE))
844 return -EINVAL;
845
846 pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
847 pwrdm->name);
848
9b7fc907
RN
849 if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange)
850 ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
90dbc7b0 851
9b7fc907 852 return ret;
90dbc7b0
RN
853}
854
ad67ef68
PW
855/**
856 * pwrdm_wait_transition - wait for powerdomain power transition to finish
857 * @pwrdm: struct powerdomain * to wait for
858 *
f0271d65 859 * If the powerdomain @pwrdm is in the process of a state transition,
ad67ef68
PW
860 * spin until it completes the power transition, or until an iteration
861 * bailout value is reached. Returns -EINVAL if the powerdomain
862 * pointer is null, -EAGAIN if the bailout value was reached, or
863 * returns 0 upon success.
864 */
865int pwrdm_wait_transition(struct powerdomain *pwrdm)
866{
9b7fc907 867 int ret = -EINVAL;
ad67ef68
PW
868
869 if (!pwrdm)
870 return -EINVAL;
871
9b7fc907
RN
872 if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition)
873 ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
ad67ef68 874
9b7fc907 875 return ret;
ad67ef68
PW
876}
877
ba20bb12
PDS
878int pwrdm_state_switch(struct powerdomain *pwrdm)
879{
880 return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
881}
882
883int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
884{
885 if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) {
886 pwrdm_wait_transition(clkdm->pwrdm.ptr);
887 return pwrdm_state_switch(clkdm->pwrdm.ptr);
888 }
889
890 return -EINVAL;
891}
ba20bb12
PDS
892
893int pwrdm_pre_transition(void)
894{
6199ab26 895 pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
ba20bb12
PDS
896 return 0;
897}
898
899int pwrdm_post_transition(void)
900{
6199ab26 901 pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
ba20bb12
PDS
902 return 0;
903}