linux/arch/arm/mach-omap2/prm2xxx_3xxx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * OMAP2/3 PRM module functions
   4 *
   5 * Copyright (C) 2010-2011 Texas Instruments, Inc.
   6 * Copyright (C) 2010 Nokia Corporation
   7 * BenoƮt Cousson
   8 * Paul Walmsley
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/err.h>
  14#include <linux/io.h>
  15
  16#include "powerdomain.h"
  17#include "prm2xxx_3xxx.h"
  18#include "prm-regbits-24xx.h"
  19#include "clockdomain.h"
  20
  21/**
  22 * omap2_prm_is_hardreset_asserted - read the HW reset line state of
  23 * submodules contained in the hwmod module
  24 * @shift: register bit shift corresponding to the reset line to check
  25 * @part: PRM partition, ignored for OMAP2
  26 * @prm_mod: PRM submodule base (e.g. CORE_MOD)
  27 * @offset: register offset, ignored for OMAP2
  28 *
  29 * Returns 1 if the (sub)module hardreset line is currently asserted,
  30 * 0 if the (sub)module hardreset line is not currently asserted, or
  31 * -EINVAL if called while running on a non-OMAP2/3 chip.
  32 */
  33int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
  34{
  35        return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
  36                                       (1 << shift));
  37}
  38
  39/**
  40 * omap2_prm_assert_hardreset - assert the HW reset line of a submodule
  41 * @shift: register bit shift corresponding to the reset line to assert
  42 * @part: PRM partition, ignored for OMAP2
  43 * @prm_mod: PRM submodule base (e.g. CORE_MOD)
  44 * @offset: register offset, ignored for OMAP2
  45 *
  46 * Some IPs like dsp or iva contain processors that require an HW
  47 * reset line to be asserted / deasserted in order to fully enable the
  48 * IP.  These modules may have multiple hard-reset lines that reset
  49 * different 'submodules' inside the IP block.  This function will
  50 * place the submodule into reset.  Returns 0 upon success or -EINVAL
  51 * upon an argument error.
  52 */
  53int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
  54{
  55        u32 mask;
  56
  57        mask = 1 << shift;
  58        omap2_prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL);
  59
  60        return 0;
  61}
  62
  63/**
  64 * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
  65 * @prm_mod: PRM submodule base (e.g. CORE_MOD)
  66 * @rst_shift: register bit shift corresponding to the reset line to deassert
  67 * @st_shift: register bit shift for the status of the deasserted submodule
  68 * @part: PRM partition, not used for OMAP2
  69 * @prm_mod: PRM submodule base (e.g. CORE_MOD)
  70 * @rst_offset: reset register offset, not used for OMAP2
  71 * @st_offset: reset status register offset, not used for OMAP2
  72 *
  73 * Some IPs like dsp or iva contain processors that require an HW
  74 * reset line to be asserted / deasserted in order to fully enable the
  75 * IP.  These modules may have multiple hard-reset lines that reset
  76 * different 'submodules' inside the IP block.  This function will
  77 * take the submodule out of reset and wait until the PRCM indicates
  78 * that the reset has completed before returning.  Returns 0 upon success or
  79 * -EINVAL upon an argument error, -EEXIST if the submodule was already out
  80 * of reset, or -EBUSY if the submodule did not exit reset promptly.
  81 */
  82int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part,
  83                                 s16 prm_mod, u16 rst_offset, u16 st_offset)
  84{
  85        u32 rst, st;
  86        int c;
  87
  88        rst = 1 << rst_shift;
  89        st = 1 << st_shift;
  90
  91        /* Check the current status to avoid de-asserting the line twice */
  92        if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, rst) == 0)
  93                return -EEXIST;
  94
  95        /* Clear the reset status by writing 1 to the status bit */
  96        omap2_prm_rmw_mod_reg_bits(0xffffffff, st, prm_mod, OMAP2_RM_RSTST);
  97        /* de-assert the reset control line */
  98        omap2_prm_rmw_mod_reg_bits(rst, 0, prm_mod, OMAP2_RM_RSTCTRL);
  99        /* wait the status to be set */
 100        omap_test_timeout(omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST,
 101                                                  st),
 102                          MAX_MODULE_HARDRESET_WAIT, c);
 103
 104        return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
 105}
 106
 107
 108/* Powerdomain low-level functions */
 109
 110/* Common functions across OMAP2 and OMAP3 */
 111int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
 112                                                                u8 pwrst)
 113{
 114        u32 m;
 115
 116        m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
 117
 118        omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
 119                                   OMAP2_PM_PWSTCTRL);
 120
 121        return 0;
 122}
 123
 124int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
 125                                                                u8 pwrst)
 126{
 127        u32 m;
 128
 129        m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
 130
 131        omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
 132                                   OMAP2_PM_PWSTCTRL);
 133
 134        return 0;
 135}
 136
 137int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
 138{
 139        u32 m;
 140
 141        m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
 142
 143        return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST,
 144                                             m);
 145}
 146
 147int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
 148{
 149        u32 m;
 150
 151        m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
 152
 153        return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
 154                                             OMAP2_PM_PWSTCTRL, m);
 155}
 156
 157int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
 158{
 159        u32 v;
 160
 161        v = pwrst << __ffs(OMAP_LOGICRETSTATE_MASK);
 162        omap2_prm_rmw_mod_reg_bits(OMAP_LOGICRETSTATE_MASK, v, pwrdm->prcm_offs,
 163                                   OMAP2_PM_PWSTCTRL);
 164
 165        return 0;
 166}
 167
 168int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
 169{
 170        u32 c = 0;
 171
 172        /*
 173         * REVISIT: pwrdm_wait_transition() may be better implemented
 174         * via a callback and a periodic timer check -- how long do we expect
 175         * powerdomain transitions to take?
 176         */
 177
 178        /* XXX Is this udelay() value meaningful? */
 179        while ((omap2_prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) &
 180                OMAP_INTRANSITION_MASK) &&
 181                (c++ < PWRDM_TRANSITION_BAILOUT))
 182                        udelay(1);
 183
 184        if (c > PWRDM_TRANSITION_BAILOUT) {
 185                pr_err("powerdomain: %s: waited too long to complete transition\n",
 186                       pwrdm->name);
 187                return -EAGAIN;
 188        }
 189
 190        pr_debug("powerdomain: completed transition in %d loops\n", c);
 191
 192        return 0;
 193}
 194
 195int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
 196                          struct clockdomain *clkdm2)
 197{
 198        omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
 199                                   clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
 200        return 0;
 201}
 202
 203int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
 204                          struct clockdomain *clkdm2)
 205{
 206        omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
 207                                     clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
 208        return 0;
 209}
 210
 211int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
 212                           struct clockdomain *clkdm2)
 213{
 214        return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
 215                                             PM_WKDEP, (1 << clkdm2->dep_bit));
 216}
 217
 218/* XXX Caller must hold the clkdm's powerdomain lock */
 219int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
 220{
 221        struct clkdm_dep *cd;
 222        u32 mask = 0;
 223
 224        for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
 225                if (!cd->clkdm)
 226                        continue; /* only happens if data is erroneous */
 227
 228                /* PRM accesses are slow, so minimize them */
 229                mask |= 1 << cd->clkdm->dep_bit;
 230                cd->wkdep_usecount = 0;
 231        }
 232
 233        omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
 234                                     PM_WKDEP);
 235        return 0;
 236}
 237
 238