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