Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc/tegra: pmc: Add generic PM domain support

Adds generic PM domain support to the PMC driver where the PM domains
are populated from device-tree and the PM domain consumer devices are
bound to their relevant PM domains via device-tree as well.

Update the tegra_powergate_sequence_power_up() API so that internally
it calls the same tegra_powergate_xxx functions that are used by the
Tegra generic PM domain code for consistency.

To ensure that the Tegra power domains (a.k.a. powergates) cannot be
controlled via both the legacy tegra_powergate_xxx functions as well
as the generic PM domain framework, add a bit map for available
powergates that can be controlled via the legacy powergate functions.

Move the majority of the tegra_powergate_remove_clamping() function
to a sub-function, so that this can be used by both the legacy and
generic power domain code.

This is based upon work by Thierry Reding <treding@nvidia.com>
and Vince Hsu <vinceh@nvidia.com>.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Jon Hunter and committed by
Thierry Reding
a3804512 b5c46cef

+441 -77
+440 -77
drivers/soc/tegra/pmc.c
··· 31 31 #include <linux/iopoll.h> 32 32 #include <linux/of.h> 33 33 #include <linux/of_address.h> 34 + #include <linux/of_platform.h> 34 35 #include <linux/platform_device.h> 36 + #include <linux/pm_domain.h> 35 37 #include <linux/reboot.h> 36 38 #include <linux/reset.h> 37 39 #include <linux/seq_file.h> 40 + #include <linux/slab.h> 38 41 #include <linux/spinlock.h> 39 42 40 43 #include <soc/tegra/common.h> ··· 105 102 106 103 #define GPU_RG_CNTRL 0x2d4 107 104 105 + struct tegra_powergate { 106 + struct generic_pm_domain genpd; 107 + struct tegra_pmc *pmc; 108 + unsigned int id; 109 + struct clk **clks; 110 + unsigned int num_clks; 111 + struct reset_control **resets; 112 + unsigned int num_resets; 113 + }; 114 + 108 115 struct tegra_pmc_soc { 109 116 unsigned int num_powergates; 110 117 const char *const *powergates; ··· 145 132 * @cpu_pwr_good_en: CPU power good signal is enabled 146 133 * @lp0_vec_phys: physical base address of the LP0 warm boot code 147 134 * @lp0_vec_size: size of the LP0 warm boot code 135 + * @powergates_available: Bitmap of available power gates 148 136 * @powergates_lock: mutex for power gate register access 149 137 */ 150 138 struct tegra_pmc { ··· 170 156 bool cpu_pwr_good_en; 171 157 u32 lp0_vec_phys; 172 158 u32 lp0_vec_size; 159 + DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); 173 160 174 161 struct mutex powergates_lock; 175 162 }; ··· 179 164 .base = NULL, 180 165 .suspend_mode = TEGRA_SUSPEND_NONE, 181 166 }; 167 + 168 + static inline struct tegra_powergate * 169 + to_powergate(struct generic_pm_domain *domain) 170 + { 171 + return container_of(domain, struct tegra_powergate, genpd); 172 + } 182 173 183 174 static u32 tegra_pmc_readl(unsigned long offset) 184 175 { ··· 207 186 static inline bool tegra_powergate_is_valid(int id) 208 187 { 209 188 return (pmc->soc && pmc->soc->powergates[id]); 189 + } 190 + 191 + static inline bool tegra_powergate_is_available(int id) 192 + { 193 + return test_bit(id, pmc->powergates_available); 194 + } 195 + 196 + static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) 197 + { 198 + unsigned int i; 199 + 200 + if (!pmc || !pmc->soc || !name) 201 + return -EINVAL; 202 + 203 + for (i = 0; i < pmc->soc->num_powergates; i++) { 204 + if (!tegra_powergate_is_valid(i)) 205 + continue; 206 + 207 + if (!strcmp(name, pmc->soc->powergates[i])) 208 + return i; 209 + } 210 + 211 + dev_err(pmc->dev, "powergate %s not found\n", name); 212 + 213 + return -ENODEV; 210 214 } 211 215 212 216 /** ··· 264 218 return err; 265 219 } 266 220 267 - /** 268 - * tegra_powergate_power_on() - power on partition 269 - * @id: partition ID 270 - */ 271 - int tegra_powergate_power_on(unsigned int id) 272 - { 273 - if (!tegra_powergate_is_valid(id)) 274 - return -EINVAL; 275 - 276 - return tegra_powergate_set(id, true); 277 - } 278 - 279 - /** 280 - * tegra_powergate_power_off() - power off partition 281 - * @id: partition ID 282 - */ 283 - int tegra_powergate_power_off(unsigned int id) 284 - { 285 - if (!tegra_powergate_is_valid(id)) 286 - return -EINVAL; 287 - 288 - return tegra_powergate_set(id, false); 289 - } 290 - EXPORT_SYMBOL(tegra_powergate_power_off); 291 - 292 - /** 293 - * tegra_powergate_is_powered() - check if partition is powered 294 - * @id: partition ID 295 - */ 296 - int tegra_powergate_is_powered(unsigned int id) 297 - { 298 - int status; 299 - 300 - if (!tegra_powergate_is_valid(id)) 301 - return -EINVAL; 302 - 303 - mutex_lock(&pmc->powergates_lock); 304 - status = tegra_powergate_state(id); 305 - mutex_unlock(&pmc->powergates_lock); 306 - 307 - return status; 308 - } 309 - 310 - /** 311 - * tegra_powergate_remove_clamping() - remove power clamps for partition 312 - * @id: partition ID 313 - */ 314 - int tegra_powergate_remove_clamping(unsigned int id) 221 + static int __tegra_powergate_remove_clamping(unsigned int id) 315 222 { 316 223 u32 mask; 317 - 318 - if (!tegra_powergate_is_valid(id)) 319 - return -EINVAL; 320 224 321 225 mutex_lock(&pmc->powergates_lock); 322 226 ··· 299 303 300 304 return 0; 301 305 } 306 + 307 + static void tegra_powergate_disable_clocks(struct tegra_powergate *pg) 308 + { 309 + unsigned int i; 310 + 311 + for (i = 0; i < pg->num_clks; i++) 312 + clk_disable_unprepare(pg->clks[i]); 313 + } 314 + 315 + static int tegra_powergate_enable_clocks(struct tegra_powergate *pg) 316 + { 317 + unsigned int i; 318 + int err; 319 + 320 + for (i = 0; i < pg->num_clks; i++) { 321 + err = clk_prepare_enable(pg->clks[i]); 322 + if (err) 323 + goto out; 324 + } 325 + 326 + return 0; 327 + 328 + out: 329 + while (i--) 330 + clk_disable_unprepare(pg->clks[i]); 331 + 332 + return err; 333 + } 334 + 335 + static int tegra_powergate_reset_assert(struct tegra_powergate *pg) 336 + { 337 + unsigned int i; 338 + int err; 339 + 340 + for (i = 0; i < pg->num_resets; i++) { 341 + err = reset_control_assert(pg->resets[i]); 342 + if (err) 343 + return err; 344 + } 345 + 346 + return 0; 347 + } 348 + 349 + static int tegra_powergate_reset_deassert(struct tegra_powergate *pg) 350 + { 351 + unsigned int i; 352 + int err; 353 + 354 + for (i = 0; i < pg->num_resets; i++) { 355 + err = reset_control_deassert(pg->resets[i]); 356 + if (err) 357 + return err; 358 + } 359 + 360 + return 0; 361 + } 362 + 363 + static int tegra_powergate_power_up(struct tegra_powergate *pg, 364 + bool disable_clocks) 365 + { 366 + int err; 367 + 368 + err = tegra_powergate_reset_assert(pg); 369 + if (err) 370 + return err; 371 + 372 + usleep_range(10, 20); 373 + 374 + err = tegra_powergate_set(pg->id, true); 375 + if (err < 0) 376 + return err; 377 + 378 + usleep_range(10, 20); 379 + 380 + err = tegra_powergate_enable_clocks(pg); 381 + if (err) 382 + goto disable_clks; 383 + 384 + usleep_range(10, 20); 385 + 386 + err = __tegra_powergate_remove_clamping(pg->id); 387 + if (err) 388 + goto disable_clks; 389 + 390 + usleep_range(10, 20); 391 + 392 + err = tegra_powergate_reset_deassert(pg); 393 + if (err) 394 + goto powergate_off; 395 + 396 + usleep_range(10, 20); 397 + 398 + if (disable_clocks) 399 + tegra_powergate_disable_clocks(pg); 400 + 401 + return 0; 402 + 403 + disable_clks: 404 + tegra_powergate_disable_clocks(pg); 405 + usleep_range(10, 20); 406 + powergate_off: 407 + tegra_powergate_set(pg->id, false); 408 + 409 + return err; 410 + } 411 + 412 + static int tegra_powergate_power_down(struct tegra_powergate *pg) 413 + { 414 + int err; 415 + 416 + err = tegra_powergate_enable_clocks(pg); 417 + if (err) 418 + return err; 419 + 420 + usleep_range(10, 20); 421 + 422 + err = tegra_powergate_reset_assert(pg); 423 + if (err) 424 + goto disable_clks; 425 + 426 + usleep_range(10, 20); 427 + 428 + tegra_powergate_disable_clocks(pg); 429 + 430 + usleep_range(10, 20); 431 + 432 + err = tegra_powergate_set(pg->id, false); 433 + if (err) 434 + goto assert_resets; 435 + 436 + return 0; 437 + 438 + assert_resets: 439 + tegra_powergate_enable_clocks(pg); 440 + usleep_range(10, 20); 441 + tegra_powergate_reset_deassert(pg); 442 + usleep_range(10, 20); 443 + disable_clks: 444 + tegra_powergate_disable_clocks(pg); 445 + 446 + return err; 447 + } 448 + 449 + static int tegra_genpd_power_on(struct generic_pm_domain *domain) 450 + { 451 + struct tegra_powergate *pg = to_powergate(domain); 452 + struct tegra_pmc *pmc = pg->pmc; 453 + int err; 454 + 455 + err = tegra_powergate_power_up(pg, true); 456 + if (err) 457 + dev_err(pmc->dev, "failed to turn on PM domain %s: %d\n", 458 + pg->genpd.name, err); 459 + 460 + return err; 461 + } 462 + 463 + static int tegra_genpd_power_off(struct generic_pm_domain *domain) 464 + { 465 + struct tegra_powergate *pg = to_powergate(domain); 466 + struct tegra_pmc *pmc = pg->pmc; 467 + int err; 468 + 469 + err = tegra_powergate_power_down(pg); 470 + if (err) 471 + dev_err(pmc->dev, "failed to turn off PM domain %s: %d\n", 472 + pg->genpd.name, err); 473 + 474 + return err; 475 + } 476 + 477 + /** 478 + * tegra_powergate_power_on() - power on partition 479 + * @id: partition ID 480 + */ 481 + int tegra_powergate_power_on(unsigned int id) 482 + { 483 + if (!tegra_powergate_is_available(id)) 484 + return -EINVAL; 485 + 486 + return tegra_powergate_set(id, true); 487 + } 488 + 489 + /** 490 + * tegra_powergate_power_off() - power off partition 491 + * @id: partition ID 492 + */ 493 + int tegra_powergate_power_off(unsigned int id) 494 + { 495 + if (!tegra_powergate_is_available(id)) 496 + return -EINVAL; 497 + 498 + return tegra_powergate_set(id, false); 499 + } 500 + EXPORT_SYMBOL(tegra_powergate_power_off); 501 + 502 + /** 503 + * tegra_powergate_is_powered() - check if partition is powered 504 + * @id: partition ID 505 + */ 506 + int tegra_powergate_is_powered(unsigned int id) 507 + { 508 + int status; 509 + 510 + if (!tegra_powergate_is_valid(id)) 511 + return -EINVAL; 512 + 513 + mutex_lock(&pmc->powergates_lock); 514 + status = tegra_powergate_state(id); 515 + mutex_unlock(&pmc->powergates_lock); 516 + 517 + return status; 518 + } 519 + 520 + /** 521 + * tegra_powergate_remove_clamping() - remove power clamps for partition 522 + * @id: partition ID 523 + */ 524 + int tegra_powergate_remove_clamping(unsigned int id) 525 + { 526 + if (!tegra_powergate_is_available(id)) 527 + return -EINVAL; 528 + 529 + return __tegra_powergate_remove_clamping(id); 530 + } 302 531 EXPORT_SYMBOL(tegra_powergate_remove_clamping); 303 532 304 533 /** ··· 537 316 int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, 538 317 struct reset_control *rst) 539 318 { 540 - int ret; 319 + struct tegra_powergate pg; 320 + int err; 541 321 542 - reset_control_assert(rst); 322 + pg.id = id; 323 + pg.clks = &clk; 324 + pg.num_clks = 1; 325 + pg.resets = &rst; 326 + pg.num_resets = 1; 543 327 544 - ret = tegra_powergate_power_on(id); 545 - if (ret) 546 - goto err_power; 328 + err = tegra_powergate_power_up(&pg, false); 329 + if (err) 330 + pr_err("failed to turn on partition %d: %d\n", id, err); 547 331 548 - ret = clk_prepare_enable(clk); 549 - if (ret) 550 - goto err_clk; 551 - 552 - usleep_range(10, 20); 553 - 554 - ret = tegra_powergate_remove_clamping(id); 555 - if (ret) 556 - goto err_clamp; 557 - 558 - usleep_range(10, 20); 559 - reset_control_deassert(rst); 560 - 561 - return 0; 562 - 563 - err_clamp: 564 - clk_disable_unprepare(clk); 565 - err_clk: 566 - tegra_powergate_power_off(id); 567 - err_power: 568 - return ret; 332 + return err; 569 333 } 570 334 EXPORT_SYMBOL(tegra_powergate_sequence_power_up); 571 335 ··· 690 484 return -ENOMEM; 691 485 692 486 return 0; 487 + } 488 + 489 + static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, 490 + struct device_node *np) 491 + { 492 + struct clk *clk; 493 + unsigned int i, count; 494 + int err; 495 + 496 + count = of_count_phandle_with_args(np, "clocks", "#clock-cells"); 497 + if (count == 0) 498 + return -ENODEV; 499 + 500 + pg->clks = kcalloc(count, sizeof(clk), GFP_KERNEL); 501 + if (!pg->clks) 502 + return -ENOMEM; 503 + 504 + for (i = 0; i < count; i++) { 505 + pg->clks[i] = of_clk_get(np, i); 506 + if (IS_ERR(pg->clks[i])) { 507 + err = PTR_ERR(pg->clks[i]); 508 + goto err; 509 + } 510 + } 511 + 512 + pg->num_clks = count; 513 + 514 + return 0; 515 + 516 + err: 517 + while (i--) 518 + clk_put(pg->clks[i]); 519 + kfree(pg->clks); 520 + 521 + return err; 522 + } 523 + 524 + static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, 525 + struct device_node *np) 526 + { 527 + struct reset_control *rst; 528 + unsigned int i, count; 529 + int err; 530 + 531 + count = of_count_phandle_with_args(np, "resets", "#reset-cells"); 532 + if (count == 0) 533 + return -ENODEV; 534 + 535 + pg->resets = kcalloc(count, sizeof(rst), GFP_KERNEL); 536 + if (!pg->resets) 537 + return -ENOMEM; 538 + 539 + for (i = 0; i < count; i++) { 540 + pg->resets[i] = of_reset_control_get_by_index(np, i); 541 + if (IS_ERR(pg->resets[i])) { 542 + err = PTR_ERR(pg->resets[i]); 543 + goto error; 544 + } 545 + } 546 + 547 + pg->num_resets = count; 548 + 549 + return 0; 550 + 551 + error: 552 + while (i--) 553 + reset_control_put(pg->resets[i]); 554 + kfree(pg->resets); 555 + 556 + return err; 557 + } 558 + 559 + static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) 560 + { 561 + struct tegra_powergate *pg; 562 + bool off; 563 + int id; 564 + 565 + pg = kzalloc(sizeof(*pg), GFP_KERNEL); 566 + if (!pg) 567 + goto error; 568 + 569 + id = tegra_powergate_lookup(pmc, np->name); 570 + if (id < 0) 571 + goto free_mem; 572 + 573 + /* 574 + * Clear the bit for this powergate so it cannot be managed 575 + * directly via the legacy APIs for controlling powergates. 576 + */ 577 + clear_bit(id, pmc->powergates_available); 578 + 579 + pg->id = id; 580 + pg->genpd.name = np->name; 581 + pg->genpd.power_off = tegra_genpd_power_off; 582 + pg->genpd.power_on = tegra_genpd_power_on; 583 + pg->pmc = pmc; 584 + 585 + if (tegra_powergate_of_get_clks(pg, np)) 586 + goto set_available; 587 + 588 + if (tegra_powergate_of_get_resets(pg, np)) 589 + goto remove_clks; 590 + 591 + off = !tegra_powergate_is_powered(pg->id); 592 + 593 + pm_genpd_init(&pg->genpd, NULL, off); 594 + 595 + if (of_genpd_add_provider_simple(np, &pg->genpd)) 596 + goto remove_resets; 597 + 598 + dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); 599 + 600 + return; 601 + 602 + remove_resets: 603 + while (pg->num_resets--) 604 + reset_control_put(pg->resets[pg->num_resets]); 605 + kfree(pg->resets); 606 + 607 + remove_clks: 608 + while (pg->num_clks--) 609 + clk_put(pg->clks[pg->num_clks]); 610 + kfree(pg->clks); 611 + 612 + set_available: 613 + set_bit(id, pmc->powergates_available); 614 + 615 + free_mem: 616 + kfree(pg); 617 + 618 + error: 619 + dev_err(pmc->dev, "failed to create power domain for %s\n", np->name); 620 + } 621 + 622 + static void tegra_powergate_init(struct tegra_pmc *pmc) 623 + { 624 + struct device_node *np, *child; 625 + 626 + np = of_get_child_by_name(pmc->dev->of_node, "powergates"); 627 + if (!np) 628 + return; 629 + 630 + for_each_child_of_node(np, child) { 631 + tegra_powergate_add(pmc, child); 632 + of_node_put(child); 633 + } 634 + 635 + of_node_put(np); 693 636 } 694 637 695 638 static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, ··· 1242 887 return err; 1243 888 } 1244 889 890 + tegra_powergate_init(pmc); 891 + 1245 892 mutex_lock(&pmc->powergates_lock); 1246 893 iounmap(pmc->base); 1247 894 pmc->base = base; ··· 1477 1120 const struct of_device_id *match; 1478 1121 struct device_node *np; 1479 1122 struct resource regs; 1123 + unsigned int i; 1480 1124 bool invert; 1481 1125 u32 value; 1482 1126 ··· 1526 1168 pr_err("failed to map PMC registers\n"); 1527 1169 return -ENXIO; 1528 1170 } 1171 + 1172 + /* Create a bit-map of the available and valid partitions */ 1173 + for (i = 0; i < pmc->soc->num_powergates; i++) 1174 + if (pmc->soc->powergates[i]) 1175 + set_bit(i, pmc->powergates_available); 1529 1176 1530 1177 mutex_init(&pmc->powergates_lock); 1531 1178
+1
include/soc/tegra/pmc.h
··· 72 72 #define TEGRA_POWERGATE_AUD 27 73 73 #define TEGRA_POWERGATE_DFD 28 74 74 #define TEGRA_POWERGATE_VE2 29 75 + #define TEGRA_POWERGATE_MAX TEGRA_POWERGATE_VE2 75 76 76 77 #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D 77 78