The rdma (read DMA) block is one of the components of the video pipeline
on some MediaTek SoCs, such as the MT8365 and the MT8366. It feeds the
pipeline either from a framebuffer in DRAM, or from the stream coming out
of the overlay.

The DSI pipeline only goes through it in direct mode, the overlay being
the DMA master there, so the driver programs the frame size and the FIFO
thresholds and starts the block, leaving its memory mode alone. The
larb feeding it is still ungated with it, as the block sits behind it
either way.

The driver matches "mediatek,mt8183-disp-rdma" and
"mediatek,mt8195-disp-rdma", the generic fallbacks the MT8365 and the
MT8366 rdma nodes respectively carry behind their SoC specific string,
so a single entry covers every SoC reusing either generation. The FIFO
size of the compatible is only a default: the instances of one SoC may
differ, and "mediatek,rdma-fifo-size" overrides it when the device tree
describes it.

Signed-off-by: Julien Stephan <[email protected]>
---
 drivers/video/mediatek/mtk_disp_comp.h |   4 +-
 drivers/video/mediatek/mtk_disp_rdma.c | 154 +++++++++++++++++++++++++++++++++
 drivers/video/mediatek/mtk_disp_rdma.h |  30 +++++++
 3 files changed, 186 insertions(+), 2 deletions(-)

diff --git a/drivers/video/mediatek/mtk_disp_comp.h 
b/drivers/video/mediatek/mtk_disp_comp.h
index fbc2174352e..9e525521cc4 100644
--- a/drivers/video/mediatek/mtk_disp_comp.h
+++ b/drivers/video/mediatek/mtk_disp_comp.h
@@ -18,8 +18,8 @@ struct udevice;
  * @base: register window of the component
  * @clk_bulk: clocks of the component
  * @larb: optional SMI larb device (UCLASS_MEMORY), enabled and disabled
