0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #undef DEBUG
0013
0014 #include <linux/cpu_pm.h>
0015 #include <linux/kernel.h>
0016 #include <linux/types.h>
0017 #include <linux/list.h>
0018 #include <linux/errno.h>
0019 #include <linux/string.h>
0020 #include <linux/spinlock.h>
0021 #include <trace/events/power.h>
0022
0023 #include "cm2xxx_3xxx.h"
0024 #include "prcm44xx.h"
0025 #include "cm44xx.h"
0026 #include "prm2xxx_3xxx.h"
0027 #include "prm44xx.h"
0028
0029 #include <asm/cpu.h>
0030
0031 #include "powerdomain.h"
0032 #include "clockdomain.h"
0033 #include "voltage.h"
0034
0035 #include "soc.h"
0036 #include "pm.h"
0037
0038 #define PWRDM_TRACE_STATES_FLAG (1<<31)
0039
0040 void pwrdms_save_context(void);
0041 void pwrdms_restore_context(void);
0042
0043 enum {
0044 PWRDM_STATE_NOW = 0,
0045 PWRDM_STATE_PREV,
0046 };
0047
0048
0049
0050
0051
0052
0053
0054 #define ALREADYACTIVE_SWITCH 0
0055 #define FORCEWAKEUP_SWITCH 1
0056 #define LOWPOWERSTATE_SWITCH 2
0057
0058
0059 static LIST_HEAD(pwrdm_list);
0060
0061 static struct pwrdm_ops *arch_pwrdm;
0062
0063
0064
0065 static struct powerdomain *_pwrdm_lookup(const char *name)
0066 {
0067 struct powerdomain *pwrdm, *temp_pwrdm;
0068
0069 pwrdm = NULL;
0070
0071 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
0072 if (!strcmp(name, temp_pwrdm->name)) {
0073 pwrdm = temp_pwrdm;
0074 break;
0075 }
0076 }
0077
0078 return pwrdm;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 static int _pwrdm_register(struct powerdomain *pwrdm)
0090 {
0091 int i;
0092 struct voltagedomain *voltdm;
0093
0094 if (!pwrdm || !pwrdm->name)
0095 return -EINVAL;
0096
0097 if (cpu_is_omap44xx() &&
0098 pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) {
0099 pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n",
0100 pwrdm->name);
0101 return -EINVAL;
0102 }
0103
0104 if (_pwrdm_lookup(pwrdm->name))
0105 return -EEXIST;
0106
0107 if (arch_pwrdm && arch_pwrdm->pwrdm_has_voltdm)
0108 if (!arch_pwrdm->pwrdm_has_voltdm())
0109 goto skip_voltdm;
0110
0111 voltdm = voltdm_lookup(pwrdm->voltdm.name);
0112 if (!voltdm) {
0113 pr_err("powerdomain: %s: voltagedomain %s does not exist\n",
0114 pwrdm->name, pwrdm->voltdm.name);
0115 return -EINVAL;
0116 }
0117 pwrdm->voltdm.ptr = voltdm;
0118 INIT_LIST_HEAD(&pwrdm->voltdm_node);
0119 skip_voltdm:
0120 spin_lock_init(&pwrdm->_lock);
0121
0122 list_add(&pwrdm->node, &pwrdm_list);
0123
0124
0125 for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
0126 pwrdm->state_counter[i] = 0;
0127
0128 pwrdm->ret_logic_off_counter = 0;
0129 for (i = 0; i < pwrdm->banks; i++)
0130 pwrdm->ret_mem_off_counter[i] = 0;
0131
0132 if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition)
0133 arch_pwrdm->pwrdm_wait_transition(pwrdm);
0134 pwrdm->state = pwrdm_read_pwrst(pwrdm);
0135 pwrdm->state_counter[pwrdm->state] = 1;
0136
0137 pr_debug("powerdomain: registered %s\n", pwrdm->name);
0138
0139 return 0;
0140 }
0141
0142 static void _update_logic_membank_counters(struct powerdomain *pwrdm)
0143 {
0144 int i;
0145 u8 prev_logic_pwrst, prev_mem_pwrst;
0146
0147 prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
0148 if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
0149 (prev_logic_pwrst == PWRDM_POWER_OFF))
0150 pwrdm->ret_logic_off_counter++;
0151
0152 for (i = 0; i < pwrdm->banks; i++) {
0153 prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
0154
0155 if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
0156 (prev_mem_pwrst == PWRDM_POWER_OFF))
0157 pwrdm->ret_mem_off_counter[i]++;
0158 }
0159 }
0160
0161 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
0162 {
0163
0164 int prev, next, state, trace_state = 0;
0165
0166 if (pwrdm == NULL)
0167 return -EINVAL;
0168
0169 state = pwrdm_read_pwrst(pwrdm);
0170
0171 switch (flag) {
0172 case PWRDM_STATE_NOW:
0173 prev = pwrdm->state;
0174 break;
0175 case PWRDM_STATE_PREV:
0176 prev = pwrdm_read_prev_pwrst(pwrdm);
0177 if (pwrdm->state != prev)
0178 pwrdm->state_counter[prev]++;
0179 if (prev == PWRDM_POWER_RET)
0180 _update_logic_membank_counters(pwrdm);
0181
0182
0183
0184
0185 next = pwrdm_read_next_pwrst(pwrdm);
0186 if (next != prev) {
0187 trace_state = (PWRDM_TRACE_STATES_FLAG |
0188 ((next & OMAP_POWERSTATE_MASK) << 8) |
0189 ((prev & OMAP_POWERSTATE_MASK) << 0));
0190 trace_power_domain_target_rcuidle(pwrdm->name,
0191 trace_state,
0192 raw_smp_processor_id());
0193 }
0194 break;
0195 default:
0196 return -EINVAL;
0197 }
0198
0199 if (state != prev)
0200 pwrdm->state_counter[state]++;
0201
0202 pm_dbg_update_time(pwrdm, prev);
0203
0204 pwrdm->state = state;
0205
0206 return 0;
0207 }
0208
0209 static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
0210 {
0211 pwrdm_clear_all_prev_pwrst(pwrdm);
0212 _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
0213 return 0;
0214 }
0215
0216 static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
0217 {
0218 _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
0219 return 0;
0220 }
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
0237 u8 curr_pwrst, u8 pwrst)
0238 {
0239 u8 sleep_switch;
0240
0241 if (curr_pwrst < PWRDM_POWER_ON) {
0242 if (curr_pwrst > pwrst &&
0243 pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
0244 arch_pwrdm->pwrdm_set_lowpwrstchange) {
0245 sleep_switch = LOWPOWERSTATE_SWITCH;
0246 } else {
0247 clkdm_deny_idle_nolock(pwrdm->pwrdm_clkdms[0]);
0248 sleep_switch = FORCEWAKEUP_SWITCH;
0249 }
0250 } else {
0251 sleep_switch = ALREADYACTIVE_SWITCH;
0252 }
0253
0254 return sleep_switch;
0255 }
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270 static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
0271 u8 sleep_switch)
0272 {
0273 switch (sleep_switch) {
0274 case FORCEWAKEUP_SWITCH:
0275 clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]);
0276 break;
0277 case LOWPOWERSTATE_SWITCH:
0278 if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
0279 arch_pwrdm->pwrdm_set_lowpwrstchange)
0280 arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
0281 pwrdm_state_switch_nolock(pwrdm);
0282 break;
0283 }
0284 }
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298 int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
0299 {
0300 if (!po)
0301 return -EINVAL;
0302
0303 if (arch_pwrdm)
0304 return -EEXIST;
0305
0306 arch_pwrdm = po;
0307
0308 return 0;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321 int pwrdm_register_pwrdms(struct powerdomain **ps)
0322 {
0323 struct powerdomain **p = NULL;
0324
0325 if (!arch_pwrdm)
0326 return -EEXIST;
0327
0328 if (!ps)
0329 return -EINVAL;
0330
0331 for (p = ps; *p; p++)
0332 _pwrdm_register(*p);
0333
0334 return 0;
0335 }
0336
0337 static int cpu_notifier(struct notifier_block *nb, unsigned long cmd, void *v)
0338 {
0339 switch (cmd) {
0340 case CPU_CLUSTER_PM_ENTER:
0341 if (enable_off_mode)
0342 pwrdms_save_context();
0343 break;
0344 case CPU_CLUSTER_PM_EXIT:
0345 if (enable_off_mode)
0346 pwrdms_restore_context();
0347 break;
0348 }
0349
0350 return NOTIFY_OK;
0351 }
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364 int pwrdm_complete_init(void)
0365 {
0366 struct powerdomain *temp_p;
0367 static struct notifier_block nb;
0368
0369 if (list_empty(&pwrdm_list))
0370 return -EACCES;
0371
0372 list_for_each_entry(temp_p, &pwrdm_list, node)
0373 pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
0374
0375
0376 if (soc_is_am43xx()) {
0377 nb.notifier_call = cpu_notifier;
0378 cpu_pm_register_notifier(&nb);
0379 }
0380
0381 return 0;
0382 }
0383
0384
0385
0386
0387
0388
0389
0390 void pwrdm_lock(struct powerdomain *pwrdm)
0391 __acquires(&pwrdm->_lock)
0392 {
0393 spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags);
0394 }
0395
0396
0397
0398
0399
0400
0401
0402 void pwrdm_unlock(struct powerdomain *pwrdm)
0403 __releases(&pwrdm->_lock)
0404 {
0405 spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags);
0406 }
0407
0408
0409
0410
0411
0412
0413
0414
0415 struct powerdomain *pwrdm_lookup(const char *name)
0416 {
0417 struct powerdomain *pwrdm;
0418
0419 if (!name)
0420 return NULL;
0421
0422 pwrdm = _pwrdm_lookup(name);
0423
0424 return pwrdm;
0425 }
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437 int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
0438 void *user)
0439 {
0440 struct powerdomain *temp_pwrdm;
0441 int ret = 0;
0442
0443 if (!fn)
0444 return -EINVAL;
0445
0446 list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
0447 ret = (*fn)(temp_pwrdm, user);
0448 if (ret)
0449 break;
0450 }
0451
0452 return ret;
0453 }
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465 int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
0466 {
0467 int i;
0468 int ret = -EINVAL;
0469
0470 if (!pwrdm || !clkdm)
0471 return -EINVAL;
0472
0473 pr_debug("powerdomain: %s: associating clockdomain %s\n",
0474 pwrdm->name, clkdm->name);
0475
0476 for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
0477 if (!pwrdm->pwrdm_clkdms[i])
0478 break;
0479 #ifdef DEBUG
0480 if (pwrdm->pwrdm_clkdms[i] == clkdm) {
0481 ret = -EINVAL;
0482 goto pac_exit;
0483 }
0484 #endif
0485 }
0486
0487 if (i == PWRDM_MAX_CLKDMS) {
0488 pr_debug("powerdomain: %s: increase PWRDM_MAX_CLKDMS for clkdm %s\n",
0489 pwrdm->name, clkdm->name);
0490 WARN_ON(1);
0491 ret = -ENOMEM;
0492 goto pac_exit;
0493 }
0494
0495 pwrdm->pwrdm_clkdms[i] = clkdm;
0496
0497 ret = 0;
0498
0499 pac_exit:
0500 return ret;
0501 }
0502
0503
0504
0505
0506
0507
0508
0509
0510 int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
0511 {
0512 if (!pwrdm)
0513 return -EINVAL;
0514
0515 return pwrdm->banks;
0516 }
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529 int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
0530 {
0531 int ret = -EINVAL;
0532
0533 if (!pwrdm)
0534 return -EINVAL;
0535
0536 if (!(pwrdm->pwrsts & (1 << pwrst)))
0537 return -EINVAL;
0538
0539 pr_debug("powerdomain: %s: setting next powerstate to %0x\n",
0540 pwrdm->name, pwrst);
0541
0542 if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
0543
0544 trace_power_domain_target_rcuidle(pwrdm->name, pwrst,
0545 raw_smp_processor_id());
0546
0547 ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
0548 }
0549
0550 return ret;
0551 }
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561 int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
0562 {
0563 int ret = -EINVAL;
0564
0565 if (!pwrdm)
0566 return -EINVAL;
0567
0568 if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst)
0569 ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
0570
0571 return ret;
0572 }
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583 int pwrdm_read_pwrst(struct powerdomain *pwrdm)
0584 {
0585 int ret = -EINVAL;
0586
0587 if (!pwrdm)
0588 return -EINVAL;
0589
0590 if (pwrdm->pwrsts == PWRSTS_ON)
0591 return PWRDM_POWER_ON;
0592
0593 if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
0594 ret = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
0595
0596 return ret;
0597 }
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607 int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
0608 {
0609 int ret = -EINVAL;
0610
0611 if (!pwrdm)
0612 return -EINVAL;
0613
0614 if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst)
0615 ret = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
0616
0617 return ret;
0618 }
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631 int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
0632 {
0633 int ret = -EINVAL;
0634
0635 if (!pwrdm)
0636 return -EINVAL;
0637
0638 if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
0639 return -EINVAL;
0640
0641 pr_debug("powerdomain: %s: setting next logic powerstate to %0x\n",
0642 pwrdm->name, pwrst);
0643
0644 if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
0645 ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, pwrst);
0646
0647 return ret;
0648 }
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
0666 {
0667 int ret = -EINVAL;
0668
0669 if (!pwrdm)
0670 return -EINVAL;
0671
0672 if (pwrdm->banks < (bank + 1))
0673 return -EEXIST;
0674
0675 if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
0676 return -EINVAL;
0677
0678 pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
0679 pwrdm->name, bank, pwrst);
0680
0681 if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
0682 ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
0683
0684 return ret;
0685 }
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703 int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
0704 {
0705 int ret = -EINVAL;
0706
0707 if (!pwrdm)
0708 return -EINVAL;
0709
0710 if (pwrdm->banks < (bank + 1))
0711 return -EEXIST;
0712
0713 if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
0714 return -EINVAL;
0715
0716 pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
0717 pwrdm->name, bank, pwrst);
0718
0719 if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
0720 ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
0721
0722 return ret;
0723 }
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734 int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
0735 {
0736 int ret = -EINVAL;
0737
0738 if (!pwrdm)
0739 return -EINVAL;
0740
0741 if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst)
0742 ret = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
0743
0744 return ret;
0745 }
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755 int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
0756 {
0757 int ret = -EINVAL;
0758
0759 if (!pwrdm)
0760 return -EINVAL;
0761
0762 if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst)
0763 ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
0764
0765 return ret;
0766 }
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776 int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
0777 {
0778 int ret = -EINVAL;
0779
0780 if (!pwrdm)
0781 return -EINVAL;
0782
0783 if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst)
0784 ret = arch_pwrdm->pwrdm_read_logic_retst(pwrdm);
0785
0786 return ret;
0787 }
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799 int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
0800 {
0801 int ret = -EINVAL;
0802
0803 if (!pwrdm)
0804 return ret;
0805
0806 if (pwrdm->banks < (bank + 1))
0807 return ret;
0808
0809 if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
0810 bank = 1;
0811
0812 if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
0813 ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
0814
0815 return ret;
0816 }
0817
0818
0819
0820
0821
0822
0823
0824
0825
0826
0827
0828
0829 int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
0830 {
0831 int ret = -EINVAL;
0832
0833 if (!pwrdm)
0834 return ret;
0835
0836 if (pwrdm->banks < (bank + 1))
0837 return ret;
0838
0839 if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
0840 bank = 1;
0841
0842 if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
0843 ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
0844
0845 return ret;
0846 }
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857
0858 int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
0859 {
0860 int ret = -EINVAL;
0861
0862 if (!pwrdm)
0863 return ret;
0864
0865 if (pwrdm->banks < (bank + 1))
0866 return ret;
0867
0868 if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
0869 ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
0870
0871 return ret;
0872 }
0873
0874
0875
0876
0877
0878
0879
0880
0881
0882
0883 int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
0884 {
0885 int ret = -EINVAL;
0886
0887 if (!pwrdm)
0888 return ret;
0889
0890
0891
0892
0893
0894
0895 pr_debug("powerdomain: %s: clearing previous power state reg\n",
0896 pwrdm->name);
0897
0898 if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
0899 ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
0900
0901 return ret;
0902 }
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915 int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
0916 {
0917 int ret = -EINVAL;
0918
0919 if (!pwrdm)
0920 return ret;
0921
0922 if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
0923 return ret;
0924
0925 pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n", pwrdm->name);
0926
0927 if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
0928 ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
0929
0930 return ret;
0931 }
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944 int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
0945 {
0946 int ret = -EINVAL;
0947
0948 if (!pwrdm)
0949 return ret;
0950
0951 if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
0952 return ret;
0953
0954 pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n", pwrdm->name);
0955
0956 if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
0957 ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
0958
0959 return ret;
0960 }
0961
0962
0963
0964
0965
0966
0967
0968
0969 bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
0970 {
0971 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
0972 }
0973
0974 int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
0975 {
0976 int ret;
0977
0978 if (!pwrdm || !arch_pwrdm)
0979 return -EINVAL;
0980
0981 ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
0982 if (!ret)
0983 ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
0984
0985 return ret;
0986 }
0987
0988 int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)
0989 {
0990 int ret;
0991
0992 pwrdm_lock(pwrdm);
0993 ret = pwrdm_state_switch_nolock(pwrdm);
0994 pwrdm_unlock(pwrdm);
0995
0996 return ret;
0997 }
0998
0999 int pwrdm_pre_transition(struct powerdomain *pwrdm)
1000 {
1001 if (pwrdm)
1002 _pwrdm_pre_transition_cb(pwrdm, NULL);
1003 else
1004 pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
1005
1006 return 0;
1007 }
1008
1009 int pwrdm_post_transition(struct powerdomain *pwrdm)
1010 {
1011 if (pwrdm)
1012 _pwrdm_post_transition_cb(pwrdm, NULL);
1013 else
1014 pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
1015
1016 return 0;
1017 }
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042 u8 pwrdm_get_valid_lp_state(struct powerdomain *pwrdm,
1043 bool is_logic_state, u8 req_state)
1044 {
1045 u8 pwrdm_states = is_logic_state ? pwrdm->pwrsts_logic_ret :
1046 pwrdm->pwrsts;
1047
1048 u8 default_pwrst = is_logic_state ? PWRDM_POWER_RET : PWRDM_POWER_ON;
1049 u8 new_pwrst;
1050 bool found;
1051
1052
1053 if (pwrdm_states & BIT(req_state))
1054 return req_state;
1055
1056 if (!req_state)
1057 goto up_search;
1058
1059
1060
1061
1062
1063 new_pwrst = req_state - 1;
1064 found = true;
1065 while (!(pwrdm_states & BIT(new_pwrst))) {
1066
1067 if (new_pwrst == PWRDM_POWER_OFF) {
1068 found = false;
1069 break;
1070 }
1071 new_pwrst--;
1072 }
1073
1074 if (found)
1075 goto done;
1076
1077 up_search:
1078
1079 new_pwrst = req_state + 1;
1080 while (!(pwrdm_states & BIT(new_pwrst))) {
1081 if (new_pwrst > PWRDM_POWER_ON) {
1082 WARN(1, "powerdomain: %s: Fix max powerstate to ON\n",
1083 pwrdm->name);
1084 return PWRDM_POWER_ON;
1085 }
1086
1087 if (new_pwrst == default_pwrst)
1088 break;
1089 new_pwrst++;
1090 }
1091 done:
1092 return new_pwrst;
1093 }
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108 int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
1109 {
1110 u8 next_pwrst, sleep_switch;
1111 int curr_pwrst;
1112 int ret = 0;
1113
1114 if (!pwrdm || IS_ERR(pwrdm))
1115 return -EINVAL;
1116
1117 while (!(pwrdm->pwrsts & (1 << pwrst))) {
1118 if (pwrst == PWRDM_POWER_OFF)
1119 return ret;
1120 pwrst--;
1121 }
1122
1123 pwrdm_lock(pwrdm);
1124
1125 curr_pwrst = pwrdm_read_pwrst(pwrdm);
1126 if (curr_pwrst < 0) {
1127 ret = -EINVAL;
1128 goto osps_out;
1129 }
1130
1131 next_pwrst = pwrdm_read_next_pwrst(pwrdm);
1132 if (curr_pwrst == pwrst && next_pwrst == pwrst)
1133 goto osps_out;
1134
1135 sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
1136 pwrst);
1137
1138 ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
1139 if (ret)
1140 pr_err("%s: unable to set power state of powerdomain: %s\n",
1141 __func__, pwrdm->name);
1142
1143 _pwrdm_restore_clkdm_state(pwrdm, sleep_switch);
1144
1145 osps_out:
1146 pwrdm_unlock(pwrdm);
1147
1148 return ret;
1149 }
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
1160 {
1161 int i, count;
1162
1163 if (!pwrdm) {
1164 WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
1165 return -ENODEV;
1166 }
1167
1168 count = pwrdm->state_counter[PWRDM_POWER_OFF];
1169 count += pwrdm->ret_logic_off_counter;
1170
1171 for (i = 0; i < pwrdm->banks; i++)
1172 count += pwrdm->ret_mem_off_counter[i];
1173
1174
1175
1176
1177
1178 count &= INT_MAX;
1179
1180 pr_debug("powerdomain: %s: context loss count = %d\n",
1181 pwrdm->name, count);
1182
1183 return count;
1184 }
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198 bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
1199 {
1200 int i;
1201
1202 if (!pwrdm) {
1203 pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
1204 __func__);
1205 return true;
1206 }
1207
1208 if (pwrdm->pwrsts & PWRSTS_OFF)
1209 return true;
1210
1211 if (pwrdm->pwrsts & PWRSTS_RET) {
1212 if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
1213 return true;
1214
1215 for (i = 0; i < pwrdm->banks; i++)
1216 if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
1217 return true;
1218 }
1219
1220 for (i = 0; i < pwrdm->banks; i++)
1221 if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
1222 return true;
1223
1224 return false;
1225 }
1226
1227
1228
1229
1230
1231
1232
1233 static int pwrdm_save_context(struct powerdomain *pwrdm, void *unused)
1234 {
1235 if (arch_pwrdm && arch_pwrdm->pwrdm_save_context)
1236 arch_pwrdm->pwrdm_save_context(pwrdm);
1237 return 0;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246 static int pwrdm_restore_context(struct powerdomain *pwrdm, void *unused)
1247 {
1248 if (arch_pwrdm && arch_pwrdm->pwrdm_restore_context)
1249 arch_pwrdm->pwrdm_restore_context(pwrdm);
1250 return 0;
1251 }
1252
1253 static int pwrdm_lost_power(struct powerdomain *pwrdm, void *unused)
1254 {
1255 int state;
1256
1257
1258
1259
1260
1261
1262 state = pwrdm_read_pwrst(pwrdm);
1263 if (state != PWRDM_POWER_OFF) {
1264 pwrdm->state_counter[state]++;
1265 pwrdm->state_counter[PWRDM_POWER_OFF]++;
1266 }
1267 pwrdm->state = state;
1268
1269 return 0;
1270 }
1271
1272 void pwrdms_save_context(void)
1273 {
1274 pwrdm_for_each(pwrdm_save_context, NULL);
1275 }
1276
1277 void pwrdms_restore_context(void)
1278 {
1279 pwrdm_for_each(pwrdm_restore_context, NULL);
1280 }
1281
1282 void pwrdms_lost_power(void)
1283 {
1284 pwrdm_for_each(pwrdm_lost_power, NULL);
1285 }