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