1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com> 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/device.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/of_platform.h> 11 #include <linux/platform_device.h> 12 #include <linux/pm_domain.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/regmap.h> 15 #include <linux/sizes.h> 16 17 #include <dt-bindings/power/fsl,imx93-power.h> 18 19 #define BLK_SFT_RSTN 0x0 20 #define BLK_CLK_EN 0x4 21 #define BLK_MAX_CLKS 4 22 23 #define DOMAIN_MAX_CLKS 4 24 25 #define LCDIF_QOS_REG 0xC 26 #define LCDIF_DEFAULT_QOS_OFF 12 27 #define LCDIF_CFG_QOS_OFF 8 28 29 #define PXP_QOS_REG 0x10 30 #define PXP_R_DEFAULT_QOS_OFF 28 31 #define PXP_R_CFG_QOS_OFF 24 32 #define PXP_W_DEFAULT_QOS_OFF 20 33 #define PXP_W_CFG_QOS_OFF 16 34 35 #define ISI_CACHE_REG 0x14 36 37 #define ISI_QOS_REG 0x1C 38 #define ISI_V_DEFAULT_QOS_OFF 28 39 #define ISI_V_CFG_QOS_OFF 24 40 #define ISI_U_DEFAULT_QOS_OFF 20 41 #define ISI_U_CFG_QOS_OFF 16 42 #define ISI_Y_R_DEFAULT_QOS_OFF 12 43 #define ISI_Y_R_CFG_QOS_OFF 8 44 #define ISI_Y_W_DEFAULT_QOS_OFF 4 45 #define ISI_Y_W_CFG_QOS_OFF 0 46 47 #define PRIO_MASK 0xF 48 49 #define PRIO(X) (X) 50 51 #define BLK_CTRL_NO_PARENT UINT_MAX 52 53 struct imx93_blk_ctrl_domain; 54 55 struct imx93_blk_ctrl { 56 struct device *dev; 57 struct regmap *regmap; 58 int num_clks; 59 struct clk_bulk_data clks[BLK_MAX_CLKS]; 60 struct imx93_blk_ctrl_domain *domains; 61 struct genpd_onecell_data onecell_data; 62 }; 63 64 #define DOMAIN_MAX_QOS 4 65 66 struct imx93_blk_ctrl_qos { 67 u32 reg; 68 u32 cfg_off; 69 u32 default_prio; 70 u32 cfg_prio; 71 }; 72 73 struct imx93_blk_ctrl_subdomain_link { 74 struct generic_pm_domain *parent; 75 struct generic_pm_domain *subdomain; 76 }; 77 78 struct imx93_blk_ctrl_domain_data { 79 const char *name; 80 const char * const *clk_names; 81 int num_clks; 82 u32 rst_mask; 83 u32 clk_mask; 84 u32 parent; 85 int num_qos; 86 struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS]; 87 }; 88 89 struct imx93_blk_ctrl_domain { 90 struct generic_pm_domain genpd; 91 const struct imx93_blk_ctrl_domain_data *data; 92 struct clk_bulk_data clks[DOMAIN_MAX_CLKS]; 93 struct imx93_blk_ctrl *bc; 94 }; 95 96 struct imx93_blk_ctrl_data { 97 const struct imx93_blk_ctrl_domain_data *domains; 98 u32 skip_mask; 99 int num_domains; 100 const char * const *clk_names; 101 int num_clks; 102 const struct regmap_access_table *reg_access_table; 103 }; 104 105 static inline struct imx93_blk_ctrl_domain * 106 to_imx93_blk_ctrl_domain(struct generic_pm_domain *genpd) 107 { 108 return container_of(genpd, struct imx93_blk_ctrl_domain, genpd); 109 } 110 111 static int imx93_blk_ctrl_set_qos(struct imx93_blk_ctrl_domain *domain) 112 { 113 const struct imx93_blk_ctrl_domain_data *data = domain->data; 114 struct imx93_blk_ctrl *bc = domain->bc; 115 const struct imx93_blk_ctrl_qos *qos; 116 u32 val, mask; 117 int i; 118 119 for (i = 0; i < data->num_qos; i++) { 120 qos = &data->qos[i]; 121 122 mask = PRIO_MASK << qos->cfg_off; 123 mask |= PRIO_MASK << (qos->cfg_off + 4); 124 val = qos->cfg_prio << qos->cfg_off; 125 val |= qos->default_prio << (qos->cfg_off + 4); 126 127 regmap_write_bits(bc->regmap, qos->reg, mask, val); 128 129 dev_dbg(bc->dev, "data->qos[i].reg 0x%x 0x%x\n", qos->reg, val); 130 } 131 132 return 0; 133 } 134 135 static int imx93_blk_ctrl_power_on(struct generic_pm_domain *genpd) 136 { 137 struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd); 138 const struct imx93_blk_ctrl_domain_data *data = domain->data; 139 struct imx93_blk_ctrl *bc = domain->bc; 140 int ret; 141 142 ret = clk_bulk_prepare_enable(bc->num_clks, bc->clks); 143 if (ret) { 144 dev_err(bc->dev, "failed to enable bus clocks\n"); 145 return ret; 146 } 147 148 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); 149 if (ret) { 150 clk_bulk_disable_unprepare(bc->num_clks, bc->clks); 151 dev_err(bc->dev, "failed to enable clocks\n"); 152 return ret; 153 } 154 155 ret = pm_runtime_resume_and_get(bc->dev); 156 if (ret < 0) { 157 dev_err(bc->dev, "failed to power up domain\n"); 158 goto disable_clk; 159 } 160 161 /* ungate clk */ 162 regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); 163 164 /* release reset */ 165 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); 166 167 dev_dbg(bc->dev, "pd_on: name: %s\n", genpd->name); 168 169 return imx93_blk_ctrl_set_qos(domain); 170 171 disable_clk: 172 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 173 174 clk_bulk_disable_unprepare(bc->num_clks, bc->clks); 175 176 return ret; 177 } 178 179 static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd) 180 { 181 struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd); 182 const struct imx93_blk_ctrl_domain_data *data = domain->data; 183 struct imx93_blk_ctrl *bc = domain->bc; 184 185 dev_dbg(bc->dev, "pd_off: name: %s\n", genpd->name); 186 187 regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); 188 regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); 189 190 pm_runtime_put(bc->dev); 191 192 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 193 194 clk_bulk_disable_unprepare(bc->num_clks, bc->clks); 195 196 return 0; 197 } 198 199 static void imx93_release_genpd_provider(void *data) 200 { 201 struct device_node *of_node = data; 202 203 of_genpd_del_provider(of_node); 204 } 205 206 static void imx93_release_pm_genpd(void *data) 207 { 208 struct generic_pm_domain *genpd = data; 209 210 pm_genpd_remove(genpd); 211 } 212 213 static void imx93_release_subdomain(void *data) 214 { 215 struct imx93_blk_ctrl_subdomain_link *link = data; 216 217 pm_genpd_remove_subdomain(link->parent, link->subdomain); 218 } 219 220 static struct lock_class_key blk_ctrl_genpd_lock_class; 221 222 static int imx93_blk_ctrl_probe(struct platform_device *pdev) 223 { 224 struct device *dev = &pdev->dev; 225 const struct imx93_blk_ctrl_data *bc_data = of_device_get_match_data(dev); 226 struct imx93_blk_ctrl *bc; 227 void __iomem *base; 228 int i, ret; 229 230 struct regmap_config regmap_config = { 231 .reg_bits = 32, 232 .val_bits = 32, 233 .reg_stride = 4, 234 .rd_table = bc_data->reg_access_table, 235 .wr_table = bc_data->reg_access_table, 236 .max_register = SZ_4K, 237 }; 238 239 bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL); 240 if (!bc) 241 return -ENOMEM; 242 243 bc->dev = dev; 244 245 base = devm_platform_ioremap_resource(pdev, 0); 246 if (IS_ERR(base)) 247 return PTR_ERR(base); 248 249 bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config); 250 if (IS_ERR(bc->regmap)) 251 return dev_err_probe(dev, PTR_ERR(bc->regmap), 252 "failed to init regmap\n"); 253 254 bc->domains = devm_kcalloc(dev, bc_data->num_domains, 255 sizeof(struct imx93_blk_ctrl_domain), 256 GFP_KERNEL); 257 if (!bc->domains) 258 return -ENOMEM; 259 260 bc->onecell_data.num_domains = bc_data->num_domains; 261 bc->onecell_data.domains = 262 devm_kcalloc(dev, bc_data->num_domains, 263 sizeof(struct generic_pm_domain *), GFP_KERNEL); 264 if (!bc->onecell_data.domains) 265 return -ENOMEM; 266 267 for (i = 0; i < bc_data->num_clks; i++) 268 bc->clks[i].id = bc_data->clk_names[i]; 269 bc->num_clks = bc_data->num_clks; 270 271 ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks); 272 if (ret) 273 return dev_err_probe(dev, ret, "failed to get bus clock\n"); 274 275 for (i = 0; i < bc_data->num_domains; i++) { 276 const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i]; 277 struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; 278 int j; 279 280 domain->data = data; 281 if (bc_data->skip_mask & BIT(i)) 282 continue; 283 284 for (j = 0; j < data->num_clks; j++) 285 domain->clks[j].id = data->clk_names[j]; 286 287 ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); 288 if (ret) 289 return dev_err_probe(dev, ret, "failed to get clock\n"); 290 291 domain->genpd.name = data->name; 292 domain->genpd.power_on = imx93_blk_ctrl_power_on; 293 domain->genpd.power_off = imx93_blk_ctrl_power_off; 294 domain->bc = bc; 295 296 ret = pm_genpd_init(&domain->genpd, NULL, true); 297 if (ret) 298 return dev_err_probe(dev, ret, "failed to init power domain\n"); 299 300 ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd); 301 if (ret) 302 return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n"); 303 /* 304 * We use runtime PM to trigger power on/off of the upstream GPC 305 * domain, as a strict hierarchical parent/child power domain 306 * setup doesn't allow us to meet the sequencing requirements. 307 * This means we have nested locking of genpd locks, without the 308 * nesting being visible at the genpd level, so we need a 309 * separate lock class to make lockdep aware of the fact that 310 * this are separate domain locks that can be nested without a 311 * self-deadlock. 312 */ 313 lockdep_set_class(&domain->genpd.mlock, 314 &blk_ctrl_genpd_lock_class); 315 316 bc->onecell_data.domains[i] = &domain->genpd; 317 } 318 319 for (i = 0; i < bc_data->num_domains; i++) { 320 struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; 321 const struct imx93_blk_ctrl_domain_data *data = domain->data; 322 struct imx93_blk_ctrl_subdomain_link *link; 323 324 if (bc_data->skip_mask & BIT(i) || 325 data->parent == BLK_CTRL_NO_PARENT) 326 continue; 327 328 link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); 329 if (!link) 330 return -ENOMEM; 331 332 link->parent = &bc->domains[data->parent].genpd; 333 link->subdomain = &domain->genpd; 334 335 ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd, 336 &domain->genpd); 337 if (ret) 338 return dev_err_probe(dev, ret, "failed to add subdomain %s\n", 339 domain->genpd.name); 340 341 ret = devm_add_action_or_reset(dev, imx93_release_subdomain, link); 342 if (ret) 343 return dev_err_probe(dev, ret, 344 "failed to add subdomain release callback\n"); 345 } 346 347 ret = devm_pm_runtime_enable(dev); 348 if (ret) 349 return dev_err_probe(dev, ret, "failed to enable pm-runtime\n"); 350 351 ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); 352 if (ret) 353 return dev_err_probe(dev, ret, "failed to add power domain provider\n"); 354 355 ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node); 356 if (ret) 357 return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n"); 358 359 ret = devm_of_platform_populate(dev); 360 if (ret) 361 return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n"); 362 363 return 0; 364 } 365 366 static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = { 367 [IMX93_MEDIABLK_PD_MIPI_DSI] = { 368 .name = "mediablk-mipi-dsi", 369 .clk_names = (const char *[]){ "dsi" }, 370 .num_clks = 1, 371 .rst_mask = BIT(11), 372 .clk_mask = BIT(11), 373 .parent = IMX93_MEDIABLK_PD_MIPI_PHY, 374 }, 375 [IMX93_MEDIABLK_PD_MIPI_CSI] = { 376 .name = "mediablk-mipi-csi", 377 .clk_names = (const char *[]){ "cam", "csi" }, 378 .num_clks = 2, 379 .rst_mask = BIT(9) | BIT(10), 380 .clk_mask = BIT(9) | BIT(10), 381 .parent = IMX93_MEDIABLK_PD_MIPI_PHY, 382 }, 383 [IMX93_MEDIABLK_PD_PXP] = { 384 .name = "mediablk-pxp", 385 .clk_names = (const char *[]){ "pxp" }, 386 .num_clks = 1, 387 .rst_mask = BIT(7) | BIT(8), 388 .clk_mask = BIT(7) | BIT(8), 389 .parent = BLK_CTRL_NO_PARENT, 390 .num_qos = 2, 391 .qos = { 392 { 393 .reg = PXP_QOS_REG, 394 .cfg_off = PXP_R_CFG_QOS_OFF, 395 .default_prio = PRIO(3), 396 .cfg_prio = PRIO(6), 397 }, { 398 .reg = PXP_QOS_REG, 399 .cfg_off = PXP_W_CFG_QOS_OFF, 400 .default_prio = PRIO(3), 401 .cfg_prio = PRIO(6), 402 } 403 } 404 }, 405 [IMX93_MEDIABLK_PD_LCDIF] = { 406 .name = "mediablk-lcdif", 407 .clk_names = (const char *[]){ "disp", "lcdif" }, 408 .num_clks = 2, 409 .rst_mask = BIT(4) | BIT(5) | BIT(6), 410 .clk_mask = BIT(4) | BIT(5) | BIT(6), 411 .parent = BLK_CTRL_NO_PARENT, 412 .num_qos = 1, 413 .qos = { 414 { 415 .reg = LCDIF_QOS_REG, 416 .cfg_off = LCDIF_CFG_QOS_OFF, 417 .default_prio = PRIO(3), 418 .cfg_prio = PRIO(7), 419 } 420 } 421 }, 422 [IMX93_MEDIABLK_PD_ISI] = { 423 .name = "mediablk-isi", 424 .clk_names = (const char *[]){ "isi" }, 425 .num_clks = 1, 426 .rst_mask = BIT(2) | BIT(3), 427 .clk_mask = BIT(2) | BIT(3), 428 .parent = BLK_CTRL_NO_PARENT, 429 .num_qos = 4, 430 .qos = { 431 { 432 .reg = ISI_QOS_REG, 433 .cfg_off = ISI_Y_W_CFG_QOS_OFF, 434 .default_prio = PRIO(3), 435 .cfg_prio = PRIO(7), 436 }, { 437 .reg = ISI_QOS_REG, 438 .cfg_off = ISI_Y_R_CFG_QOS_OFF, 439 .default_prio = PRIO(3), 440 .cfg_prio = PRIO(7), 441 }, { 442 .reg = ISI_QOS_REG, 443 .cfg_off = ISI_U_CFG_QOS_OFF, 444 .default_prio = PRIO(3), 445 .cfg_prio = PRIO(7), 446 }, { 447 .reg = ISI_QOS_REG, 448 .cfg_off = ISI_V_CFG_QOS_OFF, 449 .default_prio = PRIO(3), 450 .cfg_prio = PRIO(7), 451 } 452 } 453 }, 454 [IMX93_MEDIABLK_PD_MIPI_PHY] = { 455 .name = "mediablk-mipi-phy", 456 .clk_names = NULL, 457 .num_clks = 0, 458 .rst_mask = BIT(12), 459 .clk_mask = BIT(12), 460 .parent = BLK_CTRL_NO_PARENT, 461 }, 462 }; 463 464 static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = { 465 regmap_reg_range(BLK_SFT_RSTN, BLK_CLK_EN), 466 regmap_reg_range(LCDIF_QOS_REG, ISI_CACHE_REG), 467 regmap_reg_range(ISI_QOS_REG, ISI_QOS_REG), 468 }; 469 470 static const struct regmap_access_table imx93_media_blk_ctl_access_table = { 471 .yes_ranges = imx93_media_blk_ctl_yes_ranges, 472 .n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges), 473 }; 474 475 static const char * const media_blk_clk_names[] = { 476 "axi", "apb", "nic" 477 }; 478 479 static const struct imx93_blk_ctrl_data imx91_media_blk_ctl_dev_data = { 480 .domains = imx93_media_blk_ctl_domain_data, 481 .skip_mask = BIT(IMX93_MEDIABLK_PD_MIPI_DSI) | BIT(IMX93_MEDIABLK_PD_PXP), 482 .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), 483 .clk_names = media_blk_clk_names, 484 .num_clks = ARRAY_SIZE(media_blk_clk_names), 485 .reg_access_table = &imx93_media_blk_ctl_access_table, 486 }; 487 488 static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = { 489 .domains = imx93_media_blk_ctl_domain_data, 490 .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), 491 .clk_names = media_blk_clk_names, 492 .num_clks = ARRAY_SIZE(media_blk_clk_names), 493 .reg_access_table = &imx93_media_blk_ctl_access_table, 494 }; 495 496 static const struct of_device_id imx93_blk_ctrl_of_match[] = { 497 { 498 .compatible = "fsl,imx91-media-blk-ctrl", 499 .data = &imx91_media_blk_ctl_dev_data 500 }, { 501 .compatible = "fsl,imx93-media-blk-ctrl", 502 .data = &imx93_media_blk_ctl_dev_data 503 }, { 504 /* Sentinel */ 505 } 506 }; 507 MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match); 508 509 static struct platform_driver imx93_blk_ctrl_driver = { 510 .probe = imx93_blk_ctrl_probe, 511 .driver = { 512 .name = "imx93-blk-ctrl", 513 .of_match_table = imx93_blk_ctrl_of_match, 514 }, 515 }; 516 module_platform_driver(imx93_blk_ctrl_driver); 517 518 MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 519 MODULE_DESCRIPTION("i.MX93 BLK CTRL driver"); 520 MODULE_LICENSE("GPL"); 521