Merge tag 'drivers-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / memory / mtk-smi.c
index c5fb51f..b883dcc 100644 (file)
 #include <dt-bindings/memory/mt2701-larb-port.h>
 #include <dt-bindings/memory/mtk-memory-port.h>
 
-/* mt8173 */
-#define SMI_LARB_MMU_EN                0xf00
+/* SMI COMMON */
+#define SMI_L1LEN                      0x100
 
-/* mt8167 */
-#define MT8167_SMI_LARB_MMU_EN 0xfc0
+#define SMI_BUS_SEL                    0x220
+#define SMI_BUS_LARB_SHIFT(larbid)     ((larbid) << 1)
+/* All are MMU0 defaultly. Only specialize mmu1 here. */
+#define F_MMU1_LARB(larbid)            (0x1 << SMI_BUS_LARB_SHIFT(larbid))
+
+#define SMI_M4U_TH                     0x234
+#define SMI_FIFO_TH1                   0x238
+#define SMI_FIFO_TH2                   0x23c
+#define SMI_DCM                                0x300
+#define SMI_DUMMY                      0x444
 
-/* mt2701 */
+/* SMI LARB */
+#define SMI_LARB_CMD_THRT_CON          0x24
+#define SMI_LARB_THRT_RD_NU_LMT_MSK    GENMASK(7, 4)
+#define SMI_LARB_THRT_RD_NU_LMT                (5 << 4)
+
+#define SMI_LARB_SW_FLAG               0x40
+#define SMI_LARB_SW_FLAG_1             0x1
+
+#define SMI_LARB_OSTDL_PORT            0x200
+#define SMI_LARB_OSTDL_PORTx(id)       (SMI_LARB_OSTDL_PORT + (((id) & 0x1f) << 2))
+
+/* Below are about mmu enable registers, they are different in SoCs */
+/* gen1: mt2701 */
 #define REG_SMI_SECUR_CON_BASE         0x5c0
 
 /* every register control 8 port, register offset 0x4 */
 /* mt2701 domain should be set to 3 */
 #define SMI_SECUR_CON_VAL_DOMAIN(id)   (0x3 << ((((id) & 0x7) << 2) + 1))
 
-/* mt2712 */
-#define SMI_LARB_NONSEC_CON(id)        (0x380 + ((id) * 4))
-#define F_MMU_EN               BIT(0)
-#define BANK_SEL(id)           ({                      \
+/* gen2: */
+/* mt8167 */
+#define MT8167_SMI_LARB_MMU_EN         0xfc0
+
+/* mt8173 */
+#define MT8173_SMI_LARB_MMU_EN         0xf00
+
+/* general */
+#define SMI_LARB_NONSEC_CON(id)                (0x380 + ((id) * 4))
+#define F_MMU_EN                       BIT(0)
+#define BANK_SEL(id)                   ({              \
        u32 _id = (id) & 0x3;                           \
        (_id << 8 | _id << 10 | _id << 12 | _id << 14); \
 })
 
-/* SMI COMMON */
-#define SMI_BUS_SEL                    0x220
-#define SMI_BUS_LARB_SHIFT(larbid)     ((larbid) << 1)
-/* All are MMU0 defaultly. Only specialize mmu1 here. */
-#define F_MMU1_LARB(larbid)            (0x1 << SMI_BUS_LARB_SHIFT(larbid))
+#define SMI_COMMON_INIT_REGS_NR                6
+#define SMI_LARB_PORT_NR_MAX           32
+
+#define MTK_SMI_FLAG_THRT_UPDATE       BIT(0)
+#define MTK_SMI_FLAG_SW_FLAG           BIT(1)
+#define MTK_SMI_CAPS(flags, _x)                (!!((flags) & (_x)))
+
+struct mtk_smi_reg_pair {
+       unsigned int            offset;
+       u32                     value;
+};
 
