gpc.c (13429B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de> 4 * Copyright 2011-2013 Freescale Semiconductor, Inc. 5 */ 6 7#include <linux/clk.h> 8#include <linux/delay.h> 9#include <linux/io.h> 10#include <linux/of_device.h> 11#include <linux/platform_device.h> 12#include <linux/pm_domain.h> 13#include <linux/regmap.h> 14#include <linux/regulator/consumer.h> 15 16#define GPC_CNTR 0x000 17 18#define GPC_PGC_CTRL_OFFS 0x0 19#define GPC_PGC_PUPSCR_OFFS 0x4 20#define GPC_PGC_PDNSCR_OFFS 0x8 21#define GPC_PGC_SW2ISO_SHIFT 0x8 22#define GPC_PGC_SW_SHIFT 0x0 23 24#define GPC_PGC_PCI_PDN 0x200 25#define GPC_PGC_PCI_SR 0x20c 26 27#define GPC_PGC_GPU_PDN 0x260 28#define GPC_PGC_GPU_PUPSCR 0x264 29#define GPC_PGC_GPU_PDNSCR 0x268 30#define GPC_PGC_GPU_SR 0x26c 31 32#define GPC_PGC_DISP_PDN 0x240 33#define GPC_PGC_DISP_SR 0x24c 34 35#define GPU_VPU_PUP_REQ BIT(1) 36#define GPU_VPU_PDN_REQ BIT(0) 37 38#define GPC_CLK_MAX 7 39 40#define PGC_DOMAIN_FLAG_NO_PD BIT(0) 41 42struct imx_pm_domain { 43 struct generic_pm_domain base; 44 struct regmap *regmap; 45 struct regulator *supply; 46 struct clk *clk[GPC_CLK_MAX]; 47 int num_clks; 48 unsigned int reg_offs; 49 signed char cntr_pdn_bit; 50 unsigned int ipg_rate_mhz; 51}; 52 53static inline struct imx_pm_domain * 54to_imx_pm_domain(struct generic_pm_domain *genpd) 55{ 56 return container_of(genpd, struct imx_pm_domain, base); 57} 58 59static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) 60{ 61 struct imx_pm_domain *pd = to_imx_pm_domain(genpd); 62 int iso, iso2sw; 63 u32 val; 64 65 /* Read ISO and ISO2SW power down delays */ 66 regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val); 67 iso = val & 0x3f; 68 iso2sw = (val >> 8) & 0x3f; 69 70 /* Gate off domain when powered down */ 71 regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, 72 0x1, 0x1); 73 74 /* Request GPC to power down domain */ 75 val = BIT(pd->cntr_pdn_bit); 76 regmap_update_bits(pd->regmap, GPC_CNTR, val, val); 77 78 /* Wait ISO + ISO2SW IPG clock cycles */ 79 udelay(DIV_ROUND_UP(iso + iso2sw, pd->ipg_rate_mhz)); 80 81 if (pd->supply) 82 regulator_disable(pd->supply); 83 84 return 0; 85} 86 87static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) 88{ 89 struct imx_pm_domain *pd = to_imx_pm_domain(genpd); 90 int i, ret; 91 u32 val, req; 92 93 if (pd->supply) { 94 ret = regulator_enable(pd->supply); 95 if (ret) { 96 pr_err("%s: failed to enable regulator: %d\n", 97 __func__, ret); 98 return ret; 99 } 100 } 101 102 /* Enable reset clocks for all devices in the domain */ 103 for (i = 0; i < pd->num_clks; i++) 104 clk_prepare_enable(pd->clk[i]); 105 106 /* Gate off domain when powered down */ 107 regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, 108 0x1, 0x1); 109 110 /* Request GPC to power up domain */ 111 req = BIT(pd->cntr_pdn_bit + 1); 112 regmap_update_bits(pd->regmap, GPC_CNTR, req, req); 113 114 /* Wait for the PGC to handle the request */ 115 ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req), 116 1, 50); 117 if (ret) 118 pr_err("powerup request on domain %s timed out\n", genpd->name); 119 120 /* Wait for reset to propagate through peripherals */ 121 usleep_range(5, 10); 122 123 /* Disable reset clocks for all devices in the domain */ 124 for (i = 0; i < pd->num_clks; i++) 125 clk_disable_unprepare(pd->clk[i]); 126 127 return 0; 128} 129 130static int imx_pgc_get_clocks(struct device *dev, struct imx_pm_domain *domain) 131{ 132 int i, ret; 133 134 for (i = 0; ; i++) { 135 struct clk *clk = of_clk_get(dev->of_node, i); 136 if (IS_ERR(clk)) 137 break; 138 if (i >= GPC_CLK_MAX) { 139 dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX); 140 ret = -EINVAL; 141 goto clk_err; 142 } 143 domain->clk[i] = clk; 144 } 145 domain->num_clks = i; 146 147 return 0; 148 149clk_err: 150 while (i--) 151 clk_put(domain->clk[i]); 152 153 return ret; 154} 155 156static void imx_pgc_put_clocks(struct imx_pm_domain *domain) 157{ 158 int i; 159 160 for (i = domain->num_clks - 1; i >= 0; i--) 161 clk_put(domain->clk[i]); 162} 163 164static int imx_pgc_parse_dt(struct device *dev, struct imx_pm_domain *domain) 165{ 166 /* try to get the domain supply regulator */ 167 domain->supply = devm_regulator_get_optional(dev, "power"); 168 if (IS_ERR(domain->supply)) { 169 if (PTR_ERR(domain->supply) == -ENODEV) 170 domain->supply = NULL; 171 else 172 return PTR_ERR(domain->supply); 173 } 174 175 /* try to get all clocks needed for reset propagation */ 176 return imx_pgc_get_clocks(dev, domain); 177} 178 179static int imx_pgc_power_domain_probe(struct platform_device *pdev) 180{ 181 struct imx_pm_domain *domain = pdev->dev.platform_data; 182 struct device *dev = &pdev->dev; 183 int ret; 184 185 /* if this PD is associated with a DT node try to parse it */ 186 if (dev->of_node) { 187 ret = imx_pgc_parse_dt(dev, domain); 188 if (ret) 189 return ret; 190 } 191 192 /* initially power on the domain */ 193 if (domain->base.power_on) 194 domain->base.power_on(&domain->base); 195 196 if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { 197 pm_genpd_init(&domain->base, NULL, false); 198 ret = of_genpd_add_provider_simple(dev->of_node, &domain->base); 199 if (ret) 200 goto genpd_err; 201 } 202 203 device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE_CONSUMER); 204 205 return 0; 206 207genpd_err: 208 pm_genpd_remove(&domain->base); 209 imx_pgc_put_clocks(domain); 210 211 return ret; 212} 213 214static int imx_pgc_power_domain_remove(struct platform_device *pdev) 215{ 216 struct imx_pm_domain *domain = pdev->dev.platform_data; 217 218 if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { 219 of_genpd_del_provider(pdev->dev.of_node); 220 pm_genpd_remove(&domain->base); 221 imx_pgc_put_clocks(domain); 222 } 223 224 return 0; 225} 226 227static const struct platform_device_id imx_pgc_power_domain_id[] = { 228 { "imx-pgc-power-domain"}, 229 { }, 230}; 231 232static struct platform_driver imx_pgc_power_domain_driver = { 233 .driver = { 234 .name = "imx-pgc-pd", 235 }, 236 .probe = imx_pgc_power_domain_probe, 237 .remove = imx_pgc_power_domain_remove, 238 .id_table = imx_pgc_power_domain_id, 239}; 240builtin_platform_driver(imx_pgc_power_domain_driver) 241 242#define GPC_PGC_DOMAIN_ARM 0 243#define GPC_PGC_DOMAIN_PU 1 244#define GPC_PGC_DOMAIN_DISPLAY 2 245#define GPC_PGC_DOMAIN_PCI 3 246 247static struct genpd_power_state imx6_pm_domain_pu_state = { 248 .power_off_latency_ns = 25000, 249 .power_on_latency_ns = 2000000, 250}; 251 252static struct imx_pm_domain imx_gpc_domains[] = { 253 [GPC_PGC_DOMAIN_ARM] = { 254 .base = { 255 .name = "ARM", 256 .flags = GENPD_FLAG_ALWAYS_ON, 257 }, 258 }, 259 [GPC_PGC_DOMAIN_PU] = { 260 .base = { 261 .name = "PU", 262 .power_off = imx6_pm_domain_power_off, 263 .power_on = imx6_pm_domain_power_on, 264 .states = &imx6_pm_domain_pu_state, 265 .state_count = 1, 266 }, 267 .reg_offs = 0x260, 268 .cntr_pdn_bit = 0, 269 }, 270 [GPC_PGC_DOMAIN_DISPLAY] = { 271 .base = { 272 .name = "DISPLAY", 273 .power_off = imx6_pm_domain_power_off, 274 .power_on = imx6_pm_domain_power_on, 275 }, 276 .reg_offs = 0x240, 277 .cntr_pdn_bit = 4, 278 }, 279 [GPC_PGC_DOMAIN_PCI] = { 280 .base = { 281 .name = "PCI", 282 .power_off = imx6_pm_domain_power_off, 283 .power_on = imx6_pm_domain_power_on, 284 }, 285 .reg_offs = 0x200, 286 .cntr_pdn_bit = 6, 287 }, 288}; 289 290struct imx_gpc_dt_data { 291 int num_domains; 292 bool err009619_present; 293 bool err006287_present; 294}; 295 296static const struct imx_gpc_dt_data imx6q_dt_data = { 297 .num_domains = 2, 298 .err009619_present = false, 299 .err006287_present = false, 300}; 301 302static const struct imx_gpc_dt_data imx6qp_dt_data = { 303 .num_domains = 2, 304 .err009619_present = true, 305 .err006287_present = false, 306}; 307 308static const struct imx_gpc_dt_data imx6sl_dt_data = { 309 .num_domains = 3, 310 .err009619_present = false, 311 .err006287_present = true, 312}; 313 314static const struct imx_gpc_dt_data imx6sx_dt_data = { 315 .num_domains = 4, 316 .err009619_present = false, 317 .err006287_present = false, 318}; 319 320static const struct of_device_id imx_gpc_dt_ids[] = { 321 { .compatible = "fsl,imx6q-gpc", .data = &imx6q_dt_data }, 322 { .compatible = "fsl,imx6qp-gpc", .data = &imx6qp_dt_data }, 323 { .compatible = "fsl,imx6sl-gpc", .data = &imx6sl_dt_data }, 324 { .compatible = "fsl,imx6sx-gpc", .data = &imx6sx_dt_data }, 325 { } 326}; 327 328static const struct regmap_range yes_ranges[] = { 329 regmap_reg_range(GPC_CNTR, GPC_CNTR), 330 regmap_reg_range(GPC_PGC_PCI_PDN, GPC_PGC_PCI_SR), 331 regmap_reg_range(GPC_PGC_GPU_PDN, GPC_PGC_GPU_SR), 332 regmap_reg_range(GPC_PGC_DISP_PDN, GPC_PGC_DISP_SR), 333}; 334 335static const struct regmap_access_table access_table = { 336 .yes_ranges = yes_ranges, 337 .n_yes_ranges = ARRAY_SIZE(yes_ranges), 338}; 339 340static const struct regmap_config imx_gpc_regmap_config = { 341 .reg_bits = 32, 342 .val_bits = 32, 343 .reg_stride = 4, 344 .rd_table = &access_table, 345 .wr_table = &access_table, 346 .max_register = 0x2ac, 347 .fast_io = true, 348}; 349 350static struct generic_pm_domain *imx_gpc_onecell_domains[] = { 351 &imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base, 352 &imx_gpc_domains[GPC_PGC_DOMAIN_PU].base, 353}; 354 355static struct genpd_onecell_data imx_gpc_onecell_data = { 356 .domains = imx_gpc_onecell_domains, 357 .num_domains = 2, 358}; 359 360static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap, 361 unsigned int num_domains) 362{ 363 struct imx_pm_domain *domain; 364 int i, ret; 365 366 for (i = 0; i < num_domains; i++) { 367 domain = &imx_gpc_domains[i]; 368 domain->regmap = regmap; 369 domain->ipg_rate_mhz = 66; 370 371 if (i == 1) { 372 domain->supply = devm_regulator_get(dev, "pu"); 373 if (IS_ERR(domain->supply)) 374 return PTR_ERR(domain->supply); 375 376 ret = imx_pgc_get_clocks(dev, domain); 377 if (ret) 378 goto clk_err; 379 380 domain->base.power_on(&domain->base); 381 } 382 } 383 384 for (i = 0; i < num_domains; i++) 385 pm_genpd_init(&imx_gpc_domains[i].base, NULL, false); 386 387 if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { 388 ret = of_genpd_add_provider_onecell(dev->of_node, 389 &imx_gpc_onecell_data); 390 if (ret) 391 goto genpd_err; 392 } 393 394 return 0; 395 396genpd_err: 397 for (i = 0; i < num_domains; i++) 398 pm_genpd_remove(&imx_gpc_domains[i].base); 399 imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]); 400clk_err: 401 return ret; 402} 403 404static int imx_gpc_probe(struct platform_device *pdev) 405{ 406 const struct of_device_id *of_id = 407 of_match_device(imx_gpc_dt_ids, &pdev->dev); 408 const struct imx_gpc_dt_data *of_id_data = of_id->data; 409 struct device_node *pgc_node; 410 struct regmap *regmap; 411 void __iomem *base; 412 int ret; 413 414 pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); 415 416 /* bail out if DT too old and doesn't provide the necessary info */ 417 if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && 418 !pgc_node) 419 return 0; 420 421 base = devm_platform_ioremap_resource(pdev, 0); 422 if (IS_ERR(base)) 423 return PTR_ERR(base); 424 425 regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, 426 &imx_gpc_regmap_config); 427 if (IS_ERR(regmap)) { 428 ret = PTR_ERR(regmap); 429 dev_err(&pdev->dev, "failed to init regmap: %d\n", 430 ret); 431 return ret; 432 } 433 434 /* 435 * Disable PU power down by runtime PM if ERR009619 is present. 436 * 437 * The PRE clock will be paused for several cycles when turning on the 438 * PU domain LDO from power down state. If PRE is in use at that time, 439 * the IPU/PRG cannot get the correct display data from the PRE. 440 * 441 * This is not a concern when the whole system enters suspend state, so 442 * it's safe to power down PU in this case. 443 */ 444 if (of_id_data->err009619_present) 445 imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |= 446 GENPD_FLAG_RPM_ALWAYS_ON; 447 448 /* Keep DISP always on if ERR006287 is present */ 449 if (of_id_data->err006287_present) 450 imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |= 451 GENPD_FLAG_ALWAYS_ON; 452 453 if (!pgc_node) { 454 ret = imx_gpc_old_dt_init(&pdev->dev, regmap, 455 of_id_data->num_domains); 456 if (ret) 457 return ret; 458 } else { 459 struct imx_pm_domain *domain; 460 struct platform_device *pd_pdev; 461 struct device_node *np; 462 struct clk *ipg_clk; 463 unsigned int ipg_rate_mhz; 464 int domain_index; 465 466 ipg_clk = devm_clk_get(&pdev->dev, "ipg"); 467 if (IS_ERR(ipg_clk)) 468 return PTR_ERR(ipg_clk); 469 ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000; 470 471 for_each_child_of_node(pgc_node, np) { 472 ret = of_property_read_u32(np, "reg", &domain_index); 473 if (ret) { 474 of_node_put(np); 475 return ret; 476 } 477 if (domain_index >= of_id_data->num_domains) 478 continue; 479 480 pd_pdev = platform_device_alloc("imx-pgc-power-domain", 481 domain_index); 482 if (!pd_pdev) { 483 of_node_put(np); 484 return -ENOMEM; 485 } 486 487 ret = platform_device_add_data(pd_pdev, 488 &imx_gpc_domains[domain_index], 489 sizeof(imx_gpc_domains[domain_index])); 490 if (ret) { 491 platform_device_put(pd_pdev); 492 of_node_put(np); 493 return ret; 494 } 495 domain = pd_pdev->dev.platform_data; 496 domain->regmap = regmap; 497 domain->ipg_rate_mhz = ipg_rate_mhz; 498 499 pd_pdev->dev.parent = &pdev->dev; 500 pd_pdev->dev.of_node = np; 501 502 ret = platform_device_add(pd_pdev); 503 if (ret) { 504 platform_device_put(pd_pdev); 505 of_node_put(np); 506 return ret; 507 } 508 } 509 } 510 511 return 0; 512} 513 514static int imx_gpc_remove(struct platform_device *pdev) 515{ 516 struct device_node *pgc_node; 517 int ret; 518 519 pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); 520 521 /* bail out if DT too old and doesn't provide the necessary info */ 522 if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && 523 !pgc_node) 524 return 0; 525 526 /* 527 * If the old DT binding is used the toplevel driver needs to 528 * de-register the power domains 529 */ 530 if (!pgc_node) { 531 of_genpd_del_provider(pdev->dev.of_node); 532 533 ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); 534 if (ret) 535 return ret; 536 imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]); 537 538 ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base); 539 if (ret) 540 return ret; 541 } 542 543 return 0; 544} 545 546static struct platform_driver imx_gpc_driver = { 547 .driver = { 548 .name = "imx-gpc", 549 .of_match_table = imx_gpc_dt_ids, 550 }, 551 .probe = imx_gpc_probe, 552 .remove = imx_gpc_remove, 553}; 554builtin_platform_driver(imx_gpc_driver)