~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-omap2/powerdomain.c

Version: ~ [ linux-5.6-rc1 ] ~ [ linux-5.5.2 ] ~ [ linux-5.4.17 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.102 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.170 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.213 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.213 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * OMAP powerdomain control
  3  *
  4  * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
  5  * Copyright (C) 2007-2011 Nokia Corporation
  6  *
  7  * Written by Paul Walmsley
  8  * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
  9  * State counting code by Tero Kristo <tero.kristo@nokia.com>
 10  *
 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  */
 15 #undef DEBUG
 16 
 17 #include <linux/kernel.h>
 18 #include <linux/types.h>
 19 #include <linux/list.h>
 20 #include <linux/errno.h>
 21 #include <linux/string.h>
 22 #include <linux/spinlock.h>
 23 #include <trace/events/power.h>
 24 
 25 #include "cm2xxx_3xxx.h"
 26 #include "prcm44xx.h"
 27 #include "cm44xx.h"
 28 #include "prm2xxx_3xxx.h"
 29 #include "prm44xx.h"
 30 
 31 #include <asm/cpu.h>
 32 
 33 #include "powerdomain.h"
 34 #include "clockdomain.h"
 35 
 36 #include "soc.h"
 37 #include "pm.h"
 38 
 39 #define PWRDM_TRACE_STATES_FLAG (1<<31)
 40 
 41 enum {
 42         PWRDM_STATE_NOW = 0,
 43         PWRDM_STATE_PREV,
 44 };
 45 
 46 /*
 47  * Types of sleep_switch used internally in omap_set_pwrdm_state()
 48  * and its associated static functions
 49  *
 50  * XXX Better documentation is needed here
 51  */
 52 #define ALREADYACTIVE_SWITCH            0
 53 #define FORCEWAKEUP_SWITCH              1
 54 #define LOWPOWERSTATE_SWITCH            2
 55 
 56 /* pwrdm_list contains all registered struct powerdomains */
 57 static LIST_HEAD(pwrdm_list);
 58 
 59 static struct pwrdm_ops *arch_pwrdm;
 60 
 61 /* Private functions */
 62 
 63 static struct powerdomain *_pwrdm_lookup(const char *name)
 64 {
 65         struct powerdomain *pwrdm, *temp_pwrdm;
 66 
 67         pwrdm = NULL;
 68 
 69         list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
 70                 if (!strcmp(name, temp_pwrdm->name)) {
 71                         pwrdm = temp_pwrdm;
 72                         break;
 73                 }
 74         }
 75 
 76         return pwrdm;
 77 }
 78 
 79 /**
 80  * _pwrdm_register - register a powerdomain
 81  * @pwrdm: struct powerdomain * to register
 82  *
 83  * Adds a powerdomain to the internal powerdomain list.  Returns
 84  * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
 85  * already registered by the provided name, or 0 upon success.
 86  */
 87 static int _pwrdm_register(struct powerdomain *pwrdm)
 88 {
 89         int i;
 90         struct voltagedomain *voltdm;
 91 
 92         if (!pwrdm || !pwrdm->name)
 93                 return -EINVAL;
 94 
 95         if (cpu_is_omap44xx() &&
 96             pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) {
 97                 pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n",
 98                        pwrdm->name);
 99                 return -EINVAL;
100         }
101 
102         if (_pwrdm_lookup(pwrdm->name))
103                 return -EEXIST;
104 
105         if (arch_pwrdm && arch_pwrdm->pwrdm_has_voltdm)
106                 if (!arch_pwrdm->pwrdm_has_voltdm())
107                         goto skip_voltdm;
108 
109         voltdm = voltdm_lookup(pwrdm->voltdm.name);
110         if (!voltdm) {
111                 pr_err("powerdomain: %s: voltagedomain %s does not exist\n",
112                        pwrdm->name, pwrdm->voltdm.name);
113                 return -EINVAL;
114         }
115         pwrdm->voltdm.ptr = voltdm;
116         INIT_LIST_HEAD(&pwrdm->voltdm_node);
117         voltdm_add_pwrdm(voltdm, pwrdm);
118 skip_voltdm:
119         spin_lock_init(&pwrdm->_lock);
120 
121         list_add(&pwrdm->node, &pwrdm_list);
122 
123         /* Initialize the powerdomain's state counter */
124         for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
125                 pwrdm->state_counter[i] = 0;
126 
127         pwrdm->ret_logic_off_counter = 0;
128         for (i = 0; i < pwrdm->banks; i++)
129                 pwrdm->ret_mem_off_counter[i] = 0;
130 
131         arch_pwrdm->pwrdm_wait_transition(pwrdm);
132         pwrdm->state = pwrdm_read_pwrst(pwrdm);
133         pwrdm->state_counter[pwrdm->state] = 1;
134 
135         pr_debug("powerdomain: registered %s\n", pwrdm->name);
136 
137         return 0;
138 }
139 
140 static void _update_logic_membank_counters(struct powerdomain *pwrdm)
141 {
142         int i;
143         u8 prev_logic_pwrst, prev_mem_pwrst;
144 
145         prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
146         if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
147             (prev_logic_pwrst == PWRDM_POWER_OFF))
148                 pwrdm->ret_logic_off_counter++;
149 
150         for (i = 0; i < pwrdm->banks; i++) {
151                 prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
152 
153                 if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
154                     (prev_mem_pwrst == PWRDM_POWER_OFF))
155                         pwrdm->ret_mem_off_counter[i]++;
156         }
157 }
158 
159 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
160 {
161 
162         int prev, next, state, trace_state = 0;
163 
164         if (pwrdm == NULL)
165                 return -EINVAL;
166 
167         state = pwrdm_read_pwrst(pwrdm);
168 
169         switch (flag) {
170         case PWRDM_STATE_NOW:
171                 prev = pwrdm->state;
172                 break;
173         case PWRDM_STATE_PREV:
174                 prev = pwrdm_read_prev_pwrst(pwrdm);
175                 if (pwrdm->state != prev)
176                         pwrdm->state_counter[prev]++;
177                 if (prev == PWRDM_POWER_RET)
178                         _update_logic_membank_counters(pwrdm);
179                 /*
180                  * If the power domain did not hit the desired state,
181                  * generate a trace event with both the desired and hit states
182                  */
183                 next = pwrdm_read_next_pwrst(pwrdm);
184                 if (next != prev) {
185                         trace_state = (PWRDM_TRACE_STATES_FLAG |
186                                        ((next & OMAP_POWERSTATE_MASK) << 8) |
187                                        ((prev & OMAP_POWERSTATE_MASK) << 0));
188                         trace_power_domain_target(pwrdm->name, trace_state,
189                                                   smp_processor_id());
190                 }
191                 break;
192         default:
193                 return -EINVAL;
194         }
195 
196         if (state != prev)
197                 pwrdm->state_counter[state]++;
198 
199         pm_dbg_update_time(pwrdm, prev);
200 
201         pwrdm->state = state;
202 
203         return 0;
204 }
205 
206 static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
207 {
208         pwrdm_clear_all_prev_pwrst(pwrdm);
209         _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
210         return 0;
211 }
212 
213 static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
214 {
215         _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
216         return 0;
217 }
218 
219 /**
220  * _pwrdm_save_clkdm_state_and_activate - prepare for power state change
221  * @pwrdm: struct powerdomain * to operate on
222  * @curr_pwrst: current power state of @pwrdm
223  * @pwrst: power state to switch to
224  * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised
225  *
226  * Determine whether the powerdomain needs to be turned on before
227  * attempting to switch power states.  Called by
228  * omap_set_pwrdm_state().  NOTE that if the powerdomain contains
229  * multiple clockdomains, this code assumes that the first clockdomain
230  * supports software-supervised wakeup mode - potentially a problem.
231  * Returns the power state switch mode currently in use (see the
232  * "Types of sleep_switch" comment above).
233  */
234 static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
235                                                u8 curr_pwrst, u8 pwrst,
236                                                bool *hwsup)
237 {
238         u8 sleep_switch;
239 
240         if (curr_pwrst < PWRDM_POWER_ON) {
241                 if (curr_pwrst > pwrst &&
242                     pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
243                     arch_pwrdm->pwrdm_set_lowpwrstchange) {
244                         sleep_switch = LOWPOWERSTATE_SWITCH;
245                 } else {
246                         *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
247                         clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]);
248                         sleep_switch = FORCEWAKEUP_SWITCH;
249                 }
250         } else {
251                 sleep_switch = ALREADYACTIVE_SWITCH;
252         }
253 
254         return sleep_switch;
255 }
256 
257 /**
258  * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change
259  * @pwrdm: struct powerdomain * to operate on
260  * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate()
261  * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode?
262  *
263  * Restore the clockdomain state perturbed by
264  * _pwrdm_save_clkdm_state_and_activate(), and call the power state
265  * bookkeeping code.  Called by omap_set_pwrdm_state().  NOTE that if
266  * the powerdomain contains multiple clockdomains, this assumes that
267  * the first associated clockdomain supports either
268  * hardware-supervised idle control in the register, or
269  * software-supervised sleep.  No return value.
270  */
271 static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
272                                        u8 sleep_switch, bool hwsup)
273 {
274         switch (sleep_switch) {
275         case FORCEWAKEUP_SWITCH:
276                 if (hwsup)
277                         clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]);
278                 else
279                         clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]);
280                 break;
281         case LOWPOWERSTATE_SWITCH:
282                 if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
283                     arch_pwrdm->pwrdm_set_lowpwrstchange)
284                         arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
285                 pwrdm_state_switch_nolock(pwrdm);
286                 break;
287         }
288 }
289 
290 /* Public functions */
291 
292 /**
293  * pwrdm_register_platform_funcs - register powerdomain implementation fns
294  * @po: func pointers for arch specific implementations
295  *
296  * Register the list of function pointers used to implement the
297  * powerdomain functions on different OMAP SoCs.  Should be called
298  * before any other pwrdm_register*() function.  Returns -EINVAL if
299  * @po is null, -EEXIST if platform functions have already been
300  * registered, or 0 upon success.
301  */
302 int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
303 {
304         if (!po)
305                 return -EINVAL;
306 
307         if (arch_pwrdm)
308                 return -EEXIST;
309 
310         arch_pwrdm = po;
311 
312         return 0;
313 }
314 
315 /**
316  * pwrdm_register_pwrdms - register SoC powerdomains
317  * @ps: pointer to an array of struct powerdomain to register
318  *
319  * Register the powerdomains available on a particular OMAP SoC.  Must
320  * be called after pwrdm_register_platform_funcs().  May be called
321  * multiple times.  Returns -EACCES if called before
322  * pwrdm_register_platform_funcs(); -EINVAL if the argument @ps is
323  * null; or 0 upon success.
324  */
325 int pwrdm_register_pwrdms(struct powerdomain **ps)
326 {
327         struct powerdomain **p = NULL;
328 
329         if (!arch_pwrdm)
330                 return -EEXIST;
331 
332         if (!ps)
333                 return -EINVAL;
334 
335         for (p = ps; *p; p++)
336                 _pwrdm_register(*p);
337 
338         return 0;
339 }
340 
341 /**
342  * pwrdm_complete_init - set up the powerdomain layer
343  *
344  * Do whatever is necessary to initialize registered powerdomains and
345  * powerdomain code.  Currently, this programs the next power state
346  * for each powerdomain to ON.  This prevents powerdomains from
347  * unexpectedly losing context or entering high wakeup latency modes
348  * with non-power-management-enabled kernels.  Must be called after
349  * pwrdm_register_pwrdms().  Returns -EACCES if called before
350  * pwrdm_register_pwrdms(), or 0 upon success.
351  */
352 int pwrdm_complete_init(void)
353 {
354         struct powerdomain *temp_p;
355 
356         if (list_empty(&pwrdm_list))
357                 return -EACCES;
358 
359         list_for_each_entry(temp_p, &pwrdm_list, node)
360                 pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
361 
362         return 0;
363 }
364 
365 /**
366  * pwrdm_lock - acquire a Linux spinlock on a powerdomain
367  * @pwrdm: struct powerdomain * to lock
368  *
369  * Acquire the powerdomain spinlock on @pwrdm.  No return value.
370  */
371 void pwrdm_lock(struct powerdomain *pwrdm)
372         __acquires(&pwrdm->_lock)
373 {
374         spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags);
375 }
376 
377 /**
378  * pwrdm_unlock - release a Linux spinlock on a powerdomain
379  * @pwrdm: struct powerdomain * to unlock
380  *
381  * Release the powerdomain spinlock on @pwrdm.  No return value.
382  */
383 void pwrdm_unlock(struct powerdomain *pwrdm)
384         __releases(&pwrdm->_lock)
385 {
386         spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags);
387 }
388 
389 /**
390  * pwrdm_lookup - look up a powerdomain by name, return a pointer
391  * @name: name of powerdomain
392  *
393  * Find a registered powerdomain by its name @name.  Returns a pointer
394  * to the struct powerdomain if found, or NULL otherwise.
395  */
396 struct powerdomain *pwrdm_lookup(const char *name)
397 {
398         struct powerdomain *pwrdm;
399 
400         if (!name)
401                 return NULL;
402 
403         pwrdm = _pwrdm_lookup(name);
404 
405         return pwrdm;
406 }
407 
408 /**
409  * pwrdm_for_each - call function on each registered clockdomain
410  * @fn: callback function *
411  *
412  * Call the supplied function @fn for each registered powerdomain.
413  * The callback function @fn can return anything but 0 to bail out
414  * early from the iterator.  Returns the last return value of the
415  * callback function, which should be 0 for success or anything else
416  * to indicate failure; or -EINVAL if the function pointer is null.
417  */
418 int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
419                    void *user)
420 {
421         struct powerdomain *temp_pwrdm;
422         int ret = 0;
423 
424         if (!fn)
425                 return -EINVAL;
426 
427         list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
428                 ret = (*fn)(temp_pwrdm, user);
429                 if (ret)
430                         break;
431         }
432 
433         return ret;
434 }
435 
436 /**
437  * pwrdm_add_clkdm - add a clockdomain to a powerdomain
438  * @pwrdm: struct powerdomain * to add the clockdomain to
439  * @clkdm: struct clockdomain * to associate with a powerdomain
440  *
441  * Associate the clockdomain @clkdm with a powerdomain @pwrdm.  This
442  * enables the use of pwrdm_for_each_clkdm().  Returns -EINVAL if
443  * presented with invalid pointers; -ENOMEM if memory could not be allocated;
444  * or 0 upon success.
445  */
446 int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
447 {
448         int i;
449         int ret = -EINVAL;
450 
451         if (!pwrdm || !clkdm)
452                 return -EINVAL;
453 
454         pr_debug("powerdomain: %s: associating clockdomain %s\n",
455                  pwrdm->name, clkdm->name);
456 
457         for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
458                 if (!pwrdm->pwrdm_clkdms[i])
459                         break;
460 #ifdef DEBUG
461                 if (pwrdm->pwrdm_clkdms[i] == clkdm) {
462                         ret = -EINVAL;
463                         goto pac_exit;
464                 }
465 #endif
466         }
467 
468         if (i == PWRDM_MAX_CLKDMS) {
469                 pr_debug("powerdomain: %s: increase PWRDM_MAX_CLKDMS for clkdm %s\n",
470                          pwrdm->name, clkdm->name);
471                 WARN_ON(1);
472                 ret = -ENOMEM;
473                 goto pac_exit;
474         }
475 
476         pwrdm->pwrdm_clkdms[i] = clkdm;
477 
478         ret = 0;
479 
480 pac_exit:
481         return ret;
482 }
483 
484 /**
485  * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
486  * @pwrdm: struct powerdomain * to add the clockdomain to
487  * @clkdm: struct clockdomain * to associate with a powerdomain
488  *
489  * Dissociate the clockdomain @clkdm from the powerdomain
490  * @pwrdm. Returns -EINVAL if presented with invalid pointers; -ENOENT
491  * if @clkdm was not associated with the powerdomain, or 0 upon
492  * success.
493  */
494 int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
495 {
496         int ret = -EINVAL;
497         int i;
498 
499         if (!pwrdm || !clkdm)
500                 return -EINVAL;
501 
502         pr_debug("powerdomain: %s: dissociating clockdomain %s\n",
503                  pwrdm->name, clkdm->name);
504 
505         for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
506                 if (pwrdm->pwrdm_clkdms[i] == clkdm)
507                         break;
508 
509         if (i == PWRDM_MAX_CLKDMS) {
510                 pr_debug("powerdomain: %s: clkdm %s not associated?!\n",
511                          pwrdm->name, clkdm->name);
512                 ret = -ENOENT;
513                 goto pdc_exit;
514         }
515 
516         pwrdm->pwrdm_clkdms[i] = NULL;
517 
518         ret = 0;
519 
520 pdc_exit:
521         return ret;
522 }
523 
524 /**
525  * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
526  * @pwrdm: struct powerdomain * to iterate over
527  * @fn: callback function *
528  *
529  * Call the supplied function @fn for each clockdomain in the powerdomain
530  * @pwrdm.  The callback function can return anything but 0 to bail
531  * out early from the iterator.  Returns -EINVAL if presented with
532  * invalid pointers; or passes along the last return value of the
533  * callback function, which should be 0 for success or anything else
534  * to indicate failure.
535  */
536 int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
537                          int (*fn)(struct powerdomain *pwrdm,
538                                    struct clockdomain *clkdm))
539 {
540         int ret = 0;
541         int i;
542 
543         if (!fn)
544                 return -EINVAL;
545 
546         for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
547                 ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
548 
549         return ret;
550 }
551 
552 /**
553  * pwrdm_get_voltdm - return a ptr to the voltdm that this pwrdm resides in
554  * @pwrdm: struct powerdomain *
555  *
556  * Return a pointer to the struct voltageomain that the specified powerdomain
557  * @pwrdm exists in.
558  */
559 struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm)
560 {
561         return pwrdm->voltdm.ptr;
562 }
563 
564 /**
565  * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
566  * @pwrdm: struct powerdomain *
567  *
568  * Return the number of controllable memory banks in powerdomain @pwrdm,
569  * starting with 1.  Returns -EINVAL if the powerdomain pointer is null.
570  */
571 int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
572 {
573         if (!pwrdm)
574                 return -EINVAL;
575 
576         return pwrdm->banks;
577 }
578 
579 /**
580  * pwrdm_set_next_pwrst - set next powerdomain power state
581  * @pwrdm: struct powerdomain * to set
582  * @pwrst: one of the PWRDM_POWER_* macros
583  *
584  * Set the powerdomain @pwrdm's next power state to @pwrst.  The powerdomain
585  * may not enter this state immediately if the preconditions for this state
586  * have not been satisfied.  Returns -EINVAL if the powerdomain pointer is
587  * null or if the power state is invalid for the powerdomin, or returns 0
588  * upon success.
589  */
590 int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
591 {
592         int ret = -EINVAL;
593 
594         if (!pwrdm)
595                 return -EINVAL;
596 
597         if (!(pwrdm->pwrsts & (1 << pwrst)))
598                 return -EINVAL;
599 
600         pr_debug("powerdomain: %s: setting next powerstate to %0x\n",
601                  pwrdm->name, pwrst);
602 
603         if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
604                 /* Trace the pwrdm desired target state */
605                 trace_power_domain_target(pwrdm->name, pwrst,
606                                           smp_processor_id());
607                 /* Program the pwrdm desired target state */
608                 ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
609         }
610 
611         return ret;
612 }
613 
614 /**
615  * pwrdm_read_next_pwrst - get next powerdomain power state
616  * @pwrdm: struct powerdomain * to get power state
617  *
618  * Return the powerdomain @pwrdm's next power state.  Returns -EINVAL
619  * if the powerdomain pointer is null or returns the next power state
620  * upon success.
621  */
622 int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
623 {
624         int ret = -EINVAL;
625 
626         if (!pwrdm)
627                 return -EINVAL;
628 
629         if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst)
630                 ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
631 
632         return ret;
633 }
634 
635 /**
636  * pwrdm_read_pwrst - get current powerdomain power state
637  * @pwrdm: struct powerdomain * to get power state
638  *
639  * Return the powerdomain @pwrdm's current power state. Returns -EINVAL
640  * if the powerdomain pointer is null or returns the current power state
641  * upon success. Note that if the power domain only supports the ON state
642  * then just return ON as the current state.
643  */
644 int pwrdm_read_pwrst(struct powerdomain *pwrdm)
645 {
646         int ret = -EINVAL;
647 
648         if (!pwrdm)
649                 return -EINVAL;
650 
651         if (pwrdm->pwrsts == PWRSTS_ON)
652                 return PWRDM_POWER_ON;
653 
654         if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
655                 ret = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
656 
657         return ret;
658 }
659 
660 /**
661  * pwrdm_read_prev_pwrst - get previous powerdomain power state
662  * @pwrdm: struct powerdomain * to get previous power state
663  *
664  * Return the powerdomain @pwrdm's previous power state.  Returns -EINVAL
665  * if the powerdomain pointer is null or returns the previous power state
666  * upon success.
667  */
668 int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
669 {
670         int ret = -EINVAL;
671 
672         if (!pwrdm)
673                 return -EINVAL;
674 
675         if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst)
676                 ret = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
677 
678         return ret;
679 }
680 
681 /**
682  * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
683  * @pwrdm: struct powerdomain * to set
684  * @pwrst: one of the PWRDM_POWER_* macros
685  *
686  * Set the next power state @pwrst that the logic portion of the
687  * powerdomain @pwrdm will enter when the powerdomain enters retention.
688  * This will be either RETENTION or OFF, if supported.  Returns
689  * -EINVAL if the powerdomain pointer is null or the target power
690  * state is not not supported, or returns 0 upon success.
691  */
692 int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
693 {
694         int ret = -EINVAL;
695 
696         if (!pwrdm)
697                 return -EINVAL;
698 
699         if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
700                 return -EINVAL;
701 
702         pr_debug("powerdomain: %s: setting next logic powerstate to %0x\n",
703                  pwrdm->name, pwrst);
704 
705         if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
706                 ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, pwrst);
707 
708         return ret;
709 }
710 
711 /**
712  * pwrdm_set_mem_onst - set memory power state while powerdomain ON
713  * @pwrdm: struct powerdomain * to set
714  * @bank: memory bank number to set (0-3)
715  * @pwrst: one of the PWRDM_POWER_* macros
716  *
717  * Set the next power state @pwrst that memory bank @bank of the
718  * powerdomain @pwrdm will enter when the powerdomain enters the ON
719  * state.  @bank will be a number from 0 to 3, and represents different
720  * types of memory, depending on the powerdomain.  Returns -EINVAL if
721  * the powerdomain pointer is null or the target power state is not
722  * not supported for this memory bank, -EEXIST if the target memory
723  * bank does not exist or is not controllable, or returns 0 upon
724  * success.
725  */
726 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
727 {
728         int ret = -EINVAL;
729 
730         if (!pwrdm)
731                 return -EINVAL;
732 
733         if (pwrdm->banks < (bank + 1))
734                 return -EEXIST;
735 
736         if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
737                 return -EINVAL;
738 
739         pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
740                  pwrdm->name, bank, pwrst);
741 
742         if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
743                 ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
744 
745         return ret;
746 }
747 
748 /**
749  * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
750  * @pwrdm: struct powerdomain * to set
751  * @bank: memory bank number to set (0-3)
752  * @pwrst: one of the PWRDM_POWER_* macros
753  *
754  * Set the next power state @pwrst that memory bank @bank of the
755  * powerdomain @pwrdm will enter when the powerdomain enters the
756  * RETENTION state.  Bank will be a number from 0 to 3, and represents
757  * different types of memory, depending on the powerdomain.  @pwrst
758  * will be either RETENTION or OFF, if supported.  Returns -EINVAL if
759  * the powerdomain pointer is null or the target power state is not
760  * not supported for this memory bank, -EEXIST if the target memory
761  * bank does not exist or is not controllable, or returns 0 upon
762  * success.
763  */
764 int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
765 {
766         int ret = -EINVAL;
767 
768         if (!pwrdm)
769                 return -EINVAL;
770 
771         if (pwrdm->banks < (bank + 1))
772                 return -EEXIST;
773 
774         if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
775                 return -EINVAL;
776 
777         pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
778                  pwrdm->name, bank, pwrst);
779 
780         if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
781                 ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
782 
783         return ret;
784 }
785 
786 /**
787  * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
788  * @pwrdm: struct powerdomain * to get current logic retention power state
789  *
790  * Return the power state that the logic portion of powerdomain @pwrdm
791  * will enter when the powerdomain enters retention.  Returns -EINVAL
792  * if the powerdomain pointer is null or returns the logic retention
793  * power state upon success.
794  */
795 int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
796 {
797         int ret = -EINVAL;
798 
799         if (!pwrdm)
800                 return -EINVAL;
801 
802         if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst)
803                 ret = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
804 
805         return ret;
806 }
807 
808 /**
809  * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
810  * @pwrdm: struct powerdomain * to get previous logic power state
811  *
812  * Return the powerdomain @pwrdm's previous logic power state.  Returns
813  * -EINVAL if the powerdomain pointer is null or returns the previous
814  * logic power state upon success.
815  */
816 int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
817 {
818         int ret = -EINVAL;
819 
820         if (!pwrdm)
821                 return -EINVAL;
822 
823         if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst)
824                 ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
825 
826         return ret;
827 }
828 
829 /**
830  * pwrdm_read_logic_retst - get next powerdomain logic power state
831  * @pwrdm: struct powerdomain * to get next logic power state
832  *
833  * Return the powerdomain pwrdm's logic power state.  Returns -EINVAL
834  * if the powerdomain pointer is null or returns the next logic
835  * power state upon success.
836  */
837 int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
838 {
839         int ret = -EINVAL;
840 
841         if (!pwrdm)
842                 return -EINVAL;
843 
844         if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst)
845                 ret = arch_pwrdm->pwrdm_read_logic_retst(pwrdm);
846 
847         return ret;
848 }
849 
850 /**
851  * pwrdm_read_mem_pwrst - get current memory bank power state
852  * @pwrdm: struct powerdomain * to get current memory bank power state
853  * @bank: memory bank number (0-3)
854  *
855  * Return the powerdomain @pwrdm's current memory power state for bank
856  * @bank.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
857  * the target memory bank does not exist or is not controllable, or
858  * returns the current memory power state upon success.
859  */
860 int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
861 {
862         int ret = -EINVAL;
863 
864         if (!pwrdm)
865                 return ret;
866 
867         if (pwrdm->banks < (bank + 1))
868                 return ret;
869 
870         if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
871                 bank = 1;
872 
873         if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
874                 ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
875 
876         return ret;
877 }
878 
879 /**
880  * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
881  * @pwrdm: struct powerdomain * to get previous memory bank power state
882  * @bank: memory bank number (0-3)
883  *
884  * Return the powerdomain @pwrdm's previous memory power state for
885  * bank @bank.  Returns -EINVAL if the powerdomain pointer is null,
886  * -EEXIST if the target memory bank does not exist or is not
887  * controllable, or returns the previous memory power state upon
888  * success.
889  */
890 int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
891 {
892         int ret = -EINVAL;
893 
894         if (!pwrdm)
895                 return ret;
896 
897         if (pwrdm->banks < (bank + 1))
898                 return ret;
899 
900         if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
901                 bank = 1;
902 
903         if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
904                 ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
905 
906         return ret;
907 }
908 
909 /**
910  * pwrdm_read_mem_retst - get next memory bank power state
911  * @pwrdm: struct powerdomain * to get mext memory bank power state
912  * @bank: memory bank number (0-3)
913  *
914  * Return the powerdomain pwrdm's next memory power state for bank
915  * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
916  * the target memory bank does not exist or is not controllable, or
917  * returns the next memory power state upon success.
918  */
919 int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
920 {
921         int ret = -EINVAL;
922 
923         if (!pwrdm)
924                 return ret;
925 
926         if (pwrdm->banks < (bank + 1))
927                 return ret;
928 
929         if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
930                 ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
931 
932         return ret;
933 }
934 
935 /**
936  * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
937  * @pwrdm: struct powerdomain * to clear
938  *
939  * Clear the powerdomain's previous power state register @pwrdm.
940  * Clears the entire register, including logic and memory bank
941  * previous power states.  Returns -EINVAL if the powerdomain pointer
942  * is null, or returns 0 upon success.
943  */
944 int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
945 {
946         int ret = -EINVAL;
947 
948         if (!pwrdm)
949                 return ret;
950 
951         /*
952          * XXX should get the powerdomain's current state here;
953          * warn & fail if it is not ON.
954          */
955 
956         pr_debug("powerdomain: %s: clearing previous power state reg\n",
957                  pwrdm->name);
958 
959         if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
960                 ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
961 
962         return ret;
963 }
964 
965 /**
966  * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
967  * @pwrdm: struct powerdomain *
968  *
969  * Enable automatic context save-and-restore upon power state change
970  * for some devices in the powerdomain @pwrdm.  Warning: this only
971  * affects a subset of devices in a powerdomain; check the TRM
972  * closely.  Returns -EINVAL if the powerdomain pointer is null or if
973  * the powerdomain does not support automatic save-and-restore, or
974  * returns 0 upon success.
975  */
976 int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
977 {
978         int ret = -EINVAL;
979 
980         if (!pwrdm)
981                 return ret;
982 
983         if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
984                 return ret;
985 
986         pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n", pwrdm->name);
987 
988         if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
989                 ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
990 
991         return ret;
992 }
993 
994 /**
995  * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
996  * @pwrdm: struct powerdomain *
997  *
998  * Disable automatic context save-and-restore upon power state change
999  * for some devices in the powerdomain @pwrdm.  Warning: this only
1000  * affects a subset of devices in a powerdomain; check the TRM
1001  * closely.  Returns -EINVAL if the powerdomain pointer is null or if
1002  * the powerdomain does not support automatic save-and-restore, or
1003  * returns 0 upon success.
1004  */
1005 int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
1006 {
1007         int ret = -EINVAL;
1008 
1009         if (!pwrdm)
1010                 return ret;
1011 
1012         if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
1013                 return ret;
1014 
1015         pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n", pwrdm->name);
1016 
1017         if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
1018                 ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
1019 
1020         return ret;
1021 }
1022 
1023 /**
1024  * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
1025  * @pwrdm: struct powerdomain *
1026  *
1027  * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore
1028  * for some devices, or 0 if it does not.
1029  */
1030 bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
1031 {
1032         return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
1033 }
1034 
1035 int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
1036 {
1037         int ret;
1038 
1039         if (!pwrdm || !arch_pwrdm)
1040                 return -EINVAL;
1041 
1042         ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
1043         if (!ret)
1044                 ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
1045 
1046         return ret;
1047 }
1048 
1049 int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)
1050 {
1051         int ret;
1052 
1053         pwrdm_lock(pwrdm);
1054         ret = pwrdm_state_switch_nolock(pwrdm);
1055         pwrdm_unlock(pwrdm);
1056 
1057         return ret;
1058 }
1059 
1060 int pwrdm_pre_transition(struct powerdomain *pwrdm)
1061 {
1062         if (pwrdm)
1063                 _pwrdm_pre_transition_cb(pwrdm, NULL);
1064         else
1065                 pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
1066 
1067         return 0;
1068 }
1069 
1070 int pwrdm_post_transition(struct powerdomain *pwrdm)
1071 {
1072         if (pwrdm)
1073                 _pwrdm_post_transition_cb(pwrdm, NULL);
1074         else
1075                 pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
1076 
1077         return 0;
1078 }
1079 
1080 /**
1081  * omap_set_pwrdm_state - change a powerdomain's current power state
1082  * @pwrdm: struct powerdomain * to change the power state of
1083  * @pwrst: power state to change to
1084  *
1085  * Change the current hardware power state of the powerdomain
1086  * represented by @pwrdm to the power state represented by @pwrst.
1087  * Returns -EINVAL if @pwrdm is null or invalid or if the
1088  * powerdomain's current power state could not be read, or returns 0
1089  * upon success or if @pwrdm does not support @pwrst or any
1090  * lower-power state.  XXX Should not return 0 if the @pwrdm does not
1091  * support @pwrst or any lower-power state: this should be an error.
1092  */
1093 int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
1094 {
1095         u8 next_pwrst, sleep_switch;
1096         int curr_pwrst;
1097         int ret = 0;
1098         bool hwsup = false;
1099 
1100         if (!pwrdm || IS_ERR(pwrdm))
1101                 return -EINVAL;
1102 
1103         while (!(pwrdm->pwrsts & (1 << pwrst))) {
1104                 if (pwrst == PWRDM_POWER_OFF)
1105                         return ret;
1106                 pwrst--;
1107         }
1108 
1109         pwrdm_lock(pwrdm);
1110 
1111         curr_pwrst = pwrdm_read_pwrst(pwrdm);
1112         if (curr_pwrst < 0) {
1113                 ret = -EINVAL;
1114                 goto osps_out;
1115         }
1116 
1117         next_pwrst = pwrdm_read_next_pwrst(pwrdm);
1118         if (curr_pwrst == pwrst && next_pwrst == pwrst)
1119                 goto osps_out;
1120 
1121         sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
1122                                                             pwrst, &hwsup);
1123 
1124         ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
1125         if (ret)
1126                 pr_err("%s: unable to set power state of powerdomain: %s\n",
1127                        __func__, pwrdm->name);
1128 
1129         _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
1130 
1131 osps_out:
1132         pwrdm_unlock(pwrdm);
1133 
1134         return ret;
1135 }
1136 
1137 /**
1138  * pwrdm_get_context_loss_count - get powerdomain's context loss count
1139  * @pwrdm: struct powerdomain * to wait for
1140  *
1141  * Context loss count is the sum of powerdomain off-mode counter, the
1142  * logic off counter and the per-bank memory off counter.  Returns negative
1143  * (and WARNs) upon error, otherwise, returns the context loss count.
1144  */
1145 int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
1146 {
1147         int i, count;
1148 
1149         if (!pwrdm) {
1150                 WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
1151                 return -ENODEV;
1152         }
1153 
1154         count = pwrdm->state_counter[PWRDM_POWER_OFF];
1155         count += pwrdm->ret_logic_off_counter;
1156 
1157         for (i = 0; i < pwrdm->banks; i++)
1158                 count += pwrdm->ret_mem_off_counter[i];
1159 
1160         /*
1161          * Context loss count has to be a non-negative value. Clear the sign
1162          * bit to get a value range from 0 to INT_MAX.
1163          */
1164         count &= INT_MAX;
1165 
1166         pr_debug("powerdomain: %s: context loss count = %d\n",
1167                  pwrdm->name, count);
1168 
1169         return count;
1170 }
1171 
1172 /**
1173  * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
1174  * @pwrdm: struct powerdomain *
1175  *
1176  * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
1177  * can lose either memory or logic context or if @pwrdm is invalid, or
1178  * returns 0 otherwise.  This function is not concerned with how the
1179  * powerdomain registers are programmed (i.e., to go off or not); it's
1180  * concerned with whether it's ever possible for this powerdomain to
1181  * go off while some other part of the chip is active.  This function
1182  * assumes that every powerdomain can go to either ON or INACTIVE.
1183  */
1184 bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
1185 {
1186         int i;
1187 
1188         if (!pwrdm) {
1189                 pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
1190                          __func__);
1191                 return 1;
1192         }
1193 
1194         if (pwrdm->pwrsts & PWRSTS_OFF)
1195                 return 1;
1196 
1197         if (pwrdm->pwrsts & PWRSTS_RET) {
1198                 if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
1199                         return 1;
1200 
1201                 for (i = 0; i < pwrdm->banks; i++)
1202                         if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
1203                                 return 1;
1204         }
1205 
1206         for (i = 0; i < pwrdm->banks; i++)
1207                 if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
1208                         return 1;
1209 
1210         return 0;
1211 }
1212 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp