1 /* 2 * OMAP2xxx PRM module functions 3 * 4 * Copyright (C) 2010-2012 Texas Instruments, Inc. 5 * Copyright (C) 2010 Nokia Corporation 6 * Benoît Cousson 7 * Paul Walmsley 8 * Rajendra Nayak <rnayak@ti.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <linux/kernel.h> 16 #include <linux/errno.h> 17 #include <linux/err.h> 18 #include <linux/io.h> 19 #include <linux/irq.h> 20 21 #include "powerdomain.h" 22 #include "clockdomain.h" 23 #include "prm2xxx.h" 24 #include "cm2xxx_3xxx.h" 25 #include "prm-regbits-24xx.h" 26 27 /* 28 * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits - 29 * these are reversed from the bits used on OMAP3+ 30 */ 31 #define OMAP24XX_PWRDM_POWER_ON 0x0 32 #define OMAP24XX_PWRDM_POWER_RET 0x1 33 #define OMAP24XX_PWRDM_POWER_OFF 0x3 34 35 /* 36 * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP 37 * hardware register (which are specific to the OMAP2xxx SoCs) to 38 * reset source ID bit shifts (which is an OMAP SoC-independent 39 * enumeration) 40 */ 41 static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = { 42 { OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, 43 { OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, 44 { OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, 45 { OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, 46 { OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT }, 47 { OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, 48 { -1, -1 }, 49 }; 50 51 /** 52 * omap2xxx_prm_read_reset_sources - return the last SoC reset source 53 * 54 * Return a u32 representing the last reset sources of the SoC. The 55 * returned reset source bits are standardized across OMAP SoCs. 56 */ 57 static u32 omap2xxx_prm_read_reset_sources(void) 58 { 59 struct prm_reset_src_map *p; 60 u32 r = 0; 61 u32 v; 62 63 v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); 64 65 p = omap2xxx_prm_reset_src_map; 66 while (p->reg_shift >= 0 && p->std_shift >= 0) { 67 if (v & (1 << p->reg_shift)) 68 r |= 1 << p->std_shift; 69 p++; 70 } 71 72 return r; 73 } 74 75 /** 76 * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst 77 * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert 78 * 79 * Return the common power state bits corresponding to the OMAP2xxx 80 * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error. 81 */ 82 static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) 83 { 84 u8 pwrst; 85 86 switch (omap2xxx_pwrst) { 87 case OMAP24XX_PWRDM_POWER_OFF: 88 pwrst = PWRDM_POWER_OFF; 89 break; 90 case OMAP24XX_PWRDM_POWER_RET: 91 pwrst = PWRDM_POWER_RET; 92 break; 93 case OMAP24XX_PWRDM_POWER_ON: 94 pwrst = PWRDM_POWER_ON; 95 break; 96 default: 97 return -EINVAL; 98 } 99 100 return pwrst; 101 } 102 103 /** 104 * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC 105 * 106 * Set the DPLL reset bit, which should reboot the SoC. This is the 107 * recommended way to restart the SoC. No return value. 108 */ 109 static void omap2xxx_prm_dpll_reset(void) 110 { 111 omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, 112 OMAP2_RM_RSTCTRL); 113 /* OCP barrier */ 114 omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL); 115 } 116 117 /** 118 * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module 119 * @module: PRM module to clear wakeups from 120 * @regs: register offset to clear 121 * @wkst_mask: wakeup status mask to clear 122 * 123 * Clears wakeup status bits for a given module, so that the device can 124 * re-enter idle. 125 */ 126 void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) 127 { 128 u32 wkst; 129 130 wkst = omap2_prm_read_mod_reg(module, regs); 131 wkst &= wkst_mask; 132 omap2_prm_write_mod_reg(wkst, module, regs); 133 } 134 135 int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) 136 { 137 omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 138 clkdm->pwrdm.ptr->prcm_offs, 139 OMAP2_PM_PWSTCTRL); 140 return 0; 141 } 142 143 int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm) 144 { 145 omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 146 clkdm->pwrdm.ptr->prcm_offs, 147 OMAP2_PM_PWSTCTRL); 148 return 0; 149 } 150 151 static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 152 { 153 u8 omap24xx_pwrst; 154 155 switch (pwrst) { 156 case PWRDM_POWER_OFF: 157 omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF; 158 break; 159 case PWRDM_POWER_RET: 160 omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET; 161 break; 162 case PWRDM_POWER_ON: 163 omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON; 164 break; 165 default: 166 return -EINVAL; 167 } 168 169 omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, 170 (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT), 171 pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); 172 return 0; 173 } 174 175 static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 176 { 177 u8 omap2xxx_pwrst; 178 179 omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 180 OMAP2_PM_PWSTCTRL, 181 OMAP_POWERSTATE_MASK); 182 183 return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); 184 } 185 186 static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 187 { 188 u8 omap2xxx_pwrst; 189 190 omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 191 OMAP2_PM_PWSTST, 192 OMAP_POWERSTATEST_MASK); 193 194 return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); 195 } 196 197 struct pwrdm_ops omap2_pwrdm_operations = { 198 .pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst, 199 .pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst, 200 .pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst, 201 .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, 202 .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, 203 .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, 204 .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, 205 .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, 206 .pwrdm_wait_transition = omap2_pwrdm_wait_transition, 207 }; 208 209 /* 210 * 211 */ 212 213 static struct prm_ll_data omap2xxx_prm_ll_data = { 214 .read_reset_sources = &omap2xxx_prm_read_reset_sources, 215 .assert_hardreset = &omap2_prm_assert_hardreset, 216 .deassert_hardreset = &omap2_prm_deassert_hardreset, 217 .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, 218 .reset_system = &omap2xxx_prm_dpll_reset, 219 }; 220 221 int __init omap2xxx_prm_init(void) 222 { 223 return prm_register(&omap2xxx_prm_ll_data); 224 } 225 226 static void __exit omap2xxx_prm_exit(void) 227 { 228 prm_unregister(&omap2xxx_prm_ll_data); 229 } 230 __exitcall(omap2xxx_prm_exit); 231