Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP2/3 PRM module functions
0004  *
0005  * Copyright (C) 2010-2011 Texas Instruments, Inc.
0006  * Copyright (C) 2010 Nokia Corporation
0007  * BenoƮt Cousson
0008  * Paul Walmsley
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/errno.h>
0013 #include <linux/err.h>
0014 #include <linux/io.h>
0015 
0016 #include "powerdomain.h"
0017 #include "prm2xxx_3xxx.h"
0018 #include "prm-regbits-24xx.h"
0019 #include "clockdomain.h"
0020 
0021 /**
0022  * omap2_prm_is_hardreset_asserted - read the HW reset line state of
0023  * submodules contained in the hwmod module
0024  * @shift: register bit shift corresponding to the reset line to check
0025  * @part: PRM partition, ignored for OMAP2
0026  * @prm_mod: PRM submodule base (e.g. CORE_MOD)
0027  * @offset: register offset, ignored for OMAP2
0028  *
0029  * Returns 1 if the (sub)module hardreset line is currently asserted,
0030  * 0 if the (sub)module hardreset line is not currently asserted, or
0031  * -EINVAL if called while running on a non-OMAP2/3 chip.
0032  */
0033 int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
0034 {
0035     return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
0036                        (1 << shift));
0037 }
0038 
0039 /**
0040  * omap2_prm_assert_hardreset - assert the HW reset line of a submodule
0041  * @shift: register bit shift corresponding to the reset line to assert
0042  * @part: PRM partition, ignored for OMAP2
0043  * @prm_mod: PRM submodule base (e.g. CORE_MOD)
0044  * @offset: register offset, ignored for OMAP2
0045  *
0046  * Some IPs like dsp or iva contain processors that require an HW
0047  * reset line to be asserted / deasserted in order to fully enable the
0048  * IP.  These modules may have multiple hard-reset lines that reset
0049  * different 'submodules' inside the IP block.  This function will
0050  * place the submodule into reset.  Returns 0 upon success or -EINVAL
0051  * upon an argument error.
0052  */
0053 int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
0054 {
0055     u32 mask;
0056 
0057     mask = 1 << shift;
0058     omap2_prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL);
0059 
0060     return 0;
0061 }
0062 
0063 /**
0064  * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
0065  * @prm_mod: PRM submodule base (e.g. CORE_MOD)
0066  * @rst_shift: register bit shift corresponding to the reset line to deassert
0067  * @st_shift: register bit shift for the status of the deasserted submodule
0068  * @part: PRM partition, not used for OMAP2
0069  * @prm_mod: PRM submodule base (e.g. CORE_MOD)
0070  * @rst_offset: reset register offset, not used for OMAP2
0071  * @st_offset: reset status register offset, not used for OMAP2
0072  *
0073  * Some IPs like dsp or iva contain processors that require an HW
0074  * reset line to be asserted / deasserted in order to fully enable the
0075  * IP.  These modules may have multiple hard-reset lines that reset
0076  * different 'submodules' inside the IP block.  This function will
0077  * take the submodule out of reset and wait until the PRCM indicates
0078  * that the reset has completed before returning.  Returns 0 upon success or
0079  * -EINVAL upon an argument error, -EEXIST if the submodule was already out
0080  * of reset, or -EBUSY if the submodule did not exit reset promptly.
0081  */
0082 int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part,
0083                  s16 prm_mod, u16 rst_offset, u16 st_offset)
0084 {
0085     u32 rst, st;
0086     int c;
0087 
0088     rst = 1 << rst_shift;
0089     st = 1 << st_shift;
0090 
0091     /* Check the current status to avoid de-asserting the line twice */
0092     if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, rst) == 0)
0093         return -EEXIST;
0094 
0095     /* Clear the reset status by writing 1 to the status bit */
0096     omap2_prm_rmw_mod_reg_bits(0xffffffff, st, prm_mod, OMAP2_RM_RSTST);
0097     /* de-assert the reset control line */
0098     omap2_prm_rmw_mod_reg_bits(rst, 0, prm_mod, OMAP2_RM_RSTCTRL);
0099     /* wait the status to be set */
0100     omap_test_timeout(omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST,
0101                           st),
0102               MAX_MODULE_HARDRESET_WAIT, c);
0103 
0104     return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
0105 }
0106 
0107 
0108 /* Powerdomain low-level functions */
0109 
0110 /* Common functions across OMAP2 and OMAP3 */
0111 int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
0112                                 u8 pwrst)
0113 {
0114     u32 m;
0115 
0116     m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
0117 
0118     omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
0119                    OMAP2_PM_PWSTCTRL);
0120 
0121     return 0;
0122 }
0123 
0124 int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
0125                                 u8 pwrst)
0126 {
0127     u32 m;
0128 
0129     m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
0130 
0131     omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
0132                    OMAP2_PM_PWSTCTRL);
0133 
0134     return 0;
0135 }
0136 
0137 int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
0138 {
0139     u32 m;
0140 
0141     m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
0142 
0143     return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST,
0144                          m);
0145 }
0146 
0147 int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
0148 {
0149     u32 m;
0150 
0151     m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
0152 
0153     return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
0154                          OMAP2_PM_PWSTCTRL, m);
0155 }
0156 
0157 int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
0158 {
0159     u32 v;
0160 
0161     v = pwrst << __ffs(OMAP_LOGICRETSTATE_MASK);
0162     omap2_prm_rmw_mod_reg_bits(OMAP_LOGICRETSTATE_MASK, v, pwrdm->prcm_offs,
0163                    OMAP2_PM_PWSTCTRL);
0164 
0165     return 0;
0166 }
0167 
0168 int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
0169 {
0170     u32 c = 0;
0171 
0172     /*
0173      * REVISIT: pwrdm_wait_transition() may be better implemented
0174      * via a callback and a periodic timer check -- how long do we expect
0175      * powerdomain transitions to take?
0176      */
0177 
0178     /* XXX Is this udelay() value meaningful? */
0179     while ((omap2_prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) &
0180         OMAP_INTRANSITION_MASK) &&
0181         (c++ < PWRDM_TRANSITION_BAILOUT))
0182             udelay(1);
0183 
0184     if (c > PWRDM_TRANSITION_BAILOUT) {
0185         pr_err("powerdomain: %s: waited too long to complete transition\n",
0186                pwrdm->name);
0187         return -EAGAIN;
0188     }
0189 
0190     pr_debug("powerdomain: completed transition in %d loops\n", c);
0191 
0192     return 0;
0193 }
0194 
0195 int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
0196               struct clockdomain *clkdm2)
0197 {
0198     omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
0199                    clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
0200     return 0;
0201 }
0202 
0203 int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
0204               struct clockdomain *clkdm2)
0205 {
0206     omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
0207                      clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
0208     return 0;
0209 }
0210 
0211 int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
0212                struct clockdomain *clkdm2)
0213 {
0214     return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
0215                          PM_WKDEP, (1 << clkdm2->dep_bit));
0216 }
0217 
0218 /* XXX Caller must hold the clkdm's powerdomain lock */
0219 int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
0220 {
0221     struct clkdm_dep *cd;
0222     u32 mask = 0;
0223 
0224     for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
0225         if (!cd->clkdm)
0226             continue; /* only happens if data is erroneous */
0227 
0228         /* PRM accesses are slow, so minimize them */
0229         mask |= 1 << cd->clkdm->dep_bit;
0230         cd->wkdep_usecount = 0;
0231     }
0232 
0233     omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
0234                      PM_WKDEP);
0235     return 0;
0236 }
0237