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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10 814 lines 20 kB view raw
1/* 2 * Rockchip Generic power domain support. 3 * 4 * Copyright (c) 2015 ROCKCHIP, Co. Ltd. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11#include <linux/io.h> 12#include <linux/iopoll.h> 13#include <linux/err.h> 14#include <linux/pm_clock.h> 15#include <linux/pm_domain.h> 16#include <linux/of_address.h> 17#include <linux/of_platform.h> 18#include <linux/clk.h> 19#include <linux/regmap.h> 20#include <linux/mfd/syscon.h> 21#include <dt-bindings/power/rk3288-power.h> 22#include <dt-bindings/power/rk3368-power.h> 23#include <dt-bindings/power/rk3399-power.h> 24 25struct rockchip_domain_info { 26 int pwr_mask; 27 int status_mask; 28 int req_mask; 29 int idle_mask; 30 int ack_mask; 31 bool active_wakeup; 32}; 33 34struct rockchip_pmu_info { 35 u32 pwr_offset; 36 u32 status_offset; 37 u32 req_offset; 38 u32 idle_offset; 39 u32 ack_offset; 40 41 u32 core_pwrcnt_offset; 42 u32 gpu_pwrcnt_offset; 43 44 unsigned int core_power_transition_time; 45 unsigned int gpu_power_transition_time; 46 47 int num_domains; 48 const struct rockchip_domain_info *domain_info; 49}; 50 51#define MAX_QOS_REGS_NUM 5 52#define QOS_PRIORITY 0x08 53#define QOS_MODE 0x0c 54#define QOS_BANDWIDTH 0x10 55#define QOS_SATURATION 0x14 56#define QOS_EXTCONTROL 0x18 57 58struct rockchip_pm_domain { 59 struct generic_pm_domain genpd; 60 const struct rockchip_domain_info *info; 61 struct rockchip_pmu *pmu; 62 int num_qos; 63 struct regmap **qos_regmap; 64 u32 *qos_save_regs[MAX_QOS_REGS_NUM]; 65 int num_clks; 66 struct clk *clks[]; 67}; 68 69struct rockchip_pmu { 70 struct device *dev; 71 struct regmap *regmap; 72 const struct rockchip_pmu_info *info; 73 struct mutex mutex; /* mutex lock for pmu */ 74 struct genpd_onecell_data genpd_data; 75 struct generic_pm_domain *domains[]; 76}; 77 78#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd) 79 80#define DOMAIN(pwr, status, req, idle, ack, wakeup) \ 81{ \ 82 .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \ 83 .status_mask = (status >= 0) ? BIT(status) : 0, \ 84 .req_mask = (req >= 0) ? BIT(req) : 0, \ 85 .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ 86 .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ 87 .active_wakeup = wakeup, \ 88} 89 90#define DOMAIN_RK3288(pwr, status, req, wakeup) \ 91 DOMAIN(pwr, status, req, req, (req) + 16, wakeup) 92 93#define DOMAIN_RK3368(pwr, status, req, wakeup) \ 94 DOMAIN(pwr, status, req, (req) + 16, req, wakeup) 95 96#define DOMAIN_RK3399(pwr, status, req, wakeup) \ 97 DOMAIN(pwr, status, req, req, req, wakeup) 98 99static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) 100{ 101 struct rockchip_pmu *pmu = pd->pmu; 102 const struct rockchip_domain_info *pd_info = pd->info; 103 unsigned int val; 104 105 regmap_read(pmu->regmap, pmu->info->idle_offset, &val); 106 return (val & pd_info->idle_mask) == pd_info->idle_mask; 107} 108 109static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu) 110{ 111 unsigned int val; 112 113 regmap_read(pmu->regmap, pmu->info->ack_offset, &val); 114 return val; 115} 116 117static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, 118 bool idle) 119{ 120 const struct rockchip_domain_info *pd_info = pd->info; 121 struct generic_pm_domain *genpd = &pd->genpd; 122 struct rockchip_pmu *pmu = pd->pmu; 123 unsigned int target_ack; 124 unsigned int val; 125 bool is_idle; 126 int ret; 127 128 if (pd_info->req_mask == 0) 129 return 0; 130 131 regmap_update_bits(pmu->regmap, pmu->info->req_offset, 132 pd_info->req_mask, idle ? -1U : 0); 133 134 dsb(sy); 135 136 /* Wait util idle_ack = 1 */ 137 target_ack = idle ? pd_info->ack_mask : 0; 138 ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val, 139 (val & pd_info->ack_mask) == target_ack, 140 0, 10000); 141 if (ret) { 142 dev_err(pmu->dev, 143 "failed to get ack on domain '%s', val=0x%x\n", 144 genpd->name, val); 145 return ret; 146 } 147 148 ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd, 149 is_idle, is_idle == idle, 0, 10000); 150 if (ret) { 151 dev_err(pmu->dev, 152 "failed to set idle on domain '%s', val=%d\n", 153 genpd->name, is_idle); 154 return ret; 155 } 156 157 return 0; 158} 159 160static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) 161{ 162 int i; 163 164 for (i = 0; i < pd->num_qos; i++) { 165 regmap_read(pd->qos_regmap[i], 166 QOS_PRIORITY, 167 &pd->qos_save_regs[0][i]); 168 regmap_read(pd->qos_regmap[i], 169 QOS_MODE, 170 &pd->qos_save_regs[1][i]); 171 regmap_read(pd->qos_regmap[i], 172 QOS_BANDWIDTH, 173 &pd->qos_save_regs[2][i]); 174 regmap_read(pd->qos_regmap[i], 175 QOS_SATURATION, 176 &pd->qos_save_regs[3][i]); 177 regmap_read(pd->qos_regmap[i], 178 QOS_EXTCONTROL, 179 &pd->qos_save_regs[4][i]); 180 } 181 return 0; 182} 183 184static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) 185{ 186 int i; 187 188 for (i = 0; i < pd->num_qos; i++) { 189 regmap_write(pd->qos_regmap[i], 190 QOS_PRIORITY, 191 pd->qos_save_regs[0][i]); 192 regmap_write(pd->qos_regmap[i], 193 QOS_MODE, 194 pd->qos_save_regs[1][i]); 195 regmap_write(pd->qos_regmap[i], 196 QOS_BANDWIDTH, 197 pd->qos_save_regs[2][i]); 198 regmap_write(pd->qos_regmap[i], 199 QOS_SATURATION, 200 pd->qos_save_regs[3][i]); 201 regmap_write(pd->qos_regmap[i], 202 QOS_EXTCONTROL, 203 pd->qos_save_regs[4][i]); 204 } 205 206 return 0; 207} 208 209static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) 210{ 211 struct rockchip_pmu *pmu = pd->pmu; 212 unsigned int val; 213 214 /* check idle status for idle-only domains */ 215 if (pd->info->status_mask == 0) 216 return !rockchip_pmu_domain_is_idle(pd); 217 218 regmap_read(pmu->regmap, pmu->info->status_offset, &val); 219 220 /* 1'b0: power on, 1'b1: power off */ 221 return !(val & pd->info->status_mask); 222} 223 224static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, 225 bool on) 226{ 227 struct rockchip_pmu *pmu = pd->pmu; 228 struct generic_pm_domain *genpd = &pd->genpd; 229 bool is_on; 230 231 if (pd->info->pwr_mask == 0) 232 return; 233 234 regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, 235 pd->info->pwr_mask, on ? 0 : -1U); 236 237 dsb(sy); 238 239 if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, 240 is_on == on, 0, 10000)) { 241 dev_err(pmu->dev, 242 "failed to set domain '%s', val=%d\n", 243 genpd->name, is_on); 244 return; 245 } 246} 247 248static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) 249{ 250 int i; 251 252 mutex_lock(&pd->pmu->mutex); 253 254 if (rockchip_pmu_domain_is_on(pd) != power_on) { 255 for (i = 0; i < pd->num_clks; i++) 256 clk_enable(pd->clks[i]); 257 258 if (!power_on) { 259 rockchip_pmu_save_qos(pd); 260 261 /* if powering down, idle request to NIU first */ 262 rockchip_pmu_set_idle_request(pd, true); 263 } 264 265 rockchip_do_pmu_set_power_domain(pd, power_on); 266 267 if (power_on) { 268 /* if powering up, leave idle mode */ 269 rockchip_pmu_set_idle_request(pd, false); 270 271 rockchip_pmu_restore_qos(pd); 272 } 273 274 for (i = pd->num_clks - 1; i >= 0; i--) 275 clk_disable(pd->clks[i]); 276 } 277 278 mutex_unlock(&pd->pmu->mutex); 279 return 0; 280} 281 282static int rockchip_pd_power_on(struct generic_pm_domain *domain) 283{ 284 struct rockchip_pm_domain *pd = to_rockchip_pd(domain); 285 286 return rockchip_pd_power(pd, true); 287} 288 289static int rockchip_pd_power_off(struct generic_pm_domain *domain) 290{ 291 struct rockchip_pm_domain *pd = to_rockchip_pd(domain); 292 293 return rockchip_pd_power(pd, false); 294} 295 296static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd, 297 struct device *dev) 298{ 299 struct clk *clk; 300 int i; 301 int error; 302 303 dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name); 304 305 error = pm_clk_create(dev); 306 if (error) { 307 dev_err(dev, "pm_clk_create failed %d\n", error); 308 return error; 309 } 310 311 i = 0; 312 while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) { 313 dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk); 314 error = pm_clk_add_clk(dev, clk); 315 if (error) { 316 dev_err(dev, "pm_clk_add_clk failed %d\n", error); 317 clk_put(clk); 318 pm_clk_destroy(dev); 319 return error; 320 } 321 } 322 323 return 0; 324} 325 326static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd, 327 struct device *dev) 328{ 329 dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name); 330 331 pm_clk_destroy(dev); 332} 333 334static bool rockchip_active_wakeup(struct device *dev) 335{ 336 struct generic_pm_domain *genpd; 337 struct rockchip_pm_domain *pd; 338 339 genpd = pd_to_genpd(dev->pm_domain); 340 pd = container_of(genpd, struct rockchip_pm_domain, genpd); 341 342 return pd->info->active_wakeup; 343} 344 345static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, 346 struct device_node *node) 347{ 348 const struct rockchip_domain_info *pd_info; 349 struct rockchip_pm_domain *pd; 350 struct device_node *qos_node; 351 struct clk *clk; 352 int clk_cnt; 353 int i, j; 354 u32 id; 355 int error; 356 357 error = of_property_read_u32(node, "reg", &id); 358 if (error) { 359 dev_err(pmu->dev, 360 "%s: failed to retrieve domain id (reg): %d\n", 361 node->name, error); 362 return -EINVAL; 363 } 364 365 if (id >= pmu->info->num_domains) { 366 dev_err(pmu->dev, "%s: invalid domain id %d\n", 367 node->name, id); 368 return -EINVAL; 369 } 370 371 pd_info = &pmu->info->domain_info[id]; 372 if (!pd_info) { 373 dev_err(pmu->dev, "%s: undefined domain id %d\n", 374 node->name, id); 375 return -EINVAL; 376 } 377 378 clk_cnt = of_count_phandle_with_args(node, "clocks", "#clock-cells"); 379 pd = devm_kzalloc(pmu->dev, 380 sizeof(*pd) + clk_cnt * sizeof(pd->clks[0]), 381 GFP_KERNEL); 382 if (!pd) 383 return -ENOMEM; 384 385 pd->info = pd_info; 386 pd->pmu = pmu; 387 388 for (i = 0; i < clk_cnt; i++) { 389 clk = of_clk_get(node, i); 390 if (IS_ERR(clk)) { 391 error = PTR_ERR(clk); 392 dev_err(pmu->dev, 393 "%s: failed to get clk at index %d: %d\n", 394 node->name, i, error); 395 goto err_out; 396 } 397 398 error = clk_prepare(clk); 399 if (error) { 400 dev_err(pmu->dev, 401 "%s: failed to prepare clk %pC (index %d): %d\n", 402 node->name, clk, i, error); 403 clk_put(clk); 404 goto err_out; 405 } 406 407 pd->clks[pd->num_clks++] = clk; 408 409 dev_dbg(pmu->dev, "added clock '%pC' to domain '%s'\n", 410 clk, node->name); 411 } 412 413 pd->num_qos = of_count_phandle_with_args(node, "pm_qos", 414 NULL); 415 416 if (pd->num_qos > 0) { 417 pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos, 418 sizeof(*pd->qos_regmap), 419 GFP_KERNEL); 420 if (!pd->qos_regmap) { 421 error = -ENOMEM; 422 goto err_out; 423 } 424 425 for (j = 0; j < MAX_QOS_REGS_NUM; j++) { 426 pd->qos_save_regs[j] = devm_kcalloc(pmu->dev, 427 pd->num_qos, 428 sizeof(u32), 429 GFP_KERNEL); 430 if (!pd->qos_save_regs[j]) { 431 error = -ENOMEM; 432 goto err_out; 433 } 434 } 435 436 for (j = 0; j < pd->num_qos; j++) { 437 qos_node = of_parse_phandle(node, "pm_qos", j); 438 if (!qos_node) { 439 error = -ENODEV; 440 goto err_out; 441 } 442 pd->qos_regmap[j] = syscon_node_to_regmap(qos_node); 443 if (IS_ERR(pd->qos_regmap[j])) { 444 error = -ENODEV; 445 of_node_put(qos_node); 446 goto err_out; 447 } 448 of_node_put(qos_node); 449 } 450 } 451 452 error = rockchip_pd_power(pd, true); 453 if (error) { 454 dev_err(pmu->dev, 455 "failed to power on domain '%s': %d\n", 456 node->name, error); 457 goto err_out; 458 } 459 460 pd->genpd.name = node->name; 461 pd->genpd.power_off = rockchip_pd_power_off; 462 pd->genpd.power_on = rockchip_pd_power_on; 463 pd->genpd.attach_dev = rockchip_pd_attach_dev; 464 pd->genpd.detach_dev = rockchip_pd_detach_dev; 465 pd->genpd.dev_ops.active_wakeup = rockchip_active_wakeup; 466 pd->genpd.flags = GENPD_FLAG_PM_CLK; 467 pm_genpd_init(&pd->genpd, NULL, false); 468 469 pmu->genpd_data.domains[id] = &pd->genpd; 470 return 0; 471 472err_out: 473 while (--i >= 0) { 474 clk_unprepare(pd->clks[i]); 475 clk_put(pd->clks[i]); 476 } 477 return error; 478} 479 480static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd) 481{ 482 int i, ret; 483 484 /* 485 * We're in the error cleanup already, so we only complain, 486 * but won't emit another error on top of the original one. 487 */ 488 ret = pm_genpd_remove(&pd->genpd); 489 if (ret < 0) 490 dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n", 491 pd->genpd.name, ret); 492 493 for (i = 0; i < pd->num_clks; i++) { 494 clk_unprepare(pd->clks[i]); 495 clk_put(pd->clks[i]); 496 } 497 498 /* protect the zeroing of pm->num_clks */ 499 mutex_lock(&pd->pmu->mutex); 500 pd->num_clks = 0; 501 mutex_unlock(&pd->pmu->mutex); 502 503 /* devm will free our memory */ 504} 505 506static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu) 507{ 508 struct generic_pm_domain *genpd; 509 struct rockchip_pm_domain *pd; 510 int i; 511 512 for (i = 0; i < pmu->genpd_data.num_domains; i++) { 513 genpd = pmu->genpd_data.domains[i]; 514 if (genpd) { 515 pd = to_rockchip_pd(genpd); 516 rockchip_pm_remove_one_domain(pd); 517 } 518 } 519 520 /* devm will free our memory */ 521} 522 523static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu, 524 u32 domain_reg_offset, 525 unsigned int count) 526{ 527 /* First configure domain power down transition count ... */ 528 regmap_write(pmu->regmap, domain_reg_offset, count); 529 /* ... and then power up count. */ 530 regmap_write(pmu->regmap, domain_reg_offset + 4, count); 531} 532 533static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, 534 struct device_node *parent) 535{ 536 struct device_node *np; 537 struct generic_pm_domain *child_domain, *parent_domain; 538 int error; 539 540 for_each_child_of_node(parent, np) { 541 u32 idx; 542 543 error = of_property_read_u32(parent, "reg", &idx); 544 if (error) { 545 dev_err(pmu->dev, 546 "%s: failed to retrieve domain id (reg): %d\n", 547 parent->name, error); 548 goto err_out; 549 } 550 parent_domain = pmu->genpd_data.domains[idx]; 551 552 error = rockchip_pm_add_one_domain(pmu, np); 553 if (error) { 554 dev_err(pmu->dev, "failed to handle node %s: %d\n", 555 np->name, error); 556 goto err_out; 557 } 558 559 error = of_property_read_u32(np, "reg", &idx); 560 if (error) { 561 dev_err(pmu->dev, 562 "%s: failed to retrieve domain id (reg): %d\n", 563 np->name, error); 564 goto err_out; 565 } 566 child_domain = pmu->genpd_data.domains[idx]; 567 568 error = pm_genpd_add_subdomain(parent_domain, child_domain); 569 if (error) { 570 dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n", 571 parent_domain->name, child_domain->name, error); 572 goto err_out; 573 } else { 574 dev_dbg(pmu->dev, "%s add subdomain: %s\n", 575 parent_domain->name, child_domain->name); 576 } 577 578 rockchip_pm_add_subdomain(pmu, np); 579 } 580 581 return 0; 582 583err_out: 584 of_node_put(np); 585 return error; 586} 587 588static int rockchip_pm_domain_probe(struct platform_device *pdev) 589{ 590 struct device *dev = &pdev->dev; 591 struct device_node *np = dev->of_node; 592 struct device_node *node; 593 struct device *parent; 594 struct rockchip_pmu *pmu; 595 const struct of_device_id *match; 596 const struct rockchip_pmu_info *pmu_info; 597 int error; 598 599 if (!np) { 600 dev_err(dev, "device tree node not found\n"); 601 return -ENODEV; 602 } 603 604 match = of_match_device(dev->driver->of_match_table, dev); 605 if (!match || !match->data) { 606 dev_err(dev, "missing pmu data\n"); 607 return -EINVAL; 608 } 609 610 pmu_info = match->data; 611 612 pmu = devm_kzalloc(dev, 613 sizeof(*pmu) + 614 pmu_info->num_domains * sizeof(pmu->domains[0]), 615 GFP_KERNEL); 616 if (!pmu) 617 return -ENOMEM; 618 619 pmu->dev = &pdev->dev; 620 mutex_init(&pmu->mutex); 621 622 pmu->info = pmu_info; 623 624 pmu->genpd_data.domains = pmu->domains; 625 pmu->genpd_data.num_domains = pmu_info->num_domains; 626 627 parent = dev->parent; 628 if (!parent) { 629 dev_err(dev, "no parent for syscon devices\n"); 630 return -ENODEV; 631 } 632 633 pmu->regmap = syscon_node_to_regmap(parent->of_node); 634 if (IS_ERR(pmu->regmap)) { 635 dev_err(dev, "no regmap available\n"); 636 return PTR_ERR(pmu->regmap); 637 } 638 639 /* 640 * Configure power up and down transition delays for CORE 641 * and GPU domains. 642 */ 643 if (pmu_info->core_power_transition_time) 644 rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset, 645 pmu_info->core_power_transition_time); 646 if (pmu_info->gpu_pwrcnt_offset) 647 rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset, 648 pmu_info->gpu_power_transition_time); 649 650 error = -ENODEV; 651 652 for_each_available_child_of_node(np, node) { 653 error = rockchip_pm_add_one_domain(pmu, node); 654 if (error) { 655 dev_err(dev, "failed to handle node %s: %d\n", 656 node->name, error); 657 of_node_put(node); 658 goto err_out; 659 } 660 661 error = rockchip_pm_add_subdomain(pmu, node); 662 if (error < 0) { 663 dev_err(dev, "failed to handle subdomain node %s: %d\n", 664 node->name, error); 665 of_node_put(node); 666 goto err_out; 667 } 668 } 669 670 if (error) { 671 dev_dbg(dev, "no power domains defined\n"); 672 goto err_out; 673 } 674 675 error = of_genpd_add_provider_onecell(np, &pmu->genpd_data); 676 if (error) { 677 dev_err(dev, "failed to add provider: %d\n", error); 678 goto err_out; 679 } 680 681 return 0; 682 683err_out: 684 rockchip_pm_domain_cleanup(pmu); 685 return error; 686} 687 688static const struct rockchip_domain_info rk3288_pm_domains[] = { 689 [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4, false), 690 [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9, false), 691 [RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3, false), 692 [RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2, false), 693}; 694 695static const struct rockchip_domain_info rk3368_pm_domains[] = { 696 [RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6, true), 697 [RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8, false), 698 [RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7, false), 699 [RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2, false), 700 [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2, false), 701}; 702 703static const struct rockchip_domain_info rk3399_pm_domains[] = { 704 [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1, false), 705 [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1, false), 706 [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1, true), 707 [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15, true), 708 [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16, true), 709 [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1, true), 710 [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2, true), 711 [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14, true), 712 [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17, false), 713 [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0, false), 714 [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3, false), 715 [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4, false), 716 [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5, false), 717 [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6, false), 718 [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1, false), 719 [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7, false), 720 [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8, false), 721 [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9, false), 722 [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10, false), 723 [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11, false), 724 [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23, true), 725 [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24, true), 726 [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12, true), 727 [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22, false), 728 [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27, true), 729 [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28, true), 730 [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29, true), 731}; 732 733static const struct rockchip_pmu_info rk3288_pmu = { 734 .pwr_offset = 0x08, 735 .status_offset = 0x0c, 736 .req_offset = 0x10, 737 .idle_offset = 0x14, 738 .ack_offset = 0x14, 739 740 .core_pwrcnt_offset = 0x34, 741 .gpu_pwrcnt_offset = 0x3c, 742 743 .core_power_transition_time = 24, /* 1us */ 744 .gpu_power_transition_time = 24, /* 1us */ 745 746 .num_domains = ARRAY_SIZE(rk3288_pm_domains), 747 .domain_info = rk3288_pm_domains, 748}; 749 750static const struct rockchip_pmu_info rk3368_pmu = { 751 .pwr_offset = 0x0c, 752 .status_offset = 0x10, 753 .req_offset = 0x3c, 754 .idle_offset = 0x40, 755 .ack_offset = 0x40, 756 757 .core_pwrcnt_offset = 0x48, 758 .gpu_pwrcnt_offset = 0x50, 759 760 .core_power_transition_time = 24, 761 .gpu_power_transition_time = 24, 762 763 .num_domains = ARRAY_SIZE(rk3368_pm_domains), 764 .domain_info = rk3368_pm_domains, 765}; 766 767static const struct rockchip_pmu_info rk3399_pmu = { 768 .pwr_offset = 0x14, 769 .status_offset = 0x18, 770 .req_offset = 0x60, 771 .idle_offset = 0x64, 772 .ack_offset = 0x68, 773 774 /* ARM Trusted Firmware manages power transition times */ 775 776 .num_domains = ARRAY_SIZE(rk3399_pm_domains), 777 .domain_info = rk3399_pm_domains, 778}; 779 780static const struct of_device_id rockchip_pm_domain_dt_match[] = { 781 { 782 .compatible = "rockchip,rk3288-power-controller", 783 .data = (void *)&rk3288_pmu, 784 }, 785 { 786 .compatible = "rockchip,rk3368-power-controller", 787 .data = (void *)&rk3368_pmu, 788 }, 789 { 790 .compatible = "rockchip,rk3399-power-controller", 791 .data = (void *)&rk3399_pmu, 792 }, 793 { /* sentinel */ }, 794}; 795 796static struct platform_driver rockchip_pm_domain_driver = { 797 .probe = rockchip_pm_domain_probe, 798 .driver = { 799 .name = "rockchip-pm-domain", 800 .of_match_table = rockchip_pm_domain_dt_match, 801 /* 802 * We can't forcibly eject devices form power domain, 803 * so we can't really remove power domains once they 804 * were added. 805 */ 806 .suppress_bind_attrs = true, 807 }, 808}; 809 810static int __init rockchip_pm_domain_drv_register(void) 811{ 812 return platform_driver_register(&rockchip_pm_domain_driver); 813} 814postcore_initcall(rockchip_pm_domain_drv_register);