18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * AM33XX PRM functions 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 118c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 128c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138c2ecf20Sopenharmony_ci * GNU General Public License for more details. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/errno.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "powerdomain.h" 238c2ecf20Sopenharmony_ci#include "prm33xx.h" 248c2ecf20Sopenharmony_ci#include "prm-regbits-33xx.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define AM33XX_PRM_RSTCTRL_OFFSET 0x0000 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Read a register in a PRM instance */ 318c2ecf20Sopenharmony_cistatic u32 am33xx_prm_read_reg(s16 inst, u16 idx) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci return readl_relaxed(prm_base.va + inst + idx); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Write into a register in a PRM instance */ 378c2ecf20Sopenharmony_cistatic void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci writel_relaxed(val, prm_base.va + inst + idx); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Read-modify-write a register in PRM. Caller must lock */ 438c2ecf20Sopenharmony_cistatic u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci u32 v; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(inst, idx); 488c2ecf20Sopenharmony_ci v &= ~mask; 498c2ecf20Sopenharmony_ci v |= bits; 508c2ecf20Sopenharmony_ci am33xx_prm_write_reg(v, inst, idx); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return v; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * am33xx_prm_is_hardreset_asserted - read the HW reset line state of 578c2ecf20Sopenharmony_ci * submodules contained in the hwmod module 588c2ecf20Sopenharmony_ci * @shift: register bit shift corresponding to the reset line to check 598c2ecf20Sopenharmony_ci * @part: PRM partition, ignored for AM33xx 608c2ecf20Sopenharmony_ci * @inst: CM instance register offset (*_INST macro) 618c2ecf20Sopenharmony_ci * @rstctrl_offs: RM_RSTCTRL register address offset for this module 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * Returns 1 if the (sub)module hardreset line is currently asserted, 648c2ecf20Sopenharmony_ci * 0 if the (sub)module hardreset line is not currently asserted, or 658c2ecf20Sopenharmony_ci * -EINVAL upon parameter error. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst, 688c2ecf20Sopenharmony_ci u16 rstctrl_offs) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci u32 v; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(inst, rstctrl_offs); 738c2ecf20Sopenharmony_ci v &= 1 << shift; 748c2ecf20Sopenharmony_ci v >>= shift; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return v; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule 818c2ecf20Sopenharmony_ci * @shift: register bit shift corresponding to the reset line to assert 828c2ecf20Sopenharmony_ci * @part: CM partition, ignored for AM33xx 838c2ecf20Sopenharmony_ci * @inst: CM instance register offset (*_INST macro) 848c2ecf20Sopenharmony_ci * @rstctrl_reg: RM_RSTCTRL register address for this module 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Some IPs like dsp, ipu or iva contain processors that require an HW 878c2ecf20Sopenharmony_ci * reset line to be asserted / deasserted in order to fully enable the 888c2ecf20Sopenharmony_ci * IP. These modules may have multiple hard-reset lines that reset 898c2ecf20Sopenharmony_ci * different 'submodules' inside the IP block. This function will 908c2ecf20Sopenharmony_ci * place the submodule into reset. Returns 0 upon success or -EINVAL 918c2ecf20Sopenharmony_ci * upon an argument error. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistatic int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst, 948c2ecf20Sopenharmony_ci u16 rstctrl_offs) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci u32 mask = 1 << shift; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and 1058c2ecf20Sopenharmony_ci * wait 1068c2ecf20Sopenharmony_ci * @shift: register bit shift corresponding to the reset line to deassert 1078c2ecf20Sopenharmony_ci * @st_shift: reset status register bit shift corresponding to the reset line 1088c2ecf20Sopenharmony_ci * @part: PRM partition, not used for AM33xx 1098c2ecf20Sopenharmony_ci * @inst: CM instance register offset (*_INST macro) 1108c2ecf20Sopenharmony_ci * @rstctrl_reg: RM_RSTCTRL register address for this module 1118c2ecf20Sopenharmony_ci * @rstst_reg: RM_RSTST register address for this module 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * Some IPs like dsp, ipu or iva contain processors that require an HW 1148c2ecf20Sopenharmony_ci * reset line to be asserted / deasserted in order to fully enable the 1158c2ecf20Sopenharmony_ci * IP. These modules may have multiple hard-reset lines that reset 1168c2ecf20Sopenharmony_ci * different 'submodules' inside the IP block. This function will 1178c2ecf20Sopenharmony_ci * take the submodule out of reset and wait until the PRCM indicates 1188c2ecf20Sopenharmony_ci * that the reset has completed before returning. Returns 0 upon success or 1198c2ecf20Sopenharmony_ci * -EINVAL upon an argument error, -EEXIST if the submodule was already out 1208c2ecf20Sopenharmony_ci * of reset, or -EBUSY if the submodule did not exit reset promptly. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, 1238c2ecf20Sopenharmony_ci s16 inst, u16 rstctrl_offs, 1248c2ecf20Sopenharmony_ci u16 rstst_offs) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci int c; 1278c2ecf20Sopenharmony_ci u32 mask = 1 << st_shift; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Check the current status to avoid de-asserting the line twice */ 1308c2ecf20Sopenharmony_ci if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0) 1318c2ecf20Sopenharmony_ci return -EEXIST; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Clear the reset status by writing 1 to the status bit */ 1348c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* de-assert the reset control line */ 1378c2ecf20Sopenharmony_ci mask = 1 << shift; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* wait the status to be set */ 1428c2ecf20Sopenharmony_ci omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst, 1438c2ecf20Sopenharmony_ci rstst_offs), 1448c2ecf20Sopenharmony_ci MAX_MODULE_HARDRESET_WAIT, c); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK, 1528c2ecf20Sopenharmony_ci (pwrst << OMAP_POWERSTATE_SHIFT), 1538c2ecf20Sopenharmony_ci pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci u32 v; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 1628c2ecf20Sopenharmony_ci v &= OMAP_POWERSTATE_MASK; 1638c2ecf20Sopenharmony_ci v >>= OMAP_POWERSTATE_SHIFT; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return v; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci u32 v; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 1738c2ecf20Sopenharmony_ci v &= OMAP_POWERSTATEST_MASK; 1748c2ecf20Sopenharmony_ci v >>= OMAP_POWERSTATEST_SHIFT; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return v; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK, 1828c2ecf20Sopenharmony_ci (1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT), 1838c2ecf20Sopenharmony_ci pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK, 1908c2ecf20Sopenharmony_ci AM33XX_LASTPOWERSTATEENTERED_MASK, 1918c2ecf20Sopenharmony_ci pwrdm->prcm_offs, pwrdm->pwrstst_offs); 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci u32 m; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci m = pwrdm->logicretstate_mask; 2008c2ecf20Sopenharmony_ci if (!m) 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 2048c2ecf20Sopenharmony_ci pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci u32 v; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 2148c2ecf20Sopenharmony_ci v &= AM33XX_LOGICSTATEST_MASK; 2158c2ecf20Sopenharmony_ci v >>= AM33XX_LOGICSTATEST_SHIFT; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return v; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci u32 v, m; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci m = pwrdm->logicretstate_mask; 2258c2ecf20Sopenharmony_ci if (!m) 2268c2ecf20Sopenharmony_ci return -EINVAL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 2298c2ecf20Sopenharmony_ci v &= m; 2308c2ecf20Sopenharmony_ci v >>= __ffs(m); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return v; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, 2368c2ecf20Sopenharmony_ci u8 pwrst) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci u32 m; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci m = pwrdm->mem_on_mask[bank]; 2418c2ecf20Sopenharmony_ci if (!m) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 2458c2ecf20Sopenharmony_ci pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, 2518c2ecf20Sopenharmony_ci u8 pwrst) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci u32 m; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci m = pwrdm->mem_ret_mask[bank]; 2568c2ecf20Sopenharmony_ci if (!m) 2578c2ecf20Sopenharmony_ci return -EINVAL; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)), 2608c2ecf20Sopenharmony_ci pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci u32 m, v; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci m = pwrdm->mem_pwrst_mask[bank]; 2708c2ecf20Sopenharmony_ci if (!m) 2718c2ecf20Sopenharmony_ci return -EINVAL; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs); 2748c2ecf20Sopenharmony_ci v &= m; 2758c2ecf20Sopenharmony_ci v >>= __ffs(m); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return v; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci u32 m, v; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci m = pwrdm->mem_retst_mask[bank]; 2858c2ecf20Sopenharmony_ci if (!m) 2868c2ecf20Sopenharmony_ci return -EINVAL; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs); 2898c2ecf20Sopenharmony_ci v &= m; 2908c2ecf20Sopenharmony_ci v >>= __ffs(m); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return v; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci u32 c = 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * REVISIT: pwrdm_wait_transition() may be better implemented 3018c2ecf20Sopenharmony_ci * via a callback and a periodic timer check -- how long do we expect 3028c2ecf20Sopenharmony_ci * powerdomain transitions to take? 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* XXX Is this udelay() value meaningful? */ 3068c2ecf20Sopenharmony_ci while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs) 3078c2ecf20Sopenharmony_ci & OMAP_INTRANSITION_MASK) && 3088c2ecf20Sopenharmony_ci (c++ < PWRDM_TRANSITION_BAILOUT)) 3098c2ecf20Sopenharmony_ci udelay(1); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (c > PWRDM_TRANSITION_BAILOUT) { 3128c2ecf20Sopenharmony_ci pr_err("powerdomain: %s: waited too long to complete transition\n", 3138c2ecf20Sopenharmony_ci pwrdm->name); 3148c2ecf20Sopenharmony_ci return -EAGAIN; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pr_debug("powerdomain: completed transition in %d loops\n", c); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int am33xx_check_vcvp(void) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci /* No VC/VP on am33xx devices */ 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/** 3298c2ecf20Sopenharmony_ci * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * Immediately reboots the device through warm reset. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_cistatic void am33xx_prm_global_warm_sw_reset(void) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, 3368c2ecf20Sopenharmony_ci AM33XX_RST_GLOBAL_WARM_SW_MASK, 3378c2ecf20Sopenharmony_ci AM33XX_PRM_DEVICE_MOD, 3388c2ecf20Sopenharmony_ci AM33XX_PRM_RSTCTRL_OFFSET); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* OCP barrier */ 3418c2ecf20Sopenharmony_ci (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, 3428c2ecf20Sopenharmony_ci AM33XX_PRM_RSTCTRL_OFFSET); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic void am33xx_pwrdm_save_context(struct powerdomain *pwrdm) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci pwrdm->context = am33xx_prm_read_reg(pwrdm->prcm_offs, 3488c2ecf20Sopenharmony_ci pwrdm->pwrstctrl_offs); 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request, 3518c2ecf20Sopenharmony_ci * reading back a 1 indicates a request in progress. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci pwrdm->context &= ~AM33XX_LOWPOWERSTATECHANGE_MASK; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void am33xx_pwrdm_restore_context(struct powerdomain *pwrdm) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci int st, ctrl; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci st = am33xx_prm_read_reg(pwrdm->prcm_offs, 3618c2ecf20Sopenharmony_ci pwrdm->pwrstst_offs); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci am33xx_prm_write_reg(pwrdm->context, pwrdm->prcm_offs, 3648c2ecf20Sopenharmony_ci pwrdm->pwrstctrl_offs); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Make sure we only wait for a transition if there is one */ 3678c2ecf20Sopenharmony_ci st &= OMAP_POWERSTATEST_MASK; 3688c2ecf20Sopenharmony_ci ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (st != ctrl) 3718c2ecf20Sopenharmony_ci am33xx_pwrdm_wait_transition(pwrdm); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistruct pwrdm_ops am33xx_pwrdm_operations = { 3758c2ecf20Sopenharmony_ci .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, 3768c2ecf20Sopenharmony_ci .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, 3778c2ecf20Sopenharmony_ci .pwrdm_read_pwrst = am33xx_pwrdm_read_pwrst, 3788c2ecf20Sopenharmony_ci .pwrdm_set_logic_retst = am33xx_pwrdm_set_logic_retst, 3798c2ecf20Sopenharmony_ci .pwrdm_read_logic_pwrst = am33xx_pwrdm_read_logic_pwrst, 3808c2ecf20Sopenharmony_ci .pwrdm_read_logic_retst = am33xx_pwrdm_read_logic_retst, 3818c2ecf20Sopenharmony_ci .pwrdm_clear_all_prev_pwrst = am33xx_pwrdm_clear_all_prev_pwrst, 3828c2ecf20Sopenharmony_ci .pwrdm_set_lowpwrstchange = am33xx_pwrdm_set_lowpwrstchange, 3838c2ecf20Sopenharmony_ci .pwrdm_read_mem_pwrst = am33xx_pwrdm_read_mem_pwrst, 3848c2ecf20Sopenharmony_ci .pwrdm_read_mem_retst = am33xx_pwrdm_read_mem_retst, 3858c2ecf20Sopenharmony_ci .pwrdm_set_mem_onst = am33xx_pwrdm_set_mem_onst, 3868c2ecf20Sopenharmony_ci .pwrdm_set_mem_retst = am33xx_pwrdm_set_mem_retst, 3878c2ecf20Sopenharmony_ci .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, 3888c2ecf20Sopenharmony_ci .pwrdm_has_voltdm = am33xx_check_vcvp, 3898c2ecf20Sopenharmony_ci .pwrdm_save_context = am33xx_pwrdm_save_context, 3908c2ecf20Sopenharmony_ci .pwrdm_restore_context = am33xx_pwrdm_restore_context, 3918c2ecf20Sopenharmony_ci}; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct prm_ll_data am33xx_prm_ll_data = { 3948c2ecf20Sopenharmony_ci .assert_hardreset = am33xx_prm_assert_hardreset, 3958c2ecf20Sopenharmony_ci .deassert_hardreset = am33xx_prm_deassert_hardreset, 3968c2ecf20Sopenharmony_ci .is_hardreset_asserted = am33xx_prm_is_hardreset_asserted, 3978c2ecf20Sopenharmony_ci .reset_system = am33xx_prm_global_warm_sw_reset, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ciint __init am33xx_prm_init(const struct omap_prcm_init_data *data) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci return prm_register(&am33xx_prm_ll_data); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void __exit am33xx_prm_exit(void) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci prm_unregister(&am33xx_prm_ll_data); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci__exitcall(am33xx_prm_exit); 410