* [PATCH v4 0/3] Add Amlogic general DMA
@ 2026-02-27 7:20 Xianwei Zhao via B4 Relay
2026-02-27 7:20 ` [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA Xianwei Zhao via B4 Relay
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2026-02-27 7:20 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva
Cc: linux-amlogic, dmaengine, devicetree, linux-kernel,
linux-hardening, Xianwei Zhao
Add DMA driver and bindigns for the Amlogic SoCs.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
Changes in v4:
- Support Split transfer when data len > MAX_LEN.
- When a module fails or exits, perform de-initialization.
- Some other minor modifications.
- Link to v3: https://lore.kernel.org/r/20260206-amlogic-dma-v3-0-56fb9f59ed22@amlogic.com
Changes in v3:
- Adjust the format of binding according to Frank's suggestion.
- Some code format modified according to Frank's suggestion.
- Support one prep_sg and one submit, drop multi prep_sg and one submit.
- Keep pre state when resume from pause status.
- Link to v2: https://lore.kernel.org/r/20260127-amlogic-dma-v2-0-4525d327d74d@amlogic.com
Changes in v2:
- Introduce what the DMA is used for in the A9 SoC.
- Some minor modifications were made according to Krzysztof's suggestions.
- Some modifications were made according to Neil's suggestions.
- Fix a build error.
- Link to v1: https://lore.kernel.org/r/20251216-amlogic-dma-v1-0-e289e57e96a7@amlogic.com
---
Xianwei Zhao (3):
dt-bindings: dma: Add Amlogic A9 SoC DMA
dma: amlogic: Add general DMA driver for A9
MAINTAINERS: Add an entry for Amlogic DMA driver
.../devicetree/bindings/dma/amlogic,a9-dma.yaml | 65 +++
MAINTAINERS | 7 +
drivers/dma/Kconfig | 9 +
drivers/dma/Makefile | 1 +
drivers/dma/amlogic-dma.c | 585 +++++++++++++++++++++
include/dt-bindings/dma/amlogic-dma.h | 8 +
6 files changed, 675 insertions(+)
---
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
change-id: 20251215-amlogic-dma-79477d5cd264
Best regards,
--
Xianwei Zhao <xianwei.zhao@amlogic.com>
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA
2026-02-27 7:20 [PATCH v4 0/3] Add Amlogic general DMA Xianwei Zhao via B4 Relay
@ 2026-02-27 7:20 ` Xianwei Zhao via B4 Relay
2026-02-27 9:18 ` Krzysztof Kozlowski
2026-02-27 7:20 ` [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9 Xianwei Zhao via B4 Relay
2026-02-27 7:20 ` [PATCH v4 3/3] MAINTAINERS: Add an entry for Amlogic DMA driver Xianwei Zhao via B4 Relay
2 siblings, 1 reply; 9+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2026-02-27 7:20 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva
Cc: linux-amlogic, dmaengine, devicetree, linux-kernel,
linux-hardening, Xianwei Zhao
From: Xianwei Zhao <xianwei.zhao@amlogic.com>
Add documentation describing the Amlogic A9 SoC DMA. And add
the properties specific values defines into a new include file.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
.../devicetree/bindings/dma/amlogic,a9-dma.yaml | 65 ++++++++++++++++++++++
include/dt-bindings/dma/amlogic-dma.h | 8 +++
2 files changed, 73 insertions(+)
diff --git a/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml b/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
new file mode 100644
index 000000000000..efd7b2602c33
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/amlogic,a9-dma.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic general DMA controller
+
+description:
+ This is a general-purpose peripheral DMA controller. It currently supports
+ major peripherals including I2C, I3C, PIO, and CAN-BUS. Transmit and receive
+ for the same peripheral use two separate channels, controlled by different
+ register sets. I2C and I3C transfer data in 1-byte units, while PIO and
+ CAN-BUS transfer data in 4-byte units. From the controller’s perspective,
+ there is no significant difference.
+
+maintainers:
+ - Xianwei Zhao <xianwei.zhao@amlogic.com>
+
+properties:
+ compatible:
+ const: amlogic,a9-dma
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: sys
+
+ '#dma-cells':
+ const: 2
+
+ dma-channels:
+ maximum: 64
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - '#dma-cells'
+ - dma-channels
+
+allOf:
+ - $ref: dma-controller.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ dma-controller@fe400000{
+ compatible = "amlogic,a9-dma";
+ reg = <0xfe400000 0x4000>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc 45>;
+ #dma-cells = <2>;
+ dma-channels = <28>;
+ };
diff --git a/include/dt-bindings/dma/amlogic-dma.h b/include/dt-bindings/dma/amlogic-dma.h
new file mode 100644
index 000000000000..025ecc42e395
--- /dev/null
+++ b/include/dt-bindings/dma/amlogic-dma.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+
+#ifndef __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
+#define __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
+
+#define AML_DMA_TYPE_TX 0
+#define AML_DMA_TYPE_RX 1
+#endif /* __DT_BINDINGS_DMA_AMLOGIC_DMA_H__ */
--
2.52.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9
2026-02-27 7:20 [PATCH v4 0/3] Add Amlogic general DMA Xianwei Zhao via B4 Relay
2026-02-27 7:20 ` [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA Xianwei Zhao via B4 Relay
@ 2026-02-27 7:20 ` Xianwei Zhao via B4 Relay
2026-03-02 8:46 ` Dan Carpenter
2026-02-27 7:20 ` [PATCH v4 3/3] MAINTAINERS: Add an entry for Amlogic DMA driver Xianwei Zhao via B4 Relay
2 siblings, 1 reply; 9+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2026-02-27 7:20 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva
Cc: linux-amlogic, dmaengine, devicetree, linux-kernel,
linux-hardening, Xianwei Zhao
From: Xianwei Zhao <xianwei.zhao@amlogic.com>
Amlogic A9 SoCs include a general-purpose DMA controller that can be used
by multiple peripherals, such as I2C PIO and I3C. Each peripheral group
is associated with a dedicated DMA channel in hardware.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
drivers/dma/Kconfig | 9 +
drivers/dma/Makefile | 1 +
drivers/dma/amlogic-dma.c | 585 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 595 insertions(+)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 66cda7cc9f7a..8d4578513acf 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -85,6 +85,15 @@ config AMCC_PPC440SPE_ADMA
help
Enable support for the AMCC PPC440SPe RAID engines.
+config AMLOGIC_DMA
+ tristate "Amlogic general DMA support"
+ depends on ARCH_MESON || COMPILE_TEST
+ select DMA_ENGINE
+ select REGMAP_MMIO
+ help
+ Enable support for the Amlogic general DMA engines. THis DMA
+ controller is used some Amlogic SoCs, such as A9.
+
config APPLE_ADMAC
tristate "Apple ADMAC support"
depends on ARCH_APPLE || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a54d7688392b..fc28dade5b69 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o
obj-$(CONFIG_ALTERA_MSGDMA) += altera-msgdma.o
obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
+obj-$(CONFIG_AMLOGIC_DMA) += amlogic-dma.o
obj-$(CONFIG_APPLE_ADMAC) += apple-admac.o
obj-$(CONFIG_ARM_DMA350) += arm-dma350.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
diff --git a/drivers/dma/amlogic-dma.c b/drivers/dma/amlogic-dma.c
new file mode 100644
index 000000000000..e297ef82eda9
--- /dev/null
+++ b/drivers/dma/amlogic-dma.c
@@ -0,0 +1,585 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2025 Amlogic, Inc. All rights reserved
+ * Author: Xianwei Zhao <xianwei.zhao@amlogic.com>
+ */
+
+#include <dt-bindings/dma/amlogic-dma.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "dmaengine.h"
+
+#define RCH_REG_BASE 0x0
+#define WCH_REG_BASE 0x2000
+/*
+ * Each rch (read from memory) REG offset Rch_offset 0x0 each channel total 0x40
+ * rch addr = DMA_base + Rch_offset+ chan_id * 0x40 + reg_offset
+ */
+#define RCH_READY 0x0
+#define RCH_STATUS 0x4
+#define RCH_CFG 0x8
+#define CFG_CLEAR BIT(25)
+#define CFG_PAUSE BIT(26)
+#define CFG_ENABLE BIT(27)
+#define CFG_DONE BIT(28)
+#define RCH_ADDR 0xc
+#define RCH_LEN 0x10
+#define RCH_RD_LEN 0x14
+#define RCH_PRT 0x18
+#define RCH_SYCN_STAT 0x1c
+#define RCH_ADDR_LOW 0x20
+#define RCH_ADDR_HIGH 0x24
+/* if work on 64, it work with RCH_PRT */
+#define RCH_PTR_HIGH 0x28
+
+/*
+ * Each wch (write to memory) REG offset Wch_offset 0x2000 each channel total 0x40
+ * wch addr = DMA_base + Wch_offset+ chan_id * 0x40 + reg_offset
+ */
+#define WCH_READY 0x0
+#define WCH_TOTAL_LEN 0x4
+#define WCH_CFG 0x8
+#define WCH_ADDR 0xc
+#define WCH_LEN 0x10
+#define WCH_RD_LEN 0x14
+#define WCH_PRT 0x18
+#define WCH_CMD_CNT 0x1c
+#define WCH_ADDR_LOW 0x20
+#define WCH_ADDR_HIGH 0x24
+/* if work on 64, it work with RCH_PRT */
+#define WCH_PTR_HIGH 0x28
+
+/* DMA controller reg */
+#define RCH_INT_MASK 0x1000
+#define WCH_INT_MASK 0x1004
+#define CLEAR_W_BATCH 0x1014
+#define CLEAR_RCH 0x1024
+#define CLEAR_WCH 0x1028
+#define RCH_ACTIVE 0x1038
+#define WCH_ACTIVE 0x103c
+#define RCH_DONE 0x104c
+#define WCH_DONE 0x1050
+#define RCH_ERR 0x1060
+#define RCH_LEN_ERR 0x1064
+#define WCH_ERR 0x1068
+#define DMA_BATCH_END 0x1078
+#define WCH_EOC_DONE 0x1088
+#define WDMA_RESP_ERR 0x1098
+#define UPT_PKT_SYNC 0x10a8
+#define RCHN_CFG 0x10ac
+#define WCHN_CFG 0x10b0
+#define MEM_PD_CFG 0x10b4
+#define MEM_BUS_CFG 0x10b8
+#define DMA_GMV_CFG 0x10bc
+#define DMA_GMR_CFG 0x10c0
+
+#define DMA_MAX_LINK 8
+#define MAX_CHAN_ID 32
+#define SG_MAX_LEN GENMASK(26, 0)
+
+struct aml_dma_sg_link {
+#define LINK_LEN GENMASK(26, 0)
+#define LINK_IRQ BIT(27)
+#define LINK_EOC BIT(28)
+#define LINK_LOOP BIT(29)
+#define LINK_ERR BIT(30)
+#define LINK_OWNER BIT(31)
+ u32 ctl;
+ u64 address;
+ u32 revered;
+} __packed;
+
+struct aml_dma_chan {
+ struct dma_chan chan;
+ struct dma_async_tx_descriptor desc;
+ struct aml_dma_dev *aml_dma;
+ struct aml_dma_sg_link *sg_link;
+ dma_addr_t sg_link_phys;
+ int sg_link_cnt;
+ int data_len;
+ enum dma_status pre_status;
+ enum dma_status status;
+ enum dma_transfer_direction direction;
+ int chan_id;
+ /* reg_base (direction + chan_id) */
+ int reg_offs;
+};
+
+struct aml_dma_dev {
+ struct dma_device dma_device;
+ void __iomem *base;
+ struct regmap *regmap;
+ struct clk *clk;
+ int irq;
+ struct platform_device *pdev;
+ struct aml_dma_chan *aml_rch[MAX_CHAN_ID];
+ struct aml_dma_chan *aml_wch[MAX_CHAN_ID];
+ unsigned int chan_nr;
+ unsigned int chan_used;
+ struct aml_dma_chan aml_chans[]__counted_by(chan_nr);
+};
+
+static struct aml_dma_chan *to_aml_dma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct aml_dma_chan, chan);
+}
+
+static dma_cookie_t aml_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ return dma_cookie_assign(tx);
+}
+
+static int aml_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+ size_t size = size_mul(sizeof(struct aml_dma_sg_link), DMA_MAX_LINK);
+
+ aml_chan->sg_link = dma_alloc_coherent(aml_dma->dma_device.dev, size,
+ &aml_chan->sg_link_phys, GFP_KERNEL);
+ if (!aml_chan->sg_link)
+ return -ENOMEM;
+
+ /* offset is the same RCH_CFG and WCH_CFG */
+ regmap_update_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR, CFG_CLEAR);
+ aml_chan->status = DMA_COMPLETE;
+ dma_async_tx_descriptor_init(&aml_chan->desc, chan);
+ aml_chan->desc.tx_submit = aml_dma_tx_submit;
+ regmap_update_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR, 0);
+
+ return 0;
+}
+
+static void aml_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+
+ aml_chan->status = DMA_COMPLETE;
+ dma_free_coherent(aml_dma->dma_device.dev,
+ sizeof(struct aml_dma_sg_link) * DMA_MAX_LINK,
+ aml_chan->sg_link, aml_chan->sg_link_phys);
+}
+
+/* DMA transfer state update how many data reside it */
+static enum dma_status aml_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+ u32 residue, done;
+
+ regmap_read(aml_dma->regmap, aml_chan->reg_offs + RCH_RD_LEN, &done);
+ residue = aml_chan->data_len - done;
+ dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
+ residue);
+
+ return aml_chan->status;
+}
+
+static struct dma_async_tx_descriptor *aml_dma_prep_slave_sg
+ (struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+ struct aml_dma_sg_link *sg_link;
+ struct scatterlist *sg;
+ int idx = 0;
+ u64 paddr;
+ u32 reg, link_count, avail, chan_id;
+ u32 i;
+
+ if (aml_chan->direction != direction) {
+ dev_err(aml_dma->dma_device.dev, "direction not support\n");
+ return NULL;
+ }
+
+ switch (aml_chan->status) {
+ case DMA_IN_PROGRESS:
+ dev_err(aml_dma->dma_device.dev, "not support multi tx_desciptor\n");
+ return NULL;
+
+ case DMA_COMPLETE:
+ aml_chan->data_len = 0;
+ chan_id = aml_chan->chan_id;
+ reg = (direction == DMA_DEV_TO_MEM) ? WCH_INT_MASK : RCH_INT_MASK;
+ regmap_update_bits(aml_dma->regmap, reg, BIT(chan_id), BIT(chan_id));
+
+ break;
+ default:
+ dev_err(aml_dma->dma_device.dev, "status error\n");
+ return NULL;
+ }
+
+ link_count = sg_nents_for_dma(sgl, sg_len, SG_MAX_LEN);
+
+ if (link_count > DMA_MAX_LINK) {
+ dev_err(aml_dma->dma_device.dev,
+ "maximum number of sg exceeded: %d > %d\n",
+ sg_len, DMA_MAX_LINK);
+ aml_chan->status = DMA_ERROR;
+ return NULL;
+ }
+
+ aml_chan->status = DMA_IN_PROGRESS;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ avail = sg_dma_len(sg);
+ paddr = sg->dma_address;
+ while (avail > SG_MAX_LEN) {
+ sg_link = &aml_chan->sg_link[idx++];
+ /* set dma address and len to sglink*/
+ sg_link->address = paddr;
+ sg_link->ctl = FIELD_PREP(LINK_LEN, SG_MAX_LEN);
+ paddr = paddr + SG_MAX_LEN;
+ avail = avail - SG_MAX_LEN;
+ }
+ sg_link = &aml_chan->sg_link[idx++];
+ /* set dma address and len to sglink*/
+ sg_link->address = paddr;
+ sg_link->ctl = FIELD_PREP(LINK_LEN, avail);
+
+ aml_chan->data_len += sg_dma_len(sg);
+ }
+ aml_chan->sg_link_cnt = idx;
+
+ return &aml_chan->desc;
+}
+
+static int aml_dma_pause_chan(struct dma_chan *chan)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+
+ regmap_update_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE, CFG_PAUSE);
+ aml_chan->pre_status = aml_chan->status;
+ aml_chan->status = DMA_PAUSED;
+
+ return 0;
+}
+
+static int aml_dma_resume_chan(struct dma_chan *chan)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+
+ regmap_update_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE, 0);
+ aml_chan->status = aml_chan->pre_status;
+
+ return 0;
+}
+
+static int aml_dma_terminate_all(struct dma_chan *chan)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+ int chan_id = aml_chan->chan_id;
+
+ aml_dma_pause_chan(chan);
+ regmap_update_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR, CFG_CLEAR);
+
+ if (aml_chan->direction == DMA_MEM_TO_DEV)
+ regmap_update_bits(aml_dma->regmap, RCH_INT_MASK, BIT(chan_id), BIT(chan_id));
+ else if (aml_chan->direction == DMA_DEV_TO_MEM)
+ regmap_update_bits(aml_dma->regmap, WCH_INT_MASK, BIT(chan_id), BIT(chan_id));
+
+ aml_chan->status = DMA_COMPLETE;
+
+ return 0;
+}
+
+static void aml_dma_enable_chan(struct dma_chan *chan)
+{
+ struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
+ struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
+ struct aml_dma_sg_link *sg_link;
+ int chan_id = aml_chan->chan_id;
+ int idx = aml_chan->sg_link_cnt - 1;
+
+ /* the last sg set eoc flag */
+ sg_link = &aml_chan->sg_link[idx];
+ sg_link->ctl |= LINK_EOC;
+ if (aml_chan->direction == DMA_MEM_TO_DEV) {
+ regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_ADDR,
+ aml_chan->sg_link_phys);
+ regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_LEN, aml_chan->data_len);
+ regmap_update_bits(aml_dma->regmap, RCH_INT_MASK, BIT(chan_id), 0);
+ /* for rch (tx) need set cfg 0 to trigger start */
+ regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, 0);
+ } else if (aml_chan->direction == DMA_DEV_TO_MEM) {
+ regmap_write(aml_dma->regmap, aml_chan->reg_offs + WCH_ADDR,
+ aml_chan->sg_link_phys);
+ regmap_write(aml_dma->regmap, aml_chan->reg_offs + WCH_LEN, aml_chan->data_len);
+ regmap_update_bits(aml_dma->regmap, WCH_INT_MASK, BIT(chan_id), 0);
+ }
+}
+
+static irqreturn_t aml_dma_interrupt_handler(int irq, void *dev_id)
+{
+ struct aml_dma_dev *aml_dma = dev_id;
+ struct aml_dma_chan *aml_chan;
+ u32 done, eoc_done, err, err_l, end;
+ int i = 0;
+
+ /* deal with rch normal complete and error */
+ regmap_read(aml_dma->regmap, RCH_DONE, &done);
+ regmap_read(aml_dma->regmap, RCH_ERR, &err);
+ regmap_read(aml_dma->regmap, RCH_LEN_ERR, &err_l);
+ err = err | err_l;
+
+ done = done | err;
+
+ while (done) {
+ i = ffs(done) - 1;
+ aml_chan = aml_dma->aml_rch[i];
+ regmap_write(aml_dma->regmap, CLEAR_RCH, BIT(aml_chan->chan_id));
+ if (!aml_chan) {
+ dev_err(aml_dma->dma_device.dev, "idx %d rch not initialized\n", i);
+ done &= ~BIT(i);
+ continue;
+ }
+ aml_chan->status = (err & (1 << i)) ? DMA_ERROR : DMA_COMPLETE;
+ dma_cookie_complete(&aml_chan->desc);
+ dmaengine_desc_get_callback_invoke(&aml_chan->desc, NULL);
+ done &= ~BIT(i);
+ }
+
+ /* deal with wch normal complete and error */
+ regmap_read(aml_dma->regmap, DMA_BATCH_END, &end);
+ if (end)
+ regmap_write(aml_dma->regmap, CLEAR_W_BATCH, end);
+
+ regmap_read(aml_dma->regmap, WCH_DONE, &done);
+ regmap_read(aml_dma->regmap, WCH_EOC_DONE, &eoc_done);
+ done = done | eoc_done;
+
+ regmap_read(aml_dma->regmap, WCH_ERR, &err);
+ regmap_read(aml_dma->regmap, WDMA_RESP_ERR, &err_l);
+ err = err | err_l;
+
+ done = done | err;
+ i = 0;
+ while (done) {
+ i = ffs(done) - 1;
+ aml_chan = aml_dma->aml_wch[i];
+ regmap_write(aml_dma->regmap, CLEAR_WCH, BIT(aml_chan->chan_id));
+ if (!aml_chan) {
+ dev_err(aml_dma->dma_device.dev, "idx %d wch not initialized\n", i);
+ done &= ~BIT(i);
+ continue;
+ }
+ aml_chan->status = (err & (1 << i)) ? DMA_ERROR : DMA_COMPLETE;
+ dma_cookie_complete(&aml_chan->desc);
+ dmaengine_desc_get_callback_invoke(&aml_chan->desc, NULL);
+ done &= ~BIT(i);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct dma_chan *aml_of_dma_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma)
+{
+ struct aml_dma_dev *aml_dma = (struct aml_dma_dev *)ofdma->of_dma_data;
+ struct aml_dma_chan *aml_chan = NULL;
+ u32 type;
+ u32 phy_chan_id;
+
+ if (dma_spec->args_count != 2)
+ return NULL;
+
+ type = dma_spec->args[0];
+ phy_chan_id = dma_spec->args[1];
+
+ if (phy_chan_id >= MAX_CHAN_ID)
+ return NULL;
+
+ if (type == AML_DMA_TYPE_TX) {
+ aml_chan = aml_dma->aml_rch[phy_chan_id];
+ if (!aml_chan) {
+ if (aml_dma->chan_used >= aml_dma->chan_nr) {
+ dev_err(aml_dma->dma_device.dev, "some dma clients err used\n");
+ return NULL;
+ }
+ aml_chan = &aml_dma->aml_chans[aml_dma->chan_used];
+ aml_dma->chan_used++;
+ aml_chan->direction = DMA_MEM_TO_DEV;
+ aml_chan->chan_id = phy_chan_id;
+ aml_chan->reg_offs = RCH_REG_BASE + 0x40 * aml_chan->chan_id;
+ aml_dma->aml_rch[phy_chan_id] = aml_chan;
+ }
+ } else if (type == AML_DMA_TYPE_RX) {
+ aml_chan = aml_dma->aml_wch[phy_chan_id];
+ if (!aml_chan) {
+ if (aml_dma->chan_used >= aml_dma->chan_nr) {
+ dev_err(aml_dma->dma_device.dev, "some dma clients err used\n");
+ return NULL;
+ }
+ aml_chan = &aml_dma->aml_chans[aml_dma->chan_used];
+ aml_dma->chan_used++;
+ aml_chan->direction = DMA_DEV_TO_MEM;
+ aml_chan->chan_id = phy_chan_id;
+ aml_chan->reg_offs = WCH_REG_BASE + 0x40 * aml_chan->chan_id;
+ aml_dma->aml_wch[phy_chan_id] = aml_chan;
+ }
+ } else {
+ dev_err(aml_dma->dma_device.dev, "type %d not supported\n", type);
+ return NULL;
+ }
+
+ return dma_get_slave_channel(&aml_chan->chan);
+}
+
+static int aml_dma_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct dma_device *dma_dev;
+ struct aml_dma_dev *aml_dma;
+ int ret, i, len;
+ u32 chan_nr;
+
+ const struct regmap_config aml_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x3000,
+ };
+
+ ret = of_property_read_u32(np, "dma-channels", &chan_nr);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to read dma-channels\n");
+
+ len = sizeof(struct aml_dma_dev) + sizeof(struct aml_dma_chan) * chan_nr;
+ aml_dma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+ if (!aml_dma)
+ return -ENOMEM;
+
+ aml_dma->chan_nr = chan_nr;
+
+ aml_dma->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(aml_dma->base))
+ return PTR_ERR(aml_dma->base);
+
+ aml_dma->regmap = devm_regmap_init_mmio(&pdev->dev, aml_dma->base,
+ &aml_regmap_config);
+ if (IS_ERR_OR_NULL(aml_dma->regmap))
+ return PTR_ERR(aml_dma->regmap);
+
+ aml_dma->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(aml_dma->clk))
+ return PTR_ERR(aml_dma->clk);
+
+ aml_dma->irq = platform_get_irq(pdev, 0);
+
+ aml_dma->pdev = pdev;
+ aml_dma->dma_device.dev = &pdev->dev;
+
+ dma_dev = &aml_dma->dma_device;
+ INIT_LIST_HEAD(&dma_dev->channels);
+
+ /* Initialize channel parameters */
+ for (i = 0; i < chan_nr; i++) {
+ struct aml_dma_chan *aml_chan = &aml_dma->aml_chans[i];
+
+ aml_chan->aml_dma = aml_dma;
+ aml_chan->chan.device = &aml_dma->dma_device;
+ dma_cookie_init(&aml_chan->chan);
+
+ /* Add the channel to aml_chan list */
+ list_add_tail(&aml_chan->chan.device_node,
+ &aml_dma->dma_device.channels);
+ }
+ aml_dma->chan_used = 0;
+
+ dma_set_max_seg_size(dma_dev->dev, SG_MAX_LEN);
+
+ dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+ dma_dev->device_alloc_chan_resources = aml_dma_alloc_chan_resources;
+ dma_dev->device_free_chan_resources = aml_dma_free_chan_resources;
+ dma_dev->device_tx_status = aml_dma_tx_status;
+ dma_dev->device_prep_slave_sg = aml_dma_prep_slave_sg;
+
+ dma_dev->device_pause = aml_dma_pause_chan;
+ dma_dev->device_resume = aml_dma_resume_chan;
+ dma_dev->device_terminate_all = aml_dma_terminate_all;
+ dma_dev->device_issue_pending = aml_dma_enable_chan;
+ /* PIO 4 bytes and I2C 1 byte */
+ dma_dev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+ dma_dev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
+ ret = dmaenginem_async_device_register(dma_dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to register dmaenginem\n");
+
+ ret = of_dma_controller_register(np, aml_of_dma_xlate, aml_dma);
+ if (ret)
+ goto err_dmaenginem_register;
+
+ regmap_write(aml_dma->regmap, RCH_INT_MASK, 0xffffffff);
+ regmap_write(aml_dma->regmap, WCH_INT_MASK, 0xffffffff);
+
+ ret = devm_request_irq(&pdev->dev, aml_dma->irq, aml_dma_interrupt_handler,
+ IRQF_SHARED, dev_name(&pdev->dev), aml_dma);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to reqest_irq\n");
+ goto err_of_dma_controller;
+ }
+
+ platform_set_drvdata(pdev, aml_dma);
+
+ return 0;
+
+err_of_dma_controller:
+ of_dma_controller_free(np);
+err_dmaenginem_register:
+ dma_async_device_unregister(dma_dev);
+
+ return ret;
+}
+
+static void aml_dma_remove(struct platform_device *pdev)
+{
+ struct aml_dma_dev *aml_dma = platform_get_drvdata(pdev);
+
+ of_dma_controller_free((&pdev->dev)->of_node);
+ dma_async_device_unregister(&aml_dma->dma_device);
+}
+
+static const struct of_device_id aml_dma_ids[] = {
+ { .compatible = "amlogic,a9-dma", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aml_dma_ids);
+
+static struct platform_driver aml_dma_driver = {
+ .probe = aml_dma_probe,
+ .remove = aml_dma_remove,
+ .driver = {
+ .name = "aml-dma",
+ .of_match_table = aml_dma_ids,
+ },
+};
+
+module_platform_driver(aml_dma_driver);
+
+MODULE_DESCRIPTION("GENERAL DMA driver for Amlogic");
+MODULE_AUTHOR("Xianwei Zhao <xianwei.zhao@amlogic.com>");
+MODULE_LICENSE("GPL");
--
2.52.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 3/3] MAINTAINERS: Add an entry for Amlogic DMA driver
2026-02-27 7:20 [PATCH v4 0/3] Add Amlogic general DMA Xianwei Zhao via B4 Relay
2026-02-27 7:20 ` [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA Xianwei Zhao via B4 Relay
2026-02-27 7:20 ` [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9 Xianwei Zhao via B4 Relay
@ 2026-02-27 7:20 ` Xianwei Zhao via B4 Relay
2 siblings, 0 replies; 9+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2026-02-27 7:20 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva
Cc: linux-amlogic, dmaengine, devicetree, linux-kernel,
linux-hardening, Xianwei Zhao
From: Xianwei Zhao <xianwei.zhao@amlogic.com>
Add Amlogic DMA controller entry to MAINTAINERS to clarify
the maintainers.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 55af015174a5..e9c52dfba2df 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1316,6 +1316,13 @@ F: Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
F: drivers/perf/amlogic/
F: include/soc/amlogic/
+AMLOGIC DMA DRIVER
+M: Xianwei Zhao <xianwei.zhao@amlogic.com>
+L: linux-amlogic@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
+F: drivers/dma/amlogic-dma.c
+
AMLOGIC ISP DRIVER
M: Keke Li <keke.li@amlogic.com>
L: linux-media@vger.kernel.org
--
2.52.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA
2026-02-27 7:20 ` [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA Xianwei Zhao via B4 Relay
@ 2026-02-27 9:18 ` Krzysztof Kozlowski
2026-02-27 9:43 ` Xianwei Zhao
0 siblings, 1 reply; 9+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-27 9:18 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva, linux-amlogic, dmaengine,
devicetree, linux-kernel, linux-hardening
On Fri, Feb 27, 2026 at 07:20:53AM +0000, Xianwei Zhao wrote:
> Add documentation describing the Amlogic A9 SoC DMA. And add
> the properties specific values defines into a new include file.
>
> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
> ---
> .../devicetree/bindings/dma/amlogic,a9-dma.yaml | 65 ++++++++++++++++++++++
> include/dt-bindings/dma/amlogic-dma.h | 8 +++
> 2 files changed, 73 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml b/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
> new file mode 100644
> index 000000000000..efd7b2602c33
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
> @@ -0,0 +1,65 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/dma/amlogic,a9-dma.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Amlogic general DMA controller
> +
> +description:
> + This is a general-purpose peripheral DMA controller. It currently supports
> + major peripherals including I2C, I3C, PIO, and CAN-BUS. Transmit and receive
> + for the same peripheral use two separate channels, controlled by different
> + register sets. I2C and I3C transfer data in 1-byte units, while PIO and
> + CAN-BUS transfer data in 4-byte units. From the controller’s perspective,
> + there is no significant difference.
> +
> +maintainers:
> + - Xianwei Zhao <xianwei.zhao@amlogic.com>
> +
> +properties:
> + compatible:
> + const: amlogic,a9-dma
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + clocks:
> + maxItems: 1
> +
> + clock-names:
> + const: sys
> +
> + '#dma-cells':
> + const: 2
> +
> + dma-channels:
> + maximum: 64
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - clocks
> + - '#dma-cells'
> + - dma-channels
> +
> +allOf:
> + - $ref: dma-controller.yaml#
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + dma-controller@fe400000{
> + compatible = "amlogic,a9-dma";
> + reg = <0xfe400000 0x4000>;
> + interrupts = <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>;
> + clocks = <&clkc 45>;
> + #dma-cells = <2>;
> + dma-channels = <28>;
> + };
> diff --git a/include/dt-bindings/dma/amlogic-dma.h b/include/dt-bindings/dma/amlogic-dma.h
Filename must be the same as binding file.
> new file mode 100644
> index 000000000000..025ecc42e395
> --- /dev/null
> +++ b/include/dt-bindings/dma/amlogic-dma.h
> @@ -0,0 +1,8 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +
> +#ifndef __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
> +#define __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
> +
> +#define AML_DMA_TYPE_TX 0
> +#define AML_DMA_TYPE_RX 1
You sure you need AML prefix? Your clock constants do not have AML
prefixes. What other constants do you expect here?
Best regards,
Krzysztof
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA
2026-02-27 9:18 ` Krzysztof Kozlowski
@ 2026-02-27 9:43 ` Xianwei Zhao
2026-02-27 9:44 ` Krzysztof Kozlowski
0 siblings, 1 reply; 9+ messages in thread
From: Xianwei Zhao @ 2026-02-27 9:43 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva, linux-amlogic, dmaengine,
devicetree, linux-kernel, linux-hardening
Hi Krzysztof,
Thanks for your reply.
On 2026/2/27 17:18, Krzysztof Kozlowski wrote:
> On Fri, Feb 27, 2026 at 07:20:53AM +0000, Xianwei Zhao wrote:
>> Add documentation describing the Amlogic A9 SoC DMA. And add
>> the properties specific values defines into a new include file.
>>
>> Signed-off-by: Xianwei Zhao<xianwei.zhao@amlogic.com>
>> ---
>> .../devicetree/bindings/dma/amlogic,a9-dma.yaml | 65 ++++++++++++++++++++++
>> include/dt-bindings/dma/amlogic-dma.h | 8 +++
>> 2 files changed, 73 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml b/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
>> new file mode 100644
>> index 000000000000..efd7b2602c33
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
>> @@ -0,0 +1,65 @@
>> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
>> +%YAML 1.2
>> +---
>> +$id:http://devicetree.org/schemas/dma/amlogic,a9-dma.yaml#
>> +$schema:http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Amlogic general DMA controller
>> +
>> +description:
>> + This is a general-purpose peripheral DMA controller. It currently supports
>> + major peripherals including I2C, I3C, PIO, and CAN-BUS. Transmit and receive
>> + for the same peripheral use two separate channels, controlled by different
>> + register sets. I2C and I3C transfer data in 1-byte units, while PIO and
>> + CAN-BUS transfer data in 4-byte units. From the controller’s perspective,
>> + there is no significant difference.
>> +
>> +maintainers:
>> + - Xianwei Zhao<xianwei.zhao@amlogic.com>
>> +
>> +properties:
>> + compatible:
>> + const: amlogic,a9-dma
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + clocks:
>> + maxItems: 1
>> +
>> + clock-names:
>> + const: sys
>> +
>> + '#dma-cells':
>> + const: 2
>> +
>> + dma-channels:
>> + maximum: 64
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - interrupts
>> + - clocks
>> + - '#dma-cells'
>> + - dma-channels
>> +
>> +allOf:
>> + - $ref: dma-controller.yaml#
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + dma-controller@fe400000{
>> + compatible = "amlogic,a9-dma";
>> + reg = <0xfe400000 0x4000>;
>> + interrupts = <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>;
>> + clocks = <&clkc 45>;
>> + #dma-cells = <2>;
>> + dma-channels = <28>;
>> + };
>> diff --git a/include/dt-bindings/dma/amlogic-dma.h b/include/dt-bindings/dma/amlogic-dma.h
> Filename must be the same as binding file.
>
Will do.
>> new file mode 100644
>> index 000000000000..025ecc42e395
>> --- /dev/null
>> +++ b/include/dt-bindings/dma/amlogic-dma.h
>> @@ -0,0 +1,8 @@
>> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>> +
>> +#ifndef __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
>> +#define __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
>> +
>> +#define AML_DMA_TYPE_TX 0
>> +#define AML_DMA_TYPE_RX 1
> You sure you need AML prefix? Your clock constants do not have AML
> prefixes. What other constants do you expect here?
>
I will delete AML prefix in next version.
> Best regards,
> Krzysztof
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA
2026-02-27 9:43 ` Xianwei Zhao
@ 2026-02-27 9:44 ` Krzysztof Kozlowski
2026-02-27 9:49 ` Xianwei Zhao
0 siblings, 1 reply; 9+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-27 9:44 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva, linux-amlogic, dmaengine,
devicetree, linux-kernel, linux-hardening
On 27/02/2026 10:43, Xianwei Zhao wrote:
>>> new file mode 100644
>>> index 000000000000..025ecc42e395
>>> --- /dev/null
>>> +++ b/include/dt-bindings/dma/amlogic-dma.h
>>> @@ -0,0 +1,8 @@
>>> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>>> +
>>> +#ifndef __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
>>> +#define __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
>>> +
>>> +#define AML_DMA_TYPE_TX 0
>>> +#define AML_DMA_TYPE_RX 1
>> You sure you need AML prefix? Your clock constants do not have AML
>> prefixes. What other constants do you expect here?
>>
>
> I will delete AML prefix in next version.
I assume this is an argument to "dma" phandle (cells), so maybe should
be "DMA_TX/RX"?
Best regards,
Krzysztof
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA
2026-02-27 9:44 ` Krzysztof Kozlowski
@ 2026-02-27 9:49 ` Xianwei Zhao
0 siblings, 0 replies; 9+ messages in thread
From: Xianwei Zhao @ 2026-02-27 9:49 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Kees Cook, Gustavo A. R. Silva, linux-amlogic, dmaengine,
devicetree, linux-kernel, linux-hardening
On 2026/2/27 17:44, Krzysztof Kozlowski wrote:
> On 27/02/2026 10:43, Xianwei Zhao wrote:
>>>> new file mode 100644
>>>> index 000000000000..025ecc42e395
>>>> --- /dev/null
>>>> +++ b/include/dt-bindings/dma/amlogic-dma.h
>>>> @@ -0,0 +1,8 @@
>>>> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>>>> +
>>>> +#ifndef __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
>>>> +#define __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
>>>> +
>>>> +#define AML_DMA_TYPE_TX 0
>>>> +#define AML_DMA_TYPE_RX 1
>>> You sure you need AML prefix? Your clock constants do not have AML
>>> prefixes. What other constants do you expect here?
>>>
>> I will delete AML prefix in next version.
> I assume this is an argument to "dma" phandle (cells), so maybe should
> be "DMA_TX/RX"?
>
Thank you for your suggestion. I'll use it.
> Best regards,
> Krzysztof
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9
2026-02-27 7:20 ` [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9 Xianwei Zhao via B4 Relay
@ 2026-03-02 8:46 ` Dan Carpenter
0 siblings, 0 replies; 9+ messages in thread
From: Dan Carpenter @ 2026-03-02 8:46 UTC (permalink / raw)
To: oe-kbuild, Xianwei Zhao via B4 Relay, Vinod Koul, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kees Cook,
Gustavo A. R. Silva
Cc: lkp, oe-kbuild-all, linux-amlogic, dmaengine, devicetree,
linux-kernel, linux-hardening, Xianwei Zhao
Hi Xianwei,
kernel test robot noticed the following build warnings:
url: https://github.com/intel-lab-lkp/linux/commits/Xianwei-Zhao-via-B4-Relay/dt-bindings-dma-Add-Amlogic-A9-SoC-DMA/20260227-152743
base: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
patch link: https://lore.kernel.org/r/20260227-amlogic-dma-v4-2-f25e4614e9b7%40amlogic.com
patch subject: [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9
config: arm-randconfig-r073-20260228 (https://download.01.org/0day-ci/archive/20260302/202603020642.3hq2CxZ7-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
smatch version: v0.5.0-8994-gd50c5a4c
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202603020642.3hq2CxZ7-lkp@intel.com/
New smatch warnings:
drivers/dma/amlogic-dma.c:354 aml_dma_interrupt_handler() warn: variable dereferenced before check 'aml_chan' (see line 353)
drivers/dma/amlogic-dma.c:483 aml_dma_probe() warn: passing zero to 'PTR_ERR'
Old smatch warnings:
drivers/dma/amlogic-dma.c:384 aml_dma_interrupt_handler() warn: variable dereferenced before check 'aml_chan' (see line 383)
vim +/aml_chan +354 drivers/dma/amlogic-dma.c
c01d15789f1d15b Xianwei Zhao 2026-02-27 335 static irqreturn_t aml_dma_interrupt_handler(int irq, void *dev_id)
c01d15789f1d15b Xianwei Zhao 2026-02-27 336 {
c01d15789f1d15b Xianwei Zhao 2026-02-27 337 struct aml_dma_dev *aml_dma = dev_id;
c01d15789f1d15b Xianwei Zhao 2026-02-27 338 struct aml_dma_chan *aml_chan;
c01d15789f1d15b Xianwei Zhao 2026-02-27 339 u32 done, eoc_done, err, err_l, end;
c01d15789f1d15b Xianwei Zhao 2026-02-27 340 int i = 0;
c01d15789f1d15b Xianwei Zhao 2026-02-27 341
c01d15789f1d15b Xianwei Zhao 2026-02-27 342 /* deal with rch normal complete and error */
c01d15789f1d15b Xianwei Zhao 2026-02-27 343 regmap_read(aml_dma->regmap, RCH_DONE, &done);
c01d15789f1d15b Xianwei Zhao 2026-02-27 344 regmap_read(aml_dma->regmap, RCH_ERR, &err);
c01d15789f1d15b Xianwei Zhao 2026-02-27 345 regmap_read(aml_dma->regmap, RCH_LEN_ERR, &err_l);
c01d15789f1d15b Xianwei Zhao 2026-02-27 346 err = err | err_l;
c01d15789f1d15b Xianwei Zhao 2026-02-27 347
c01d15789f1d15b Xianwei Zhao 2026-02-27 348 done = done | err;
c01d15789f1d15b Xianwei Zhao 2026-02-27 349
c01d15789f1d15b Xianwei Zhao 2026-02-27 350 while (done) {
c01d15789f1d15b Xianwei Zhao 2026-02-27 351 i = ffs(done) - 1;
c01d15789f1d15b Xianwei Zhao 2026-02-27 352 aml_chan = aml_dma->aml_rch[i];
c01d15789f1d15b Xianwei Zhao 2026-02-27 @353 regmap_write(aml_dma->regmap, CLEAR_RCH, BIT(aml_chan->chan_id));
^^^^^^^^^^^^^^^^^^
Move this dereference
c01d15789f1d15b Xianwei Zhao 2026-02-27 @354 if (!aml_chan) {
^^^^^^^^
after this NULL check?
c01d15789f1d15b Xianwei Zhao 2026-02-27 355 dev_err(aml_dma->dma_device.dev, "idx %d rch not initialized\n", i);
c01d15789f1d15b Xianwei Zhao 2026-02-27 356 done &= ~BIT(i);
c01d15789f1d15b Xianwei Zhao 2026-02-27 357 continue;
c01d15789f1d15b Xianwei Zhao 2026-02-27 358 }
c01d15789f1d15b Xianwei Zhao 2026-02-27 359 aml_chan->status = (err & (1 << i)) ? DMA_ERROR : DMA_COMPLETE;
c01d15789f1d15b Xianwei Zhao 2026-02-27 360 dma_cookie_complete(&aml_chan->desc);
c01d15789f1d15b Xianwei Zhao 2026-02-27 361 dmaengine_desc_get_callback_invoke(&aml_chan->desc, NULL);
c01d15789f1d15b Xianwei Zhao 2026-02-27 362 done &= ~BIT(i);
c01d15789f1d15b Xianwei Zhao 2026-02-27 363 }
c01d15789f1d15b Xianwei Zhao 2026-02-27 364
c01d15789f1d15b Xianwei Zhao 2026-02-27 365 /* deal with wch normal complete and error */
c01d15789f1d15b Xianwei Zhao 2026-02-27 366 regmap_read(aml_dma->regmap, DMA_BATCH_END, &end);
c01d15789f1d15b Xianwei Zhao 2026-02-27 367 if (end)
c01d15789f1d15b Xianwei Zhao 2026-02-27 368 regmap_write(aml_dma->regmap, CLEAR_W_BATCH, end);
c01d15789f1d15b Xianwei Zhao 2026-02-27 369
c01d15789f1d15b Xianwei Zhao 2026-02-27 370 regmap_read(aml_dma->regmap, WCH_DONE, &done);
c01d15789f1d15b Xianwei Zhao 2026-02-27 371 regmap_read(aml_dma->regmap, WCH_EOC_DONE, &eoc_done);
c01d15789f1d15b Xianwei Zhao 2026-02-27 372 done = done | eoc_done;
c01d15789f1d15b Xianwei Zhao 2026-02-27 373
c01d15789f1d15b Xianwei Zhao 2026-02-27 374 regmap_read(aml_dma->regmap, WCH_ERR, &err);
c01d15789f1d15b Xianwei Zhao 2026-02-27 375 regmap_read(aml_dma->regmap, WDMA_RESP_ERR, &err_l);
c01d15789f1d15b Xianwei Zhao 2026-02-27 376 err = err | err_l;
c01d15789f1d15b Xianwei Zhao 2026-02-27 377
c01d15789f1d15b Xianwei Zhao 2026-02-27 378 done = done | err;
c01d15789f1d15b Xianwei Zhao 2026-02-27 379 i = 0;
c01d15789f1d15b Xianwei Zhao 2026-02-27 380 while (done) {
c01d15789f1d15b Xianwei Zhao 2026-02-27 381 i = ffs(done) - 1;
c01d15789f1d15b Xianwei Zhao 2026-02-27 382 aml_chan = aml_dma->aml_wch[i];
c01d15789f1d15b Xianwei Zhao 2026-02-27 383 regmap_write(aml_dma->regmap, CLEAR_WCH, BIT(aml_chan->chan_id));
c01d15789f1d15b Xianwei Zhao 2026-02-27 384 if (!aml_chan) {
Same.
c01d15789f1d15b Xianwei Zhao 2026-02-27 385 dev_err(aml_dma->dma_device.dev, "idx %d wch not initialized\n", i);
c01d15789f1d15b Xianwei Zhao 2026-02-27 386 done &= ~BIT(i);
c01d15789f1d15b Xianwei Zhao 2026-02-27 387 continue;
c01d15789f1d15b Xianwei Zhao 2026-02-27 388 }
c01d15789f1d15b Xianwei Zhao 2026-02-27 389 aml_chan->status = (err & (1 << i)) ? DMA_ERROR : DMA_COMPLETE;
c01d15789f1d15b Xianwei Zhao 2026-02-27 390 dma_cookie_complete(&aml_chan->desc);
c01d15789f1d15b Xianwei Zhao 2026-02-27 391 dmaengine_desc_get_callback_invoke(&aml_chan->desc, NULL);
c01d15789f1d15b Xianwei Zhao 2026-02-27 392 done &= ~BIT(i);
c01d15789f1d15b Xianwei Zhao 2026-02-27 393 }
c01d15789f1d15b Xianwei Zhao 2026-02-27 394
c01d15789f1d15b Xianwei Zhao 2026-02-27 395 return IRQ_HANDLED;
c01d15789f1d15b Xianwei Zhao 2026-02-27 396 }
[ snip ]
c01d15789f1d15b Xianwei Zhao 2026-02-27 450 static int aml_dma_probe(struct platform_device *pdev)
c01d15789f1d15b Xianwei Zhao 2026-02-27 451 {
c01d15789f1d15b Xianwei Zhao 2026-02-27 452 struct device_node *np = pdev->dev.of_node;
c01d15789f1d15b Xianwei Zhao 2026-02-27 453 struct dma_device *dma_dev;
c01d15789f1d15b Xianwei Zhao 2026-02-27 454 struct aml_dma_dev *aml_dma;
c01d15789f1d15b Xianwei Zhao 2026-02-27 455 int ret, i, len;
c01d15789f1d15b Xianwei Zhao 2026-02-27 456 u32 chan_nr;
c01d15789f1d15b Xianwei Zhao 2026-02-27 457
c01d15789f1d15b Xianwei Zhao 2026-02-27 458 const struct regmap_config aml_regmap_config = {
c01d15789f1d15b Xianwei Zhao 2026-02-27 459 .reg_bits = 32,
c01d15789f1d15b Xianwei Zhao 2026-02-27 460 .val_bits = 32,
c01d15789f1d15b Xianwei Zhao 2026-02-27 461 .reg_stride = 4,
c01d15789f1d15b Xianwei Zhao 2026-02-27 462 .max_register = 0x3000,
c01d15789f1d15b Xianwei Zhao 2026-02-27 463 };
c01d15789f1d15b Xianwei Zhao 2026-02-27 464
c01d15789f1d15b Xianwei Zhao 2026-02-27 465 ret = of_property_read_u32(np, "dma-channels", &chan_nr);
c01d15789f1d15b Xianwei Zhao 2026-02-27 466 if (ret)
c01d15789f1d15b Xianwei Zhao 2026-02-27 467 return dev_err_probe(&pdev->dev, ret, "failed to read dma-channels\n");
c01d15789f1d15b Xianwei Zhao 2026-02-27 468
c01d15789f1d15b Xianwei Zhao 2026-02-27 469 len = sizeof(struct aml_dma_dev) + sizeof(struct aml_dma_chan) * chan_nr;
c01d15789f1d15b Xianwei Zhao 2026-02-27 470 aml_dma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
c01d15789f1d15b Xianwei Zhao 2026-02-27 471 if (!aml_dma)
c01d15789f1d15b Xianwei Zhao 2026-02-27 472 return -ENOMEM;
c01d15789f1d15b Xianwei Zhao 2026-02-27 473
c01d15789f1d15b Xianwei Zhao 2026-02-27 474 aml_dma->chan_nr = chan_nr;
c01d15789f1d15b Xianwei Zhao 2026-02-27 475
c01d15789f1d15b Xianwei Zhao 2026-02-27 476 aml_dma->base = devm_platform_ioremap_resource(pdev, 0);
c01d15789f1d15b Xianwei Zhao 2026-02-27 477 if (IS_ERR(aml_dma->base))
c01d15789f1d15b Xianwei Zhao 2026-02-27 478 return PTR_ERR(aml_dma->base);
c01d15789f1d15b Xianwei Zhao 2026-02-27 479
c01d15789f1d15b Xianwei Zhao 2026-02-27 480 aml_dma->regmap = devm_regmap_init_mmio(&pdev->dev, aml_dma->base,
c01d15789f1d15b Xianwei Zhao 2026-02-27 481 &aml_regmap_config);
c01d15789f1d15b Xianwei Zhao 2026-02-27 482 if (IS_ERR_OR_NULL(aml_dma->regmap))
This should just be if (IS_ERR(aml_dma->regmap)) since
devm_regmap_init_mmio() can't return NULL.
https://staticthinking.wordpress.com/2022/08/01/mixing-error-pointers-and-null/
c01d15789f1d15b Xianwei Zhao 2026-02-27 @483 return PTR_ERR(aml_dma->regmap);
c01d15789f1d15b Xianwei Zhao 2026-02-27 484
c01d15789f1d15b Xianwei Zhao 2026-02-27 485 aml_dma->clk = devm_clk_get_enabled(&pdev->dev, NULL);
c01d15789f1d15b Xianwei Zhao 2026-02-27 486 if (IS_ERR(aml_dma->clk))
c01d15789f1d15b Xianwei Zhao 2026-02-27 487 return PTR_ERR(aml_dma->clk);
c01d15789f1d15b Xianwei Zhao 2026-02-27 488
c01d15789f1d15b Xianwei Zhao 2026-02-27 489 aml_dma->irq = platform_get_irq(pdev, 0);
c01d15789f1d15b Xianwei Zhao 2026-02-27 490
c01d15789f1d15b Xianwei Zhao 2026-02-27 491 aml_dma->pdev = pdev;
c01d15789f1d15b Xianwei Zhao 2026-02-27 492 aml_dma->dma_device.dev = &pdev->dev;
c01d15789f1d15b Xianwei Zhao 2026-02-27 493
c01d15789f1d15b Xianwei Zhao 2026-02-27 494 dma_dev = &aml_dma->dma_device;
c01d15789f1d15b Xianwei Zhao 2026-02-27 495 INIT_LIST_HEAD(&dma_dev->channels);
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-03-02 8:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-27 7:20 [PATCH v4 0/3] Add Amlogic general DMA Xianwei Zhao via B4 Relay
2026-02-27 7:20 ` [PATCH v4 1/3] dt-bindings: dma: Add Amlogic A9 SoC DMA Xianwei Zhao via B4 Relay
2026-02-27 9:18 ` Krzysztof Kozlowski
2026-02-27 9:43 ` Xianwei Zhao
2026-02-27 9:44 ` Krzysztof Kozlowski
2026-02-27 9:49 ` Xianwei Zhao
2026-02-27 7:20 ` [PATCH v4 2/3] dma: amlogic: Add general DMA driver for A9 Xianwei Zhao via B4 Relay
2026-03-02 8:46 ` Dan Carpenter
2026-02-27 7:20 ` [PATCH v4 3/3] MAINTAINERS: Add an entry for Amlogic DMA driver Xianwei Zhao via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome