1 /* 2 * OMAP2/3/4 clockdomain framework functions 3 * 4 * Copyright (C) 2008-2010 Texas Instruments, Inc. 5 * Copyright (C) 2008-2010 Nokia Corporation 6 * 7 * Written by Paul Walmsley and Jouni Högander 8 * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 #undef DEBUG 15 16 #include <linux/module.h> 17 #include <linux/kernel.h> 18 #include <linux/device.h> 19 #include <linux/list.h> 20 #include <linux/errno.h> 21 #include <linux/delay.h> 22 #include <linux/clk.h> 23 #include <linux/limits.h> 24 #include <linux/err.h> 25 26 #include <linux/io.h> 27 28 #include <linux/bitops.h> 29 30 #include "prm2xxx_3xxx.h" 31 #include "prm-regbits-24xx.h" 32 #include "cm2xxx_3xxx.h" 33 #include "cm2xxx_3xxx.h" 34 35 #include <plat/clock.h> 36 #include <plat/powerdomain.h> 37 #include <plat/clockdomain.h> 38 #include <plat/prcm.h> 39 40 /* clkdm_list contains all registered struct clockdomains */ 41 static LIST_HEAD(clkdm_list); 42 43 /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ 44 static struct clkdm_autodep *autodeps; 45 46 47 /* Private functions */ 48 49 static struct clockdomain *_clkdm_lookup(const char *name) 50 { 51 struct clockdomain *clkdm, *temp_clkdm; 52 53 if (!name) 54 return NULL; 55 56 clkdm = NULL; 57 58 list_for_each_entry(temp_clkdm, &clkdm_list, node) { 59 if (!strcmp(name, temp_clkdm->name)) { 60 clkdm = temp_clkdm; 61 break; 62 } 63 } 64 65 return clkdm; 66 } 67 68 /** 69 * _clkdm_register - register a clockdomain 70 * @clkdm: struct clockdomain * to register 71 * 72 * Adds a clockdomain to the internal clockdomain list. 73 * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is 74 * already registered by the provided name, or 0 upon success. 75 */ 76 static int _clkdm_register(struct clockdomain *clkdm) 77 { 78 struct powerdomain *pwrdm; 79 80 if (!clkdm || !clkdm->name) 81 return -EINVAL; 82 83 if (!omap_chip_is(clkdm->omap_chip)) 84 return -EINVAL; 85 86 pwrdm = pwrdm_lookup(clkdm->pwrdm.name); 87 if (!pwrdm) { 88 pr_err("clockdomain: %s: powerdomain %s does not exist\n", 89 clkdm->name, clkdm->pwrdm.name); 90 return -EINVAL; 91 } 92 clkdm->pwrdm.ptr = pwrdm; 93 94 /* Verify that the clockdomain is not already registered */ 95 if (_clkdm_lookup(clkdm->name)) 96 return -EEXIST; 97 98 list_add(&clkdm->node, &clkdm_list); 99 100 pwrdm_add_clkdm(pwrdm, clkdm); 101 102 pr_debug("clockdomain: registered %s\n", clkdm->name); 103 104 return 0; 105 } 106 107 /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */ 108 static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, 109 struct clkdm_dep *deps) 110 { 111 struct clkdm_dep *cd; 112 113 if (!clkdm || !deps || !omap_chip_is(clkdm->omap_chip)) 114 return ERR_PTR(-EINVAL); 115 116 for (cd = deps; cd->clkdm_name; cd++) { 117 if (!omap_chip_is(cd->omap_chip)) 118 continue; 119 120 if (!cd->clkdm && cd->clkdm_name) 121 cd->clkdm = _clkdm_lookup(cd->clkdm_name); 122 123 if (cd->clkdm == clkdm) 124 break; 125 } 126 127 if (!cd->clkdm_name) 128 return ERR_PTR(-ENOENT); 129 130 return cd; 131 } 132 133 /* 134 * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store 135 * @autodep: struct clkdm_autodep * to resolve 136 * 137 * Resolve autodep clockdomain names to clockdomain pointers via 138 * clkdm_lookup() and store the pointers in the autodep structure. An 139 * "autodep" is a clockdomain sleep/wakeup dependency that is 140 * automatically added and removed whenever clocks in the associated 141 * clockdomain are enabled or disabled (respectively) when the 142 * clockdomain is in hardware-supervised mode. Meant to be called 143 * once at clockdomain layer initialization, since these should remain 144 * fixed for a particular architecture. No return value. 145 */ 146 static void _autodep_lookup(struct clkdm_autodep *autodep) 147 { 148 struct clockdomain *clkdm; 149 150 if (!autodep) 151 return; 152 153 if (!omap_chip_is(autodep->omap_chip)) 154 return; 155 156 clkdm = clkdm_lookup(autodep->clkdm.name); 157 if (!clkdm) { 158 pr_err("clockdomain: autodeps: clockdomain %s does not exist\n", 159 autodep->clkdm.name); 160 clkdm = ERR_PTR(-ENOENT); 161 } 162 autodep->clkdm.ptr = clkdm; 163 } 164 165 /* 166 * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable 167 * @clkdm: struct clockdomain * 168 * 169 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' 170 * in hardware-supervised mode. Meant to be called from clock framework 171 * when a clock inside clockdomain 'clkdm' is enabled. No return value. 172 */ 173 static void _clkdm_add_autodeps(struct clockdomain *clkdm) 174 { 175 struct clkdm_autodep *autodep; 176 177 if (!autodeps) 178 return; 179 180 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 181 if (IS_ERR(autodep->clkdm.ptr)) 182 continue; 183 184 if (!omap_chip_is(autodep->omap_chip)) 185 continue; 186 187 pr_debug("clockdomain: adding %s sleepdep/wkdep for " 188 "clkdm %s\n", autodep->clkdm.ptr->name, 189 clkdm->name); 190 191 clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); 192 clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); 193 } 194 } 195 196 /* 197 * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm 198 * @clkdm: struct clockdomain * 199 * 200 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' 201 * in hardware-supervised mode. Meant to be called from clock framework 202 * when a clock inside clockdomain 'clkdm' is disabled. No return value. 203 */ 204 static void _clkdm_del_autodeps(struct clockdomain *clkdm) 205 { 206 struct clkdm_autodep *autodep; 207 208 if (!autodeps) 209 return; 210 211 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 212 if (IS_ERR(autodep->clkdm.ptr)) 213 continue; 214 215 if (!omap_chip_is(autodep->omap_chip)) 216 continue; 217 218 pr_debug("clockdomain: removing %s sleepdep/wkdep for " 219 "clkdm %s\n", autodep->clkdm.ptr->name, 220 clkdm->name); 221 222 clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); 223 clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); 224 } 225 } 226 227 /* 228 * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit 229 * @clkdm: struct clockdomain * 230 * @enable: int 0 to disable, 1 to enable 231 * 232 * Internal helper for actually switching the bit that controls hwsup 233 * idle transitions for clkdm. 234 */ 235 static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) 236 { 237 u32 bits, v; 238 239 if (cpu_is_omap24xx()) { 240 if (enable) 241 bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; 242 else 243 bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; 244 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 245 if (enable) 246 bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; 247 else 248 bits = OMAP34XX_CLKSTCTRL_DISABLE_AUTO; 249 } else { 250 BUG(); 251 } 252 253 bits = bits << __ffs(clkdm->clktrctrl_mask); 254 255 v = __raw_readl(clkdm->clkstctrl_reg); 256 v &= ~(clkdm->clktrctrl_mask); 257 v |= bits; 258 __raw_writel(v, clkdm->clkstctrl_reg); 259 260 } 261 262 /* Public functions */ 263 264 /** 265 * clkdm_init - set up the clockdomain layer 266 * @clkdms: optional pointer to an array of clockdomains to register 267 * @init_autodeps: optional pointer to an array of autodeps to register 268 * 269 * Set up internal state. If a pointer to an array of clockdomains 270 * @clkdms was supplied, loop through the list of clockdomains, 271 * register all that are available on the current platform. Similarly, 272 * if a pointer to an array of clockdomain autodependencies 273 * @init_autodeps was provided, register those. No return value. 274 */ 275 void clkdm_init(struct clockdomain **clkdms, 276 struct clkdm_autodep *init_autodeps) 277 { 278 struct clockdomain **c = NULL; 279 struct clockdomain *clkdm; 280 struct clkdm_autodep *autodep = NULL; 281 282 if (clkdms) 283 for (c = clkdms; *c; c++) 284 _clkdm_register(*c); 285 286 autodeps = init_autodeps; 287 if (autodeps) 288 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) 289 _autodep_lookup(autodep); 290 291 /* 292 * Put all clockdomains into software-supervised mode; PM code 293 * should later enable hardware-supervised mode as appropriate 294 */ 295 list_for_each_entry(clkdm, &clkdm_list, node) { 296 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 297 omap2_clkdm_wakeup(clkdm); 298 else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) 299 omap2_clkdm_deny_idle(clkdm); 300 301 clkdm_clear_all_wkdeps(clkdm); 302 clkdm_clear_all_sleepdeps(clkdm); 303 } 304 } 305 306 /** 307 * clkdm_lookup - look up a clockdomain by name, return a pointer 308 * @name: name of clockdomain 309 * 310 * Find a registered clockdomain by its name @name. Returns a pointer 311 * to the struct clockdomain if found, or NULL otherwise. 312 */ 313 struct clockdomain *clkdm_lookup(const char *name) 314 { 315 struct clockdomain *clkdm, *temp_clkdm; 316 317 if (!name) 318 return NULL; 319 320 clkdm = NULL; 321 322 list_for_each_entry(temp_clkdm, &clkdm_list, node) { 323 if (!strcmp(name, temp_clkdm->name)) { 324 clkdm = temp_clkdm; 325 break; 326 } 327 } 328 329 return clkdm; 330 } 331 332 /** 333 * clkdm_for_each - call function on each registered clockdomain 334 * @fn: callback function * 335 * 336 * Call the supplied function @fn for each registered clockdomain. 337 * The callback function @fn can return anything but 0 to bail 338 * out early from the iterator. The callback function is called with 339 * the clkdm_mutex held, so no clockdomain structure manipulation 340 * functions should be called from the callback, although hardware 341 * clockdomain control functions are fine. Returns the last return 342 * value of the callback function, which should be 0 for success or 343 * anything else to indicate failure; or -EINVAL if the function pointer 344 * is null. 345 */ 346 int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), 347 void *user) 348 { 349 struct clockdomain *clkdm; 350 int ret = 0; 351 352 if (!fn) 353 return -EINVAL; 354 355 list_for_each_entry(clkdm, &clkdm_list, node) { 356 ret = (*fn)(clkdm, user); 357 if (ret) 358 break; 359 } 360 361 return ret; 362 } 363 364 365 /** 366 * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in 367 * @clkdm: struct clockdomain * 368 * 369 * Return a pointer to the struct powerdomain that the specified clockdomain 370 * @clkdm exists in, or returns NULL if @clkdm is NULL. 371 */ 372 struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) 373 { 374 if (!clkdm) 375 return NULL; 376 377 return clkdm->pwrdm.ptr; 378 } 379 380 381 /* Hardware clockdomain control */ 382 383 /** 384 * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 385 * @clkdm1: wake this struct clockdomain * up (dependent) 386 * @clkdm2: when this struct clockdomain * wakes up (source) 387 * 388 * When the clockdomain represented by @clkdm2 wakes up, wake up 389 * @clkdm1. Implemented in hardware on the OMAP, this feature is 390 * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. 391 * Returns -EINVAL if presented with invalid clockdomain pointers, 392 * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon 393 * success. 394 */ 395 int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 396 { 397 struct clkdm_dep *cd; 398 399 if (!clkdm1 || !clkdm2) 400 return -EINVAL; 401 402 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 403 if (IS_ERR(cd)) { 404 pr_debug("clockdomain: hardware cannot set/clear wake up of " 405 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 406 return PTR_ERR(cd); 407 } 408 409 if (atomic_inc_return(&cd->wkdep_usecount) == 1) { 410 pr_debug("clockdomain: hardware will wake up %s when %s wakes " 411 "up\n", clkdm1->name, clkdm2->name); 412 413 prm_set_mod_reg_bits((1 << clkdm2->dep_bit), 414 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 415 } 416 417 return 0; 418 } 419 420 /** 421 * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1 422 * @clkdm1: wake this struct clockdomain * up (dependent) 423 * @clkdm2: when this struct clockdomain * wakes up (source) 424 * 425 * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 426 * wakes up. Returns -EINVAL if presented with invalid clockdomain 427 * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 428 * 0 upon success. 429 */ 430 int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 431 { 432 struct clkdm_dep *cd; 433 434 if (!clkdm1 || !clkdm2) 435 return -EINVAL; 436 437 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 438 if (IS_ERR(cd)) { 439 pr_debug("clockdomain: hardware cannot set/clear wake up of " 440 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 441 return PTR_ERR(cd); 442 } 443 444 if (atomic_dec_return(&cd->wkdep_usecount) == 0) { 445 pr_debug("clockdomain: hardware will no longer wake up %s " 446 "after %s wakes up\n", clkdm1->name, clkdm2->name); 447 448 prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 449 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 450 } 451 452 return 0; 453 } 454 455 /** 456 * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1 457 * @clkdm1: wake this struct clockdomain * up (dependent) 458 * @clkdm2: when this struct clockdomain * wakes up (source) 459 * 460 * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be 461 * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL 462 * if either clockdomain pointer is invalid; or -ENOENT if the hardware 463 * is incapable. 464 * 465 * REVISIT: Currently this function only represents software-controllable 466 * wakeup dependencies. Wakeup dependencies fixed in hardware are not 467 * yet handled here. 468 */ 469 int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 470 { 471 struct clkdm_dep *cd; 472 473 if (!clkdm1 || !clkdm2) 474 return -EINVAL; 475 476 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 477 if (IS_ERR(cd)) { 478 pr_debug("clockdomain: hardware cannot set/clear wake up of " 479 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 480 return PTR_ERR(cd); 481 } 482 483 /* XXX It's faster to return the atomic wkdep_usecount */ 484 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, 485 (1 << clkdm2->dep_bit)); 486 } 487 488 /** 489 * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm 490 * @clkdm: struct clockdomain * to remove all wakeup dependencies from 491 * 492 * Remove all inter-clockdomain wakeup dependencies that could cause 493 * @clkdm to wake. Intended to be used during boot to initialize the 494 * PRCM to a known state, after all clockdomains are put into swsup idle 495 * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or 496 * 0 upon success. 497 */ 498 int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) 499 { 500 struct clkdm_dep *cd; 501 u32 mask = 0; 502 503 if (!clkdm) 504 return -EINVAL; 505 506 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { 507 if (!omap_chip_is(cd->omap_chip)) 508 continue; 509 510 if (!cd->clkdm && cd->clkdm_name) 511 cd->clkdm = _clkdm_lookup(cd->clkdm_name); 512 513 /* PRM accesses are slow, so minimize them */ 514 mask |= 1 << cd->clkdm->dep_bit; 515 atomic_set(&cd->wkdep_usecount, 0); 516 } 517 518 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP); 519 520 return 0; 521 } 522 523 /** 524 * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 525 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 526 * @clkdm2: when this struct clockdomain * is active (source) 527 * 528 * Prevent @clkdm1 from automatically going inactive (and then to 529 * retention or off) if @clkdm2 is active. Returns -EINVAL if 530 * presented with invalid clockdomain pointers or called on a machine 531 * that does not support software-configurable hardware sleep 532 * dependencies, -ENOENT if the specified dependency cannot be set in 533 * hardware, or 0 upon success. 534 */ 535 int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 536 { 537 struct clkdm_dep *cd; 538 539 if (!cpu_is_omap34xx()) 540 return -EINVAL; 541 542 if (!clkdm1 || !clkdm2) 543 return -EINVAL; 544 545 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 546 if (IS_ERR(cd)) { 547 pr_debug("clockdomain: hardware cannot set/clear sleep " 548 "dependency affecting %s from %s\n", clkdm1->name, 549 clkdm2->name); 550 return PTR_ERR(cd); 551 } 552 553 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { 554 pr_debug("clockdomain: will prevent %s from sleeping if %s " 555 "is active\n", clkdm1->name, clkdm2->name); 556 557 cm_set_mod_reg_bits((1 << clkdm2->dep_bit), 558 clkdm1->pwrdm.ptr->prcm_offs, 559 OMAP3430_CM_SLEEPDEP); 560 } 561 562 return 0; 563 } 564 565 /** 566 * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1 567 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 568 * @clkdm2: when this struct clockdomain * is active (source) 569 * 570 * Allow @clkdm1 to automatically go inactive (and then to retention or 571 * off), independent of the activity state of @clkdm2. Returns -EINVAL 572 * if presented with invalid clockdomain pointers or called on a machine 573 * that does not support software-configurable hardware sleep dependencies, 574 * -ENOENT if the specified dependency cannot be cleared in hardware, or 575 * 0 upon success. 576 */ 577 int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 578 { 579 struct clkdm_dep *cd; 580 581 if (!cpu_is_omap34xx()) 582 return -EINVAL; 583 584 if (!clkdm1 || !clkdm2) 585 return -EINVAL; 586 587 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 588 if (IS_ERR(cd)) { 589 pr_debug("clockdomain: hardware cannot set/clear sleep " 590 "dependency affecting %s from %s\n", clkdm1->name, 591 clkdm2->name); 592 return PTR_ERR(cd); 593 } 594 595 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { 596 pr_debug("clockdomain: will no longer prevent %s from " 597 "sleeping if %s is active\n", clkdm1->name, 598 clkdm2->name); 599 600 cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 601 clkdm1->pwrdm.ptr->prcm_offs, 602 OMAP3430_CM_SLEEPDEP); 603 } 604 605 return 0; 606 } 607 608 /** 609 * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1 610 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 611 * @clkdm2: when this struct clockdomain * is active (source) 612 * 613 * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will 614 * not be allowed to automatically go inactive if @clkdm2 is active; 615 * 0 if @clkdm1's automatic power state inactivity transition is independent 616 * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called 617 * on a machine that does not support software-configurable hardware sleep 618 * dependencies; or -ENOENT if the hardware is incapable. 619 * 620 * REVISIT: Currently this function only represents software-controllable 621 * sleep dependencies. Sleep dependencies fixed in hardware are not 622 * yet handled here. 623 */ 624 int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 625 { 626 struct clkdm_dep *cd; 627 628 if (!cpu_is_omap34xx()) 629 return -EINVAL; 630 631 if (!clkdm1 || !clkdm2) 632 return -EINVAL; 633 634 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 635 if (IS_ERR(cd)) { 636 pr_debug("clockdomain: hardware cannot set/clear sleep " 637 "dependency affecting %s from %s\n", clkdm1->name, 638 clkdm2->name); 639 return PTR_ERR(cd); 640 } 641 642 /* XXX It's faster to return the atomic sleepdep_usecount */ 643 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, 644 OMAP3430_CM_SLEEPDEP, 645 (1 << clkdm2->dep_bit)); 646 } 647 648 /** 649 * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm 650 * @clkdm: struct clockdomain * to remove all sleep dependencies from 651 * 652 * Remove all inter-clockdomain sleep dependencies that could prevent 653 * @clkdm from idling. Intended to be used during boot to initialize the 654 * PRCM to a known state, after all clockdomains are put into swsup idle 655 * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or 656 * 0 upon success. 657 */ 658 int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) 659 { 660 struct clkdm_dep *cd; 661 u32 mask = 0; 662 663 if (!cpu_is_omap34xx()) 664 return -EINVAL; 665 666 if (!clkdm) 667 return -EINVAL; 668 669 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { 670 if (!omap_chip_is(cd->omap_chip)) 671 continue; 672 673 if (!cd->clkdm && cd->clkdm_name) 674 cd->clkdm = _clkdm_lookup(cd->clkdm_name); 675 676 /* PRM accesses are slow, so minimize them */ 677 mask |= 1 << cd->clkdm->dep_bit; 678 atomic_set(&cd->sleepdep_usecount, 0); 679 } 680 681 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, 682 OMAP3430_CM_SLEEPDEP); 683 684 return 0; 685 } 686 687 /** 688 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode 689 * @clkdm: struct clkdm * of a clockdomain 690 * 691 * Return the clockdomain @clkdm current state transition mode from the 692 * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if @clkdm 693 * is NULL or the current mode upon success. 694 */ 695 static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) 696 { 697 u32 v; 698 699 if (!clkdm) 700 return -EINVAL; 701 702 v = __raw_readl(clkdm->clkstctrl_reg); 703 v &= clkdm->clktrctrl_mask; 704 v >>= __ffs(clkdm->clktrctrl_mask); 705 706 return v; 707 } 708 709 /** 710 * omap2_clkdm_sleep - force clockdomain sleep transition 711 * @clkdm: struct clockdomain * 712 * 713 * Instruct the CM to force a sleep transition on the specified 714 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if 715 * clockdomain does not support software-initiated sleep; 0 upon 716 * success. 717 */ 718 int omap2_clkdm_sleep(struct clockdomain *clkdm) 719 { 720 if (!clkdm) 721 return -EINVAL; 722 723 if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { 724 pr_debug("clockdomain: %s does not support forcing " 725 "sleep via software\n", clkdm->name); 726 return -EINVAL; 727 } 728 729 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 730 731 if (cpu_is_omap24xx()) { 732 733 cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 734 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); 735 736 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 737 738 u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << 739 __ffs(clkdm->clktrctrl_mask)); 740 741 u32 v = __raw_readl(clkdm->clkstctrl_reg); 742 v &= ~(clkdm->clktrctrl_mask); 743 v |= bits; 744 __raw_writel(v, clkdm->clkstctrl_reg); 745 746 } else { 747 BUG(); 748 }; 749 750 return 0; 751 } 752 753 /** 754 * omap2_clkdm_wakeup - force clockdomain wakeup transition 755 * @clkdm: struct clockdomain * 756 * 757 * Instruct the CM to force a wakeup transition on the specified 758 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the 759 * clockdomain does not support software-controlled wakeup; 0 upon 760 * success. 761 */ 762 int omap2_clkdm_wakeup(struct clockdomain *clkdm) 763 { 764 if (!clkdm) 765 return -EINVAL; 766 767 if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { 768 pr_debug("clockdomain: %s does not support forcing " 769 "wakeup via software\n", clkdm->name); 770 return -EINVAL; 771 } 772 773 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 774 775 if (cpu_is_omap24xx()) { 776 777 cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 778 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); 779 780 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 781 782 u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << 783 __ffs(clkdm->clktrctrl_mask)); 784 785 u32 v = __raw_readl(clkdm->clkstctrl_reg); 786 v &= ~(clkdm->clktrctrl_mask); 787 v |= bits; 788 __raw_writel(v, clkdm->clkstctrl_reg); 789 790 } else { 791 BUG(); 792 }; 793 794 return 0; 795 } 796 797 /** 798 * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm 799 * @clkdm: struct clockdomain * 800 * 801 * Allow the hardware to automatically switch the clockdomain @clkdm into 802 * active or idle states, as needed by downstream clocks. If the 803 * clockdomain has any downstream clocks enabled in the clock 804 * framework, wkdep/sleepdep autodependencies are added; this is so 805 * device drivers can read and write to the device. No return value. 806 */ 807 void omap2_clkdm_allow_idle(struct clockdomain *clkdm) 808 { 809 if (!clkdm) 810 return; 811 812 if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) { 813 pr_debug("clock: automatic idle transitions cannot be enabled " 814 "on clockdomain %s\n", clkdm->name); 815 return; 816 } 817 818 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 819 clkdm->name); 820 821 /* 822 * XXX This should be removed once TI adds wakeup/sleep 823 * dependency code and data for OMAP4. 824 */ 825 if (cpu_is_omap44xx()) { 826 WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency " 827 "support is not yet implemented\n"); 828 } else { 829 if (atomic_read(&clkdm->usecount) > 0) 830 _clkdm_add_autodeps(clkdm); 831 } 832 833 _omap2_clkdm_set_hwsup(clkdm, 1); 834 835 pwrdm_clkdm_state_switch(clkdm); 836 } 837 838 /** 839 * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm 840 * @clkdm: struct clockdomain * 841 * 842 * Prevent the hardware from automatically switching the clockdomain 843 * @clkdm into inactive or idle states. If the clockdomain has 844 * downstream clocks enabled in the clock framework, wkdep/sleepdep 845 * autodependencies are removed. No return value. 846 */ 847 void omap2_clkdm_deny_idle(struct clockdomain *clkdm) 848 { 849 if (!clkdm) 850 return; 851 852 if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) { 853 pr_debug("clockdomain: automatic idle transitions cannot be " 854 "disabled on %s\n", clkdm->name); 855 return; 856 } 857 858 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 859 clkdm->name); 860 861 _omap2_clkdm_set_hwsup(clkdm, 0); 862 863 /* 864 * XXX This should be removed once TI adds wakeup/sleep 865 * dependency code and data for OMAP4. 866 */ 867 if (cpu_is_omap44xx()) { 868 WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency " 869 "support is not yet implemented\n"); 870 } else { 871 if (atomic_read(&clkdm->usecount) > 0) 872 _clkdm_del_autodeps(clkdm); 873 } 874 } 875 876 877 /* Clockdomain-to-clock framework interface code */ 878 879 /** 880 * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm 881 * @clkdm: struct clockdomain * 882 * @clk: struct clk * of the enabled downstream clock 883 * 884 * Increment the usecount of the clockdomain @clkdm and ensure that it 885 * is awake before @clk is enabled. Intended to be called by 886 * clk_enable() code. If the clockdomain is in software-supervised 887 * idle mode, force the clockdomain to wake. If the clockdomain is in 888 * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to 889 * ensure that devices in the clockdomain can be read from/written to 890 * by on-chip processors. Returns -EINVAL if passed null pointers; 891 * returns 0 upon success or if the clockdomain is in hwsup idle mode. 892 */ 893 int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) 894 { 895 int v; 896 897 /* 898 * XXX Rewrite this code to maintain a list of enabled 899 * downstream clocks for debugging purposes? 900 */ 901 902 if (!clkdm || !clk) 903 return -EINVAL; 904 905 if (atomic_inc_return(&clkdm->usecount) > 1) 906 return 0; 907 908 /* Clockdomain now has one enabled downstream clock */ 909 910 pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name, 911 clk->name); 912 913 if (!clkdm->clkstctrl_reg) 914 return 0; 915 916 v = omap2_clkdm_clktrctrl_read(clkdm); 917 918 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || 919 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) { 920 /* Disable HW transitions when we are changing deps */ 921 _omap2_clkdm_set_hwsup(clkdm, 0); 922 _clkdm_add_autodeps(clkdm); 923 _omap2_clkdm_set_hwsup(clkdm, 1); 924 } else { 925 omap2_clkdm_wakeup(clkdm); 926 } 927 928 pwrdm_wait_transition(clkdm->pwrdm.ptr); 929 pwrdm_clkdm_state_switch(clkdm); 930 931 return 0; 932 } 933 934 /** 935 * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm 936 * @clkdm: struct clockdomain * 937 * @clk: struct clk * of the disabled downstream clock 938 * 939 * Decrement the usecount of this clockdomain @clkdm when @clk is 940 * disabled. Intended to be called by clk_disable() code. If the 941 * clockdomain usecount goes to 0, put the clockdomain to sleep 942 * (software-supervised mode) or remove the clkdm autodependencies 943 * (hardware-supervised mode). Returns -EINVAL if passed null 944 * pointers; -ERANGE if the @clkdm usecount underflows and debugging 945 * is enabled; or returns 0 upon success or if the clockdomain is in 946 * hwsup idle mode. 947 */ 948 int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 949 { 950 int v; 951 952 /* 953 * XXX Rewrite this code to maintain a list of enabled 954 * downstream clocks for debugging purposes? 955 */ 956 957 if (!clkdm || !clk) 958 return -EINVAL; 959 960 #ifdef DEBUG 961 if (atomic_read(&clkdm->usecount) == 0) { 962 WARN_ON(1); /* underflow */ 963 return -ERANGE; 964 } 965 #endif 966 967 if (atomic_dec_return(&clkdm->usecount) > 0) 968 return 0; 969 970 /* All downstream clocks of this clockdomain are now disabled */ 971 972 pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, 973 clk->name); 974 975 if (!clkdm->clkstctrl_reg) 976 return 0; 977 978 v = omap2_clkdm_clktrctrl_read(clkdm); 979 980 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || 981 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) { 982 /* Disable HW transitions when we are changing deps */ 983 _omap2_clkdm_set_hwsup(clkdm, 0); 984 _clkdm_del_autodeps(clkdm); 985 _omap2_clkdm_set_hwsup(clkdm, 1); 986 } else { 987 omap2_clkdm_sleep(clkdm); 988 } 989 990 pwrdm_clkdm_state_switch(clkdm); 991 992 return 0; 993 } 994 995