Re: [PATCH 2/6] pmdomain: imx8mp-blk-ctrl: add media blk-ctrl power domain support

Ahmad Fatoum <[email protected]>
Newsgroups org.infradead.lists.barebox
Message-ID <[email protected]>
Hello,

On 6/2/26 6:09 AM, Johannes Schneider wrote:
> From: Thomas Haemmerle <[email protected]>
> 
> The i.MX8MP LCDIF2 controller lives inside the MEDIAMIX power domain,
> which has its own blk-ctrl to gate clocks and control resets.  Without
> enabling the MEDIAMIX bus clock and de-asserting the block-level resets
> before the first register access, any read or write to LCDIF2 registers
> causes an AXI bus hang and barebox locks up on startup.
> 
> Extend the existing blk-ctrl driver (currently HSIO-only) to support the
> media blk-ctrl (fsl,imx8mp-media-blk-ctrl) by:
> - Separating the HSIO ADB handshake into the HSIO-specific power_on hook
>   so the generic path is clean for other blk-ctrls without such handshake.
> - Adding null checks on bc->power_on/off to allow instances without custom
>   callbacks.
> - Increasing DOMAIN_MAX_CLKS from 2 to 3 (LCDIF2 needs disp2, axi, apb).
> - Adding media blk-ctrl probe that enables the MEDIAMIX bus clock and
>   de-asserts LCDIF2 clocks/resets, mirroring what the Linux kernel does
>   in imx8mp_media_power_notifier.
> 
> The media_blk_ctrl DTS node retains its syscon compatible so that
> syscon_node_to_regmap() continues to work for the LDB bridge sub-device.
> 
> Assisted-by: Claude:claude-sonnet-4-6
> Signed-of-by: Thomas Haemmerle <[email protected]>
> ---
>  drivers/pmdomain/imx/imx8mp-blk-ctrl.c | 117 +++++++++++++++++++++++--
>  1 file changed, 108 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
> index 3d302cbde7..87e0114c22 100644
> --- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
> +++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
> @@ -17,6 +17,7 @@
>  
>  #include <dt-bindings/power/imx8mp-power.h>
>  
> +/* HSIO blk-ctrl registers */
>  #define GPR_REG0		0x0
>  #define  PCIE_CLOCK_MODULE_EN	BIT(0)
>  #define  USB_CLOCK_MODULE_EN	BIT(1)
> @@ -32,6 +33,11 @@
>  #define  PLL_CKE		BIT(17)
>  #define  PLL_RST		BIT(31)
>  
> +/* Media blk-ctrl registers */
> +#define LCDIF_ARCACHE_CTRL	0x40
> +#define  LCDIF_1_RD_HURRY	GENMASK(6, 4)
> +#define  LCDIF_0_RD_HURRY	GENMASK(2, 0)
> +
>  struct imx8mp_blk_ctrl_domain;
>  
>  struct imx8mp_blk_ctrl {
> @@ -51,7 +57,7 @@ struct imx8mp_blk_ctrl_domain_data {
>  	const char *gpc_name;
>  };
>  
> -#define DOMAIN_MAX_CLKS 2
> +#define DOMAIN_MAX_CLKS 3
>  
>  struct imx8mp_blk_ctrl_domain {
>  	struct generic_pm_domain genpd;
> @@ -155,9 +161,14 @@ static int imx8mp_hsio_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc)
>  	return of_clk_add_hw_provider(dev_of_node(bc->dev), of_clk_hw_simple_get, hw);
>  }
>  
> +static int imx8mp_hsio_propagate_adb_handshake(struct imx8mp_blk_ctrl *bc);
> +
>  static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
>  					  struct imx8mp_blk_ctrl_domain *domain)
>  {
> +	/* propagate ADB handshake once before any HSIO sub-domain is enabled */
> +	imx8mp_hsio_propagate_adb_handshake(bc);

This used to happen _before_ enabling upstream clocks, but now it
happens _after_. The commit message doesn't explain why this would be ok.

Maybe Marco or Lucas have a thought on this?

Cheers,
Ahmad

> +
>  	switch (domain->id) {
>  	case IMX8MP_HSIOBLK_PD_USB:
>  		regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
> @@ -259,6 +270,66 @@ static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
>  	.num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
>  };
>  
> +/* Media blk-ctrl */
> +
> +/*
> + * MEDIAMIX BLK_CTRL register offsets (from i.MX 8M Plus RM, section 13).
> + * Bit SET = reset de-asserted / clock enabled.
> + */
> +#define BLK_SFT_RSTN		0x00
> +#define BLK_CLK_EN		0x04
> +
> +/* BIT(8): bus/APB clock and reset for the MEDIAMIX interconnect */
> +#define MEDIAMIX_BUS_CLK_RST	BIT(8)
> +
> +/*
> + * LCDIF2 (mediablk-lcdif-2) bits in BLK_SFT_RSTN and BLK_CLK_EN:
> + *   BIT(11): lcdif2-axi, BIT(12): lcdif2-apb, BIT(24): disp2 pixel clock
> + * (from Linux kernel imx8m-blk-ctrl.c IMX8MP_MEDIABLK_PD_LCDIF_2)
> + */
> +#define LCDIF2_CLK_RST_MASK	(BIT(11) | BIT(12) | BIT(24))
> +
> +static int imx8mp_media_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc)
> +{
> +	/* Set panic read hurry level for LCDIF interfaces to 7 */
> +	regmap_update_bits(bc->regmap, LCDIF_ARCACHE_CTRL,
> +			   FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
> +			   FIELD_PREP(LCDIF_0_RD_HURRY, 7),
> +			   FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
> +			   FIELD_PREP(LCDIF_0_RD_HURRY, 7));
> +
> +	/*
> +	 * Enable the MEDIAMIX bus clock and de-assert its reset so the
> +	 * internal AHB/APB fabric is up before sub-module access.
> +	 * (Mirrors Linux kernel imx8mp_media_power_notifier BIT(8) writes.)
> +	 */
> +	regmap_set_bits(bc->regmap, BLK_CLK_EN,  MEDIAMIX_BUS_CLK_RST);
> +	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, MEDIAMIX_BUS_CLK_RST);
> +	udelay(5); /* wait for ADB handshake, as Linux kernel does */
> +
> +	/*
> +	 * Enable LCDIF2 clocks and de-assert its reset within MEDIAMIX.
> +	 * Without this, LCDIF2 registers are inaccessible (AXI bus hangs).
> +	 * (Mirrors Linux kernel imx8mp_blk_ctrl_power_on for LCDIF_2 domain.)
> +	 */
> +	regmap_set_bits(bc->regmap, BLK_CLK_EN,  LCDIF2_CLK_RST_MASK);
> +	regmap_set_bits(bc->regmap, BLK_SFT_RSTN, LCDIF2_CLK_RST_MASK);
> +
> +	return 0;
> +}
> +
> +static const struct imx8mp_blk_ctrl_data imx8mp_media_blk_ctl_dev_data = {
> +	.max_reg = 0x138,
> +	.probe = imx8mp_media_blk_ctrl_probe,
> +	/*
> +	 * num_domains intentionally omitted (= 0): skip GPC power domain
> +	 * management for the media blk-ctrl.  MEDIAMIX is already powered
> +	 * on by the boot ROM/SPL, so no GPC sequencing is needed in the
> +	 * bootloader.  With barebox deep-probe enabled, lcdif2
> +	 * silently ignores the missing genpd provider and probes directly.
> +	 */
> +};
> +
>  static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
>  {
>  	struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
> @@ -273,12 +344,6 @@ static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
>  		return ret;
>  	}
>  
> -	ret = imx8mp_hsio_propagate_adb_handshake(bc);
> -	if (ret) {
> -		dev_err(bc->dev, "failed to propagate adb handshake\n");
> -		goto bus_put;
> -	}
> -
>  	/* enable upstream clocks */
>  	ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
>  	if (ret) {
> @@ -287,7 +352,8 @@ static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
>  	}
>  
>  	/* domain specific blk-ctrl manipulation */
> -	bc->power_on(bc, domain);
> +	if (bc->power_on)
> +		bc->power_on(bc, domain);
>  
>  	/* power up upstream GPC domain */
>  	ret = pm_runtime_resume_and_get_genpd(domain->power_dev);
> @@ -322,7 +388,8 @@ static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
>  	}
>  
>  	/* domain specific blk-ctrl manipulation */
> -	bc->power_off(bc, domain);
> +	if (bc->power_off)
> +		bc->power_off(bc, domain);
>  
>  	clk_bulk_disable_unprepare(data->num_clks, domain->clks);
>  
> @@ -380,6 +447,35 @@ static int imx8mp_blk_ctrl_probe(struct device *dev)
>  	if (!bc->onecell_data.domains)
>  		return -ENOMEM;
>  
> +	/*
> +	 * Skip GPC power domain management when num_domains == 0.
> +	 * This is used for blk-ctrl instances (e.g. media) where we only
> +	 * want the regmap/probe side-effects and not genpd provider
> +	 * registration, which could trigger GPC power-on sequences at
> +	 * unexpected times during boot.
> +	 */
> +	if (num_domains == 0) {
> +		/*
> +		 * For the media blk-ctrl we skip genpd provider registration to
> +		 * avoid triggering full GPC power sequencing for every consumer.
> +		 * However we still need the MEDIAMIX domain to be powered before
> +		 * accessing any of its registers (including blk-ctrl itself).
> +		 * Power it on via the "bus" domain and keep it on.
> +		 */
> +		bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus");
> +		if (!IS_ERR_OR_NULL(bc->bus_power_dev)) {
> +			ret = pm_runtime_resume_and_get_genpd(bc->bus_power_dev);
> +			if (ret < 0)
> +				dev_warn(dev, "failed to power on MEDIAMIX (ignoring): %d\n", ret);
> +		}
> +		if (bc_data->probe) {
> +			ret = bc_data->probe(bc);
> +			if (ret)
> +				return ret;
> +		}
> +		return 0;
> +	}
> +
>  	bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus");
>  	if (IS_ERR(bc->bus_power_dev))
>  		return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
> @@ -461,6 +557,9 @@ static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
>  	{
>  		.compatible = "fsl,imx8mp-hsio-blk-ctrl",
>  		.data = &imx8mp_hsio_blk_ctl_dev_data,
> +	}, {
> +		.compatible = "fsl,imx8mp-media-blk-ctrl",
> +		.data = &imx8mp_media_blk_ctl_dev_data,
>  	}, {
>  		/* Sentinel */
>  	}

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.