DMA Engine development
 help / color / mirror / Atom feed
* [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support
@ 2026-09-22  9:25 Binbin Zhou
  2026-09-22  9:25 ` [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-22  9:25 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine
  Cc: Huacai Chen, devicetree, Keguang Zhang, Binbin Zhou

Hi all:

Loongson-2K0300 integrates a CMC DMA controller with 8 physical
channels. Peripheral DMA requests are not hard-wired to these channels;
they are routed through the CHIP_CTRL13/14/15 DMA_MAP fields.

This series adds support for that DMA request router.

Patch 1 adds the DT binding constants for the peripheral request IDs.
Patch 2 adds the DT binding documentation for the DMA mux.
Patch 3 adds the driver, Kconfig symbol and Makefile entry.

The driver registers with of_dma_router_register(). In the route
allocation callback it validates the <request> <channel> <flags>
specifier, programs the SoC-specific route register, and forwards
<channel> <flags> to the parent CMC DMA controller.

Thanks.
Binbin.

Binbin Zhou (3):
  dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs
  dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
  dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver

 .../dma/loongson,ls2k0300-dmamux.yaml         |  49 +++
 MAINTAINERS                                   |   3 +
 drivers/dma/loongson/Kconfig                  |  13 +
 drivers/dma/loongson/Makefile                 |   1 +
 drivers/dma/loongson/loongson2-apb-dmamux.c   | 380 ++++++++++++++++++
 .../dt-bindings/dma/loongson,ls2k-dmamux.h    |  56 +++
 6 files changed, 502 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
 create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c
 create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h


base-commit: 0a8dda0a15d3926422d286567f945a05328a4ac6
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs
  2026-09-22  9:25 [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou
@ 2026-09-22  9:25 ` Binbin Zhou
  2026-09-22  9:34   ` sashiko-bot
  2026-09-30 21:52   ` Frank Li
  2026-09-22  9:25 ` [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-22  9:25 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine
  Cc: Huacai Chen, devicetree, Keguang Zhang, Binbin Zhou

Add DT binding constants for the Loongson-2 DMA mux.

The header defines the peripheral request IDs used in the DMA specifier
<request channel flags> for Loongson-2K0300, covering UART0-9, I2C0-3,
SPI2/3, I2S, ADC and CAN0-3. It also documents the channel-pair semantics
for peripherals that use paired DMA channels.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 MAINTAINERS                                   |  1 +
 .../dt-bindings/dma/loongson,ls2k-dmamux.h    | 56 +++++++++++++++++++
 2 files changed, 57 insertions(+)
 create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h

diff --git a/MAINTAINERS b/MAINTAINERS
index c31b81eb42d7..b021fb623446 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15347,6 +15347,7 @@ F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
 F:	Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
 F:	drivers/dma/loongson/loongson2-apb-cmc-dma.c
 F:	drivers/dma/loongson/loongson2-apb-dma.c
+F:	include/dt-bindings/dma/loongson,ls2k-dmamux.h
 
 LOONGSON LS2X I2C DRIVER
 M:	Binbin Zhou <zhoubinbin@loongson.cn>
diff --git a/include/dt-bindings/dma/loongson,ls2k-dmamux.h b/include/dt-bindings/dma/loongson,ls2k-dmamux.h
new file mode 100644
index 000000000000..dcc8df86befb
--- /dev/null
+++ b/include/dt-bindings/dma/loongson,ls2k-dmamux.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Loongson-2 SoC DMA Mux dt-bindings
+ *
+ * DMA specifier format:
+ *   dmas = <&dma_mux <request> <channel> <flags>>;
+ *
+ * The <channel> cell selects a physical CMC DMA channel (0-7)
+ * For peripherals using channel pairs (UART, I2C, SPI2/3, I2S),
+ * the channel number selects the pair: 0/1 -> pair 0, 2/3 -> pair 1,
+ * 4/5 -> pair 2, 6/7 -> pair 3.
+ *
+ * Copyright (C) 2026 Loongson Technology Corporation Limited
+ */
+
+#ifndef _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H
+#define _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H
+
+/* UART controllers */
+#define LS2K0300_DMA_UART0		0
+#define LS2K0300_DMA_UART1		1
+#define LS2K0300_DMA_UART2		2
+#define LS2K0300_DMA_UART3		3
+#define LS2K0300_DMA_UART4		4
+#define LS2K0300_DMA_UART5		5
+#define LS2K0300_DMA_UART6		6
+#define LS2K0300_DMA_UART7		7
+#define LS2K0300_DMA_UART8		8
+#define LS2K0300_DMA_UART9		9
+
+/* I2C controllers */
+#define LS2K0300_DMA_I2C0		10
+#define LS2K0300_DMA_I2C1		11
+#define LS2K0300_DMA_I2C2		12
+#define LS2K0300_DMA_I2C3		13
+
+/* SPI controllers (IO mode) */
+#define LS2K0300_DMA_SPI2		14
+#define LS2K0300_DMA_SPI3		15
+
+/* I2S controller */
+#define LS2K0300_DMA_I2S		16
+
+/* ADC controller */
+#define LS2K0300_DMA_ADC		17
+
+/* CAN-FD controllers */
+#define LS2K0300_DMA_CAN0		18
+#define LS2K0300_DMA_CAN1		19
+#define LS2K0300_DMA_CAN2		20
+#define LS2K0300_DMA_CAN3		21
+
+/* Total number of 2K0300 DMA requests */
+#define LS2K0300_DMA_REQ_MAX		22
+
+#endif /* _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
  2026-09-22  9:25 [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou
  2026-09-22  9:25 ` [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
@ 2026-09-22  9:25 ` Binbin Zhou
  2026-09-30 21:44   ` Frank Li
  2026-09-22  9:25 ` [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
  2026-09-22 16:45 ` [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Frank Li
  3 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2026-09-22  9:25 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine
  Cc: Huacai Chen, devicetree, Keguang Zhang, Binbin Zhou

The DMA mux on Loongson-2K0300 is not a standalone hardware block. It is
implemented as part of the chip configuration registers CHIP_CTRL13/14/15,
which route peripheral DMA requests to the physical channels of the CMC
DMA controller.

Document this as a DMA router. The #dma-cells = <3> specifier contains
the peripheral request ID, the target CMC DMA channel, and channel
configuration flags forwarded to the parent DMA controller.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 .../dma/loongson,ls2k0300-dmamux.yaml         | 49 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml

diff --git a/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
new file mode 100644
index 000000000000..12b8f8af51e9
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/loongson,ls2k0300-dmamux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Loongson-2 APB DMA MUX (DMA request router)
+
+maintainers:
+  - Binbin Zhou <zhoubinbin@loongson.cn>
+
+allOf:
+  - $ref: /schemas/dma/dma-router.yaml#
+
+properties:
+  compatible:
+    const: loongson,ls2k0300-dmamux
+
+  reg:
+    maxItems: 1
+
+  '#dma-cells':
+    const: 3
+    description: |
+      Each cell represents the following:
+      1. The peripheral request id (see
+         include/dt-bindings/dma/loongson,ls2k-dmamux.h)
+      2. The physical CMC DMA channel (0-7) that is passed to the real
+         DMA controller
+      3. Bitfield representing DMA channel configuration that is passed
+         to the real DMA controller
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/dma/loongson,ls2k-dmamux.h>
+    dma-router@16000134 {
+        compatible = "loongson,ls2k0300-dmamux";
+        reg = <0x16000134 0xc>;
+        #dma-cells = <3>;
+        dma-masters = <&dma>;
+        dma-requests = <22>;
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index b021fb623446..dc976938c58c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15344,6 +15344,7 @@ M:	Binbin Zhou <zhoubinbin@loongson.cn>
 L:	dmaengine@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
+F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
 F:	Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
 F:	drivers/dma/loongson/loongson2-apb-cmc-dma.c
 F:	drivers/dma/loongson/loongson2-apb-dma.c
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver
  2026-09-22  9:25 [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou
  2026-09-22  9:25 ` [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
  2026-09-22  9:25 ` [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou
@ 2026-09-22  9:25 ` Binbin Zhou
  2026-09-22  9:36   ` sashiko-bot
                     ` (2 more replies)
  2026-09-22 16:45 ` [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Frank Li
  3 siblings, 3 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-22  9:25 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine
  Cc: Huacai Chen, devicetree, Keguang Zhang, Binbin Zhou

The Loongson-2K0300 DMA mux is not a standalone DMA controller. It is
implemented as a set of routing fields in the chip global configuration
registers CHIP_CTRL13/14/15, which select which physical channel of the
on-chip CMC DMA controller handles each peripheral DMA request.

Add a driver that exposes these routing fields as an OF DMA router. The
router's allocation callback validates the <request> <channel> <flags>
specifier, programs the corresponding CHIP_CTRL register field, and then
rewrites the specifier to <channel> <flags> so that the parent CMC DMA
controller's xlate is used.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 MAINTAINERS                                 |   1 +
 drivers/dma/loongson/Kconfig                |  13 +
 drivers/dma/loongson/Makefile               |   1 +
 drivers/dma/loongson/loongson2-apb-dmamux.c | 380 ++++++++++++++++++++
 4 files changed, 395 insertions(+)
 create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index dc976938c58c..82b32e14581f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15348,6 +15348,7 @@ F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
 F:	Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
 F:	drivers/dma/loongson/loongson2-apb-cmc-dma.c
 F:	drivers/dma/loongson/loongson2-apb-dma.c
+F:	drivers/dma/loongson/loongson2-apb-dmamux.c
 F:	include/dt-bindings/dma/loongson,ls2k-dmamux.h
 
 LOONGSON LS2X I2C DRIVER
diff --git a/drivers/dma/loongson/Kconfig b/drivers/dma/loongson/Kconfig
index c4e62dce5d4f..18edf06ef64e 100644
--- a/drivers/dma/loongson/Kconfig
+++ b/drivers/dma/loongson/Kconfig
@@ -38,4 +38,17 @@ config LOONGSON2_APB_CMC_DMA
 	  which has 4/8 channels internally, enabling bidirectional data transfer
 	  between devices and memory.
 
+config LOONGSON2_APB_DMAMUX
+	tristate "Loongson2 APB DMA Router (dmamux) support"
+	depends on LOONGSON2_APB_CMC_DMA
+	help
+	  Support for the DMA Mux controller found on Loongson-2 SoCs.
+
+	  On Loongson-2K0300, the DMA Mux routes peripheral DMA requests to
+	  one of the 8 physical channels of the on-chip CMC DMA controller
+	  by programming the CHIP_CTRL13/14/15 registers.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called loongson2-apb-dmamux.
+
 endif
diff --git a/drivers/dma/loongson/Makefile b/drivers/dma/loongson/Makefile
index 48c19781e729..517826a003ac 100644
--- a/drivers/dma/loongson/Makefile
+++ b/drivers/dma/loongson/Makefile
@@ -2,3 +2,4 @@
 obj-$(CONFIG_LOONGSON1_APB_DMA) += loongson1-apb-dma.o
 obj-$(CONFIG_LOONGSON2_APB_DMA) += loongson2-apb-dma.o
 obj-$(CONFIG_LOONGSON2_APB_CMC_DMA) += loongson2-apb-cmc-dma.o
+obj-$(CONFIG_LOONGSON2_APB_DMAMUX) += loongson2-apb-dmamux.o
diff --git a/drivers/dma/loongson/loongson2-apb-dmamux.c b/drivers/dma/loongson/loongson2-apb-dmamux.c
new file mode 100644
index 000000000000..b6f1f4112d61
--- /dev/null
+++ b/drivers/dma/loongson/loongson2-apb-dmamux.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Loongson2 SoC APB DMA Mux Controller
+ *
+ * Copyright (C) 2026 Loongson Technology Corporation Limited
+ *
+ * Device tree bindings:
+ *
+ *   2K0300:
+ *     dma_mux: dma-mux@16000134 {
+ *             compatible = "loongson,ls2k0300-dmamux";
+ *             reg = <0x0 0x16000134 0x0 0xc>;
+ *             #dma-cells = <3>;
+ *             dma-masters = <&dma>;
+ *             dma-requests = <22>;
+ *     };
+ *
+ * DMA specifier: <request> <channel> <flags>
+ *   - request: peripheral request ID (LS2K0300_DMA_* or LS2K1000_DMA_*)
+ *   - channel: target physical DMA channel or controller index
+ *   - flags:   channel configuration flags forwarded to the parent DMA
+ *              controller
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/dma/loongson,ls2k-dmamux.h>
+
+/* Loongson-2K0300 registers definitions */
+#define LS2K0300_CHIP_CTRL13		0x00
+#define LS2K0300_CHIP_CTRL14		0x04
+#define LS2K0300_CHIP_CTRL15		0x08
+
+/* CHIP_CTRL13 bitfields */
+#define CTRL13_UART0_DMA_MAP		GENMASK(17, 16)
+#define CTRL13_UART1_DMA_MAP		GENMASK(19, 18)
+#define CTRL13_UART2_DMA_MAP		GENMASK(21, 20)
+#define CTRL13_UART3_DMA_MAP		GENMASK(23, 22)
+#define CTRL13_UART4_DMA_MAP		GENMASK(25, 24)
+#define CTRL13_UART5_DMA_MAP		GENMASK(27, 26)
+#define CTRL13_UART6_DMA_MAP		GENMASK(29, 28)
+#define CTRL13_UART7_DMA_MAP		GENMASK(31, 30)
+
+/* CHIP_CTRL14 bitfields */
+#define CTRL14_UART8_DMA_MAP		GENMASK(1, 0)
+#define CTRL14_UART9_DMA_MAP		GENMASK(3, 2)
+#define CTRL14_I2C0_DMA_MAP		GENMASK(5, 4)
+#define CTRL14_I2C1_DMA_MAP		GENMASK(7, 6)
+#define CTRL14_I2C2_DMA_MAP		GENMASK(9, 8)
+#define CTRL14_I2C3_DMA_MAP		GENMASK(11, 10)
+#define CTRL14_SPI2_DMA_MAP		GENMASK(13, 12)
+#define CTRL14_SPI3_DMA_MAP		GENMASK(15, 14)
+#define CTRL14_I2S_DMA_MAP		GENMASK(17, 16)
+#define CTRL14_ADC_DMA_MAP		GENMASK(20, 18)
+#define CTRL14_CAN0_DMA_MAP		GENMASK(23, 21)
+#define CTRL14_CAN1_DMA_MAP		GENMASK(26, 24)
+#define CTRL14_CAN2_DMA_MAP		GENMASK(29, 27)
+#define CTRL14_CAN3_DMA_MAP		GENMASK(31, 30)
+
+/* CHIP_CTRL15 bitfields */
+#define CTRL15_CAN3_DMA_MAP_HI		BIT(0)
+
+#define LS2K0300_DMA_MAX_CHANNEL	7
+
+/**
+ * enum loongson2_dmamux_type - Type of the mapping field
+ * @LOONGSON_DMAMUX_PAIR: 2-bit field, value selects a channel pair
+ *                        (0/1, 2/3, 4/5, 6/7) — used on 2K0300.
+ * @LOONGSON_DMAMUX_SINGLE: 3-bit field, value selects a single channel
+ *                          or controller index directly.
+ */
+enum loongson2_dmamux_type {
+	LOONGSON_DMAMUX_PAIR,
+	LOONGSON_DMAMUX_SINGLE,
+};
+
+/**
+ * struct loongson2_dmamux_map - DMA request to register bitfield mapping
+ * @reg: Register offset from the controller base
+ * @mask: Bitfield mask within the register
+ * @shift: Starting bit position of the bitfield
+ * @type: Mapping type (pair or single)
+ * @high_reg: Optional extension register offset (0 if unused)
+ * @high_shift: Bit position in the extension register
+ */
+struct loongson2_dmamux_map {
+	u32 reg;
+	u32 mask;
+	u8 shift;
+	enum loongson2_dmamux_type type;
+	u32 high_reg;
+	u8 high_shift;
+};
+
+/**
+ * struct loongson2_dmamux_config - SoC-specific DMA mux configuration
+ * @maps: Pointer to the request mapping table
+ * @num_maps: Number of entries in @maps
+ * @max_channel: Highest valid channel/controller index
+ * @parent_args_count: Number of cells to write to dma_spec->args[]
+ *                     when forwarding to the parent xlate.
+ */
+struct loongson2_dmamux_config {
+	const struct loongson2_dmamux_map *maps;
+	u32 num_maps;
+	u32 max_channel;
+	u32 parent_args_count;
+};
+
+/**
+ * struct loongson2_dmamux - DMA mux controller state
+ * @dev: Back pointer to the platform device
+ * @base: I/O-mapped register base
+ * @lock: Protects register read-modify-write sequences
+ * @dma_np: The parent DMA controller device nodes
+ * @dma_router: Router structure passed to of_dma_router_register()
+ * @config: SoC-specific configuration
+ */
+struct loongson2_dmamux {
+	struct device *dev;
+	void __iomem *base;
+	struct mutex lock;	/* Protects register read-modify-write sequences */
+	struct device_node *dma_np;
+	struct dma_router dma_router;
+	const struct loongson2_dmamux_config *config;
+};
+
+/* Loongson-2K0300 mapping table */
+static const struct loongson2_dmamux_map ls2k0300_dmamux_maps[] = {
+	[LS2K0300_DMA_UART0] = { LS2K0300_CHIP_CTRL13, CTRL13_UART0_DMA_MAP, 16,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART1] = { LS2K0300_CHIP_CTRL13, CTRL13_UART1_DMA_MAP, 18,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART2] = { LS2K0300_CHIP_CTRL13, CTRL13_UART2_DMA_MAP, 20,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART3] = { LS2K0300_CHIP_CTRL13, CTRL13_UART3_DMA_MAP, 22,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART4] = { LS2K0300_CHIP_CTRL13, CTRL13_UART4_DMA_MAP, 24,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART5] = { LS2K0300_CHIP_CTRL13, CTRL13_UART5_DMA_MAP, 26,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART6] = { LS2K0300_CHIP_CTRL13, CTRL13_UART6_DMA_MAP, 28,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART7] = { LS2K0300_CHIP_CTRL13, CTRL13_UART7_DMA_MAP, 30,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART8] = { LS2K0300_CHIP_CTRL14, CTRL14_UART8_DMA_MAP,  0,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_UART9] = { LS2K0300_CHIP_CTRL14, CTRL14_UART9_DMA_MAP,  2,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_I2C0]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C0_DMA_MAP,   4,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_I2C1]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C1_DMA_MAP,   6,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_I2C2]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C2_DMA_MAP,   8,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_I2C3]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C3_DMA_MAP,  10,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_SPI2]  = { LS2K0300_CHIP_CTRL14, CTRL14_SPI2_DMA_MAP,  12,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_SPI3]  = { LS2K0300_CHIP_CTRL14, CTRL14_SPI3_DMA_MAP,  14,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_I2S]   = { LS2K0300_CHIP_CTRL14, CTRL14_I2S_DMA_MAP,   16,
+				 LOONGSON_DMAMUX_PAIR,   0, 0 },
+	[LS2K0300_DMA_ADC]   = { LS2K0300_CHIP_CTRL14, CTRL14_ADC_DMA_MAP,   18,
+				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
+	[LS2K0300_DMA_CAN0]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN0_DMA_MAP,  21,
+				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
+	[LS2K0300_DMA_CAN1]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN1_DMA_MAP,  24,
+				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
+	[LS2K0300_DMA_CAN2]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN2_DMA_MAP,  27,
+				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
+	[LS2K0300_DMA_CAN3]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN3_DMA_MAP,  30,
+				 LOONGSON_DMAMUX_SINGLE, LS2K0300_CHIP_CTRL15, 0 },
+};
+
+static const struct loongson2_dmamux_config ls2k0300_dmamux_config = {
+	.maps			= ls2k0300_dmamux_maps,
+	.num_maps		= ARRAY_SIZE(ls2k0300_dmamux_maps),
+	.max_channel		= LS2K0300_DMA_MAX_CHANNEL,
+	.parent_args_count	= 2,
+};
+
+static inline u32 loongson2_dmamux_read(struct loongson2_dmamux *mux, u32 reg)
+{
+	return readl(mux->base + reg);
+}
+
+static inline void loongson2_dmamux_write(struct loongson2_dmamux *mux, u32 reg, u32 val)
+{
+	writel(val, mux->base + reg);
+}
+
+/**
+ * loongson2_dmamux_set_route() - Program the DMA request route
+ * @mux:     DMA mux controller
+ * @request: Peripheral DMA request ID
+ * @channel: Target physical DMA channel or controller index
+ *
+ * Computes the register value according to the mapping type:
+ *   - PAIR   : channel / 2 selects the pair index
+ *   - SINGLE : channel is written directly
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+static int loongson2_dmamux_set_route(struct loongson2_dmamux *mux, u32 request, u32 channel)
+{
+	const struct loongson2_dmamux_map *map;
+	u32 reg_val, route_val, high_val = 0;
+
+	if (request >= mux->config->num_maps)
+		return -EINVAL;
+
+	if (channel > mux->config->max_channel)
+		return -EINVAL;
+
+	map = &mux->config->maps[request];
+
+	switch (map->type) {
+	case LOONGSON_DMAMUX_PAIR:
+		route_val = channel / 2;
+		break;
+	case LOONGSON_DMAMUX_SINGLE:
+		route_val = channel;
+		if (map->high_reg)
+			high_val = (channel >> 2) & 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&mux->lock);
+
+	/* Write the primary register field */
+	reg_val = loongson2_dmamux_read(mux, map->reg);
+	reg_val &= ~map->mask;
+	reg_val |= field_prep(map->mask, route_val);
+	loongson2_dmamux_write(mux, map->reg, reg_val);
+
+	/* Write the extension register field if present */
+	if (map->high_reg) {
+		reg_val = loongson2_dmamux_read(mux, map->high_reg);
+		reg_val &= ~BIT(map->high_shift);
+		reg_val |= high_val << map->high_shift;
+		loongson2_dmamux_write(mux, map->high_reg, reg_val);
+	}
+
+	mutex_unlock(&mux->lock);
+
+	return 0;
+}
+
+/**
+ * loongson2_dmamux_route_allocate() - DMA router allocation callback
+ * @dma_spec: OF DMA specifier <request> <channel> <flags>
+ * @ofdma:    Router's of_dma structure; ofdma->dma_router points to our
+ *            struct dma_router embedded in struct loongson2_dmamux.
+ *
+ * Return: NULL as route_data (nothing to free), or an ERR_PTR on failure.
+ */
+static void *loongson2_dmamux_route_allocate(struct of_phandle_args *dma_spec,
+					     struct of_dma *ofdma)
+{
+	struct loongson2_dmamux *mux;
+	u32 request, channel, flags;
+	int ret;
+
+	if (!ofdma->dma_router)
+		return ERR_PTR(-EINVAL);
+
+	mux = container_of(ofdma->dma_router, struct loongson2_dmamux, dma_router);
+
+	if (dma_spec->args_count < 3)
+		return ERR_PTR(-EINVAL);
+
+	request = dma_spec->args[0];
+	channel = dma_spec->args[1];
+	flags = dma_spec->args[2];
+
+	if (request >= mux->config->num_maps ||
+	    channel > mux->config->max_channel)
+		return ERR_PTR(-EINVAL);
+
+	/* Program the SoC-specific route register */
+	ret = loongson2_dmamux_set_route(mux, request, channel);
+	if (ret)
+		return ERR_PTR(ret);
+
+	/*
+	 * Rewrite dma_spec so the kernel router framework uses it to look
+	 * up the parent DMA controller and invoke its xlate.
+	 */
+	dma_spec->np = mux->dma_np;
+	dma_spec->args[0] = channel;
+	dma_spec->args[1] = flags;
+	dma_spec->args_count = mux->config->parent_args_count;
+
+	return NULL;
+}
+
+static int loongson2_dmamux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct loongson2_dmamux *mux;
+	int ret;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	mux->dev = dev;
+	mux->config = &ls2k0300_dmamux_config;
+	mutex_init(&mux->lock);
+
+	mux->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(mux->base))
+		return PTR_ERR(mux->base);
+
+	/* Parse parent DMA controller nodes */
+	mux->dma_np = of_parse_phandle(dev->of_node, "dma-masters", 0);
+	if (!mux->dma_np)
+		return dev_err_probe(dev, -ENODEV,
+				     "Failed to find parent DMA controller\n");
+
+	mux->dma_router.dev = dev;
+	mux->dma_router.route_free = NULL;
+
+	platform_set_drvdata(pdev, mux);
+
+	ret = of_dma_router_register(dev->of_node, loongson2_dmamux_route_allocate,
+				     &mux->dma_router);
+	if (ret) {
+		of_node_put(mux->dma_np);
+		return dev_err_probe(dev, ret,
+				     "Failed to register DMA router\n");
+	}
+
+	dev_info(dev,
+		 "Loongson2 DMA Mux Controller registered (max_channel=%u, requests=%u)\n",
+		 mux->config->max_channel, mux->config->num_maps);
+
+	return 0;
+}
+
+static void loongson2_dmamux_remove(struct platform_device *pdev)
+{
+	struct loongson2_dmamux *mux = platform_get_drvdata(pdev);
+
+	of_dma_controller_free(pdev->dev.of_node);
+	of_node_put(mux->dma_np);
+}
+
+static const struct of_device_id loongson2_dmamux_of_match[] = {
+	{ .compatible = "loongson,ls2k0300-dmamux" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, loongson2_dmamux_of_match);
+
+static struct platform_driver loongson2_dmamux_driver = {
+	.driver = {
+		.name = "loongson2-dmamux",
+		.of_match_table = loongson2_dmamux_of_match,
+	},
+	.probe = loongson2_dmamux_probe,
+	.remove = loongson2_dmamux_remove,
+};
+module_platform_driver(loongson2_dmamux_driver);
+
+MODULE_DESCRIPTION("Loongson SoC DMA Mux Controller driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs
  2026-09-22  9:25 ` [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
@ 2026-09-22  9:34   ` sashiko-bot
  2026-09-30 21:52   ` Frank Li
  1 sibling, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-09-22  9:34 UTC (permalink / raw)
  To: Binbin Zhou; +Cc: vkoul, conor+dt, devicetree, robh, Frank.Li, dmaengine

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] dma: loongson: hardcoding physical DMA channel in device tree
- [Low] dma: loongson: expose LS2K0300_DMA_REQ_MAX in binding header
--

commit e4e9feb04bfe5cf0cae531423dc7021c3d20e99c
Author: Binbin Zhou <zhoubinbin@loongson.cn>

dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs

Add DT binding constants for the Loongson-2 DMA mux. It covers UART,
I2C, SPI, I2S, ADC, and CAN peripherals for Loongson-2K0300. It also
documents channel-pair semantics for peripherals using paired channels.

> diff --git a/include/dt-bindings/dma/loongson,ls2k-dmamux.h b/include/dt-bindings/dma/loongson,ls2k-dmamux.h
> new file mode 100644
> index 0000000000000..dcc8df86befbb
> --- /dev/null
> +++ b/include/dt-bindings/dma/loongson,ls2k-dmamux.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * Loongson-2 SoC DMA Mux dt-bindings
> + *
> + * DMA specifier format:
> + *   dmas = <&dma_mux <request> <channel> <flags>>;
> + *
> + * The <channel> cell selects a physical CMC DMA channel (0-7)

[Severity: Medium]
Does this design hardcode software resource allocation policy into the hardware
description?

Device trees should describe immutable hardware wiring rather than software
policy. Since the Loongson DMA mux is flexible (e.g., UART0 can be mapped to
one of 4 channel pairs via a 2-bit register field), shouldn't the OS DMA
engine dynamically allocate an available channel from a pool and program the
mux accordingly?

Statically assigning the channel in the DT shifts this policy to the hardware
description, preventing dynamic allocation and risking runtime resource
conflicts if multiple peripherals concurrently request the same statically
assigned channel.

> + * For peripherals using channel pairs (UART, I2C, SPI2/3, I2S),
> + * the channel number selects the pair: 0/1 -> pair 0, 2/3 -> pair 1,
> + * 4/5 -> pair 2, 6/7 -> pair 3.
> + *
> + * Copyright (C) 2026 Loongson Technology Corporation Limited
> + */

[ ... ]

> +/* CAN-FD controllers */
> +#define LS2K0300_DMA_CAN0		18
> +#define LS2K0300_DMA_CAN1		19
> +#define LS2K0300_DMA_CAN2		20
> +#define LS2K0300_DMA_CAN3		21
> +
> +/* Total number of 2K0300 DMA requests */
> +#define LS2K0300_DMA_REQ_MAX		22

[Severity: Low]
Is it safe to expose LS2K0300_DMA_REQ_MAX in a device tree binding header?

Device tree binding headers define the stable ABI between the hardware
description and the operating system. Exposing a _MAX macro is a known DT
anti-pattern.

If future hardware revisions or bindings add new request IDs, updating the _MAX
macro breaks backward compatibility with older compiled device trees or drivers
that rely on the previous value, potentially leading to out-of-bounds accesses
or ABI mismatches.

Should this macro be removed from the ABI header to prevent misuse?

> +
> +#endif /* _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1790068409.git.zhoubinbin@loongson.cn?part=1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver
  2026-09-22  9:25 ` [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
@ 2026-09-22  9:36   ` sashiko-bot
  2026-09-23  4:17   ` Huacai Chen
  2026-09-30 21:56   ` Frank Li
  2 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-09-22  9:36 UTC (permalink / raw)
  To: Binbin Zhou; +Cc: conor+dt, devicetree, vkoul, Frank.Li, robh, dmaengine

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] dmaengine: loongson: fix UAF of parent DMA node on route allocation
- [High] dmaengine: loongson: fix NULL pointer dereference on routing error paths
- [Low] dmaengine: loongson: remove unused 'shift' field from mapping structure
--

commit c46c8efe97ecad5eafdc1a9b6a37374efa172f8a
Author: Binbin Zhou <zhoubinbin@loongson.cn>

dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver

This commit adds a DMA mux driver for the Loongson-2K0300 SoC. It exposes the
routing fields in the chip global configuration registers as an OF DMA router,
which validates the specifier, programs the route, and forwards the translation
to the parent CMC DMA controller.

> diff --git a/drivers/dma/loongson/loongson2-apb-dmamux.c b/drivers/dma/loongson/loongson2-apb-dmamux.c
> new file mode 100644
> index 0000000000000..b6f1f4112d612
> --- /dev/null
> +++ b/drivers/dma/loongson/loongson2-apb-dmamux.c

[ ... ]

> +struct loongson2_dmamux_map {
> +	u32 reg;
> +	u32 mask;
> +	u8 shift;

[Severity: Low]
Is this shift field needed? Code inspection shows it is initialized in the
ls2k0300_dmamux_maps array for all entries but is never read. 

The routing logic in loongson2_dmamux_set_route() correctly manages the
shift operation implicitly using the field_prep() macro, which extracts
the shift directly from the compile-time constant mask.

> +	enum loongson2_dmamux_type type;
> +	u32 high_reg;
> +	u8 high_shift;
> +};

[ ... ]

> +static void *loongson2_dmamux_route_allocate(struct of_phandle_args *dma_spec,
> +					     struct of_dma *ofdma)
> +{

[ ... ]

> +	/* Program the SoC-specific route register */
> +	ret = loongson2_dmamux_set_route(mux, request, channel);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	/*
> +	 * Rewrite dma_spec so the kernel router framework uses it to look
> +	 * up the parent DMA controller and invoke its xlate.
> +	 */
> +	dma_spec->np = mux->dma_np;

[Severity: High]
Does this need to increment the reference count on the cached device node?

Looking at the OF DMA framework, of_dma_router_xlate() explicitly calls
of_node_put(dma_spec_target.np) after translating the channel request. Since
this assignment directly copies the pointer without taking a reference via
of_node_get(), will each DMA request unconditionally decrement the reference
count of the cached parent device node, leading to a premature release?

> +	dma_spec->args[0] = channel;
> +	dma_spec->args[1] = flags;
> +	dma_spec->args_count = mux->config->parent_args_count;
> +
> +	return NULL;
> +}

[ ... ]

> +static int loongson2_dmamux_probe(struct platform_device *pdev)
> +{

[ ... ]

> +	mux->dma_router.dev = dev;
> +	mux->dma_router.route_free = NULL;

[Severity: High]
Will setting this callback to NULL cause a panic on error paths?

In the framework's of_dma_router_xlate() function, if the parent DMA
controller is not yet available (triggering -EPROBE_DEFER), the framework
unconditionally executes ofdma->dma_router->route_free(...) without
checking if the callback exists.

Could this crash the kernel if the parent CMC DMA controller probes after
the peripheral?

> +
> +	platform_set_drvdata(pdev, mux);
> +
> +	ret = of_dma_router_register(dev->of_node, loongson2_dmamux_route_allocate,
> +				     &mux->dma_router);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1790068409.git.zhoubinbin@loongson.cn?part=3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support
  2026-09-22  9:25 [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou
                   ` (2 preceding siblings ...)
  2026-09-22  9:25 ` [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
@ 2026-09-22 16:45 ` Frank Li
  2026-09-23  5:53   ` Binbin Zhou
  3 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2026-09-22 16:45 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

On Tue, Sep 22, 2026 at 05:25:41PM +0800, Binbin Zhou wrote:
> Hi all:
>
> Loongson-2K0300 integrates a CMC DMA controller with 8 physical
> channels. Peripheral DMA requests are not hard-wired to these channels;
> they are routed through the CHIP_CTRL13/14/15 DMA_MAP fields.
>
> This series adds support for that DMA request router.
>
> Patch 1 adds the DT binding constants for the peripheral request IDs.
> Patch 2 adds the DT binding documentation for the DMA mux.
> Patch 3 adds the driver, Kconfig symbol and Makefile entry.
>
> The driver registers with of_dma_router_register(). In the route
> allocation callback it validates the <request> <channel> <flags>
> specifier, programs the SoC-specific route register, and forwards
> <channel> <flags> to the parent CMC DMA controller.

Is it possible use standard mux interface?

drivers/mux/mmio.c

Frank

>
> Thanks.
> Binbin.
>
> Binbin Zhou (3):
>   dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs
>   dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
>   dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver
>
>  .../dma/loongson,ls2k0300-dmamux.yaml         |  49 +++
>  MAINTAINERS                                   |   3 +
>  drivers/dma/loongson/Kconfig                  |  13 +
>  drivers/dma/loongson/Makefile                 |   1 +
>  drivers/dma/loongson/loongson2-apb-dmamux.c   | 380 ++++++++++++++++++
>  .../dt-bindings/dma/loongson,ls2k-dmamux.h    |  56 +++
>  6 files changed, 502 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
>  create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c
>  create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h
>
>
> base-commit: 0a8dda0a15d3926422d286567f945a05328a4ac6
> --
> 2.52.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver
  2026-09-22  9:25 ` [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
  2026-09-22  9:36   ` sashiko-bot
@ 2026-09-23  4:17   ` Huacai Chen
  2026-09-30 21:56   ` Frank Li
  2 siblings, 0 replies; 15+ messages in thread
From: Huacai Chen @ 2026-09-23  4:17 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, devicetree,
	Keguang Zhang

Hi, Binbin,

On Tue, Sep 22, 2026 at 5:26 PM Binbin Zhou <zhoubinbin@loongson.cn> wrote:
>
> The Loongson-2K0300 DMA mux is not a standalone DMA controller. It is
> implemented as a set of routing fields in the chip global configuration
> registers CHIP_CTRL13/14/15, which select which physical channel of the
> on-chip CMC DMA controller handles each peripheral DMA request.
>
> Add a driver that exposes these routing fields as an OF DMA router. The
> router's allocation callback validates the <request> <channel> <flags>
> specifier, programs the corresponding CHIP_CTRL register field, and then
> rewrites the specifier to <channel> <flags> so that the parent CMC DMA
> controller's xlate is used.
>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  MAINTAINERS                                 |   1 +
>  drivers/dma/loongson/Kconfig                |  13 +
>  drivers/dma/loongson/Makefile               |   1 +
>  drivers/dma/loongson/loongson2-apb-dmamux.c | 380 ++++++++++++++++++++
>  4 files changed, 395 insertions(+)
>  create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index dc976938c58c..82b32e14581f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15348,6 +15348,7 @@ F:      Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
>  F:     Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
>  F:     drivers/dma/loongson/loongson2-apb-cmc-dma.c
>  F:     drivers/dma/loongson/loongson2-apb-dma.c
> +F:     drivers/dma/loongson/loongson2-apb-dmamux.c
>  F:     include/dt-bindings/dma/loongson,ls2k-dmamux.h
>
>  LOONGSON LS2X I2C DRIVER
> diff --git a/drivers/dma/loongson/Kconfig b/drivers/dma/loongson/Kconfig
> index c4e62dce5d4f..18edf06ef64e 100644
> --- a/drivers/dma/loongson/Kconfig
> +++ b/drivers/dma/loongson/Kconfig
> @@ -38,4 +38,17 @@ config LOONGSON2_APB_CMC_DMA
>           which has 4/8 channels internally, enabling bidirectional data transfer
>           between devices and memory.
>
> +config LOONGSON2_APB_DMAMUX
> +       tristate "Loongson2 APB DMA Router (dmamux) support"
> +       depends on LOONGSON2_APB_CMC_DMA
If LOONGSON2_APB_DMAMUX is bound to LOONGSON2_APB_CMC_DMA (currently
it is true but I'm not sure in future), just use LOONGSON2_APB_CMC_DMA
in Makefile to compile both loongson2-apb-cmc-dma.c and
loongson2-apb-dmamux.c.

Huacai

> +       help
> +         Support for the DMA Mux controller found on Loongson-2 SoCs.
> +
> +         On Loongson-2K0300, the DMA Mux routes peripheral DMA requests to
> +         one of the 8 physical channels of the on-chip CMC DMA controller
> +         by programming the CHIP_CTRL13/14/15 registers.
> +
> +         To compile this driver as a module, choose M here: the module
> +         will be called loongson2-apb-dmamux.
> +
>  endif
> diff --git a/drivers/dma/loongson/Makefile b/drivers/dma/loongson/Makefile
> index 48c19781e729..517826a003ac 100644
> --- a/drivers/dma/loongson/Makefile
> +++ b/drivers/dma/loongson/Makefile
> @@ -2,3 +2,4 @@
>  obj-$(CONFIG_LOONGSON1_APB_DMA) += loongson1-apb-dma.o
>  obj-$(CONFIG_LOONGSON2_APB_DMA) += loongson2-apb-dma.o
>  obj-$(CONFIG_LOONGSON2_APB_CMC_DMA) += loongson2-apb-cmc-dma.o
> +obj-$(CONFIG_LOONGSON2_APB_DMAMUX) += loongson2-apb-dmamux.o
> diff --git a/drivers/dma/loongson/loongson2-apb-dmamux.c b/drivers/dma/loongson/loongson2-apb-dmamux.c
> new file mode 100644
> index 000000000000..b6f1f4112d61
> --- /dev/null
> +++ b/drivers/dma/loongson/loongson2-apb-dmamux.c
> @@ -0,0 +1,380 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Loongson2 SoC APB DMA Mux Controller
> + *
> + * Copyright (C) 2026 Loongson Technology Corporation Limited
> + *
> + * Device tree bindings:
> + *
> + *   2K0300:
> + *     dma_mux: dma-mux@16000134 {
> + *             compatible = "loongson,ls2k0300-dmamux";
> + *             reg = <0x0 0x16000134 0x0 0xc>;
> + *             #dma-cells = <3>;
> + *             dma-masters = <&dma>;
> + *             dma-requests = <22>;
> + *     };
> + *
> + * DMA specifier: <request> <channel> <flags>
> + *   - request: peripheral request ID (LS2K0300_DMA_* or LS2K1000_DMA_*)
> + *   - channel: target physical DMA channel or controller index
> + *   - flags:   channel configuration flags forwarded to the parent DMA
> + *              controller
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/device.h>
> +#include <linux/dmaengine.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_dma.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include <dt-bindings/dma/loongson,ls2k-dmamux.h>
> +
> +/* Loongson-2K0300 registers definitions */
> +#define LS2K0300_CHIP_CTRL13           0x00
> +#define LS2K0300_CHIP_CTRL14           0x04
> +#define LS2K0300_CHIP_CTRL15           0x08
> +
> +/* CHIP_CTRL13 bitfields */
> +#define CTRL13_UART0_DMA_MAP           GENMASK(17, 16)
> +#define CTRL13_UART1_DMA_MAP           GENMASK(19, 18)
> +#define CTRL13_UART2_DMA_MAP           GENMASK(21, 20)
> +#define CTRL13_UART3_DMA_MAP           GENMASK(23, 22)
> +#define CTRL13_UART4_DMA_MAP           GENMASK(25, 24)
> +#define CTRL13_UART5_DMA_MAP           GENMASK(27, 26)
> +#define CTRL13_UART6_DMA_MAP           GENMASK(29, 28)
> +#define CTRL13_UART7_DMA_MAP           GENMASK(31, 30)
> +
> +/* CHIP_CTRL14 bitfields */
> +#define CTRL14_UART8_DMA_MAP           GENMASK(1, 0)
> +#define CTRL14_UART9_DMA_MAP           GENMASK(3, 2)
> +#define CTRL14_I2C0_DMA_MAP            GENMASK(5, 4)
> +#define CTRL14_I2C1_DMA_MAP            GENMASK(7, 6)
> +#define CTRL14_I2C2_DMA_MAP            GENMASK(9, 8)
> +#define CTRL14_I2C3_DMA_MAP            GENMASK(11, 10)
> +#define CTRL14_SPI2_DMA_MAP            GENMASK(13, 12)
> +#define CTRL14_SPI3_DMA_MAP            GENMASK(15, 14)
> +#define CTRL14_I2S_DMA_MAP             GENMASK(17, 16)
> +#define CTRL14_ADC_DMA_MAP             GENMASK(20, 18)
> +#define CTRL14_CAN0_DMA_MAP            GENMASK(23, 21)
> +#define CTRL14_CAN1_DMA_MAP            GENMASK(26, 24)
> +#define CTRL14_CAN2_DMA_MAP            GENMASK(29, 27)
> +#define CTRL14_CAN3_DMA_MAP            GENMASK(31, 30)
> +
> +/* CHIP_CTRL15 bitfields */
> +#define CTRL15_CAN3_DMA_MAP_HI         BIT(0)
> +
> +#define LS2K0300_DMA_MAX_CHANNEL       7
> +
> +/**
> + * enum loongson2_dmamux_type - Type of the mapping field
> + * @LOONGSON_DMAMUX_PAIR: 2-bit field, value selects a channel pair
> + *                        (0/1, 2/3, 4/5, 6/7) — used on 2K0300.
> + * @LOONGSON_DMAMUX_SINGLE: 3-bit field, value selects a single channel
> + *                          or controller index directly.
> + */
> +enum loongson2_dmamux_type {
> +       LOONGSON_DMAMUX_PAIR,
> +       LOONGSON_DMAMUX_SINGLE,
> +};
> +
> +/**
> + * struct loongson2_dmamux_map - DMA request to register bitfield mapping
> + * @reg: Register offset from the controller base
> + * @mask: Bitfield mask within the register
> + * @shift: Starting bit position of the bitfield
> + * @type: Mapping type (pair or single)
> + * @high_reg: Optional extension register offset (0 if unused)
> + * @high_shift: Bit position in the extension register
> + */
> +struct loongson2_dmamux_map {
> +       u32 reg;
> +       u32 mask;
> +       u8 shift;
> +       enum loongson2_dmamux_type type;
> +       u32 high_reg;
> +       u8 high_shift;
> +};
> +
> +/**
> + * struct loongson2_dmamux_config - SoC-specific DMA mux configuration
> + * @maps: Pointer to the request mapping table
> + * @num_maps: Number of entries in @maps
> + * @max_channel: Highest valid channel/controller index
> + * @parent_args_count: Number of cells to write to dma_spec->args[]
> + *                     when forwarding to the parent xlate.
> + */
> +struct loongson2_dmamux_config {
> +       const struct loongson2_dmamux_map *maps;
> +       u32 num_maps;
> +       u32 max_channel;
> +       u32 parent_args_count;
> +};
> +
> +/**
> + * struct loongson2_dmamux - DMA mux controller state
> + * @dev: Back pointer to the platform device
> + * @base: I/O-mapped register base
> + * @lock: Protects register read-modify-write sequences
> + * @dma_np: The parent DMA controller device nodes
> + * @dma_router: Router structure passed to of_dma_router_register()
> + * @config: SoC-specific configuration
> + */
> +struct loongson2_dmamux {
> +       struct device *dev;
> +       void __iomem *base;
> +       struct mutex lock;      /* Protects register read-modify-write sequences */
> +       struct device_node *dma_np;
> +       struct dma_router dma_router;
> +       const struct loongson2_dmamux_config *config;
> +};
> +
> +/* Loongson-2K0300 mapping table */
> +static const struct loongson2_dmamux_map ls2k0300_dmamux_maps[] = {
> +       [LS2K0300_DMA_UART0] = { LS2K0300_CHIP_CTRL13, CTRL13_UART0_DMA_MAP, 16,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART1] = { LS2K0300_CHIP_CTRL13, CTRL13_UART1_DMA_MAP, 18,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART2] = { LS2K0300_CHIP_CTRL13, CTRL13_UART2_DMA_MAP, 20,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART3] = { LS2K0300_CHIP_CTRL13, CTRL13_UART3_DMA_MAP, 22,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART4] = { LS2K0300_CHIP_CTRL13, CTRL13_UART4_DMA_MAP, 24,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART5] = { LS2K0300_CHIP_CTRL13, CTRL13_UART5_DMA_MAP, 26,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART6] = { LS2K0300_CHIP_CTRL13, CTRL13_UART6_DMA_MAP, 28,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART7] = { LS2K0300_CHIP_CTRL13, CTRL13_UART7_DMA_MAP, 30,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART8] = { LS2K0300_CHIP_CTRL14, CTRL14_UART8_DMA_MAP,  0,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_UART9] = { LS2K0300_CHIP_CTRL14, CTRL14_UART9_DMA_MAP,  2,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_I2C0]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C0_DMA_MAP,   4,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_I2C1]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C1_DMA_MAP,   6,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_I2C2]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C2_DMA_MAP,   8,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_I2C3]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C3_DMA_MAP,  10,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_SPI2]  = { LS2K0300_CHIP_CTRL14, CTRL14_SPI2_DMA_MAP,  12,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_SPI3]  = { LS2K0300_CHIP_CTRL14, CTRL14_SPI3_DMA_MAP,  14,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_I2S]   = { LS2K0300_CHIP_CTRL14, CTRL14_I2S_DMA_MAP,   16,
> +                                LOONGSON_DMAMUX_PAIR,   0, 0 },
> +       [LS2K0300_DMA_ADC]   = { LS2K0300_CHIP_CTRL14, CTRL14_ADC_DMA_MAP,   18,
> +                                LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +       [LS2K0300_DMA_CAN0]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN0_DMA_MAP,  21,
> +                                LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +       [LS2K0300_DMA_CAN1]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN1_DMA_MAP,  24,
> +                                LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +       [LS2K0300_DMA_CAN2]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN2_DMA_MAP,  27,
> +                                LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +       [LS2K0300_DMA_CAN3]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN3_DMA_MAP,  30,
> +                                LOONGSON_DMAMUX_SINGLE, LS2K0300_CHIP_CTRL15, 0 },
> +};
> +
> +static const struct loongson2_dmamux_config ls2k0300_dmamux_config = {
> +       .maps                   = ls2k0300_dmamux_maps,
> +       .num_maps               = ARRAY_SIZE(ls2k0300_dmamux_maps),
> +       .max_channel            = LS2K0300_DMA_MAX_CHANNEL,
> +       .parent_args_count      = 2,
> +};
> +
> +static inline u32 loongson2_dmamux_read(struct loongson2_dmamux *mux, u32 reg)
> +{
> +       return readl(mux->base + reg);
> +}
> +
> +static inline void loongson2_dmamux_write(struct loongson2_dmamux *mux, u32 reg, u32 val)
> +{
> +       writel(val, mux->base + reg);
> +}
> +
> +/**
> + * loongson2_dmamux_set_route() - Program the DMA request route
> + * @mux:     DMA mux controller
> + * @request: Peripheral DMA request ID
> + * @channel: Target physical DMA channel or controller index
> + *
> + * Computes the register value according to the mapping type:
> + *   - PAIR   : channel / 2 selects the pair index
> + *   - SINGLE : channel is written directly
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int loongson2_dmamux_set_route(struct loongson2_dmamux *mux, u32 request, u32 channel)
> +{
> +       const struct loongson2_dmamux_map *map;
> +       u32 reg_val, route_val, high_val = 0;
> +
> +       if (request >= mux->config->num_maps)
> +               return -EINVAL;
> +
> +       if (channel > mux->config->max_channel)
> +               return -EINVAL;
> +
> +       map = &mux->config->maps[request];
> +
> +       switch (map->type) {
> +       case LOONGSON_DMAMUX_PAIR:
> +               route_val = channel / 2;
> +               break;
> +       case LOONGSON_DMAMUX_SINGLE:
> +               route_val = channel;
> +               if (map->high_reg)
> +                       high_val = (channel >> 2) & 0x1;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       mutex_lock(&mux->lock);
> +
> +       /* Write the primary register field */
> +       reg_val = loongson2_dmamux_read(mux, map->reg);
> +       reg_val &= ~map->mask;
> +       reg_val |= field_prep(map->mask, route_val);
> +       loongson2_dmamux_write(mux, map->reg, reg_val);
> +
> +       /* Write the extension register field if present */
> +       if (map->high_reg) {
> +               reg_val = loongson2_dmamux_read(mux, map->high_reg);
> +               reg_val &= ~BIT(map->high_shift);
> +               reg_val |= high_val << map->high_shift;
> +               loongson2_dmamux_write(mux, map->high_reg, reg_val);
> +       }
> +
> +       mutex_unlock(&mux->lock);
> +
> +       return 0;
> +}
> +
> +/**
> + * loongson2_dmamux_route_allocate() - DMA router allocation callback
> + * @dma_spec: OF DMA specifier <request> <channel> <flags>
> + * @ofdma:    Router's of_dma structure; ofdma->dma_router points to our
> + *            struct dma_router embedded in struct loongson2_dmamux.
> + *
> + * Return: NULL as route_data (nothing to free), or an ERR_PTR on failure.
> + */
> +static void *loongson2_dmamux_route_allocate(struct of_phandle_args *dma_spec,
> +                                            struct of_dma *ofdma)
> +{
> +       struct loongson2_dmamux *mux;
> +       u32 request, channel, flags;
> +       int ret;
> +
> +       if (!ofdma->dma_router)
> +               return ERR_PTR(-EINVAL);
> +
> +       mux = container_of(ofdma->dma_router, struct loongson2_dmamux, dma_router);
> +
> +       if (dma_spec->args_count < 3)
> +               return ERR_PTR(-EINVAL);
> +
> +       request = dma_spec->args[0];
> +       channel = dma_spec->args[1];
> +       flags = dma_spec->args[2];
> +
> +       if (request >= mux->config->num_maps ||
> +           channel > mux->config->max_channel)
> +               return ERR_PTR(-EINVAL);
> +
> +       /* Program the SoC-specific route register */
> +       ret = loongson2_dmamux_set_route(mux, request, channel);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       /*
> +        * Rewrite dma_spec so the kernel router framework uses it to look
> +        * up the parent DMA controller and invoke its xlate.
> +        */
> +       dma_spec->np = mux->dma_np;
> +       dma_spec->args[0] = channel;
> +       dma_spec->args[1] = flags;
> +       dma_spec->args_count = mux->config->parent_args_count;
> +
> +       return NULL;
> +}
> +
> +static int loongson2_dmamux_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct loongson2_dmamux *mux;
> +       int ret;
> +
> +       mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
> +       if (!mux)
> +               return -ENOMEM;
> +
> +       mux->dev = dev;
> +       mux->config = &ls2k0300_dmamux_config;
> +       mutex_init(&mux->lock);
> +
> +       mux->base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(mux->base))
> +               return PTR_ERR(mux->base);
> +
> +       /* Parse parent DMA controller nodes */
> +       mux->dma_np = of_parse_phandle(dev->of_node, "dma-masters", 0);
> +       if (!mux->dma_np)
> +               return dev_err_probe(dev, -ENODEV,
> +                                    "Failed to find parent DMA controller\n");
> +
> +       mux->dma_router.dev = dev;
> +       mux->dma_router.route_free = NULL;
> +
> +       platform_set_drvdata(pdev, mux);
> +
> +       ret = of_dma_router_register(dev->of_node, loongson2_dmamux_route_allocate,
> +                                    &mux->dma_router);
> +       if (ret) {
> +               of_node_put(mux->dma_np);
> +               return dev_err_probe(dev, ret,
> +                                    "Failed to register DMA router\n");
> +       }
> +
> +       dev_info(dev,
> +                "Loongson2 DMA Mux Controller registered (max_channel=%u, requests=%u)\n",
> +                mux->config->max_channel, mux->config->num_maps);
> +
> +       return 0;
> +}
> +
> +static void loongson2_dmamux_remove(struct platform_device *pdev)
> +{
> +       struct loongson2_dmamux *mux = platform_get_drvdata(pdev);
> +
> +       of_dma_controller_free(pdev->dev.of_node);
> +       of_node_put(mux->dma_np);
> +}
> +
> +static const struct of_device_id loongson2_dmamux_of_match[] = {
> +       { .compatible = "loongson,ls2k0300-dmamux" },
> +       { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, loongson2_dmamux_of_match);
> +
> +static struct platform_driver loongson2_dmamux_driver = {
> +       .driver = {
> +               .name = "loongson2-dmamux",
> +               .of_match_table = loongson2_dmamux_of_match,
> +       },
> +       .probe = loongson2_dmamux_probe,
> +       .remove = loongson2_dmamux_remove,
> +};
> +module_platform_driver(loongson2_dmamux_driver);
> +
> +MODULE_DESCRIPTION("Loongson SoC DMA Mux Controller driver");
> +MODULE_AUTHOR("Loongson Technology Corporation Limited");
> +MODULE_LICENSE("GPL");
> --
> 2.52.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support
  2026-09-22 16:45 ` [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Frank Li
@ 2026-09-23  5:53   ` Binbin Zhou
  0 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-09-23  5:53 UTC (permalink / raw)
  To: Frank Li
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

Hi Frank:

On Wed, Sep 23, 2026 at 12:45 AM Frank Li <Frank.li@oss.nxp.com> wrote:
>
> On Tue, Sep 22, 2026 at 05:25:41PM +0800, Binbin Zhou wrote:
> > Hi all:
> >
> > Loongson-2K0300 integrates a CMC DMA controller with 8 physical
> > channels. Peripheral DMA requests are not hard-wired to these channels;
> > they are routed through the CHIP_CTRL13/14/15 DMA_MAP fields.
> >
> > This series adds support for that DMA request router.
> >
> > Patch 1 adds the DT binding constants for the peripheral request IDs.
> > Patch 2 adds the DT binding documentation for the DMA mux.
> > Patch 3 adds the driver, Kconfig symbol and Makefile entry.
> >
> > The driver registers with of_dma_router_register(). In the route
> > allocation callback it validates the <request> <channel> <flags>
> > specifier, programs the SoC-specific route register, and forwards
> > <channel> <flags> to the parent CMC DMA controller.
>
> Is it possible use standard mux interface?
>
> drivers/mux/mmio.c

It does not appear to be reusable.
The mmio.c file appears to only involve setting bit fields in
registers, but here, not only do we need to set the bit fields, but we
also need to pass additional parameters to the DMA controller.

Take i2s as an example:
&i2s {
        status = “okay”;

        pinctrl-0 = <&i2s_pins>;
        pinctrl-names = “default”;

        dmas = <&dma_router LS2K0300_DMA_I2S 3 0xbf>,
                    <&dma_router LS2K0300_DMA_I2S 2 0xaf>;
        dma-names = “tx”, “rx”;
};

We need to pass the last two parameters <3, 0xbf>/<2, 0xaf> to
`loongson2-apb-cmc-dma` to complete the relevant configuration.

> Frank
>
> >
> > Thanks.
> > Binbin.
> >
> > Binbin Zhou (3):
> >   dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs
> >   dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
> >   dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver
> >
> >  .../dma/loongson,ls2k0300-dmamux.yaml         |  49 +++
> >  MAINTAINERS                                   |   3 +
> >  drivers/dma/loongson/Kconfig                  |  13 +
> >  drivers/dma/loongson/Makefile                 |   1 +
> >  drivers/dma/loongson/loongson2-apb-dmamux.c   | 380 ++++++++++++++++++
> >  .../dt-bindings/dma/loongson,ls2k-dmamux.h    |  56 +++
> >  6 files changed, 502 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> >  create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c
> >  create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h
> >
> >
> > base-commit: 0a8dda0a15d3926422d286567f945a05328a4ac6
> > --
> > 2.52.0
> >

-- 
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
  2026-09-22  9:25 ` [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou
@ 2026-09-30 21:44   ` Frank Li
  2026-10-02 14:00     ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2026-09-30 21:44 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

On Tue, Sep 22, 2026 at 05:25:43PM +0800, Binbin Zhou wrote:
> The DMA mux on Loongson-2K0300 is not a standalone hardware block. It is
> implemented as part of the chip configuration registers CHIP_CTRL13/14/15,
> which route peripheral DMA requests to the physical channels of the CMC
> DMA controller.
>
> Document this as a DMA router. The #dma-cells = <3> specifier contains
> the peripheral request ID, the target CMC DMA channel, and channel
> configuration flags forwarded to the parent DMA controller.
>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  .../dma/loongson,ls2k0300-dmamux.yaml         | 49 +++++++++++++++++++
>  MAINTAINERS                                   |  1 +
>  2 files changed, 50 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
>
> diff --git a/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> new file mode 100644
> index 000000000000..12b8f8af51e9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/dma/loongson,ls2k0300-dmamux.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Loongson-2 APB DMA MUX (DMA request router)
> +
> +maintainers:
> +  - Binbin Zhou <zhoubinbin@loongson.cn>
> +
> +allOf:
> +  - $ref: /schemas/dma/dma-router.yaml#
> +
> +properties:
> +  compatible:
> +    const: loongson,ls2k0300-dmamux
> +
> +  reg:
> +    maxItems: 1
> +
> +  '#dma-cells':
> +    const: 3
> +    description: |
> +      Each cell represents the following:
> +      1. The peripheral request id (see
> +         include/dt-bindings/dma/loongson,ls2k-dmamux.h)
> +      2. The physical CMC DMA channel (0-7) that is passed to the real
> +         DMA controller

Do you have restriction between request id and channel? Does any request id
route to any channel?

Frank
> +      3. Bitfield representing DMA channel configuration that is passed
> +         to the real DMA controller
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/dma/loongson,ls2k-dmamux.h>
> +    dma-router@16000134 {
> +        compatible = "loongson,ls2k0300-dmamux";
> +        reg = <0x16000134 0xc>;
> +        #dma-cells = <3>;
> +        dma-masters = <&dma>;
> +        dma-requests = <22>;
> +    };
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b021fb623446..dc976938c58c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15344,6 +15344,7 @@ M:	Binbin Zhou <zhoubinbin@loongson.cn>
>  L:	dmaengine@vger.kernel.org
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
> +F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
>  F:	Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
>  F:	drivers/dma/loongson/loongson2-apb-cmc-dma.c
>  F:	drivers/dma/loongson/loongson2-apb-dma.c
> --
> 2.52.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs
  2026-09-22  9:25 ` [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
  2026-09-22  9:34   ` sashiko-bot
@ 2026-09-30 21:52   ` Frank Li
  1 sibling, 0 replies; 15+ messages in thread
From: Frank Li @ 2026-09-30 21:52 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

On Tue, Sep 22, 2026 at 05:25:42PM +0800, Binbin Zhou wrote:
> Add DT binding constants for the Loongson-2 DMA mux.
>
> The header defines the peripheral request IDs used in the DMA specifier
> <request channel flags> for Loongson-2K0300, covering UART0-9, I2C0-3,
> SPI2/3, I2S, ADC and CAN0-3. It also documents the channel-pair semantics
> for peripherals that use paired DMA channels.
>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  MAINTAINERS                                   |  1 +
>  .../dt-bindings/dma/loongson,ls2k-dmamux.h    | 56 +++++++++++++++++++
>  2 files changed, 57 insertions(+)
>  create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c31b81eb42d7..b021fb623446 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15347,6 +15347,7 @@ F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
>  F:	Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
>  F:	drivers/dma/loongson/loongson2-apb-cmc-dma.c
>  F:	drivers/dma/loongson/loongson2-apb-dma.c
> +F:	include/dt-bindings/dma/loongson,ls2k-dmamux.h
>
>  LOONGSON LS2X I2C DRIVER
>  M:	Binbin Zhou <zhoubinbin@loongson.cn>
> diff --git a/include/dt-bindings/dma/loongson,ls2k-dmamux.h b/include/dt-bindings/dma/loongson,ls2k-dmamux.h
> new file mode 100644
> index 000000000000..dcc8df86befb
> --- /dev/null
> +++ b/include/dt-bindings/dma/loongson,ls2k-dmamux.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * Loongson-2 SoC DMA Mux dt-bindings
> + *
> + * DMA specifier format:
> + *   dmas = <&dma_mux <request> <channel> <flags>>;
> + *
> + * The <channel> cell selects a physical CMC DMA channel (0-7)
> + * For peripherals using channel pairs (UART, I2C, SPI2/3, I2S),
> + * the channel number selects the pair: 0/1 -> pair 0, 2/3 -> pair 1,
> + * 4/5 -> pair 2, 6/7 -> pair 3.
> + *
> + * Copyright (C) 2026 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H
> +#define _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H
> +
> +/* UART controllers */
> +#define LS2K0300_DMA_UART0		0
> +#define LS2K0300_DMA_UART1		1
> +#define LS2K0300_DMA_UART2		2
> +#define LS2K0300_DMA_UART3		3
> +#define LS2K0300_DMA_UART4		4
> +#define LS2K0300_DMA_UART5		5
> +#define LS2K0300_DMA_UART6		6
> +#define LS2K0300_DMA_UART7		7
> +#define LS2K0300_DMA_UART8		8
> +#define LS2K0300_DMA_UART9		9
> +
> +/* I2C controllers */
> +#define LS2K0300_DMA_I2C0		10
> +#define LS2K0300_DMA_I2C1		11
> +#define LS2K0300_DMA_I2C2		12
> +#define LS2K0300_DMA_I2C3		13
> +
> +/* SPI controllers (IO mode) */
> +#define LS2K0300_DMA_SPI2		14
> +#define LS2K0300_DMA_SPI3		15
> +
> +/* I2S controller */
> +#define LS2K0300_DMA_I2S		16
> +
> +/* ADC controller */
> +#define LS2K0300_DMA_ADC		17
> +
> +/* CAN-FD controllers */
> +#define LS2K0300_DMA_CAN0		18
> +#define LS2K0300_DMA_CAN1		19
> +#define LS2K0300_DMA_CAN2		20
> +#define LS2K0300_DMA_CAN3		21
> +
> +/* Total number of 2K0300 DMA requests */
> +#define LS2K0300_DMA_REQ_MAX		22

REQ_MAX is not ABI and your driver have not use it.

Frnak

> +
> +#endif /* _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H */
> --
> 2.52.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver
  2026-09-22  9:25 ` [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
  2026-09-22  9:36   ` sashiko-bot
  2026-09-23  4:17   ` Huacai Chen
@ 2026-09-30 21:56   ` Frank Li
  2 siblings, 0 replies; 15+ messages in thread
From: Frank Li @ 2026-09-30 21:56 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

On Tue, Sep 22, 2026 at 05:25:44PM +0800, Binbin Zhou wrote:
> The Loongson-2K0300 DMA mux is not a standalone DMA controller. It is
> implemented as a set of routing fields in the chip global configuration
> registers CHIP_CTRL13/14/15, which select which physical channel of the
> on-chip CMC DMA controller handles each peripheral DMA request.
>
> Add a driver that exposes these routing fields as an OF DMA router. The
> router's allocation callback validates the <request> <channel> <flags>
> specifier, programs the corresponding CHIP_CTRL register field, and then
> rewrites the specifier to <channel> <flags> so that the parent CMC DMA
> controller's xlate is used.
>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  MAINTAINERS                                 |   1 +
>  drivers/dma/loongson/Kconfig                |  13 +
>  drivers/dma/loongson/Makefile               |   1 +
>  drivers/dma/loongson/loongson2-apb-dmamux.c | 380 ++++++++++++++++++++
>  4 files changed, 395 insertions(+)
>  create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index dc976938c58c..82b32e14581f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15348,6 +15348,7 @@ F:	Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
>  F:	Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
>  F:	drivers/dma/loongson/loongson2-apb-cmc-dma.c
>  F:	drivers/dma/loongson/loongson2-apb-dma.c
> +F:	drivers/dma/loongson/loongson2-apb-dmamux.c
>  F:	include/dt-bindings/dma/loongson,ls2k-dmamux.h
>
>  LOONGSON LS2X I2C DRIVER
> diff --git a/drivers/dma/loongson/Kconfig b/drivers/dma/loongson/Kconfig
> index c4e62dce5d4f..18edf06ef64e 100644
> --- a/drivers/dma/loongson/Kconfig
> +++ b/drivers/dma/loongson/Kconfig
> @@ -38,4 +38,17 @@ config LOONGSON2_APB_CMC_DMA
>  	  which has 4/8 channels internally, enabling bidirectional data transfer
>  	  between devices and memory.
>
> +config LOONGSON2_APB_DMAMUX
> +	tristate "Loongson2 APB DMA Router (dmamux) support"
> +	depends on LOONGSON2_APB_CMC_DMA
> +	help
> +	  Support for the DMA Mux controller found on Loongson-2 SoCs.
> +
> +	  On Loongson-2K0300, the DMA Mux routes peripheral DMA requests to
> +	  one of the 8 physical channels of the on-chip CMC DMA controller
> +	  by programming the CHIP_CTRL13/14/15 registers.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called loongson2-apb-dmamux.
> +
>  endif
> diff --git a/drivers/dma/loongson/Makefile b/drivers/dma/loongson/Makefile
> index 48c19781e729..517826a003ac 100644
> --- a/drivers/dma/loongson/Makefile
> +++ b/drivers/dma/loongson/Makefile
> @@ -2,3 +2,4 @@
>  obj-$(CONFIG_LOONGSON1_APB_DMA) += loongson1-apb-dma.o
>  obj-$(CONFIG_LOONGSON2_APB_DMA) += loongson2-apb-dma.o
>  obj-$(CONFIG_LOONGSON2_APB_CMC_DMA) += loongson2-apb-cmc-dma.o
> +obj-$(CONFIG_LOONGSON2_APB_DMAMUX) += loongson2-apb-dmamux.o
> diff --git a/drivers/dma/loongson/loongson2-apb-dmamux.c b/drivers/dma/loongson/loongson2-apb-dmamux.c
> new file mode 100644
> index 000000000000..b6f1f4112d61
> --- /dev/null
> +++ b/drivers/dma/loongson/loongson2-apb-dmamux.c
> @@ -0,0 +1,380 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Loongson2 SoC APB DMA Mux Controller
> + *
> + * Copyright (C) 2026 Loongson Technology Corporation Limited
> + *
> + * Device tree bindings:
> + *
> + *   2K0300:
> + *     dma_mux: dma-mux@16000134 {
> + *             compatible = "loongson,ls2k0300-dmamux";
> + *             reg = <0x0 0x16000134 0x0 0xc>;
> + *             #dma-cells = <3>;
> + *             dma-masters = <&dma>;
> + *             dma-requests = <22>;
> + *     };
> + *
> + * DMA specifier: <request> <channel> <flags>
> + *   - request: peripheral request ID (LS2K0300_DMA_* or LS2K1000_DMA_*)
> + *   - channel: target physical DMA channel or controller index
> + *   - flags:   channel configuration flags forwarded to the parent DMA
> + *              controller
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/device.h>
> +#include <linux/dmaengine.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_dma.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include <dt-bindings/dma/loongson,ls2k-dmamux.h>
> +
> +/* Loongson-2K0300 registers definitions */
> +#define LS2K0300_CHIP_CTRL13		0x00
> +#define LS2K0300_CHIP_CTRL14		0x04
> +#define LS2K0300_CHIP_CTRL15		0x08
> +
> +/* CHIP_CTRL13 bitfields */
> +#define CTRL13_UART0_DMA_MAP		GENMASK(17, 16)
> +#define CTRL13_UART1_DMA_MAP		GENMASK(19, 18)
> +#define CTRL13_UART2_DMA_MAP		GENMASK(21, 20)
> +#define CTRL13_UART3_DMA_MAP		GENMASK(23, 22)
> +#define CTRL13_UART4_DMA_MAP		GENMASK(25, 24)
> +#define CTRL13_UART5_DMA_MAP		GENMASK(27, 26)
> +#define CTRL13_UART6_DMA_MAP		GENMASK(29, 28)
> +#define CTRL13_UART7_DMA_MAP		GENMASK(31, 30)
> +
> +/* CHIP_CTRL14 bitfields */
> +#define CTRL14_UART8_DMA_MAP		GENMASK(1, 0)
> +#define CTRL14_UART9_DMA_MAP		GENMASK(3, 2)
> +#define CTRL14_I2C0_DMA_MAP		GENMASK(5, 4)
> +#define CTRL14_I2C1_DMA_MAP		GENMASK(7, 6)
> +#define CTRL14_I2C2_DMA_MAP		GENMASK(9, 8)
> +#define CTRL14_I2C3_DMA_MAP		GENMASK(11, 10)
> +#define CTRL14_SPI2_DMA_MAP		GENMASK(13, 12)
> +#define CTRL14_SPI3_DMA_MAP		GENMASK(15, 14)
> +#define CTRL14_I2S_DMA_MAP		GENMASK(17, 16)
> +#define CTRL14_ADC_DMA_MAP		GENMASK(20, 18)
> +#define CTRL14_CAN0_DMA_MAP		GENMASK(23, 21)
> +#define CTRL14_CAN1_DMA_MAP		GENMASK(26, 24)
> +#define CTRL14_CAN2_DMA_MAP		GENMASK(29, 27)
> +#define CTRL14_CAN3_DMA_MAP		GENMASK(31, 30)
> +
> +/* CHIP_CTRL15 bitfields */
> +#define CTRL15_CAN3_DMA_MAP_HI		BIT(0)
> +
> +#define LS2K0300_DMA_MAX_CHANNEL	7
> +
> +/**
> + * enum loongson2_dmamux_type - Type of the mapping field
> + * @LOONGSON_DMAMUX_PAIR: 2-bit field, value selects a channel pair
> + *                        (0/1, 2/3, 4/5, 6/7) — used on 2K0300.
> + * @LOONGSON_DMAMUX_SINGLE: 3-bit field, value selects a single channel
> + *                          or controller index directly.
> + */
> +enum loongson2_dmamux_type {
> +	LOONGSON_DMAMUX_PAIR,
> +	LOONGSON_DMAMUX_SINGLE,
> +};
> +
> +/**
> + * struct loongson2_dmamux_map - DMA request to register bitfield mapping
> + * @reg: Register offset from the controller base
> + * @mask: Bitfield mask within the register
> + * @shift: Starting bit position of the bitfield
> + * @type: Mapping type (pair or single)
> + * @high_reg: Optional extension register offset (0 if unused)
> + * @high_shift: Bit position in the extension register
> + */
> +struct loongson2_dmamux_map {
> +	u32 reg;
> +	u32 mask;
> +	u8 shift;
> +	enum loongson2_dmamux_type type;
> +	u32 high_reg;
> +	u8 high_shift;
> +};
> +
> +/**
> + * struct loongson2_dmamux_config - SoC-specific DMA mux configuration
> + * @maps: Pointer to the request mapping table
> + * @num_maps: Number of entries in @maps
> + * @max_channel: Highest valid channel/controller index
> + * @parent_args_count: Number of cells to write to dma_spec->args[]
> + *                     when forwarding to the parent xlate.
> + */
> +struct loongson2_dmamux_config {
> +	const struct loongson2_dmamux_map *maps;
> +	u32 num_maps;
> +	u32 max_channel;
> +	u32 parent_args_count;
> +};
> +
> +/**
> + * struct loongson2_dmamux - DMA mux controller state
> + * @dev: Back pointer to the platform device
> + * @base: I/O-mapped register base
> + * @lock: Protects register read-modify-write sequences
> + * @dma_np: The parent DMA controller device nodes
> + * @dma_router: Router structure passed to of_dma_router_register()
> + * @config: SoC-specific configuration
> + */
> +struct loongson2_dmamux {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct mutex lock;	/* Protects register read-modify-write sequences */
> +	struct device_node *dma_np;
> +	struct dma_router dma_router;
> +	const struct loongson2_dmamux_config *config;
> +};
> +
> +/* Loongson-2K0300 mapping table */
> +static const struct loongson2_dmamux_map ls2k0300_dmamux_maps[] = {
> +	[LS2K0300_DMA_UART0] = { LS2K0300_CHIP_CTRL13, CTRL13_UART0_DMA_MAP, 16,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART1] = { LS2K0300_CHIP_CTRL13, CTRL13_UART1_DMA_MAP, 18,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART2] = { LS2K0300_CHIP_CTRL13, CTRL13_UART2_DMA_MAP, 20,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART3] = { LS2K0300_CHIP_CTRL13, CTRL13_UART3_DMA_MAP, 22,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART4] = { LS2K0300_CHIP_CTRL13, CTRL13_UART4_DMA_MAP, 24,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART5] = { LS2K0300_CHIP_CTRL13, CTRL13_UART5_DMA_MAP, 26,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART6] = { LS2K0300_CHIP_CTRL13, CTRL13_UART6_DMA_MAP, 28,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART7] = { LS2K0300_CHIP_CTRL13, CTRL13_UART7_DMA_MAP, 30,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART8] = { LS2K0300_CHIP_CTRL14, CTRL14_UART8_DMA_MAP,  0,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_UART9] = { LS2K0300_CHIP_CTRL14, CTRL14_UART9_DMA_MAP,  2,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_I2C0]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C0_DMA_MAP,   4,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_I2C1]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C1_DMA_MAP,   6,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_I2C2]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C2_DMA_MAP,   8,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_I2C3]  = { LS2K0300_CHIP_CTRL14, CTRL14_I2C3_DMA_MAP,  10,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_SPI2]  = { LS2K0300_CHIP_CTRL14, CTRL14_SPI2_DMA_MAP,  12,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_SPI3]  = { LS2K0300_CHIP_CTRL14, CTRL14_SPI3_DMA_MAP,  14,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_I2S]   = { LS2K0300_CHIP_CTRL14, CTRL14_I2S_DMA_MAP,   16,
> +				 LOONGSON_DMAMUX_PAIR,   0, 0 },
> +	[LS2K0300_DMA_ADC]   = { LS2K0300_CHIP_CTRL14, CTRL14_ADC_DMA_MAP,   18,
> +				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +	[LS2K0300_DMA_CAN0]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN0_DMA_MAP,  21,
> +				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +	[LS2K0300_DMA_CAN1]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN1_DMA_MAP,  24,
> +				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +	[LS2K0300_DMA_CAN2]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN2_DMA_MAP,  27,
> +				 LOONGSON_DMAMUX_SINGLE, 0, 0 },
> +	[LS2K0300_DMA_CAN3]  = { LS2K0300_CHIP_CTRL14, CTRL14_CAN3_DMA_MAP,  30,
> +				 LOONGSON_DMAMUX_SINGLE, LS2K0300_CHIP_CTRL15, 0 },
> +};
> +
> +static const struct loongson2_dmamux_config ls2k0300_dmamux_config = {
> +	.maps			= ls2k0300_dmamux_maps,
> +	.num_maps		= ARRAY_SIZE(ls2k0300_dmamux_maps),
> +	.max_channel		= LS2K0300_DMA_MAX_CHANNEL,
> +	.parent_args_count	= 2,
> +};
> +
> +static inline u32 loongson2_dmamux_read(struct loongson2_dmamux *mux, u32 reg)
> +{
> +	return readl(mux->base + reg);
> +}
> +
> +static inline void loongson2_dmamux_write(struct loongson2_dmamux *mux, u32 reg, u32 val)
> +{
> +	writel(val, mux->base + reg);
> +}
> +
> +/**
> + * loongson2_dmamux_set_route() - Program the DMA request route
> + * @mux:     DMA mux controller
> + * @request: Peripheral DMA request ID
> + * @channel: Target physical DMA channel or controller index
> + *
> + * Computes the register value according to the mapping type:
> + *   - PAIR   : channel / 2 selects the pair index
> + *   - SINGLE : channel is written directly
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int loongson2_dmamux_set_route(struct loongson2_dmamux *mux, u32 request, u32 channel)
> +{
> +	const struct loongson2_dmamux_map *map;
> +	u32 reg_val, route_val, high_val = 0;
> +
> +	if (request >= mux->config->num_maps)
> +		return -EINVAL;
> +
> +	if (channel > mux->config->max_channel)
> +		return -EINVAL;
> +
> +	map = &mux->config->maps[request];
> +
> +	switch (map->type) {
> +	case LOONGSON_DMAMUX_PAIR:
> +		route_val = channel / 2;
> +		break;
> +	case LOONGSON_DMAMUX_SINGLE:
> +		route_val = channel;
> +		if (map->high_reg)
> +			high_val = (channel >> 2) & 0x1;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&mux->lock);
> +
> +	/* Write the primary register field */
> +	reg_val = loongson2_dmamux_read(mux, map->reg);
> +	reg_val &= ~map->mask;
> +	reg_val |= field_prep(map->mask, route_val);
> +	loongson2_dmamux_write(mux, map->reg, reg_val);
> +
> +	/* Write the extension register field if present */
> +	if (map->high_reg) {
> +		reg_val = loongson2_dmamux_read(mux, map->high_reg);
> +		reg_val &= ~BIT(map->high_shift);
> +		reg_val |= high_val << map->high_shift;
> +		loongson2_dmamux_write(mux, map->high_reg, reg_val);
> +	}
> +
> +	mutex_unlock(&mux->lock);
> +
> +	return 0;
> +}
> +
> +/**
> + * loongson2_dmamux_route_allocate() - DMA router allocation callback
> + * @dma_spec: OF DMA specifier <request> <channel> <flags>
> + * @ofdma:    Router's of_dma structure; ofdma->dma_router points to our
> + *            struct dma_router embedded in struct loongson2_dmamux.
> + *
> + * Return: NULL as route_data (nothing to free), or an ERR_PTR on failure.
> + */
> +static void *loongson2_dmamux_route_allocate(struct of_phandle_args *dma_spec,
> +					     struct of_dma *ofdma)
> +{
> +	struct loongson2_dmamux *mux;
> +	u32 request, channel, flags;
> +	int ret;
> +
> +	if (!ofdma->dma_router)
> +		return ERR_PTR(-EINVAL);
> +
> +	mux = container_of(ofdma->dma_router, struct loongson2_dmamux, dma_router);
> +
> +	if (dma_spec->args_count < 3)
> +		return ERR_PTR(-EINVAL);
> +
> +	request = dma_spec->args[0];
> +	channel = dma_spec->args[1];
> +	flags = dma_spec->args[2];
> +
> +	if (request >= mux->config->num_maps ||
> +	    channel > mux->config->max_channel)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* Program the SoC-specific route register */
> +	ret = loongson2_dmamux_set_route(mux, request, channel);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	/*
> +	 * Rewrite dma_spec so the kernel router framework uses it to look
> +	 * up the parent DMA controller and invoke its xlate.
> +	 */
> +	dma_spec->np = mux->dma_np;
> +	dma_spec->args[0] = channel;
> +	dma_spec->args[1] = flags;
> +	dma_spec->args_count = mux->config->parent_args_count;
> +
> +	return NULL;
> +}
> +
> +static int loongson2_dmamux_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct loongson2_dmamux *mux;
> +	int ret;
> +
> +	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return -ENOMEM;
> +
> +	mux->dev = dev;
> +	mux->config = &ls2k0300_dmamux_config;
> +	mutex_init(&mux->lock);

use devm_mutex_init();

> +
> +	mux->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(mux->base))
> +		return PTR_ERR(mux->base);
> +
> +	/* Parse parent DMA controller nodes */
> +	mux->dma_np = of_parse_phandle(dev->of_node, "dma-masters", 0);
> +	if (!mux->dma_np)
> +		return dev_err_probe(dev, -ENODEV,
> +				     "Failed to find parent DMA controller\n");
> +
> +	mux->dma_router.dev = dev;
> +	mux->dma_router.route_free = NULL;
> +
> +	platform_set_drvdata(pdev, mux);
> +
> +	ret = of_dma_router_register(dev->of_node, loongson2_dmamux_route_allocate,
> +				     &mux->dma_router);
> +	if (ret) {
> +		of_node_put(mux->dma_np);
> +		return dev_err_probe(dev, ret,
> +				     "Failed to register DMA router\n");
> +	}
> +
> +	dev_info(dev,
> +		 "Loongson2 DMA Mux Controller registered (max_channel=%u, requests=%u)\n",
> +		 mux->config->max_channel, mux->config->num_maps);
> +
> +	return 0;
> +}
> +
> +static void loongson2_dmamux_remove(struct platform_device *pdev)
> +{
> +	struct loongson2_dmamux *mux = platform_get_drvdata(pdev);
> +
> +	of_dma_controller_free(pdev->dev.of_node);

of_dma_router_free() is match of_dma_router_register() even through
it is the same.

Frank
> +	of_node_put(mux->dma_np);
> +}
> +
> +static const struct of_device_id loongson2_dmamux_of_match[] = {
> +	{ .compatible = "loongson,ls2k0300-dmamux" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, loongson2_dmamux_of_match);
> +
> +static struct platform_driver loongson2_dmamux_driver = {
> +	.driver = {
> +		.name = "loongson2-dmamux",
> +		.of_match_table = loongson2_dmamux_of_match,
> +	},
> +	.probe = loongson2_dmamux_probe,
> +	.remove = loongson2_dmamux_remove,
> +};
> +module_platform_driver(loongson2_dmamux_driver);
> +
> +MODULE_DESCRIPTION("Loongson SoC DMA Mux Controller driver");
> +MODULE_AUTHOR("Loongson Technology Corporation Limited");
> +MODULE_LICENSE("GPL");
> --
> 2.52.0
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
  2026-09-30 21:44   ` Frank Li
@ 2026-10-02 14:00     ` Binbin Zhou
  2026-10-02 14:47       ` Frank Li
  0 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2026-10-02 14:00 UTC (permalink / raw)
  To: Frank Li
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

Hi Frank:

Thanks for your reply.

On Thu, Oct 1, 2026 at 5:44 AM Frank Li <Frank.li@oss.nxp.com> wrote:
>
> On Tue, Sep 22, 2026 at 05:25:43PM +0800, Binbin Zhou wrote:
> > The DMA mux on Loongson-2K0300 is not a standalone hardware block. It is
> > implemented as part of the chip configuration registers CHIP_CTRL13/14/15,
> > which route peripheral DMA requests to the physical channels of the CMC
> > DMA controller.
> >
> > Document this as a DMA router. The #dma-cells = <3> specifier contains
> > the peripheral request ID, the target CMC DMA channel, and channel
> > configuration flags forwarded to the parent DMA controller.
> >
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> >  .../dma/loongson,ls2k0300-dmamux.yaml         | 49 +++++++++++++++++++
> >  MAINTAINERS                                   |  1 +
> >  2 files changed, 50 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > new file mode 100644
> > index 000000000000..12b8f8af51e9
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > @@ -0,0 +1,49 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/dma/loongson,ls2k0300-dmamux.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Loongson-2 APB DMA MUX (DMA request router)
> > +
> > +maintainers:
> > +  - Binbin Zhou <zhoubinbin@loongson.cn>
> > +
> > +allOf:
> > +  - $ref: /schemas/dma/dma-router.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    const: loongson,ls2k0300-dmamux
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  '#dma-cells':
> > +    const: 3
> > +    description: |
> > +      Each cell represents the following:
> > +      1. The peripheral request id (see
> > +         include/dt-bindings/dma/loongson,ls2k-dmamux.h)
> > +      2. The physical CMC DMA channel (0-7) that is passed to the real
> > +         DMA controller
>
> Do you have restriction between request id and channel? Does any request id
> route to any channel?

Yes, according to the description of this register’s bit fields in the
manual, DMA channels are not mapped arbitrarily.

We can broadly categorize them as follows:
1. First, most peripherals that use this DMA controller request
adjacent DMA channels (TX/RX) in pairs.
Let’s take I2S as an example.
Bits [17:16] at address `0x16000138` controls the I2S DMA channel mapping:
00: Channels 0, 1
01: Channels 2, 3
10: Channels 4, 5
11: Channels 6, 7
2. The SM/DES/AES module uses only channels 0 and 1, corresponding to
the bit field values 00 and 01, respectively.
3. The can/adc module is single-channel, so each bit in the
corresponding bit field corresponds to channels 0–7.

>
> Frank
> > +      3. Bitfield representing DMA channel configuration that is passed
> > +         to the real DMA controller
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/dma/loongson,ls2k-dmamux.h>
> > +    dma-router@16000134 {
> > +        compatible = "loongson,ls2k0300-dmamux";
> > +        reg = <0x16000134 0xc>;
> > +        #dma-cells = <3>;
> > +        dma-masters = <&dma>;
> > +        dma-requests = <22>;
> > +    };
> > +...
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index b021fb623446..dc976938c58c 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -15344,6 +15344,7 @@ M:    Binbin Zhou <zhoubinbin@loongson.cn>
> >  L:   dmaengine@vger.kernel.org
> >  S:   Maintained
> >  F:   Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
> > +F:   Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> >  F:   Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
> >  F:   drivers/dma/loongson/loongson2-apb-cmc-dma.c
> >  F:   drivers/dma/loongson/loongson2-apb-dma.c
> > --
> > 2.52.0
> >

--
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
  2026-10-02 14:00     ` Binbin Zhou
@ 2026-10-02 14:47       ` Frank Li
  2026-10-04  6:27         ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2026-10-02 14:47 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

On Fri, Oct 02, 2026 at 10:00:11PM +0800, Binbin Zhou wrote:
> Hi Frank:
>
> Thanks for your reply.
>
> On Thu, Oct 1, 2026 at 5:44 AM Frank Li <Frank.li@oss.nxp.com> wrote:
> >
> > On Tue, Sep 22, 2026 at 05:25:43PM +0800, Binbin Zhou wrote:
> > > The DMA mux on Loongson-2K0300 is not a standalone hardware block. It is
> > > implemented as part of the chip configuration registers CHIP_CTRL13/14/15,
> > > which route peripheral DMA requests to the physical channels of the CMC
> > > DMA controller.
> > >
> > > Document this as a DMA router. The #dma-cells = <3> specifier contains
> > > the peripheral request ID, the target CMC DMA channel, and channel
> > > configuration flags forwarded to the parent DMA controller.
> > >
> > > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > > ---
> > >  .../dma/loongson,ls2k0300-dmamux.yaml         | 49 +++++++++++++++++++
> > >  MAINTAINERS                                   |  1 +
> > >  2 files changed, 50 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > > new file mode 100644
> > > index 000000000000..12b8f8af51e9
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > > @@ -0,0 +1,49 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/dma/loongson,ls2k0300-dmamux.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Loongson-2 APB DMA MUX (DMA request router)
> > > +
> > > +maintainers:
> > > +  - Binbin Zhou <zhoubinbin@loongson.cn>
> > > +
> > > +allOf:
> > > +  - $ref: /schemas/dma/dma-router.yaml#
> > > +
> > > +properties:
> > > +  compatible:
> > > +    const: loongson,ls2k0300-dmamux
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  '#dma-cells':
> > > +    const: 3
> > > +    description: |
> > > +      Each cell represents the following:
> > > +      1. The peripheral request id (see
> > > +         include/dt-bindings/dma/loongson,ls2k-dmamux.h)
> > > +      2. The physical CMC DMA channel (0-7) that is passed to the real
> > > +         DMA controller
> >
> > Do you have restriction between request id and channel? Does any request id
> > route to any channel?
>
> Yes, according to the description of this register’s bit fields in the
> manual, DMA channels are not mapped arbitrarily.
>
> We can broadly categorize them as follows:
> 1. First, most peripherals that use this DMA controller request
> adjacent DMA channels (TX/RX) in pairs.
> Let’s take I2S as an example.
> Bits [17:16] at address `0x16000138` controls the I2S DMA channel mapping:
> 00: Channels 0, 1
> 01: Channels 2, 3
> 10: Channels 4, 5
> 11: Channels 6, 7
> 2. The SM/DES/AES module uses only channels 0 and 1, corresponding to
> the bit field values 00 and 01, respectively.
> 3. The can/adc module is single-channel, so each bit in the
> corresponding bit field corresponds to channels 0–7.

Does channel dynmatic allocated or have to static assign, if channel dynmatic
allocated, needn't arg2. If static assign, it'd better descript clean about
restriction between arg1 and arg2.

Frank

>
> >
> > Frank
> > > +      3. Bitfield representing DMA channel configuration that is passed
> > > +         to the real DMA controller
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +
> > > +unevaluatedProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    #include <dt-bindings/dma/loongson,ls2k-dmamux.h>
> > > +    dma-router@16000134 {
> > > +        compatible = "loongson,ls2k0300-dmamux";
> > > +        reg = <0x16000134 0xc>;
> > > +        #dma-cells = <3>;
> > > +        dma-masters = <&dma>;
> > > +        dma-requests = <22>;
> > > +    };
> > > +...
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index b021fb623446..dc976938c58c 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -15344,6 +15344,7 @@ M:    Binbin Zhou <zhoubinbin@loongson.cn>
> > >  L:   dmaengine@vger.kernel.org
> > >  S:   Maintained
> > >  F:   Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
> > > +F:   Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > >  F:   Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
> > >  F:   drivers/dma/loongson/loongson2-apb-cmc-dma.c
> > >  F:   drivers/dma/loongson/loongson2-apb-dma.c
> > > --
> > > 2.52.0
> > >
>
> --
> Thanks.
> Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support
  2026-10-02 14:47       ` Frank Li
@ 2026-10-04  6:27         ` Binbin Zhou
  0 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2026-10-04  6:27 UTC (permalink / raw)
  To: Frank Li
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen,
	devicetree, Keguang Zhang

Hi Frank:

On Fri, Oct 2, 2026 at 10:47 PM Frank Li <Frank.li@oss.nxp.com> wrote:
>
> On Fri, Oct 02, 2026 at 10:00:11PM +0800, Binbin Zhou wrote:
> > Hi Frank:
> >
> > Thanks for your reply.
> >
> > On Thu, Oct 1, 2026 at 5:44 AM Frank Li <Frank.li@oss.nxp.com> wrote:
> > >
> > > On Tue, Sep 22, 2026 at 05:25:43PM +0800, Binbin Zhou wrote:
> > > > The DMA mux on Loongson-2K0300 is not a standalone hardware block. It is
> > > > implemented as part of the chip configuration registers CHIP_CTRL13/14/15,
> > > > which route peripheral DMA requests to the physical channels of the CMC
> > > > DMA controller.
> > > >
> > > > Document this as a DMA router. The #dma-cells = <3> specifier contains
> > > > the peripheral request ID, the target CMC DMA channel, and channel
> > > > configuration flags forwarded to the parent DMA controller.
> > > >
> > > > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > > > ---
> > > >  .../dma/loongson,ls2k0300-dmamux.yaml         | 49 +++++++++++++++++++
> > > >  MAINTAINERS                                   |  1 +
> > > >  2 files changed, 50 insertions(+)
> > > >  create mode 100644 Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > > > new file mode 100644
> > > > index 000000000000..12b8f8af51e9
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > > > @@ -0,0 +1,49 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/dma/loongson,ls2k0300-dmamux.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Loongson-2 APB DMA MUX (DMA request router)
> > > > +
> > > > +maintainers:
> > > > +  - Binbin Zhou <zhoubinbin@loongson.cn>
> > > > +
> > > > +allOf:
> > > > +  - $ref: /schemas/dma/dma-router.yaml#
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    const: loongson,ls2k0300-dmamux
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  '#dma-cells':
> > > > +    const: 3
> > > > +    description: |
> > > > +      Each cell represents the following:
> > > > +      1. The peripheral request id (see
> > > > +         include/dt-bindings/dma/loongson,ls2k-dmamux.h)
> > > > +      2. The physical CMC DMA channel (0-7) that is passed to the real
> > > > +         DMA controller
> > >
> > > Do you have restriction between request id and channel? Does any request id
> > > route to any channel?
> >
> > Yes, according to the description of this register’s bit fields in the
> > manual, DMA channels are not mapped arbitrarily.
> >
> > We can broadly categorize them as follows:
> > 1. First, most peripherals that use this DMA controller request
> > adjacent DMA channels (TX/RX) in pairs.
> > Let’s take I2S as an example.
> > Bits [17:16] at address `0x16000138` controls the I2S DMA channel mapping:
> > 00: Channels 0, 1
> > 01: Channels 2, 3
> > 10: Channels 4, 5
> > 11: Channels 6, 7
> > 2. The SM/DES/AES module uses only channels 0 and 1, corresponding to
> > the bit field values 00 and 01, respectively.
> > 3. The can/adc module is single-channel, so each bit in the
> > corresponding bit field corresponds to channels 0–7.
>
> Does channel dynmatic allocated or have to static assign, if channel dynmatic
> allocated, needn't arg2. If static assign, it'd better descript clean about
> restriction between arg1 and arg2.

No, it needs to be statically assigned based on the register configuration.

Let me think about how to describe this better. First, both arg1 and
arg2 are required; they fully configure the register. arg1 determines
the range of the bit field, and arg2 determines the value of that bit
field.
At the same time, arg2 and arg3 are passed to the DMA controller
itself to complete the relevant initialization.

Is this description acceptable?

'#dma-cells':
const: 3
description: |
Each cell represents the following:
1. Peripheral request ID: This describes the corresponding bit field
for that peripheral in the configuration register; see (
include/dt-bindings/dma/loongson,ls2k-dmamux.h) for details.
2. Physical DMA channel (0–7): This not only represents the DMA
channel used by the peripheral but is also converted into a value for
the corresponding bit field in the configuration register, indicating
the legitimacy of that peripheral using that channel.
Specifically:
     1. I2S/SPI/UART/I2C: Require adjacent channels in pairs; valid
values are 0/1, 2/3, 4/5, 6/7;
     2. SM3/SM4/DES/AES: Single channel; valid values are limited to 0/1;
     3. CAN/ADC: Single channel; valid values range from 0 to 7.
3. DMA Channel Configuration: A 32-bit mask used to specify
device-specific DMA channel configurations.
- Bit 6: Peripheral Address Increment Mode
0x0: Disabled
0x1: Enabled
- Bit 7: Memory Address Increment Mode
0x0: Disabled
0x1: Enabled
- Bits 12–13: Priority
0x0: Low
0x1: Medium
0x2: High
0x3: Very High
.........

>
> Frank
>
> >
> > >
> > > Frank
> > > > +      3. Bitfield representing DMA channel configuration that is passed
> > > > +         to the real DMA controller
> > > > +
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > > +
> > > > +unevaluatedProperties: false
> > > > +
> > > > +examples:
> > > > +  - |
> > > > +    #include <dt-bindings/dma/loongson,ls2k-dmamux.h>
> > > > +    dma-router@16000134 {
> > > > +        compatible = "loongson,ls2k0300-dmamux";
> > > > +        reg = <0x16000134 0xc>;
> > > > +        #dma-cells = <3>;
> > > > +        dma-masters = <&dma>;
> > > > +        dma-requests = <22>;
> > > > +    };
> > > > +...
> > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > index b021fb623446..dc976938c58c 100644
> > > > --- a/MAINTAINERS
> > > > +++ b/MAINTAINERS
> > > > @@ -15344,6 +15344,7 @@ M:    Binbin Zhou <zhoubinbin@loongson.cn>
> > > >  L:   dmaengine@vger.kernel.org
> > > >  S:   Maintained
> > > >  F:   Documentation/devicetree/bindings/dma/loongson,ls2k0300-dma.yaml
> > > > +F:   Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml
> > > >  F:   Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
> > > >  F:   drivers/dma/loongson/loongson2-apb-cmc-dma.c
> > > >  F:   drivers/dma/loongson/loongson2-apb-dma.c
> > > > --
> > > > 2.52.0
> > > >
> >
> > --
> > Thanks.
> > Binbin

-- 
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-10-04  6:28 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-22  9:25 [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou
2026-09-22  9:25 ` [PATCH 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
2026-09-22  9:34   ` sashiko-bot
2026-09-30 21:52   ` Frank Li
2026-09-22  9:25 ` [PATCH 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou
2026-09-30 21:44   ` Frank Li
2026-10-02 14:00     ` Binbin Zhou
2026-10-02 14:47       ` Frank Li
2026-10-04  6:27         ` Binbin Zhou
2026-09-22  9:25 ` [PATCH 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
2026-09-22  9:36   ` sashiko-bot
2026-09-23  4:17   ` Huacai Chen
2026-09-30 21:56   ` Frank Li
2026-09-22 16:45 ` [PATCH 0/3] Add Loongson-2K0300 APB DMA mux support Frank Li
2026-09-23  5:53   ` Binbin Zhou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox