From: Michael Trimarchi <mich...@amarulasolutions.com>

Add iMX8 block ctrl driver for displaymix on iMX8MM/iMX8MN and
mediamix on iMX8MP.

To support blk ctrl driver, the power domain driver on iMX8M needs
update to add relevant PGC domains

Signed-off-by: Ye Li <ye...@nxp.com>
Signed-off-by: Michael Trimarchi <mich...@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binac...@amarulasolutions.com>
---

 drivers/power/domain/Kconfig              |   6 +
 drivers/power/domain/Makefile             |   1 +
 drivers/power/domain/imx8m-blk-ctrl.c     | 438 ++++++++++++++++++++++
 drivers/power/domain/imx8m-power-domain.c | 213 ++++++++++-
 4 files changed, 656 insertions(+), 2 deletions(-)
 create mode 100644 drivers/power/domain/imx8m-blk-ctrl.c

diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index bd82d2f7044b..fb006b6e8e28 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -40,6 +40,12 @@ config IMX8M_POWER_DOMAIN
          Enable support for manipulating NXP i.MX8M on-SoC power domains via
          requests to the ATF.
 
+config IMX8M_BLK_CTRL
+       bool "Enable i.MX8M block control driver"
+       depends on POWER_DOMAIN && ARCH_IMX8M
+       help
+         Enable support for manipulating NXP i.MX8M on-SoC block control driver
+
 config IMX8MP_HSIOMIX_BLKCTRL
        bool "Enable i.MX8MP HSIOMIX domain driver"
        depends on POWER_DOMAIN && IMX8MP
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 2daab73eb758..46849fd2a4db 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o
 obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
 obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o 
imx8-power-domain.o
 obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o
+obj-$(CONFIG_IMX8M_BLK_CTRL) += imx8m-blk-ctrl.o
 obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o
 obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
 obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
