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