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