The SMI local arbiters (larbs) gate a multimedia subsystem's access to
DRAM. On the MT8188 the display data path feeds through the VDO1 larbs
(larb2 and larb3), whose clocks must be ungated for the HDMI pipeline to
reach the framebuffer.

There is no dedicated SMI larb driver upstream, as Linux handles the
larbs through its SMI/IOMMU framework (drivers/memory/mtk-smi.c). Add a
minimal U-Boot driver that ungates the clocks of one larb, and export
mtk_smi_larb_enable() and mtk_smi_larb_disable() so that the DMA master
behind a larb can tie it to its own lifetime.

The larbs are not video devices: they serve every multimedia master
(display, video codec, camera, MDP), so the driver lives in
drivers/memory with its own Kconfig symbol rather than being built as
part of one master's driver. Every "mediatek,mt8188-smi-larb" node
binds, which is cheap, and a larb is only probed once a master asks
for it.

Signed-off-by: Julien Stephan <[email protected]>
---
 drivers/memory/Kconfig        | 10 +++++
 drivers/memory/Makefile       |  1 +
 drivers/memory/mtk-smi-larb.c | 89 +++++++++++++++++++++++++++++++++++++++++++
 include/mtk_smi.h             | 37 ++++++++++++++++++
 4 files changed, 137 insertions(+)

diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 5f029fd3e70..52b0104e2f0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -20,6 +20,16 @@ config ATMEL_EBI
          driver. Doesn't provide an access to EBI controller. Select
          this option to enable the NAND flash controller driver
 
+config MTK_SMI_LARB
+       bool "MediaTek SMI local arbiter driver"
+       depends on ARCH_MEDIATEK && DM
+       select MEMORY
+       help
+         This driver ungates the clocks of the SMI local arbiters (larb)
+         found on MediaTek SoCs. A larb gates the access of one multimedia
+         subsystem (display, video codec, camera, MDP) to DRAM, so the larb
+         feeding a DMA master must be ungated before that master can run.
+
 config SANDBOX_MEMORY
        bool "Enable Sandbox Memory Controller driver"
        depends on SANDBOX && MEMORY
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index d5f5b073672..ee7bd9a9ea1 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -1,6 +1,7 @@
 
 obj-$(CONFIG_ATMEL_EBI) += atmel_ebi.o
 obj-$(CONFIG_MEMORY) += memory-uclass.o
+obj-$(CONFIG_MTK_SMI_LARB) += mtk-smi-larb.o
 obj-$(CONFIG_SANDBOX_MEMORY) += memory-sandbox.o
 obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o
 obj-$(CONFIG_STM32_OMM) += stm32_omm.o
diff --git a/drivers/memory/mtk-smi-larb.c b/drivers/memory/mtk-smi-larb.c
new file mode 100644
index 00000000000..b90f5cc135f
--- /dev/null
+++ b/drivers/memory/mtk-smi-larb.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek SMI local arbiter (larb) driver
+ *
+ * Copyright (c) 2026 BayLibre, SAS.
+ * Author: Julien Stephan <[email protected]>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <mtk_smi.h>
+
+/**
+ * struct mtk_smi_larb_priv - private data of an SMI larb
+ * @clk_bulk: clocks of the larb
+ * @enable_count: number of DMA masters that enabled the larb
+ *
+ * The SMI local arbiters gate a multimedia subsystem's access to DRAM. Linux
+ * handles them as part of its SMI/IOMMU framework (drivers/memory/mtk-smi.c);
+ * U-Boot has no such framework, so this minimal driver only ungates the larb
+ * clocks on behalf of the DMA master sitting behind it.
+ */
+struct mtk_smi_larb_priv {
+       struct clk_bulk clk_bulk;
+       unsigned int enable_count;
+};
+
+int mtk_smi_larb_enable(struct udevice *dev)
+{
+       struct mtk_smi_larb_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       /* several DMA masters can sit behind the same larb */
+       if (priv->enable_count++)
+               return 0;
+
+       ret = clk_enable_bulk(&priv->clk_bulk);
+       if (ret) {
+               dev_err(dev, "failed to enable clocks: %d\n", ret);
+               priv->enable_count--;
+       }
+
+       return ret;
+}
+
+int mtk_smi_larb_disable(struct udevice *dev)
+{
+       struct mtk_smi_larb_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       if (!priv->enable_count)
+               return -EINVAL;
+
+       if (--priv->enable_count)
+               return 0;
+
+       ret = clk_disable_bulk(&priv->clk_bulk);
+       if (ret)
+               dev_err(dev, "failed to disable clocks: %d\n", ret);
+
+       return ret;
+}
+
+static int mtk_smi_larb_probe(struct udevice *dev)
+{
+       struct mtk_smi_larb_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = clk_get_bulk(dev, &priv->clk_bulk);
+       if (ret)
+               dev_err(dev, "failed to get clocks: %d\n", ret);
+
+       return ret;
+}
+
+static const struct udevice_id mtk_smi_larb_ids[] = {
+       { .compatible = "mediatek,mt8188-smi-larb" },
+       { }
+};
+
+U_BOOT_DRIVER(mtk_smi_larb) = {
+       .name      = "mtk_smi_larb",
+       .id        = UCLASS_MEMORY,
+       .of_match  = mtk_smi_larb_ids,
+       .probe     = mtk_smi_larb_probe,
+       .priv_auto = sizeof(struct mtk_smi_larb_priv),
+};
diff --git a/include/mtk_smi.h b/include/mtk_smi.h
new file mode 100644
index 00000000000..b0166b37538
--- /dev/null
+++ b/include/mtk_smi.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * MediaTek SMI local arbiter (larb) API
+ *
+ * Copyright (c) 2026 BayLibre, SAS.
+ * Author: Julien Stephan <[email protected]>
+ */
+
+#ifndef _MTK_SMI_H
+#define _MTK_SMI_H
+
+struct udevice;
+
+/**
+ * mtk_smi_larb_enable() - ungate an SMI local arbiter
+ * @dev: larb device
+ *
+ * Enable the clocks of the larb so that the DMA master behind it can reach
+ * DRAM. Calls are refcounted, so several masters can share one larb.
+ *
+ * Return: 0 on success, or a negative error code
+ */
+int mtk_smi_larb_enable(struct udevice *dev);
+
+/**
+ * mtk_smi_larb_disable() - gate an SMI local arbiter
+ * @dev: larb device
+ *
+ * Drop one reference taken by mtk_smi_larb_enable(), and disable the larb
+ * clocks when it was the last one.
+ *
+ * Return: 0 on success, -EINVAL if the larb is not enabled, or another
+ * negative error code
+ */
+int mtk_smi_larb_disable(struct udevice *dev);
+
+#endif /* _MTK_SMI_H */

-- 
2.55.0

Reply via email to