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

imx8mp-blk-ctrl.c (19663B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3/*
      4 * Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de>
      5 */
      6
      7#include <linux/clk.h>
      8#include <linux/device.h>
      9#include <linux/module.h>
     10#include <linux/of_device.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
     16#include <dt-bindings/power/imx8mp-power.h>
     17
     18#define GPR_REG0		0x0
     19#define  PCIE_CLOCK_MODULE_EN	BIT(0)
     20#define  USB_CLOCK_MODULE_EN	BIT(1)
     21
     22struct imx8mp_blk_ctrl_domain;
     23
     24struct imx8mp_blk_ctrl {
     25	struct device *dev;
     26	struct notifier_block power_nb;
     27	struct device *bus_power_dev;
     28	struct regmap *regmap;
     29	struct imx8mp_blk_ctrl_domain *domains;
     30	struct genpd_onecell_data onecell_data;
     31	void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
     32	void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
     33};
     34
     35struct imx8mp_blk_ctrl_domain_data {
     36	const char *name;
     37	const char * const *clk_names;
     38	int num_clks;
     39	const char *gpc_name;
     40};
     41
     42#define DOMAIN_MAX_CLKS 2
     43
     44struct imx8mp_blk_ctrl_domain {
     45	struct generic_pm_domain genpd;
     46	const struct imx8mp_blk_ctrl_domain_data *data;
     47	struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
     48	struct device *power_dev;
     49	struct imx8mp_blk_ctrl *bc;
     50	int id;
     51};
     52
     53struct imx8mp_blk_ctrl_data {
     54	int max_reg;
     55	notifier_fn_t power_notifier_fn;
     56	void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
     57	void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
     58	const struct imx8mp_blk_ctrl_domain_data *domains;
     59	int num_domains;
     60};
     61
     62static inline struct imx8mp_blk_ctrl_domain *
     63to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd)
     64{
     65	return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd);
     66}
     67
     68static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
     69					  struct imx8mp_blk_ctrl_domain *domain)
     70{
     71	switch (domain->id) {
     72	case IMX8MP_HSIOBLK_PD_USB:
     73		regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
     74		break;
     75	case IMX8MP_HSIOBLK_PD_PCIE:
     76		regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
     77		break;
     78	default:
     79		break;
     80	}
     81}
     82
     83static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
     84					   struct imx8mp_blk_ctrl_domain *domain)
     85{
     86	switch (domain->id) {
     87	case IMX8MP_HSIOBLK_PD_USB:
     88		regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
     89		break;
     90	case IMX8MP_HSIOBLK_PD_PCIE:
     91		regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
     92		break;
     93	default:
     94		break;
     95	}
     96}
     97
     98static int imx8mp_hsio_power_notifier(struct notifier_block *nb,
     99				      unsigned long action, void *data)
    100{
    101	struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
    102						 power_nb);
    103	struct clk_bulk_data *usb_clk = bc->domains[IMX8MP_HSIOBLK_PD_USB].clks;
    104	int num_clks = bc->domains[IMX8MP_HSIOBLK_PD_USB].data->num_clks;
    105	int ret;
    106
    107	switch (action) {
    108	case GENPD_NOTIFY_ON:
    109		/*
    110		 * enable USB clock for a moment for the power-on ADB handshake
    111		 * to proceed
    112		 */
    113		ret = clk_bulk_prepare_enable(num_clks, usb_clk);
    114		if (ret)
    115			return NOTIFY_BAD;
    116		regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
    117
    118		udelay(5);
    119
    120		regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
    121		clk_bulk_disable_unprepare(num_clks, usb_clk);
    122		break;
    123	case GENPD_NOTIFY_PRE_OFF:
    124		/* enable USB clock for the power-down ADB handshake to work */
    125		ret = clk_bulk_prepare_enable(num_clks, usb_clk);
    126		if (ret)
    127			return NOTIFY_BAD;
    128
    129		regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
    130		break;
    131	case GENPD_NOTIFY_OFF:
    132		clk_bulk_disable_unprepare(num_clks, usb_clk);
    133		break;
    134	default:
    135		break;
    136	}
    137
    138	return NOTIFY_OK;
    139}
    140
    141static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
    142	[IMX8MP_HSIOBLK_PD_USB] = {
    143		.name = "hsioblk-usb",
    144		.clk_names = (const char *[]){ "usb" },
    145		.num_clks = 1,
    146		.gpc_name = "usb",
    147	},
    148	[IMX8MP_HSIOBLK_PD_USB_PHY1] = {
    149		.name = "hsioblk-usb-phy1",
    150		.gpc_name = "usb-phy1",
    151	},
    152	[IMX8MP_HSIOBLK_PD_USB_PHY2] = {
    153		.name = "hsioblk-usb-phy2",
    154		.gpc_name = "usb-phy2",
    155	},
    156	[IMX8MP_HSIOBLK_PD_PCIE] = {
    157		.name = "hsioblk-pcie",
    158		.clk_names = (const char *[]){ "pcie" },
    159		.num_clks = 1,
    160		.gpc_name = "pcie",
    161	},
    162	[IMX8MP_HSIOBLK_PD_PCIE_PHY] = {
    163		.name = "hsioblk-pcie-phy",
    164		.gpc_name = "pcie-phy",
    165	},
    166};
    167
    168static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
    169	.max_reg = 0x24,
    170	.power_on = imx8mp_hsio_blk_ctrl_power_on,
    171	.power_off = imx8mp_hsio_blk_ctrl_power_off,
    172	.power_notifier_fn = imx8mp_hsio_power_notifier,
    173	.domains = imx8mp_hsio_domain_data,
    174	.num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
    175};
    176
    177#define HDMI_RTX_RESET_CTL0	0x20
    178#define HDMI_RTX_CLK_CTL0	0x40
    179#define HDMI_RTX_CLK_CTL1	0x50
    180#define HDMI_RTX_CLK_CTL2	0x60
    181#define HDMI_RTX_CLK_CTL3	0x70
    182#define HDMI_RTX_CLK_CTL4	0x80
    183#define HDMI_TX_CONTROL0	0x200
    184
    185static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
    186					  struct imx8mp_blk_ctrl_domain *domain)
    187{
    188	switch (domain->id) {
    189	case IMX8MP_HDMIBLK_PD_IRQSTEER:
    190		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
    191		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
    192		break;
    193	case IMX8MP_HDMIBLK_PD_LCDIF:
    194		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
    195				BIT(7) | BIT(16) | BIT(17) | BIT(18) |
    196				BIT(19) | BIT(20));
    197		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
    198		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
    199				BIT(4) | BIT(5) | BIT(6));
    200		break;
    201	case IMX8MP_HDMIBLK_PD_PAI:
    202		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
    203		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
    204		break;
    205	case IMX8MP_HDMIBLK_PD_PVI:
    206		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
    207		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
    208		break;
    209	case IMX8MP_HDMIBLK_PD_TRNG:
    210		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
    211		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
    212		break;
    213	case IMX8MP_HDMIBLK_PD_HDMI_TX:
    214		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
    215				BIT(2) | BIT(4) | BIT(5));
    216		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
    217				BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
    218				BIT(18) | BIT(19) | BIT(20) | BIT(21));
    219		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
    220				BIT(7) | BIT(10) | BIT(11));
    221		regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
    222		break;
    223	case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
    224		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
    225		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
    226		regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
    227		break;
    228	default:
    229		break;
    230	}
    231}
    232
    233static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
    234					   struct imx8mp_blk_ctrl_domain *domain)
    235{
    236	switch (domain->id) {
    237	case IMX8MP_HDMIBLK_PD_IRQSTEER:
    238		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
    239		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
    240		break;
    241	case IMX8MP_HDMIBLK_PD_LCDIF:
    242		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
    243				  BIT(4) | BIT(5) | BIT(6));
    244		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
    245		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
    246				  BIT(7) | BIT(16) | BIT(17) | BIT(18) |
    247				  BIT(19) | BIT(20));
    248		break;
    249	case IMX8MP_HDMIBLK_PD_PAI:
    250		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
    251		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
    252		break;
    253	case IMX8MP_HDMIBLK_PD_PVI:
    254		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
    255		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
    256		break;
    257	case IMX8MP_HDMIBLK_PD_TRNG:
    258		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
    259		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
    260		break;
    261	case IMX8MP_HDMIBLK_PD_HDMI_TX:
    262		regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
    263		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
    264				  BIT(7) | BIT(10) | BIT(11));
    265		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
    266				  BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
    267				  BIT(18) | BIT(19) | BIT(20) | BIT(21));
    268		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
    269				  BIT(2) | BIT(4) | BIT(5));
    270		break;
    271	case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
    272		regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
    273		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
    274		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
    275		break;
    276	default:
    277		break;
    278	}
    279}
    280
    281static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
    282				      unsigned long action, void *data)
    283{
    284	struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
    285						 power_nb);
    286
    287	if (action != GENPD_NOTIFY_ON)
    288		return NOTIFY_OK;
    289
    290	/*
    291	 * Contrary to other blk-ctrls the reset and clock don't clear when the
    292	 * power domain is powered down. To ensure the proper reset pulsing,
    293	 * first clear them all to asserted state, then enable the bus clocks
    294	 * and then release the ADB reset.
    295	 */
    296	regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0);
    297	regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
    298	regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
    299	regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
    300			BIT(0) | BIT(1) | BIT(10));
    301	regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
    302
    303	/*
    304	 * On power up we have no software backchannel to the GPC to
    305	 * wait for the ADB handshake to happen, so we just delay for a
    306	 * bit. On power down the GPC driver waits for the handshake.
    307	 */
    308	udelay(5);
    309
    310	return NOTIFY_OK;
    311}
    312
    313static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
    314	[IMX8MP_HDMIBLK_PD_IRQSTEER] = {
    315		.name = "hdmiblk-irqsteer",
    316		.clk_names = (const char *[]){ "apb" },
    317		.num_clks = 1,
    318		.gpc_name = "irqsteer",
    319	},
    320	[IMX8MP_HDMIBLK_PD_LCDIF] = {
    321		.name = "hdmiblk-lcdif",
    322		.clk_names = (const char *[]){ "axi", "apb" },
    323		.num_clks = 2,
    324		.gpc_name = "lcdif",
    325	},
    326	[IMX8MP_HDMIBLK_PD_PAI] = {
    327		.name = "hdmiblk-pai",
    328		.clk_names = (const char *[]){ "apb" },
    329		.num_clks = 1,
    330		.gpc_name = "pai",
    331	},
    332	[IMX8MP_HDMIBLK_PD_PVI] = {
    333		.name = "hdmiblk-pvi",
    334		.clk_names = (const char *[]){ "apb" },
    335		.num_clks = 1,
    336		.gpc_name = "pvi",
    337	},
    338	[IMX8MP_HDMIBLK_PD_TRNG] = {
    339		.name = "hdmiblk-trng",
    340		.clk_names = (const char *[]){ "apb" },
    341		.num_clks = 1,
    342		.gpc_name = "trng",
    343	},
    344	[IMX8MP_HDMIBLK_PD_HDMI_TX] = {
    345		.name = "hdmiblk-hdmi-tx",
    346		.clk_names = (const char *[]){ "apb", "ref_266m" },
    347		.num_clks = 2,
    348		.gpc_name = "hdmi-tx",
    349	},
    350	[IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
    351		.name = "hdmiblk-hdmi-tx-phy",
    352		.clk_names = (const char *[]){ "apb", "ref_24m" },
    353		.num_clks = 2,
    354		.gpc_name = "hdmi-tx-phy",
    355	},
    356};
    357
    358static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
    359	.max_reg = 0x23c,
    360	.power_on = imx8mp_hdmi_blk_ctrl_power_on,
    361	.power_off = imx8mp_hdmi_blk_ctrl_power_off,
    362	.power_notifier_fn = imx8mp_hdmi_power_notifier,
    363	.domains = imx8mp_hdmi_domain_data,
    364	.num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data),
    365};
    366
    367static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
    368{
    369	struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
    370	const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
    371	struct imx8mp_blk_ctrl *bc = domain->bc;
    372	int ret;
    373
    374	/* make sure bus domain is awake */
    375	ret = pm_runtime_resume_and_get(bc->bus_power_dev);
    376	if (ret < 0) {
    377		dev_err(bc->dev, "failed to power up bus domain\n");
    378		return ret;
    379	}
    380
    381	/* enable upstream clocks */
    382	ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
    383	if (ret) {
    384		dev_err(bc->dev, "failed to enable clocks\n");
    385		goto bus_put;
    386	}
    387
    388	/* domain specific blk-ctrl manipulation */
    389	bc->power_on(bc, domain);
    390
    391	/* power up upstream GPC domain */
    392	ret = pm_runtime_resume_and_get(domain->power_dev);
    393	if (ret < 0) {
    394		dev_err(bc->dev, "failed to power up peripheral domain\n");
    395		goto clk_disable;
    396	}
    397
    398	clk_bulk_disable_unprepare(data->num_clks, domain->clks);
    399
    400	return 0;
    401
    402clk_disable:
    403	clk_bulk_disable_unprepare(data->num_clks, domain->clks);
    404bus_put:
    405	pm_runtime_put(bc->bus_power_dev);
    406
    407	return ret;
    408}
    409
    410static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
    411{
    412	struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
    413	const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
    414	struct imx8mp_blk_ctrl *bc = domain->bc;
    415	int ret;
    416
    417	ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
    418	if (ret) {
    419		dev_err(bc->dev, "failed to enable clocks\n");
    420		return ret;
    421	}
    422
    423	/* domain specific blk-ctrl manipulation */
    424	bc->power_off(bc, domain);
    425
    426	clk_bulk_disable_unprepare(data->num_clks, domain->clks);
    427
    428	/* power down upstream GPC domain */
    429	pm_runtime_put(domain->power_dev);
    430
    431	/* allow bus domain to suspend */
    432	pm_runtime_put(bc->bus_power_dev);
    433
    434	return 0;
    435}
    436
    437static struct generic_pm_domain *
    438imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
    439{
    440	struct genpd_onecell_data *onecell_data = data;
    441	unsigned int index = args->args[0];
    442
    443	if (args->args_count != 1 ||
    444	    index >= onecell_data->num_domains)
    445		return ERR_PTR(-EINVAL);
    446
    447	return onecell_data->domains[index];
    448}
    449
    450static struct lock_class_key blk_ctrl_genpd_lock_class;
    451
    452static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
    453{
    454	const struct imx8mp_blk_ctrl_data *bc_data;
    455	struct device *dev = &pdev->dev;
    456	struct imx8mp_blk_ctrl *bc;
    457	void __iomem *base;
    458	int num_domains, i, ret;
    459
    460	struct regmap_config regmap_config = {
    461		.reg_bits	= 32,
    462		.val_bits	= 32,
    463		.reg_stride	= 4,
    464	};
    465
    466	bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
    467	if (!bc)
    468		return -ENOMEM;
    469
    470	bc->dev = dev;
    471
    472	bc_data = of_device_get_match_data(dev);
    473	num_domains = bc_data->num_domains;
    474
    475	base = devm_platform_ioremap_resource(pdev, 0);
    476	if (IS_ERR(base))
    477		return PTR_ERR(base);
    478
    479	regmap_config.max_register = bc_data->max_reg;
    480	bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
    481	if (IS_ERR(bc->regmap))
    482		return dev_err_probe(dev, PTR_ERR(bc->regmap),
    483				     "failed to init regmap\n");
    484
    485	bc->domains = devm_kcalloc(dev, num_domains,
    486				   sizeof(struct imx8mp_blk_ctrl_domain),
    487				   GFP_KERNEL);
    488	if (!bc->domains)
    489		return -ENOMEM;
    490
    491	bc->onecell_data.num_domains = num_domains;
    492	bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
    493	bc->onecell_data.domains =
    494		devm_kcalloc(dev, num_domains,
    495			     sizeof(struct generic_pm_domain *), GFP_KERNEL);
    496	if (!bc->onecell_data.domains)
    497		return -ENOMEM;
    498
    499	bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
    500	if (IS_ERR(bc->bus_power_dev))
    501		return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
    502				     "failed to attach bus power domain\n");
    503
    504	bc->power_off = bc_data->power_off;
    505	bc->power_on = bc_data->power_on;
    506
    507	for (i = 0; i < num_domains; i++) {
    508		const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i];
    509		struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
    510		int j;
    511
    512		domain->data = data;
    513
    514		for (j = 0; j < data->num_clks; j++)
    515			domain->clks[j].id = data->clk_names[j];
    516
    517		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
    518		if (ret) {
    519			dev_err_probe(dev, ret, "failed to get clock\n");
    520			goto cleanup_pds;
    521		}
    522
    523		domain->power_dev =
    524			dev_pm_domain_attach_by_name(dev, data->gpc_name);
    525		if (IS_ERR(domain->power_dev)) {
    526			dev_err_probe(dev, PTR_ERR(domain->power_dev),
    527				      "failed to attach power domain %s\n",
    528				      data->gpc_name);
    529			ret = PTR_ERR(domain->power_dev);
    530			goto cleanup_pds;
    531		}
    532		dev_set_name(domain->power_dev, "%s", data->name);
    533
    534		domain->genpd.name = data->name;
    535		domain->genpd.power_on = imx8mp_blk_ctrl_power_on;
    536		domain->genpd.power_off = imx8mp_blk_ctrl_power_off;
    537		domain->bc = bc;
    538		domain->id = i;
    539
    540		ret = pm_genpd_init(&domain->genpd, NULL, true);
    541		if (ret) {
    542			dev_err_probe(dev, ret, "failed to init power domain\n");
    543			dev_pm_domain_detach(domain->power_dev, true);
    544			goto cleanup_pds;
    545		}
    546
    547		/*
    548		 * We use runtime PM to trigger power on/off of the upstream GPC
    549		 * domain, as a strict hierarchical parent/child power domain
    550		 * setup doesn't allow us to meet the sequencing requirements.
    551		 * This means we have nested locking of genpd locks, without the
    552		 * nesting being visible at the genpd level, so we need a
    553		 * separate lock class to make lockdep aware of the fact that
    554		 * this are separate domain locks that can be nested without a
    555		 * self-deadlock.
    556		 */
    557		lockdep_set_class(&domain->genpd.mlock,
    558				  &blk_ctrl_genpd_lock_class);
    559
    560		bc->onecell_data.domains[i] = &domain->genpd;
    561	}
    562
    563	ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
    564	if (ret) {
    565		dev_err_probe(dev, ret, "failed to add power domain provider\n");
    566		goto cleanup_pds;
    567	}
    568
    569	bc->power_nb.notifier_call = bc_data->power_notifier_fn;
    570	ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
    571	if (ret) {
    572		dev_err_probe(dev, ret, "failed to add power notifier\n");
    573		goto cleanup_provider;
    574	}
    575
    576	dev_set_drvdata(dev, bc);
    577
    578	return 0;
    579
    580cleanup_provider:
    581	of_genpd_del_provider(dev->of_node);
    582cleanup_pds:
    583	for (i--; i >= 0; i--) {
    584		pm_genpd_remove(&bc->domains[i].genpd);
    585		dev_pm_domain_detach(bc->domains[i].power_dev, true);
    586	}
    587
    588	dev_pm_domain_detach(bc->bus_power_dev, true);
    589
    590	return ret;
    591}
    592
    593static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
    594{
    595	struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
    596	int i;
    597
    598	of_genpd_del_provider(pdev->dev.of_node);
    599
    600	for (i = 0; bc->onecell_data.num_domains; i++) {
    601		struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
    602
    603		pm_genpd_remove(&domain->genpd);
    604		dev_pm_domain_detach(domain->power_dev, true);
    605	}
    606
    607	dev_pm_genpd_remove_notifier(bc->bus_power_dev);
    608
    609	dev_pm_domain_detach(bc->bus_power_dev, true);
    610
    611	return 0;
    612}
    613
    614#ifdef CONFIG_PM_SLEEP
    615static int imx8mp_blk_ctrl_suspend(struct device *dev)
    616{
    617	struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
    618	int ret, i;
    619
    620	/*
    621	 * This may look strange, but is done so the generic PM_SLEEP code
    622	 * can power down our domains and more importantly power them up again
    623	 * after resume, without tripping over our usage of runtime PM to
    624	 * control the upstream GPC domains. Things happen in the right order
    625	 * in the system suspend/resume paths due to the device parent/child
    626	 * hierarchy.
    627	 */
    628	ret = pm_runtime_get_sync(bc->bus_power_dev);
    629	if (ret < 0) {
    630		pm_runtime_put_noidle(bc->bus_power_dev);
    631		return ret;
    632	}
    633
    634	for (i = 0; i < bc->onecell_data.num_domains; i++) {
    635		struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
    636
    637		ret = pm_runtime_get_sync(domain->power_dev);
    638		if (ret < 0) {
    639			pm_runtime_put_noidle(domain->power_dev);
    640			goto out_fail;
    641		}
    642	}
    643
    644	return 0;
    645
    646out_fail:
    647	for (i--; i >= 0; i--)
    648		pm_runtime_put(bc->domains[i].power_dev);
    649
    650	pm_runtime_put(bc->bus_power_dev);
    651
    652	return ret;
    653}
    654
    655static int imx8mp_blk_ctrl_resume(struct device *dev)
    656{
    657	struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
    658	int i;
    659
    660	for (i = 0; i < bc->onecell_data.num_domains; i++)
    661		pm_runtime_put(bc->domains[i].power_dev);
    662
    663	pm_runtime_put(bc->bus_power_dev);
    664
    665	return 0;
    666}
    667#endif
    668
    669static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = {
    670	SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend,
    671				imx8mp_blk_ctrl_resume)
    672};
    673
    674static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
    675	{
    676		.compatible = "fsl,imx8mp-hsio-blk-ctrl",
    677		.data = &imx8mp_hsio_blk_ctl_dev_data,
    678	}, {
    679		.compatible = "fsl,imx8mp-hdmi-blk-ctrl",
    680		.data = &imx8mp_hdmi_blk_ctl_dev_data,
    681	}, {
    682		/* Sentinel */
    683	}
    684};
    685MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
    686
    687static struct platform_driver imx8mp_blk_ctrl_driver = {
    688	.probe = imx8mp_blk_ctrl_probe,
    689	.remove = imx8mp_blk_ctrl_remove,
    690	.driver = {
    691		.name = "imx8mp-blk-ctrl",
    692		.pm = &imx8mp_blk_ctrl_pm_ops,
    693		.of_match_table = imx8mp_blk_ctrl_of_match,
    694	},
    695};
    696module_platform_driver(imx8mp_blk_ctrl_driver);