linux/arch/arm/mach-omap2/powerdomain.c
<<
>>
Prefs
   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/module.h>
  19#include <linux/types.h>
  20#include <linux/delay.h>
  21#include <linux/spinlock.h>
  22#include <linux/list.h>
  23#include <linux/errno.h>
  24#include <linux/err.h>
  25#include <linux/io.h>
  26
  27#include <asm/atomic.h>
  28
  29#include "cm.h"
  30#include "cm-regbits-34xx.h"
  31#include "cm-regbits-44xx.h"
  32#include "prm.h"
  33#include "prm-regbits-34xx.h"
  34#include "prm-regbits-44xx.h"
  35
  36#include <plat/cpu.h>
  37#include <plat/powerdomain.h>
  38#include <plat/clockdomain.h>
  39#include <plat/prcm.h>
  40
  41#include "pm.h"
  42
  43enum {
  44        PWRDM_STATE_NOW = 0,
  45        PWRDM_STATE_PREV,
  46};
  47
  48/* Variable holding value of the CPU dependent PWRSTCTRL Register Offset */
  49static u16 pwrstctrl_reg_offs;
  50
  51/* Variable holding value of the CPU dependent PWRSTST Register Offset */
  52static u16 pwrstst_reg_offs;
  53
  54/* OMAP3 and OMAP4 specific register bit initialisations
  55 * Notice that the names here are not according to each power
  56 * domain but the bit mapping used applies to all of them
  57 */
  58
  59/* OMAP3 and OMAP4 Memory Onstate Masks (common across all power domains) */
  60#define OMAP_MEM0_ONSTATE_MASK OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK
  61#define OMAP_MEM1_ONSTATE_MASK OMAP3430_L1FLATMEMONSTATE_MASK
  62#define OMAP_MEM2_ONSTATE_MASK OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK
  63#define OMAP_MEM3_ONSTATE_MASK OMAP3430_L2FLATMEMONSTATE_MASK
  64#define OMAP_MEM4_ONSTATE_MASK OMAP4430_OCP_NRET_BANK_ONSTATE_MASK
  65
  66/* OMAP3 and OMAP4 Memory Retstate Masks (common across all power domains) */
  67#define OMAP_MEM0_RETSTATE_MASK OMAP3430_SHAREDL1CACHEFLATRETSTATE_MASK
  68#define OMAP_MEM1_RETSTATE_MASK OMAP3430_L1FLATMEMRETSTATE_MASK
  69#define OMAP_MEM2_RETSTATE_MASK OMAP3430_SHAREDL2CACHEFLATRETSTATE_MASK
  70#define OMAP_MEM3_RETSTATE_MASK OMAP3430_L2FLATMEMRETSTATE_MASK
  71#define OMAP_MEM4_RETSTATE_MASK OMAP4430_OCP_NRET_BANK_RETSTATE_MASK
  72
  73/* OMAP3 and OMAP4 Memory Status bits */
  74#define OMAP_MEM0_STATEST_MASK OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK
  75#define OMAP_MEM1_STATEST_MASK OMAP3430_L1FLATMEMSTATEST_MASK
  76#define OMAP_MEM2_STATEST_MASK OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK
  77#define OMAP_MEM3_STATEST_MASK OMAP3430_L2FLATMEMSTATEST_MASK
  78#define OMAP_MEM4_STATEST_MASK OMAP4430_OCP_NRET_BANK_STATEST_MASK
  79
  80/* pwrdm_list contains all registered struct powerdomains */
  81static LIST_HEAD(pwrdm_list);
  82
  83/* Private functions */
  84
  85static struct powerdomain *_pwrdm_lookup(const char *name)
  86{
  87        struct powerdomain *pwrdm, *temp_pwrdm;
  88
  89        pwrdm = NULL;
  90
  91        list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
  92                if (!strcmp(name, temp_pwrdm->name)) {
  93                        pwrdm = temp_pwrdm;
  94                        break;
  95                }
  96        }
  97
  98        return pwrdm;
  99}
 100
 101/**
 102 * _pwrdm_register - register a powerdomain
 103 * @pwrdm: struct powerdomain * to register
 104 *
 105 * Adds a powerdomain to the internal powerdomain list.  Returns
 106 * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
 107 * already registered by the provided name, or 0 upon success.
 108 */
 109static int _pwrdm_register(struct powerdomain *pwrdm)
 110{
 111        int i;
 112
 113        if (!pwrdm)
 114                return -EINVAL;
 115
 116        if (!omap_chip_is(pwrdm->omap_chip))
 117                return -EINVAL;
 118
 119        if (_pwrdm_lookup(pwrdm->name))
 120                return -EEXIST;
 121
 122        list_add(&pwrdm->node, &pwrdm_list);
 123
 124        /* Initialize the powerdomain's state counter */
 125        for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
 126                pwrdm->state_counter[i] = 0;
 127
 128        pwrdm->ret_logic_off_counter = 0;
 129        for (i = 0; i < pwrdm->banks; i++)
 130                pwrdm->ret_mem_off_counter[i] = 0;
 131
 132        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
 141static 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
 160static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 161{
 162
 163        int prev;
 164        int state;
 165
 166        if (pwrdm == NULL)
 167                return -EINVAL;
 168
 169        state = pwrdm_read_pwrst(pwrdm);
 170
 171        switch (flag) {
 172        case PWRDM_STATE_NOW:
 173                prev = pwrdm->state;
 174                break;
 175        case PWRDM_STATE_PREV:
 176                prev = pwrdm_read_prev_pwrst(pwrdm);
 177                if (pwrdm->state != prev)
 178                        pwrdm->state_counter[prev]++;
 179                if (prev == PWRDM_POWER_RET)
 180                        _update_logic_membank_counters(pwrdm);
 181                break;
 182        default:
 183                return -EINVAL;
 184        }
 185
 186        if (state != prev)
 187                pwrdm->state_counter[state]++;
 188
 189        pm_dbg_update_time(pwrdm, prev);
 190
 191        pwrdm->state = state;
 192
 193        return 0;
 194}
 195
 196static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
 197{
 198        pwrdm_clear_all_prev_pwrst(pwrdm);
 199        _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
 200        return 0;
 201}
 202
 203static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 204{
 205        _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
 206        return 0;
 207}
 208
 209/* Public functions */
 210
 211/**
 212 * pwrdm_init - set up the powerdomain layer
 213 * @pwrdm_list: array of struct powerdomain pointers to register
 214 *
 215 * Loop through the array of powerdomains @pwrdm_list, registering all
 216 * that are available on the current CPU. If pwrdm_list is supplied
 217 * and not null, all of the referenced powerdomains will be
 218 * registered.  No return value.  XXX pwrdm_list is not really a
 219 * "list"; it is an array.  Rename appropriately.
 220 */
 221void pwrdm_init(struct powerdomain **pwrdm_list)
 222{
 223        struct powerdomain **p = NULL;
 224
 225        if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
 226                pwrstctrl_reg_offs = OMAP2_PM_PWSTCTRL;
 227                pwrstst_reg_offs = OMAP2_PM_PWSTST;
 228        } else if (cpu_is_omap44xx()) {
 229                pwrstctrl_reg_offs = OMAP4_PM_PWSTCTRL;
 230                pwrstst_reg_offs = OMAP4_PM_PWSTST;
 231        } else {
 232                printk(KERN_ERR "Power Domain struct not supported for " \
 233                                                        "this CPU\n");
 234                return;
 235        }
 236
 237        if (pwrdm_list) {
 238                for (p = pwrdm_list; *p; p++)
 239                        _pwrdm_register(*p);
 240        }
 241}
 242
 243/**
 244 * pwrdm_lookup - look up a powerdomain by name, return a pointer
 245 * @name: name of powerdomain
 246 *
 247 * Find a registered powerdomain by its name @name.  Returns a pointer
 248 * to the struct powerdomain if found, or NULL otherwise.
 249 */
 250struct powerdomain *pwrdm_lookup(const char *name)
 251{
 252        struct powerdomain *pwrdm;
 253
 254        if (!name)
 255                return NULL;
 256
 257        pwrdm = _pwrdm_lookup(name);
 258
 259        return pwrdm;
 260}
 261
 262/**
 263 * pwrdm_for_each - call function on each registered clockdomain
 264 * @fn: callback function *
 265 *
 266 * Call the supplied function @fn for each registered powerdomain.
 267 * The callback function @fn can return anything but 0 to bail out
 268 * early from the iterator.  Returns the last return value of the
 269 * callback function, which should be 0 for success or anything else
 270 * to indicate failure; or -EINVAL if the function pointer is null.
 271 */
 272int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
 273                   void *user)
 274{
 275        struct powerdomain *temp_pwrdm;
 276        int ret = 0;
 277
 278        if (!fn)
 279                return -EINVAL;
 280
 281        list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
 282                ret = (*fn)(temp_pwrdm, user);
 283                if (ret)
 284                        break;
 285        }
 286
 287        return ret;
 288}
 289
 290/**
 291 * pwrdm_add_clkdm - add a clockdomain to a powerdomain
 292 * @pwrdm: struct powerdomain * to add the clockdomain to
 293 * @clkdm: struct clockdomain * to associate with a powerdomain
 294 *
 295 * Associate the clockdomain @clkdm with a powerdomain @pwrdm.  This
 296 * enables the use of pwrdm_for_each_clkdm().  Returns -EINVAL if
 297 * presented with invalid pointers; -ENOMEM if memory could not be allocated;
 298 * or 0 upon success.
 299 */
 300int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
 301{
 302        int i;
 303        int ret = -EINVAL;
 304
 305        if (!pwrdm || !clkdm)
 306                return -EINVAL;
 307
 308        pr_debug("powerdomain: associating clockdomain %s with powerdomain "
 309                 "%s\n", clkdm->name, pwrdm->name);
 310
 311        for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
 312                if (!pwrdm->pwrdm_clkdms[i])
 313                        break;
 314#ifdef DEBUG
 315                if (pwrdm->pwrdm_clkdms[i] == clkdm) {
 316                        ret = -EINVAL;
 317                        goto pac_exit;
 318                }
 319#endif
 320        }
 321
 322        if (i == PWRDM_MAX_CLKDMS) {
 323                pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
 324                         "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
 325                WARN_ON(1);
 326                ret = -ENOMEM;
 327                goto pac_exit;
 328        }
 329
 330        pwrdm->pwrdm_clkdms[i] = clkdm;
 331
 332        ret = 0;
 333
 334pac_exit:
 335        return ret;
 336}
 337
 338/**
 339 * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
 340 * @pwrdm: struct powerdomain * to add the clockdomain to
 341 * @clkdm: struct clockdomain * to associate with a powerdomain
 342 *
 343 * Dissociate the clockdomain @clkdm from the powerdomain
 344 * @pwrdm. Returns -EINVAL if presented with invalid pointers; -ENOENT
 345 * if @clkdm was not associated with the powerdomain, or 0 upon
 346 * success.
 347 */
 348int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
 349{
 350        int ret = -EINVAL;
 351        int i;
 352
 353        if (!pwrdm || !clkdm)
 354                return -EINVAL;
 355
 356        pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
 357                 "%s\n", clkdm->name, pwrdm->name);
 358
 359        for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
 360                if (pwrdm->pwrdm_clkdms[i] == clkdm)
 361                        break;
 362
 363        if (i == PWRDM_MAX_CLKDMS) {
 364                pr_debug("powerdomain: clkdm %s not associated with pwrdm "
 365                         "%s ?!\n", clkdm->name, pwrdm->name);
 366                ret = -ENOENT;
 367                goto pdc_exit;
 368        }
 369
 370        pwrdm->pwrdm_clkdms[i] = NULL;
 371
 372        ret = 0;
 373
 374pdc_exit:
 375        return ret;
 376}
 377
 378/**
 379 * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
 380 * @pwrdm: struct powerdomain * to iterate over
 381 * @fn: callback function *
 382 *
 383 * Call the supplied function @fn for each clockdomain in the powerdomain
 384 * @pwrdm.  The callback function can return anything but 0 to bail
 385 * out early from the iterator.  Returns -EINVAL if presented with
 386 * invalid pointers; or passes along the last return value of the
 387 * callback function, which should be 0 for success or anything else
 388 * to indicate failure.
 389 */
 390int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
 391                         int (*fn)(struct powerdomain *pwrdm,
 392                                   struct clockdomain *clkdm))
 393{
 394        int ret = 0;
 395        int i;
 396
 397        if (!fn)
 398                return -EINVAL;
 399
 400        for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
 401                ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
 402
 403        return ret;
 404}
 405
 406/**
 407 * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
 408 * @pwrdm: struct powerdomain *
 409 *
 410 * Return the number of controllable memory banks in powerdomain @pwrdm,
 411 * starting with 1.  Returns -EINVAL if the powerdomain pointer is null.
 412 */
 413int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
 414{
 415        if (!pwrdm)
 416                return -EINVAL;
 417
 418        return pwrdm->banks;
 419}
 420
 421/**
 422 * pwrdm_set_next_pwrst - set next powerdomain power state
 423 * @pwrdm: struct powerdomain * to set
 424 * @pwrst: one of the PWRDM_POWER_* macros
 425 *
 426 * Set the powerdomain @pwrdm's next power state to @pwrst.  The powerdomain
 427 * may not enter this state immediately if the preconditions for this state
 428 * have not been satisfied.  Returns -EINVAL if the powerdomain pointer is
 429 * null or if the power state is invalid for the powerdomin, or returns 0
 430 * upon success.
 431 */
 432int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 433{
 434        if (!pwrdm)
 435                return -EINVAL;
 436
 437        if (!(pwrdm->pwrsts & (1 << pwrst)))
 438                return -EINVAL;
 439
 440        pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
 441                 pwrdm->name, pwrst);
 442
 443        prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
 444                             (pwrst << OMAP_POWERSTATE_SHIFT),
 445                             pwrdm->prcm_offs, pwrstctrl_reg_offs);
 446
 447        return 0;
 448}
 449
 450/**
 451 * pwrdm_read_next_pwrst - get next powerdomain power state
 452 * @pwrdm: struct powerdomain * to get power state
 453 *
 454 * Return the powerdomain @pwrdm's next power state.  Returns -EINVAL
 455 * if the powerdomain pointer is null or returns the next power state
 456 * upon success.
 457 */
 458int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 459{
 460        if (!pwrdm)
 461                return -EINVAL;
 462
 463        return prm_read_mod_bits_shift(pwrdm->prcm_offs,
 464                                 pwrstctrl_reg_offs, OMAP_POWERSTATE_MASK);
 465}
 466
 467/**
 468 * pwrdm_read_pwrst - get current powerdomain power state
 469 * @pwrdm: struct powerdomain * to get power state
 470 *
 471 * Return the powerdomain @pwrdm's current power state. Returns -EINVAL
 472 * if the powerdomain pointer is null or returns the current power state
 473 * upon success.
 474 */
 475int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 476{
 477        if (!pwrdm)
 478                return -EINVAL;
 479
 480        return prm_read_mod_bits_shift(pwrdm->prcm_offs,
 481                                 pwrstst_reg_offs, OMAP_POWERSTATEST_MASK);
 482}
 483
 484/**
 485 * pwrdm_read_prev_pwrst - get previous powerdomain power state
 486 * @pwrdm: struct powerdomain * to get previous power state
 487 *
 488 * Return the powerdomain @pwrdm's previous power state.  Returns -EINVAL
 489 * if the powerdomain pointer is null or returns the previous power state
 490 * upon success.
 491 */
 492int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 493{
 494        if (!pwrdm)
 495                return -EINVAL;
 496
 497        return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
 498                                        OMAP3430_LASTPOWERSTATEENTERED_MASK);
 499}
 500
 501/**
 502 * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
 503 * @pwrdm: struct powerdomain * to set
 504 * @pwrst: one of the PWRDM_POWER_* macros
 505 *
 506 * Set the next power state @pwrst that the logic portion of the
 507 * powerdomain @pwrdm will enter when the powerdomain enters retention.
 508 * This will be either RETENTION or OFF, if supported.  Returns
 509 * -EINVAL if the powerdomain pointer is null or the target power
 510 * state is not not supported, or returns 0 upon success.
 511 */
 512int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
 513{
 514        u32 v;
 515
 516        if (!pwrdm)
 517                return -EINVAL;
 518
 519        if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
 520                return -EINVAL;
 521
 522        pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
 523                 pwrdm->name, pwrst);
 524
 525        /*
 526         * The register bit names below may not correspond to the
 527         * actual names of the bits in each powerdomain's register,
 528         * but the type of value returned is the same for each
 529         * powerdomain.
 530         */
 531        v = pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE_MASK);
 532        prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE_MASK, v,
 533                             pwrdm->prcm_offs, pwrstctrl_reg_offs);
 534
 535        return 0;
 536}
 537
 538/**
 539 * pwrdm_set_mem_onst - set memory power state while powerdomain ON
 540 * @pwrdm: struct powerdomain * to set
 541 * @bank: memory bank number to set (0-3)
 542 * @pwrst: one of the PWRDM_POWER_* macros
 543 *
 544 * Set the next power state @pwrst that memory bank @bank of the
 545 * powerdomain @pwrdm will enter when the powerdomain enters the ON
 546 * state.  @bank will be a number from 0 to 3, and represents different
 547 * types of memory, depending on the powerdomain.  Returns -EINVAL if
 548 * the powerdomain pointer is null or the target power state is not
 549 * not supported for this memory bank, -EEXIST if the target memory
 550 * bank does not exist or is not controllable, or returns 0 upon
 551 * success.
 552 */
 553int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 554{
 555        u32 m;
 556
 557        if (!pwrdm)
 558                return -EINVAL;
 559
 560        if (pwrdm->banks < (bank + 1))
 561                return -EEXIST;
 562
 563        if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
 564                return -EINVAL;
 565
 566        pr_debug("powerdomain: setting next memory powerstate for domain %s "
 567                 "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
 568
 569        /*
 570         * The register bit names below may not correspond to the
 571         * actual names of the bits in each powerdomain's register,
 572         * but the type of value returned is the same for each
 573         * powerdomain.
 574         */
 575        switch (bank) {
 576        case 0:
 577                m = OMAP_MEM0_ONSTATE_MASK;
 578                break;
 579        case 1:
 580                m = OMAP_MEM1_ONSTATE_MASK;
 581                break;
 582        case 2:
 583                m = OMAP_MEM2_ONSTATE_MASK;
 584                break;
 585        case 3:
 586                m = OMAP_MEM3_ONSTATE_MASK;
 587                break;
 588        case 4:
 589                m = OMAP_MEM4_ONSTATE_MASK;
 590                break;
 591        default:
 592                WARN_ON(1); /* should never happen */
 593                return -EEXIST;
 594        }
 595
 596        prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
 597                             pwrdm->prcm_offs, pwrstctrl_reg_offs);
 598
 599        return 0;
 600}
 601
 602/**
 603 * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
 604 * @pwrdm: struct powerdomain * to set
 605 * @bank: memory bank number to set (0-3)
 606 * @pwrst: one of the PWRDM_POWER_* macros
 607 *
 608 * Set the next power state @pwrst that memory bank @bank of the
 609 * powerdomain @pwrdm will enter when the powerdomain enters the
 610 * RETENTION state.  Bank will be a number from 0 to 3, and represents
 611 * different types of memory, depending on the powerdomain.  @pwrst
 612 * will be either RETENTION or OFF, if supported.  Returns -EINVAL if
 613 * the powerdomain pointer is null or the target power state is not
 614 * not supported for this memory bank, -EEXIST if the target memory
 615 * bank does not exist or is not controllable, or returns 0 upon
 616 * success.
 617 */
 618int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 619{
 620        u32 m;
 621
 622        if (!pwrdm)
 623                return -EINVAL;
 624
 625        if (pwrdm->banks < (bank + 1))
 626                return -EEXIST;
 627
 628        if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
 629                return -EINVAL;
 630
 631        pr_debug("powerdomain: setting next memory powerstate for domain %s "
 632                 "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
 633
 634        /*
 635         * The register bit names below may not correspond to the
 636         * actual names of the bits in each powerdomain's register,
 637         * but the type of value returned is the same for each
 638         * powerdomain.
 639         */
 640        switch (bank) {
 641        case 0:
 642                m = OMAP_MEM0_RETSTATE_MASK;
 643                break;
 644        case 1:
 645                m = OMAP_MEM1_RETSTATE_MASK;
 646                break;
 647        case 2:
 648                m = OMAP_MEM2_RETSTATE_MASK;
 649                break;
 650        case 3:
 651                m = OMAP_MEM3_RETSTATE_MASK;
 652                break;
 653        case 4:
 654                m = OMAP_MEM4_RETSTATE_MASK;
 655                break;
 656        default:
 657                WARN_ON(1); /* should never happen */
 658                return -EEXIST;
 659        }
 660
 661        prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
 662                             pwrstctrl_reg_offs);
 663
 664        return 0;
 665}
 666
 667/**
 668 * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
 669 * @pwrdm: struct powerdomain * to get current logic retention power state
 670 *
 671 * Return the power state that the logic portion of powerdomain @pwrdm
 672 * will enter when the powerdomain enters retention.  Returns -EINVAL
 673 * if the powerdomain pointer is null or returns the logic retention
 674 * power state upon success.
 675 */
 676int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
 677{
 678        if (!pwrdm)
 679                return -EINVAL;
 680
 681        return prm_read_mod_bits_shift(pwrdm->prcm_offs, pwrstst_reg_offs,
 682                                       OMAP3430_LOGICSTATEST_MASK);
 683}
 684
 685/**
 686 * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
 687 * @pwrdm: struct powerdomain * to get previous logic power state
 688 *
 689 * Return the powerdomain @pwrdm's previous logic power state.  Returns
 690 * -EINVAL if the powerdomain pointer is null or returns the previous
 691 * logic power state upon success.
 692 */
 693int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
 694{
 695        if (!pwrdm)
 696                return -EINVAL;
 697
 698        /*
 699         * The register bit names below may not correspond to the
 700         * actual names of the bits in each powerdomain's register,
 701         * but the type of value returned is the same for each
 702         * powerdomain.
 703         */
 704        return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
 705                                        OMAP3430_LASTLOGICSTATEENTERED_MASK);
 706}
 707
 708/**
 709 * pwrdm_read_logic_retst - get next powerdomain logic power state
 710 * @pwrdm: struct powerdomain * to get next logic power state
 711 *
 712 * Return the powerdomain pwrdm's logic power state.  Returns -EINVAL
 713 * if the powerdomain pointer is null or returns the next logic
 714 * power state upon success.
 715 */
 716int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
 717{
 718        if (!pwrdm)
 719                return -EINVAL;
 720
 721        /*
 722         * The register bit names below may not correspond to the
 723         * actual names of the bits in each powerdomain's register,
 724         * but the type of value returned is the same for each
 725         * powerdomain.
 726         */
 727        return prm_read_mod_bits_shift(pwrdm->prcm_offs, pwrstctrl_reg_offs,
 728                                       OMAP3430_LOGICSTATEST_MASK);
 729}
 730
 731/**
 732 * pwrdm_read_mem_pwrst - get current memory bank power state
 733 * @pwrdm: struct powerdomain * to get current memory bank power state
 734 * @bank: memory bank number (0-3)
 735 *
 736 * Return the powerdomain @pwrdm's current memory power state for bank
 737 * @bank.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
 738 * the target memory bank does not exist or is not controllable, or
 739 * returns the current memory power state upon success.
 740 */
 741int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
 742{
 743        u32 m;
 744
 745        if (!pwrdm)
 746                return -EINVAL;
 747
 748        if (pwrdm->banks < (bank + 1))
 749                return -EEXIST;
 750
 751        if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
 752                bank = 1;
 753
 754        /*
 755         * The register bit names below may not correspond to the
 756         * actual names of the bits in each powerdomain's register,
 757         * but the type of value returned is the same for each
 758         * powerdomain.
 759         */
 760        switch (bank) {
 761        case 0:
 762                m = OMAP_MEM0_STATEST_MASK;
 763                break;
 764        case 1:
 765                m = OMAP_MEM1_STATEST_MASK;
 766                break;
 767        case 2:
 768                m = OMAP_MEM2_STATEST_MASK;
 769                break;
 770        case 3:
 771                m = OMAP_MEM3_STATEST_MASK;
 772                break;
 773        case 4:
 774                m = OMAP_MEM4_STATEST_MASK;
 775                break;
 776        default:
 777                WARN_ON(1); /* should never happen */
 778                return -EEXIST;
 779        }
 780
 781        return prm_read_mod_bits_shift(pwrdm->prcm_offs,
 782                                         pwrstst_reg_offs, m);
 783}
 784
 785/**
 786 * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
 787 * @pwrdm: struct powerdomain * to get previous memory bank power state
 788 * @bank: memory bank number (0-3)
 789 *
 790 * Return the powerdomain @pwrdm's previous memory power state for
 791 * bank @bank.  Returns -EINVAL if the powerdomain pointer is null,
 792 * -EEXIST if the target memory bank does not exist or is not
 793 * controllable, or returns the previous memory power state upon
 794 * success.
 795 */
 796int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
 797{
 798        u32 m;
 799
 800        if (!pwrdm)
 801                return -EINVAL;
 802
 803        if (pwrdm->banks < (bank + 1))
 804                return -EEXIST;
 805
 806        if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
 807                bank = 1;
 808
 809        /*
 810         * The register bit names below may not correspond to the
 811         * actual names of the bits in each powerdomain's register,
 812         * but the type of value returned is the same for each
 813         * powerdomain.
 814         */
 815        switch (bank) {
 816        case 0:
 817                m = OMAP3430_LASTMEM1STATEENTERED_MASK;
 818                break;
 819        case 1:
 820                m = OMAP3430_LASTMEM2STATEENTERED_MASK;
 821                break;
 822        case 2:
 823                m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
 824                break;
 825        case 3:
 826                m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
 827                break;
 828        default:
 829                WARN_ON(1); /* should never happen */
 830                return -EEXIST;
 831        }
 832
 833        return prm_read_mod_bits_shift(pwrdm->prcm_offs,
 834                                        OMAP3430_PM_PREPWSTST, m);
 835}
 836
 837/**
 838 * pwrdm_read_mem_retst - get next memory bank power state
 839 * @pwrdm: struct powerdomain * to get mext memory bank power state
 840 * @bank: memory bank number (0-3)
 841 *
 842 * Return the powerdomain pwrdm's next memory power state for bank
 843 * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
 844 * the target memory bank does not exist or is not controllable, or
 845 * returns the next memory power state upon success.
 846 */
 847int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
 848{
 849        u32 m;
 850
 851        if (!pwrdm)
 852                return -EINVAL;
 853
 854        if (pwrdm->banks < (bank + 1))
 855                return -EEXIST;
 856
 857        /*
 858         * The register bit names below may not correspond to the
 859         * actual names of the bits in each powerdomain's register,
 860         * but the type of value returned is the same for each
 861         * powerdomain.
 862         */
 863        switch (bank) {
 864        case 0:
 865                m = OMAP_MEM0_RETSTATE_MASK;
 866                break;
 867        case 1:
 868                m = OMAP_MEM1_RETSTATE_MASK;
 869                break;
 870        case 2:
 871                m = OMAP_MEM2_RETSTATE_MASK;
 872                break;
 873        case 3:
 874                m = OMAP_MEM3_RETSTATE_MASK;
 875                break;
 876        case 4:
 877                m = OMAP_MEM4_RETSTATE_MASK;
 878        default:
 879                WARN_ON(1); /* should never happen */
 880                return -EEXIST;
 881        }
 882
 883        return prm_read_mod_bits_shift(pwrdm->prcm_offs,
 884                                        pwrstctrl_reg_offs, m);
 885}
 886
 887/**
 888 * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
 889 * @pwrdm: struct powerdomain * to clear
 890 *
 891 * Clear the powerdomain's previous power state register @pwrdm.
 892 * Clears the entire register, including logic and memory bank
 893 * previous power states.  Returns -EINVAL if the powerdomain pointer
 894 * is null, or returns 0 upon success.
 895 */
 896int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
 897{
 898        if (!pwrdm)
 899                return -EINVAL;
 900
 901        /*
 902         * XXX should get the powerdomain's current state here;
 903         * warn & fail if it is not ON.
 904         */
 905
 906        pr_debug("powerdomain: clearing previous power state reg for %s\n",
 907                 pwrdm->name);
 908
 909        prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
 910
 911        return 0;
 912}
 913
 914/**
 915 * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
 916 * @pwrdm: struct powerdomain *
 917 *
 918 * Enable automatic context save-and-restore upon power state change
 919 * for some devices in the powerdomain @pwrdm.  Warning: this only
 920 * affects a subset of devices in a powerdomain; check the TRM
 921 * closely.  Returns -EINVAL if the powerdomain pointer is null or if
 922 * the powerdomain does not support automatic save-and-restore, or
 923 * returns 0 upon success.
 924 */
 925int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
 926{
 927        if (!pwrdm)
 928                return -EINVAL;
 929
 930        if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
 931                return -EINVAL;
 932
 933        pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
 934                 pwrdm->name);
 935
 936        prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
 937                             pwrdm->prcm_offs, pwrstctrl_reg_offs);
 938
 939        return 0;
 940}
 941
 942/**
 943 * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
 944 * @pwrdm: struct powerdomain *
 945 *
 946 * Disable automatic context save-and-restore upon power state change
 947 * for some devices in the powerdomain @pwrdm.  Warning: this only
 948 * affects a subset of devices in a powerdomain; check the TRM
 949 * closely.  Returns -EINVAL if the powerdomain pointer is null or if
 950 * the powerdomain does not support automatic save-and-restore, or
 951 * returns 0 upon success.
 952 */
 953int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 954{
 955        if (!pwrdm)
 956                return -EINVAL;
 957
 958        if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
 959                return -EINVAL;
 960
 961        pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
 962                 pwrdm->name);
 963
 964        prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0,
 965                             pwrdm->prcm_offs, pwrstctrl_reg_offs);
 966
 967        return 0;
 968}
 969
 970/**
 971 * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
 972 * @pwrdm: struct powerdomain *
 973 *
 974 * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore
 975 * for some devices, or 0 if it does not.
 976 */
 977bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
 978{
 979        return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
 980}
 981
 982/**
 983 * pwrdm_set_lowpwrstchange - Request a low power state change
 984 * @pwrdm: struct powerdomain *
 985 *
 986 * Allows a powerdomain to transtion to a lower power sleep state
 987 * from an existing sleep state without waking up the powerdomain.
 988 * Returns -EINVAL if the powerdomain pointer is null or if the
 989 * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0
 990 * upon success.
 991 */
 992int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
 993{
 994        if (!pwrdm)
 995                return -EINVAL;
 996
 997        if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE))
 998                return -EINVAL;
 999
