* [PATCH v2 0/3] Add Loongson-2K0300 APB DMA mux support
@ 2026-10-09 9:19 Binbin Zhou
2026-10-09 9:19 ` [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Binbin Zhou @ 2026-10-09 9:19 UTC (permalink / raw)
To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Frank Li, dmaengine
Cc: Huacai Chen, Xuerui Wang, loongarch, 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.
=========
V2:
Patch(1/3):
- Drop LS2K0300_DMA_REQ_MAX as it is not part of the ABI;
Patch(2/3):
- More detailed description of `dma-cells`;
- Add the `dma_requests` constraint
Patch(3/3):
- Drop loongson2_dmamux_map->shift;
- Move of_parse_phandle() into loongson2_dmamux_route_allocate() avoid
UAF;
- Drop loongson2_dmamux->dma_np;
- Check dma_requests;
- Add devm_add_action_or_reset() instead of .remove();
- Replace `metux()` with `spinlock()`, which has lower overhead;
- Add loongson2_dmamux_route_free().
Link to V1:
https://lore.kernel.org/all/cover.1790068409.git.zhoubinbin@loongson.cn/
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 | 72 ++++
MAINTAINERS | 3 +
drivers/dma/loongson/Makefile | 1 +
drivers/dma/loongson/loongson2-apb-dmamux.c | 398 ++++++++++++++++++
.../dt-bindings/dma/loongson,ls2k-dmamux.h | 53 +++
5 files changed, 527 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: 1d8ae2003de08f61095e4e928b1b8cce6c23cabd
--
2.52.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs 2026-10-09 9:19 [PATCH v2 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou @ 2026-10-09 9:19 ` Binbin Zhou 2026-10-09 14:38 ` Conor Dooley 2026-10-09 9:19 ` [PATCH v2 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou 2026-10-09 9:19 ` [PATCH v2 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou 2 siblings, 1 reply; 6+ messages in thread From: Binbin Zhou @ 2026-10-09 9:19 UTC (permalink / raw) To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Frank Li, dmaengine Cc: Huacai Chen, Xuerui Wang, loongarch, 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 | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h diff --git a/MAINTAINERS b/MAINTAINERS index 42f5165019ee..172dde21275f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15354,6 +15354,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..1e2907ab069d --- /dev/null +++ b/include/dt-bindings/dma/loongson,ls2k-dmamux.h @@ -0,0 +1,53 @@ +/* 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 + +#endif /* _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H */ -- 2.52.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs 2026-10-09 9:19 ` [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou @ 2026-10-09 14:38 ` Conor Dooley 0 siblings, 0 replies; 6+ messages in thread From: Conor Dooley @ 2026-10-09 14:38 UTC (permalink / raw) To: Binbin Zhou Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen, Xuerui Wang, loongarch, devicetree, Keguang Zhang [-- Attachment #1: Type: text/plain, Size: 3381 bytes --] On Fri, Oct 09, 2026 at 05:19:32PM +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> Squash this with the binding patch please. If checkpatch told you to split this, binding headers are bindings and such that warning is a false positive. pw-bot: changes-requested Thanks, Conor. > --- > MAINTAINERS | 1 + > .../dt-bindings/dma/loongson,ls2k-dmamux.h | 53 +++++++++++++++++++ > 2 files changed, 54 insertions(+) > create mode 100644 include/dt-bindings/dma/loongson,ls2k-dmamux.h > > diff --git a/MAINTAINERS b/MAINTAINERS > index 42f5165019ee..172dde21275f 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -15354,6 +15354,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..1e2907ab069d > --- /dev/null > +++ b/include/dt-bindings/dma/loongson,ls2k-dmamux.h > @@ -0,0 +1,53 @@ > +/* 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 > + > +#endif /* _DT_BINDINGS_DMA_LOONGSON_LS2K_DMAMUX_H */ > -- > 2.52.0 > [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support 2026-10-09 9:19 [PATCH v2 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou 2026-10-09 9:19 ` [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou @ 2026-10-09 9:19 ` Binbin Zhou 2026-10-09 14:43 ` Conor Dooley 2026-10-09 9:19 ` [PATCH v2 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou 2 siblings, 1 reply; 6+ messages in thread From: Binbin Zhou @ 2026-10-09 9:19 UTC (permalink / raw) To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Frank Li, dmaengine Cc: Huacai Chen, Xuerui Wang, loongarch, 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 | 72 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 73 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..0e6c794e1c90 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/loongson,ls2k0300-dmamux.yaml @@ -0,0 +1,72 @@ +# 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. 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: + - I2S/SPI/UART/I2C: Require adjacent channels in pairs; valid + values are 0/1, 2/3, 4/5, 6/7; + - SM3/SM4/DES/AES: Single channel; valid values are limited to 0/1; + - 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 + + dma-requests: + const: 22 + +required: + - compatible + - reg + - dma-requests + +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 172dde21275f..78622b255f88 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15351,6 +15351,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] 6+ messages in thread
* Re: [PATCH v2 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support 2026-10-09 9:19 ` [PATCH v2 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou @ 2026-10-09 14:43 ` Conor Dooley 0 siblings, 0 replies; 6+ messages in thread From: Conor Dooley @ 2026-10-09 14:43 UTC (permalink / raw) To: Binbin Zhou Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Frank Li, dmaengine, Huacai Chen, Xuerui Wang, loongarch, devicetree, Keguang Zhang [-- Attachment #1: Type: text/plain, Size: 75 bytes --] Acked-by: Conor Dooley <conor.dooley@microchip.com> pw-bot: not-applicable [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver 2026-10-09 9:19 [PATCH v2 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou 2026-10-09 9:19 ` [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou 2026-10-09 9:19 ` [PATCH v2 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou @ 2026-10-09 9:19 ` Binbin Zhou 2 siblings, 0 replies; 6+ messages in thread From: Binbin Zhou @ 2026-10-09 9:19 UTC (permalink / raw) To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Frank Li, dmaengine Cc: Huacai Chen, Xuerui Wang, loongarch, 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/Makefile | 1 + drivers/dma/loongson/loongson2-apb-dmamux.c | 398 ++++++++++++++++++++ 3 files changed, 400 insertions(+) create mode 100644 drivers/dma/loongson/loongson2-apb-dmamux.c diff --git a/MAINTAINERS b/MAINTAINERS index 78622b255f88..0b0c6ea41c64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15355,6 +15355,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/Makefile b/drivers/dma/loongson/Makefile index 48c19781e729..271fd38fa8f2 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_CMC_DMA) += 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..01bd3ce4ca25 --- /dev/null +++ b/drivers/dma/loongson/loongson2-apb-dmamux.c @@ -0,0 +1,398 @@ +// 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_*) + * - channel: target physical DMA channel + * - flags: channel configuration flags forwarded to the parent DMA + * controller + */ + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/dmaengine.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_dma.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.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). + * @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 + * @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; + 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 + * @base: I/O-mapped register base + * @lock: Protects register read-modify-write sequences + * @dma_router: Router structure passed to of_dma_router_register() + * @config: SoC-specific configuration + */ +struct loongson2_dmamux { + void __iomem *base; + spinlock_t lock; /* Protects register read-modify-write sequences */ + 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, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART1] = { LS2K0300_CHIP_CTRL13, CTRL13_UART1_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART2] = { LS2K0300_CHIP_CTRL13, CTRL13_UART2_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART3] = { LS2K0300_CHIP_CTRL13, CTRL13_UART3_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART4] = { LS2K0300_CHIP_CTRL13, CTRL13_UART4_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART5] = { LS2K0300_CHIP_CTRL13, CTRL13_UART5_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART6] = { LS2K0300_CHIP_CTRL13, CTRL13_UART6_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART7] = { LS2K0300_CHIP_CTRL13, CTRL13_UART7_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART8] = { LS2K0300_CHIP_CTRL14, CTRL14_UART8_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_UART9] = { LS2K0300_CHIP_CTRL14, CTRL14_UART9_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_I2C0] = { LS2K0300_CHIP_CTRL14, CTRL14_I2C0_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_I2C1] = { LS2K0300_CHIP_CTRL14, CTRL14_I2C1_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_I2C2] = { LS2K0300_CHIP_CTRL14, CTRL14_I2C2_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_I2C3] = { LS2K0300_CHIP_CTRL14, CTRL14_I2C3_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_SPI2] = { LS2K0300_CHIP_CTRL14, CTRL14_SPI2_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_SPI3] = { LS2K0300_CHIP_CTRL14, CTRL14_SPI3_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_I2S] = { LS2K0300_CHIP_CTRL14, CTRL14_I2S_DMA_MAP, LOONGSON_DMAMUX_PAIR, + 0, 0 }, + [LS2K0300_DMA_ADC] = { LS2K0300_CHIP_CTRL14, CTRL14_ADC_DMA_MAP, LOONGSON_DMAMUX_SINGLE, + 0, 0 }, + [LS2K0300_DMA_CAN0] = { LS2K0300_CHIP_CTRL14, CTRL14_CAN0_DMA_MAP, LOONGSON_DMAMUX_SINGLE, + 0, 0 }, + [LS2K0300_DMA_CAN1] = { LS2K0300_CHIP_CTRL14, CTRL14_CAN1_DMA_MAP, LOONGSON_DMAMUX_SINGLE, + 0, 0 }, + [LS2K0300_DMA_CAN2] = { LS2K0300_CHIP_CTRL14, CTRL14_CAN2_DMA_MAP, LOONGSON_DMAMUX_SINGLE, + 0, 0 }, + [LS2K0300_DMA_CAN3] = { LS2K0300_CHIP_CTRL14, CTRL14_CAN3_DMA_MAP, 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; + } + + guard(spinlock_irqsave)(&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); + } + + 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); + + /* The of_node_put() will be done in of_dma_router_xlate function */ + dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); + if (!dma_spec->np) + return ERR_PTR(-ENODEV); + + dma_spec->args[0] = channel; + dma_spec->args[1] = flags; + dma_spec->args_count = mux->config->parent_args_count; + + return NULL; +} + +/** + * loongson2_dmamux_route_free() - DMA router free callback + * @dev: Back pointer to the router's device + * @route_data: Router-specific data returned by route_allocate + * + * The driver does not allocate any per-route resources, so this callback + * is intentionally empty. It must still be provided because the OF DMA + * core calls it unconditionally on some error paths (e.g. -EPROBE_DEFER) + * without checking for a NULL pointer. + */ +static void loongson2_dmamux_route_free(struct device *dev, void *route_data) +{ +} + +/** + * loongson2_dmamux_unregister_of_dma() - devm action to unregister the router + * @data: Pointer to struct loongson2_dmamux + * + * Called automatically by the device-managed resource framework both on + * probe failure and on driver removal, ensuring the OF DMA router is + * always unregistered. + */ +static void loongson2_dmamux_unregister_of_dma(void *data) +{ + struct loongson2_dmamux *mux = data; + + of_dma_router_free(mux->dma_router.dev->of_node); +} + +static int loongson2_dmamux_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct loongson2_dmamux *mux; + u32 dma_requests; + int ret; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + mux->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mux->base)) + return PTR_ERR(mux->base); + + spin_lock_init(&mux->lock); + mux->config = &ls2k0300_dmamux_config; + + ret = of_property_read_u32(dev->of_node, "dma-requests", &dma_requests); + if (ret) + return dev_err_probe(dev, ret, "missing dma-requests property\n"); + + if (dma_requests != mux->config->num_maps) + return dev_err_probe(dev, -EINVAL, + "dma-requests=%u mismatches driver num_maps=%u", + dma_requests, mux->config->num_maps); + + mux->dma_router.dev = dev; + mux->dma_router.route_free = loongson2_dmamux_route_free; + + platform_set_drvdata(pdev, mux); + + ret = of_dma_router_register(dev->of_node, loongson2_dmamux_route_allocate, + &mux->dma_router); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register DMA router"); + + ret = devm_add_action_or_reset(dev, loongson2_dmamux_unregister_of_dma, mux); + if (ret) + return ret; + + dev_info(dev, + "Loongson2 DMA Mux Controller registered (max_channel=%u, requests=%u)", + mux->config->max_channel, mux->config->num_maps); + + return 0; +} + +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, +}; +module_platform_driver(loongson2_dmamux_driver); + +MODULE_DESCRIPTION("Loongson2 SoC DMA Mux Controller driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); -- 2.52.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-09 14:43 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-09 9:19 [PATCH v2 0/3] Add Loongson-2K0300 APB DMA mux support Binbin Zhou 2026-10-09 9:19 ` [PATCH v2 1/3] dt-bindings: dma: loongson: Add Loongson-2 DMA mux request IDs Binbin Zhou 2026-10-09 14:38 ` Conor Dooley 2026-10-09 9:19 ` [PATCH v2 2/3] dt-bindings: dma: loongson: Add Loongson-2K0300 DMA mux support Binbin Zhou 2026-10-09 14:43 ` Conor Dooley 2026-10-09 9:19 ` [PATCH v2 3/3] dmaengine: loongson: Add Loongson-2K0300 APB DMA mux driver Binbin Zhou
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox