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 <plat/common.h> 23ddd04b98SVaibhav Hiremath 24ddd04b98SVaibhav Hiremath #include "common.h" 2549815399SPaul Walmsley #include "powerdomain.h" 26ddd04b98SVaibhav Hiremath #include "prm33xx.h" 27ddd04b98SVaibhav Hiremath #include "prm-regbits-33xx.h" 28ddd04b98SVaibhav Hiremath 29ddd04b98SVaibhav Hiremath /* Read a register in a PRM instance */ 30ddd04b98SVaibhav Hiremath u32 am33xx_prm_read_reg(s16 inst, u16 idx) 31ddd04b98SVaibhav Hiremath { 32ddd04b98SVaibhav Hiremath return __raw_readl(prm_base + inst + idx); 33ddd04b98SVaibhav Hiremath } 34ddd04b98SVaibhav Hiremath 35ddd04b98SVaibhav Hiremath /* Write into a register in a PRM instance */ 36ddd04b98SVaibhav Hiremath void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) 37ddd04b98SVaibhav Hiremath { 38ddd04b98SVaibhav Hiremath __raw_writel(val, prm_base + inst + idx); 39ddd04b98SVaibhav Hiremath } 40ddd04b98SVaibhav Hiremath 41ddd04b98SVaibhav Hiremath /* Read-modify-write a register in PRM. Caller must lock */ 42ddd04b98SVaibhav Hiremath u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) 43ddd04b98SVaibhav Hiremath { 44ddd04b98SVaibhav Hiremath u32 v; 45ddd04b98SVaibhav Hiremath 46ddd04b98SVaibhav Hiremath v = am33xx_prm_read_reg(inst, idx); 47ddd04b98SVaibhav Hiremath v &= ~mask; 48ddd04b98SVaibhav Hiremath v |= bits; 49ddd04b98SVaibhav Hiremath am33xx_prm_write_reg(v, inst, idx); 50ddd04b98SVaibhav Hiremath 51ddd04b98SVaibhav Hiremath return v; 52ddd04b98SVaibhav Hiremath } 53ddd04b98SVaibhav Hiremath 54ddd04b98SVaibhav Hiremath /** 55ddd04b98SVaibhav Hiremath * am33xx_prm_is_hardreset_asserted - read the HW reset line state of 56ddd04b98SVaibhav Hiremath * submodules contained in the hwmod module 57ddd04b98SVaibhav Hiremath * @shift: register bit shift corresponding to the reset line to check 58ddd04b98SVaibhav Hiremath * @inst: CM instance register offset (*_INST macro) 59ddd04b98SVaibhav Hiremath * @rstctrl_offs: RM_RSTCTRL register address offset for this module 60ddd04b98SVaibhav Hiremath * 61ddd04b98SVaibhav Hiremath * Returns 1 if the (sub)module hardreset line is currently asserted, 62ddd04b98SVaibhav Hiremath * 0 if the (sub)module hardreset line is not currently asserted, or 63ddd04b98SVaibhav Hiremath * -EINVAL upon parameter error. 64ddd04b98SVaibhav Hiremath */ 65ddd04b98SVaibhav Hiremath int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) 66ddd04b98SVaibhav Hiremath { 67ddd04b98SVaibhav Hiremath u32 v; 68ddd04b98SVaibhav Hiremath 69ddd04b98SVaibhav Hiremath v = am33xx_prm_read_reg(inst, rstctrl_offs); 70ddd04b98SVaibhav Hiremath v &= 1 << shift; 71ddd04b98SVaibhav Hiremath v >>= shift; 72ddd04b98SVaibhav Hiremath 73ddd04b98SVaibhav Hiremath return v; 74ddd04b98SVaibhav Hiremath } 75ddd04b98SVaibhav Hiremath 76ddd04b98SVaibhav Hiremath /** 77ddd04b98SVaibhav Hiremath * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule 78ddd04b98SVaibhav Hiremath * @shift: register bit shift corresponding to the reset line to assert 79ddd04b98SVaibhav Hiremath * @inst: CM instance register offset (*_INST macro) 80ddd04b98SVaibhav Hiremath * @rstctrl_reg: RM_RSTCTRL register address for this module 81ddd04b98SVaibhav Hiremath * 82ddd04b98SVaibhav Hiremath * Some IPs like dsp, ipu or iva contain processors that require an HW 83ddd04b98SVaibhav Hiremath * reset line to be asserted / deasserted in order to fully enable the 84ddd04b98SVaibhav Hiremath * IP. These modules may have multiple hard-reset lines that reset 85ddd04b98SVaibhav Hiremath * different 'submodules' inside the IP block. This function will 86ddd04b98SVaibhav Hiremath * place the submodule into reset. Returns 0 upon success or -EINVAL 87ddd04b98SVaibhav Hiremath * upon an argument error. 88ddd04b98SVaibhav Hiremath */ 89ddd04b98SVaibhav Hiremath int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) 90ddd04b98SVaibhav Hiremath { 91ddd04b98SVaibhav Hiremath u32 mask = 1 << shift; 92ddd04b98SVaibhav Hiremath 93ddd04b98SVaibhav Hiremath am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs); 94ddd04b98SVaibhav Hiremath 95ddd04b98SVaibhav Hiremath return 0; 96ddd04b98SVaibhav Hiremath } 97ddd04b98SVaibhav Hiremath 98ddd04b98SVaibhav Hiremath /** 99ddd04b98SVaibhav Hiremath * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and 100ddd04b98SVaibhav Hiremath * wait 101ddd04b98SVaibhav Hiremath * @shift: register bit shift corresponding to the reset line to deassert 102ddd04b98SVaibhav Hiremath * @inst: CM instance register offset (*_INST macro) 103ddd04b98SVaibhav Hiremath * @rstctrl_reg: RM_RSTCTRL register address for this module 104ddd04b98SVaibhav Hiremath * @rstst_reg: RM_RSTST register address for this module 105ddd04b98SVaibhav Hiremath * 106ddd04b98SVaibhav Hiremath * Some IPs like dsp, ipu or iva contain processors that require an HW 107ddd04b98SVaibhav Hiremath * reset line to be asserted / deasserted in order to fully enable the 108ddd04b98SVaibhav Hiremath * IP. These modules may have multiple hard-reset lines that reset 109ddd04b98SVaibhav Hiremath * different 'submodules' inside the IP block. This function will 110ddd04b98SVaibhav Hiremath * take the submodule out of reset and wait until the PRCM indicates 111ddd04b98SVaibhav Hiremath * that the reset has completed before returning. Returns 0 upon success or 112ddd04b98SVaibhav Hiremath * -EINVAL upon an argument error, -EEXIST if the submodule was already out 113ddd04b98SVaibhav Hiremath * of reset, or -EBUSY if the submodule did not exit reset promptly. 114ddd04b98SVaibhav Hiremath */ 115ddd04b98SVaibhav Hiremath int am33xx_prm_deassert_hardreset(u8 shift, s16 inst, 116ddd04b98SVaibhav Hiremath u16 rstctrl_offs, u16 rstst_offs) 117ddd04b98SVaibhav Hiremath { 118ddd04b98SVaibhav Hiremath int c; 119ddd04b98SVaibhav Hiremath u32 mask = 1 << shift; 120ddd04b98SVaibhav Hiremath 121ddd04b98SVaibhav Hiremath /* Check the current status to avoid de-asserting the line twice */ 122ddd04b98SVaibhav Hiremath if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0) 123ddd04b98SVaibhav Hiremath return -EEXIST; 124ddd04b98SVaibhav Hiremath 125ddd04b98SVaibhav Hiremath /* Clear the reset status by writing 1 to the status bit */ 126ddd04b98SVaibhav Hiremath am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs); 127ddd04b98SVaibhav Hiremath /* de-assert the reset control line */ 128ddd04b98SVaibhav Hiremath am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); 129ddd04b98SVaibhav Hiremath /* wait the status to be set */ 130ddd04b98SVaibhav Hiremath 131ddd04b98SVaibhav Hiremath omap_test_timeout(am33xx_prm_is_hardreset_asserted(shift, inst, 132ddd04b98SVaibhav Hiremath rstst_offs), 133ddd04b98SVaibhav Hiremath MAX_MODULE_HARDRESET_WAIT, c); 134ddd04b98SVaibhav Hiremath 135ddd04b98SVaibhav Hiremath return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; 136ddd04b98SVaibhav Hiremath } 13749815399SPaul Walmsley 13849815399SPaul Walmsley static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 13949815399SPaul Walmsley { 14049815399SPaul Walmsley am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK, 14149815399SPaul Walmsley (pwrst << OMAP_POWERSTATE_SHIFT), 14249815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 14349815399SPaul Walmsley return 0; 14449815399SPaul Walmsley } 14549815399SPaul Walmsley 14649815399SPaul Walmsley static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 14749815399SPaul Walmsley { 14849815399SPaul Walmsley u32 v; 14949815399SPaul Walmsley 15049815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 15149815399SPaul Walmsley v &= OMAP_POWERSTATE_MASK; 15249815399SPaul Walmsley v >>= OMAP_POWERSTATE_SHIFT; 15349815399SPaul Walmsley 15449815399SPaul Walmsley return v; 15549815399SPaul Walmsley } 15649815399SPaul Walmsley 15749815399SPaul Walmsley static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 15849815399SPaul Walmsley { 15949815399SPaul Walmsley u32 v; 16049815399SPaul Walmsley 16149815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 16249815399SPaul Walmsley v &= OMAP_POWERSTATEST_MASK; 16349815399SPaul Walmsley v >>= OMAP_POWERSTATEST_SHIFT; 16449815399SPaul Walmsley 16549815399SPaul Walmsley return v; 16649815399SPaul Walmsley } 16749815399SPaul Walmsley 16849815399SPaul Walmsley static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) 16949815399SPaul Walmsley { 17049815399SPaul Walmsley u32 v; 17149815399SPaul Walmsley 17249815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 17349815399SPaul Walmsley v &= AM33XX_LASTPOWERSTATEENTERED_MASK; 17449815399SPaul Walmsley v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT; 17549815399SPaul Walmsley 17649815399SPaul Walmsley return v; 17749815399SPaul Walmsley } 17849815399SPaul Walmsley 17949815399SPaul Walmsley static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) 18049815399SPaul Walmsley { 18149815399SPaul Walmsley am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK, 18249815399SPaul Walmsley (1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT), 18349815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 18449815399SPaul Walmsley return 0; 18549815399SPaul Walmsley } 18649815399SPaul Walmsley 18749815399SPaul Walmsley static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) 18849815399SPaul Walmsley { 18949815399SPaul Walmsley am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK, 19049815399SPaul Walmsley AM33XX_LASTPOWERSTATEENTERED_MASK, 19149815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstst_offs); 19249815399SPaul Walmsley return 0; 19349815399SPaul Walmsley } 19449815399SPaul Walmsley 19549815399SPaul Walmsley static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) 19649815399SPaul Walmsley { 19749815399SPaul Walmsley u32 m; 19849815399SPaul Walmsley 19949815399SPaul Walmsley m = pwrdm->logicretstate_mask; 20049815399SPaul Walmsley if (!m) 20149815399SPaul Walmsley return -EINVAL; 20249815399SPaul Walmsley 20349815399SPaul Walmsley am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 20449815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 20549815399SPaul Walmsley 20649815399SPaul Walmsley return 0; 20749815399SPaul Walmsley } 20849815399SPaul Walmsley 20949815399SPaul Walmsley static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) 21049815399SPaul Walmsley { 21149815399SPaul Walmsley u32 v; 21249815399SPaul Walmsley 21349815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 21449815399SPaul Walmsley v &= AM33XX_LOGICSTATEST_MASK; 21549815399SPaul Walmsley v >>= AM33XX_LOGICSTATEST_SHIFT; 21649815399SPaul Walmsley 21749815399SPaul Walmsley return v; 21849815399SPaul Walmsley } 21949815399SPaul Walmsley 22049815399SPaul Walmsley static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm) 22149815399SPaul Walmsley { 22249815399SPaul Walmsley u32 v, m; 22349815399SPaul Walmsley 22449815399SPaul Walmsley m = pwrdm->logicretstate_mask; 22549815399SPaul Walmsley if (!m) 22649815399SPaul Walmsley return -EINVAL; 22749815399SPaul Walmsley 22849815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 22949815399SPaul Walmsley v &= m; 23049815399SPaul Walmsley v >>= __ffs(m); 23149815399SPaul Walmsley 23249815399SPaul Walmsley return v; 23349815399SPaul Walmsley } 23449815399SPaul Walmsley 23549815399SPaul Walmsley static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, 23649815399SPaul Walmsley u8 pwrst) 23749815399SPaul Walmsley { 23849815399SPaul Walmsley u32 m; 23949815399SPaul Walmsley 24049815399SPaul Walmsley m = pwrdm->mem_on_mask[bank]; 24149815399SPaul Walmsley if (!m) 24249815399SPaul Walmsley return -EINVAL; 24349815399SPaul Walmsley 24449815399SPaul Walmsley am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 24549815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 24649815399SPaul Walmsley 24749815399SPaul Walmsley return 0; 24849815399SPaul Walmsley } 24949815399SPaul Walmsley 25049815399SPaul Walmsley static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, 25149815399SPaul Walmsley u8 pwrst) 25249815399SPaul Walmsley { 25349815399SPaul Walmsley u32 m; 25449815399SPaul Walmsley 25549815399SPaul Walmsley m = pwrdm->mem_ret_mask[bank]; 25649815399SPaul Walmsley if (!m) 25749815399SPaul Walmsley return -EINVAL; 25849815399SPaul Walmsley 25949815399SPaul Walmsley am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 26049815399SPaul Walmsley pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 26149815399SPaul Walmsley 26249815399SPaul Walmsley return 0; 26349815399SPaul Walmsley } 26449815399SPaul Walmsley 26549815399SPaul Walmsley static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) 26649815399SPaul Walmsley { 26749815399SPaul Walmsley u32 m, v; 26849815399SPaul Walmsley 26949815399SPaul Walmsley m = pwrdm->mem_pwrst_mask[bank]; 27049815399SPaul Walmsley if (!m) 27149815399SPaul Walmsley return -EINVAL; 27249815399SPaul Walmsley 27349815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 27449815399SPaul Walmsley v &= m; 27549815399SPaul Walmsley v >>= __ffs(m); 27649815399SPaul Walmsley 27749815399SPaul Walmsley return v; 27849815399SPaul Walmsley } 27949815399SPaul Walmsley 28049815399SPaul Walmsley static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank) 28149815399SPaul Walmsley { 28249815399SPaul Walmsley u32 m, v; 28349815399SPaul Walmsley 28449815399SPaul Walmsley m = pwrdm->mem_retst_mask[bank]; 28549815399SPaul Walmsley if (!m) 28649815399SPaul Walmsley return -EINVAL; 28749815399SPaul Walmsley 28849815399SPaul Walmsley v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 28949815399SPaul Walmsley v &= m; 29049815399SPaul Walmsley v >>= __ffs(m); 29149815399SPaul Walmsley 29249815399SPaul Walmsley return v; 29349815399SPaul Walmsley } 29449815399SPaul Walmsley 29549815399SPaul Walmsley static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm) 29649815399SPaul Walmsley { 29749815399SPaul Walmsley u32 c = 0; 29849815399SPaul Walmsley 29949815399SPaul Walmsley /* 30049815399SPaul Walmsley * REVISIT: pwrdm_wait_transition() may be better implemented 30149815399SPaul Walmsley * via a callback and a periodic timer check -- how long do we expect 30249815399SPaul Walmsley * powerdomain transitions to take? 30349815399SPaul Walmsley */ 30449815399SPaul Walmsley 30549815399SPaul Walmsley /* XXX Is this udelay() value meaningful? */ 30649815399SPaul Walmsley while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs) 30749815399SPaul Walmsley & OMAP_INTRANSITION_MASK) && 30849815399SPaul Walmsley (c++ < PWRDM_TRANSITION_BAILOUT)) 30949815399SPaul Walmsley udelay(1); 31049815399SPaul Walmsley 31149815399SPaul Walmsley if (c > PWRDM_TRANSITION_BAILOUT) { 31249815399SPaul Walmsley pr_err("powerdomain: %s: waited too long to complete transition\n", 31349815399SPaul Walmsley pwrdm->name); 31449815399SPaul Walmsley return -EAGAIN; 31549815399SPaul Walmsley } 31649815399SPaul Walmsley 31749815399SPaul Walmsley pr_debug("powerdomain: completed transition in %d loops\n", c); 31849815399SPaul Walmsley 31949815399SPaul Walmsley return 0; 32049815399SPaul Walmsley } 32149815399SPaul Walmsley 32249815399SPaul Walmsley struct pwrdm_ops am33xx_pwrdm_operations = { 32349815399SPaul Walmsley .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, 32449815399SPaul Walmsley .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, 32549815399SPaul Walmsley .pwrdm_read_pwrst = am33xx_pwrdm_read_pwrst, 32649815399SPaul Walmsley .pwrdm_read_prev_pwrst = am33xx_pwrdm_read_prev_pwrst, 32749815399SPaul Walmsley .pwrdm_set_logic_retst = am33xx_pwrdm_set_logic_retst, 32849815399SPaul Walmsley .pwrdm_read_logic_pwrst = am33xx_pwrdm_read_logic_pwrst, 32949815399SPaul Walmsley .pwrdm_read_logic_retst = am33xx_pwrdm_read_logic_retst, 33049815399SPaul Walmsley .pwrdm_clear_all_prev_pwrst = am33xx_pwrdm_clear_all_prev_pwrst, 33149815399SPaul Walmsley .pwrdm_set_lowpwrstchange = am33xx_pwrdm_set_lowpwrstchange, 33249815399SPaul Walmsley .pwrdm_read_mem_pwrst = am33xx_pwrdm_read_mem_pwrst, 33349815399SPaul Walmsley .pwrdm_read_mem_retst = am33xx_pwrdm_read_mem_retst, 33449815399SPaul Walmsley .pwrdm_set_mem_onst = am33xx_pwrdm_set_mem_onst, 33549815399SPaul Walmsley .pwrdm_set_mem_retst = am33xx_pwrdm_set_mem_retst, 33649815399SPaul Walmsley .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, 33749815399SPaul Walmsley }; 338