[PATCH v2 03/11] pmdomain: imx8mp-blk-ctrl: add media blk-ctrl power domain support
Johannes Schneider
johannes.schneider at leica-geosystems.com
Wed Jun 3 23:49:58 PDT 2026
From: Thomas Haemmerle <thomas.haemmerle at leica-geosystems.com>
The i.MX8MP LCDIF2 sits inside MEDIAMIX, whose blk-ctrl gates clocks
and holds resets. Without enabling the MEDIAMIX bus clock and
de-asserting LCDIF2's block-level resets, the first register access
to LCDIF2 AXI-hangs barebox.
Extend the existing HSIO-only blk-ctrl driver for fsl,imx8mp-media-
blk-ctrl:
- Route the HSIO ADB handshake through a new pre_power_on hook so
the generic power_on path calls it *before* clk_bulk_prepare_enable,
preserving v1's ordering while keeping HSIO specifics off the
generic path.
- NULL-check bc->power_on/off so blk-ctrls without per-domain
callbacks (e.g. media) work.
- Bump DOMAIN_MAX_CLKS from 2 to 3 (LCDIF2 needs disp2, axi, apb).
- Add an imx8mp_media_blk_ctrl_probe that maxes the LCDIF NoC
read-hurry, brings the MEDIAMIX fabric up, and de-asserts LCDIF2
clocks + resets, mirroring imx8mp_media_power_notifier in Linux.
The media_blk_ctrl DTS node keeps its syscon compatible so the LDB
bridge sub-device can still get the regmap via syscon_node_to_regmap().
Signed-off-by: Thomas Haemmerle <thomas.haemmerle at leica-geosystems.com>
---
drivers/pmdomain/imx/imx8mp-blk-ctrl.c | 91 ++++++++++++++++++++++++--
1 file changed, 84 insertions(+), 7 deletions(-)
diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
index 3d302cbde7..3db26e91b3 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 {
@@ -40,6 +46,7 @@ struct imx8mp_blk_ctrl {
struct regmap *regmap;
struct imx8mp_blk_ctrl_domain *domains;
struct genpd_onecell_data onecell_data;
+ int (*pre_power_on) (struct imx8mp_blk_ctrl *bc);
void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
};
@@ -51,7 +58,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;
@@ -65,6 +72,7 @@ struct imx8mp_blk_ctrl_domain {
struct imx8mp_blk_ctrl_data {
int max_reg;
int (*probe) (struct imx8mp_blk_ctrl *bc);
+ int (*pre_power_on) (struct imx8mp_blk_ctrl *bc);
void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
const struct imx8mp_blk_ctrl_domain_data *domains;
@@ -253,12 +261,52 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
.max_reg = 0x24,
.probe = imx8mp_hsio_blk_ctrl_probe,
+ .pre_power_on = imx8mp_hsio_propagate_adb_handshake,
.power_on = imx8mp_hsio_blk_ctrl_power_on,
.power_off = imx8mp_hsio_blk_ctrl_power_off,
.domains = imx8mp_hsio_domain_data,
.num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
};
+/* Media blk-ctrl */
+
+/* MEDIAMIX BLK_CTRL register offsets (i.MX 8M Plus RM section 13) */
+#define BLK_SFT_RSTN 0x00
+#define BLK_CLK_EN 0x04
+
+/* MEDIAMIX bus/APB clock + reset */
+#define MEDIAMIX_BUS_CLK_RST BIT(8)
+
+/* LCDIF2 in BLK_SFT_RSTN/BLK_CLK_EN: axi (11), apb (12), disp2 pixel (24) */
+#define LCDIF2_CLK_RST_MASK (BIT(11) | BIT(12) | BIT(24))
+
+static int imx8mp_media_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc)
+{
+ /* maximize LCDIF NoC AXI read priority to avoid scanout underflow */
+ 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));
+
+ /* bring MEDIAMIX fabric up before any sub-module access */
+ 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); /* ADB handshake settle */
+
+ /* LCDIF2 registers AXI-hang until its own clocks + reset are de-asserted */
+ 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 = 0: skip genpd; MEDIAMIX is already on from SPL */
+};
+
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,10 +321,12 @@ 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;
+ if (bc->pre_power_on) {
+ ret = bc->pre_power_on(bc);
+ if (ret) {
+ dev_err(bc->dev, "pre_power_on failed: %d\n", ret);
+ goto bus_put;
+ }
}
/* enable upstream clocks */
@@ -287,7 +337,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 +373,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 +432,27 @@ static int imx8mp_blk_ctrl_probe(struct device *dev)
if (!bc->onecell_data.domains)
return -ENOMEM;
+ /*
+ * num_domains == 0: blk-ctrl instances (e.g. media) that only need
+ * the regmap/probe side-effects and no genpd provider. Power on
+ * the bus domain so the blk-ctrl's own registers are accessible,
+ * then run its probe and return.
+ */
+ if (num_domains == 0) {
+ 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),
@@ -387,6 +460,7 @@ static int imx8mp_blk_ctrl_probe(struct device *dev)
bc->power_off = bc_data->power_off;
bc->power_on = bc_data->power_on;
+ bc->pre_power_on = bc_data->pre_power_on;
for (i = 0; i < num_domains; i++) {
const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i];
@@ -461,6 +535,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 */
}
--
2.43.0
More information about the barebox
mailing list