1 /* 2 * OMAP2/3 clockdomain framework functions 3 * 4 * Copyright (C) 2008 Texas Instruments, Inc. 5 * Copyright (C) 2008 Nokia Corporation 6 * 7 * Written by Paul Walmsley and Jouni Högander 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 #ifdef CONFIG_OMAP_DEBUG_CLOCKDOMAIN 14 # define DEBUG 15 #endif 16 17 #include <linux/module.h> 18 #include <linux/kernel.h> 19 #include <linux/device.h> 20 #include <linux/list.h> 21 #include <linux/errno.h> 22 #include <linux/delay.h> 23 #include <linux/clk.h> 24 #include <linux/limits.h> 25 26 #include <linux/io.h> 27 28 #include <linux/bitops.h> 29 30 #include <mach/clock.h> 31 32 #include "prm.h" 33 #include "prm-regbits-24xx.h" 34 #include "cm.h" 35 36 #include <mach/powerdomain.h> 37 #include <mach/clockdomain.h> 38 39 /* clkdm_list contains all registered struct clockdomains */ 40 static LIST_HEAD(clkdm_list); 41 42 /* clkdm_mutex protects clkdm_list add and del ops */ 43 static DEFINE_MUTEX(clkdm_mutex); 44 45 /* array of powerdomain deps to be added/removed when clkdm in hwsup mode */ 46 static struct clkdm_pwrdm_autodep *autodeps; 47 48 49 /* Private functions */ 50 51 /* 52 * _autodep_lookup - resolve autodep pwrdm names to pwrdm pointers; store 53 * @autodep: struct clkdm_pwrdm_autodep * to resolve 54 * 55 * Resolve autodep powerdomain names to powerdomain pointers via 56 * pwrdm_lookup() and store the pointers in the autodep structure. An 57 * "autodep" is a powerdomain sleep/wakeup dependency that is 58 * automatically added and removed whenever clocks in the associated 59 * clockdomain are enabled or disabled (respectively) when the 60 * clockdomain is in hardware-supervised mode. Meant to be called 61 * once at clockdomain layer initialization, since these should remain 62 * fixed for a particular architecture. No return value. 63 */ 64 static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep) 65 { 66 struct powerdomain *pwrdm; 67 68 if (!autodep) 69 return; 70 71 if (!omap_chip_is(autodep->omap_chip)) 72 return; 73 74 pwrdm = pwrdm_lookup(autodep->pwrdm_name); 75 if (!pwrdm) { 76 pr_debug("clockdomain: _autodep_lookup: powerdomain %s " 77 "does not exist\n", autodep->pwrdm_name); 78 WARN_ON(1); 79 return; 80 } 81 autodep->pwrdm = pwrdm; 82 83 return; 84 } 85 86 /* 87 * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable 88 * @clkdm: struct clockdomain * 89 * 90 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' 91 * in hardware-supervised mode. Meant to be called from clock framework 92 * when a clock inside clockdomain 'clkdm' is enabled. No return value. 93 */ 94 static void _clkdm_add_autodeps(struct clockdomain *clkdm) 95 { 96 struct clkdm_pwrdm_autodep *autodep; 97 98 for (autodep = autodeps; autodep->pwrdm_name; autodep++) { 99 if (!autodep->pwrdm) 100 continue; 101 102 pr_debug("clockdomain: adding %s sleepdep/wkdep for " 103 "pwrdm %s\n", autodep->pwrdm_name, 104 clkdm->pwrdm->name); 105 106 pwrdm_add_sleepdep(clkdm->pwrdm, autodep->pwrdm); 107 pwrdm_add_wkdep(clkdm->pwrdm, autodep->pwrdm); 108 } 109 } 110 111 /* 112 * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm 113 * @clkdm: struct clockdomain * 114 * 115 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' 116 * in hardware-supervised mode. Meant to be called from clock framework 117 * when a clock inside clockdomain 'clkdm' is disabled. No return value. 118 */ 119 static void _clkdm_del_autodeps(struct clockdomain *clkdm) 120 { 121 struct clkdm_pwrdm_autodep *autodep; 122 123 for (autodep = autodeps; autodep->pwrdm_name; autodep++) { 124 if (!autodep->pwrdm) 125 continue; 126 127 pr_debug("clockdomain: removing %s sleepdep/wkdep for " 128 "pwrdm %s\n", autodep->pwrdm_name, 129 clkdm->pwrdm->name); 130 131 pwrdm_del_sleepdep(clkdm->pwrdm, autodep->pwrdm); 132 pwrdm_del_wkdep(clkdm->pwrdm, autodep->pwrdm); 133 } 134 } 135 136 137 static struct clockdomain *_clkdm_lookup(const char *name) 138 { 139 struct clockdomain *clkdm, *temp_clkdm; 140 141 if (!name) 142 return NULL; 143 144 clkdm = NULL; 145 146 list_for_each_entry(temp_clkdm, &clkdm_list, node) { 147 if (!strcmp(name, temp_clkdm->name)) { 148 clkdm = temp_clkdm; 149 break; 150 } 151 } 152 153 return clkdm; 154 } 155 156 157 /* Public functions */ 158 159 /** 160 * clkdm_init - set up the clockdomain layer 161 * @clkdms: optional pointer to an array of clockdomains to register 162 * @init_autodeps: optional pointer to an array of autodeps to register 163 * 164 * Set up internal state. If a pointer to an array of clockdomains 165 * was supplied, loop through the list of clockdomains, register all 166 * that are available on the current platform. Similarly, if a 167 * pointer to an array of clockdomain-powerdomain autodependencies was 168 * provided, register those. No return value. 169 */ 170 void clkdm_init(struct clockdomain **clkdms, 171 struct clkdm_pwrdm_autodep *init_autodeps) 172 { 173 struct clockdomain **c = NULL; 174 struct clkdm_pwrdm_autodep *autodep = NULL; 175 176 if (clkdms) 177 for (c = clkdms; *c; c++) 178 clkdm_register(*c); 179 180 autodeps = init_autodeps; 181 if (autodeps) 182 for (autodep = autodeps; autodep->pwrdm_name; autodep++) 183 _autodep_lookup(autodep); 184 } 185 186 /** 187 * clkdm_register - register a clockdomain 188 * @clkdm: struct clockdomain * to register 189 * 190 * Adds a clockdomain to the internal clockdomain list. 191 * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is 192 * already registered by the provided name, or 0 upon success. 193 */ 194 int clkdm_register(struct clockdomain *clkdm) 195 { 196 int ret = -EINVAL; 197 struct powerdomain *pwrdm; 198 199 if (!clkdm || !clkdm->name) 200 return -EINVAL; 201 202 if (!omap_chip_is(clkdm->omap_chip)) 203 return -EINVAL; 204 205 pwrdm = pwrdm_lookup(clkdm->pwrdm_name); 206 if (!pwrdm) { 207 pr_debug("clockdomain: clkdm_register %s: powerdomain %s " 208 "does not exist\n", clkdm->name, clkdm->pwrdm_name); 209 return -EINVAL; 210 } 211 clkdm->pwrdm = pwrdm; 212 213 mutex_lock(&clkdm_mutex); 214 /* Verify that the clockdomain is not already registered */ 215 if (_clkdm_lookup(clkdm->name)) { 216 ret = -EEXIST; 217 goto cr_unlock; 218 }; 219 220 list_add(&clkdm->node, &clkdm_list); 221 222 pwrdm_add_clkdm(pwrdm, clkdm); 223 224 pr_debug("clockdomain: registered %s\n", clkdm->name); 225 ret = 0; 226 227 cr_unlock: 228 mutex_unlock(&clkdm_mutex); 229 230 return ret; 231 } 232 233 /** 234 * clkdm_unregister - unregister a clockdomain 235 * @clkdm: struct clockdomain * to unregister 236 * 237 * Removes a clockdomain from the internal clockdomain list. Returns 238 * -EINVAL if clkdm argument is NULL. 239 */ 240 int clkdm_unregister(struct clockdomain *clkdm) 241 { 242 if (!clkdm) 243 return -EINVAL; 244 245 pwrdm_del_clkdm(clkdm->pwrdm, clkdm); 246 247 mutex_lock(&clkdm_mutex); 248 list_del(&clkdm->node); 249 mutex_unlock(&clkdm_mutex); 250 251 pr_debug("clockdomain: unregistered %s\n", clkdm->name); 252 253 return 0; 254 } 255 256 /** 257 * clkdm_lookup - look up a clockdomain by name, return a pointer 258 * @name: name of clockdomain 259 * 260 * Find a registered clockdomain by its name. Returns a pointer to the 261 * struct clockdomain if found, or NULL otherwise. 262 */ 263 struct clockdomain *clkdm_lookup(const char *name) 264 { 265 struct clockdomain *clkdm, *temp_clkdm; 266 267 if (!name) 268 return NULL; 269 270 clkdm = NULL; 271 272 mutex_lock(&clkdm_mutex); 273 list_for_each_entry(temp_clkdm, &clkdm_list, node) { 274 if (!strcmp(name, temp_clkdm->name)) { 275 clkdm = temp_clkdm; 276 break; 277 } 278 } 279 mutex_unlock(&clkdm_mutex); 280 281 return clkdm; 282 } 283 284 /** 285 * clkdm_for_each - call function on each registered clockdomain 286 * @fn: callback function * 287 * 288 * Call the supplied function for each registered clockdomain. 289 * The callback function can return anything but 0 to bail 290 * out early from the iterator. The callback function is called with 291 * the clkdm_mutex held, so no clockdomain structure manipulation 292 * functions should be called from the callback, although hardware 293 * clockdomain control functions are fine. Returns the last return 294 * value of the callback function, which should be 0 for success or 295 * anything else to indicate failure; or -EINVAL if the function pointer 296 * is null. 297 */ 298 int clkdm_for_each(int (*fn)(struct clockdomain *clkdm)) 299 { 300 struct clockdomain *clkdm; 301 int ret = 0; 302 303 if (!fn) 304 return -EINVAL; 305 306 mutex_lock(&clkdm_mutex); 307 list_for_each_entry(clkdm, &clkdm_list, node) { 308 ret = (*fn)(clkdm); 309 if (ret) 310 break; 311 } 312 mutex_unlock(&clkdm_mutex); 313 314 return ret; 315 } 316 317 318 /** 319 * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in 320 * @clkdm: struct clockdomain * 321 * 322 * Return a pointer to the struct powerdomain that the specified clockdomain 323 * 'clkdm' exists in, or returns NULL if clkdm argument is NULL. 324 */ 325 struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) 326 { 327 if (!clkdm) 328 return NULL; 329 330 return clkdm->pwrdm; 331 } 332 333 334 /* Hardware clockdomain control */ 335 336 /** 337 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode 338 * @clk: struct clk * of a clockdomain 339 * 340 * Return the clockdomain's current state transition mode from the 341 * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if clk 342 * is NULL or the current mode upon success. 343 */ 344 static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) 345 { 346 u32 v; 347 348 if (!clkdm) 349 return -EINVAL; 350 351 v = cm_read_mod_reg(clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL); 352 v &= clkdm->clktrctrl_mask; 353 v >>= __ffs(clkdm->clktrctrl_mask); 354 355 return v; 356 } 357 358 /** 359 * omap2_clkdm_sleep - force clockdomain sleep transition 360 * @clkdm: struct clockdomain * 361 * 362 * Instruct the CM to force a sleep transition on the specified 363 * clockdomain 'clkdm'. Returns -EINVAL if clk is NULL or if 364 * clockdomain does not support software-initiated sleep; 0 upon 365 * success. 366 */ 367 int omap2_clkdm_sleep(struct clockdomain *clkdm) 368 { 369 if (!clkdm) 370 return -EINVAL; 371 372 if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { 373 pr_debug("clockdomain: %s does not support forcing " 374 "sleep via software\n", clkdm->name); 375 return -EINVAL; 376 } 377 378 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 379 380 if (cpu_is_omap24xx()) { 381 382 cm_set_mod_reg_bits(OMAP24XX_FORCESTATE, 383 clkdm->pwrdm->prcm_offs, PM_PWSTCTRL); 384 385 } else if (cpu_is_omap34xx()) { 386 387 u32 v = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << 388 __ffs(clkdm->clktrctrl_mask)); 389 390 cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v, 391 clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL); 392 393 } else { 394 BUG(); 395 }; 396 397 return 0; 398 } 399 400 /** 401 * omap2_clkdm_wakeup - force clockdomain wakeup transition 402 * @clkdm: struct clockdomain * 403 * 404 * Instruct the CM to force a wakeup transition on the specified 405 * clockdomain 'clkdm'. Returns -EINVAL if clkdm is NULL or if the 406 * clockdomain does not support software-controlled wakeup; 0 upon 407 * success. 408 */ 409 int omap2_clkdm_wakeup(struct clockdomain *clkdm) 410 { 411 if (!clkdm) 412 return -EINVAL; 413 414 if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { 415 pr_debug("clockdomain: %s does not support forcing " 416 "wakeup via software\n", clkdm->name); 417 return -EINVAL; 418 } 419 420 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 421 422 if (cpu_is_omap24xx()) { 423 424 cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE, 425 clkdm->pwrdm->prcm_offs, PM_PWSTCTRL); 426 427 } else if (cpu_is_omap34xx()) { 428 429 u32 v = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << 430 __ffs(clkdm->clktrctrl_mask)); 431 432 cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v, 433 clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL); 434 435 } else { 436 BUG(); 437 }; 438 439 return 0; 440 } 441 442 /** 443 * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm 444 * @clkdm: struct clockdomain * 445 * 446 * Allow the hardware to automatically switch the clockdomain into 447 * active or idle states, as needed by downstream clocks. If the 448 * clockdomain has any downstream clocks enabled in the clock 449 * framework, wkdep/sleepdep autodependencies are added; this is so 450 * device drivers can read and write to the device. No return value. 451 */ 452 void omap2_clkdm_allow_idle(struct clockdomain *clkdm) 453 { 454 u32 v; 455 456 if (!clkdm) 457 return; 458 459 if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) { 460 pr_debug("clock: automatic idle transitions cannot be enabled " 461 "on clockdomain %s\n", clkdm->name); 462 return; 463 } 464 465 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 466 clkdm->name); 467 468 if (atomic_read(&clkdm->usecount) > 0) 469 _clkdm_add_autodeps(clkdm); 470 471 if (cpu_is_omap24xx()) 472 v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; 473 else if (cpu_is_omap34xx()) 474 v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; 475 else 476 BUG(); 477 478 479 cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, 480 v << __ffs(clkdm->clktrctrl_mask), 481 clkdm->pwrdm->prcm_offs, 482 CM_CLKSTCTRL); 483 } 484 485 /** 486 * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm 487 * @clkdm: struct clockdomain * 488 * 489 * Prevent the hardware from automatically switching the clockdomain 490 * into inactive or idle states. If the clockdomain has downstream 491 * clocks enabled in the clock framework, wkdep/sleepdep 492 * autodependencies are removed. No return value. 493 */ 494 void omap2_clkdm_deny_idle(struct clockdomain *clkdm) 495 { 496 u32 v; 497 498 if (!clkdm) 499 return; 500 501 if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) { 502 pr_debug("clockdomain: automatic idle transitions cannot be " 503 "disabled on %s\n", clkdm->name); 504 return; 505 } 506 507 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 508 clkdm->name); 509 510 if (cpu_is_omap24xx()) 511 v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; 512 else if (cpu_is_omap34xx()) 513 v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO; 514 else 515 BUG(); 516 517 cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, 518 v << __ffs(clkdm->clktrctrl_mask), 519 clkdm->pwrdm->prcm_offs, CM_CLKSTCTRL); 520 521 if (atomic_read(&clkdm->usecount) > 0) 522 _clkdm_del_autodeps(clkdm); 523 } 524 525 526 /* Clockdomain-to-clock framework interface code */ 527 528 /** 529 * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm 530 * @clkdm: struct clockdomain * 531 * @clk: struct clk * of the enabled downstream clock 532 * 533 * Increment the usecount of this clockdomain 'clkdm' and ensure that 534 * it is awake. Intended to be called by clk_enable() code. If the 535 * clockdomain is in software-supervised idle mode, force the 536 * clockdomain to wake. If the clockdomain is in hardware-supervised 537 * idle mode, add clkdm-pwrdm autodependencies, to ensure that devices 538 * in the clockdomain can be read from/written to by on-chip processors. 539 * Returns -EINVAL if passed null pointers; returns 0 upon success or 540 * if the clockdomain is in hwsup idle mode. 541 */ 542 int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) 543 { 544 int v; 545 546 /* 547 * XXX Rewrite this code to maintain a list of enabled 548 * downstream clocks for debugging purposes? 549 */ 550 551 if (!clkdm || !clk) 552 return -EINVAL; 553 554 if (atomic_inc_return(&clkdm->usecount) > 1) 555 return 0; 556 557 /* Clockdomain now has one enabled downstream clock */ 558 559 pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name, 560 clk->name); 561 562 v = omap2_clkdm_clktrctrl_read(clkdm); 563 564 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || 565 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) 566 _clkdm_add_autodeps(clkdm); 567 else 568 omap2_clkdm_wakeup(clkdm); 569 570 return 0; 571 } 572 573 /** 574 * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm 575 * @clkdm: struct clockdomain * 576 * @clk: struct clk * of the disabled downstream clock 577 * 578 * Decrement the usecount of this clockdomain 'clkdm'. Intended to be 579 * called by clk_disable() code. If the usecount goes to 0, put the 580 * clockdomain to sleep (software-supervised mode) or remove the 581 * clkdm-pwrdm autodependencies (hardware-supervised mode). Returns 582 * -EINVAL if passed null pointers; -ERANGE if the clkdm usecount 583 * underflows and debugging is enabled; or returns 0 upon success or 584 * if the clockdomain is in hwsup idle mode. 585 */ 586 int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 587 { 588 int v; 589 590 /* 591 * XXX Rewrite this code to maintain a list of enabled 592 * downstream clocks for debugging purposes? 593 */ 594 595 if (!clkdm || !clk) 596 return -EINVAL; 597 598 #ifdef DEBUG 599 if (atomic_read(&clkdm->usecount) == 0) { 600 WARN_ON(1); /* underflow */ 601 return -ERANGE; 602 } 603 #endif 604 605 if (atomic_dec_return(&clkdm->usecount) > 0) 606 return 0; 607 608 /* All downstream clocks of this clockdomain are now disabled */ 609 610 pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, 611 clk->name); 612 613 v = omap2_clkdm_clktrctrl_read(clkdm); 614 615 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || 616 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) 617 _clkdm_del_autodeps(clkdm); 618 else 619 omap2_clkdm_sleep(clkdm); 620 621 return 0; 622 } 623 624