1ddd04b98SVaibhav Hiremath /* 2ddd04b98SVaibhav Hiremath * AM33XX PRM functions 3ddd04b98SVaibhav Hiremath * 4ddd04b98SVaibhav Hiremath * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ 5ddd04b98SVaibhav Hiremath * 6ddd04b98SVaibhav Hiremath * This program is free software; you can redistribute it and/or 7ddd04b98SVaibhav Hiremath * modify it under the terms of the GNU General Public License as 8ddd04b98SVaibhav Hiremath * published by the Free Software Foundation version 2. 9ddd04b98SVaibhav Hiremath * 10ddd04b98SVaibhav Hiremath * This program is distributed "as is" WITHOUT ANY WARRANTY of any 11ddd04b98SVaibhav Hiremath * kind, whether express or implied; without even the implied warranty 12ddd04b98SVaibhav Hiremath * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13ddd04b98SVaibhav Hiremath * GNU General Public License for more details. 14ddd04b98SVaibhav Hiremath */ 15ddd04b98SVaibhav Hiremath 16ddd04b98SVaibhav Hiremath #include <linux/kernel.h> 17ddd04b98SVaibhav Hiremath #include <linux/types.h> 18ddd04b98SVaibhav Hiremath #include <linux/errno.h> 19ddd04b98SVaibhav Hiremath #include <linux/err.h> 20ddd04b98SVaibhav Hiremath #include <linux/io.h> 21ddd04b98SVaibhav Hiremath 22ddd04b98SVaibhav Hiremath #include "common.h" 2349815399SPaul Walmsley #include "powerdomain.h" 24ddd04b98SVaibhav Hiremath #include "prm33xx.h" 25ddd04b98SVaibhav Hiremath #include "prm-regbits-33xx.h" 26ddd04b98SVaibhav Hiremath 27ddd04b98SVaibhav Hiremath /* Read a register in a PRM instance */ 28ddd04b98SVaibhav Hiremath u32 am33xx_prm_read_reg(s16 inst, u16 idx) 29ddd04b98SVaibhav Hiremath { 30edfaf05cSVictor Kamensky return readl_relaxed(prm_base + inst + idx); 31ddd04b98SVaibhav Hiremath } 32ddd04b98SVaibhav Hiremath 33ddd04b98SVaibhav Hiremath /* Write into a register in a PRM instance */ 34ddd04b98SVaibhav Hiremath void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) 35ddd04b98SVaibhav Hiremath { 36edfaf05cSVictor Kamensky writel_relaxed(val, prm_base + inst + idx); 37ddd04b98SVaibhav Hiremath } 38ddd04b98SVaibhav Hiremath 39ddd04b98SVaibhav Hiremath /* Read-modify-write a register in PRM. Caller must lock */ 40ddd04b98SVaibhav Hiremath u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) 41ddd04b98SVaibhav Hiremath { 42ddd04b98SVaibhav Hiremath u32 v; 43ddd04b98SVaibhav Hiremath 44ddd04b98SVaibhav Hiremath v = am33xx_prm_read_reg(inst, idx); 45ddd04b98SVaibhav Hiremath v &= ~mask; 46ddd04b98SVaibhav Hiremath v |= bits; 47ddd04b98SVaibhav Hiremath am33xx_prm_write_reg(v, inst, idx); 48ddd04b98SVaibhav Hiremath 49ddd04b98SVaibhav Hiremath return v; 50ddd04b98SVaibhav Hiremath } 51ddd04b98SVaibhav Hiremath 52ddd04b98SVaibhav Hiremath /** 53ddd04b98SVaibhav Hiremath * am33xx_prm_is_hardreset_asserted - read the HW reset line state of 54ddd04b98SVaibhav Hiremath * submodules contained in the hwmod module 55ddd04b98SVaibhav Hiremath * @shift: register bit shift corresponding to the reset line to check 56ddd04b98SVaibhav Hiremath * @inst: CM instance register offset (*_INST macro) 57ddd04b98SVaibhav Hiremath * @rstctrl_offs: RM_RSTCTRL register address offset for this module 58ddd04b98SVaibhav Hiremath * 59ddd04b98SVaibhav Hiremath * Returns 1 if the (sub)module hardreset line is currently asserted, 60ddd04b98SVaibhav Hiremath * 0 if the (sub)module hardreset line is not currently asserted, or 61ddd04b98SVaibhav Hiremath * -EINVAL upon parameter error. 62ddd04b98SVaibhav Hiremath */ 63ddd04b98SVaibhav Hiremath int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) 64ddd04b98SVaibhav Hiremath { 65ddd04b98SVaibhav Hiremath u32 v; 66ddd04b98SVaibhav Hiremath 67ddd04b98SVaibhav Hiremath v = am33xx_prm_read_reg(inst, rstctrl_offs); 68ddd04b98SVaibhav Hiremath v &= 1 << shift; 69ddd04b98SVaibhav Hiremath v >>= shift; 70ddd04b98SVaibhav Hiremath 71ddd04b98SVaibhav Hiremath return v; 72ddd04b98SVaibhav Hiremath } 73ddd04b98SVaibhav Hiremath 74ddd04b98SVaibhav Hiremath /** 75ddd04b98SVaibhav Hiremath * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule 76ddd04b98SVaibhav Hiremath * @shift: register bit shift corresponding to the reset line to assert 77ddd04b98SVaibhav Hiremath * @inst: CM instance register offset (*_INST macro) 78ddd04b98SVaibhav Hiremath * @rstctrl_reg: RM_RSTCTRL register address for this module 79ddd04b98SVaibhav Hiremath * 80ddd04b98SVaibhav Hiremath * Some IPs like dsp, ipu or iva contain processors that require an HW 81ddd04b98SVaibhav Hiremath * reset line to be asserted / deasserted in order to fully enable the 82ddd04b98SVaibhav Hiremath * IP. These modules may have multiple hard-reset lines that reset 83ddd04b98SVaibhav Hiremath * different 'submodules' inside the IP block. This function will 84ddd04b98SVaibhav Hiremath * place the submodule into reset. Returns 0 upon success or -EINVAL 85ddd04b98SVaibhav Hiremath * upon an argument error. 86ddd04b98SVaibhav Hiremath */ 87ddd04b98SVaibhav Hiremath int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) 88ddd04b98SVaibhav Hiremath { 89ddd04b98SVaibhav Hiremath u32 mask = 1 << shift; 90ddd04b98SVaibhav Hiremath 91ddd04b98SVaibhav Hiremath am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs); 92ddd04b98SVaibhav Hiremath 93ddd04b98SVaibhav Hiremath return 0; 94ddd04b98SVaibhav Hiremath } 95ddd04b98SVaibhav Hiremath 96ddd04b98SVaibhav Hiremath /** 97ddd04b98SVaibhav Hiremath * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and 98ddd04b98SVaibhav Hiremath * wait 99ddd04b98SVaibhav Hiremath * @shift: register bit shift corresponding to the reset line to deassert 100ddd04b98SVaibhav Hiremath * @inst: CM instance register offset (*_INST macro) 101ddd04b98SVaibhav Hiremath * @rstctrl_reg: RM_RSTCTRL register address for this module 102ddd04b98SVaibhav Hiremath * @rstst_reg: RM_RSTST register address for this module 103ddd04b98SVaibhav Hiremath * 104ddd04b98SVaibhav Hiremath * Some IPs like dsp, ipu or iva contain processors that require an HW 105ddd04b98SVaibhav Hiremath * reset line to be asserted / deasserted in order to fully enable the 106ddd04b98SVaibhav Hiremath * IP. These modules may have multiple hard-reset lines that reset 107ddd04b98SVaibhav Hiremath * different 'submodules' inside the IP block. This function will 108ddd04b98SVaibhav Hiremath * take the submodule out of reset and wait until the PRCM indicates 109ddd04b98SVaibhav Hiremath * that the reset has completed before returning. Returns 0 upon success or 110ddd04b98SVaibhav Hiremath * -EINVAL upon an argument error, -EEXIST if the submodule was already out 111ddd04b98SVaibhav Hiremath * of reset, or -EBUSY if the submodule did not exit reset promptly. 112ddd04b98SVaibhav Hiremath */ 1133c06f1b8SVaibhav Bedia int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, 114ddd04b98SVaibhav Hiremath u16 rstctrl_offs, u16 rstst_offs) 115ddd04b98SVaibhav Hiremath { 116ddd04b98SVaibhav Hiremath int c; 1173c06f1b8SVaibhav Bedia u32 mask = 1 << st_shift; 118ddd04b98SVaibhav Hiremath 119ddd04b98SVaibhav Hiremath /* Check the current status to avoid de-asserting the line twice */ 120ddd04b98SVaibhav Hiremath if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0) 121ddd04b98SVaibhav Hiremath return -EEXIST; 122ddd04b98SVaibhav Hiremath 123ddd04b98SVaibhav Hiremath /* Clear the reset status by writing 1 to the status bit */ 124ddd04b98SVaibhav Hiremath am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs); 125ddd04b98SVaibhav Hiremath 1263c06f1b8SVaibhav Bedia /* de-assert the reset control line */ 1273c06f1b8SVaibhav Bedia mask = 1 << shift; 1283c06f1b8SVaibhav Bedia 1293c06f1b8SVaibhav Bedia am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); 1303c06f1b8SVaibhav Bedia 1313c06f1b8SVaibhav Bedia /* wait the status to be set */ 1323c06f1b8SVaibhav Bedia omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst, 133ddd04b98SVaibhav Hiremath rstst_offs), 134ddd04b98SVaibhav Hiremath MAX_MODULE_HARDRESET_WAIT, c); 135ddd04b98SVaibhav Hiremath 136ddd04b98SVaibhav Hiremath return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; 137ddd04b98SVaibhav Hiremath } 13849815399SPaul Walmsley 13949815399SPaul Walmsley static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 14049815399SPaul Walmsley { 14149815399SPaul Walmsley am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK, 14249815399SPaul Walmsley (pwrst << OMAP_POWERSTATE_SHIFT), 14349815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 14449815399SPaul Walmsley return 0; 14549815399SPaul Walmsley } 14649815399SPaul Walmsley 14749815399SPaul Walmsley static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 14849815399SPaul Walmsley { 14949815399SPaul Walmsley u32 v; 15049815399SPaul Walmsley 15149815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 15249815399SPaul Walmsley v &= OMAP_POWERSTATE_MASK; 15349815399SPaul Walmsley v >>= OMAP_POWERSTATE_SHIFT; 15449815399SPaul Walmsley 15549815399SPaul Walmsley return v; 15649815399SPaul Walmsley } 15749815399SPaul Walmsley 15849815399SPaul Walmsley static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 15949815399SPaul Walmsley { 16049815399SPaul Walmsley u32 v; 16149815399SPaul Walmsley 16249815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 16349815399SPaul Walmsley v &= OMAP_POWERSTATEST_MASK; 16449815399SPaul Walmsley v >>= OMAP_POWERSTATEST_SHIFT; 16549815399SPaul Walmsley 16649815399SPaul Walmsley return v; 16749815399SPaul Walmsley } 16849815399SPaul Walmsley 16949815399SPaul Walmsley static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) 17049815399SPaul Walmsley { 17149815399SPaul Walmsley u32 v; 17249815399SPaul Walmsley 17349815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 17449815399SPaul Walmsley v &= AM33XX_LASTPOWERSTATEENTERED_MASK; 17549815399SPaul Walmsley v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT; 17649815399SPaul Walmsley 17749815399SPaul Walmsley return v; 17849815399SPaul Walmsley } 17949815399SPaul Walmsley 18049815399SPaul Walmsley static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) 18149815399SPaul Walmsley { 18249815399SPaul Walmsley am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK, 18349815399SPaul Walmsley (1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT), 18449815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 18549815399SPaul Walmsley return 0; 18649815399SPaul Walmsley } 18749815399SPaul Walmsley 18849815399SPaul Walmsley static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) 18949815399SPaul Walmsley { 19049815399SPaul Walmsley am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK, 19149815399SPaul Walmsley AM33XX_LASTPOWERSTATEENTERED_MASK, 19249815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstst_offs); 19349815399SPaul Walmsley return 0; 19449815399SPaul Walmsley } 19549815399SPaul Walmsley 19649815399SPaul Walmsley static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) 19749815399SPaul Walmsley { 19849815399SPaul Walmsley u32 m; 19949815399SPaul Walmsley 20049815399SPaul Walmsley m = pwrdm->logicretstate_mask; 20149815399SPaul Walmsley if (!m) 20249815399SPaul Walmsley return -EINVAL; 20349815399SPaul Walmsley 20449815399SPaul Walmsley am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 20549815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 20649815399SPaul Walmsley 20749815399SPaul Walmsley return 0; 20849815399SPaul Walmsley } 20949815399SPaul Walmsley 21049815399SPaul Walmsley static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) 21149815399SPaul Walmsley { 21249815399SPaul Walmsley u32 v; 21349815399SPaul Walmsley 21449815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 21549815399SPaul Walmsley v &= AM33XX_LOGICSTATEST_MASK; 21649815399SPaul Walmsley v >>= AM33XX_LOGICSTATEST_SHIFT; 21749815399SPaul Walmsley 21849815399SPaul Walmsley return v; 21949815399SPaul Walmsley } 22049815399SPaul Walmsley 22149815399SPaul Walmsley static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm) 22249815399SPaul Walmsley { 22349815399SPaul Walmsley u32 v, m; 22449815399SPaul Walmsley 22549815399SPaul Walmsley m = pwrdm->logicretstate_mask; 22649815399SPaul Walmsley if (!m) 22749815399SPaul Walmsley return -EINVAL; 22849815399SPaul Walmsley 22949815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 23049815399SPaul Walmsley v &= m; 23149815399SPaul Walmsley v >>= __ffs(m); 23249815399SPaul Walmsley 23349815399SPaul Walmsley return v; 23449815399SPaul Walmsley } 23549815399SPaul Walmsley 23649815399SPaul Walmsley static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, 23749815399SPaul Walmsley u8 pwrst) 23849815399SPaul Walmsley { 23949815399SPaul Walmsley u32 m; 24049815399SPaul Walmsley 24149815399SPaul Walmsley m = pwrdm->mem_on_mask[bank]; 24249815399SPaul Walmsley if (!m) 24349815399SPaul Walmsley return -EINVAL; 24449815399SPaul Walmsley 24549815399SPaul Walmsley am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 24649815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 24749815399SPaul Walmsley 24849815399SPaul Walmsley return 0; 24949815399SPaul Walmsley } 25049815399SPaul Walmsley 25149815399SPaul Walmsley static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, 25249815399SPaul Walmsley u8 pwrst) 25349815399SPaul Walmsley { 25449815399SPaul Walmsley u32 m; 25549815399SPaul Walmsley 25649815399SPaul Walmsley m = pwrdm->mem_ret_mask[bank]; 25749815399SPaul Walmsley if (!m) 25849815399SPaul Walmsley return -EINVAL; 25949815399SPaul Walmsley 26049815399SPaul Walmsley am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 26149815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 26249815399SPaul Walmsley 26349815399SPaul Walmsley return 0; 26449815399SPaul Walmsley } 26549815399SPaul Walmsley 26649815399SPaul Walmsley static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) 26749815399SPaul Walmsley { 26849815399SPaul Walmsley u32 m, v; 26949815399SPaul Walmsley 27049815399SPaul Walmsley m = pwrdm->mem_pwrst_mask[bank]; 27149815399SPaul Walmsley if (!m) 27249815399SPaul Walmsley return -EINVAL; 27349815399SPaul Walmsley 27449815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 27549815399SPaul Walmsley v &= m; 27649815399SPaul Walmsley v >>= __ffs(m); 27749815399SPaul Walmsley 27849815399SPaul Walmsley return v; 27949815399SPaul Walmsley } 28049815399SPaul Walmsley 28149815399SPaul Walmsley static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank) 28249815399SPaul Walmsley { 28349815399SPaul Walmsley u32 m, v; 28449815399SPaul Walmsley 28549815399SPaul Walmsley m = pwrdm->mem_retst_mask[bank]; 28649815399SPaul Walmsley if (!m) 28749815399SPaul Walmsley return -EINVAL; 28849815399SPaul Walmsley 28949815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 29049815399SPaul Walmsley v &= m; 29149815399SPaul Walmsley v >>= __ffs(m); 29249815399SPaul Walmsley 29349815399SPaul Walmsley return v; 29449815399SPaul Walmsley } 29549815399SPaul Walmsley 29649815399SPaul Walmsley static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm) 29749815399SPaul Walmsley { 29849815399SPaul Walmsley u32 c = 0; 29949815399SPaul Walmsley 30049815399SPaul Walmsley /* 30149815399SPaul Walmsley * REVISIT: pwrdm_wait_transition() may be better implemented 30249815399SPaul Walmsley * via a callback and a periodic timer check -- how long do we expect 30349815399SPaul Walmsley * powerdomain transitions to take? 30449815399SPaul Walmsley */ 30549815399SPaul Walmsley 30649815399SPaul Walmsley /* XXX Is this udelay() value meaningful? */ 30749815399SPaul Walmsley while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs) 30849815399SPaul Walmsley & OMAP_INTRANSITION_MASK) && 30949815399SPaul Walmsley (c++ < PWRDM_TRANSITION_BAILOUT)) 31049815399SPaul Walmsley udelay(1); 31149815399SPaul Walmsley 31249815399SPaul Walmsley if (c > PWRDM_TRANSITION_BAILOUT) { 31349815399SPaul Walmsley pr_err("powerdomain: %s: waited too long to complete transition\n", 31449815399SPaul Walmsley pwrdm->name); 31549815399SPaul Walmsley return -EAGAIN; 31649815399SPaul Walmsley } 31749815399SPaul Walmsley 31849815399SPaul Walmsley pr_debug("powerdomain: completed transition in %d loops\n", c); 31949815399SPaul Walmsley 32049815399SPaul Walmsley return 0; 32149815399SPaul Walmsley } 32249815399SPaul Walmsley 32363b0420cSRajendra Nayak static int am33xx_check_vcvp(void) 32463b0420cSRajendra Nayak { 32563b0420cSRajendra Nayak /* No VC/VP on am33xx devices */ 32663b0420cSRajendra Nayak return 0; 32763b0420cSRajendra Nayak } 32863b0420cSRajendra Nayak 32949815399SPaul Walmsley struct pwrdm_ops am33xx_pwrdm_operations = { 33049815399SPaul Walmsley .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, 33149815399SPaul Walmsley .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, 33249815399SPaul Walmsley .pwrdm_read_pwrst = am33xx_pwrdm_read_pwrst, 33349815399SPaul Walmsley .pwrdm_read_prev_pwrst = am33xx_pwrdm_read_prev_pwrst, 33449815399SPaul Walmsley .pwrdm_set_logic_retst = am33xx_pwrdm_set_logic_retst, 33549815399SPaul Walmsley .pwrdm_read_logic_pwrst = am33xx_pwrdm_read_logic_pwrst, 33649815399SPaul Walmsley .pwrdm_read_logic_retst = am33xx_pwrdm_read_logic_retst, 33749815399SPaul Walmsley .pwrdm_clear_all_prev_pwrst = am33xx_pwrdm_clear_all_prev_pwrst, 33849815399SPaul Walmsley .pwrdm_set_lowpwrstchange = am33xx_pwrdm_set_lowpwrstchange, 33949815399SPaul Walmsley .pwrdm_read_mem_pwrst = am33xx_pwrdm_read_mem_pwrst, 34049815399SPaul Walmsley .pwrdm_read_mem_retst = am33xx_pwrdm_read_mem_retst, 34149815399SPaul Walmsley .pwrdm_set_mem_onst = am33xx_pwrdm_set_mem_onst, 34249815399SPaul Walmsley .pwrdm_set_mem_retst = am33xx_pwrdm_set_mem_retst, 34349815399SPaul Walmsley .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, 34463b0420cSRajendra Nayak .pwrdm_has_voltdm = am33xx_check_vcvp, 34549815399SPaul Walmsley }; 346