cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

imx8m-blk-ctrl.c (22745B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3/*
      4 * Copyright 2021 Pengutronix, Lucas Stach <kernel@pengutronix.de>
      5 */
      6
      7#include <linux/device.h>
      8#include <linux/module.h>
      9#include <linux/of_device.h>
     10#include <linux/platform_device.h>
     11#include <linux/pm_domain.h>
     12#include <linux/pm_runtime.h>
     13#include <linux/regmap.h>
     14#include <linux/clk.h>
     15
     16#include <dt-bindings/power/imx8mm-power.h>
     17#include <dt-bindings/power/imx8mn-power.h>
     18#include <dt-bindings/power/imx8mp-power.h>
     19#include <dt-bindings/power/imx8mq-power.h>
     20
     21#define BLK_SFT_RSTN	0x0
     22#define BLK_CLK_EN	0x4
     23#define BLK_MIPI_RESET_DIV	0x8 /* Mini/Nano/Plus DISPLAY_BLK_CTRL only */
     24
     25struct imx8m_blk_ctrl_domain;
     26
     27struct imx8m_blk_ctrl {
     28	struct device *dev;
     29	struct notifier_block power_nb;
     30	struct device *bus_power_dev;
     31	struct regmap *regmap;
     32	struct imx8m_blk_ctrl_domain *domains;
     33	struct genpd_onecell_data onecell_data;
     34};
     35
     36struct imx8m_blk_ctrl_domain_data {
     37	const char *name;
     38	const char * const *clk_names;
     39	int num_clks;
     40	const char *gpc_name;
     41	u32 rst_mask;
     42	u32 clk_mask;
     43
     44	/*
     45	 * i.MX8M Mini, Nano and Plus have a third DISPLAY_BLK_CTRL register
     46	 * which is used to control the reset for the MIPI Phy.
     47	 * Since it's only present in certain circumstances,
     48	 * an if-statement should be used before setting and clearing this
     49	 * register.
     50	 */
     51	u32 mipi_phy_rst_mask;
     52};
     53
     54#define DOMAIN_MAX_CLKS 4
     55
     56struct imx8m_blk_ctrl_domain {
     57	struct generic_pm_domain genpd;
     58	const struct imx8m_blk_ctrl_domain_data *data;
     59	struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
     60	struct device *power_dev;
     61	struct imx8m_blk_ctrl *bc;
     62};
     63
     64struct imx8m_blk_ctrl_data {
     65	int max_reg;
     66	notifier_fn_t power_notifier_fn;
     67	const struct imx8m_blk_ctrl_domain_data *domains;
     68	int num_domains;
     69};
     70
     71static inline struct imx8m_blk_ctrl_domain *
     72to_imx8m_blk_ctrl_domain(struct generic_pm_domain *genpd)
     73{
     74	return container_of(genpd, struct imx8m_blk_ctrl_domain, genpd);
     75}
     76
     77static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
     78{
     79	struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
     80	const struct imx8m_blk_ctrl_domain_data *data = domain->data;
     81	struct imx8m_blk_ctrl *bc = domain->bc;
     82	int ret;
     83
     84	/* make sure bus domain is awake */
     85	ret = pm_runtime_get_sync(bc->bus_power_dev);
     86	if (ret < 0) {
     87		pm_runtime_put_noidle(bc->bus_power_dev);
     88		dev_err(bc->dev, "failed to power up bus domain\n");
     89		return ret;
     90	}
     91
     92	/* put devices into reset */
     93	regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
     94	if (data->mipi_phy_rst_mask)
     95		regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
     96
     97	/* enable upstream and blk-ctrl clocks to allow reset to propagate */
     98	ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
     99	if (ret) {
    100		dev_err(bc->dev, "failed to enable clocks\n");
    101		goto bus_put;
    102	}
    103	regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
    104
    105	/* power up upstream GPC domain */
    106	ret = pm_runtime_get_sync(domain->power_dev);
    107	if (ret < 0) {
    108		dev_err(bc->dev, "failed to power up peripheral domain\n");
    109		goto clk_disable;
    110	}
    111
    112	/* wait for reset to propagate */
    113	udelay(5);
    114
    115	/* release reset */
    116	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
    117	if (data->mipi_phy_rst_mask)
    118		regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
    119
    120	/* disable upstream clocks */
    121	clk_bulk_disable_unprepare(data->num_clks, domain->clks);
    122
    123	return 0;
    124
    125clk_disable:
    126	clk_bulk_disable_unprepare(data->num_clks, domain->clks);
    127bus_put:
    128	pm_runtime_put(bc->bus_power_dev);
    129
    130	return ret;
    131}
    132
    133static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
    134{
    135	struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
    136	const struct imx8m_blk_ctrl_domain_data *data = domain->data;
    137	struct imx8m_blk_ctrl *bc = domain->bc;
    138
    139	/* put devices into reset and disable clocks */
    140	if (data->mipi_phy_rst_mask)
    141		regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
    142
    143	regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
    144	regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
    145
    146	/* power down upstream GPC domain */
    147	pm_runtime_put(domain->power_dev);
    148
    149	/* allow bus domain to suspend */
    150	pm_runtime_put(bc->bus_power_dev);
    151
    152	return 0;
    153}
    154
    155static struct generic_pm_domain *
    156imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
    157{
    158	struct genpd_onecell_data *onecell_data = data;
    159	unsigned int index = args->args[0];
    160
    161	if (args->args_count != 1 ||
    162	    index >= onecell_data->num_domains)
    163		return ERR_PTR(-EINVAL);
    164
    165	return onecell_data->domains[index];
    166}
    167
    168static struct lock_class_key blk_ctrl_genpd_lock_class;
    169
    170static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
    171{
    172	const struct imx8m_blk_ctrl_data *bc_data;
    173	struct device *dev = &pdev->dev;
    174	struct imx8m_blk_ctrl *bc;
    175	void __iomem *base;
    176	int i, ret;
    177
    178	struct regmap_config regmap_config = {
    179		.reg_bits	= 32,
    180		.val_bits	= 32,
    181		.reg_stride	= 4,
    182	};
    183
    184	bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
    185	if (!bc)
    186		return -ENOMEM;
    187
    188	bc->dev = dev;
    189
    190	bc_data = of_device_get_match_data(dev);
    191
    192	base = devm_platform_ioremap_resource(pdev, 0);
    193	if (IS_ERR(base))
    194		return PTR_ERR(base);
    195
    196	regmap_config.max_register = bc_data->max_reg;
    197	bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
    198	if (IS_ERR(bc->regmap))
    199		return dev_err_probe(dev, PTR_ERR(bc->regmap),
    200				     "failed to init regmap\n");
    201
    202	bc->domains = devm_kcalloc(dev, bc_data->num_domains,
    203				   sizeof(struct imx8m_blk_ctrl_domain),
    204				   GFP_KERNEL);
    205	if (!bc->domains)
    206		return -ENOMEM;
    207
    208	bc->onecell_data.num_domains = bc_data->num_domains;
    209	bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
    210	bc->onecell_data.domains =
    211		devm_kcalloc(dev, bc_data->num_domains,
    212			     sizeof(struct generic_pm_domain *), GFP_KERNEL);
    213	if (!bc->onecell_data.domains)
    214		return -ENOMEM;
    215
    216	bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
    217	if (IS_ERR(bc->bus_power_dev))
    218		return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
    219				     "failed to attach power domain\n");
    220
    221	for (i = 0; i < bc_data->num_domains; i++) {
    222		const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
    223		struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
    224		int j;
    225
    226		domain->data = data;
    227
    228		for (j = 0; j < data->num_clks; j++)
    229			domain->clks[j].id = data->clk_names[j];
    230
    231		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
    232		if (ret) {
    233			dev_err_probe(dev, ret, "failed to get clock\n");
    234			goto cleanup_pds;
    235		}
    236
    237		domain->power_dev =
    238			dev_pm_domain_attach_by_name(dev, data->gpc_name);
    239		if (IS_ERR(domain->power_dev)) {
    240			dev_err_probe(dev, PTR_ERR(domain->power_dev),
    241				      "failed to attach power domain\n");
    242			ret = PTR_ERR(domain->power_dev);
    243			goto cleanup_pds;
    244		}
    245		dev_set_name(domain->power_dev, "%s", data->name);
    246
    247		domain->genpd.name = data->name;
    248		domain->genpd.power_on = imx8m_blk_ctrl_power_on;
    249		domain->genpd.power_off = imx8m_blk_ctrl_power_off;
    250		domain->bc = bc;
    251
    252		ret = pm_genpd_init(&domain->genpd, NULL, true);
    253		if (ret) {
    254			dev_err_probe(dev, ret, "failed to init power domain\n");
    255			dev_pm_domain_detach(domain->power_dev, true);
    256			goto cleanup_pds;
    257		}
    258
    259		/*
    260		 * We use runtime PM to trigger power on/off of the upstream GPC
    261		 * domain, as a strict hierarchical parent/child power domain
    262		 * setup doesn't allow us to meet the sequencing requirements.
    263		 * This means we have nested locking of genpd locks, without the
    264		 * nesting being visible at the genpd level, so we need a
    265		 * separate lock class to make lockdep aware of the fact that
    266		 * this are separate domain locks that can be nested without a
    267		 * self-deadlock.
    268		 */
    269		lockdep_set_class(&domain->genpd.mlock,
    270				  &blk_ctrl_genpd_lock_class);
    271
    272		bc->onecell_data.domains[i] = &domain->genpd;
    273	}
    274
    275	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
    276	if (ret) {
    277		dev_err_probe(dev, ret, "failed to add power domain provider\n");
    278		goto cleanup_pds;
    279	}
    280
    281	bc->power_nb.notifier_call = bc_data->power_notifier_fn;
    282	ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
    283	if (ret) {
    284		dev_err_probe(dev, ret, "failed to add power notifier\n");
    285		goto cleanup_provider;
    286	}
    287
    288	dev_set_drvdata(dev, bc);
    289
    290	return 0;
    291
    292cleanup_provider:
    293	of_genpd_del_provider(dev->of_node);
    294cleanup_pds:
    295	for (i--; i >= 0; i--) {
    296		pm_genpd_remove(&bc->domains[i].genpd);
    297		dev_pm_domain_detach(bc->domains[i].power_dev, true);
    298	}
    299
    300	dev_pm_domain_detach(bc->bus_power_dev, true);
    301
    302	return ret;
    303}
    304
    305static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
    306{
    307	struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
    308	int i;
    309
    310	of_genpd_del_provider(pdev->dev.of_node);
    311
    312	for (i = 0; bc->onecell_data.num_domains; i++) {
    313		struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
    314
    315		pm_genpd_remove(&domain->genpd);
    316		dev_pm_domain_detach(domain->power_dev, true);
    317	}
    318
    319	dev_pm_genpd_remove_notifier(bc->bus_power_dev);
    320
    321	dev_pm_domain_detach(bc->bus_power_dev, true);
    322
    323	return 0;
    324}
    325
    326#ifdef CONFIG_PM_SLEEP
    327static int imx8m_blk_ctrl_suspend(struct device *dev)
    328{
    329	struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
    330	int ret, i;
    331
    332	/*
    333	 * This may look strange, but is done so the generic PM_SLEEP code
    334	 * can power down our domains and more importantly power them up again
    335	 * after resume, without tripping over our usage of runtime PM to
    336	 * control the upstream GPC domains. Things happen in the right order
    337	 * in the system suspend/resume paths due to the device parent/child
    338	 * hierarchy.
    339	 */
    340	ret = pm_runtime_get_sync(bc->bus_power_dev);
    341	if (ret < 0) {
    342		pm_runtime_put_noidle(bc->bus_power_dev);
    343		return ret;
    344	}
    345
    346	for (i = 0; i < bc->onecell_data.num_domains; i++) {
    347		struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
    348
    349		ret = pm_runtime_get_sync(domain->power_dev);
    350		if (ret < 0) {
    351			pm_runtime_put_noidle(domain->power_dev);
    352			goto out_fail;
    353		}
    354	}
    355
    356	return 0;
    357
    358out_fail:
    359	for (i--; i >= 0; i--)
    360		pm_runtime_put(bc->domains[i].power_dev);
    361
    362	pm_runtime_put(bc->bus_power_dev);
    363
    364	return ret;
    365}
    366
    367static int imx8m_blk_ctrl_resume(struct device *dev)
    368{
    369	struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
    370	int i;
    371
    372	for (i = 0; i < bc->onecell_data.num_domains; i++)
    373		pm_runtime_put(bc->domains[i].power_dev);
    374
    375	pm_runtime_put(bc->bus_power_dev);
    376
    377	return 0;
    378}
    379#endif
    380
    381static const struct dev_pm_ops imx8m_blk_ctrl_pm_ops = {
    382	SET_SYSTEM_SLEEP_PM_OPS(imx8m_blk_ctrl_suspend, imx8m_blk_ctrl_resume)
    383};
    384
    385static int imx8mm_vpu_power_notifier(struct notifier_block *nb,
    386				     unsigned long action, void *data)
    387{
    388	struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
    389						 power_nb);
    390
    391	if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
    392		return NOTIFY_OK;
    393
    394	/*
    395	 * The ADB in the VPUMIX domain has no separate reset and clock
    396	 * enable bits, but is ungated together with the VPU clocks. To
    397	 * allow the handshake with the GPC to progress we put the VPUs
    398	 * in reset and ungate the clocks.
    399	 */
    400	regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1) | BIT(2));
    401	regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1) | BIT(2));
    402
    403	if (action == GENPD_NOTIFY_ON) {
    404		/*
    405		 * On power up we have no software backchannel to the GPC to
    406		 * wait for the ADB handshake to happen, so we just delay for a
    407		 * bit. On power down the GPC driver waits for the handshake.
    408		 */
    409		udelay(5);
    410
    411		/* set "fuse" bits to enable the VPUs */
    412		regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
    413		regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
    414		regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
    415		regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
    416	}
    417
    418	return NOTIFY_OK;
    419}
    420
    421static const struct imx8m_blk_ctrl_domain_data imx8mm_vpu_blk_ctl_domain_data[] = {
    422	[IMX8MM_VPUBLK_PD_G1] = {
    423		.name = "vpublk-g1",
    424		.clk_names = (const char *[]){ "g1", },
    425		.num_clks = 1,
    426		.gpc_name = "g1",
    427		.rst_mask = BIT(1),
    428		.clk_mask = BIT(1),
    429	},
    430	[IMX8MM_VPUBLK_PD_G2] = {
    431		.name = "vpublk-g2",
    432		.clk_names = (const char *[]){ "g2", },
    433		.num_clks = 1,
    434		.gpc_name = "g2",
    435		.rst_mask = BIT(0),
    436		.clk_mask = BIT(0),
    437	},
    438	[IMX8MM_VPUBLK_PD_H1] = {
    439		.name = "vpublk-h1",
    440		.clk_names = (const char *[]){ "h1", },
    441		.num_clks = 1,
    442		.gpc_name = "h1",
    443		.rst_mask = BIT(2),
    444		.clk_mask = BIT(2),
    445	},
    446};
    447
    448static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = {
    449	.max_reg = 0x18,
    450	.power_notifier_fn = imx8mm_vpu_power_notifier,
    451	.domains = imx8mm_vpu_blk_ctl_domain_data,
    452	.num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data),
    453};
    454
    455static int imx8mm_disp_power_notifier(struct notifier_block *nb,
    456				      unsigned long action, void *data)
    457{
    458	struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
    459						 power_nb);
    460
    461	if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
    462		return NOTIFY_OK;
    463
    464	/* Enable bus clock and deassert bus reset */
    465	regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(12));
    466	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(6));
    467
    468	/*
    469	 * On power up we have no software backchannel to the GPC to
    470	 * wait for the ADB handshake to happen, so we just delay for a
    471	 * bit. On power down the GPC driver waits for the handshake.
    472	 */
    473	if (action == GENPD_NOTIFY_ON)
    474		udelay(5);
    475
    476
    477	return NOTIFY_OK;
    478}
    479
    480static const struct imx8m_blk_ctrl_domain_data imx8mm_disp_blk_ctl_domain_data[] = {
    481	[IMX8MM_DISPBLK_PD_CSI_BRIDGE] = {
    482		.name = "dispblk-csi-bridge",
    483		.clk_names = (const char *[]){ "csi-bridge-axi", "csi-bridge-apb",
    484					       "csi-bridge-core", },
    485		.num_clks = 3,
    486		.gpc_name = "csi-bridge",
    487		.rst_mask = BIT(0) | BIT(1) | BIT(2),
    488		.clk_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
    489	},
    490	[IMX8MM_DISPBLK_PD_LCDIF] = {
    491		.name = "dispblk-lcdif",
    492		.clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
    493		.num_clks = 3,
    494		.gpc_name = "lcdif",
    495		.clk_mask = BIT(6) | BIT(7),
    496	},
    497	[IMX8MM_DISPBLK_PD_MIPI_DSI] = {
    498		.name = "dispblk-mipi-dsi",
    499		.clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
    500		.num_clks = 2,
    501		.gpc_name = "mipi-dsi",
    502		.rst_mask = BIT(5),
    503		.clk_mask = BIT(8) | BIT(9),
    504		.mipi_phy_rst_mask = BIT(17),
    505	},
    506	[IMX8MM_DISPBLK_PD_MIPI_CSI] = {
    507		.name = "dispblk-mipi-csi",
    508		.clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
    509		.num_clks = 2,
    510		.gpc_name = "mipi-csi",
    511		.rst_mask = BIT(3) | BIT(4),
    512		.clk_mask = BIT(10) | BIT(11),
    513		.mipi_phy_rst_mask = BIT(16),
    514	},
    515};
    516
    517static const struct imx8m_blk_ctrl_data imx8mm_disp_blk_ctl_dev_data = {
    518	.max_reg = 0x2c,
    519	.power_notifier_fn = imx8mm_disp_power_notifier,
    520	.domains = imx8mm_disp_blk_ctl_domain_data,
    521	.num_domains = ARRAY_SIZE(imx8mm_disp_blk_ctl_domain_data),
    522};
    523
    524
    525static int imx8mn_disp_power_notifier(struct notifier_block *nb,
    526				      unsigned long action, void *data)
    527{
    528	struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
    529						 power_nb);
    530
    531	if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
    532		return NOTIFY_OK;
    533
    534	/* Enable bus clock and deassert bus reset */
    535	regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
    536	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
    537
    538	/*
    539	 * On power up we have no software backchannel to the GPC to
    540	 * wait for the ADB handshake to happen, so we just delay for a
    541	 * bit. On power down the GPC driver waits for the handshake.
    542	 */
    543	if (action == GENPD_NOTIFY_ON)
    544		udelay(5);
    545
    546
    547	return NOTIFY_OK;
    548}
    549
    550static const struct imx8m_blk_ctrl_domain_data imx8mn_disp_blk_ctl_domain_data[] = {
    551	[IMX8MN_DISPBLK_PD_MIPI_DSI] = {
    552		.name = "dispblk-mipi-dsi",
    553		.clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
    554		.num_clks = 2,
    555		.gpc_name = "mipi-dsi",
    556		.rst_mask = BIT(0) | BIT(1),
    557		.clk_mask = BIT(0) | BIT(1),
    558		.mipi_phy_rst_mask = BIT(17),
    559	},
    560	[IMX8MN_DISPBLK_PD_MIPI_CSI] = {
    561		.name = "dispblk-mipi-csi",
    562		.clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
    563		.num_clks = 2,
    564		.gpc_name = "mipi-csi",
    565		.rst_mask = BIT(2) | BIT(3),
    566		.clk_mask = BIT(2) | BIT(3),
    567		.mipi_phy_rst_mask = BIT(16),
    568	},
    569	[IMX8MN_DISPBLK_PD_LCDIF] = {
    570		.name = "dispblk-lcdif",
    571		.clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
    572		.num_clks = 3,
    573		.gpc_name = "lcdif",
    574		.rst_mask = BIT(4) | BIT(5),
    575		.clk_mask = BIT(4) | BIT(5),
    576	},
    577	[IMX8MN_DISPBLK_PD_ISI] = {
    578		.name = "dispblk-isi",
    579		.clk_names = (const char *[]){ "disp_axi", "disp_apb", "disp_axi_root",
    580						"disp_apb_root"},
    581		.num_clks = 4,
    582		.gpc_name = "isi",
    583		.rst_mask = BIT(6) | BIT(7),
    584		.clk_mask = BIT(6) | BIT(7),
    585	},
    586};
    587
    588static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
    589	.max_reg = 0x84,
    590	.power_notifier_fn = imx8mn_disp_power_notifier,
    591	.domains = imx8mn_disp_blk_ctl_domain_data,
    592	.num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
    593};
    594
    595static int imx8mp_media_power_notifier(struct notifier_block *nb,
    596				unsigned long action, void *data)
    597{
    598	struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
    599						 power_nb);
    600
    601	if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
    602		return NOTIFY_OK;
    603
    604	/* Enable bus clock and deassert bus reset */
    605	regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
    606	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
    607
    608	/*
    609	 * On power up we have no software backchannel to the GPC to
    610	 * wait for the ADB handshake to happen, so we just delay for a
    611	 * bit. On power down the GPC driver waits for the handshake.
    612	 */
    613	if (action == GENPD_NOTIFY_ON)
    614		udelay(5);
    615
    616	return NOTIFY_OK;
    617}
    618
    619/*
    620 * From i.MX 8M Plus Applications Processor Reference Manual, Rev. 1,
    621 * section 13.2.2, 13.2.3
    622 * isp-ahb and dwe are not in Figure 13-5. Media BLK_CTRL Clocks
    623 */
    624static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[] = {
    625	[IMX8MP_MEDIABLK_PD_MIPI_DSI_1] = {
    626		.name = "mediablk-mipi-dsi-1",
    627		.clk_names = (const char *[]){ "apb", "phy", },
    628		.num_clks = 2,
    629		.gpc_name = "mipi-dsi1",
    630		.rst_mask = BIT(0) | BIT(1),
    631		.clk_mask = BIT(0) | BIT(1),
    632		.mipi_phy_rst_mask = BIT(17),
    633	},
    634	[IMX8MP_MEDIABLK_PD_MIPI_CSI2_1] = {
    635		.name = "mediablk-mipi-csi2-1",
    636		.clk_names = (const char *[]){ "apb", "cam1" },
    637		.num_clks = 2,
    638		.gpc_name = "mipi-csi1",
    639		.rst_mask = BIT(2) | BIT(3),
    640		.clk_mask = BIT(2) | BIT(3),
    641		.mipi_phy_rst_mask = BIT(16),
    642	},
    643	[IMX8MP_MEDIABLK_PD_LCDIF_1] = {
    644		.name = "mediablk-lcdif-1",
    645		.clk_names = (const char *[]){ "disp1", "apb", "axi", },
    646		.num_clks = 3,
    647		.gpc_name = "lcdif1",
    648		.rst_mask = BIT(4) | BIT(5) | BIT(23),
    649		.clk_mask = BIT(4) | BIT(5) | BIT(23),
    650	},
    651	[IMX8MP_MEDIABLK_PD_ISI] = {
    652		.name = "mediablk-isi",
    653		.clk_names = (const char *[]){ "axi", "apb" },
    654		.num_clks = 2,
    655		.gpc_name = "isi",
    656		.rst_mask = BIT(6) | BIT(7),
    657		.clk_mask = BIT(6) | BIT(7),
    658	},
    659	[IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
    660		.name = "mediablk-mipi-csi2-2",
    661		.clk_names = (const char *[]){ "apb", "cam2" },
    662		.num_clks = 2,
    663		.gpc_name = "mipi-csi2",
    664		.rst_mask = BIT(9) | BIT(10),
    665		.clk_mask = BIT(9) | BIT(10),
    666		.mipi_phy_rst_mask = BIT(30),
    667	},
    668	[IMX8MP_MEDIABLK_PD_LCDIF_2] = {
    669		.name = "mediablk-lcdif-2",
    670		.clk_names = (const char *[]){ "disp2", "apb", "axi", },
    671		.num_clks = 3,
    672		.gpc_name = "lcdif2",
    673		.rst_mask = BIT(11) | BIT(12) | BIT(24),
    674		.clk_mask = BIT(11) | BIT(12) | BIT(24),
    675	},
    676	[IMX8MP_MEDIABLK_PD_ISP] = {
    677		.name = "mediablk-isp",
    678		.clk_names = (const char *[]){ "isp", "axi", "apb" },
    679		.num_clks = 3,
    680		.gpc_name = "isp",
    681		.rst_mask = BIT(16) | BIT(17) | BIT(18),
    682		.clk_mask = BIT(16) | BIT(17) | BIT(18),
    683	},
    684	[IMX8MP_MEDIABLK_PD_DWE] = {
    685		.name = "mediablk-dwe",
    686		.clk_names = (const char *[]){ "axi", "apb" },
    687		.num_clks = 2,
    688		.gpc_name = "dwe",
    689		.rst_mask = BIT(19) | BIT(20) | BIT(21),
    690		.clk_mask = BIT(19) | BIT(20) | BIT(21),
    691	},
    692	[IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
    693		.name = "mediablk-mipi-dsi-2",
    694		.clk_names = (const char *[]){ "phy", },
    695		.num_clks = 1,
    696		.gpc_name = "mipi-dsi2",
    697		.rst_mask = BIT(22),
    698		.clk_mask = BIT(22),
    699		.mipi_phy_rst_mask = BIT(29),
    700	},
    701};
    702
    703static const struct imx8m_blk_ctrl_data imx8mp_media_blk_ctl_dev_data = {
    704	.max_reg = 0x138,
    705	.power_notifier_fn = imx8mp_media_power_notifier,
    706	.domains = imx8mp_media_blk_ctl_domain_data,
    707	.num_domains = ARRAY_SIZE(imx8mp_media_blk_ctl_domain_data),
    708};
    709
    710static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
    711				     unsigned long action, void *data)
    712{
    713	struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
    714						 power_nb);
    715
    716	if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
    717		return NOTIFY_OK;
    718
    719	/*
    720	 * The ADB in the VPUMIX domain has no separate reset and clock
    721	 * enable bits, but is ungated and reset together with the VPUs. The
    722	 * reset and clock enable inputs to the ADB is a logical OR of the
    723	 * VPU bits. In order to set the G2 fuse bits, the G2 clock must
    724	 * also be enabled.
    725	 */
    726	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1));
    727	regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1));
    728
    729	if (action == GENPD_NOTIFY_ON) {
    730		/*
    731		 * On power up we have no software backchannel to the GPC to
    732		 * wait for the ADB handshake to happen, so we just delay for a
    733		 * bit. On power down the GPC driver waits for the handshake.
    734		 */
    735		udelay(5);
    736
    737		/* set "fuse" bits to enable the VPUs */
    738		regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
    739		regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
    740		regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
    741	}
    742
    743	return NOTIFY_OK;
    744}
    745
    746static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
    747	[IMX8MQ_VPUBLK_PD_G1] = {
    748		.name = "vpublk-g1",
    749		.clk_names = (const char *[]){ "g1", },
    750		.num_clks = 1,
    751		.gpc_name = "g1",
    752		.rst_mask = BIT(1),
    753		.clk_mask = BIT(1),
    754	},
    755	[IMX8MQ_VPUBLK_PD_G2] = {
    756		.name = "vpublk-g2",
    757		.clk_names = (const char *[]){ "g2", },
    758		.num_clks = 1,
    759		.gpc_name = "g2",
    760		.rst_mask = BIT(0),
    761		.clk_mask = BIT(0),
    762	},
    763};
    764
    765static const struct imx8m_blk_ctrl_data imx8mq_vpu_blk_ctl_dev_data = {
    766	.max_reg = 0x14,
    767	.power_notifier_fn = imx8mq_vpu_power_notifier,
    768	.domains = imx8mq_vpu_blk_ctl_domain_data,
    769	.num_domains = ARRAY_SIZE(imx8mq_vpu_blk_ctl_domain_data),
    770};
    771
    772static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
    773	{
    774		.compatible = "fsl,imx8mm-vpu-blk-ctrl",
    775		.data = &imx8mm_vpu_blk_ctl_dev_data
    776	}, {
    777		.compatible = "fsl,imx8mm-disp-blk-ctrl",
    778		.data = &imx8mm_disp_blk_ctl_dev_data
    779	}, {
    780		.compatible = "fsl,imx8mn-disp-blk-ctrl",
    781		.data = &imx8mn_disp_blk_ctl_dev_data
    782	}, {
    783		.compatible = "fsl,imx8mp-media-blk-ctrl",
    784		.data = &imx8mp_media_blk_ctl_dev_data
    785	}, {
    786		.compatible = "fsl,imx8mq-vpu-blk-ctrl",
    787		.data = &imx8mq_vpu_blk_ctl_dev_data
    788	}, {
    789		/* Sentinel */
    790	}
    791};
    792MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
    793
    794static struct platform_driver imx8m_blk_ctrl_driver = {
    795	.probe = imx8m_blk_ctrl_probe,
    796	.remove = imx8m_blk_ctrl_remove,
    797	.driver = {
    798		.name = "imx8m-blk-ctrl",
    799		.pm = &imx8m_blk_ctrl_pm_ops,
    800		.of_match_table = imx8m_blk_ctrl_of_match,
    801	},
    802};
    803module_platform_driver(imx8m_blk_ctrl_driver);