149815399SPaul Walmsley /* 249815399SPaul Walmsley * OMAP2xxx PRM module functions 349815399SPaul Walmsley * 449815399SPaul Walmsley * Copyright (C) 2010-2012 Texas Instruments, Inc. 549815399SPaul Walmsley * Copyright (C) 2010 Nokia Corporation 649815399SPaul Walmsley * Benoît Cousson 749815399SPaul Walmsley * Paul Walmsley 849815399SPaul Walmsley * Rajendra Nayak <rnayak@ti.com> 949815399SPaul Walmsley * 1049815399SPaul Walmsley * This program is free software; you can redistribute it and/or modify 1149815399SPaul Walmsley * it under the terms of the GNU General Public License version 2 as 1249815399SPaul Walmsley * published by the Free Software Foundation. 1349815399SPaul Walmsley */ 1449815399SPaul Walmsley 1549815399SPaul Walmsley #include <linux/kernel.h> 1649815399SPaul Walmsley #include <linux/errno.h> 1749815399SPaul Walmsley #include <linux/err.h> 1849815399SPaul Walmsley #include <linux/io.h> 1949815399SPaul Walmsley #include <linux/irq.h> 2049815399SPaul Walmsley 2149815399SPaul Walmsley #include "powerdomain.h" 224bd5259eSPaul Walmsley #include "clockdomain.h" 2349815399SPaul Walmsley #include "prm2xxx.h" 2449815399SPaul Walmsley #include "cm2xxx_3xxx.h" 2549815399SPaul Walmsley #include "prm-regbits-24xx.h" 2649815399SPaul Walmsley 272bb2a5d3SPaul Walmsley /* 287e7fff82SPaul Walmsley * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits - 297e7fff82SPaul Walmsley * these are reversed from the bits used on OMAP3+ 307e7fff82SPaul Walmsley */ 317e7fff82SPaul Walmsley #define OMAP24XX_PWRDM_POWER_ON 0x0 327e7fff82SPaul Walmsley #define OMAP24XX_PWRDM_POWER_RET 0x1 337e7fff82SPaul Walmsley #define OMAP24XX_PWRDM_POWER_OFF 0x3 347e7fff82SPaul Walmsley 357e7fff82SPaul Walmsley /* 362bb2a5d3SPaul Walmsley * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP 372bb2a5d3SPaul Walmsley * hardware register (which are specific to the OMAP2xxx SoCs) to 382bb2a5d3SPaul Walmsley * reset source ID bit shifts (which is an OMAP SoC-independent 392bb2a5d3SPaul Walmsley * enumeration) 402bb2a5d3SPaul Walmsley */ 412bb2a5d3SPaul Walmsley static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = { 422bb2a5d3SPaul Walmsley { OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, 432bb2a5d3SPaul Walmsley { OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, 442bb2a5d3SPaul Walmsley { OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, 452bb2a5d3SPaul Walmsley { OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, 462bb2a5d3SPaul Walmsley { OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT }, 472bb2a5d3SPaul Walmsley { OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, 482bb2a5d3SPaul Walmsley { -1, -1 }, 492bb2a5d3SPaul Walmsley }; 502bb2a5d3SPaul Walmsley 512bb2a5d3SPaul Walmsley /** 522bb2a5d3SPaul Walmsley * omap2xxx_prm_read_reset_sources - return the last SoC reset source 532bb2a5d3SPaul Walmsley * 542bb2a5d3SPaul Walmsley * Return a u32 representing the last reset sources of the SoC. The 552bb2a5d3SPaul Walmsley * returned reset source bits are standardized across OMAP SoCs. 562bb2a5d3SPaul Walmsley */ 572bb2a5d3SPaul Walmsley static u32 omap2xxx_prm_read_reset_sources(void) 582bb2a5d3SPaul Walmsley { 592bb2a5d3SPaul Walmsley struct prm_reset_src_map *p; 602bb2a5d3SPaul Walmsley u32 r = 0; 612bb2a5d3SPaul Walmsley u32 v; 622bb2a5d3SPaul Walmsley 632bb2a5d3SPaul Walmsley v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); 642bb2a5d3SPaul Walmsley 652bb2a5d3SPaul Walmsley p = omap2xxx_prm_reset_src_map; 662bb2a5d3SPaul Walmsley while (p->reg_shift >= 0 && p->std_shift >= 0) { 672bb2a5d3SPaul Walmsley if (v & (1 << p->reg_shift)) 682bb2a5d3SPaul Walmsley r |= 1 << p->std_shift; 692bb2a5d3SPaul Walmsley p++; 702bb2a5d3SPaul Walmsley } 712bb2a5d3SPaul Walmsley 722bb2a5d3SPaul Walmsley return r; 732bb2a5d3SPaul Walmsley } 742bb2a5d3SPaul Walmsley 75d08cce6aSPaul Walmsley /** 767e7fff82SPaul Walmsley * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst 777e7fff82SPaul Walmsley * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert 787e7fff82SPaul Walmsley * 797e7fff82SPaul Walmsley * Return the common power state bits corresponding to the OMAP2xxx 807e7fff82SPaul Walmsley * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error. 817e7fff82SPaul Walmsley */ 827e7fff82SPaul Walmsley static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) 837e7fff82SPaul Walmsley { 847e7fff82SPaul Walmsley u8 pwrst; 857e7fff82SPaul Walmsley 867e7fff82SPaul Walmsley switch (omap2xxx_pwrst) { 877e7fff82SPaul Walmsley case OMAP24XX_PWRDM_POWER_OFF: 887e7fff82SPaul Walmsley pwrst = PWRDM_POWER_OFF; 897e7fff82SPaul Walmsley break; 907e7fff82SPaul Walmsley case OMAP24XX_PWRDM_POWER_RET: 917e7fff82SPaul Walmsley pwrst = PWRDM_POWER_RET; 927e7fff82SPaul Walmsley break; 937e7fff82SPaul Walmsley case OMAP24XX_PWRDM_POWER_ON: 947e7fff82SPaul Walmsley pwrst = PWRDM_POWER_ON; 957e7fff82SPaul Walmsley break; 967e7fff82SPaul Walmsley default: 977e7fff82SPaul Walmsley return -EINVAL; 987e7fff82SPaul Walmsley } 997e7fff82SPaul Walmsley 1007e7fff82SPaul Walmsley return pwrst; 1017e7fff82SPaul Walmsley } 1027e7fff82SPaul Walmsley 1037e7fff82SPaul Walmsley /** 104d08cce6aSPaul Walmsley * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC 105d08cce6aSPaul Walmsley * 106d08cce6aSPaul Walmsley * Set the DPLL reset bit, which should reboot the SoC. This is the 107d08cce6aSPaul Walmsley * recommended way to restart the SoC. No return value. 108d08cce6aSPaul Walmsley */ 109d08cce6aSPaul Walmsley void omap2xxx_prm_dpll_reset(void) 110d08cce6aSPaul Walmsley { 111d08cce6aSPaul Walmsley omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, 112d08cce6aSPaul Walmsley OMAP2_RM_RSTCTRL); 113d08cce6aSPaul Walmsley /* OCP barrier */ 114d08cce6aSPaul Walmsley omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL); 115d08cce6aSPaul Walmsley } 116d08cce6aSPaul Walmsley 1176bdc4b44STero Kristo /** 1186bdc4b44STero Kristo * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module 1196bdc4b44STero Kristo * @module: PRM module to clear wakeups from 1206bdc4b44STero Kristo * @regs: register offset to clear 1216bdc4b44STero Kristo * @wkst_mask: wakeup status mask to clear 1226bdc4b44STero Kristo * 1236bdc4b44STero Kristo * Clears wakeup status bits for a given module, so that the device can 1246bdc4b44STero Kristo * re-enter idle. 1256bdc4b44STero Kristo */ 1266bdc4b44STero Kristo void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) 1276bdc4b44STero Kristo { 1286bdc4b44STero Kristo u32 wkst; 1296bdc4b44STero Kristo 1306bdc4b44STero Kristo wkst = omap2_prm_read_mod_reg(module, regs); 1316bdc4b44STero Kristo wkst &= wkst_mask; 1326bdc4b44STero Kristo omap2_prm_write_mod_reg(wkst, module, regs); 1336bdc4b44STero Kristo } 1346bdc4b44STero Kristo 1354bd5259eSPaul Walmsley int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) 1364bd5259eSPaul Walmsley { 1374bd5259eSPaul Walmsley omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 1384bd5259eSPaul Walmsley clkdm->pwrdm.ptr->prcm_offs, 1394bd5259eSPaul Walmsley OMAP2_PM_PWSTCTRL); 1404bd5259eSPaul Walmsley return 0; 1414bd5259eSPaul Walmsley } 1424bd5259eSPaul Walmsley 1434bd5259eSPaul Walmsley int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm) 1444bd5259eSPaul Walmsley { 1454bd5259eSPaul Walmsley omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 1464bd5259eSPaul Walmsley clkdm->pwrdm.ptr->prcm_offs, 1474bd5259eSPaul Walmsley OMAP2_PM_PWSTCTRL); 1484bd5259eSPaul Walmsley return 0; 1494bd5259eSPaul Walmsley } 1504bd5259eSPaul Walmsley 1517e7fff82SPaul Walmsley static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 1527e7fff82SPaul Walmsley { 1537e7fff82SPaul Walmsley u8 omap24xx_pwrst; 1547e7fff82SPaul Walmsley 1557e7fff82SPaul Walmsley switch (pwrst) { 1567e7fff82SPaul Walmsley case PWRDM_POWER_OFF: 1577e7fff82SPaul Walmsley omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF; 1587e7fff82SPaul Walmsley break; 1597e7fff82SPaul Walmsley case PWRDM_POWER_RET: 1607e7fff82SPaul Walmsley omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET; 1617e7fff82SPaul Walmsley break; 1627e7fff82SPaul Walmsley case PWRDM_POWER_ON: 1637e7fff82SPaul Walmsley omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON; 1647e7fff82SPaul Walmsley break; 1657e7fff82SPaul Walmsley default: 1667e7fff82SPaul Walmsley return -EINVAL; 1677e7fff82SPaul Walmsley } 1687e7fff82SPaul Walmsley 1697e7fff82SPaul Walmsley omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, 1707e7fff82SPaul Walmsley (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT), 1717e7fff82SPaul Walmsley pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); 1727e7fff82SPaul Walmsley return 0; 1737e7fff82SPaul Walmsley } 1747e7fff82SPaul Walmsley 1757e7fff82SPaul Walmsley static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 1767e7fff82SPaul Walmsley { 1777e7fff82SPaul Walmsley u8 omap2xxx_pwrst; 1787e7fff82SPaul Walmsley 1797e7fff82SPaul Walmsley omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 1807e7fff82SPaul Walmsley OMAP2_PM_PWSTCTRL, 1817e7fff82SPaul Walmsley OMAP_POWERSTATE_MASK); 1827e7fff82SPaul Walmsley 1837e7fff82SPaul Walmsley return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); 1847e7fff82SPaul Walmsley } 1857e7fff82SPaul Walmsley 1867e7fff82SPaul Walmsley static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 1877e7fff82SPaul Walmsley { 1887e7fff82SPaul Walmsley u8 omap2xxx_pwrst; 1897e7fff82SPaul Walmsley 1907e7fff82SPaul Walmsley omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 1917e7fff82SPaul Walmsley OMAP2_PM_PWSTST, 1927e7fff82SPaul Walmsley OMAP_POWERSTATEST_MASK); 1937e7fff82SPaul Walmsley 1947e7fff82SPaul Walmsley return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); 1957e7fff82SPaul Walmsley } 1967e7fff82SPaul Walmsley 19749815399SPaul Walmsley struct pwrdm_ops omap2_pwrdm_operations = { 1987e7fff82SPaul Walmsley .pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst, 1997e7fff82SPaul Walmsley .pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst, 2007e7fff82SPaul Walmsley .pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst, 20149815399SPaul Walmsley .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, 20249815399SPaul Walmsley .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, 20349815399SPaul Walmsley .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, 20449815399SPaul Walmsley .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, 20549815399SPaul Walmsley .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, 20649815399SPaul Walmsley .pwrdm_wait_transition = omap2_pwrdm_wait_transition, 20749815399SPaul Walmsley }; 2082bb2a5d3SPaul Walmsley 2092bb2a5d3SPaul Walmsley /* 2102bb2a5d3SPaul Walmsley * 2112bb2a5d3SPaul Walmsley */ 2122bb2a5d3SPaul Walmsley 2132bb2a5d3SPaul Walmsley static struct prm_ll_data omap2xxx_prm_ll_data = { 2142bb2a5d3SPaul Walmsley .read_reset_sources = &omap2xxx_prm_read_reset_sources, 2152bb2a5d3SPaul Walmsley }; 2162bb2a5d3SPaul Walmsley 21763a293e0SPaul Walmsley int __init omap2xxx_prm_init(void) 2182bb2a5d3SPaul Walmsley { 2192bb2a5d3SPaul Walmsley return prm_register(&omap2xxx_prm_ll_data); 2202bb2a5d3SPaul Walmsley } 2212bb2a5d3SPaul Walmsley 2222bb2a5d3SPaul Walmsley static void __exit omap2xxx_prm_exit(void) 2232bb2a5d3SPaul Walmsley { 224d8871cd2STero Kristo prm_unregister(&omap2xxx_prm_ll_data); 2252bb2a5d3SPaul Walmsley } 2262bb2a5d3SPaul Walmsley __exitcall(omap2xxx_prm_exit); 227