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 "clockdomain.h" 26 #include "cm.h" 27 #include "cm33xx.h" 28 #include "cm-regbits-34xx.h" 29 #include "cm-regbits-33xx.h" 30 #include "prm33xx.h" 31 32 /* 33 * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield: 34 * 35 * 0x0 func: Module is fully functional, including OCP 36 * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep 37 * abortion 38 * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if 39 * using separate functional clock 40 * 0x3 disabled: Module is disabled and cannot be accessed 41 * 42 */ 43 #define CLKCTRL_IDLEST_FUNCTIONAL 0x0 44 #define CLKCTRL_IDLEST_INTRANSITION 0x1 45 #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2 46 #define CLKCTRL_IDLEST_DISABLED 0x3 47 48 /* Private functions */ 49 50 /* Read a register in a CM instance */ 51 static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx) 52 { 53 return readl_relaxed(cm_base + inst + idx); 54 } 55 56 /* Write into a register in a CM */ 57 static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx) 58 { 59 writel_relaxed(val, cm_base + inst + idx); 60 } 61 62 /* Read-modify-write a register in CM */ 63 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) 64 { 65 u32 v; 66 67 v = am33xx_cm_read_reg(inst, idx); 68 v &= ~mask; 69 v |= bits; 70 am33xx_cm_write_reg(v, inst, idx); 71 72 return v; 73 } 74 75 static inline u32 am33xx_cm_set_reg_bits(u32 bits, s16 inst, s16 idx) 76 { 77 return am33xx_cm_rmw_reg_bits(bits, bits, inst, idx); 78 } 79 80 static inline u32 am33xx_cm_clear_reg_bits(u32 bits, s16 inst, s16 idx) 81 { 82 return am33xx_cm_rmw_reg_bits(bits, 0x0, inst, idx); 83 } 84 85 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) 86 { 87 u32 v; 88 89 v = am33xx_cm_read_reg(inst, idx); 90 v &= mask; 91 v >>= __ffs(mask); 92 93 return v; 94 } 95 96 /** 97 * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield 98 * @inst: CM instance register offset (*_INST macro) 99 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 100 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 101 * 102 * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to 103 * bit 0. 104 */ 105 static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) 106 { 107 u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); 108 v &= AM33XX_IDLEST_MASK; 109 v >>= AM33XX_IDLEST_SHIFT; 110 return v; 111 } 112 113 /** 114 * _is_module_ready - can module registers be accessed without causing an abort? 115 * @inst: CM instance register offset (*_INST macro) 116 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 117 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 118 * 119 * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either 120 * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. 121 */ 122 static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) 123 { 124 u32 v; 125 126 v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs); 127 128 return (v == CLKCTRL_IDLEST_FUNCTIONAL || 129 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; 130 } 131 132 /** 133 * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield 134 * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted) 135 * @inst: CM instance register offset (*_INST macro) 136 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 137 * 138 * @c must be the unshifted value for CLKTRCTRL - i.e., this function 139 * will handle the shift itself. 140 */ 141 static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs) 142 { 143 u32 v; 144 145 v = am33xx_cm_read_reg(inst, cdoffs); 146 v &= ~AM33XX_CLKTRCTRL_MASK; 147 v |= c << AM33XX_CLKTRCTRL_SHIFT; 148 am33xx_cm_write_reg(v, inst, cdoffs); 149 } 150 151 /* Public functions */ 152 153 /** 154 * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode? 155 * @inst: CM instance register offset (*_INST macro) 156 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 157 * 158 * Returns true if the clockdomain referred to by (@inst, @cdoffs) 159 * is in hardware-supervised idle mode, or 0 otherwise. 160 */ 161 bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) 162 { 163 u32 v; 164 165 v = am33xx_cm_read_reg(inst, cdoffs); 166 v &= AM33XX_CLKTRCTRL_MASK; 167 v >>= AM33XX_CLKTRCTRL_SHIFT; 168 169 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false; 170 } 171 172 /** 173 * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode 174 * @inst: CM instance register offset (*_INST macro) 175 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 176 * 177 * Put a clockdomain referred to by (@inst, @cdoffs) into 178 * hardware-supervised idle mode. No return value. 179 */ 180 void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) 181 { 182 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); 183 } 184 185 /** 186 * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode 187 * @inst: CM instance register offset (*_INST macro) 188 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 189 * 190 * Put a clockdomain referred to by (@inst, @cdoffs) into 191 * software-supervised idle mode, i.e., controlled manually by the 192 * Linux OMAP clockdomain code. No return value. 193 */ 194 void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) 195 { 196 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); 197 } 198 199 /** 200 * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle 201 * @inst: CM instance register offset (*_INST macro) 202 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 203 * 204 * Put a clockdomain referred to by (@inst, @cdoffs) into idle 205 * No return value. 206 */ 207 void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) 208 { 209 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); 210 } 211 212 /** 213 * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle 214 * @inst: CM instance register offset (*_INST macro) 215 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 216 * 217 * Take a clockdomain referred to by (@inst, @cdoffs) out of idle, 218 * waking it up. No return value. 219 */ 220 void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) 221 { 222 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); 223 } 224 225 /* 226 * 227 */ 228 229 /** 230 * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state 231 * @inst: CM instance register offset (*_INST macro) 232 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 233 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 234 * 235 * Wait for the module IDLEST to be functional. If the idle state is in any 236 * the non functional state (trans, idle or disabled), module and thus the 237 * sysconfig cannot be accessed and will probably lead to an "imprecise 238 * external abort" 239 */ 240 int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) 241 { 242 int i = 0; 243 244 omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs), 245 MAX_MODULE_READY_TIME, i); 246 247 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 248 } 249 250 /** 251 * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' 252 * state 253 * @inst: CM instance register offset (*_INST macro) 254 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 255 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 256 * 257 * Wait for the module IDLEST to be disabled. Some PRCM transition, 258 * like reset assertion or parent clock de-activation must wait the 259 * module to be fully disabled. 260 */ 261 int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) 262 { 263 int i = 0; 264 265 if (!clkctrl_offs) 266 return 0; 267 268 omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) == 269 CLKCTRL_IDLEST_DISABLED), 270 MAX_MODULE_READY_TIME, i); 271 272 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 273 } 274 275 /** 276 * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL 277 * @mode: Module mode (SW or HW) 278 * @inst: CM instance register offset (*_INST macro) 279 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 280 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 281 * 282 * No return value. 283 */ 284 void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) 285 { 286 u32 v; 287 288 v = am33xx_cm_read_reg(inst, clkctrl_offs); 289 v &= ~AM33XX_MODULEMODE_MASK; 290 v |= mode << AM33XX_MODULEMODE_SHIFT; 291 am33xx_cm_write_reg(v, inst, clkctrl_offs); 292 } 293 294 /** 295 * am33xx_cm_module_disable - Disable the module inside CLKCTRL 296 * @inst: CM instance register offset (*_INST macro) 297 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 298 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 299 * 300 * No return value. 301 */ 302 void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) 303 { 304 u32 v; 305 306 v = am33xx_cm_read_reg(inst, clkctrl_offs); 307 v &= ~AM33XX_MODULEMODE_MASK; 308 am33xx_cm_write_reg(v, inst, clkctrl_offs); 309 } 310 311 /* 312 * Clockdomain low-level functions 313 */ 314 315 static int am33xx_clkdm_sleep(struct clockdomain *clkdm) 316 { 317 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs); 318 return 0; 319 } 320 321 static int am33xx_clkdm_wakeup(struct clockdomain *clkdm) 322 { 323 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs); 324 return 0; 325 } 326 327 static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm) 328 { 329 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); 330 } 331 332 static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm) 333 { 334 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); 335 } 336 337 static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm) 338 { 339 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 340 return am33xx_clkdm_wakeup(clkdm); 341 342 return 0; 343 } 344 345 static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm) 346 { 347 bool hwsup = false; 348 349 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); 350 351 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) 352 am33xx_clkdm_sleep(clkdm); 353 354 return 0; 355 } 356 357 struct clkdm_ops am33xx_clkdm_operations = { 358 .clkdm_sleep = am33xx_clkdm_sleep, 359 .clkdm_wakeup = am33xx_clkdm_wakeup, 360 .clkdm_allow_idle = am33xx_clkdm_allow_idle, 361 .clkdm_deny_idle = am33xx_clkdm_deny_idle, 362 .clkdm_clk_enable = am33xx_clkdm_clk_enable, 363 .clkdm_clk_disable = am33xx_clkdm_clk_disable, 364 }; 365