1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2cf21405fSPaul Walmsley /* 3cf21405fSPaul Walmsley * OMAP2/3 PRM module functions 4cf21405fSPaul Walmsley * 526c98c56SPaul Walmsley * Copyright (C) 2010-2011 Texas Instruments, Inc. 6cf21405fSPaul Walmsley * Copyright (C) 2010 Nokia Corporation 7cf21405fSPaul Walmsley * Benoît Cousson 8cf21405fSPaul Walmsley * Paul Walmsley 9cf21405fSPaul Walmsley */ 10cf21405fSPaul Walmsley 11cf21405fSPaul Walmsley #include <linux/kernel.h> 12cf21405fSPaul Walmsley #include <linux/errno.h> 13cf21405fSPaul Walmsley #include <linux/err.h> 1459fb659bSPaul Walmsley #include <linux/io.h> 15cf21405fSPaul Walmsley 1649815399SPaul Walmsley #include "powerdomain.h" 1759fb659bSPaul Walmsley #include "prm2xxx_3xxx.h" 18cf21405fSPaul Walmsley #include "prm-regbits-24xx.h" 194bd5259eSPaul Walmsley #include "clockdomain.h" 2059fb659bSPaul Walmsley 21cf21405fSPaul Walmsley /** 22cf21405fSPaul Walmsley * omap2_prm_is_hardreset_asserted - read the HW reset line state of 23cf21405fSPaul Walmsley * submodules contained in the hwmod module 24cf21405fSPaul Walmsley * @shift: register bit shift corresponding to the reset line to check 251bc28b34STero Kristo * @part: PRM partition, ignored for OMAP2 261bc28b34STero Kristo * @prm_mod: PRM submodule base (e.g. CORE_MOD) 271bc28b34STero Kristo * @offset: register offset, ignored for OMAP2 28cf21405fSPaul Walmsley * 29cf21405fSPaul Walmsley * Returns 1 if the (sub)module hardreset line is currently asserted, 30cf21405fSPaul Walmsley * 0 if the (sub)module hardreset line is not currently asserted, or 31cf21405fSPaul Walmsley * -EINVAL if called while running on a non-OMAP2/3 chip. 32cf21405fSPaul Walmsley */ 331bc28b34STero Kristo int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) 34cf21405fSPaul Walmsley { 35c4d7e58fSPaul Walmsley return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, 36cf21405fSPaul Walmsley (1 << shift)); 37cf21405fSPaul Walmsley } 38cf21405fSPaul Walmsley 39cf21405fSPaul Walmsley /** 40cf21405fSPaul Walmsley * omap2_prm_assert_hardreset - assert the HW reset line of a submodule 41cf21405fSPaul Walmsley * @shift: register bit shift corresponding to the reset line to assert 42efd44dc3STero Kristo * @part: PRM partition, ignored for OMAP2 43efd44dc3STero Kristo * @prm_mod: PRM submodule base (e.g. CORE_MOD) 44efd44dc3STero Kristo * @offset: register offset, ignored for OMAP2 45cf21405fSPaul Walmsley * 46cf21405fSPaul Walmsley * Some IPs like dsp or iva contain processors that require an HW 47cf21405fSPaul Walmsley * reset line to be asserted / deasserted in order to fully enable the 48cf21405fSPaul Walmsley * IP. These modules may have multiple hard-reset lines that reset 49cf21405fSPaul Walmsley * different 'submodules' inside the IP block. This function will 50cf21405fSPaul Walmsley * place the submodule into reset. Returns 0 upon success or -EINVAL 51cf21405fSPaul Walmsley * upon an argument error. 52cf21405fSPaul Walmsley */ 53efd44dc3STero Kristo int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) 54cf21405fSPaul Walmsley { 55cf21405fSPaul Walmsley u32 mask; 56cf21405fSPaul Walmsley 57cf21405fSPaul Walmsley mask = 1 << shift; 58c4d7e58fSPaul Walmsley omap2_prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL); 59cf21405fSPaul Walmsley 60cf21405fSPaul Walmsley return 0; 61cf21405fSPaul Walmsley } 62cf21405fSPaul Walmsley 63cf21405fSPaul Walmsley /** 64cf21405fSPaul Walmsley * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait 65cf21405fSPaul Walmsley * @prm_mod: PRM submodule base (e.g. CORE_MOD) 66cc1226e7Somar ramirez * @rst_shift: register bit shift corresponding to the reset line to deassert 67cc1226e7Somar ramirez * @st_shift: register bit shift for the status of the deasserted submodule 6837fb59d7STero Kristo * @part: PRM partition, not used for OMAP2 6937fb59d7STero Kristo * @prm_mod: PRM submodule base (e.g. CORE_MOD) 7037fb59d7STero Kristo * @rst_offset: reset register offset, not used for OMAP2 7137fb59d7STero Kristo * @st_offset: reset status register offset, not used for OMAP2 72cf21405fSPaul Walmsley * 73cf21405fSPaul Walmsley * Some IPs like dsp or iva contain processors that require an HW 74cf21405fSPaul Walmsley * reset line to be asserted / deasserted in order to fully enable the 75cf21405fSPaul Walmsley * IP. These modules may have multiple hard-reset lines that reset 76cf21405fSPaul Walmsley * different 'submodules' inside the IP block. This function will 77cf21405fSPaul Walmsley * take the submodule out of reset and wait until the PRCM indicates 78cf21405fSPaul Walmsley * that the reset has completed before returning. Returns 0 upon success or 79cf21405fSPaul Walmsley * -EINVAL upon an argument error, -EEXIST if the submodule was already out 80cf21405fSPaul Walmsley * of reset, or -EBUSY if the submodule did not exit reset promptly. 81cf21405fSPaul Walmsley */ 8237fb59d7STero Kristo int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, 8337fb59d7STero Kristo s16 prm_mod, u16 rst_offset, u16 st_offset) 84cf21405fSPaul Walmsley { 85cc1226e7Somar ramirez u32 rst, st; 86cf21405fSPaul Walmsley int c; 87cf21405fSPaul Walmsley 88cc1226e7Somar ramirez rst = 1 << rst_shift; 89cc1226e7Somar ramirez st = 1 << st_shift; 90cf21405fSPaul Walmsley 91cf21405fSPaul Walmsley /* Check the current status to avoid de-asserting the line twice */ 92cc1226e7Somar ramirez if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, rst) == 0) 93cf21405fSPaul Walmsley return -EEXIST; 94cf21405fSPaul Walmsley 95cf21405fSPaul Walmsley /* Clear the reset status by writing 1 to the status bit */ 96cc1226e7Somar ramirez omap2_prm_rmw_mod_reg_bits(0xffffffff, st, prm_mod, OMAP2_RM_RSTST); 97cf21405fSPaul Walmsley /* de-assert the reset control line */ 98cc1226e7Somar ramirez omap2_prm_rmw_mod_reg_bits(rst, 0, prm_mod, OMAP2_RM_RSTCTRL); 99cf21405fSPaul Walmsley /* wait the status to be set */ 100c4d7e58fSPaul Walmsley omap_test_timeout(omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST, 101cc1226e7Somar ramirez st), 102cf21405fSPaul Walmsley MAX_MODULE_HARDRESET_WAIT, c); 103cf21405fSPaul Walmsley 104cf21405fSPaul Walmsley return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; 105cf21405fSPaul Walmsley } 10658aaa599SKevin Hilman 10749815399SPaul Walmsley 10849815399SPaul Walmsley /* Powerdomain low-level functions */ 10949815399SPaul Walmsley 11049815399SPaul Walmsley /* Common functions across OMAP2 and OMAP3 */ 11149815399SPaul Walmsley int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, 11249815399SPaul Walmsley u8 pwrst) 11349815399SPaul Walmsley { 11449815399SPaul Walmsley u32 m; 11549815399SPaul Walmsley 11649815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_onstate_mask(bank); 11749815399SPaul Walmsley 11849815399SPaul Walmsley omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs, 11949815399SPaul Walmsley OMAP2_PM_PWSTCTRL); 12049815399SPaul Walmsley 12149815399SPaul Walmsley return 0; 12249815399SPaul Walmsley } 12349815399SPaul Walmsley 12449815399SPaul Walmsley int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, 12549815399SPaul Walmsley u8 pwrst) 12649815399SPaul Walmsley { 12749815399SPaul Walmsley u32 m; 12849815399SPaul Walmsley 12949815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_retst_mask(bank); 13049815399SPaul Walmsley 13149815399SPaul Walmsley omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs, 13249815399SPaul Walmsley OMAP2_PM_PWSTCTRL); 13349815399SPaul Walmsley 13449815399SPaul Walmsley return 0; 13549815399SPaul Walmsley } 13649815399SPaul Walmsley 13749815399SPaul Walmsley int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) 13849815399SPaul Walmsley { 13949815399SPaul Walmsley u32 m; 14049815399SPaul Walmsley 14149815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_stst_mask(bank); 14249815399SPaul Walmsley 14349815399SPaul Walmsley return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST, 14449815399SPaul Walmsley m); 14549815399SPaul Walmsley } 14649815399SPaul Walmsley 14749815399SPaul Walmsley int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank) 14849815399SPaul Walmsley { 14949815399SPaul Walmsley u32 m; 15049815399SPaul Walmsley 15149815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_retst_mask(bank); 15249815399SPaul Walmsley 15349815399SPaul Walmsley return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 15449815399SPaul Walmsley OMAP2_PM_PWSTCTRL, m); 15549815399SPaul Walmsley } 15649815399SPaul Walmsley 15749815399SPaul Walmsley int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) 15849815399SPaul Walmsley { 15949815399SPaul Walmsley u32 v; 16049815399SPaul Walmsley 16149815399SPaul Walmsley v = pwrst << __ffs(OMAP_LOGICRETSTATE_MASK); 16249815399SPaul Walmsley omap2_prm_rmw_mod_reg_bits(OMAP_LOGICRETSTATE_MASK, v, pwrdm->prcm_offs, 16349815399SPaul Walmsley OMAP2_PM_PWSTCTRL); 16449815399SPaul Walmsley 16549815399SPaul Walmsley return 0; 16649815399SPaul Walmsley } 16749815399SPaul Walmsley 16849815399SPaul Walmsley int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm) 16949815399SPaul Walmsley { 17049815399SPaul Walmsley u32 c = 0; 17149815399SPaul Walmsley 17249815399SPaul Walmsley /* 17349815399SPaul Walmsley * REVISIT: pwrdm_wait_transition() may be better implemented 17449815399SPaul Walmsley * via a callback and a periodic timer check -- how long do we expect 17549815399SPaul Walmsley * powerdomain transitions to take? 17649815399SPaul Walmsley */ 17749815399SPaul Walmsley 17849815399SPaul Walmsley /* XXX Is this udelay() value meaningful? */ 17949815399SPaul Walmsley while ((omap2_prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) & 18049815399SPaul Walmsley OMAP_INTRANSITION_MASK) && 18149815399SPaul Walmsley (c++ < PWRDM_TRANSITION_BAILOUT)) 18249815399SPaul Walmsley udelay(1); 18349815399SPaul Walmsley 18449815399SPaul Walmsley if (c > PWRDM_TRANSITION_BAILOUT) { 18549815399SPaul Walmsley pr_err("powerdomain: %s: waited too long to complete transition\n", 18649815399SPaul Walmsley pwrdm->name); 18749815399SPaul Walmsley return -EAGAIN; 18849815399SPaul Walmsley } 18949815399SPaul Walmsley 19049815399SPaul Walmsley pr_debug("powerdomain: completed transition in %d loops\n", c); 19149815399SPaul Walmsley 19249815399SPaul Walmsley return 0; 19349815399SPaul Walmsley } 19449815399SPaul Walmsley 1954bd5259eSPaul Walmsley int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1, 1964bd5259eSPaul Walmsley struct clockdomain *clkdm2) 1974bd5259eSPaul Walmsley { 1984bd5259eSPaul Walmsley omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit), 1994bd5259eSPaul Walmsley clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 2004bd5259eSPaul Walmsley return 0; 2014bd5259eSPaul Walmsley } 2024bd5259eSPaul Walmsley 2034bd5259eSPaul Walmsley int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1, 2044bd5259eSPaul Walmsley struct clockdomain *clkdm2) 2054bd5259eSPaul Walmsley { 2064bd5259eSPaul Walmsley omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 2074bd5259eSPaul Walmsley clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 2084bd5259eSPaul Walmsley return 0; 2094bd5259eSPaul Walmsley } 2104bd5259eSPaul Walmsley 2114bd5259eSPaul Walmsley int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1, 2124bd5259eSPaul Walmsley struct clockdomain *clkdm2) 2134bd5259eSPaul Walmsley { 2144bd5259eSPaul Walmsley return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, 2154bd5259eSPaul Walmsley PM_WKDEP, (1 << clkdm2->dep_bit)); 2164bd5259eSPaul Walmsley } 2174bd5259eSPaul Walmsley 21892493870SPaul Walmsley /* XXX Caller must hold the clkdm's powerdomain lock */ 2194bd5259eSPaul Walmsley int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) 2204bd5259eSPaul Walmsley { 2214bd5259eSPaul Walmsley struct clkdm_dep *cd; 2224bd5259eSPaul Walmsley u32 mask = 0; 2234bd5259eSPaul Walmsley 2244bd5259eSPaul Walmsley for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { 2254bd5259eSPaul Walmsley if (!cd->clkdm) 2264bd5259eSPaul Walmsley continue; /* only happens if data is erroneous */ 2274bd5259eSPaul Walmsley 2284bd5259eSPaul Walmsley /* PRM accesses are slow, so minimize them */ 2294bd5259eSPaul Walmsley mask |= 1 << cd->clkdm->dep_bit; 23092493870SPaul Walmsley cd->wkdep_usecount = 0; 2314bd5259eSPaul Walmsley } 2324bd5259eSPaul Walmsley 2334bd5259eSPaul Walmsley omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, 2344bd5259eSPaul Walmsley PM_WKDEP); 2354bd5259eSPaul Walmsley return 0; 2364bd5259eSPaul Walmsley } 2374bd5259eSPaul Walmsley 238