From 6aa38ef0eab32df5409b72d62509de6ba09cea50 Mon Sep 17 00:00:00 2001 From: Guoniu Zhou Date: Tue, 9 Jun 2026 14:26:40 +0800 Subject: [PATCH 1/4] dt-bindings: power: imx93: Add MIPI PHY power domain Add MIPI PHY power domain for shared PHY resources used by both MIPI DSI and CSI blocks. Signed-off-by: Guoniu Zhou Reviewed-by: Frank Li Acked-by: Krzysztof Kozlowski Reviewed-by: Peng Fan Fixes: e9aa77d413c9 ("soc: imx: add i.MX93 media blk ctrl driver") Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- include/dt-bindings/power/fsl,imx93-power.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/power/fsl,imx93-power.h b/include/dt-bindings/power/fsl,imx93-power.h index 17f9f015bf7d..071221fe5c57 100644 --- a/include/dt-bindings/power/fsl,imx93-power.h +++ b/include/dt-bindings/power/fsl,imx93-power.h @@ -11,5 +11,6 @@ #define IMX93_MEDIABLK_PD_PXP 2 #define IMX93_MEDIABLK_PD_LCDIF 3 #define IMX93_MEDIABLK_PD_ISI 4 +#define IMX93_MEDIABLK_PD_MIPI_PHY 5 #endif From 99611233f8cda833169fa6487d5dacdf189e5cb0 Mon Sep 17 00:00:00 2001 From: Guoniu Zhou Date: Tue, 9 Jun 2026 14:26:41 +0800 Subject: [PATCH 2/4] pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI The MIPI DSI and CSI domains share control bits for clock and reset, which can lead to incorrect behavior if one domain disables the shared resource while the other is still active. To fix the issue, introduce a shared MIPI PHY power domain to own the common resources and make DSI and CSI its subdomains. This ensures the shared bits are properly managed and not disabled while still in use. Fixes: e9aa77d413c9 ("soc: imx: add i.MX93 media blk ctrl driver") Cc: stable@vger.kernel.org Signed-off-by: Guoniu Zhou Reviewed-by: Frank Li Reviewed-by: Peng Fan Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx93-blk-ctrl.c | 60 ++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c index 1afc78b034fa..243ce939ba68 100644 --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c @@ -48,6 +48,8 @@ #define PRIO(X) (X) +#define BLK_CTRL_NO_PARENT UINT_MAX + struct imx93_blk_ctrl_domain; struct imx93_blk_ctrl { @@ -68,12 +70,18 @@ struct imx93_blk_ctrl_qos { u32 cfg_prio; }; +struct imx93_blk_ctrl_subdomain_link { + struct generic_pm_domain *parent; + struct generic_pm_domain *subdomain; +}; + struct imx93_blk_ctrl_domain_data { const char *name; const char * const *clk_names; int num_clks; u32 rst_mask; u32 clk_mask; + u32 parent; int num_qos; struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS]; }; @@ -203,6 +211,13 @@ static void imx93_release_pm_genpd(void *data) pm_genpd_remove(genpd); } +static void imx93_release_subdomain(void *data) +{ + struct imx93_blk_ctrl_subdomain_link *link = data; + + pm_genpd_remove_subdomain(link->parent, link->subdomain); +} + static struct lock_class_key blk_ctrl_genpd_lock_class; static int imx93_blk_ctrl_probe(struct platform_device *pdev) @@ -302,6 +317,34 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) bc->onecell_data.domains[i] = &domain->genpd; } + for (i = 0; i < bc_data->num_domains; i++) { + struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; + const struct imx93_blk_ctrl_domain_data *data = domain->data; + struct imx93_blk_ctrl_subdomain_link *link; + + if (bc_data->skip_mask & BIT(i) || + data->parent == BLK_CTRL_NO_PARENT) + continue; + + link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); + if (!link) + return -ENOMEM; + + link->parent = &bc->domains[data->parent].genpd; + link->subdomain = &domain->genpd; + + ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd, + &domain->genpd); + if (ret) + return dev_err_probe(dev, ret, "failed to add subdomain %s\n", + domain->genpd.name); + + ret = devm_add_action_or_reset(dev, imx93_release_subdomain, link); + if (ret) + return dev_err_probe(dev, ret, + "failed to add subdomain release callback\n"); + } + ret = devm_pm_runtime_enable(dev); if (ret) return dev_err_probe(dev, ret, "failed to enable pm-runtime\n"); @@ -326,8 +369,9 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] .name = "mediablk-mipi-dsi", .clk_names = (const char *[]){ "dsi" }, .num_clks = 1, - .rst_mask = BIT(11) | BIT(12), - .clk_mask = BIT(11) | BIT(12), + .rst_mask = BIT(11), + .clk_mask = BIT(11), + .parent = IMX93_MEDIABLK_PD_MIPI_PHY, }, [IMX93_MEDIABLK_PD_MIPI_CSI] = { .name = "mediablk-mipi-csi", @@ -335,6 +379,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] .num_clks = 2, .rst_mask = BIT(9) | BIT(10), .clk_mask = BIT(9) | BIT(10), + .parent = IMX93_MEDIABLK_PD_MIPI_PHY, }, [IMX93_MEDIABLK_PD_PXP] = { .name = "mediablk-pxp", @@ -342,6 +387,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] .num_clks = 1, .rst_mask = BIT(7) | BIT(8), .clk_mask = BIT(7) | BIT(8), + .parent = BLK_CTRL_NO_PARENT, .num_qos = 2, .qos = { { @@ -363,6 +409,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] .num_clks = 2, .rst_mask = BIT(4) | BIT(5) | BIT(6), .clk_mask = BIT(4) | BIT(5) | BIT(6), + .parent = BLK_CTRL_NO_PARENT, .num_qos = 1, .qos = { { @@ -379,6 +426,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] .num_clks = 1, .rst_mask = BIT(2) | BIT(3), .clk_mask = BIT(2) | BIT(3), + .parent = BLK_CTRL_NO_PARENT, .num_qos = 4, .qos = { { @@ -404,6 +452,14 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] } } }, + [IMX93_MEDIABLK_PD_MIPI_PHY] = { + .name = "mediablk-mipi-phy", + .clk_names = NULL, + .num_clks = 0, + .rst_mask = BIT(12), + .clk_mask = BIT(12), + .parent = BLK_CTRL_NO_PARENT, + }, }; static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = { From 72422525f641f68bed6ca3389d29ee3f41fdea33 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jun 2026 22:39:10 +0800 Subject: [PATCH 3/4] pmdomain: imx: Fix i.MX8MP power notifier Using imx8mm_vpu_power_notifier() for i.MX8MP is wrong, as it ungates the VPU clocks to provide the ADB clock, which is necessary on i.MX8MM, but on i.MX8MP there is a separate gate (bit 3) for the NoC. So add imx8mp_vpu_power_notifier() for i.MX8MP. Fixes: a1a5f15f7f6cb ("soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl") Cc: stable@vger.kernel.org Reviewed-by: Frank Li Signed-off-by: Peng Fan Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx8m-blk-ctrl.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c index 19e992d2ee3b..e13a47eeed75 100644 --- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c @@ -514,9 +514,34 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[] }, }; +static int imx8mp_vpu_power_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl, + power_nb); + + if (action == GENPD_NOTIFY_ON) { + /* + * On power up we have no software backchannel to the GPC to + * wait for the ADB handshake to happen, so we just delay for a + * bit. On power down the GPC driver waits for the handshake. + */ + + udelay(5); + + /* set "fuse" bits to enable the VPUs */ + regmap_set_bits(bc->regmap, 0x8, 0xffffffff); + regmap_set_bits(bc->regmap, 0xc, 0xffffffff); + regmap_set_bits(bc->regmap, 0x10, 0xffffffff); + regmap_set_bits(bc->regmap, 0x14, 0xffffffff); + } + + return NOTIFY_OK; +} + static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = { .max_reg = 0x18, - .power_notifier_fn = imx8mm_vpu_power_notifier, + .power_notifier_fn = imx8mp_vpu_power_notifier, .domains = imx8mp_vpu_blk_ctl_domain_data, .num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data), }; From 25e252bcf1593b420b12a7231d9dd64b885a2ae2 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jun 2026 22:39:11 +0800 Subject: [PATCH 4/4] pmdomain: imx: Fix i.MX8MP VC8000E power up sequence Per errata[1]: ERR050531: VPU_NOC power down handshake may hang during VC8000E/VPUMIX power up/down cycling. Description: VC8000E reset de-assertion edge and AXI clock may have a timing issue. Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is de-asserted by HW) Add a bool variable is_errata_err050531 in 'struct imx8m_blk_ctrl_domain_data' to represent whether the workaround is needed. If is_errata_err050531 is true, first clear the clk before powering up gpc, then enable the clk after powering up gpc. [1] https://www.nxp.com/webapp/Download?colCode=IMX8MP_1P33A Fixes: a1a5f15f7f6cb ("soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl") Cc: stable@vger.kernel.org Signed-off-by: Peng Fan Reviewed-by: Frank Li Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/imx8m-blk-ctrl.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c index e13a47eeed75..99d100e1d923 100644 --- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c @@ -54,6 +54,15 @@ struct imx8m_blk_ctrl_domain_data { * register. */ u32 mipi_phy_rst_mask; + + /* + * VC8000E reset de-assertion edge and AXI clock may have a timing issue. + * Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off + * both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to + * VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is + * de-asserted by HW) + */ + bool is_errata_err050531; }; #define DOMAIN_MAX_CLKS 4 @@ -108,7 +117,11 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd) dev_err(bc->dev, "failed to enable clocks\n"); goto bus_put; } - regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); + + if (data->is_errata_err050531) + regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); + else + regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); /* power up upstream GPC domain */ ret = pm_runtime_get_sync(domain->power_dev); @@ -117,6 +130,9 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd) goto clk_disable; } + if (data->is_errata_err050531) + regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); + /* wait for reset to propagate */ udelay(5); @@ -511,6 +527,7 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[] .clk_mask = BIT(2), .path_names = (const char *[]){"vc8000e"}, .num_paths = 1, + .is_errata_err050531 = true, }, };