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

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

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

~ [ 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