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 */ 28 u32 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 */ 34 void 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 */ 40 u32 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 */ 63 int 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 */ 87 int 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 */ 113 int am33xx_prm_deassert_hardreset(u8 shift, s16 inst, 114 u16 rstctrl_offs, u16 rstst_offs) 115 { 116 int c; 117 u32 mask = 1 << 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 /* de-assert the reset control line */ 126 am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); 127 /* wait the status to be set */ 128 129 omap_test_timeout(am33xx_prm_is_hardreset_asserted(shift, inst, 130 rstst_offs), 131 MAX_MODULE_HARDRESET_WAIT, c); 132 133 return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; 134 } 135 136 static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 137 { 138 am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK, 139 (pwrst << OMAP_POWERSTATE_SHIFT), 140 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 141 return 0; 142 } 143 144 static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 145 { 146 u32 v; 147 148 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 149 v &= OMAP_POWERSTATE_MASK; 150 v >>= OMAP_POWERSTATE_SHIFT; 151 152 return v; 153 } 154 155 static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 156 { 157 u32 v; 158 159 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 160 v &= OMAP_POWERSTATEST_MASK; 161 v >>= OMAP_POWERSTATEST_SHIFT; 162 163 return v; 164 } 165 166 static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) 167 { 168 u32 v; 169 170 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 171 v &= AM33XX_LASTPOWERSTATEENTERED_MASK; 172 v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT; 173 174 return v; 175 } 176 177 static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) 178 { 179 am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK, 180 (1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT), 181 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 182 return 0; 183 } 184 185 static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) 186 { 187 am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK, 188 AM33XX_LASTPOWERSTATEENTERED_MASK, 189 pwrdm->prcm_offs, pwrdm->pwrstst_offs); 190 return 0; 191 } 192 193 static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) 194 { 195 u32 m; 196 197 m = pwrdm->logicretstate_mask; 198 if (!m) 199 return -EINVAL; 200 201 am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 202 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 203 204 return 0; 205 } 206 207 static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) 208 { 209 u32 v; 210 211 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 212 v &= AM33XX_LOGICSTATEST_MASK; 213 v >>= AM33XX_LOGICSTATEST_SHIFT; 214 215 return v; 216 } 217 218 static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm) 219 { 220 u32 v, m; 221 222 m = pwrdm->logicretstate_mask; 223 if (!m) 224 return -EINVAL; 225 226 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 227 v &= m; 228 v >>= __ffs(m); 229 230 return v; 231 } 232 233 static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, 234 u8 pwrst) 235 { 236 u32 m; 237 238 m = pwrdm->mem_on_mask[bank]; 239 if (!m) 240 return -EINVAL; 241 242 am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 243 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 244 245 return 0; 246 } 247 248 static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, 249 u8 pwrst) 250 { 251 u32 m; 252 253 m = pwrdm->mem_ret_mask[bank]; 254 if (!m) 255 return -EINVAL; 256 257 am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 258 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 259 260 return 0; 261 } 262 263 static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) 264 { 265 u32 m, v; 266 267 m = pwrdm->mem_pwrst_mask[bank]; 268 if (!m) 269 return -EINVAL; 270 271 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 272 v &= m; 273 v >>= __ffs(m); 274 275 return v; 276 } 277 278 static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank) 279 { 280 u32 m, v; 281 282 m = pwrdm->mem_retst_mask[bank]; 283 if (!m) 284 return -EINVAL; 285 286 v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 287 v &= m; 288 v >>= __ffs(m); 289 290 return v; 291 } 292 293 static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm) 294 { 295 u32 c = 0; 296 297 /* 298 * REVISIT: pwrdm_wait_transition() may be better implemented 299 * via a callback and a periodic timer check -- how long do we expect 300 * powerdomain transitions to take? 301 */ 302 303 /* XXX Is this udelay() value meaningful? */ 304 while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs) 305 & OMAP_INTRANSITION_MASK) && 306 (c++ < PWRDM_TRANSITION_BAILOUT)) 307 udelay(1); 308 309 if (c > PWRDM_TRANSITION_BAILOUT) { 310 pr_err("powerdomain: %s: waited too long to complete transition\n", 311 pwrdm->name); 312 return -EAGAIN; 313 } 314 315 pr_debug("powerdomain: completed transition in %d loops\n", c); 316 317 return 0; 318 } 319 320 struct pwrdm_ops am33xx_pwrdm_operations = { 321 .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, 322 .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, 323 .pwrdm_read_pwrst = am33xx_pwrdm_read_pwrst, 324 .pwrdm_read_prev_pwrst = am33xx_pwrdm_read_prev_pwrst, 325 .pwrdm_set_logic_retst = am33xx_pwrdm_set_logic_retst, 326 .pwrdm_read_logic_pwrst = am33xx_pwrdm_read_logic_pwrst, 327 .pwrdm_read_logic_retst = am33xx_pwrdm_read_logic_retst, 328 .pwrdm_clear_all_prev_pwrst = am33xx_pwrdm_clear_all_prev_pwrst, 329 .pwrdm_set_lowpwrstchange = am33xx_pwrdm_set_lowpwrstchange, 330 .pwrdm_read_mem_pwrst = am33xx_pwrdm_read_mem_pwrst, 331 .pwrdm_read_mem_retst = am33xx_pwrdm_read_mem_retst, 332 .pwrdm_set_mem_onst = am33xx_pwrdm_set_mem_onst, 333 .pwrdm_set_mem_retst = am33xx_pwrdm_set_mem_retst, 334 .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, 335 }; 336