linux/arch/arm/mach-omap2/prm33xx.c
<<
>>
Prefs
   1/*
   2 * AM33XX PRM functions
   3 *
   4 * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation version 2.
   9 *
  10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  11 * kind, whether express or implied; without even the implied warranty
  12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/types.h>
  18#include <linux/errno.h>
  19#include <linux/err.h>
  20#include <linux/io.h>
  21
  22#include "common.h"
  23#include "powerdomain.h"
  24#include "prm33xx.h"
  25#include "prm-regbits-33xx.h"
  26
  27/* Read a register in a PRM instance */
  28u32 am33xx_prm_read_reg(s16 inst, u16 idx)
  29{
  30        return __raw_readl(prm_base + inst + idx);
  31}
  32
  33/* Write into a register in a PRM instance */
  34void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
  35{
  36        __raw_writel(val, prm_base + inst + idx);
  37}
  38
  39/* Read-modify-write a register in PRM. Caller must lock */
  40u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
  41{
  42        u32 v;
  43
  44        v = am33xx_prm_read_reg(inst, idx);
  45        v &= ~mask;
  46        v |= bits;
  47        am33xx_prm_write_reg(v, inst, idx);
  48
  49        return v;
  50}
  51
  52/**
  53 * am33xx_prm_is_hardreset_asserted - read the HW reset line state of
  54 * submodules contained in the hwmod module
  55 * @shift: register bit shift corresponding to the reset line to check
  56 * @inst: CM instance register offset (*_INST macro)
  57 * @rstctrl_offs: RM_RSTCTRL register address offset for this module
  58 *
  59 * Returns 1 if the (sub)module hardreset line is currently asserted,
  60 * 0 if the (sub)module hardreset line is not currently asserted, or
  61 * -EINVAL upon parameter error.
  62 */
  63int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs)
  64{
  65        u32 v;
  66
  67        v = am33xx_prm_read_reg(inst, rstctrl_offs);
  68        v &= 1 << shift;
  69        v >>= shift;
  70
  71        return v;
  72}
  73
  74/**
  75 * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule
  76 * @shift: register bit shift corresponding to the reset line to assert
  77 * @inst: CM instance register offset (*_INST macro)
  78 * @rstctrl_reg: RM_RSTCTRL register address for this module
  79 *
  80 * Some IPs like dsp, ipu or iva contain processors that require an HW
  81 * reset line to be asserted / deasserted in order to fully enable the
  82 * IP.  These modules may have multiple hard-reset lines that reset
  83 * different 'submodules' inside the IP block.  This function will
  84 * place the submodule into reset.  Returns 0 upon success or -EINVAL
  85 * upon an argument error.
  86 */
  87int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs)
  88{
  89        u32 mask = 1 << shift;
  90
  91        am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs);
  92
  93        return 0;
  94}
  95
  96/**
  97 * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and
  98 * wait
  99 * @shift: register bit shift corresponding to the reset line to deassert
 100 * @inst: CM instance register offset (*_INST macro)
 101 * @rstctrl_reg: RM_RSTCTRL register address for this module
 102 * @rstst_reg: RM_RSTST register address for this module
 103 *
 104 * Some IPs like dsp, ipu or iva contain processors that require an HW
 105 * reset line to be asserted / deasserted in order to fully enable the
 106 * IP.  These modules may have multiple hard-reset lines that reset
 107 * different 'submodules' inside the IP block.  This function will
 108 * take the submodule out of reset and wait until the PRCM indicates
 109 * that the reset has completed before returning.  Returns 0 upon success or
 110 * -EINVAL upon an argument error, -EEXIST if the submodule was already out
 111 * of reset, or -EBUSY if the submodule did not exit reset promptly.
 112 */
 113int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst,
 114                u16 rstctrl_offs, u16 rstst_offs)
 115{
 116        int c;
 117        u32 mask = 1 << st_shift;
 118
 119        /* Check the current status to avoid  de-asserting the line twice */
 120        if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0)
 121                return -EEXIST;
 122
 123        /* Clear the reset status by writing 1 to the status bit */
 124        am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs);
 125
 126        /* de-assert the reset control line */
 127        mask = 1 << shift;
 128
 129        am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs);
 130
 131        /* wait the status to be set */
 132        omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst,
 133                                                           rstst_offs),
 134                          MAX_MODULE_HARDRESET_WAIT, c);
 135
 136        return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
 137}
 138
 139static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 140{
 141        am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK,
 142                                (pwrst << OMAP_POWERSTATE_SHIFT),
 143                                pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 144        return 0;
 145}
 146
 147static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 148{
 149        u32 v;
 150
 151        v = am33xx_prm_read_reg(pwrdm->prcm_offs,  pwrdm->pwrstctrl_offs);
 152        v &= OMAP_POWERSTATE_MASK;
 153        v >>= OMAP_POWERSTATE_SHIFT;
 154
 155        return v;
 156}
 157
 158static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
 159{
 160        u32 v;
 161
 162        v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
 163        v &= OMAP_POWERSTATEST_MASK;
 164        v >>= OMAP_POWERSTATEST_SHIFT;
 165
 166        return v;
 167}
 168
 169static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 170{
 171        u32 v;
 172
 173        v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
 174        v &= AM33XX_LASTPOWERSTATEENTERED_MASK;
 175        v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT;
 176
 177        return v;
 178}
 179
 180static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
 181{
 182        am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
 183                                (1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT),
 184                                pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 185        return 0;
 186}
 187
 188static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
 189{
 190        am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK,
 191                                AM33XX_LASTPOWERSTATEENTERED_MASK,
 192                                pwrdm->prcm_offs, pwrdm->pwrstst_offs);
 193        return 0;
 194}
 195
 196static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
 197{
 198        u32 m;
 199
 200        m = pwrdm->logicretstate_mask;
 201        if (!m)
 202                return -EINVAL;
 203
 204        am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
 205                                pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 206
 207        return 0;
 208}
 209
 210static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
 211{
 212        u32 v;
 213
 214        v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
 215        v &= AM33XX_LOGICSTATEST_MASK;
 216        v >>= AM33XX_LOGICSTATEST_SHIFT;
 217
 218        return v;
 219}
 220
 221static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
 222{
 223        u32 v, m;
 224
 225        m = pwrdm->logicretstate_mask;
 226        if (!m)
 227                return -EINVAL;
 228
 229        v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 230        v &= m;
 231        v >>= __ffs(m);
 232
 233        return v;
 234}
 235
 236static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
 237                u8 pwrst)
 238{
 239        u32 m;
 240
 241        m = pwrdm->mem_on_mask[bank];
 242        if (!m)
 243                return -EINVAL;
 244
 245        am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
 246                                pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 247
 248        return 0;
 249}
 250
 251static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
 252                                        u8 pwrst)
 253{
 254        u32 m;
 255
 256        m = pwrdm->mem_ret_mask[bank];
 257        if (!m)
 258                return -EINVAL;
 259
 260        am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
 261                                pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 262
 263        return 0;
 264}
 265
 266static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
 267{
 268        u32 m, v;
 269
 270        m = pwrdm->mem_pwrst_mask[bank];
 271        if (!m)
 272                return -EINVAL;
 273
 274        v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
 275        v &= m;
 276        v >>= __ffs(m);
 277
 278        return v;
 279}
 280
 281static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
 282{
 283        u32 m, v;
 284
 285        m = pwrdm->mem_retst_mask[bank];
 286        if (!m)
 287                return -EINVAL;
 288
 289        v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
 290        v &= m;
 291        v >>= __ffs(m);
 292
 293        return v;
 294}
 295
 296static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm)
 297{
 298        u32 c = 0;
 299
 300        /*
 301         * REVISIT: pwrdm_wait_transition() may be better implemented
 302         * via a callback and a periodic timer check -- how long do we expect
 303         * powerdomain transitions to take?
 304         */
 305
 306        /* XXX Is this udelay() value meaningful? */
 307        while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs)
 308                        & OMAP_INTRANSITION_MASK) &&
 309                        (c++ < PWRDM_TRANSITION_BAILOUT))
 310                udelay(1);
 311
 312        if (c > PWRDM_TRANSITION_BAILOUT) {
 313                pr_err("powerdomain: %s: waited too long to complete transition\n",
 314                       pwrdm->name);
 315                return -EAGAIN;
 316        }
 317
 318        pr_debug("powerdomain: completed transition in %d loops\n", c);
 319
 320        return 0;
 321}
 322
 323static int am33xx_check_vcvp(void)
 324{
 325        /* No VC/VP on am33xx devices */
 326        return 0;
 327}
 328
 329struct pwrdm_ops am33xx_pwrdm_operations = {
 330        .pwrdm_set_next_pwrst           = am33xx_pwrdm_set_next_pwrst,
 331        .pwrdm_read_next_pwrst          = am33xx_pwrdm_read_next_pwrst,
 332        .pwrdm_read_pwrst               = am33xx_pwrdm_read_pwrst,
 333        .pwrdm_read_prev_pwrst          = am33xx_pwrdm_read_prev_pwrst,
 334        .pwrdm_set_logic_retst          = am33xx_pwrdm_set_logic_retst,
 335        .pwrdm_read_logic_pwrst         = am33xx_pwrdm_read_logic_pwrst,
 336        .pwrdm_read_logic_retst         = am33xx_pwrdm_read_logic_retst,
 337        .pwrdm_clear_all_prev_pwrst     = am33xx_pwrdm_clear_all_prev_pwrst,
 338        .pwrdm_set_lowpwrstchange       = am33xx_pwrdm_set_lowpwrstchange,
 339        .pwrdm_read_mem_pwrst           = am33xx_pwrdm_read_mem_pwrst,
 340        .pwrdm_read_mem_retst           = am33xx_pwrdm_read_mem_retst,
 341        .pwrdm_set_mem_onst             = am33xx_pwrdm_set_mem_onst,
 342        .pwrdm_set_mem_retst            = am33xx_pwrdm_set_mem_retst,
 343        .pwrdm_wait_transition          = am33xx_pwrdm_wait_transition,
 344        .pwrdm_has_voltdm               = am33xx_check_vcvp,
 345};
 346