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