0001
0002
0003
0004
0005
0006
0007 #include <linux/device.h>
0008 #include <linux/module.h>
0009 #include <linux/of_device.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/pm_domain.h>
0012 #include <linux/pm_runtime.h>
0013 #include <linux/regmap.h>
0014 #include <linux/clk.h>
0015
0016 #include <dt-bindings/power/imx8mm-power.h>
0017 #include <dt-bindings/power/imx8mn-power.h>
0018 #include <dt-bindings/power/imx8mp-power.h>
0019 #include <dt-bindings/power/imx8mq-power.h>
0020
0021 #define BLK_SFT_RSTN 0x0
0022 #define BLK_CLK_EN 0x4
0023 #define BLK_MIPI_RESET_DIV 0x8
0024
0025 struct imx8m_blk_ctrl_domain;
0026
0027 struct imx8m_blk_ctrl {
0028 struct device *dev;
0029 struct notifier_block power_nb;
0030 struct device *bus_power_dev;
0031 struct regmap *regmap;
0032 struct imx8m_blk_ctrl_domain *domains;
0033 struct genpd_onecell_data onecell_data;
0034 };
0035
0036 struct imx8m_blk_ctrl_domain_data {
0037 const char *name;
0038 const char * const *clk_names;
0039 int num_clks;
0040 const char *gpc_name;
0041 u32 rst_mask;
0042 u32 clk_mask;
0043
0044
0045
0046
0047
0048
0049
0050
0051 u32 mipi_phy_rst_mask;
0052 };
0053
0054 #define DOMAIN_MAX_CLKS 4
0055
0056 struct imx8m_blk_ctrl_domain {
0057 struct generic_pm_domain genpd;
0058 const struct imx8m_blk_ctrl_domain_data *data;
0059 struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
0060 struct device *power_dev;
0061 struct imx8m_blk_ctrl *bc;
0062 };
0063
0064 struct imx8m_blk_ctrl_data {
0065 int max_reg;
0066 notifier_fn_t power_notifier_fn;
0067 const struct imx8m_blk_ctrl_domain_data *domains;
0068 int num_domains;
0069 };
0070
0071 static inline struct imx8m_blk_ctrl_domain *
0072 to_imx8m_blk_ctrl_domain(struct generic_pm_domain *genpd)
0073 {
0074 return container_of(genpd, struct imx8m_blk_ctrl_domain, genpd);
0075 }
0076
0077 static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
0078 {
0079 struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
0080 const struct imx8m_blk_ctrl_domain_data *data = domain->data;
0081 struct imx8m_blk_ctrl *bc = domain->bc;
0082 int ret;
0083
0084
0085 ret = pm_runtime_get_sync(bc->bus_power_dev);
0086 if (ret < 0) {
0087 pm_runtime_put_noidle(bc->bus_power_dev);
0088 dev_err(bc->dev, "failed to power up bus domain\n");
0089 return ret;
0090 }
0091
0092
0093 regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
0094 if (data->mipi_phy_rst_mask)
0095 regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
0096
0097
0098 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
0099 if (ret) {
0100 dev_err(bc->dev, "failed to enable clocks\n");
0101 goto bus_put;
0102 }
0103 regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
0104
0105
0106 ret = pm_runtime_get_sync(domain->power_dev);
0107 if (ret < 0) {
0108 dev_err(bc->dev, "failed to power up peripheral domain\n");
0109 goto clk_disable;
0110 }
0111
0112
0113 udelay(5);
0114
0115
0116 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
0117 if (data->mipi_phy_rst_mask)
0118 regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
0119
0120
0121 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
0122
0123 return 0;
0124
0125 clk_disable:
0126 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
0127 bus_put:
0128 pm_runtime_put(bc->bus_power_dev);
0129
0130 return ret;
0131 }
0132
0133 static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
0134 {
0135 struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
0136 const struct imx8m_blk_ctrl_domain_data *data = domain->data;
0137 struct imx8m_blk_ctrl *bc = domain->bc;
0138
0139
0140 if (data->mipi_phy_rst_mask)
0141 regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
0142
0143 regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
0144 regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
0145
0146
0147 pm_runtime_put(domain->power_dev);
0148
0149
0150 pm_runtime_put(bc->bus_power_dev);
0151
0152 return 0;
0153 }
0154
0155 static struct generic_pm_domain *
0156 imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
0157 {
0158 struct genpd_onecell_data *onecell_data = data;
0159 unsigned int index = args->args[0];
0160
0161 if (args->args_count != 1 ||
0162 index >= onecell_data->num_domains)
0163 return ERR_PTR(-EINVAL);
0164
0165 return onecell_data->domains[index];
0166 }
0167
0168 static struct lock_class_key blk_ctrl_genpd_lock_class;
0169
0170 static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
0171 {
0172 const struct imx8m_blk_ctrl_data *bc_data;
0173 struct device *dev = &pdev->dev;
0174 struct imx8m_blk_ctrl *bc;
0175 void __iomem *base;
0176 int i, ret;
0177
0178 struct regmap_config regmap_config = {
0179 .reg_bits = 32,
0180 .val_bits = 32,
0181 .reg_stride = 4,
0182 };
0183
0184 bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
0185 if (!bc)
0186 return -ENOMEM;
0187
0188 bc->dev = dev;
0189
0190 bc_data = of_device_get_match_data(dev);
0191
0192 base = devm_platform_ioremap_resource(pdev, 0);
0193 if (IS_ERR(base))
0194 return PTR_ERR(base);
0195
0196 regmap_config.max_register = bc_data->max_reg;
0197 bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
0198 if (IS_ERR(bc->regmap))
0199 return dev_err_probe(dev, PTR_ERR(bc->regmap),
0200 "failed to init regmap\n");
0201
0202 bc->domains = devm_kcalloc(dev, bc_data->num_domains,
0203 sizeof(struct imx8m_blk_ctrl_domain),
0204 GFP_KERNEL);
0205 if (!bc->domains)
0206 return -ENOMEM;
0207
0208 bc->onecell_data.num_domains = bc_data->num_domains;
0209 bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
0210 bc->onecell_data.domains =
0211 devm_kcalloc(dev, bc_data->num_domains,
0212 sizeof(struct generic_pm_domain *), GFP_KERNEL);
0213 if (!bc->onecell_data.domains)
0214 return -ENOMEM;
0215
0216 bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
0217 if (IS_ERR(bc->bus_power_dev))
0218 return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
0219 "failed to attach power domain \"bus\"\n");
0220
0221 for (i = 0; i < bc_data->num_domains; i++) {
0222 const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
0223 struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
0224 int j;
0225
0226 domain->data = data;
0227
0228 for (j = 0; j < data->num_clks; j++)
0229 domain->clks[j].id = data->clk_names[j];
0230
0231 ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
0232 if (ret) {
0233 dev_err_probe(dev, ret, "failed to get clock\n");
0234 goto cleanup_pds;
0235 }
0236
0237 domain->power_dev =
0238 dev_pm_domain_attach_by_name(dev, data->gpc_name);
0239 if (IS_ERR(domain->power_dev)) {
0240 dev_err_probe(dev, PTR_ERR(domain->power_dev),
0241 "failed to attach power domain \"%s\"\n",
0242 data->gpc_name);
0243 ret = PTR_ERR(domain->power_dev);
0244 goto cleanup_pds;
0245 }
0246
0247 domain->genpd.name = data->name;
0248 domain->genpd.power_on = imx8m_blk_ctrl_power_on;
0249 domain->genpd.power_off = imx8m_blk_ctrl_power_off;
0250 domain->bc = bc;
0251
0252 ret = pm_genpd_init(&domain->genpd, NULL, true);
0253 if (ret) {
0254 dev_err_probe(dev, ret,
0255 "failed to init power domain \"%s\"\n",
0256 data->gpc_name);
0257 dev_pm_domain_detach(domain->power_dev, true);
0258 goto cleanup_pds;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271 lockdep_set_class(&domain->genpd.mlock,
0272 &blk_ctrl_genpd_lock_class);
0273
0274 bc->onecell_data.domains[i] = &domain->genpd;
0275 }
0276
0277 ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
0278 if (ret) {
0279 dev_err_probe(dev, ret, "failed to add power domain provider\n");
0280 goto cleanup_pds;
0281 }
0282
0283 bc->power_nb.notifier_call = bc_data->power_notifier_fn;
0284 ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
0285 if (ret) {
0286 dev_err_probe(dev, ret, "failed to add power notifier\n");
0287 goto cleanup_provider;
0288 }
0289
0290 dev_set_drvdata(dev, bc);
0291
0292 return 0;
0293
0294 cleanup_provider:
0295 of_genpd_del_provider(dev->of_node);
0296 cleanup_pds:
0297 for (i--; i >= 0; i--) {
0298 pm_genpd_remove(&bc->domains[i].genpd);
0299 dev_pm_domain_detach(bc->domains[i].power_dev, true);
0300 }
0301
0302 dev_pm_domain_detach(bc->bus_power_dev, true);
0303
0304 return ret;
0305 }
0306
0307 static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
0308 {
0309 struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
0310 int i;
0311
0312 of_genpd_del_provider(pdev->dev.of_node);
0313
0314 for (i = 0; bc->onecell_data.num_domains; i++) {
0315 struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
0316
0317 pm_genpd_remove(&domain->genpd);
0318 dev_pm_domain_detach(domain->power_dev, true);
0319 }
0320
0321 dev_pm_genpd_remove_notifier(bc->bus_power_dev);
0322
0323 dev_pm_domain_detach(bc->bus_power_dev, true);
0324
0325 return 0;
0326 }
0327
0328 #ifdef CONFIG_PM_SLEEP
0329 static int imx8m_blk_ctrl_suspend(struct device *dev)
0330 {
0331 struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
0332 int ret, i;
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 ret = pm_runtime_get_sync(bc->bus_power_dev);
0343 if (ret < 0) {
0344 pm_runtime_put_noidle(bc->bus_power_dev);
0345 return ret;
0346 }
0347
0348 for (i = 0; i < bc->onecell_data.num_domains; i++) {
0349 struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
0350
0351 ret = pm_runtime_get_sync(domain->power_dev);
0352 if (ret < 0) {
0353 pm_runtime_put_noidle(domain->power_dev);
0354 goto out_fail;
0355 }
0356 }
0357
0358 return 0;
0359
0360 out_fail:
0361 for (i--; i >= 0; i--)
0362 pm_runtime_put(bc->domains[i].power_dev);
0363
0364 pm_runtime_put(bc->bus_power_dev);
0365
0366 return ret;
0367 }
0368
0369 static int imx8m_blk_ctrl_resume(struct device *dev)
0370 {
0371 struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
0372 int i;
0373
0374 for (i = 0; i < bc->onecell_data.num_domains; i++)
0375 pm_runtime_put(bc->domains[i].power_dev);
0376
0377 pm_runtime_put(bc->bus_power_dev);
0378
0379 return 0;
0380 }
0381 #endif
0382
0383 static const struct dev_pm_ops imx8m_blk_ctrl_pm_ops = {
0384 SET_SYSTEM_SLEEP_PM_OPS(imx8m_blk_ctrl_suspend, imx8m_blk_ctrl_resume)
0385 };
0386
0387 static int imx8mm_vpu_power_notifier(struct notifier_block *nb,
0388 unsigned long action, void *data)
0389 {
0390 struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
0391 power_nb);
0392
0393 if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
0394 return NOTIFY_OK;
0395
0396
0397
0398
0399
0400
0401
0402 regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1) | BIT(2));
0403 regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1) | BIT(2));
0404
0405 if (action == GENPD_NOTIFY_ON) {
0406
0407
0408
0409
0410
0411 udelay(5);
0412
0413
0414 regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
0415 regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
0416 regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
0417 regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
0418 }
0419
0420 return NOTIFY_OK;
0421 }
0422
0423 static const struct imx8m_blk_ctrl_domain_data imx8mm_vpu_blk_ctl_domain_data[] = {
0424 [IMX8MM_VPUBLK_PD_G1] = {
0425 .name = "vpublk-g1",
0426 .clk_names = (const char *[]){ "g1", },
0427 .num_clks = 1,
0428 .gpc_name = "g1",
0429 .rst_mask = BIT(1),
0430 .clk_mask = BIT(1),
0431 },
0432 [IMX8MM_VPUBLK_PD_G2] = {
0433 .name = "vpublk-g2",
0434 .clk_names = (const char *[]){ "g2", },
0435 .num_clks = 1,
0436 .gpc_name = "g2",
0437 .rst_mask = BIT(0),
0438 .clk_mask = BIT(0),
0439 },
0440 [IMX8MM_VPUBLK_PD_H1] = {
0441 .name = "vpublk-h1",
0442 .clk_names = (const char *[]){ "h1", },
0443 .num_clks = 1,
0444 .gpc_name = "h1",
0445 .rst_mask = BIT(2),
0446 .clk_mask = BIT(2),
0447 },
0448 };
0449
0450 static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = {
0451 .max_reg = 0x18,
0452 .power_notifier_fn = imx8mm_vpu_power_notifier,
0453 .domains = imx8mm_vpu_blk_ctl_domain_data,
0454 .num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data),
0455 };
0456
0457 static int imx8mm_disp_power_notifier(struct notifier_block *nb,
0458 unsigned long action, void *data)
0459 {
0460 struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
0461 power_nb);
0462
0463 if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
0464 return NOTIFY_OK;
0465
0466
0467 regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(12));
0468 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(6));
0469
0470
0471
0472
0473
0474
0475 if (action == GENPD_NOTIFY_ON)
0476 udelay(5);
0477
0478
0479 return NOTIFY_OK;
0480 }
0481
0482 static const struct imx8m_blk_ctrl_domain_data imx8mm_disp_blk_ctl_domain_data[] = {
0483 [IMX8MM_DISPBLK_PD_CSI_BRIDGE] = {
0484 .name = "dispblk-csi-bridge",
0485 .clk_names = (const char *[]){ "csi-bridge-axi", "csi-bridge-apb",
0486 "csi-bridge-core", },
0487 .num_clks = 3,
0488 .gpc_name = "csi-bridge",
0489 .rst_mask = BIT(0) | BIT(1) | BIT(2),
0490 .clk_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
0491 },
0492 [IMX8MM_DISPBLK_PD_LCDIF] = {
0493 .name = "dispblk-lcdif",
0494 .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
0495 .num_clks = 3,
0496 .gpc_name = "lcdif",
0497 .clk_mask = BIT(6) | BIT(7),
0498 },
0499 [IMX8MM_DISPBLK_PD_MIPI_DSI] = {
0500 .name = "dispblk-mipi-dsi",
0501 .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
0502 .num_clks = 2,
0503 .gpc_name = "mipi-dsi",
0504 .rst_mask = BIT(5),
0505 .clk_mask = BIT(8) | BIT(9),
0506 .mipi_phy_rst_mask = BIT(17),
0507 },
0508 [IMX8MM_DISPBLK_PD_MIPI_CSI] = {
0509 .name = "dispblk-mipi-csi",
0510 .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
0511 .num_clks = 2,
0512 .gpc_name = "mipi-csi",
0513 .rst_mask = BIT(3) | BIT(4),
0514 .clk_mask = BIT(10) | BIT(11),
0515 .mipi_phy_rst_mask = BIT(16),
0516 },
0517 };
0518
0519 static const struct imx8m_blk_ctrl_data imx8mm_disp_blk_ctl_dev_data = {
0520 .max_reg = 0x2c,
0521 .power_notifier_fn = imx8mm_disp_power_notifier,
0522 .domains = imx8mm_disp_blk_ctl_domain_data,
0523 .num_domains = ARRAY_SIZE(imx8mm_disp_blk_ctl_domain_data),
0524 };
0525
0526
0527 static int imx8mn_disp_power_notifier(struct notifier_block *nb,
0528 unsigned long action, void *data)
0529 {
0530 struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
0531 power_nb);
0532
0533 if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
0534 return NOTIFY_OK;
0535
0536
0537 regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
0538 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
0539
0540
0541
0542
0543
0544
0545 if (action == GENPD_NOTIFY_ON)
0546 udelay(5);
0547
0548
0549 return NOTIFY_OK;
0550 }
0551
0552 static const struct imx8m_blk_ctrl_domain_data imx8mn_disp_blk_ctl_domain_data[] = {
0553 [IMX8MN_DISPBLK_PD_MIPI_DSI] = {
0554 .name = "dispblk-mipi-dsi",
0555 .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
0556 .num_clks = 2,
0557 .gpc_name = "mipi-dsi",
0558 .rst_mask = BIT(0) | BIT(1),
0559 .clk_mask = BIT(0) | BIT(1),
0560 .mipi_phy_rst_mask = BIT(17),
0561 },
0562 [IMX8MN_DISPBLK_PD_MIPI_CSI] = {
0563 .name = "dispblk-mipi-csi",
0564 .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
0565 .num_clks = 2,
0566 .gpc_name = "mipi-csi",
0567 .rst_mask = BIT(2) | BIT(3),
0568 .clk_mask = BIT(2) | BIT(3),
0569 .mipi_phy_rst_mask = BIT(16),
0570 },
0571 [IMX8MN_DISPBLK_PD_LCDIF] = {
0572 .name = "dispblk-lcdif",
0573 .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
0574 .num_clks = 3,
0575 .gpc_name = "lcdif",
0576 .rst_mask = BIT(4) | BIT(5),
0577 .clk_mask = BIT(4) | BIT(5),
0578 },
0579 [IMX8MN_DISPBLK_PD_ISI] = {
0580 .name = "dispblk-isi",
0581 .clk_names = (const char *[]){ "disp_axi", "disp_apb", "disp_axi_root",
0582 "disp_apb_root"},
0583 .num_clks = 4,
0584 .gpc_name = "isi",
0585 .rst_mask = BIT(6) | BIT(7),
0586 .clk_mask = BIT(6) | BIT(7),
0587 },
0588 };
0589
0590 static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
0591 .max_reg = 0x84,
0592 .power_notifier_fn = imx8mn_disp_power_notifier,
0593 .domains = imx8mn_disp_blk_ctl_domain_data,
0594 .num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
0595 };
0596
0597 static int imx8mp_media_power_notifier(struct notifier_block *nb,
0598 unsigned long action, void *data)
0599 {
0600 struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
0601 power_nb);
0602
0603 if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
0604 return NOTIFY_OK;
0605
0606
0607 regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
0608 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
0609
0610
0611
0612
0613
0614
0615 if (action == GENPD_NOTIFY_ON)
0616 udelay(5);
0617
0618 return NOTIFY_OK;
0619 }
0620
0621
0622
0623
0624
0625
0626 static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[] = {
0627 [IMX8MP_MEDIABLK_PD_MIPI_DSI_1] = {
0628 .name = "mediablk-mipi-dsi-1",
0629 .clk_names = (const char *[]){ "apb", "phy", },
0630 .num_clks = 2,
0631 .gpc_name = "mipi-dsi1",
0632 .rst_mask = BIT(0) | BIT(1),
0633 .clk_mask = BIT(0) | BIT(1),
0634 .mipi_phy_rst_mask = BIT(17),
0635 },
0636 [IMX8MP_MEDIABLK_PD_MIPI_CSI2_1] = {
0637 .name = "mediablk-mipi-csi2-1",
0638 .clk_names = (const char *[]){ "apb", "cam1" },
0639 .num_clks = 2,
0640 .gpc_name = "mipi-csi1",
0641 .rst_mask = BIT(2) | BIT(3),
0642 .clk_mask = BIT(2) | BIT(3),
0643 .mipi_phy_rst_mask = BIT(16),
0644 },
0645 [IMX8MP_MEDIABLK_PD_LCDIF_1] = {
0646 .name = "mediablk-lcdif-1",
0647 .clk_names = (const char *[]){ "disp1", "apb", "axi", },
0648 .num_clks = 3,
0649 .gpc_name = "lcdif1",
0650 .rst_mask = BIT(4) | BIT(5) | BIT(23),
0651 .clk_mask = BIT(4) | BIT(5) | BIT(23),
0652 },
0653 [IMX8MP_MEDIABLK_PD_ISI] = {
0654 .name = "mediablk-isi",
0655 .clk_names = (const char *[]){ "axi", "apb" },
0656 .num_clks = 2,
0657 .gpc_name = "isi",
0658 .rst_mask = BIT(6) | BIT(7),
0659 .clk_mask = BIT(6) | BIT(7),
0660 },
0661 [IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
0662 .name = "mediablk-mipi-csi2-2",
0663 .clk_names = (const char *[]){ "apb", "cam2" },
0664 .num_clks = 2,
0665 .gpc_name = "mipi-csi2",
0666 .rst_mask = BIT(9) | BIT(10),
0667 .clk_mask = BIT(9) | BIT(10),
0668 .mipi_phy_rst_mask = BIT(30),
0669 },
0670 [IMX8MP_MEDIABLK_PD_LCDIF_2] = {
0671 .name = "mediablk-lcdif-2",
0672 .clk_names = (const char *[]){ "disp2", "apb", "axi", },
0673 .num_clks = 3,
0674 .gpc_name = "lcdif2",
0675 .rst_mask = BIT(11) | BIT(12) | BIT(24),
0676 .clk_mask = BIT(11) | BIT(12) | BIT(24),
0677 },
0678 [IMX8MP_MEDIABLK_PD_ISP] = {
0679 .name = "mediablk-isp",
0680 .clk_names = (const char *[]){ "isp", "axi", "apb" },
0681 .num_clks = 3,
0682 .gpc_name = "isp",
0683 .rst_mask = BIT(16) | BIT(17) | BIT(18),
0684 .clk_mask = BIT(16) | BIT(17) | BIT(18),
0685 },
0686 [IMX8MP_MEDIABLK_PD_DWE] = {
0687 .name = "mediablk-dwe",
0688 .clk_names = (const char *[]){ "axi", "apb" },
0689 .num_clks = 2,
0690 .gpc_name = "dwe",
0691 .rst_mask = BIT(19) | BIT(20) | BIT(21),
0692 .clk_mask = BIT(19) | BIT(20) | BIT(21),
0693 },
0694 [IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
0695 .name = "mediablk-mipi-dsi-2",
0696 .clk_names = (const char *[]){ "phy", },
0697 .num_clks = 1,
0698 .gpc_name = "mipi-dsi2",
0699 .rst_mask = BIT(22),
0700 .clk_mask = BIT(22),
0701 .mipi_phy_rst_mask = BIT(29),
0702 },
0703 };
0704
0705 static const struct imx8m_blk_ctrl_data imx8mp_media_blk_ctl_dev_data = {
0706 .max_reg = 0x138,
0707 .power_notifier_fn = imx8mp_media_power_notifier,
0708 .domains = imx8mp_media_blk_ctl_domain_data,
0709 .num_domains = ARRAY_SIZE(imx8mp_media_blk_ctl_domain_data),
0710 };
0711
0712 static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
0713 unsigned long action, void *data)
0714 {
0715 struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
0716 power_nb);
0717
0718 if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
0719 return NOTIFY_OK;
0720
0721
0722
0723
0724
0725
0726
0727
0728 regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1));
0729 regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1));
0730
0731 if (action == GENPD_NOTIFY_ON) {
0732
0733
0734
0735
0736
0737 udelay(5);
0738
0739
0740 regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
0741 regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
0742 regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
0743 }
0744
0745 return NOTIFY_OK;
0746 }
0747
0748 static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
0749 [IMX8MQ_VPUBLK_PD_G1] = {
0750 .name = "vpublk-g1",
0751 .clk_names = (const char *[]){ "g1", },
0752 .num_clks = 1,
0753 .gpc_name = "g1",
0754 .rst_mask = BIT(1),
0755 .clk_mask = BIT(1),
0756 },
0757 [IMX8MQ_VPUBLK_PD_G2] = {
0758 .name = "vpublk-g2",
0759 .clk_names = (const char *[]){ "g2", },
0760 .num_clks = 1,
0761 .gpc_name = "g2",
0762 .rst_mask = BIT(0),
0763 .clk_mask = BIT(0),
0764 },
0765 };
0766
0767 static const struct imx8m_blk_ctrl_data imx8mq_vpu_blk_ctl_dev_data = {
0768 .max_reg = 0x14,
0769 .power_notifier_fn = imx8mq_vpu_power_notifier,
0770 .domains = imx8mq_vpu_blk_ctl_domain_data,
0771 .num_domains = ARRAY_SIZE(imx8mq_vpu_blk_ctl_domain_data),
0772 };
0773
0774 static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
0775 {
0776 .compatible = "fsl,imx8mm-vpu-blk-ctrl",
0777 .data = &imx8mm_vpu_blk_ctl_dev_data
0778 }, {
0779 .compatible = "fsl,imx8mm-disp-blk-ctrl",
0780 .data = &imx8mm_disp_blk_ctl_dev_data
0781 }, {
0782 .compatible = "fsl,imx8mn-disp-blk-ctrl",
0783 .data = &imx8mn_disp_blk_ctl_dev_data
0784 }, {
0785 .compatible = "fsl,imx8mp-media-blk-ctrl",
0786 .data = &imx8mp_media_blk_ctl_dev_data
0787 }, {
0788 .compatible = "fsl,imx8mq-vpu-blk-ctrl",
0789 .data = &imx8mq_vpu_blk_ctl_dev_data
0790 }, {
0791
0792 }
0793 };
0794 MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
0795
0796 static struct platform_driver imx8m_blk_ctrl_driver = {
0797 .probe = imx8m_blk_ctrl_probe,
0798 .remove = imx8m_blk_ctrl_remove,
0799 .driver = {
0800 .name = "imx8m-blk-ctrl",
0801 .pm = &imx8m_blk_ctrl_pm_ops,
0802 .of_match_table = imx8m_blk_ctrl_of_match,
0803 },
0804 };
0805 module_platform_driver(imx8m_blk_ctrl_driver);