mtk-pm-domains.c (16852B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2020 Collabora Ltd. 4 */ 5#include <linux/clk.h> 6#include <linux/clk-provider.h> 7#include <linux/init.h> 8#include <linux/io.h> 9#include <linux/iopoll.h> 10#include <linux/mfd/syscon.h> 11#include <linux/of_clk.h> 12#include <linux/of_device.h> 13#include <linux/platform_device.h> 14#include <linux/pm_domain.h> 15#include <linux/regmap.h> 16#include <linux/regulator/consumer.h> 17#include <linux/soc/mediatek/infracfg.h> 18 19#include "mt8167-pm-domains.h" 20#include "mt8173-pm-domains.h" 21#include "mt8183-pm-domains.h" 22#include "mt8186-pm-domains.h" 23#include "mt8192-pm-domains.h" 24#include "mt8195-pm-domains.h" 25 26#define MTK_POLL_DELAY_US 10 27#define MTK_POLL_TIMEOUT USEC_PER_SEC 28 29#define PWR_RST_B_BIT BIT(0) 30#define PWR_ISO_BIT BIT(1) 31#define PWR_ON_BIT BIT(2) 32#define PWR_ON_2ND_BIT BIT(3) 33#define PWR_CLK_DIS_BIT BIT(4) 34#define PWR_SRAM_CLKISO_BIT BIT(5) 35#define PWR_SRAM_ISOINT_B_BIT BIT(6) 36 37struct scpsys_domain { 38 struct generic_pm_domain genpd; 39 const struct scpsys_domain_data *data; 40 struct scpsys *scpsys; 41 int num_clks; 42 struct clk_bulk_data *clks; 43 int num_subsys_clks; 44 struct clk_bulk_data *subsys_clks; 45 struct regmap *infracfg; 46 struct regmap *smi; 47 struct regulator *supply; 48}; 49 50struct scpsys { 51 struct device *dev; 52 struct regmap *base; 53 const struct scpsys_soc_data *soc_data; 54 struct genpd_onecell_data pd_data; 55 struct generic_pm_domain *domains[]; 56}; 57 58#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd) 59 60static bool scpsys_domain_is_on(struct scpsys_domain *pd) 61{ 62 struct scpsys *scpsys = pd->scpsys; 63 u32 status, status2; 64 65 regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status); 66 status &= pd->data->sta_mask; 67 68 regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2); 69 status2 &= pd->data->sta_mask; 70 71 /* A domain is on when both status bits are set. */ 72 return status && status2; 73} 74 75static int scpsys_sram_enable(struct scpsys_domain *pd) 76{ 77 u32 pdn_ack = pd->data->sram_pdn_ack_bits; 78 struct scpsys *scpsys = pd->scpsys; 79 unsigned int tmp; 80 int ret; 81 82 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); 83 84 /* Either wait until SRAM_PDN_ACK all 1 or 0 */ 85 ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, 86 (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); 87 if (ret < 0) 88 return ret; 89 90 if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) { 91 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT); 92 udelay(1); 93 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT); 94 } 95 96 return 0; 97} 98 99static int scpsys_sram_disable(struct scpsys_domain *pd) 100{ 101 u32 pdn_ack = pd->data->sram_pdn_ack_bits; 102 struct scpsys *scpsys = pd->scpsys; 103 unsigned int tmp; 104 105 if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) { 106 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT); 107 udelay(1); 108 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT); 109 } 110 111 regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); 112 113 /* Either wait until SRAM_PDN_ACK all 1 or 0 */ 114 return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, 115 (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US, 116 MTK_POLL_TIMEOUT); 117} 118 119static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, struct regmap *regmap) 120{ 121 int i, ret; 122 123 for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) { 124 u32 val, mask = bpd[i].bus_prot_mask; 125 126 if (!mask) 127 break; 128 129 if (bpd[i].bus_prot_reg_update) 130 regmap_set_bits(regmap, bpd[i].bus_prot_set, mask); 131 else 132 regmap_write(regmap, bpd[i].bus_prot_set, mask); 133 134 ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, 135 val, (val & mask) == mask, 136 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); 137 if (ret) 138 return ret; 139 } 140 141 return 0; 142} 143 144static int scpsys_bus_protect_enable(struct scpsys_domain *pd) 145{ 146 int ret; 147 148 ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg); 149 if (ret) 150 return ret; 151 152 return _scpsys_bus_protect_enable(pd->data->bp_smi, pd->smi); 153} 154 155static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, 156 struct regmap *regmap) 157{ 158 int i, ret; 159 160 for (i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) { 161 u32 val, mask = bpd[i].bus_prot_mask; 162 163 if (!mask) 164 continue; 165 166 if (bpd[i].bus_prot_reg_update) 167 regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask); 168 else 169 regmap_write(regmap, bpd[i].bus_prot_clr, mask); 170 171 if (bpd[i].ignore_clr_ack) 172 continue; 173 174 ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, 175 val, !(val & mask), 176 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); 177 if (ret) 178 return ret; 179 } 180 181 return 0; 182} 183 184static int scpsys_bus_protect_disable(struct scpsys_domain *pd) 185{ 186 int ret; 187 188 ret = _scpsys_bus_protect_disable(pd->data->bp_smi, pd->smi); 189 if (ret) 190 return ret; 191 192 return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg); 193} 194 195static int scpsys_regulator_enable(struct regulator *supply) 196{ 197 return supply ? regulator_enable(supply) : 0; 198} 199 200static int scpsys_regulator_disable(struct regulator *supply) 201{ 202 return supply ? regulator_disable(supply) : 0; 203} 204 205static int scpsys_power_on(struct generic_pm_domain *genpd) 206{ 207 struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); 208 struct scpsys *scpsys = pd->scpsys; 209 bool tmp; 210 int ret; 211 212 ret = scpsys_regulator_enable(pd->supply); 213 if (ret) 214 return ret; 215 216 ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks); 217 if (ret) 218 goto err_reg; 219 220 /* subsys power on */ 221 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); 222 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); 223 224 /* wait until PWR_ACK = 1 */ 225 ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US, 226 MTK_POLL_TIMEOUT); 227 if (ret < 0) 228 goto err_pwr_ack; 229 230 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); 231 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); 232 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); 233 234 ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); 235 if (ret) 236 goto err_pwr_ack; 237 238 ret = scpsys_sram_enable(pd); 239 if (ret < 0) 240 goto err_disable_subsys_clks; 241 242 ret = scpsys_bus_protect_disable(pd); 243 if (ret < 0) 244 goto err_disable_sram; 245 246 return 0; 247 248err_disable_sram: 249 scpsys_sram_disable(pd); 250err_disable_subsys_clks: 251 clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 252err_pwr_ack: 253 clk_bulk_disable_unprepare(pd->num_clks, pd->clks); 254err_reg: 255 scpsys_regulator_disable(pd->supply); 256 return ret; 257} 258 259static int scpsys_power_off(struct generic_pm_domain *genpd) 260{ 261 struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); 262 struct scpsys *scpsys = pd->scpsys; 263 bool tmp; 264 int ret; 265 266 ret = scpsys_bus_protect_enable(pd); 267 if (ret < 0) 268 return ret; 269 270 ret = scpsys_sram_disable(pd); 271 if (ret < 0) 272 return ret; 273 274 clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 275 276 /* subsys power off */ 277 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); 278 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); 279 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); 280 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); 281 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); 282 283 /* wait until PWR_ACK = 0 */ 284 ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, 285 MTK_POLL_TIMEOUT); 286 if (ret < 0) 287 return ret; 288 289 clk_bulk_disable_unprepare(pd->num_clks, pd->clks); 290 291 scpsys_regulator_disable(pd->supply); 292 293 return 0; 294} 295 296static struct 297generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node) 298{ 299 const struct scpsys_domain_data *domain_data; 300 struct scpsys_domain *pd; 301 struct device_node *root_node = scpsys->dev->of_node; 302 struct device_node *smi_node; 303 struct property *prop; 304 const char *clk_name; 305 int i, ret, num_clks; 306 struct clk *clk; 307 int clk_ind = 0; 308 u32 id; 309 310 ret = of_property_read_u32(node, "reg", &id); 311 if (ret) { 312 dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n", 313 node, ret); 314 return ERR_PTR(-EINVAL); 315 } 316 317 if (id >= scpsys->soc_data->num_domains) { 318 dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id); 319 return ERR_PTR(-EINVAL); 320 } 321 322 domain_data = &scpsys->soc_data->domains_data[id]; 323 if (domain_data->sta_mask == 0) { 324 dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id); 325 return ERR_PTR(-EINVAL); 326 } 327 328 pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL); 329 if (!pd) 330 return ERR_PTR(-ENOMEM); 331 332 pd->data = domain_data; 333 pd->scpsys = scpsys; 334 335 if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) { 336 /* 337 * Find regulator in current power domain node. 338 * devm_regulator_get() finds regulator in a node and its child 339 * node, so set of_node to current power domain node then change 340 * back to original node after regulator is found for current 341 * power domain node. 342 */ 343 scpsys->dev->of_node = node; 344 pd->supply = devm_regulator_get(scpsys->dev, "domain"); 345 scpsys->dev->of_node = root_node; 346 if (IS_ERR(pd->supply)) { 347 dev_err_probe(scpsys->dev, PTR_ERR(pd->supply), 348 "%pOF: failed to get power supply.\n", 349 node); 350 return ERR_CAST(pd->supply); 351 } 352 } 353 354 pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg"); 355 if (IS_ERR(pd->infracfg)) 356 return ERR_CAST(pd->infracfg); 357 358 smi_node = of_parse_phandle(node, "mediatek,smi", 0); 359 if (smi_node) { 360 pd->smi = device_node_to_regmap(smi_node); 361 of_node_put(smi_node); 362 if (IS_ERR(pd->smi)) 363 return ERR_CAST(pd->smi); 364 } 365 366 num_clks = of_clk_get_parent_count(node); 367 if (num_clks > 0) { 368 /* Calculate number of subsys_clks */ 369 of_property_for_each_string(node, "clock-names", prop, clk_name) { 370 char *subsys; 371 372 subsys = strchr(clk_name, '-'); 373 if (subsys) 374 pd->num_subsys_clks++; 375 else 376 pd->num_clks++; 377 } 378 379 pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); 380 if (!pd->clks) 381 return ERR_PTR(-ENOMEM); 382 383 pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks, 384 sizeof(*pd->subsys_clks), GFP_KERNEL); 385 if (!pd->subsys_clks) 386 return ERR_PTR(-ENOMEM); 387 388 } 389 390 for (i = 0; i < pd->num_clks; i++) { 391 clk = of_clk_get(node, i); 392 if (IS_ERR(clk)) { 393 ret = PTR_ERR(clk); 394 dev_err_probe(scpsys->dev, ret, 395 "%pOF: failed to get clk at index %d: %d\n", node, i, ret); 396 goto err_put_clocks; 397 } 398 399 pd->clks[clk_ind++].clk = clk; 400 } 401 402 for (i = 0; i < pd->num_subsys_clks; i++) { 403 clk = of_clk_get(node, i + clk_ind); 404 if (IS_ERR(clk)) { 405 ret = PTR_ERR(clk); 406 dev_err_probe(scpsys->dev, ret, 407 "%pOF: failed to get clk at index %d: %d\n", node, 408 i + clk_ind, ret); 409 goto err_put_subsys_clocks; 410 } 411 412 pd->subsys_clks[i].clk = clk; 413 } 414 415 /* 416 * Initially turn on all domains to make the domains usable 417 * with !CONFIG_PM and to get the hardware in sync with the 418 * software. The unused domains will be switched off during 419 * late_init time. 420 */ 421 if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) { 422 if (scpsys_domain_is_on(pd)) 423 dev_warn(scpsys->dev, 424 "%pOF: A default off power domain has been ON\n", node); 425 } else { 426 ret = scpsys_power_on(&pd->genpd); 427 if (ret < 0) { 428 dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); 429 goto err_put_subsys_clocks; 430 } 431 } 432 433 if (scpsys->domains[id]) { 434 ret = -EINVAL; 435 dev_err(scpsys->dev, 436 "power domain with id %d already exists, check your device-tree\n", id); 437 goto err_put_subsys_clocks; 438 } 439 440 if (!pd->data->name) 441 pd->genpd.name = node->name; 442 else 443 pd->genpd.name = pd->data->name; 444 445 pd->genpd.power_off = scpsys_power_off; 446 pd->genpd.power_on = scpsys_power_on; 447 448 if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP)) 449 pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; 450 451 if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) 452 pm_genpd_init(&pd->genpd, NULL, true); 453 else 454 pm_genpd_init(&pd->genpd, NULL, false); 455 456 scpsys->domains[id] = &pd->genpd; 457 458 return scpsys->pd_data.domains[id]; 459 460err_put_subsys_clocks: 461 clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); 462err_put_clocks: 463 clk_bulk_put(pd->num_clks, pd->clks); 464 return ERR_PTR(ret); 465} 466 467static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent) 468{ 469 struct generic_pm_domain *child_pd, *parent_pd; 470 struct device_node *child; 471 int ret; 472 473 for_each_child_of_node(parent, child) { 474 u32 id; 475 476 ret = of_property_read_u32(parent, "reg", &id); 477 if (ret) { 478 dev_err(scpsys->dev, "%pOF: failed to get parent domain id\n", child); 479 goto err_put_node; 480 } 481 482 if (!scpsys->pd_data.domains[id]) { 483 ret = -EINVAL; 484 dev_err(scpsys->dev, "power domain with id %d does not exist\n", id); 485 goto err_put_node; 486 } 487 488 parent_pd = scpsys->pd_data.domains[id]; 489 490 child_pd = scpsys_add_one_domain(scpsys, child); 491 if (IS_ERR(child_pd)) { 492 ret = PTR_ERR(child_pd); 493 dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n", 494 child); 495 goto err_put_node; 496 } 497 498 ret = pm_genpd_add_subdomain(parent_pd, child_pd); 499 if (ret) { 500 dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n", 501 child_pd->name, parent_pd->name); 502 goto err_put_node; 503 } else { 504 dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name, 505 child_pd->name); 506 } 507 508 /* recursive call to add all subdomains */ 509 ret = scpsys_add_subdomain(scpsys, child); 510 if (ret) 511 goto err_put_node; 512 } 513 514 return 0; 515 516err_put_node: 517 of_node_put(child); 518 return ret; 519} 520 521static void scpsys_remove_one_domain(struct scpsys_domain *pd) 522{ 523 int ret; 524 525 if (scpsys_domain_is_on(pd)) 526 scpsys_power_off(&pd->genpd); 527 528 /* 529 * We're in the error cleanup already, so we only complain, 530 * but won't emit another error on top of the original one. 531 */ 532 ret = pm_genpd_remove(&pd->genpd); 533 if (ret < 0) 534 dev_err(pd->scpsys->dev, 535 "failed to remove domain '%s' : %d - state may be inconsistent\n", 536 pd->genpd.name, ret); 537 538 clk_bulk_put(pd->num_clks, pd->clks); 539 clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); 540} 541 542static void scpsys_domain_cleanup(struct scpsys *scpsys) 543{ 544 struct generic_pm_domain *genpd; 545 struct scpsys_domain *pd; 546 int i; 547 548 for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) { 549 genpd = scpsys->pd_data.domains[i]; 550 if (genpd) { 551 pd = to_scpsys_domain(genpd); 552 scpsys_remove_one_domain(pd); 553 } 554 } 555} 556 557static const struct of_device_id scpsys_of_match[] = { 558 { 559 .compatible = "mediatek,mt8167-power-controller", 560 .data = &mt8167_scpsys_data, 561 }, 562 { 563 .compatible = "mediatek,mt8173-power-controller", 564 .data = &mt8173_scpsys_data, 565 }, 566 { 567 .compatible = "mediatek,mt8183-power-controller", 568 .data = &mt8183_scpsys_data, 569 }, 570 { 571 .compatible = "mediatek,mt8186-power-controller", 572 .data = &mt8186_scpsys_data, 573 }, 574 { 575 .compatible = "mediatek,mt8192-power-controller", 576 .data = &mt8192_scpsys_data, 577 }, 578 { 579 .compatible = "mediatek,mt8195-power-controller", 580 .data = &mt8195_scpsys_data, 581 }, 582 { } 583}; 584 585static int scpsys_probe(struct platform_device *pdev) 586{ 587 struct device *dev = &pdev->dev; 588 struct device_node *np = dev->of_node; 589 const struct scpsys_soc_data *soc; 590 struct device_node *node; 591 struct device *parent; 592 struct scpsys *scpsys; 593 int ret; 594 595 soc = of_device_get_match_data(&pdev->dev); 596 if (!soc) { 597 dev_err(&pdev->dev, "no power controller data\n"); 598 return -EINVAL; 599 } 600 601 scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL); 602 if (!scpsys) 603 return -ENOMEM; 604 605 scpsys->dev = dev; 606 scpsys->soc_data = soc; 607 608 scpsys->pd_data.domains = scpsys->domains; 609 scpsys->pd_data.num_domains = soc->num_domains; 610 611 parent = dev->parent; 612 if (!parent) { 613 dev_err(dev, "no parent for syscon devices\n"); 614 return -ENODEV; 615 } 616 617 scpsys->base = syscon_node_to_regmap(parent->of_node); 618 if (IS_ERR(scpsys->base)) { 619 dev_err(dev, "no regmap available\n"); 620 return PTR_ERR(scpsys->base); 621 } 622 623 ret = -ENODEV; 624 for_each_available_child_of_node(np, node) { 625 struct generic_pm_domain *domain; 626 627 domain = scpsys_add_one_domain(scpsys, node); 628 if (IS_ERR(domain)) { 629 ret = PTR_ERR(domain); 630 of_node_put(node); 631 goto err_cleanup_domains; 632 } 633 634 ret = scpsys_add_subdomain(scpsys, node); 635 if (ret) { 636 of_node_put(node); 637 goto err_cleanup_domains; 638 } 639 } 640 641 if (ret) { 642 dev_dbg(dev, "no power domains present\n"); 643 return ret; 644 } 645 646 ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data); 647 if (ret) { 648 dev_err(dev, "failed to add provider: %d\n", ret); 649 goto err_cleanup_domains; 650 } 651 652 return 0; 653 654err_cleanup_domains: 655 scpsys_domain_cleanup(scpsys); 656 return ret; 657} 658 659static struct platform_driver scpsys_pm_domain_driver = { 660 .probe = scpsys_probe, 661 .driver = { 662 .name = "mtk-power-controller", 663 .suppress_bind_attrs = true, 664 .of_match_table = scpsys_of_match, 665 }, 666}; 667builtin_platform_driver(scpsys_pm_domain_driver);