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