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