-enum mtk_smi_gen {
+enum mtk_smi_type {
        MTK_SMI_GEN1,
-       MTK_SMI_GEN2
+       MTK_SMI_GEN2,           /* gen2 smi common */
+       MTK_SMI_GEN2_SUB_COMM,  /* gen2 smi sub common */
 };
 
+#define MTK_SMI_CLK_NR_MAX                     4
+
+/* larbs: Require apb/smi clocks while gals is optional. */
+static const char * const mtk_smi_larb_clks[] = {"apb", "smi", "gals"};
+#define MTK_SMI_LARB_REQ_CLK_NR                2
+#define MTK_SMI_LARB_OPT_CLK_NR                1
+
+/*
+ * common: Require these four clocks in has_gals case. Otherwise, only apb/smi are required.
+ * sub common: Require apb/smi/gals0 clocks in has_gals case. Otherwise, only apb/smi are required.
+ */
+static const char * const mtk_smi_common_clks[] = {"apb", "smi", "gals0", "gals1"};
+#define MTK_SMI_COM_REQ_CLK_NR         2
+#define MTK_SMI_COM_GALS_REQ_CLK_NR    MTK_SMI_CLK_NR_MAX
+#define MTK_SMI_SUB_COM_GALS_REQ_CLK_NR 3
+
 struct mtk_smi_common_plat {
-       enum mtk_smi_gen gen;
-       bool             has_gals;
-       u32              bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */
+       enum mtk_smi_type       type;
+       bool                    has_gals;
+       u32                     bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */
+
+       const struct mtk_smi_reg_pair   *init;
 };
 
 struct mtk_smi_larb_gen {
        int port_in_larb[MTK_LARB_NR_MAX + 1];
        void (*config_port)(struct device *dev);
        unsigned int                    larb_direct_to_common_mask;
-       bool                            has_gals;
+       unsigned int                    flags_general;
+       const u8                        (*ostd)[SMI_LARB_PORT_NR_MAX];
 };
 
 struct mtk_smi {
        struct device                   *dev;
-       struct clk                      *clk_apb, *clk_smi;
-       struct clk                      *clk_gals0, *clk_gals1;
+       unsigned int                    clk_num;
+       struct clk_bulk_data            clks[MTK_SMI_CLK_NR_MAX];
        struct clk                      *clk_async; /*only needed by mt2701*/
        union {
                void __iomem            *smi_ao_base; /* only for gen1 */
                void __iomem            *base;        /* only for gen2 */
        };
+       struct device                   *smi_common_dev; /* for sub common */
        const struct mtk_smi_common_plat *plat;
 };
 
 struct mtk_smi_larb { /* larb: local arbiter */
        struct mtk_smi                  smi;
        void __iomem                    *base;
-       struct device                   *smi_common_dev;
+       struct device                   *smi_common_dev; /* common or sub-common dev */
        const struct mtk_smi_larb_gen   *larb_gen;
        int                             larbid;
        u32                             *mmu;
        unsigned char                   *bank;
 };
 
-static int mtk_smi_clk_enable(const struct mtk_smi *smi)
-{
-       int ret;
-
-       ret = clk_prepare_enable(smi->clk_apb);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(smi->clk_smi);
-       if (ret)
-               goto err_disable_apb;
-
-       ret = clk_prepare_enable(smi->clk_gals0);
-       if (ret)
-               goto err_disable_smi;
-
-       ret = clk_prepare_enable(smi->clk_gals1);
-       if (ret)
-               goto err_disable_gals0;
-
-       return 0;
-
-err_disable_gals0:
-       clk_disable_unprepare(smi->clk_gals0);
-err_disable_smi:
-       clk_disable_unprepare(smi->clk_smi);
-err_disable_apb:
-       clk_disable_unprepare(smi->clk_apb);
-       return ret;
-}
-
-static void mtk_smi_clk_disable(const struct mtk_smi *smi)
-{
-       clk_disable_unprepare(smi->clk_gals1);
-       clk_disable_unprepare(smi->clk_gals0);
-       clk_disable_unprepare(smi->clk_smi);
-       clk_disable_unprepare(smi->clk_apb);
-}
-
 int mtk_smi_larb_get(struct device *larbdev)
 {
        int ret = pm_runtime_resume_and_get(larbdev);
@@ -166,36 +181,16 @@ mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
        return -ENODEV;
 }
 
-static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
-{
-       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
-       u32 reg;
-       int i;
-
-       if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
-               return;
-
-       for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
-               reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
-               reg |= F_MMU_EN;
-               reg |= BANK_SEL(larb->bank[i]);
-               writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
-       }
-}
-
-static void mtk_smi_larb_config_port_mt8173(struct device *dev)
+static void
+mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
 {
-       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
-
-       writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
+       /* Do nothing as the iommu is always enabled. */
 }
 
