1 /* 2 * AM33XX CM functions 3 * 4 * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ 5 * Vaibhav Hiremath <hvaibhav@ti.com> 6 * 7 * Reference taken from from OMAP4 cminst44xx.c 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation version 2. 12 * 13 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 14 * kind, whether express or implied; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/types.h> 21 #include <linux/errno.h> 22 #include <linux/err.h> 23 #include <linux/io.h> 24 25 #include <plat/common.h> 26 27 #include "cm.h" 28 #include "cm33xx.h" 29 #include "cm-regbits-34xx.h" 30 #include "cm-regbits-33xx.h" 31 #include "prm33xx.h" 32 33 /* 34 * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield: 35 * 36 * 0x0 func: Module is fully functional, including OCP 37 * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep 38 * abortion 39 * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if 40 * using separate functional clock 41 * 0x3 disabled: Module is disabled and cannot be accessed 42 * 43 */ 44 #define CLKCTRL_IDLEST_FUNCTIONAL 0x0 45 #define CLKCTRL_IDLEST_INTRANSITION 0x1 46 #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2 47 #define CLKCTRL_IDLEST_DISABLED 0x3 48 49 /* Private functions */ 50 51 /* Read a register in a CM instance */ 52 static inline u32 am33xx_cm_read_reg(s16 inst, u16 idx) 53 { 54 return __raw_readl(cm_base + inst + idx); 55 } 56 57 /* Write into a register in a CM */ 58 static inline void am33xx_cm_write_reg(u32 val, s16 inst, u16 idx) 59 { 60 __raw_writel(val, cm_base + inst + idx); 61 } 62 63 /* Read-modify-write a register in CM */ 64 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) 65 { 66 u32 v; 67 68 v = am33xx_cm_read_reg(inst, idx); 69 v &= ~mask; 70 v |= bits; 71 am33xx_cm_write_reg(v, inst, idx); 72 73 return v; 74 } 75 76 static inline u32 am33xx_cm_set_reg_bits(u32 bits, s16 inst, s16 idx) 77 { 78 return am33xx_cm_rmw_reg_bits(bits, bits, inst, idx); 79 } 80 81 static inline u32 am33xx_cm_clear_reg_bits(u32 bits, s16 inst, s16 idx) 82 { 83 return am33xx_cm_rmw_reg_bits(bits, 0x0, inst, idx); 84 } 85 86 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) 87 { 88 u32 v; 89 90 v = am33xx_cm_read_reg(inst, idx); 91 v &= mask; 92 v >>= __ffs(mask); 93 94 return v; 95 } 96 97 /** 98 * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield 99 * @inst: CM instance register offset (*_INST macro) 100 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 101 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 102 * 103 * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to 104 * bit 0. 105 */ 106 static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) 107 { 108 u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); 109 v &= AM33XX_IDLEST_MASK; 110 v >>= AM33XX_IDLEST_SHIFT; 111 return v; 112 } 113 114 /** 115 * _is_module_ready - can module registers be accessed without causing an abort? 116 * @inst: CM instance register offset (*_INST macro) 117 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 118 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 119 * 120 * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either 121 * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. 122 */ 123 static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) 124 { 125 u32 v; 126 127 v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs); 128 129 return (v == CLKCTRL_IDLEST_FUNCTIONAL || 130 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; 131 } 132 133 /** 134 * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield 135 * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted) 136 * @inst: CM instance register offset (*_INST macro) 137 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 138 * 139 * @c must be the unshifted value for CLKTRCTRL - i.e., this function 140 * will handle the shift itself. 141 */ 142 static void _clktrctrl_write(u8 c, s16 inst, u16 cdoffs) 143 { 144 u32 v; 145 146 v = am33xx_cm_read_reg(inst, cdoffs); 147 v &= ~AM33XX_CLKTRCTRL_MASK; 148 v |= c << AM33XX_CLKTRCTRL_SHIFT; 149 am33xx_cm_write_reg(v, inst, cdoffs); 150 } 151 152 /* Public functions */ 153 154 /** 155 * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode? 156 * @inst: CM instance register offset (*_INST macro) 157 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 158 * 159 * Returns true if the clockdomain referred to by (@inst, @cdoffs) 160 * is in hardware-supervised idle mode, or 0 otherwise. 161 */ 162 bool am33xx_cm_is_clkdm_in_hwsup(s16 inst, u16 cdoffs) 163 { 164 u32 v; 165 166 v = am33xx_cm_read_reg(inst, cdoffs); 167 v &= AM33XX_CLKTRCTRL_MASK; 168 v >>= AM33XX_CLKTRCTRL_SHIFT; 169 170 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false; 171 } 172 173 /** 174 * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode 175 * @inst: CM instance register offset (*_INST macro) 176 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 177 * 178 * Put a clockdomain referred to by (@inst, @cdoffs) into 179 * hardware-supervised idle mode. No return value. 180 */ 181 void am33xx_cm_clkdm_enable_hwsup(s16 inst, u16 cdoffs) 182 { 183 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); 184 } 185 186 /** 187 * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode 188 * @inst: CM instance register offset (*_INST macro) 189 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 190 * 191 * Put a clockdomain referred to by (@inst, @cdoffs) into 192 * software-supervised idle mode, i.e., controlled manually by the 193 * Linux OMAP clockdomain code. No return value. 194 */ 195 void am33xx_cm_clkdm_disable_hwsup(s16 inst, u16 cdoffs) 196 { 197 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); 198 } 199 200 /** 201 * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle 202 * @inst: CM instance register offset (*_INST macro) 203 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 204 * 205 * Put a clockdomain referred to by (@inst, @cdoffs) into idle 206 * No return value. 207 */ 208 void am33xx_cm_clkdm_force_sleep(s16 inst, u16 cdoffs) 209 { 210 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); 211 } 212 213 /** 214 * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle 215 * @inst: CM instance register offset (*_INST macro) 216 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 217 * 218 * Take a clockdomain referred to by (@inst, @cdoffs) out of idle, 219 * waking it up. No return value. 220 */ 221 void am33xx_cm_clkdm_force_wakeup(s16 inst, u16 cdoffs) 222 { 223 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); 224 } 225 226 /* 227 * 228 */ 229 230 /** 231 * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state 232 * @inst: CM instance register offset (*_INST macro) 233 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 234 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 235 * 236 * Wait for the module IDLEST to be functional. If the idle state is in any 237 * the non functional state (trans, idle or disabled), module and thus the 238 * sysconfig cannot be accessed and will probably lead to an "imprecise 239 * external abort" 240 */ 241 int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) 242 { 243 int i = 0; 244 245 if (!clkctrl_offs) 246 return 0; 247 248 omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs), 249 MAX_MODULE_READY_TIME, i); 250 251 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 252 } 253 254 /** 255 * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' 256 * state 257 * @inst: CM instance register offset (*_INST macro) 258 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 259 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 260 * 261 * Wait for the module IDLEST to be disabled. Some PRCM transition, 262 * like reset assertion or parent clock de-activation must wait the 263 * module to be fully disabled. 264 */ 265 int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) 266 { 267 int i = 0; 268 269 if (!clkctrl_offs) 270 return 0; 271 272 omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) == 273 CLKCTRL_IDLEST_DISABLED), 274 MAX_MODULE_READY_TIME, i); 275 276 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 277 } 278 279 /** 280 * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL 281 * @mode: Module mode (SW or HW) 282 * @inst: CM instance register offset (*_INST macro) 283 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 284 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 285 * 286 * No return value. 287 */ 288 void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) 289 { 290 u32 v; 291 292 v = am33xx_cm_read_reg(inst, clkctrl_offs); 293 v &= ~AM33XX_MODULEMODE_MASK; 294 v |= mode << AM33XX_MODULEMODE_SHIFT; 295 am33xx_cm_write_reg(v, inst, clkctrl_offs); 296 } 297 298 /** 299 * am33xx_cm_module_disable - Disable the module inside CLKCTRL 300 * @inst: CM instance register offset (*_INST macro) 301 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 302 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 303 * 304 * No return value. 305 */ 306 void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) 307 { 308 u32 v; 309 310 v = am33xx_cm_read_reg(inst, clkctrl_offs); 311 v &= ~AM33XX_MODULEMODE_MASK; 312 am33xx_cm_write_reg(v, inst, clkctrl_offs); 313 } 314