- *       together with the component. Only the DMA masters of the pipelines,
- *       the overlays and the MDP RDMAs, have one.
+ *       together with the component. Only the components sitting behind an
+ *       SMI larb, the overlays and the rdmas, have one.
  * @larb_port: M4U port index of the component within @larb
  */
 struct mtk_disp_comp_priv {
diff --git a/drivers/video/mediatek/mtk_disp_rdma.c 
b/drivers/video/mediatek/mtk_disp_rdma.c
new file mode 100644
index 00000000000..e66092c7799
--- /dev/null
+++ b/drivers/video/mediatek/mtk_disp_rdma.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Video RDMA support
+ *
+ * Copyright (c) 2026 BayLibre, SAS.
+ * Author: Julien Masson <[email protected]>
+ *         Julien Stephan <[email protected]>
+ */
+
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/read.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/sizes.h>
+
+#include "mtk_disp_comp.h"
+#include "mtk_disp_rdma.h"
+
+#define DISP_REG_RDMA_GLOBAL_CON       0x010
+#define RDMA_ENGINE_EN                         BIT(0)
+
+#define DISP_REG_RDMA_SIZE_CON_0       0x014
+#define RDMA_SIZE_CON_0_WIDTH                  GENMASK(11, 0)
+
+#define DISP_REG_RDMA_SIZE_CON_1       0x018
+#define RDMA_SIZE_CON_1_HEIGHT                 GENMASK(19, 0)
+
+#define DISP_REG_RDMA_FIFO_CON         0x040
+#define RDMA_FIFO_UNDERFLOW_EN                 BIT(31)
+#define RDMA_FIFO_PSEUDO_SIZE                  GENMASK(27, 16)
+#define RDMA_OUTPUT_VALID_FIFO_THRESHOLD       GENMASK(11, 0)
+
+/* the FIFO registers count in 16-byte words */
+#define RDMA_FIFO_WORD(bytes)          ((bytes) / 16)
+
+/**
+ * struct mtk_disp_rdma_data - per-SoC rdma data
+ * @fifo_size: default FIFO size, in bytes
+ */
+struct mtk_disp_rdma_data {
+       u32 fifo_size;
+};
+
+/**
+ * struct mtk_disp_rdma_priv - private data of an rdma
+ * @comp: common component state, must be the first member
+ * @fifo_size: FIFO size, in bytes, from "mediatek,rdma-fifo-size" or the
+ *            per-SoC default
+ */
+struct mtk_disp_rdma_priv {
+       struct mtk_disp_comp_priv comp;
+       u32 fifo_size;
+};
+
+void mtk_rdma_config(struct udevice *dev, const struct display_timing *timing)
+{
+       struct mtk_disp_rdma_priv *rdma = dev_get_priv(dev);
+       u32 threshold = rdma->fifo_size * 7 / 10;
+
+       mtk_disp_comp_update(dev, DISP_REG_RDMA_SIZE_CON_0,
+                            FIELD_PREP(RDMA_SIZE_CON_0_WIDTH, 
timing->hactive.typ),
+                            RDMA_SIZE_CON_0_WIDTH);
+       mtk_disp_comp_update(dev, DISP_REG_RDMA_SIZE_CON_1,
+                            FIELD_PREP(RDMA_SIZE_CON_1_HEIGHT, 
timing->vactive.typ),
+                            RDMA_SIZE_CON_1_HEIGHT);
+
+       /*
+        * Enable FIFO underflow since the DSI and the DPI can't be blocked,
+        * and set the output threshold to 70% of the FIFO size so that it
+        * never overflows.
+        */
+       mtk_disp_comp_write(dev, DISP_REG_RDMA_FIFO_CON,
+                           RDMA_FIFO_UNDERFLOW_EN |
+                           FIELD_PREP(RDMA_FIFO_PSEUDO_SIZE,
+                                      RDMA_FIFO_WORD(rdma->fifo_size)) |
+                           FIELD_PREP(RDMA_OUTPUT_VALID_FIFO_THRESHOLD,
+                                      RDMA_FIFO_WORD(threshold)));
+}
+
+void mtk_rdma_start(struct udevice *dev)
+{
+       mtk_disp_comp_update(dev, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN,
+                            RDMA_ENGINE_EN);
+}
+
+static int mtk_disp_rdma_probe(struct udevice *dev)
+{
+       struct mtk_disp_rdma_priv *rdma = dev_get_priv(dev);
+       const struct mtk_disp_rdma_data *data;
+       int ret;
+
+       data = (const struct mtk_disp_rdma_data *)dev_get_driver_data(dev);
+       if (!data)
+               return -EINVAL;
+
+       ret = mtk_disp_comp_probe(dev);
+       if (ret)
+               return ret;
+
+       /*
+        * The rdma sits behind an SMI larb, which has to be ungated with it
+        * even on the paths where the overlay is the one doing the DMA.
+        */
+       ret = mtk_disp_comp_get_larb(dev);
+       if (ret)
+               return ret;
+
+       /*
+        * The instances of a same SoC may have different FIFO depths, so the
+        * per-compatible size is only the default: the MT8365 and the MT8183
+        * describe both of their RDMAs in the device tree, the MT8186 none.
+        */
+       ret = dev_read_u32(dev, "mediatek,rdma-fifo-size", &rdma->fifo_size);
+       if (ret && ret != -EINVAL) {
+               dev_err(dev, "failed to get the rdma fifo size: %d\n", ret);
+               return ret;
+       }
+
+       if (ret)
+               rdma->fifo_size = data->fifo_size;
+
+       return 0;
+}
+
+static const struct mtk_disp_rdma_data mt8183_rdma_driver_data = {
+       .fifo_size = 5 * SZ_1K,
+};
+
+static const struct mtk_disp_rdma_data mt8195_rdma_driver_data = {
+       .fifo_size = 1920,
+};
+
+static const struct udevice_id mtk_disp_rdma_ids[] = {
+       {
+               .compatible = "mediatek,mt8183-disp-rdma",
+               .data = (ulong)&mt8183_rdma_driver_data,
+       },
+       {
+               .compatible = "mediatek,mt8195-disp-rdma",
+               .data = (ulong)&mt8195_rdma_driver_data,
+       },
+       { }
+};
+
+U_BOOT_DRIVER(mtk_disp_rdma) = {
+       .name      = "mtk_disp_rdma",
+       .id        = UCLASS_MISC,
+       .of_match  = mtk_disp_rdma_ids,
+       .probe     = mtk_disp_rdma_probe,
+       .priv_auto = sizeof(struct mtk_disp_rdma_priv),
+};
diff --git a/drivers/video/mediatek/mtk_disp_rdma.h 
b/drivers/video/mediatek/mtk_disp_rdma.h
new file mode 100644
index 00000000000..c2fe9228661
--- /dev/null
+++ b/drivers/video/mediatek/mtk_disp_rdma.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026 BayLibre, SAS.
+ * Author: Julien Masson <[email protected]>
+ *         Julien Stephan <[email protected]>
+ */
+
+#ifndef _MTK_DISP_RDMA_H
+#define _MTK_DISP_RDMA_H
+
+struct display_timing;
+struct udevice;
+
+/**
+ * mtk_rdma_config() - configure an rdma
+ * @dev: rdma device
+ * @timing: display timing, giving the frame size
+ *
+ * Set the frame size and the FIFO thresholds of the rdma, which passes the
+ * overlay output through without reading DRAM itself.
+ */
+void mtk_rdma_config(struct udevice *dev, const struct display_timing *timing);
+
+/**
+ * mtk_rdma_start() - start an rdma
+ * @dev: rdma device
+ */
+void mtk_rdma_start(struct udevice *dev);
+
+#endif /* _MTK_DISP_RDMA_H */

-- 
2.55.0

Reply via email to