1000        pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
1001                 pwrdm->name);
1002
1003        prm_rmw_mod_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK,
1004                             (1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT),
1005                             pwrdm->prcm_offs, pwrstctrl_reg_offs);
1006
1007        return 0;
1008}
1009
1010/**
1011 * pwrdm_wait_transition - wait for powerdomain power transition to finish
1012 * @pwrdm: struct powerdomain * to wait for
1013 *
1014 * If the powerdomain @pwrdm is in the process of a state transition,
1015 * spin until it completes the power transition, or until an iteration
1016 * bailout value is reached. Returns -EINVAL if the powerdomain
1017 * pointer is null, -EAGAIN if the bailout value was reached, or
1018 * returns 0 upon success.
1019 */
1020int pwrdm_wait_transition(struct powerdomain *pwrdm)
1021{
1022        u32 c = 0;
1023
1024        if (!pwrdm)
1025                return -EINVAL;
1026
1027        /*
1028         * REVISIT: pwrdm_wait_transition() may be better implemented
1029         * via a callback and a periodic timer check -- how long do we expect
1030         * powerdomain transitions to take?
1031         */
1032
1033        /* XXX Is this udelay() value meaningful? */
1034        while ((prm_read_mod_reg(pwrdm->prcm_offs, pwrstst_reg_offs) &
1035                OMAP_INTRANSITION_MASK) &&
1036               (c++ < PWRDM_TRANSITION_BAILOUT))
1037                        udelay(1);
1038
1039        if (c > PWRDM_TRANSITION_BAILOUT) {
1040                printk(KERN_ERR "powerdomain: waited too long for "
1041                       "powerdomain %s to complete transition\n", pwrdm->name);
1042                return -EAGAIN;
1043        }
1044
1045        pr_debug("powerdomain: completed transition in %d loops\n", c);
1046
1047        return 0;
1048}
1049
1050int pwrdm_state_switch(struct powerdomain *pwrdm)
1051{
1052        return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
1053}
1054
1055int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
1056{
1057        if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) {
1058                pwrdm_wait_transition(clkdm->pwrdm.ptr);
1059                return pwrdm_state_switch(clkdm->pwrdm.ptr);
1060        }
1061
1062        return -EINVAL;
1063}
1064
1065int pwrdm_pre_transition(void)
1066{
1067        pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
1068        return 0;
1069}
1070
1071int pwrdm_post_transition(void)
1072{
1073        pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
1074        return 0;
1075}
1076
1077
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.