-static void mtk_smi_larb_config_port_mt8167(struct device *dev)
-{
-       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
-
-       writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
-}
+static const struct component_ops mtk_smi_larb_component_ops = {
+       .bind = mtk_smi_larb_bind,
+       .unbind = mtk_smi_larb_unbind,
+};
 
 static void mtk_smi_larb_config_port_gen1(struct device *dev)
 {
@@ -228,25 +223,94 @@ static void mtk_smi_larb_config_port_gen1(struct device *dev)
        }
 }
 
-static void
-mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
+static void mtk_smi_larb_config_port_mt8167(struct device *dev)
 {
-       /* Do nothing as the iommu is always enabled. */
+       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+       writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
 }
 
-static const struct component_ops mtk_smi_larb_component_ops = {
-       .bind = mtk_smi_larb_bind,
-       .unbind = mtk_smi_larb_unbind,
-};
+static void mtk_smi_larb_config_port_mt8173(struct device *dev)
+{
+       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
 
-static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
-       /* mt8173 do not need the port in larb */
-       .config_port = mtk_smi_larb_config_port_mt8173,
-};
+       writel(*larb->mmu, larb->base + MT8173_SMI_LARB_MMU_EN);
+}
 
-static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
-       /* mt8167 do not need the port in larb */
-       .config_port = mtk_smi_larb_config_port_mt8167,
+static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
+{
+       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+       u32 reg, flags_general = larb->larb_gen->flags_general;
+       const u8 *larbostd = larb->larb_gen->ostd[larb->larbid];
+       int i;
+
+       if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
+               return;
+
+       if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_THRT_UPDATE)) {
+               reg = readl_relaxed(larb->base + SMI_LARB_CMD_THRT_CON);
+               reg &= ~SMI_LARB_THRT_RD_NU_LMT_MSK;
+               reg |= SMI_LARB_THRT_RD_NU_LMT;
+               writel_relaxed(reg, larb->base + SMI_LARB_CMD_THRT_CON);
+       }
+
+       if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_SW_FLAG))
+               writel_relaxed(SMI_LARB_SW_FLAG_1, larb->base + SMI_LARB_SW_FLAG);
+
+       for (i = 0; i < SMI_LARB_PORT_NR_MAX && larbostd && !!larbostd[i]; i++)
+               writel_relaxed(larbostd[i], larb->base + SMI_LARB_OSTDL_PORTx(i));
+
+       for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
+               reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
+               reg |= F_MMU_EN;
+               reg |= BANK_SEL(larb->bank[i]);
+               writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
+       }
+}
+
+static const u8 mtk_smi_larb_mt8195_ostd[][SMI_LARB_PORT_NR_MAX] = {
+       [0] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb0 */
+       [1] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb1 */
+       [2] = {0x12, 0x12, 0x12, 0x12, 0x0a,},      /* ... */
+       [3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,},
+       [4] = {0x06, 0x01, 0x17, 0x06, 0x0a,},
+       [5] = {0x06, 0x01, 0x17, 0x06, 0x06, 0x01, 0x06, 0x0a,},
+       [6] = {0x06, 0x01, 0x06, 0x0a,},
+       [7] = {0x0c, 0x0c, 0x12,},
+       [8] = {0x0c, 0x0c, 0x12,},
+       [9] = {0x0a, 0x08, 0x04, 0x06, 0x01, 0x01, 0x10, 0x18, 0x11, 0x0a,
+               0x08, 0x04, 0x11, 0x06, 0x02, 0x06, 0x01, 0x11, 0x11, 0x06,},
+       [10] = {0x18, 0x08, 0x01, 0x01, 0x20, 0x12, 0x18, 0x06, 0x05, 0x10,
+               0x08, 0x08, 0x10, 0x08, 0x08, 0x18, 0x0c, 0x09, 0x0b, 0x0d,
+               0x0d, 0x06, 0x10, 0x10,},
+       [11] = {0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x01, 0x01, 0x01, 0x01,},
+       [12] = {0x09, 0x09, 0x05, 0x05, 0x0c, 0x18, 0x02, 0x02, 0x04, 0x02,},
+       [13] = {0x02, 0x02, 0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x08, 0x01,},
+       [14] = {0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x16, 0x01, 0x16, 0x01,
+               0x01, 0x02, 0x02, 0x08, 0x02,},
+       [15] = {},
+       [16] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a,
+               0x12, 0x02, 0x0a, 0x16, 0x02, 0x04,},
+       [17] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,},
+       [18] = {0x12, 0x06, 0x12, 0x06,},
+       [19] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01,
+               0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06,
+               0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,},
+       [20] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01,
+               0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06,
+               0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,},
+       [21] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,},
+       [22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,},
+       [23] = {0x18, 0x01,},
+       [24] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
+               0x01, 0x01,},
+       [25] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16,
+               0x02, 0x01,},
+       [26] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16,
+               0x02, 0x01,},
+       [27] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16,
+               0x02, 0x01,},
+       [28] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,},
 };
 
 static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
