1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AM33XX CM functions 4 * 5 * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ 6 * Vaibhav Hiremath <hvaibhav@ti.com> 7 * 8 * Reference taken from OMAP4 cminst44xx.c 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/types.h> 13 #include <linux/errno.h> 14 #include <linux/err.h> 15 #include <linux/io.h> 16 17 #include "clockdomain.h" 18 #include "cm.h" 19 #include "cm33xx.h" 20 #include "cm-regbits-34xx.h" 21 #include "cm-regbits-33xx.h" 22 #include "prm33xx.h" 23 #if IS_ENABLED(CONFIG_SUSPEND) 24 #include <linux/suspend.h> 25 #endif 26 27 /* 28 * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield: 29 * 30 * 0x0 func: Module is fully functional, including OCP 31 * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep 32 * abortion 33 * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if 34 * using separate functional clock 35 * 0x3 disabled: Module is disabled and cannot be accessed 36 * 37 */ 38 #define CLKCTRL_IDLEST_FUNCTIONAL 0x0 39 #define CLKCTRL_IDLEST_INTRANSITION 0x1 40 #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2 41 #define CLKCTRL_IDLEST_DISABLED 0x3 42 43 /* Private functions */ 44 45 /* Read a register in a CM instance */ 46 static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx) 47 { 48 return readl_relaxed(cm_base.va + inst + idx); 49 } 50 51 /* Write into a register in a CM */ 52 static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx) 53 { 54 writel_relaxed(val, cm_base.va + inst + idx); 55 } 56 57 /* Read-modify-write a register in CM */ 58 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) 59 { 60 u32 v; 61 62 v = am33xx_cm_read_reg(inst, idx); 63 v &= ~mask; 64 v |= bits; 65 am33xx_cm_write_reg(v, inst, idx); 66 67 return v; 68 } 69 70 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) 71 { 72 u32 v; 73 74 v = am33xx_cm_read_reg(inst, idx); 75 v &= mask; 76 v >>= __ffs(mask); 77 78 return v; 79 } 80 81 /** 82 * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield 83 * @inst: CM instance register offset (*_INST macro) 84 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 85 * 86 * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to 87 * bit 0. 88 */ 89 static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs) 90 { 91 u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); 92 v &= AM33XX_IDLEST_MASK; 93 v >>= AM33XX_IDLEST_SHIFT; 94 return v; 95 } 96 97 /** 98 * _is_module_ready - can module registers be accessed without causing an abort? 99 * @inst: CM instance register offset (*_INST macro) 100 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 101 * 102 * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either 103 * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. 104 */ 105 static bool _is_module_ready(u16 inst, u16 clkctrl_offs) 106 { 107 u32 v; 108 109 v = _clkctrl_idlest(inst, clkctrl_offs); 110 111 return (v == CLKCTRL_IDLEST_FUNCTIONAL || 112 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; 113 } 114 115 /** 116 * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield 117 * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted) 118 * @inst: CM instance register offset (*_INST macro) 119 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 120 * 121 * @c must be the unshifted value for CLKTRCTRL - i.e., this function 122 * will handle the shift itself. 123 */ 124 static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs) 125 { 126 u32 v; 127 128 v = am33xx_cm_read_reg(inst, cdoffs); 129 v &= ~AM33XX_CLKTRCTRL_MASK; 130 v |= c << AM33XX_CLKTRCTRL_SHIFT; 131 am33xx_cm_write_reg(v, inst, cdoffs); 132 } 133 134 /* Public functions */ 135 136 /** 137 * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode? 138 * @inst: CM instance register offset (*_INST macro) 139 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 140 * 141 * Returns true if the clockdomain referred to by (@inst, @cdoffs) 142 * is in hardware-supervised idle mode, or 0 otherwise. 143 */ 144 static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) 145 { 146 u32 v; 147 148 v = am33xx_cm_read_reg(inst, cdoffs); 149 v &= AM33XX_CLKTRCTRL_MASK; 150 v >>= AM33XX_CLKTRCTRL_SHIFT; 151 152 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false; 153 } 154 155 /** 156 * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode 157 * @inst: CM instance register offset (*_INST macro) 158 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 159 * 160 * Put a clockdomain referred to by (@inst, @cdoffs) into 161 * hardware-supervised idle mode. No return value. 162 */ 163 static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) 164 { 165 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); 166 } 167 168 /** 169 * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode 170 * @inst: CM instance register offset (*_INST macro) 171 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 172 * 173 * Put a clockdomain referred to by (@inst, @cdoffs) into 174 * software-supervised idle mode, i.e., controlled manually by the 175 * Linux OMAP clockdomain code. No return value. 176 */ 177 static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) 178 { 179 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); 180 } 181 182 /** 183 * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle 184 * @inst: CM instance register offset (*_INST macro) 185 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 186 * 187 * Put a clockdomain referred to by (@inst, @cdoffs) into idle 188 * No return value. 189 */ 190 static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) 191 { 192 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); 193 } 194 195 /** 196 * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle 197 * @inst: CM instance register offset (*_INST macro) 198 * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 199 * 200 * Take a clockdomain referred to by (@inst, @cdoffs) out of idle, 201 * waking it up. No return value. 202 */ 203 static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) 204 { 205 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); 206 } 207 208 /* 209 * 210 */ 211 212 /** 213 * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state 214 * @part: PRCM partition, ignored for AM33xx 215 * @inst: CM instance register offset (*_INST macro) 216 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 217 * @bit_shift: bit shift for the register, ignored for AM33xx 218 * 219 * Wait for the module IDLEST to be functional. If the idle state is in any 220 * the non functional state (trans, idle or disabled), module and thus the 221 * sysconfig cannot be accessed and will probably lead to an "imprecise 222 * external abort" 223 */ 224 static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, 225 u8 bit_shift) 226 { 227 int i = 0; 228 229 omap_test_timeout(_is_module_ready(inst, clkctrl_offs), 230 MAX_MODULE_READY_TIME, i); 231 232 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 233 } 234 235 /** 236 * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' 237 * state 238 * @part: CM partition, ignored for AM33xx 239 * @inst: CM instance register offset (*_INST macro) 240 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 241 * @bit_shift: bit shift for the register, ignored for AM33xx 242 * 243 * Wait for the module IDLEST to be disabled. Some PRCM transition, 244 * like reset assertion or parent clock de-activation must wait the 245 * module to be fully disabled. 246 */ 247 static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, 248 u8 bit_shift) 249 { 250 int i = 0; 251 252 omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) == 253 CLKCTRL_IDLEST_DISABLED), 254 MAX_MODULE_READY_TIME, i); 255 256 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 257 } 258 259 /** 260 * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL 261 * @mode: Module mode (SW or HW) 262 * @part: CM partition, ignored for AM33xx 263 * @inst: CM instance register offset (*_INST macro) 264 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 265 * 266 * No return value. 267 */ 268 static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst, 269 u16 clkctrl_offs) 270 { 271 u32 v; 272 273 v = am33xx_cm_read_reg(inst, clkctrl_offs); 274 v &= ~AM33XX_MODULEMODE_MASK; 275 v |= mode << AM33XX_MODULEMODE_SHIFT; 276 am33xx_cm_write_reg(v, inst, clkctrl_offs); 277 } 278 279 /** 280 * am33xx_cm_module_disable - Disable the module inside CLKCTRL 281 * @part: CM partition, ignored for AM33xx 282 * @inst: CM instance register offset (*_INST macro) 283 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 284 * 285 * No return value. 286 */ 287 static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) 288 { 289 u32 v; 290 291 v = am33xx_cm_read_reg(inst, clkctrl_offs); 292 v &= ~AM33XX_MODULEMODE_MASK; 293 am33xx_cm_write_reg(v, inst, clkctrl_offs); 294 } 295 296 /* 297 * Clockdomain low-level functions 298 */ 299 300 static int am33xx_clkdm_sleep(struct clockdomain *clkdm) 301 { 302 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs); 303 return 0; 304 } 305 306 static int am33xx_clkdm_wakeup(struct clockdomain *clkdm) 307 { 308 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs); 309 return 0; 310 } 311 312 static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm) 313 { 314 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); 315 } 316 317 static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm) 318 { 319 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); 320 } 321 322 static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm) 323 { 324 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 325 return am33xx_clkdm_wakeup(clkdm); 326 327 return 0; 328 } 329 330 static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm) 331 { 332 bool hwsup = false; 333 334 #if IS_ENABLED(CONFIG_SUSPEND) 335 /* 336 * In case of standby, Don't put the l4ls clk domain to sleep. 337 * Since CM3 PM FW doesn't wake-up/enable the l4ls clk domain 338 * upon wake-up, CM3 PM FW fails to wake-up th MPU. 339 */ 340 if (pm_suspend_target_state == PM_SUSPEND_STANDBY && 341 (clkdm->flags & CLKDM_STANDBY_FORCE_WAKEUP)) 342 return 0; 343 #endif 344 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); 345 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) 346 am33xx_clkdm_sleep(clkdm); 347 348 return 0; 349 } 350 351 static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset) 352 { 353 return cm_base.pa + inst + offset; 354 } 355 356 /** 357 * am33xx_clkdm_save_context - Save the clockdomain transition context 358 * @clkdm: The clockdomain pointer whose context needs to be saved 359 * 360 * Save the clockdomain transition context. 361 */ 362 static int am33xx_clkdm_save_context(struct clockdomain *clkdm) 363 { 364 clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst, 365 clkdm->clkdm_offs, 366 AM33XX_CLKTRCTRL_MASK); 367 368 return 0; 369 } 370 371 /** 372 * am33xx_clkdm_restore_context - Restore the clockdomain transition context 373 * @clkdm: The clockdomain pointer whose context needs to be restored 374 * 375 * Restore the clockdomain transition context. 376 */ 377 static int am33xx_clkdm_restore_context(struct clockdomain *clkdm) 378 { 379 switch (clkdm->context) { 380 case OMAP34XX_CLKSTCTRL_DISABLE_AUTO: 381 am33xx_clkdm_deny_idle(clkdm); 382 break; 383 case OMAP34XX_CLKSTCTRL_FORCE_SLEEP: 384 am33xx_clkdm_sleep(clkdm); 385 break; 386 case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP: 387 am33xx_clkdm_wakeup(clkdm); 388 break; 389 case OMAP34XX_CLKSTCTRL_ENABLE_AUTO: 390 am33xx_clkdm_allow_idle(clkdm); 391 break; 392 } 393 return 0; 394 } 395 396 struct clkdm_ops am33xx_clkdm_operations = { 397 .clkdm_sleep = am33xx_clkdm_sleep, 398 .clkdm_wakeup = am33xx_clkdm_wakeup, 399 .clkdm_allow_idle = am33xx_clkdm_allow_idle, 400 .clkdm_deny_idle = am33xx_clkdm_deny_idle, 401 .clkdm_clk_enable = am33xx_clkdm_clk_enable, 402 .clkdm_clk_disable = am33xx_clkdm_clk_disable, 403 .clkdm_save_context = am33xx_clkdm_save_context, 404 .clkdm_restore_context = am33xx_clkdm_restore_context, 405 }; 406 407 static const struct cm_ll_data am33xx_cm_ll_data = { 408 .wait_module_ready = &am33xx_cm_wait_module_ready, 409 .wait_module_idle = &am33xx_cm_wait_module_idle, 410 .module_enable = &am33xx_cm_module_enable, 411 .module_disable = &am33xx_cm_module_disable, 412 .xlate_clkctrl = &am33xx_cm_xlate_clkctrl, 413 }; 414 415 int __init am33xx_cm_init(const struct omap_prcm_init_data *data) 416 { 417 return cm_register(&am33xx_cm_ll_data); 418 } 419 420 static void __exit am33xx_cm_exit(void) 421 { 422 cm_unregister(&am33xx_cm_ll_data); 423 } 424 __exitcall(am33xx_cm_exit); 425