diff --git a/drivers/power/domain/imx8m-blk-ctrl.c 
b/drivers/power/domain/imx8m-blk-ctrl.c
new file mode 100644
index 000000000000..4c89078b991b
--- /dev/null
+++ b/drivers/power/domain/imx8m-blk-ctrl.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 NXP
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain-uclass.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <dt-bindings/power/imx8mm-power.h>
+#include <dt-bindings/power/imx8mn-power.h>
+#include <dt-bindings/power/imx8mp-power.h>
+#include <clk.h>
+#include <linux/delay.h>
+
+#define BLK_SFT_RSTN   0x0
+#define BLK_CLK_EN     0x4
+#define BLK_MIPI_RESET_DIV     0x8 /* Mini/Nano/Plus DISPLAY_BLK_CTRL only */
+
+#define DOMAIN_MAX_CLKS 4
+
+struct imx8m_blk_ctrl_domain {
+       struct clk clks[DOMAIN_MAX_CLKS];
+       struct power_domain power_dev;
+};
+
+struct imx8m_blk_ctrl {
+       void __iomem *base;
+       struct power_domain bus_power_dev;
+       struct imx8m_blk_ctrl_domain *domains;
+};
+
+struct imx8m_blk_ctrl_domain_data {
+       const char *name;
+       const char * const *clk_names;
+       const char *gpc_name;
+       int num_clks;
+       u32 rst_mask;
+       u32 clk_mask;
+       u32 mipi_phy_rst_mask;
+};
+
+struct imx8m_blk_ctrl_data {
+       int max_reg;
+       const struct imx8m_blk_ctrl_domain_data *domains;
+       int num_domains;
+       u32 bus_rst_mask;
+       u32 bus_clk_mask;
+};
+
+static int imx8m_blk_ctrl_request(struct power_domain *power_domain)
+{
+       return 0;
+}
+
+static int imx8m_blk_ctrl_free(struct power_domain *power_domain)
+{
+       return 0;
+}
+
+static int imx8m_blk_ctrl_enable_domain_clk(struct udevice *dev, ulong 
domain_id, bool enable)
+{
+       int ret, i;
+       struct imx8m_blk_ctrl *priv = (struct imx8m_blk_ctrl 
*)dev_get_priv(dev);
+       struct imx8m_blk_ctrl_data *drv_data =
+               (struct imx8m_blk_ctrl_data *)dev_get_driver_data(dev);
+
+       debug("%s num_clk %u\n", __func__, 
drv_data->domains[domain_id].num_clks);
+
+       for (i = 0; i < drv_data->domains[domain_id].num_clks; i++) {
+               debug("%s clk %s\n", __func__, 
drv_data->domains[domain_id].clk_names[i]);
+               if (enable)
+                       ret = clk_enable(&priv->domains[domain_id].clks[i]);
+               else
+                       ret = clk_disable(&priv->domains[domain_id].clks[i]);
+               if (ret && ret != -ENOENT) {
+                       printf("Failed to %s domain clk %s\n", enable ? 
"enable" : "disable",
+                              drv_data->domains[domain_id].clk_names[i]);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int imx8m_blk_ctrl_power_on(struct power_domain *power_domain)
+{
+       struct udevice *dev = power_domain->dev;
+       struct imx8m_blk_ctrl *priv = (struct imx8m_blk_ctrl 
*)dev_get_priv(dev);
+       struct imx8m_blk_ctrl_data *drv_data =
+               (struct imx8m_blk_ctrl_data *)dev_get_driver_data(dev);
+       int ret;
+
+       debug("%s, id %lu\n", __func__, power_domain->id);
+
+       if (!priv->domains[power_domain->id].power_dev.dev)
+               return -ENODEV;
+
+       ret = power_domain_on(&priv->bus_power_dev);
+       if (ret < 0) {
+               printf("Failed to power up bus domain %d\n", ret);
+               return ret;
+       }
+
+       /* Enable bus clock and deassert bus reset */
+       setbits_le32(priv->base + BLK_CLK_EN, drv_data->bus_clk_mask);
+       setbits_le32(priv->base + BLK_SFT_RSTN, drv_data->bus_rst_mask);
+
+       /* wait for reset to propagate */
+       udelay(5);
+
+       /* put devices into reset */
+       clrbits_le32(priv->base + BLK_SFT_RSTN, 
drv_data->domains[power_domain->id].rst_mask);
+       if (drv_data->domains[power_domain->id].mipi_phy_rst_mask)
+               clrbits_le32(priv->base + BLK_MIPI_RESET_DIV, d
+                            
rv_data->domains[power_domain->id].mipi_phy_rst_mask);
+
+       /* enable upstream and blk-ctrl clocks to allow reset to propagate */
+       ret = imx8m_blk_ctrl_enable_domain_clk(dev, power_domain->id, true);
+       if (ret) {
+               printf("failed to enable clocks\n");
+               goto bus_powerdown;
+       }
+
+       /* ungate clk */
+       setbits_le32(priv->base + BLK_CLK_EN, 
drv_data->domains[power_domain->id].clk_mask);
+
+       /* power up upstream GPC domain */
+       ret = power_domain_on(&priv->domains[power_domain->id].power_dev);
+       if (ret < 0) {
+               printf("Failed to power up peripheral domain %d\n", ret);
+               goto clk_disable;
+       }
+
+       /* wait for reset to propagate */
+       udelay(5);
+
+       /* release reset */
+       setbits_le32(priv->base + BLK_SFT_RSTN, 
drv_data->domains[power_domain->id].rst_mask);
+       if (drv_data->domains[power_domain->id].mipi_phy_rst_mask)
+               setbits_le32(priv->base + BLK_MIPI_RESET_DIV,
+                            
drv_data->domains[power_domain->id].mipi_phy_rst_mask);
+
+       return 0;
+clk_disable:
+       imx8m_blk_ctrl_enable_domain_clk(dev, power_domain->id, false);
+bus_powerdown:
+       power_domain_off(&priv->bus_power_dev);
+       return ret;
+}
+
+static int imx8m_blk_ctrl_power_off(struct power_domain *power_domain)
+{
+       struct udevice *dev = power_domain->dev;
+       struct imx8m_blk_ctrl *priv = (struct imx8m_blk_ctrl 
*)dev_get_priv(dev);
+       struct imx8m_blk_ctrl_data *drv_data =
+               (struct imx8m_blk_ctrl_data *)dev_get_driver_data(dev);
+
+       debug("%s, id %lu\n", __func__, power_domain->id);
+
+       if (!priv->domains[power_domain->id].power_dev.dev)
+               return -ENODEV;
+
+       /* put devices into reset and disable clocks */
+       if (drv_data->domains[power_domain->id].mipi_phy_rst_mask)
+               clrbits_le32(priv->base + BLK_MIPI_RESET_DIV,
+                            
drv_data->domains[power_domain->id].mipi_phy_rst_mask);
+
+       /* assert reset */
+       clrbits_le32(priv->base + BLK_SFT_RSTN, 
drv_data->domains[power_domain->id].rst_mask);
+
+       /* gate clk */
+       clrbits_le32(priv->base + BLK_CLK_EN, 
drv_data->domains[power_domain->id].clk_mask);
+
+       /* power down upstream GPC domain */
+       power_domain_off(&priv->domains[power_domain->id].power_dev);
+
+       imx8m_blk_ctrl_enable_domain_clk(dev, power_domain->id, false);
+
+       /* power down bus domain */
+       power_domain_off(&priv->bus_power_dev);
+
+       return 0;
+}
+
+static int imx8m_blk_ctrl_probe(struct udevice *dev)
+{
+       int ret, i, j;
+       struct imx8m_blk_ctrl *priv = (struct imx8m_blk_ctrl 
*)dev_get_priv(dev);
+       struct imx8m_blk_ctrl_data *drv_data =
+               (struct imx8m_blk_ctrl_data *)dev_get_driver_data(dev);
+
+       priv->base = dev_read_addr_ptr(dev);
+       if (!priv->base)
+               return -EINVAL;
+
+       priv->domains = kcalloc(drv_data->num_domains,
+                               sizeof(struct imx8m_blk_ctrl_domain), 
GFP_KERNEL);
+
+       ret = power_domain_get_by_name(dev, &priv->bus_power_dev, "bus");
+       if (ret) {
+               printf("Failed to power_domain_get_by_name %s\n", "bus");
+               return ret;
+       }
+
+       for (j = 0; j < drv_data->num_domains; j++) {
+               ret = power_domain_get_by_name(dev, &priv->domains[j].power_dev,
+                                              drv_data->domains[j].gpc_name);
+               if (ret)
+                       continue;
+
+               for (i = 0; i < drv_data->domains[j].num_clks; i++) {
+                       ret = clk_get_by_name(dev, 
drv_data->domains[j].clk_names[i],
+                                             &priv->domains[j].clks[i]);
+                       if (ret) {
+                               printf("Failed to get clk %s\n", 
drv_data->domains[j].clk_names[i]);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int imx8m_blk_ctrl_remove(struct udevice *dev)
+{
+       struct imx8m_blk_ctrl *priv = (struct imx8m_blk_ctrl 
*)dev_get_priv(dev);
+
+       kfree(priv->domains);
+
+       return 0;
+}
+
+static const struct imx8m_blk_ctrl_domain_data 
imx8mm_disp_blk_ctl_domain_data[] = {
+       [IMX8MM_DISPBLK_PD_CSI_BRIDGE] = {
+               .name = "dispblk-csi-bridge",
+               .clk_names = (const char *[]){ "csi-bridge-axi", 
"csi-bridge-apb",
+                                              "csi-bridge-core", },
+               .num_clks = 3,
+               .gpc_name = "csi-bridge",
+               .rst_mask = BIT(0) | BIT(1) | BIT(2),
+               .clk_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
+       },
+       [IMX8MM_DISPBLK_PD_LCDIF] = {
+               .name = "dispblk-lcdif",
+               .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", 
"lcdif-pix", },
+               .num_clks = 3,
+               .gpc_name = "lcdif",
+               .clk_mask = BIT(6) | BIT(7),
+       },
+       [IMX8MM_DISPBLK_PD_MIPI_DSI] = {
+               .name = "dispblk-mipi-dsi",
+               .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
+               .num_clks = 2,
+               .gpc_name = "mipi-dsi",
+               .rst_mask = BIT(5),
+               .clk_mask = BIT(8) | BIT(9),
+               .mipi_phy_rst_mask = BIT(17),
+       },
+       [IMX8MM_DISPBLK_PD_MIPI_CSI] = {
+               .name = "dispblk-mipi-csi",
+               .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
+               .num_clks = 2,
+               .gpc_name = "mipi-csi",
+               .rst_mask = BIT(3) | BIT(4),
+               .clk_mask = BIT(10) | BIT(11),
+               .mipi_phy_rst_mask = BIT(16),
+       },
+};
+
+static const struct imx8m_blk_ctrl_data imx8mm_disp_blk_ctl_dev_data = {
+       .max_reg = 0x2c,
+       .domains = imx8mm_disp_blk_ctl_domain_data,
+       .num_domains = ARRAY_SIZE(imx8mm_disp_blk_ctl_domain_data),
+       .bus_rst_mask = BIT(6),
+       .bus_clk_mask = BIT(12),
+};
+
+static const struct imx8m_blk_ctrl_domain_data 
imx8mn_disp_blk_ctl_domain_data[] = {
+       [IMX8MN_DISPBLK_PD_MIPI_DSI] = {
+               .name = "dispblk-mipi-dsi",
+               .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
+               .num_clks = 2,
+               .gpc_name = "mipi-dsi",
+               .rst_mask = BIT(0) | BIT(1),
+               .clk_mask = BIT(0) | BIT(1),
+               .mipi_phy_rst_mask = BIT(17),
+       },
+       [IMX8MN_DISPBLK_PD_MIPI_CSI] = {
+               .name = "dispblk-mipi-csi",
+               .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
+               .num_clks = 2,
+               .gpc_name = "mipi-csi",
+               .rst_mask = BIT(2) | BIT(3),
+               .clk_mask = BIT(2) | BIT(3),
+               .mipi_phy_rst_mask = BIT(16),
+       },
+       [IMX8MN_DISPBLK_PD_LCDIF] = {
+               .name = "dispblk-lcdif",
+               .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", 
"lcdif-pix", },
+               .num_clks = 3,
+               .gpc_name = "lcdif",
+               .rst_mask = BIT(4) | BIT(5),
+               .clk_mask = BIT(4) | BIT(5),
+       },
+       [IMX8MN_DISPBLK_PD_ISI] = {
+               .name = "dispblk-isi",
+               .clk_names = (const char *[]){ "disp_axi", "disp_apb", 
"disp_axi_root",
+                                               "disp_apb_root"},
+               .num_clks = 4,
+               .gpc_name = "isi",
+               .rst_mask = BIT(6) | BIT(7),
+               .clk_mask = BIT(6) | BIT(7),
+       },
+};
+
+static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
+       .max_reg = 0x84,
+       .domains = imx8mn_disp_blk_ctl_domain_data,
+       .num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
+       .bus_rst_mask = BIT(8),
+       .bus_clk_mask = BIT(8),
+};
+
+static const struct imx8m_blk_ctrl_domain_data 
imx8mp_media_blk_ctl_domain_data[] = {
+       [IMX8MP_MEDIABLK_PD_MIPI_DSI_1] = {
+               .name = "mediablk-mipi-dsi-1",
+               .clk_names = (const char *[]){ "apb", "phy", },
+               .num_clks = 2,
+               .gpc_name = "mipi-dsi1",
+               .rst_mask = BIT(0) | BIT(1),
+               .clk_mask = BIT(0) | BIT(1),
+               .mipi_phy_rst_mask = BIT(17),
+       },
+       [IMX8MP_MEDIABLK_PD_MIPI_CSI2_1] = {
+               .name = "mediablk-mipi-csi2-1",
+               .clk_names = (const char *[]){ "apb", "cam1" },
+               .num_clks = 2,
+               .gpc_name = "mipi-csi1",
+               .rst_mask = BIT(2) | BIT(3),
+               .clk_mask = BIT(2) | BIT(3),
+               .mipi_phy_rst_mask = BIT(16),
+       },
+       [IMX8MP_MEDIABLK_PD_LCDIF_1] = {
+               .name = "mediablk-lcdif-1",
+               .clk_names = (const char *[]){ "disp1", "apb", "axi", },
+               .num_clks = 3,
+               .gpc_name = "lcdif1",
+               .rst_mask = BIT(4) | BIT(5) | BIT(23),
+               .clk_mask = BIT(4) | BIT(5) | BIT(23),
+       },
+       [IMX8MP_MEDIABLK_PD_ISI] = {
+               .name = "mediablk-isi",
+               .clk_names = (const char *[]){ "axi", "apb" },
+               .num_clks = 2,
+               .gpc_name = "isi",
+               .rst_mask = BIT(6) | BIT(7),
+               .clk_mask = BIT(6) | BIT(7),
+       },
+       [IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
+               .name = "mediablk-mipi-csi2-2",
+               .clk_names = (const char *[]){ "apb", "cam2" },
+               .num_clks = 2,
+               .gpc_name = "mipi-csi2",
+               .rst_mask = BIT(9) | BIT(10),
+               .clk_mask = BIT(9) | BIT(10),
+               .mipi_phy_rst_mask = BIT(30),
+       },
+       [IMX8MP_MEDIABLK_PD_LCDIF_2] = {
+               .name = "mediablk-lcdif-2",
+               .clk_names = (const char *[]){ "disp2", "apb", "axi", },
+               .num_clks = 3,
+               .gpc_name = "lcdif2",
+               .rst_mask = BIT(11) | BIT(12) | BIT(24),
+               .clk_mask = BIT(11) | BIT(12) | BIT(24),
+       },
+       [IMX8MP_MEDIABLK_PD_ISP] = {
+               .name = "mediablk-isp",
+               .clk_names = (const char *[]){ "isp", "axi", "apb" },
+               .num_clks = 3,
+               .gpc_name = "isp",
+               .rst_mask = BIT(16) | BIT(17) | BIT(18),
+               .clk_mask = BIT(16) | BIT(17) | BIT(18),
+       },
+       [IMX8MP_MEDIABLK_PD_DWE] = {
+               .name = "mediablk-dwe",
+               .clk_names = (const char *[]){ "axi", "apb" },
+               .num_clks = 2,
+               .gpc_name = "dwe",
+               .rst_mask = BIT(19) | BIT(20) | BIT(21),
+               .clk_mask = BIT(19) | BIT(20) | BIT(21),
+       },
+       [IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
+               .name = "mediablk-mipi-dsi-2",
+               .clk_names = (const char *[]){ "phy", },
+               .num_clks = 1,
+               .gpc_name = "mipi-dsi2",
+               .rst_mask = BIT(22),
+               .clk_mask = BIT(22),
+               .mipi_phy_rst_mask = BIT(29),
+       },
+};
+
+static const struct imx8m_blk_ctrl_data imx8mp_media_blk_ctl_dev_data = {
+       .max_reg = 0x138,
+       .domains = imx8mp_media_blk_ctl_domain_data,
+       .num_domains = ARRAY_SIZE(imx8mp_media_blk_ctl_domain_data),
+       .bus_rst_mask = BIT(8),
+       .bus_clk_mask = BIT(8),
+};
+
+static const struct udevice_id imx8m_blk_ctrl_ids[] = {
+       {.compatible = "fsl,imx8mm-disp-blk-ctrl", .data = 
(ulong)&imx8mm_disp_blk_ctl_dev_data},
+       {.compatible = "fsl,imx8mn-disp-blk-ctrl", .data = 
(ulong)&imx8mn_disp_blk_ctl_dev_data},
+       {.compatible = "fsl,imx8mp-media-blk-ctrl", .data = 
(ulong)&imx8mp_media_blk_ctl_dev_data},
+       {}
+};
+
+struct power_domain_ops imx8m_blk_ctrl_ops = {
+       .request = imx8m_blk_ctrl_request,
+       .rfree = imx8m_blk_ctrl_free,
+       .on = imx8m_blk_ctrl_power_on,
+       .off = imx8m_blk_ctrl_power_off,
+};
+
+U_BOOT_DRIVER(imx8m_blk_ctrl) = {
+       .name = "imx8m_blk_ctrl",
+       .id = UCLASS_POWER_DOMAIN,
+       .of_match = imx8m_blk_ctrl_ids,
+       .bind = dm_scan_fdt_dev,
+       .probe = imx8m_blk_ctrl_probe,
+       .remove = imx8m_blk_ctrl_remove,
+       .priv_auto      = sizeof(struct imx8m_blk_ctrl),
+       .ops = &imx8m_blk_ctrl_ops,
+       .flags  = DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/power/domain/imx8m-power-domain.c 
b/drivers/power/domain/imx8m-power-domain.c
index 8b6870c86463..40fec70d954a 100644
--- a/drivers/power/domain/imx8m-power-domain.c
+++ b/drivers/power/domain/imx8m-power-domain.c
@@ -32,17 +32,31 @@ DECLARE_GLOBAL_DATA_PTR;
 #define IMX8M_OTG1_A53_DOMAIN                  BIT(4)
 #define IMX8M_PCIE1_A53_DOMAIN                 BIT(3)
 
+#define IMX8MM_VPUH1_A53_DOMAIN                        BIT(15)
+#define IMX8MM_VPUG2_A53_DOMAIN                        BIT(14)
+#define IMX8MM_VPUG1_A53_DOMAIN                        BIT(13)
+#define IMX8MM_DISPMIX_A53_DOMAIN              BIT(12)
+#define IMX8MM_VPUMIX_A53_DOMAIN               BIT(10)
+#define IMX8MM_GPUMIX_A53_DOMAIN               BIT(9)
+#define IMX8MM_GPU_A53_DOMAIN                  (BIT(8) | BIT(11))
+#define IMX8MM_DDR1_A53_DOMAIN                 BIT(7)
 #define IMX8MM_OTG2_A53_DOMAIN                 BIT(5)
 #define IMX8MM_OTG1_A53_DOMAIN                 BIT(4)
 #define IMX8MM_PCIE_A53_DOMAIN                 BIT(3)
+#define IMX8MM_MIPI_A53_DOMAIN                 BIT(2)
 
+#define IMX8MN_DISPMIX_A53_DOMAIN              BIT(12)
+#define IMX8MN_GPUMIX_A53_DOMAIN               BIT(9)
+#define IMX8MN_DDR1_A53_DOMAIN         BIT(7)
 #define IMX8MN_OTG1_A53_DOMAIN                 BIT(4)
 #define IMX8MN_MIPI_A53_DOMAIN                 BIT(2)
 
 #define IMX8MP_HSIOMIX_A53_DOMAIN              BIT(19)
+#define IMX8MP_MEDIAMIX_A53_DOMAIN             BIT(12)
 #define IMX8MP_USB2_PHY_A53_DOMAIN             BIT(5)
 #define IMX8MP_USB1_PHY_A53_DOMAIN             BIT(4)
 #define IMX8MP_PCIE_PHY_A53_DOMAIN             BIT(3)
+#define IMX8MP_MIPI_PHY1_A53_DOMAIN            BIT(2)
 
 #define IMX8MP_GPC_PU_PGC_SW_PUP_REQ           0x0d8
 #define IMX8MP_GPC_PU_PGC_SW_PDN_REQ           0x0e4
@@ -50,35 +64,72 @@ DECLARE_GLOBAL_DATA_PTR;
 #define GPC_PU_PGC_SW_PUP_REQ                  0x0f8
 #define GPC_PU_PGC_SW_PDN_REQ                  0x104
 
+#define IMX8M_PCIE2_SW_Pxx_REQ                 BIT(13)
+#define IMX8M_MIPI_CSI2_SW_Pxx_REQ             BIT(12)
+#define IMX8M_MIPI_CSI1_SW_Pxx_REQ             BIT(11)
+#define IMX8M_DISP_SW_Pxx_REQ                  BIT(10)
+#define IMX8M_HDMI_SW_Pxx_REQ                  BIT(9)
+#define IMX8M_VPU_SW_Pxx_REQ                   BIT(8)
+#define IMX8M_GPU_SW_Pxx_REQ                   BIT(7)
+#define IMX8M_DDR2_SW_Pxx_REQ                  BIT(6)
+#define IMX8M_DDR1_SW_Pxx_REQ                  BIT(5)
 #define IMX8M_PCIE2_SW_Pxx_REQ                 BIT(13)
 #define IMX8M_OTG2_SW_Pxx_REQ                  BIT(3)
 #define IMX8M_OTG1_SW_Pxx_REQ                  BIT(2)
 #define IMX8M_PCIE1_SW_Pxx_REQ                 BIT(1)
 
+#define IMX8MM_VPUH1_SW_Pxx_REQ                        BIT(13)
+#define IMX8MM_VPUG2_SW_Pxx_REQ                        BIT(12)
+#define IMX8MM_VPUG1_SW_Pxx_REQ                        BIT(11)
+#define IMX8MM_DISPMIX_SW_Pxx_REQ              BIT(10)
+#define IMX8MM_VPUMIX_SW_Pxx_REQ               BIT(8)
+#define IMX8MM_GPUMIX_SW_Pxx_REQ               BIT(7)
+#define IMX8MM_GPU_SW_Pxx_REQ                  (BIT(6) | BIT(9))
+#define IMX8MM_DDR1_SW_Pxx_REQ                 BIT(5)
 #define IMX8MM_OTG2_SW_Pxx_REQ                 BIT(3)
 #define IMX8MM_OTG1_SW_Pxx_REQ                 BIT(2)
 #define IMX8MM_PCIE_SW_Pxx_REQ                 BIT(1)
+#define IMX8MM_MIPI_SW_Pxx_REQ                 BIT(0)
 
+#define IMX8MN_DISPMIX_SW_Pxx_REQ              BIT(10)
+#define IMX8MN_GPUMIX_SW_Pxx_REQ               BIT(7)
+#define IMX8MN_DDR1_SW_Pxx_REQ                 BIT(5)
 #define IMX8MN_OTG1_SW_Pxx_REQ                 BIT(2)
 #define IMX8MN_MIPI_SW_Pxx_REQ                 BIT(0)
 
 #define IMX8MP_HSIOMIX_Pxx_REQ                 BIT(17)
+#define IMX8MP_MEDIMIX_Pxx_REQ                 BIT(10)
 #define IMX8MP_USB2_PHY_Pxx_REQ                        BIT(3)
 #define IMX8MP_USB1_PHY_Pxx_REQ                        BIT(2)
 #define IMX8MP_PCIE_PHY_SW_Pxx_REQ             BIT(1)
+#define IMX8MP_MIPI_PHY1_SW_Pxx_REQ            BIT(0)
 
 #define GPC_M4_PU_PDN_FLG                      0x1bc
 
 #define IMX8MP_GPC_PU_PWRHSK                   0x190
 #define GPC_PU_PWRHSK                          0x1fc
 
+#define IMX8MM_GPUMIX_HSK_PWRDNACKN            BIT(29)
+#define IMX8MM_GPU_HSK_PWRDNACKN               (BIT(27) | BIT(28))
+#define IMX8MM_VPUMIX_HSK_PWRDNACKN            BIT(26)
+#define IMX8MM_DISPMIX_HSK_PWRDNACKN           BIT(25)
 #define IMX8MM_HSIO_HSK_PWRDNACKN              (BIT(23) | BIT(24))
+#define IMX8MM_GPUMIX_HSK_PWRDNREQN            BIT(11)
+#define IMX8MM_GPU_HSK_PWRDNREQN               (BIT(9) | BIT(10))
+#define IMX8MM_VPUMIX_HSK_PWRDNREQN            BIT(8)
+#define IMX8MM_DISPMIX_HSK_PWRDNREQN           BIT(7)
 #define IMX8MM_HSIO_HSK_PWRDNREQN              (BIT(5) | BIT(6))
 
+#define IMX8MN_GPUMIX_HSK_PWRDNACKN            (BIT(29) | BIT(27))
+#define IMX8MN_DISPMIX_HSK_PWRDNACKN           BIT(25)
 #define IMX8MN_HSIO_HSK_PWRDNACKN              BIT(23)
+#define IMX8MN_GPUMIX_HSK_PWRDNREQN            (BIT(11) | BIT(9))
+#define IMX8MN_DISPMIX_HSK_PWRDNREQN           BIT(7)
 #define IMX8MN_HSIO_HSK_PWRDNREQN              BIT(5)
 
+#define IMX8MP_MEDIAMIX_PWRDNACKN              BIT(30)
 #define IMX8MP_HSIOMIX_PWRDNACKN               BIT(28)
+#define IMX8MP_MEDIAMIX_PWRDNREQN              BIT(14)
 #define IMX8MP_HSIOMIX_PWRDNREQN               BIT(12)
 
 /*
@@ -92,15 +143,31 @@ DECLARE_GLOBAL_DATA_PTR;
 #define IMX8M_PGC_OTG2                 19
 #define IMX8M_PGC_PCIE2                        29
 
+#define IMX8MM_PGC_MIPI                        16
 #define IMX8MM_PGC_PCIE                        17
 #define IMX8MM_PGC_OTG1                        18
 #define IMX8MM_PGC_OTG2                        19
-
+#define IMX8MM_PGC_DDR1                        21
+#define IMX8MM_PGC_GPU2D               22
+#define IMX8MM_PGC_GPUMIX              23
+#define IMX8MM_PGC_VPUMIX              24
+#define IMX8MM_PGC_GPU3D               25
+#define IMX8MM_PGC_DISPMIX             26
+#define IMX8MM_PGC_VPUG1               27
+#define IMX8MM_PGC_VPUG2               28
+#define IMX8MM_PGC_VPUH1               29
+
+#define IMX8MN_PGC_MIPI                        16
 #define IMX8MN_PGC_OTG1                        18
+#define IMX8MN_PGC_DDR1                        21
+#define IMX8MN_PGC_GPUMIX              23
+#define IMX8MN_PGC_DISPMIX             26
 
+#define IMX8MP_PGC_MIPI1               12
 #define IMX8MP_PGC_PCIE                        13
 #define IMX8MP_PGC_USB1                        14
 #define IMX8MP_PGC_USB2                        15
+#define IMX8MP_PGC_MEDIAMIX            22
 #define IMX8MP_PGC_HSIOMIX             29
 
 #define GPC_PGC_CTRL(n)                        (0x800 + (n) * 0x40)
@@ -142,6 +209,7 @@ struct imx8m_power_domain_plat {
        void __iomem *base;
        int resource_id;
        int has_pd;
+       int count;
 };
 
 #if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) || defined(CONFIG_IMX8MQ)
@@ -230,6 +298,82 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
                },
                .pgc   = BIT(IMX8MM_PGC_OTG2),
        },
+
+       [IMX8MM_POWER_DOMAIN_GPUMIX] = {
+               .bits  = {
+                       .pxx = IMX8MM_GPUMIX_SW_Pxx_REQ,
+                       .map = IMX8MM_GPUMIX_A53_DOMAIN,
+                       .hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN,
+                       .hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_GPUMIX),
+               .keep_clocks = true,
+       },
+
+       [IMX8MM_POWER_DOMAIN_GPU] = {
+               .bits  = {
+                       .pxx = IMX8MM_GPU_SW_Pxx_REQ,
+                       .map = IMX8MM_GPU_A53_DOMAIN,
+                       .hskreq = IMX8MM_GPU_HSK_PWRDNREQN,
+                       .hskack = IMX8MM_GPU_HSK_PWRDNACKN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_GPU2D) | BIT(IMX8MM_PGC_GPU3D),
+       },
+
+       [IMX8MM_POWER_DOMAIN_VPUMIX] = {
+               .bits  = {
+                       .pxx = IMX8MM_VPUMIX_SW_Pxx_REQ,
+                       .map = IMX8MM_VPUMIX_A53_DOMAIN,
+                       .hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN,
+                       .hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_VPUMIX),
+               .keep_clocks = true,
+       },
+
+       [IMX8MM_POWER_DOMAIN_VPUG1] = {
+               .bits  = {
+                       .pxx = IMX8MM_VPUG1_SW_Pxx_REQ,
+                       .map = IMX8MM_VPUG1_A53_DOMAIN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_VPUG1),
+       },
+
+       [IMX8MM_POWER_DOMAIN_VPUG2] = {
+               .bits  = {
+                       .pxx = IMX8MM_VPUG2_SW_Pxx_REQ,
+                       .map = IMX8MM_VPUG2_A53_DOMAIN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_VPUG2),
+       },
+
+       [IMX8MM_POWER_DOMAIN_VPUH1] = {
+               .bits  = {
+                       .pxx = IMX8MM_VPUH1_SW_Pxx_REQ,
+                       .map = IMX8MM_VPUH1_A53_DOMAIN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_VPUH1),
+               .keep_clocks = true,
+       },
+
+       [IMX8MM_POWER_DOMAIN_DISPMIX] = {
+               .bits  = {
+                       .pxx = IMX8MM_DISPMIX_SW_Pxx_REQ,
+                       .map = IMX8MM_DISPMIX_A53_DOMAIN,
+                       .hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN,
+                       .hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_DISPMIX),
+               .keep_clocks = true,
+       },
+
+       [IMX8MM_POWER_DOMAIN_MIPI] = {
+               .bits  = {
+                       .pxx = IMX8MM_MIPI_SW_Pxx_REQ,
+                       .map = IMX8MM_MIPI_A53_DOMAIN,
+               },
+               .pgc   = BIT(IMX8MM_PGC_MIPI),
+       },
 };
 
 static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = {
@@ -258,6 +402,36 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
                },
                .pgc   = BIT(IMX8MN_PGC_OTG1),
        },
+
+       [IMX8MN_POWER_DOMAIN_GPUMIX] = {
+               .bits  = {
+                       .pxx = IMX8MN_GPUMIX_SW_Pxx_REQ,
+                       .map = IMX8MN_GPUMIX_A53_DOMAIN,
+                       .hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN,
+                       .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN,
+               },
+               .pgc   = BIT(IMX8MN_PGC_GPUMIX),
+               .keep_clocks = true,
+       },
+
+       [IMX8MN_POWER_DOMAIN_DISPMIX] = {
+               .bits  = {
+                       .pxx = IMX8MN_DISPMIX_SW_Pxx_REQ,
+                       .map = IMX8MN_DISPMIX_A53_DOMAIN,
+                       .hskreq = IMX8MN_DISPMIX_HSK_PWRDNREQN,
+                       .hskack = IMX8MN_DISPMIX_HSK_PWRDNACKN,
+               },
+               .pgc   = BIT(IMX8MN_PGC_DISPMIX),
+               .keep_clocks = true,
+       },
+
+       [IMX8MN_POWER_DOMAIN_MIPI] = {
+               .bits  = {
+                       .pxx = IMX8MN_MIPI_SW_Pxx_REQ,
+                       .map = IMX8MN_MIPI_A53_DOMAIN,
+               },
+               .pgc   = BIT(IMX8MN_PGC_MIPI),
+       },
 };
 
 static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = {
@@ -268,7 +442,15 @@ static const struct imx_pgc_domain_data 
imx8mn_pgc_domain_data = {
 #endif
 
 #ifdef CONFIG_IMX8MP
-static const struct imx_pgc_domain imx8mp_pgc_domains[] = {
+static const struct imx_pgc_domain imx8mp_pgc_domains[19] = {
+       [IMX8MP_POWER_DOMAIN_MIPI_PHY1] = {
+               .bits = {
+                       .pxx = IMX8MP_MIPI_PHY1_SW_Pxx_REQ,
+                       .map = IMX8MP_MIPI_PHY1_A53_DOMAIN,
+               },
+               .pgc = BIT(IMX8MP_PGC_MIPI1),
+       },
+
        [IMX8MP_POWER_DOMAIN_PCIE_PHY] = {
                .bits = {
                        .pxx = IMX8MP_PCIE_PHY_SW_Pxx_REQ,
@@ -293,6 +475,17 @@ static const struct imx_pgc_domain imx8mp_pgc_domains[] = {
                .pgc = BIT(IMX8MP_PGC_USB2),
        },
 
+       [IMX8MP_POWER_DOMAIN_MEDIAMIX] = {
+               .bits = {
+                       .pxx = IMX8MP_MEDIMIX_Pxx_REQ,
+                       .map = IMX8MP_MEDIAMIX_A53_DOMAIN,
+                       .hskreq = IMX8MP_MEDIAMIX_PWRDNREQN,
+                       .hskack = IMX8MP_MEDIAMIX_PWRDNACKN,
+               },
+               .pgc = BIT(IMX8MP_PGC_MEDIAMIX),
+               .keep_clocks = true,
+       },
+
        [IMX8MP_POWER_DOMAIN_HSIOMIX] = {
                .bits = {
                        .pxx = IMX8MP_HSIOMIX_Pxx_REQ,
@@ -329,6 +522,11 @@ static int imx8m_power_domain_on(struct power_domain 
*power_domain)
        u32 pgc;
        int ret;
 
+       if (pdata->count > 0) { /* Already on */
+               pdata->count++;
+               return 0;
+       }
+
        if (pdata->clk.count) {
                ret = clk_enable_bulk(&pdata->clk);
                if (ret) {
@@ -373,6 +571,8 @@ static int imx8m_power_domain_on(struct power_domain 
*power_domain)
        if (!domain->keep_clocks && pdata->clk.count)
                clk_disable_bulk(&pdata->clk);
 
+       pdata->count++;
+
        return 0;
 
 out_clk_disable:
@@ -391,6 +591,13 @@ static int imx8m_power_domain_off(struct power_domain 
*power_domain)
        u32 pgc;
        int ret;
 
+       if (!pdata->count) { /* Already off */
+               return 0;
+       } else if (pdata->count > 1) {
+               pdata->count--;
+               return 0;
+       }
+
        /* Enable reset clocks for all devices in the domain */
        if (!domain->keep_clocks && pdata->clk.count) {
                ret = clk_enable_bulk(&pdata->clk);
@@ -439,6 +646,8 @@ static int imx8m_power_domain_off(struct power_domain 
*power_domain)
        if (pdata->has_pd)
                power_domain_off(&pdata->pd);
 
+       pdata->count--;
+
        return 0;
 
 out_clk_disable:
-- 
2.43.0

Reply via email to