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_get_sync(bc->dev); 156 if (ret < 0) { 157 pm_runtime_put_noidle(bc->dev); 158 dev_err(bc->dev, "failed to power up domain\n"); 159 goto disable_clk; 160 } 161 162 /* ungate clk */ 163 regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); 164 165 /* release reset */ 166 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); 167 168 dev_dbg(bc->dev, "pd_on: name: %s\n", genpd->name); 169 170 return imx93_blk_ctrl_set_qos(domain); 171 172 disable_clk: 173 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 174 175 clk_bulk_disable_unprepare(bc->num_clks, bc->clks); 176 177 return ret; 178 } 179 180 static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd) 181 { 182 struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd); 183 const struct imx93_blk_ctrl_domain_data *data = domain->data; 184 struct imx93_blk_ctrl *bc = domain->bc; 185 186 dev_dbg(bc->dev, "pd_off: name: %s\n", genpd->name); 187 188 regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); 189 regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); 190 191 pm_runtime_put(bc->dev); 192 193 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 194 195 clk_bulk_disable_unprepare(bc->num_clks, bc->clks); 196 197 return 0; 198 } 199 200 static void imx93_release_genpd_provider(void *data) 201 { 202 struct device_node *of_node = data; 203 204 of_genpd_del_provider(of_node); 205 } 206 207 static void imx93_release_pm_genpd(void *data) 208 { 209 struct generic_pm_domain *genpd = data; 210 211 pm_genpd_remove(genpd); 212 } 213 214 static void imx93_release_subdomain(void *data) 215 { 216 struct imx93_blk_ctrl_subdomain_link *link = data; 217 218 pm_genpd_remove_subdomain(link->parent, link->subdomain); 219 } 220 221 static struct lock_class_key blk_ctrl_genpd_lock_class; 222 223 static int imx93_blk_ctrl_probe(struct platform_device *pdev) 224 { 225 struct device *dev = &pdev->dev; 226 const struct imx93_blk_ctrl_data *bc_data = of_device_get_match_data(dev); 227 struct imx93_blk_ctrl *bc; 228 void __iomem *base; 229 int i, ret; 230 231 struct regmap_config regmap_config = { 232 .reg_bits = 32, 233 .val_bits = 32, 234 .reg_stride = 4, 235 .rd_table = bc_data->reg_access_table, 236 .wr_table = bc_data->reg_access_table, 237 .max_register = SZ_4K, 238 }; 239 240 bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL); 241 if (!bc) 242 return -ENOMEM; 243 244 bc->dev = dev; 245 246 base = devm_platform_ioremap_resource(pdev, 0); 247 if (IS_ERR(base)) 248 return PTR_ERR(base); 249 250 bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config); 251 if (IS_ERR(bc->regmap)) 252 return dev_err_probe(dev, PTR_ERR(bc->regmap), 253 "failed to init regmap\n"); 254 255 bc->domains = devm_kcalloc(dev, bc_data->num_domains, 256 sizeof(struct imx93_blk_ctrl_domain), 257 GFP_KERNEL); 258 if (!bc->domains) 259 return -ENOMEM; 260 261 bc->onecell_data.num_domains = bc_data->num_domains; 262 bc->onecell_data.domains = 263 devm_kcalloc(dev, bc_data->num_domains, 264 sizeof(struct generic_pm_domain *), GFP_KERNEL); 265 if (!bc->onecell_data.domains) 266 return -ENOMEM; 267 268 for (i = 0; i < bc_data->num_clks; i++) 269 bc->clks[i].id = bc_data->clk_names[i]; 270 bc->num_clks = bc_data->num_clks; 271 272 ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks); 273 if (ret) 274 return dev_err_probe(dev, ret, "failed to get bus clock\n"); 275 276 for (i = 0; i < bc_data->num_domains; i++) { 277 const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i]; 278 struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; 279 int j; 280 281 domain->data = data; 282 if (bc_data->skip_mask & BIT(i)) 283 continue; 284 285 for (j = 0; j < data->num_clks; j++) 286 domain->clks[j].id = data->clk_names[j]; 287 288 ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); 289 if (ret) 290 return dev_err_probe(dev, ret, "failed to get clock\n"); 291 292 domain->genpd.name = data->name; 293 domain->genpd.power_on = imx93_blk_ctrl_power_on; 294 domain->genpd.power_off = imx93_blk_ctrl_power_off; 295 domain->bc = bc; 296 297 ret = pm_genpd_init(&domain->genpd, NULL, true); 298 if (ret) 299 return dev_err_probe(dev, ret, "failed to init power domain\n"); 300 301 ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd); 302 if (ret) 303 return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n"); 304 /* 305 * We use runtime PM to trigger power on/off of the upstream GPC 306 * domain, as a strict hierarchical parent/child power domain 307 * setup doesn't allow us to meet the sequencing requirements. 308 * This means we have nested locking of genpd locks, without the 309 * nesting being visible at the genpd level, so we need a 310 * separate lock class to make lockdep aware of the fact that 311 * this are separate domain locks that can be nested without a 312 * self-deadlock. 313 */ 314 lockdep_set_class(&domain->genpd.mlock, 315 &blk_ctrl_genpd_lock_class); 316 317 bc->onecell_data.domains[i] = &domain->genpd; 318 } 319 320 for (i = 0; i < bc_data->num_domains; i++) { 321 struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; 322 const struct imx93_blk_ctrl_domain_data *data = domain->data; 323 struct imx93_blk_ctrl_subdomain_link *link; 324 325 if (bc_data->skip_mask & BIT(i) || 326 data->parent == BLK_CTRL_NO_PARENT) 327 continue; 328 329 link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); 330 if (!link) 331 return -ENOMEM; 332 333 link->parent = &bc->domains[data->parent].genpd; 334 link->subdomain = &domain->genpd; 335 336 ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd, 337 &domain->genpd); 338 if (ret) 339 return dev_err_probe(dev, ret, "failed to add subdomain %s\n", 340 domain->genpd.name); 341 342 ret = devm_add_action_or_reset(dev, imx93_release_subdomain, link); 343 if (ret) 344 return dev_err_probe(dev, ret, 345 "failed to add subdomain release callback\n"); 346 } 347 348 ret = devm_pm_runtime_enable(dev); 349 if (ret) 350 return dev_err_probe(dev, ret, "failed to enable pm-runtime\n"); 351 352 ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); 353 if (ret) 354 return dev_err_probe(dev, ret, "failed to add power domain provider\n"); 355 356 ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node); 357 if (ret) 358 return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n"); 359 360 ret = devm_of_platform_populate(dev); 361 if (ret) 362 return dev_err_probe(dev, ret, "failed to populate blk-ctrl sub-devices\n"); 363 364 return 0; 365 } 366 367 static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = { 368 [IMX93_MEDIABLK_PD_MIPI_DSI] = { 369 .name = "mediablk-mipi-dsi", 370 .clk_names = (const char *[]){ "dsi" }, 371 .num_clks = 1, 372 .rst_mask = BIT(11), 373 .clk_mask = BIT(11), 374 .parent = IMX93_MEDIABLK_PD_MIPI_PHY, 375 }, 376 [IMX93_MEDIABLK_PD_MIPI_CSI] = { 377 .name = "mediablk-mipi-csi", 378 .clk_names = (const char *[]){ "cam", "csi" }, 379 .num_clks = 2, 380 .rst_mask = BIT(9) | BIT(10), 381 .clk_mask = BIT(9) | BIT(10), 382 .parent = IMX93_MEDIABLK_PD_MIPI_PHY, 383 }, 384 [IMX93_MEDIABLK_PD_PXP] = { 385 .name = "mediablk-pxp", 386 .clk_names = (const char *[]){ "pxp" }, 387 .num_clks = 1, 388 .rst_mask = BIT(7) | BIT(8), 389 .clk_mask = BIT(7) | BIT(8), 390 .parent = BLK_CTRL_NO_PARENT, 391 .num_qos = 2, 392 .qos = { 393 { 394 .reg = PXP_QOS_REG, 395 .cfg_off = PXP_R_CFG_QOS_OFF, 396 .default_prio = PRIO(3), 397 .cfg_prio = PRIO(6), 398 }, { 399 .reg = PXP_QOS_REG, 400 .cfg_off = PXP_W_CFG_QOS_OFF, 401 .default_prio = PRIO(3), 402 .cfg_prio = PRIO(6), 403 } 404 } 405 }, 406 [IMX93_MEDIABLK_PD_LCDIF] = { 407 .name = "mediablk-lcdif", 408 .clk_names = (const char *[]){ "disp", "lcdif" }, 409 .num_clks = 2, 410 .rst_mask = BIT(4) | BIT(5) | BIT(6), 411 .clk_mask = BIT(4) | BIT(5) | BIT(6), 412 .parent = BLK_CTRL_NO_PARENT, 413 .num_qos = 1, 414 .qos = { 415 { 416 .reg = LCDIF_QOS_REG, 417 .cfg_off = LCDIF_CFG_QOS_OFF, 418 .default_prio = PRIO(3), 419 .cfg_prio = PRIO(7), 420 } 421 } 422 }, 423 [IMX93_MEDIABLK_PD_ISI] = { 424 .name = "mediablk-isi", 425 .clk_names = (const char *[]){ "isi" }, 426 .num_clks = 1, 427 .rst_mask = BIT(2) | BIT(3), 428 .clk_mask = BIT(2) | BIT(3), 429 .parent = BLK_CTRL_NO_PARENT, 430 .num_qos = 4, 431 .qos = { 432 { 433 .reg = ISI_QOS_REG, 434 .cfg_off = ISI_Y_W_CFG_QOS_OFF, 435 .default_prio = PRIO(3), 436 .cfg_prio = PRIO(7), 437 }, { 438 .reg = ISI_QOS_REG, 439 .cfg_off = ISI_Y_R_CFG_QOS_OFF, 440 .default_prio = PRIO(3), 441 .cfg_prio = PRIO(7), 442 }, { 443 .reg = ISI_QOS_REG, 444 .cfg_off = ISI_U_CFG_QOS_OFF, 445 .default_prio = PRIO(3), 446 .cfg_prio = PRIO(7), 447 }, { 448 .reg = ISI_QOS_REG, 449 .cfg_off = ISI_V_CFG_QOS_OFF, 450 .default_prio = PRIO(3), 451 .cfg_prio = PRIO(7), 452 } 453 } 454 }, 455 [IMX93_MEDIABLK_PD_MIPI_PHY] = { 456 .name = "mediablk-mipi-phy", 457 .clk_names = NULL, 458 .num_clks = 0, 459 .rst_mask = BIT(12), 460 .clk_mask = BIT(12), 461 .parent = BLK_CTRL_NO_PARENT, 462 }, 463 }; 464 465 static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = { 466 regmap_reg_range(BLK_SFT_RSTN, BLK_CLK_EN), 467 regmap_reg_range(LCDIF_QOS_REG, ISI_CACHE_REG), 468 regmap_reg_range(ISI_QOS_REG, ISI_QOS_REG), 469 }; 470 471 static const struct regmap_access_table imx93_media_blk_ctl_access_table = { 472 .yes_ranges = imx93_media_blk_ctl_yes_ranges, 473 .n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges), 474 }; 475 476 static const char * const media_blk_clk_names[] = { 477 "axi", "apb", "nic" 478 }; 479 480 static const struct imx93_blk_ctrl_data imx91_media_blk_ctl_dev_data = { 481 .domains = imx93_media_blk_ctl_domain_data, 482 .skip_mask = BIT(IMX93_MEDIABLK_PD_MIPI_DSI) | BIT(IMX93_MEDIABLK_PD_PXP), 483 .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), 484 .clk_names = media_blk_clk_names, 485 .num_clks = ARRAY_SIZE(media_blk_clk_names), 486 .reg_access_table = &imx93_media_blk_ctl_access_table, 487 }; 488 489 static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = { 490 .domains = imx93_media_blk_ctl_domain_data, 491 .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), 492 .clk_names = media_blk_clk_names, 493 .num_clks = ARRAY_SIZE(media_blk_clk_names), 494 .reg_access_table = &imx93_media_blk_ctl_access_table, 495 }; 496 497 static const struct of_device_id imx93_blk_ctrl_of_match[] = { 498 { 499 .compatible = "fsl,imx91-media-blk-ctrl", 500 .data = &imx91_media_blk_ctl_dev_data 501 }, { 502 .compatible = "fsl,imx93-media-blk-ctrl", 503 .data = &imx93_media_blk_ctl_dev_data 504 }, { 505 /* Sentinel */ 506 } 507 }; 508 MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match); 509 510 static struct platform_driver imx93_blk_ctrl_driver = { 511 .probe = imx93_blk_ctrl_probe, 512 .driver = { 513 .name = "imx93-blk-ctrl", 514 .of_match_table = imx93_blk_ctrl_of_match, 515 }, 516 }; 517 module_platform_driver(imx93_blk_ctrl_driver); 518 519 MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 520 MODULE_DESCRIPTION("i.MX93 BLK CTRL driver"); 521 MODULE_LICENSE("GPL"); 522