@@ -269,8 +333,17 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = {
                /* DUMMY | IPU0 | IPU1 | CCU | MDLA */
 };
 
+static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
+       /* mt8167 do not need the port in larb */
+       .config_port = mtk_smi_larb_config_port_mt8167,
+};
+
+static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
+       /* mt8173 do not need the port in larb */
+       .config_port = mtk_smi_larb_config_port_mt8173,
+};
+
 static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
-       .has_gals                   = true,
        .config_port                = mtk_smi_larb_config_port_gen2_general,
        .larb_direct_to_common_mask = BIT(2) | BIT(3) | BIT(7),
                                      /* IPU0 | IPU1 | CCU */
@@ -280,99 +353,114 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
        .config_port                = mtk_smi_larb_config_port_gen2_general,
 };
 
+static const struct mtk_smi_larb_gen mtk_smi_larb_mt8195 = {
+       .config_port                = mtk_smi_larb_config_port_gen2_general,
+       .flags_general              = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG,
+       .ostd                       = mtk_smi_larb_mt8195_ostd,
+};
+
 static const struct of_device_id mtk_smi_larb_of_ids[] = {
-       {
-               .compatible = "mediatek,mt8167-smi-larb",
-               .data = &mtk_smi_larb_mt8167
-       },
-       {
-               .compatible = "mediatek,mt8173-smi-larb",
-               .data = &mtk_smi_larb_mt8173
-       },
-       {
-               .compatible = "mediatek,mt2701-smi-larb",
-               .data = &mtk_smi_larb_mt2701
-       },
-       {
-               .compatible = "mediatek,mt2712-smi-larb",
-               .data = &mtk_smi_larb_mt2712
-       },
-       {
-               .compatible = "mediatek,mt6779-smi-larb",
-               .data = &mtk_smi_larb_mt6779
-       },
-       {
-               .compatible = "mediatek,mt8183-smi-larb",
-               .data = &mtk_smi_larb_mt8183
-       },
-       {
-               .compatible = "mediatek,mt8192-smi-larb",
-               .data = &mtk_smi_larb_mt8192
-       },
+       {.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701},
+       {.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712},
+       {.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779},
+       {.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167},
+       {.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
+       {.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
+       {.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192},
+       {.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
        {}
 };
 
-static int mtk_smi_larb_probe(struct platform_device *pdev)
+static int mtk_smi_device_link_common(struct device *dev, struct device **com_dev)
 {
-       struct mtk_smi_larb *larb;
-       struct resource *res;
-       struct device *dev = &pdev->dev;
-       struct device_node *smi_node;
-       struct platform_device *smi_pdev;
+       struct platform_device *smi_com_pdev;
+       struct device_node *smi_com_node;
+       struct device *smi_com_dev;
        struct device_link *link;
 
-       larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
-       if (!larb)
-               return -ENOMEM;
-
-       larb->larb_gen = of_device_get_match_data(dev);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       larb->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(larb->base))
-               return PTR_ERR(larb->base);
-
-       larb->smi.clk_apb = devm_clk_get(dev, "apb");
-       if (IS_ERR(larb->smi.clk_apb))
-               return PTR_ERR(larb->smi.clk_apb);
-
-       larb->smi.clk_smi = devm_clk_get(dev, "smi");
-       if (IS_ERR(larb->smi.clk_smi))
-               return PTR_ERR(larb->smi.clk_smi);
-
-       if (larb->larb_gen->has_gals) {
-               /* The larbs may still haven't gals even if the SoC support.*/
-               larb->smi.clk_gals0 = devm_clk_get(dev, "gals");
-               if (PTR_ERR(larb->smi.clk_gals0) == -ENOENT)
-                       larb->smi.clk_gals0 = NULL;
-               else if (IS_ERR(larb->smi.clk_gals0))
-                       return PTR_ERR(larb->smi.clk_gals0);
-       }
-       larb->smi.dev = dev;
-
-       smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
-       if (!smi_node)
+       smi_com_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
+       if (!smi_com_node)
                return -EINVAL;
 
-       smi_pdev = of_find_device_by_node(smi_node);
-       of_node_put(smi_node);
-       if (smi_pdev) {
-               if (!platform_get_drvdata(smi_pdev))
+       smi_com_pdev = of_find_device_by_node(smi_com_node);
+       of_node_put(smi_com_node);
+       if (smi_com_pdev) {
+               /* smi common is the supplier, Make sure it is ready before */
+               if (!platform_get_drvdata(smi_com_pdev))
                        return -EPROBE_DEFER;
-               larb->smi_common_dev = &smi_pdev->dev;
-               link = device_link_add(dev, larb->smi_common_dev,
+               smi_com_dev = &smi_com_pdev->dev;
+               link = device_link_add(dev, smi_com_dev,
                                       DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
                if (!link) {
                        dev_err(dev, "Unable to link smi-common dev\n");
                        return -ENODEV;
                }
+               *com_dev = smi_com_dev;
        } else {
                dev_err(dev, "Failed to get the smi_common device\n");
                return -EINVAL;
        }
+       return 0;
+}
+
+static int mtk_smi_dts_clk_init(struct device *dev, struct mtk_smi *smi,
+                               const char * const clks[],
+                               unsigned int clk_nr_required,
+                               unsigned int clk_nr_optional)
+{
+       int i, ret;
+
+       for (i = 0; i < clk_nr_required; i++)
+               smi->clks[i].id = clks[i];
+       ret = devm_clk_bulk_get(dev, clk_nr_required, smi->clks);
+       if (ret)
+               return ret;
+
+       for (i = clk_nr_required; i < clk_nr_required + clk_nr_optional; i++)
+               smi->clks[i].id = clks[i];
+       ret = devm_clk_bulk_get_optional(dev, clk_nr_optional,
+                                        smi->clks + clk_nr_required);
+       smi->clk_num = clk_nr_required + clk_nr_optional;
+       return ret;
+}
+
+static int mtk_smi_larb_probe(struct platform_device *pdev)
+{
+       struct mtk_smi_larb *larb;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
+       if (!larb)
+               return -ENOMEM;
+
+       larb->larb_gen = of_device_get_match_data(dev);
+       larb->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(larb->base))
+               return PTR_ERR(larb->base);
+
+       ret = mtk_smi_dts_clk_init(dev, &larb->smi, mtk_smi_larb_clks,
+                                  MTK_SMI_LARB_REQ_CLK_NR, MTK_SMI_LARB_OPT_CLK_NR);
+       if (ret)
+               return ret;
+
+       larb->smi.dev = dev;
+
+       ret = mtk_smi_device_link_common(dev, &larb->smi_common_dev);
+       if (ret < 0)
+               return ret;
 
        pm_runtime_enable(dev);
        platform_set_drvdata(pdev, larb);
-       return component_add(dev, &mtk_smi_larb_component_ops);
+       ret = component_add(dev, &mtk_smi_larb_component_ops);
+       if (ret)
+               goto err_pm_disable;
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(dev);
+       device_link_remove(dev, larb->smi_common_dev);
+       return ret;
 }
 
 static int mtk_smi_larb_remove(struct platform_device *pdev)
@@ -391,11 +479,9 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
        const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
        int ret;
 
-       ret = mtk_smi_clk_enable(&larb->smi);
-       if (ret < 0) {
-               dev_err(dev, "Failed to enable clock(%d).\n", ret);
+       ret = clk_bulk_prepare_enable(larb->smi.clk_num, larb->smi.clks);
+       if (ret < 0)
                return ret;
-       }
 
        /* Configure the basic setting for this larb */
        larb_gen->config_port(dev);
@@ -407,7 +493,7 @@ static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
 {
        struct mtk_smi_larb *larb = dev_get_drvdata(dev);
 
-       mtk_smi_clk_disable(&larb->smi);
+       clk_bulk_disable_unprepare(larb->smi.clk_num, larb->smi.clks);
        return 0;
 }
 
@@ -427,64 +513,75 @@ static struct platform_driver mtk_smi_larb_driver = {
        }
 };
 
+static const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = {
+       {SMI_L1LEN, 0xb},
+       {SMI_M4U_TH, 0xe100e10},
+       {SMI_FIFO_TH1, 0x506090a},
+       {SMI_FIFO_TH2, 0x506090a},
+       {SMI_DCM, 0x4f1},
+       {SMI_DUMMY, 0x1},
+};
+
 static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
-       .gen = MTK_SMI_GEN1,
+       .type     = MTK_SMI_GEN1,
 };
 
 static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
-       .gen = MTK_SMI_GEN2,
+       .type     = MTK_SMI_GEN2,
 };
 
 static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = {
-       .gen            = MTK_SMI_GEN2,
-       .has_gals       = true,
-       .bus_sel        = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) |
-                         F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
+       .type     = MTK_SMI_GEN2,
+       .has_gals = true,
+       .bus_sel  = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) |
+                   F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
 };
 
 static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
-       .gen      = MTK_SMI_GEN2,
+       .type     = MTK_SMI_GEN2,
        .has_gals = true,
        .bus_sel  = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
                    F_MMU1_LARB(7),
 };
 
 static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
-       .gen      = MTK_SMI_GEN2,
+       .type     = MTK_SMI_GEN2,
        .has_gals = true,
        .bus_sel  = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
                    F_MMU1_LARB(6),
 };
 
+static const struct mtk_smi_common_plat mtk_smi_common_mt8195_vdo = {
+       .type     = MTK_SMI_GEN2,
+       .has_gals = true,
+       .bus_sel  = F_MMU1_LARB(1) | F_MMU1_LARB(3) | F_MMU1_LARB(5) |
+                   F_MMU1_LARB(7),
+       .init     = mtk_smi_common_mt8195_init,
+};
+
+static const struct mtk_smi_common_plat mtk_smi_common_mt8195_vpp = {
+       .type     = MTK_SMI_GEN2,
+       .has_gals = true,
+       .bus_sel  = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7),
+       .init     = mtk_smi_common_mt8195_init,
+};
+
+static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = {
+       .type     = MTK_SMI_GEN2_SUB_COMM,
+       .has_gals = true,
+};
+
 static const struct of_device_id mtk_smi_common_of_ids[] = {
-       {
-               .compatible = "mediatek,mt8173-smi-common",
-               .data = &mtk_smi_common_gen2,
-       },
-       {
-               .compatible = "mediatek,mt8167-smi-common",
-               .data = &mtk_smi_common_gen2,
-       },
-       {
-               .compatible = "mediatek,mt2701-smi-common",
-               .data = &mtk_smi_common_gen1,
-       },
-       {
-               .compatible = "mediatek,mt2712-smi-common",
-               .data = &mtk_smi_common_gen2,
-       },
-       {
-               .compatible = "mediatek,mt6779-smi-common",
-               .data = &mtk_smi_common_mt6779,
-       },
-       {
-               .compatible = "mediatek,mt8183-smi-common",
-               .data = &mtk_smi_common_mt8183,
-       },
-       {
-               .compatible = "mediatek,mt8192-smi-common",
-               .data = &mtk_smi_common_mt8192,
-       },
+       {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
+       {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
+       {.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779},
+       {.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2},
+       {.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2},
+       {.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183},
+       {.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192},
+       {.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo},
+       {.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp},
+       {.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195},
        {}
 };
 
@@ -492,8 +589,7 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mtk_smi *common;
-       struct resource *res;
-       int ret;
+       int ret, clk_required = MTK_SMI_COM_REQ_CLK_NR;
 
        common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
        if (!common)
@@ -501,23 +597,15 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
        common->dev = dev;
        common->plat = of_device_get_match_data(dev);
 
-       common->clk_apb = devm_clk_get(dev, "apb");
-       if (IS_ERR(common->clk_apb))
-               return PTR_ERR(common->clk_apb);
-
-       common->clk_smi = devm_clk_get(dev, "smi");
-       if (IS_ERR(common->clk_smi))
-               return PTR_ERR(common->clk_smi);
-
        if (common->plat->has_gals) {
-               common->clk_gals0 = devm_clk_get(dev, "gals0");
-               if (IS_ERR(common->clk_gals0))
-                       return PTR_ERR(common->clk_gals0);
-
-               common->clk_gals1 = devm_clk_get(dev, "gals1");
-               if (IS_ERR(common->clk_gals1))
-                       return PTR_ERR(common->clk_gals1);
+               if (common->plat->type == MTK_SMI_GEN2)
+                       clk_required = MTK_SMI_COM_GALS_REQ_CLK_NR;
+               else if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
+                       clk_required = MTK_SMI_SUB_COM_GALS_REQ_CLK_NR;
        }
+       ret = mtk_smi_dts_clk_init(dev, common, mtk_smi_common_clks, clk_required, 0);
+       if (ret)
+               return ret;
 
        /*
         * for mtk smi gen 1, we need to get the ao(always on) base to config
@@ -525,9 +613,8 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
         * clock into emi clock domain, but for mtk smi gen2, there's no smi ao
         * base.
         */
-       if (common->plat->gen == MTK_SMI_GEN1) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               common->smi_ao_base = devm_ioremap_resource(dev, res);
+       if (common->plat->type == MTK_SMI_GEN1) {
+               common->smi_ao_base = devm_platform_ioremap_resource(pdev, 0);
                if (IS_ERR(common->smi_ao_base))
                        return PTR_ERR(common->smi_ao_base);
 
@@ -539,11 +626,18 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
                if (ret)
                        return ret;
        } else {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               common->base = devm_ioremap_resource(dev, res);
+               common->base = devm_platform_ioremap_resource(pdev, 0);
                if (IS_ERR(common->base))
                        return PTR_ERR(common->base);
        }
+
+       /* link its smi-common if this is smi-sub-common */
+       if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) {
+               ret = mtk_smi_device_link_common(dev, &common->smi_common_dev);
+               if (ret < 0)
+                       return ret;
+       }
+
        pm_runtime_enable(dev);
        platform_set_drvdata(pdev, common);
        return 0;
@@ -551,6 +645,10 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
 
 static int mtk_smi_common_remove(struct platform_device *pdev)
 {
+       struct mtk_smi *common = dev_get_drvdata(&pdev->dev);
+
+       if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
+               device_link_remove(&pdev->dev, common->smi_common_dev);
        pm_runtime_disable(&pdev->dev);
        return 0;
 }
@@ -558,17 +656,21 @@ static int mtk_smi_common_remove(struct platform_device *pdev)
 static int __maybe_unused mtk_smi_common_resume(struct device *dev)
 {
        struct mtk_smi *common = dev_get_drvdata(dev);
-       u32 bus_sel = common->plat->bus_sel;
-       int ret;
+       const struct mtk_smi_reg_pair *init = common->plat->init;
+       u32 bus_sel = common->plat->bus_sel; /* default is 0 */
+       int ret, i;
 
-       ret = mtk_smi_clk_enable(common);
-       if (ret) {
-               dev_err(common->dev, "Failed to enable clock(%d).\n", ret);
+       ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
+       if (ret)
                return ret;
-       }
 
-       if (common->plat->gen == MTK_SMI_GEN2 && bus_sel)
-               writel(bus_sel, common->base + SMI_BUS_SEL);
+       if (common->plat->type != MTK_SMI_GEN2)
+               return 0;
+
+       for (i = 0; i < SMI_COMMON_INIT_REGS_NR && init && init[i].offset; i++)
+               writel_relaxed(init[i].value, common->base + init[i].offset);
+
+       writel(bus_sel, common->base + SMI_BUS_SEL);
        return 0;
 }
 
@@ -576,7 +678,7 @@ static int __maybe_unused mtk_smi_common_suspend(struct device *dev)
 {
        struct mtk_smi *common = dev_get_drvdata(dev);
 
-       mtk_smi_clk_disable(common);
+       clk_bulk_disable_unprepare(common->clk_num, common->clks);
        return 0;
 }