mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration
@ 2026-09-07  3:33 Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 1/5] dmaengine: arm-dma350: Fix source trigger bit Jelly Jia
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Jelly Jia @ 2026-09-07  3:33 UTC (permalink / raw)
  To: vkoul, robh, krzk+dt, conor+dt
  Cc: devicetree, Frank.Li, robin.murphy, cix-kernel-upstream,
	dmaengine, linux-arm-kernel, linux-kernel, Jelly Jia

Hello,

This series adds slave transfer support to the Arm DMA-350 driver and
the CIX Sky1 SoC integration around it.

Patch 1 fixes the CH_CTRL_USESRCTRIGIN definition: the source trigger
enable bit is bit 25, not bit 26 (which is the destination trigger
enable bit).

Patch 2 adds slave transfer support to the Arm DMA-350 driver:
scatter-gather and cyclic preparation, command-list allocation,
per-channel resource mapping including address translation through the
parent bus dma-ranges, and residue reporting. Slave transfers are
needed to serve peripheral requests, for example the audio FIFOs of
the CIX Sky1 audio subsystem.

Patch 3 documents the CIX Sky1 DMA-350 integration binding: a wrapper
node owning the SoC resources (clocks, resets, interrupt routing via
a syscon phandle, optional reserved memory) with the generic Arm
DMA-350 controller as its child.

Patch 4 adds the matching integration driver, which manages those
resources and populates the child controller.

Patch 5 adds the two Sky1 instances (FCH and AUDSS) to the SoC
devicetree.

The series is based on v7.3-rc1.

Testing:
- Built for arm64 with GCC 12.3 as both built-in and module, with no
  new warnings; sparse clean.
- checkpatch clean; dt_binding_check and dtbs_check pass for the new
  binding and nodes.
- Runtime-tested on CIX Sky1 boards with the FCH and AUDSS DMA-350
  instances.

Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>

Jelly Jia (5):
  dmaengine: arm-dma350: Fix source trigger bit
  dmaengine: arm-dma350: Add slave transfer support
  dt-bindings: dma: Add CIX Sky1 DMA-350 integration
  dmaengine: cix-sky1-dma350: Add Sky1 integration driver
  arm64: dts: cix: Add Sky1 DMA-350 nodes

 .../bindings/dma/cix,sky1-dma350.yaml         | 102 +++
 MAINTAINERS                                   |   2 +
 arch/arm64/boot/dts/cix/sky1.dtsi             |  61 +-
 drivers/dma/Kconfig                           |  15 +
 drivers/dma/Makefile                          |   1 +
 drivers/dma/arm-dma350.c                      | 642 +++++++++++++++++-
 drivers/dma/cix-sky1-dma350.c                 | 206 ++++++
 7 files changed, 993 insertions(+), 36 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
 create mode 100644 drivers/dma/cix-sky1-dma350.c


base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
-- 
2.54.0


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

* [PATCH v1 1/5] dmaengine: arm-dma350: Fix source trigger bit
  2026-09-07  3:33 [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration Jelly Jia
@ 2026-09-07  3:34 ` Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 2/5] dmaengine: arm-dma350: Add slave transfer support Jelly Jia
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Jelly Jia @ 2026-09-07  3:34 UTC (permalink / raw)
  To: vkoul, robh, krzk+dt, conor+dt
  Cc: devicetree, Frank.Li, robin.murphy, cix-kernel-upstream,
	dmaengine, linux-arm-kernel, linux-kernel, Jelly Jia

CH_CTRL_USESRCTRIGIN is the source trigger enable bit in CH_CTRL and
must use bit 25, not bit 26 which is the destination trigger enable bit
(CH_CTRL_USEDESTRIGIN).

The constant has no users yet, but enabling the source trigger input
would silently enable the destination trigger input instead, breaking
any transfer that waits for a peripheral request. Fix it before the
first user arrives.

Fixes: 5d099706449d ("dmaengine: Add Arm DMA-350 driver")
Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>
---
 drivers/dma/arm-dma350.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/arm-dma350.c b/drivers/dma/arm-dma350.c
index 09403aca8bb0..4e17130de6c8 100644
--- a/drivers/dma/arm-dma350.c
+++ b/drivers/dma/arm-dma350.c
@@ -63,7 +63,7 @@
 
 #define CH_CTRL			0x0c
 #define CH_CTRL_USEDESTRIGIN	BIT(26)
-#define CH_CTRL_USESRCTRIGIN	BIT(26)
+#define CH_CTRL_USESRCTRIGIN	BIT(25)
 #define CH_CTRL_DONETYPE	GENMASK(23, 21)
 #define CH_CTRL_REGRELOADTYPE	GENMASK(20, 18)
 #define CH_CTRL_XTYPE		GENMASK(11, 9)
-- 
2.54.0


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

* [PATCH v1 2/5] dmaengine: arm-dma350: Add slave transfer support
  2026-09-07  3:33 [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 1/5] dmaengine: arm-dma350: Fix source trigger bit Jelly Jia
@ 2026-09-07  3:34 ` Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration Jelly Jia
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Jelly Jia @ 2026-09-07  3:34 UTC (permalink / raw)
  To: vkoul, robh, krzk+dt, conor+dt
  Cc: devicetree, Frank.Li, robin.murphy, cix-kernel-upstream,
	dmaengine, linux-arm-kernel, linux-kernel, Jelly Jia

Add DMA slave support to the Arm DMA-350 driver, which so far only
supports memory-to-memory transfers.

Slave transfers are needed to serve peripheral requests: on the CIX
Sky1 SoC, for example, the audio subsystem uses DMA-350 channels to
move PCM data between memory and peripheral FIFOs, which requires both
scatter-gather and cyclic transfers.

This adds scatter-gather and cyclic preparation, command-list
allocation, per-channel resource mapping, and residue reporting.

Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>
---
 drivers/dma/arm-dma350.c | 640 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 617 insertions(+), 23 deletions(-)

diff --git a/drivers/dma/arm-dma350.c b/drivers/dma/arm-dma350.c
index 4e17130de6c8..85e8c5e42804 100644
--- a/drivers/dma/arm-dma350.c
+++ b/drivers/dma/arm-dma350.c
@@ -3,12 +3,19 @@
 // Arm DMA-350 driver
 
 #include <linux/bitfield.h>
+#include <linux/bitops.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
 #include <linux/module.h>
+#include <linux/overflow.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
 
 #include "dmaengine.h"
 #include "virt-dma.h"
@@ -102,6 +109,10 @@
 #define CH_FILLVAL		0x38
 #define CH_SRCTRIGINCFG		0x4c
 #define CH_DESTRIGINCFG		0x50
+#define CH_TRIGINCFG_BLKSIZE	GENMASK(23, 16)
+#define CH_TRIGINCFG_MODE	GENMASK(11, 10)
+#define CH_TRIGINCFG_TYPE	GENMASK(9, 8)
+#define CH_TRIGINCFG_SEL	GENMASK(7, 0)
 #define CH_LINKATTR		0x70
 #define CH_LINK_SHAREATTR	GENMASK(9, 8)
 #define CH_LINK_MEMATTR		GENMASK(7, 0)
@@ -147,6 +158,7 @@
 #define LINK_LINKADDR		BIT(30)
 #define LINK_LINKADDRHI		BIT(31)
 
+#define D350_SLAVE_CMD_WORDS	14
 
 enum ch_ctrl_donetype {
 	CH_CTRL_DONETYPE_NONE = 0,
@@ -161,6 +173,18 @@ enum ch_ctrl_xtype {
 	CH_CTRL_XTYPE_FILL = 3
 };
 
+enum ch_trigincfg_mode {
+	CH_TRIGINCFG_MODE_COMMAND = 0,
+	CH_TRIGINCFG_MODE_DMA_FC = 2,
+	CH_TRIGINCFG_MODE_PERIPH_FC = 3
+};
+
+enum ch_trigincfg_type {
+	CH_TRIGINCFG_TYPE_SW = 0,
+	CH_TRIGINCFG_TYPE_HW = 2,
+	CH_TRIGINCFG_TYPE_INTERNAL = 3
+};
+
 enum ch_cfg_shareattr {
 	SHAREATTR_NSH = 0,
 	SHAREATTR_OSH = 2,
@@ -178,7 +202,26 @@ struct d350_desc {
 	u32 command[16];
 	u16 xsize;
 	u16 xsizehi;
+	u32 *cmds;
+	dma_addr_t cmds_dma;	/* DMA API address from dma_alloc_coherent() */
+	dma_addr_t cmds_bus;	/* DMA350-visible address for CH_LINKADDR */
+	size_t cmds_size;
+	u32 *cmd_len;
+	size_t ncmds;
+	size_t bytes;
+	size_t period_len;
+	size_t periods;
+	size_t period;
 	u8 tsz;
+	bool cyclic;
+};
+
+struct d350_chan_map {
+	phys_addr_t cpu_addr;
+	dma_addr_t dma_addr;
+	size_t size;
+	enum dma_data_direction dir;
+	bool needs_unmap;
 };
 
 struct d350_chan {
@@ -189,10 +232,13 @@ struct d350_chan {
 	enum dma_status status;
 	dma_cookie_t cookie;
 	u32 residue;
+	u32 req;
 	u8 tsz;
 	bool has_trig;
 	bool has_wrap;
 	bool coherent;
+	struct d350_chan_map map;
+	struct dma_slave_config sconfig;
 };
 
 struct d350 {
@@ -212,9 +258,462 @@ static inline struct d350_desc *to_d350_desc(struct virt_dma_desc *vd)
 	return container_of(vd, struct d350_desc, vd);
 }
 
+static void d350_free_cmds(struct device *dev, struct d350_desc *desc)
+{
+	if (desc->cmds)
+		dma_free_coherent(dev, desc->cmds_size, desc->cmds,
+				  desc->cmds_dma);
+	kfree(desc->cmd_len);
+}
+
 static void d350_desc_free(struct virt_dma_desc *vd)
 {
-	kfree(to_d350_desc(vd));
+	struct d350_desc *desc = to_d350_desc(vd);
+
+	d350_free_cmds(vd->tx.chan->device->dev, desc);
+	kfree(desc);
+}
+
+static int d350_alloc_cmds(struct dma_chan *dchan, struct d350_desc *desc,
+			   size_t ncmds)
+{
+	size_t cmd_size = D350_SLAVE_CMD_WORDS * sizeof(u32);
+
+	if (check_mul_overflow(ncmds, cmd_size, &desc->cmds_size))
+		return -ENOMEM;
+
+	desc->cmds = dma_alloc_coherent(dchan->device->dev, desc->cmds_size,
+					&desc->cmds_dma, GFP_NOWAIT);
+	if (!desc->cmds)
+		return -ENOMEM;
+
+	desc->cmds_bus = desc->cmds_dma;
+	desc->ncmds = ncmds;
+
+	return 0;
+}
+
+static void d350_unmap_resource(struct d350_chan *dch)
+{
+	struct device *dev = dch->vc.chan.device->dev;
+	struct d350_chan_map *map = &dch->map;
+
+	if (map->dir == DMA_NONE)
+		return;
+
+	if (map->needs_unmap)
+		dma_unmap_resource(dev, map->dma_addr, map->size, map->dir, 0);
+
+	map->dir = DMA_NONE;
+	map->needs_unmap = false;
+}
+
+/*
+ * Translate a CPU physical/resource address to the address visible to DMA350
+ * using the dma-ranges property of its parent bus. This is needed for internal
+ * interconnect windows where the DMA master sees slave peripherals at
+ * different addresses from the CPU.
+ */
+static int d350_xlate_parent_dma_range(struct device *dev, phys_addr_t phys,
+				       size_t size, dma_addr_t *dma)
+{
+	struct device_node *parent;
+	struct of_range_parser parser;
+	struct of_range range;
+	int ret = -ENOENT;
+
+	parent = of_get_parent(dev->of_node);
+	if (!parent)
+		return -ENOENT;
+
+	if (of_pci_dma_range_parser_init(&parser, parent))
+		goto out_put;
+
+	for_each_of_range(&parser, &range) {
+		u64 offset;
+
+		if (phys < range.cpu_addr)
+			continue;
+
+		offset = phys - range.cpu_addr;
+		if (offset >= range.size)
+			continue;
+
+		if (size > range.size - offset)
+			continue;
+
+		*dma = range.bus_addr + offset;
+		ret = 0;
+		break;
+	}
+
+out_put:
+	of_node_put(parent);
+	return ret;
+}
+
+static dma_addr_t d350_map_resource(struct d350_chan *dch,
+				    phys_addr_t cpu_addr, size_t size,
+				    enum dma_data_direction dir)
+{
+	struct device *dev = dch->vc.chan.device->dev;
+	struct d350_chan_map *map = &dch->map;
+	dma_addr_t dma_addr;
+	int ret;
+
+	if (map->dir == dir && map->cpu_addr == cpu_addr &&
+	    map->size == size)
+		return map->dma_addr;
+
+	d350_unmap_resource(dch);
+
+	if (!device_iommu_mapped(dev)) {
+		ret = d350_xlate_parent_dma_range(dev, cpu_addr, size,
+						  &dma_addr);
+		if (!ret)
+			goto done;
+
+		if (ret != -ENOENT) {
+			dev_err(dev, "translate resource failed ch%u phys=%pa size=%zu\n",
+				dch->vc.chan.chan_id, &cpu_addr, size);
+			return DMA_MAPPING_ERROR;
+		}
+	}
+
+	dma_addr = dma_map_resource(dev, cpu_addr, size, dir, 0);
+	if (dma_mapping_error(dev, dma_addr)) {
+		dev_err(dev, "map slave failed ch%u phys=%pa size=%zu dir=%d\n",
+			dch->vc.chan.chan_id, &cpu_addr, size, dir);
+		return DMA_MAPPING_ERROR;
+	}
+	map->needs_unmap = true;
+
+done:
+	map->cpu_addr = cpu_addr;
+	map->dma_addr = dma_addr;
+	map->size = size;
+	map->dir = dir;
+
+	return map->dma_addr;
+}
+
+static bool d350_buswidth_supported(u32 widths, enum dma_slave_buswidth width)
+{
+	return width < BITS_PER_TYPE(widths) && (widths & BIT(width));
+}
+
+static int d350_check_slave_config(struct dma_device *dma,
+				   struct dma_slave_config *config)
+{
+	u32 maxburst = FIELD_MAX(CH_CFG_MAXBURSTLEN) + 1;
+	u32 widths = dma->src_addr_widths | dma->dst_addr_widths;
+
+	if (!d350_buswidth_supported(widths, config->src_addr_width) ||
+	    !d350_buswidth_supported(widths, config->dst_addr_width))
+		return -EINVAL;
+
+	if (config->src_maxburst > maxburst ||
+	    config->dst_maxburst > maxburst)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int d350_config(struct dma_chan *chan, struct dma_slave_config *config)
+{
+	struct d350_chan *dch = to_d350_chan(chan);
+	struct dma_device *dma = chan->device;
+	unsigned long flags;
+	int ret;
+
+	ret = d350_check_slave_config(dma, config);
+	if (ret) {
+		dev_err(dma->dev, "invalid slave configuration\n");
+		return ret;
+	}
+
+	spin_lock_irqsave(&dch->vc.lock, flags);
+	if (dch->desc || !list_empty(&dch->vc.desc_allocated) ||
+	    !list_empty(&dch->vc.desc_submitted) ||
+	    !list_empty(&dch->vc.desc_issued)) {
+		spin_unlock_irqrestore(&dch->vc.lock, flags);
+		return -EBUSY;
+	}
+	spin_unlock_irqrestore(&dch->vc.lock, flags);
+
+	d350_unmap_resource(dch);
+	memcpy(&dch->sconfig, config, sizeof(dch->sconfig));
+
+	return 0;
+}
+
+static struct dma_chan *d350_of_xlate(struct of_phandle_args *dma_spec,
+				      struct of_dma *ofdma)
+{
+	struct d350 *dmac = ofdma->of_dma_data;
+	struct dma_chan *chan;
+	struct d350_chan *dch;
+	u32 req;
+
+	if (dma_spec->args_count != 1) {
+		dev_err(dmac->dma.dev, "dma phandle must have one argument\n");
+		return NULL;
+	}
+
+	req = dma_spec->args[0];
+	if (req >= dmac->nreq) {
+		dev_err(dmac->dma.dev, "invalid DMA request %u, have %d\n",
+			req, dmac->nreq);
+		return NULL;
+	}
+
+	chan = dma_get_any_slave_channel(&dmac->dma);
+	if (!chan) {
+		dev_err(dmac->dma.dev, "can't get a dma channel\n");
+		return NULL;
+	}
+
+	dch = to_d350_chan(chan);
+	if (!dch->has_trig) {
+		dev_err(dmac->dma.dev, "channel %d has no trigger support\n",
+			chan->chan_id);
+		dma_release_channel(chan);
+		return NULL;
+	}
+	dch->req = req;
+
+	return chan;
+}
+
+static u32 d350_device_transcfg(u32 maxburst)
+{
+	return FIELD_PREP(CH_CFG_MAXBURSTLEN, maxburst - 1) |
+	       FIELD_PREP(CH_CFG_SHAREATTR, SHAREATTR_OSH) |
+	       FIELD_PREP(CH_CFG_MEMATTR, MEMATTR_DEVICE);
+}
+
+static int d350_slave_params(struct d350_chan *dch,
+			     enum dma_transfer_direction direction,
+			     phys_addr_t *dev_cpu_addr,
+			     enum dma_data_direction *dev_dir,
+			     enum dma_slave_buswidth *width, u32 *maxburst)
+{
+	struct dma_slave_config *config = &dch->sconfig;
+
+	if (direction == DMA_MEM_TO_DEV) {
+		*dev_cpu_addr = config->dst_addr;
+		*dev_dir = DMA_FROM_DEVICE;
+		*width = config->dst_addr_width;
+		*maxburst = config->dst_maxburst;
+	} else if (direction == DMA_DEV_TO_MEM) {
+		*dev_cpu_addr = config->src_addr;
+		*dev_dir = DMA_TO_DEVICE;
+		*width = config->src_addr_width;
+		*maxburst = config->src_maxburst;
+	} else {
+		return -EINVAL;
+	}
+
+	return *width && *maxburst ? 0 : -EINVAL;
+}
+
+static void d350_fill_slave_cmd(struct d350_chan *dch, struct d350_desc *desc,
+				u32 *cmd, dma_addr_t mem, dma_addr_t dev_dma_addr,
+				size_t len, dma_addr_t link_addr,
+				enum dma_transfer_direction direction,
+				enum dma_slave_buswidth width, u32 maxburst,
+				enum ch_ctrl_donetype donetype)
+{
+	bool mem_to_dev = direction == DMA_MEM_TO_DEV;
+	u16 xsize, xsizehi;
+	u32 devcfg;
+	u32 memcfg;
+	u32 trigcfg;
+
+	desc->tsz = __ffs(width);
+	xsize = lower_16_bits(len >> desc->tsz);
+	xsizehi = upper_16_bits(len >> desc->tsz);
+	devcfg = d350_device_transcfg(maxburst);
+	memcfg = dch->coherent ? TRANSCFG_WB : TRANSCFG_NC;
+
+	trigcfg = FIELD_PREP(CH_TRIGINCFG_BLKSIZE,
+			     mem_to_dev ? maxburst - 1 : 0) |
+		  FIELD_PREP(CH_TRIGINCFG_MODE, CH_TRIGINCFG_MODE_PERIPH_FC) |
+		  FIELD_PREP(CH_TRIGINCFG_TYPE, CH_TRIGINCFG_TYPE_HW) |
+		  FIELD_PREP(CH_TRIGINCFG_SEL, dch->req);
+
+	cmd[0] = LINK_CTRL | LINK_SRCADDR | LINK_SRCADDRHI | LINK_DESADDR |
+		 LINK_DESADDRHI | LINK_XSIZE | LINK_XSIZEHI | LINK_SRCTRANSCFG |
+		 LINK_DESTRANSCFG | LINK_XADDRINC | LINK_LINKADDR |
+		 LINK_LINKADDRHI |
+		 (mem_to_dev ? LINK_DESTRIGINCFG : LINK_SRCTRIGINCFG);
+	cmd[1] = (mem_to_dev ? CH_CTRL_USEDESTRIGIN : CH_CTRL_USESRCTRIGIN) |
+		 FIELD_PREP(CH_CTRL_TRANSIZE, desc->tsz) |
+		 FIELD_PREP(CH_CTRL_XTYPE, CH_CTRL_XTYPE_CONTINUE) |
+		 FIELD_PREP(CH_CTRL_DONETYPE, donetype);
+	cmd[2] = lower_32_bits(mem_to_dev ? mem : dev_dma_addr);
+	cmd[3] = upper_32_bits(mem_to_dev ? mem : dev_dma_addr);
+	cmd[4] = lower_32_bits(mem_to_dev ? dev_dma_addr : mem);
+	cmd[5] = upper_32_bits(mem_to_dev ? dev_dma_addr : mem);
+	cmd[6] = FIELD_PREP(CH_XY_SRC, xsize) |
+		 FIELD_PREP(CH_XY_DES, xsize);
+	cmd[7] = FIELD_PREP(CH_XY_SRC, xsizehi) |
+		 FIELD_PREP(CH_XY_DES, xsizehi);
+	cmd[8] = mem_to_dev ? memcfg : devcfg;
+	cmd[9] = mem_to_dev ? devcfg : memcfg;
+	cmd[10] = mem_to_dev ? FIELD_PREP(CH_XY_SRC, 1) :
+				FIELD_PREP(CH_XY_DES, 1);
+	cmd[11] = trigcfg;
+	cmd[12] = lower_32_bits(link_addr) |
+		  (link_addr ? CH_LINKADDR_EN : 0);
+	cmd[13] = upper_32_bits(link_addr);
+}
+
+static struct dma_async_tx_descriptor *
+d350_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+		   unsigned int sg_len,
+		   enum dma_transfer_direction direction,
+		   unsigned long flags, void *context)
+{
+	struct d350_chan *dch = to_d350_chan(dchan);
+	size_t cmd_size = D350_SLAVE_CMD_WORDS * sizeof(u32);
+	enum dma_data_direction dev_dir;
+	enum dma_slave_buswidth width;
+	struct d350_desc *desc;
+	phys_addr_t dev_cpu_addr;
+	dma_addr_t dev_dma_addr, mem;
+	struct scatterlist *sg;
+	u32 maxburst;
+	size_t len;
+	int i;
+
+	if (unlikely(!is_slave_direction(direction) || !sg_len))
+		return NULL;
+
+	if (d350_slave_params(dch, direction, &dev_cpu_addr, &dev_dir, &width,
+			      &maxburst))
+		return NULL;
+
+	dev_dma_addr = d350_map_resource(dch, dev_cpu_addr, width, dev_dir);
+	if (dma_mapping_error(dchan->device->dev, dev_dma_addr))
+		return NULL;
+
+	desc = kzalloc_obj(*desc, GFP_NOWAIT);
+	if (!desc)
+		return NULL;
+
+	if (sg_len > 1) {
+		if (d350_alloc_cmds(dchan, desc, sg_len))
+			goto err_free_desc;
+
+		desc->cmd_len = kcalloc(sg_len, sizeof(*desc->cmd_len),
+					GFP_NOWAIT);
+		if (!desc->cmd_len)
+			goto err_free_cmds;
+	}
+
+	for_each_sg(sgl, sg, sg_len, i) {
+		enum ch_ctrl_donetype donetype = CH_CTRL_DONETYPE_CMD;
+		dma_addr_t link_addr = 0;
+		u32 *cmd = desc->command;
+
+		mem = sg_dma_address(sg);
+		len = sg_dma_len(sg);
+		if (!len || (len >> __ffs(width)) > U32_MAX ||
+		    !IS_ALIGNED(len | mem | dev_dma_addr, width))
+			goto err_free_cmds;
+
+		if (sg_len > 1) {
+			cmd = desc->cmds + i * D350_SLAVE_CMD_WORDS;
+			if (i < sg_len - 1) {
+				link_addr = desc->cmds_bus + (i + 1) * cmd_size;
+				donetype = CH_CTRL_DONETYPE_NONE;
+			}
+			desc->cmd_len[i] = len;
+		}
+
+		if (check_add_overflow(desc->bytes, len, &desc->bytes) ||
+		    desc->bytes > U32_MAX)
+			goto err_free_cmds;
+
+		d350_fill_slave_cmd(dch, desc, cmd, mem, dev_dma_addr, len,
+				    link_addr, direction, width, maxburst,
+				    donetype);
+	}
+
+	if (sg_len > 1)
+		memcpy(desc->command, desc->cmds, cmd_size);
+
+	return vchan_tx_prep(&dch->vc, &desc->vd, flags);
+
+err_free_cmds:
+	d350_free_cmds(dchan->device->dev, desc);
+err_free_desc:
+	kfree(desc);
+
+	return NULL;
+}
+
+static struct dma_async_tx_descriptor *
+d350_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t buf_addr,
+		     size_t buf_len, size_t period_len,
+		     enum dma_transfer_direction direction, unsigned long flags)
+{
+	struct d350_chan *dch = to_d350_chan(dchan);
+	struct d350_desc *desc;
+	phys_addr_t dev_cpu_addr;
+	dma_addr_t dev_dma_addr;
+	enum dma_data_direction dev_dir;
+	enum dma_slave_buswidth width;
+	size_t period, cmd_size;
+	u32 maxburst;
+	int ret;
+
+	if (!buf_len || !period_len || buf_len % period_len ||
+	    buf_len > U32_MAX || !is_slave_direction(direction))
+		return NULL;
+
+	ret = d350_slave_params(dch, direction, &dev_cpu_addr, &dev_dir, &width,
+				&maxburst);
+	if (ret)
+		return NULL;
+
+	dev_dma_addr = d350_map_resource(dch, dev_cpu_addr, width, dev_dir);
+	if (dma_mapping_error(dchan->device->dev, dev_dma_addr))
+		return NULL;
+
+	if (!IS_ALIGNED(buf_addr | dev_dma_addr | period_len, width))
+		return NULL;
+
+	desc = kzalloc_obj(*desc, GFP_NOWAIT);
+	if (!desc)
+		return NULL;
+
+	desc->bytes = buf_len;
+	desc->period_len = period_len;
+	desc->periods = buf_len / period_len;
+	desc->cyclic = true;
+
+	if (d350_alloc_cmds(dchan, desc, desc->periods)) {
+		kfree(desc);
+		return NULL;
+	}
+
+	cmd_size = D350_SLAVE_CMD_WORDS * sizeof(u32);
+
+	for (period = 0; period < desc->periods; period++) {
+		u32 *cmd = desc->cmds + period * D350_SLAVE_CMD_WORDS;
+		dma_addr_t mem = buf_addr + period * period_len;
+		dma_addr_t next = desc->cmds_bus +
+				  ((period + 1) % desc->periods) * cmd_size;
+
+		d350_fill_slave_cmd(dch, desc, cmd, mem, dev_dma_addr,
+				    period_len, next, direction, width, maxburst,
+				    CH_CTRL_DONETYPE_CMD);
+	}
+	memcpy(desc->command, desc->cmds, cmd_size);
+
+	return vchan_tx_prep(&dch->vc, &desc->vd, flags);
 }
 
 static struct dma_async_tx_descriptor *d350_prep_memcpy(struct dma_chan *chan,
@@ -228,6 +727,7 @@ static struct dma_async_tx_descriptor *d350_prep_memcpy(struct dma_chan *chan,
 	if (!desc)
 		return NULL;
 
+	desc->bytes = len;
 	desc->tsz = __ffs(len | dest | src | (1 << dch->tsz));
 	desc->xsize = lower_16_bits(len >> desc->tsz);
 	desc->xsizehi = upper_16_bits(len >> desc->tsz);
@@ -266,6 +766,7 @@ static struct dma_async_tx_descriptor *d350_prep_memset(struct dma_chan *chan,
 	if (!desc)
 		return NULL;
 
+	desc->bytes = len;
 	desc->tsz = __ffs(len | dest | (1 << dch->tsz));
 	desc->xsize = lower_16_bits(len >> desc->tsz);
 	desc->xsizehi = upper_16_bits(len >> desc->tsz);
@@ -339,6 +840,45 @@ static u32 d350_get_residue(struct d350_chan *dch)
 	return res << dch->desc->tsz;
 }
 
+static u32 d350_get_sg_residue(struct d350_chan *dch)
+{
+	struct d350_desc *desc = dch->desc;
+	size_t cmd_size = D350_SLAVE_CMD_WORDS * sizeof(u32);
+	size_t cmd = 0, i;
+	u32 residue;
+	u64 next_cmd;
+
+	if (!desc->cmd_len)
+		return d350_get_residue(dch);
+
+	/*
+	 * CH_LINKADDR points at the next command. Match it against the command
+	 * array to find the command currently executing, then add every later
+	 * command which has not started yet.
+	 */
+	next_cmd = readl_relaxed(dch->base + CH_LINKADDR) & ~CH_LINKADDR_EN;
+	next_cmd |= (u64)readl_relaxed(dch->base + CH_LINKADDRHI) << 32;
+
+	if (!next_cmd) {
+		cmd = desc->ncmds - 1;
+	} else {
+		for (i = 1; i < desc->ncmds; i++) {
+			if (next_cmd == desc->cmds_bus + i * cmd_size) {
+				cmd = i - 1;
+				break;
+			}
+		}
+		if (i == desc->ncmds)
+			return dch->residue;
+	}
+
+	residue = d350_get_residue(dch);
+	for (i = cmd + 1; i < desc->ncmds; i++)
+		residue += desc->cmd_len[i];
+
+	return residue;
+}
+
 static int d350_terminate_all(struct dma_chan *chan)
 {
 	struct d350_chan *dch = to_d350_chan(chan);
@@ -369,7 +909,20 @@ static void d350_synchronize(struct dma_chan *chan)
 
 static u32 d350_desc_bytes(struct d350_desc *desc)
 {
-	return ((u32)desc->xsizehi << 16 | desc->xsize) << desc->tsz;
+	return desc->bytes;
+}
+
+static u32 d350_get_cyclic_residue(struct d350_desc *desc)
+{
+	return desc->bytes - desc->period * desc->period_len;
+}
+
+static u32 d350_get_active_residue(struct d350_chan *dch)
+{
+	if (dch->desc->cyclic)
+		return d350_get_cyclic_residue(dch->desc);
+
+	return d350_get_sg_residue(dch);
 }
 
 static enum dma_status d350_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
@@ -387,7 +940,7 @@ static enum dma_status d350_tx_status(struct dma_chan *chan, dma_cookie_t cookie
 	if (cookie == dch->cookie) {
 		status = dch->status;
 		if (status == DMA_IN_PROGRESS || status == DMA_PAUSED)
-			dch->residue = d350_get_residue(dch);
+			dch->residue = d350_get_active_residue(dch);
 		residue = dch->residue;
 	} else if ((vd = vchan_find_desc(&dch->vc, cookie))) {
 		residue = d350_desc_bytes(to_d350_desc(vd));
@@ -469,17 +1022,32 @@ static void d350_issue_pending(struct dma_chan *chan)
 static irqreturn_t d350_irq(int irq, void *data)
 {
 	struct d350_chan *dch = data;
-	struct device *dev = dch->vc.chan.device->dev;
-	struct virt_dma_desc *vd = &dch->desc->vd;
+	struct virt_dma_desc *vd;
+	struct d350_desc *desc;
+	u32 residue = 0;
 	u32 ch_status;
+	u32 irq_status;
+	u32 errinfo = 0;
 
 	ch_status = readl(dch->base + CH_STATUS);
-	if (!ch_status)
+	irq_status = ch_status & (CH_STAT_INTR_DONE | CH_STAT_INTR_ERR);
+	if (!irq_status)
 		return IRQ_NONE;
 
-	if (ch_status & CH_STAT_INTR_ERR) {
-		u32 errinfo = readl_relaxed(dch->base + CH_ERRINFO);
+	if (irq_status & CH_STAT_INTR_ERR)
+		errinfo = readl_relaxed(dch->base + CH_ERRINFO);
 
+	writel_relaxed(ch_status, dch->base + CH_STATUS);
+
+	spin_lock(&dch->vc.lock);
+	desc = dch->desc;
+	if (!desc) {
+		spin_unlock(&dch->vc.lock);
+		return IRQ_HANDLED;
+	}
+
+	vd = &desc->vd;
+	if (irq_status & CH_STAT_INTR_ERR) {
 		if (errinfo & (CH_ERRINFO_AXIRDPOISERR | CH_ERRINFO_AXIRDRESPERR))
 			vd->tx_result.result = DMA_TRANS_READ_FAILED;
 		else if (errinfo & CH_ERRINFO_AXIWRRESPERR)
@@ -487,21 +1055,27 @@ static irqreturn_t d350_irq(int irq, void *data)
 		else
 			vd->tx_result.result = DMA_TRANS_ABORTED;
 
-		vd->tx_result.residue = d350_get_residue(dch);
-	} else if (!(ch_status & CH_STAT_INTR_DONE)) {
-		dev_warn(dev, "Unexpected IRQ source? 0x%08x\n", ch_status);
-	}
-	writel_relaxed(ch_status, dch->base + CH_STATUS);
-
-	spin_lock(&dch->vc.lock);
-	vchan_cookie_complete(vd);
-	if (ch_status & CH_STAT_INTR_DONE) {
-		dch->status = DMA_COMPLETE;
-		dch->residue = 0;
-		d350_start_next(dch);
-	} else {
+		residue = d350_get_active_residue(dch);
+		vd->tx_result.residue = residue;
 		dch->status = DMA_ERROR;
-		dch->residue = vd->tx_result.residue;
+		dch->residue = residue;
+		dch->desc = NULL;
+		if (desc->cyclic)
+			vchan_terminate_vdesc(vd);
+		else
+			vchan_cookie_complete(vd);
+	} else {
+		if (desc->cyclic) {
+			desc->period = (desc->period + 1) % desc->periods;
+			dch->residue = d350_get_cyclic_residue(desc);
+			vchan_cyclic_callback(vd);
+		} else {
+			dch->status = DMA_COMPLETE;
+			dch->residue = 0;
+			dch->desc = NULL;
+			vchan_cookie_complete(vd);
+			d350_start_next(dch);
+		}
 	}
 	spin_unlock(&dch->vc.lock);
 
@@ -525,6 +1099,7 @@ static void d350_free_chan_resources(struct dma_chan *chan)
 
 	writel_relaxed(0, dch->base + CH_INTREN);
 	free_irq(dch->irq, dch);
+	d350_unmap_resource(dch);
 	vchan_free_chan_resources(&dch->vc);
 }
 
@@ -568,23 +1143,32 @@ static int d350_probe(struct platform_device *pdev)
 	dev_dbg(dev, "DMA-350 r%dp%d with %d channels, %d requests\n", r, p, dmac->nchan, dmac->nreq);
 
 	dmac->dma.dev = dev;
+	dmac->dma.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
+	dmac->dma.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
 	for (int i = min(dw, 16); i > 0; i /= 2) {
 		dmac->dma.src_addr_widths |= BIT(i);
 		dmac->dma.dst_addr_widths |= BIT(i);
 	}
-	dmac->dma.directions = BIT(DMA_MEM_TO_MEM);
+	dmac->dma.directions = BIT(DMA_MEM_TO_MEM) |
+			BIT(DMA_MEM_TO_DEV) |
+			BIT(DMA_DEV_TO_MEM);
 	dmac->dma.descriptor_reuse = true;
 	dmac->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
 	dmac->dma.device_alloc_chan_resources = d350_alloc_chan_resources;
 	dmac->dma.device_free_chan_resources = d350_free_chan_resources;
 	dma_cap_set(DMA_MEMCPY, dmac->dma.cap_mask);
+	dma_cap_set(DMA_SLAVE, dmac->dma.cap_mask);
+	dma_cap_set(DMA_CYCLIC, dmac->dma.cap_mask);
 	dmac->dma.device_prep_dma_memcpy = d350_prep_memcpy;
+	dmac->dma.device_prep_slave_sg = d350_prep_slave_sg;
+	dmac->dma.device_prep_dma_cyclic = d350_prep_dma_cyclic;
 	dmac->dma.device_pause = d350_pause;
 	dmac->dma.device_resume = d350_resume;
 	dmac->dma.device_terminate_all = d350_terminate_all;
 	dmac->dma.device_synchronize = d350_synchronize;
 	dmac->dma.device_tx_status = d350_tx_status;
 	dmac->dma.device_issue_pending = d350_issue_pending;
+	dmac->dma.device_config = d350_config;
 	INIT_LIST_HEAD(&dmac->dma.channels);
 
 	reg = readl_relaxed(base + DMANSECCTRL + NSEC_CTRL);
@@ -623,6 +1207,8 @@ static int d350_probe(struct platform_device *pdev)
 		reg |= FIELD_PREP(CH_LINK_MEMATTR, coherent ? MEMATTR_WB : MEMATTR_NC);
 		writel_relaxed(reg, dch->base + CH_LINKATTR);
 
+		dch->coherent = coherent;
+		dch->map.dir = DMA_NONE;
 		dch->vc.desc_free = d350_desc_free;
 		vchan_init(&dch->vc, &dmac->dma);
 	}
@@ -638,6 +1224,13 @@ static int d350_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to register DMA device\n");
 
+	ret = of_dma_controller_register(dev->of_node, d350_of_xlate, dmac);
+	if (ret) {
+		dma_async_device_unregister(&dmac->dma);
+		return dev_err_probe(dev, ret,
+				     "Failed to register OF DMA controller\n");
+	}
+
 	return 0;
 }
 
@@ -645,6 +1238,7 @@ static void d350_remove(struct platform_device *pdev)
 {
 	struct d350 *dmac = platform_get_drvdata(pdev);
 
+	of_dma_controller_free(pdev->dev.of_node);
 	dma_async_device_unregister(&dmac->dma);
 }
 
-- 
2.54.0


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

* [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
  2026-09-07  3:33 [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 1/5] dmaengine: arm-dma350: Fix source trigger bit Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 2/5] dmaengine: arm-dma350: Add slave transfer support Jelly Jia
@ 2026-09-07  3:34 ` Jelly Jia
  2026-09-07 17:15   ` Conor Dooley
  2026-09-07  3:34 ` [PATCH v1 4/5] dmaengine: cix-sky1-dma350: Add Sky1 integration driver Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 5/5] arm64: dts: cix: Add Sky1 DMA-350 nodes Jelly Jia
  4 siblings, 1 reply; 9+ messages in thread
From: Jelly Jia @ 2026-09-07  3:34 UTC (permalink / raw)
  To: vkoul, robh, krzk+dt, conor+dt
  Cc: devicetree, Frank.Li, robin.murphy, cix-kernel-upstream,
	dmaengine, linux-arm-kernel, linux-kernel, Jelly Jia

Document the CIX Sky1 integration wrapper around an Arm DMA-350 controller.

The wrapper owns SoC integration resources. The child node describes the
generic Arm DMA-350 IP.

Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>
---
 .../bindings/dma/cix,sky1-dma350.yaml         | 102 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 2 files changed, 103 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml

diff --git a/Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml b/Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
new file mode 100644
index 000000000000..e533f355d135
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/cix,sky1-dma350.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CIX Sky1 DMA-350 Integration
+
+maintainers:
+  - CIX Kernel Team <cix-kernel-upstream@cixtech.com>
+
+description:
+  The CIX Sky1 DMA-350 integration driver owns SoC resources around an
+  Arm DMA-350 controller, such as clocks, resets, interrupt routing, and
+  optional reserved memory. Reserved memory is described on this parent node
+  and assigned by the integration driver to the child DMA-350 device. The child
+  node describes the generic DMA-350 IP.
+
+properties:
+  $nodename:
+    pattern: "^dma@[0-9a-f]+$"
+
+  compatible:
+    const: cix,sky1-dma350
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 2
+
+  ranges: true
+
+  dma-ranges: true
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  cix,irq-router:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Syscon phandle for the Sky1 subsystem register block that routes
+      DMA-350 channel interrupts to the AP interrupt controller.
+
+  memory-region:
+    maxItems: 1
+    description:
+      Reserved memory pool assigned by the CIX Sky1 DMA-350 integration driver
+      to the child Arm DMA-350 device.
+
+patternProperties:
+  '^dma-controller@[0-9a-f]+$':
+    $ref: arm,dma-350.yaml#
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - dma-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    / {
+        #address-cells = <2>;
+        #size-cells = <2>;
+        interrupt-parent = <&gic>;
+
+        gic: interrupt-controller {
+            #address-cells = <0>;
+            interrupt-controller;
+            #interrupt-cells = <4>;
+        };
+
+        dma@7010000 {
+            compatible = "cix,sky1-dma350";
+            #address-cells = <2>;
+            #size-cells = <2>;
+            ranges = <0x0 0x0 0x0 0x07010000 0x0 0x10000>;
+            dma-ranges = <0x0 0x20000000 0x0 0x07010000 0x0 0x00100000>;
+            clocks = <&clk 9>;
+            resets = <&rst 15>;
+            cix,irq-router = <&audss_cru>;
+
+            dma-controller@0 {
+                compatible = "arm,dma-350";
+                reg = <0x0 0x0 0x0 0x10000>;
+                interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>;
+                #dma-cells = <1>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c..feff8f9ecb2b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2825,6 +2825,7 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 T:	git https://github.com/cixtech/linux-mainline.git
 F:	Documentation/devicetree/bindings/arm/cix.yaml
+F:	Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
 F:	Documentation/devicetree/bindings/mailbox/cix,sky1-mbox.yaml
 F:	arch/arm64/boot/dts/cix/
 F:	drivers/mailbox/cix-mailbox.c
-- 
2.54.0


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

* [PATCH v1 4/5] dmaengine: cix-sky1-dma350: Add Sky1 integration driver
  2026-09-07  3:33 [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration Jelly Jia
                   ` (2 preceding siblings ...)
  2026-09-07  3:34 ` [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration Jelly Jia
@ 2026-09-07  3:34 ` Jelly Jia
  2026-09-07  3:34 ` [PATCH v1 5/5] arm64: dts: cix: Add Sky1 DMA-350 nodes Jelly Jia
  4 siblings, 0 replies; 9+ messages in thread
From: Jelly Jia @ 2026-09-07  3:34 UTC (permalink / raw)
  To: vkoul, robh, krzk+dt, conor+dt
  Cc: devicetree, Frank.Li, robin.murphy, cix-kernel-upstream,
	dmaengine, linux-arm-kernel, linux-kernel, Jelly Jia

Add a CIX Sky1 integration driver for Arm DMA-350 instances.

The driver manages clocks, reset, optional interrupt routing, optional
reserved memory attachment, and populates the child Arm DMA-350
controller.

Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>
---
 MAINTAINERS                   |   1 +
 drivers/dma/Kconfig           |  15 +++
 drivers/dma/Makefile          |   1 +
 drivers/dma/cix-sky1-dma350.c | 206 ++++++++++++++++++++++++++++++++++
 4 files changed, 223 insertions(+)
 create mode 100644 drivers/dma/cix-sky1-dma350.c

diff --git a/MAINTAINERS b/MAINTAINERS
index feff8f9ecb2b..8d972fe2c994 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2828,6 +2828,7 @@ F:	Documentation/devicetree/bindings/arm/cix.yaml
 F:	Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
 F:	Documentation/devicetree/bindings/mailbox/cix,sky1-mbox.yaml
 F:	arch/arm64/boot/dts/cix/
+F:	drivers/dma/cix-sky1-dma350.c
 F:	drivers/mailbox/cix-mailbox.c
 K:	\bcix\b
 
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ae6a682c9f76..51c881dfa6d3 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -147,6 +147,21 @@ config DMA_BCM2835
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 
+config CIX_SKY1_DMA350
+	tristate "CIX Sky1 DMA-350 integration support"
+	depends on OF && ARM_DMA350
+	depends on OF_RESERVED_MEM
+	depends on ARCH_CIX || COMPILE_TEST
+	default ARCH_CIX
+	select MFD_SYSCON
+	help
+	  Enable support for the CIX Sky1 integration around Arm
+	  DMA-350 controllers.
+
+	  This driver owns SoC integration resources such as clocks, resets,
+	  reserved memory attachment, and interrupt routing registers, while the
+	  child controller is handled by the generic Arm DMA-350 driver.
+
 config DMA_JZ4780
 	tristate "JZ4780 DMA support"
 	depends on MIPS || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 14aa086629d5..a69964251f68 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
 obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o
 obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.o
 obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
+obj-$(CONFIG_CIX_SKY1_DMA350) += cix-sky1-dma350.o
 obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o
 obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
 obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o
diff --git a/drivers/dma/cix-sky1-dma350.c b/drivers/dma/cix-sky1-dma350.c
new file mode 100644
index 000000000000..5904453f3481
--- /dev/null
+++ b/drivers/dma/cix-sky1-dma350.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CIX Sky1 DMA-350 integration driver
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define SKY1_DMA350_CRU_DMAC_AP_IRQ	0x54
+#define SKY1_DMA350_IRQ_ROUTE_MASK	0xff
+
+struct cix_sky1_dma350 {
+	struct clk_bulk_data *clks;
+	struct reset_control *reset;
+	struct regmap *irq_router;
+	struct device *rmem_dev;
+	int num_clks;
+};
+
+static int cix_sky1_dma350_route_irqs(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+
+	if (!data->irq_router)
+		return 0;
+
+	return regmap_update_bits(data->irq_router,
+				  SKY1_DMA350_CRU_DMAC_AP_IRQ,
+				  SKY1_DMA350_IRQ_ROUTE_MASK,
+				  SKY1_DMA350_IRQ_ROUTE_MASK);
+}
+
+static int cix_sky1_dma350_enable_resources(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_bulk_prepare_enable(data->num_clks, data->clks);
+	if (ret)
+		return ret;
+
+	ret = reset_control_reset(data->reset);
+	if (ret)
+		goto err_disable_clks;
+
+	ret = cix_sky1_dma350_route_irqs(dev);
+	if (ret)
+		goto err_disable_clks;
+
+	return 0;
+
+err_disable_clks:
+	clk_bulk_disable_unprepare(data->num_clks, data->clks);
+	return ret;
+}
+
+static void cix_sky1_dma350_disable_resources(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+
+	reset_control_assert(data->reset);
+	clk_bulk_disable_unprepare(data->num_clks, data->clks);
+}
+
+static int cix_sky1_dma350_attach_reserved_mem(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+	struct platform_device *child_pdev;
+	struct device_node *child_np;
+	int ret;
+
+	if (!of_property_present(dev->of_node, "memory-region"))
+		return 0;
+
+	child_np = of_get_compatible_child(dev->of_node, "arm,dma-350");
+	if (!child_np)
+		return -ENODEV;
+
+	child_pdev = of_find_device_by_node(child_np);
+	of_node_put(child_np);
+	if (!child_pdev)
+		return -EPROBE_DEFER;
+
+	/*
+	 * Reserved memory is attached after the child has probed. This relies
+	 * on arm-dma350 not allocating coherent command buffers in probe;
+	 * those allocations happen per descriptor at prep time.
+	 */
+	ret = of_reserved_mem_device_init_by_idx(&child_pdev->dev,
+						 dev->of_node, 0);
+	if (ret) {
+		put_device(&child_pdev->dev);
+		return ret;
+	}
+
+	data->rmem_dev = &child_pdev->dev;
+
+	return 0;
+}
+
+static void cix_sky1_dma350_release_reserved_mem(struct device *dev)
+{
+	struct cix_sky1_dma350 *data = dev_get_drvdata(dev);
+
+	if (data->rmem_dev) {
+		of_reserved_mem_device_release(data->rmem_dev);
+		put_device(data->rmem_dev);
+		data->rmem_dev = NULL;
+	}
+}
+
+static int cix_sky1_dma350_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cix_sky1_dma350 *data;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, data);
+
+	data->num_clks = devm_clk_bulk_get_all(dev, &data->clks);
+	if (data->num_clks < 0)
+		return dev_err_probe(dev, data->num_clks,
+				     "failed to get clocks\n");
+
+	data->reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+	if (IS_ERR(data->reset))
+		return dev_err_probe(dev, PTR_ERR(data->reset),
+				     "failed to get reset\n");
+
+	data->irq_router = syscon_regmap_lookup_by_phandle_optional(dev->of_node,
+								    "cix,irq-router");
+	if (IS_ERR(data->irq_router))
+		return dev_err_probe(dev, PTR_ERR(data->irq_router),
+				     "failed to get IRQ router\n");
+
+	ret = cix_sky1_dma350_enable_resources(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable resources\n");
+
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret)
+		goto err_disable_resources;
+
+	ret = cix_sky1_dma350_attach_reserved_mem(dev);
+	if (ret)
+		goto err_depopulate;
+
+	return 0;
+
+err_depopulate:
+	of_platform_depopulate(dev);
+err_disable_resources:
+	cix_sky1_dma350_disable_resources(dev);
+	return dev_err_probe(dev, ret, "failed to initialize child devices\n");
+}
+
+static void cix_sky1_dma350_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	of_platform_depopulate(dev);
+	cix_sky1_dma350_release_reserved_mem(dev);
+	cix_sky1_dma350_disable_resources(dev);
+}
+
+static int __maybe_unused cix_sky1_dma350_resume_noirq(struct device *dev)
+{
+	return cix_sky1_dma350_route_irqs(dev);
+}
+
+static const struct dev_pm_ops cix_sky1_dma350_pm = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, cix_sky1_dma350_resume_noirq)
+};
+
+static const struct of_device_id cix_sky1_dma350_of_match[] = {
+	{ .compatible = "cix,sky1-dma350" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, cix_sky1_dma350_of_match);
+
+static struct platform_driver cix_sky1_dma350_driver = {
+	.probe = cix_sky1_dma350_probe,
+	.remove = cix_sky1_dma350_remove,
+	.driver = {
+		.name = "cix-sky1-dma350",
+		.of_match_table = cix_sky1_dma350_of_match,
+		.pm = pm_sleep_ptr(&cix_sky1_dma350_pm),
+	},
+};
+module_platform_driver(cix_sky1_dma350_driver);
+
+MODULE_AUTHOR("Jelly Jia <Jelly.Jia@cixtech.com>");
+MODULE_DESCRIPTION("CIX Sky1 DMA-350 integration driver");
+MODULE_LICENSE("GPL");
-- 
2.54.0


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

* [PATCH v1 5/5] arm64: dts: cix: Add Sky1 DMA-350 nodes
  2026-09-07  3:33 [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration Jelly Jia
                   ` (3 preceding siblings ...)
  2026-09-07  3:34 ` [PATCH v1 4/5] dmaengine: cix-sky1-dma350: Add Sky1 integration driver Jelly Jia
@ 2026-09-07  3:34 ` Jelly Jia
  4 siblings, 0 replies; 9+ messages in thread
From: Jelly Jia @ 2026-09-07  3:34 UTC (permalink / raw)
  To: vkoul, robh, krzk+dt, conor+dt
  Cc: devicetree, Frank.Li, robin.murphy, cix-kernel-upstream,
	dmaengine, linux-arm-kernel, linux-kernel, Jelly Jia

Add CIX Sky1 DMA-350 integration nodes with child Arm DMA-350 controllers.

The nodes describe the FCH and AUDSS DMA instances.

Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>
---
 arch/arm64/boot/dts/cix/sky1.dtsi | 61 +++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
index 0a820f45feb9..7a5e463dc7c5 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -518,18 +518,29 @@ iomuxc: pinctrl@4170000 {
 			reg = <0x0 0x04170000 0x0 0x1000>;
 		};
 
-		fch_dmac: dma-controller@4190000 {
-			compatible = "arm,dma-350";
-			reg = <0x0 0x4190000 0x0 0x10000>;
-			interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
-				     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>;
-			#dma-cells = <1>;
+		cix_fch_dmac: dma@4190000 {
+			compatible = "cix,sky1-dma350";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges = <0x0 0x0 0x0 0x4190000 0x0 0x10000>;
+			dma-ranges = <0x0 0x040a0000 0x0 0x040b0000 0x0 0x00040000>,
+				     <0x0 0x80000000 0x0 0x80000000 0x8 0x00000000>,
+				     <0x80 0x00000000 0x80 0x00000000 0x80 0x00000000>;
+			clocks = <&scmi_clk CLK_TREE_FCH_DMA_ACLK>;
+
+			fch_dmac: dma-controller@0 {
+				compatible = "arm,dma-350";
+				reg = <0x0 0x0 0x0 0x10000>;
+				interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>,
+						<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>;
+				#dma-cells = <1>;
+			};
 		};
 
 		mbox_ap2se: mailbox@5060000 {
@@ -576,6 +587,32 @@ mbox_pm2ap: mailbox@65a0080 {
 			cix,mbox-dir = "rx";
 		};
 
+		cix_audss_dmac: dma@7010000 {
+			compatible = "cix,sky1-dma350";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges = <0x0 0x0 0x0 0x07010000 0x0 0x10000>;
+			dma-ranges = <0x0 0x20000000 0x0 0x07010000 0x0 0x00100000>,
+				     <0x0 0x30000000 0x0 0xc0000000 0x0 0x20000000>;
+			clocks = <&audss_cru CLK_DMAC_AXI>;
+			resets = <&audss_cru AUDSS_DMAC_SW_RST>;
+			cix,irq-router = <&audss_cru>;
+
+			audss_dmac: dma-controller@0 {
+				compatible = "arm,dma-350";
+				reg = <0x0 0x0 0x0 0x10000>;
+				interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>;
+				#dma-cells = <1>;
+			};
+		};
+
 		audss_cru: clock-controller@7110000 {
 			compatible = "cix,sky1-audss-cru";
 			reg = <0x0 0x07110000 0x0 0x10000>;
-- 
2.54.0


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

* Re: [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
  2026-09-07  3:34 ` [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration Jelly Jia
@ 2026-09-07 17:15   ` Conor Dooley
  2026-09-09  6:05     ` Jelly Jia
  0 siblings, 1 reply; 9+ messages in thread
From: Conor Dooley @ 2026-09-07 17:15 UTC (permalink / raw)
  To: Jelly Jia
  Cc: vkoul, robh, krzk+dt, conor+dt, devicetree, Frank.Li,
	robin.murphy, cix-kernel-upstream, dmaengine, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4692 bytes --]

On Mon, Sep 07, 2026 at 11:34:02AM +0800, Jelly Jia wrote:
> Document the CIX Sky1 integration wrapper around an Arm DMA-350 controller.
> 
> The wrapper owns SoC integration resources. The child node describes the
> generic Arm DMA-350 IP.
> 
> Signed-off-by: Jelly Jia <Jelly.Jia@cixtech.com>
> ---
>  .../bindings/dma/cix,sky1-dma350.yaml         | 102 ++++++++++++++++++
>  MAINTAINERS                                   |   1 +
>  2 files changed, 103 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
> 
> diff --git a/Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml b/Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
> new file mode 100644
> index 000000000000..e533f355d135
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
> @@ -0,0 +1,102 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/dma/cix,sky1-dma350.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: CIX Sky1 DMA-350 Integration
> +
> +maintainers:
> +  - CIX Kernel Team <cix-kernel-upstream@cixtech.com>
> +
> +description:
> +  The CIX Sky1 DMA-350 integration driver owns SoC resources around an
> +  Arm DMA-350 controller, such as clocks, resets, interrupt routing, and
> +  optional reserved memory. Reserved memory is described on this parent node
> +  and assigned by the integration driver to the child DMA-350 device. The child
> +  node describes the generic DMA-350 IP.

I cannot really speak to whether this is a correct thing to do with a
dma-350, but it seems to me like something that should be resolved with
a device specific comaptible in the dma-350 node. Someone more familar
with the IP will have to comment on that.

However I would like to know how this impacts the existing dma-350 in he
sky1 devicetree.

> +
> +properties:
> +  $nodename:
> +    pattern: "^dma@[0-9a-f]+$"
> +
> +  compatible:
> +    const: cix,sky1-dma350
> +
> +  "#address-cells":
> +    const: 2
> +
> +  "#size-cells":
> +    const: 2
> +
> +  ranges: true
> +
> +  dma-ranges: true
> +
> +  clocks:
> +    maxItems: 1
> +
> +  resets:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  cix,irq-router:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      Syscon phandle for the Sky1 subsystem register block that routes
> +      DMA-350 channel interrupts to the AP interrupt controller.
> +
> +  memory-region:
> +    maxItems: 1
> +    description:
> +      Reserved memory pool assigned by the CIX Sky1 DMA-350 integration driver
> +      to the child Arm DMA-350 device.
> +
> +patternProperties:
> +  '^dma-controller@[0-9a-f]+$':
> +    $ref: arm,dma-350.yaml#
> +
> +required:
> +  - compatible
> +  - "#address-cells"
> +  - "#size-cells"
> +  - ranges
> +  - dma-ranges
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    / {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +        interrupt-parent = <&gic>;
> +
> +        gic: interrupt-controller {
> +            #address-cells = <0>;
> +            interrupt-controller;
> +            #interrupt-cells = <4>;
> +        };
> +
> +        dma@7010000 {
> +            compatible = "cix,sky1-dma350";
> +            #address-cells = <2>;
> +            #size-cells = <2>;
> +            ranges = <0x0 0x0 0x0 0x07010000 0x0 0x10000>;
> +            dma-ranges = <0x0 0x20000000 0x0 0x07010000 0x0 0x00100000>;
> +            clocks = <&clk 9>;
> +            resets = <&rst 15>;
> +            cix,irq-router = <&audss_cru>;
> +
> +            dma-controller@0 {
> +                compatible = "arm,dma-350";
> +                reg = <0x0 0x0 0x0 0x10000>;
> +                interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH 0>;
> +                #dma-cells = <1>;
> +            };
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3a19da74d00c..feff8f9ecb2b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2825,6 +2825,7 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
>  S:	Maintained
>  T:	git https://github.com/cixtech/linux-mainline.git
>  F:	Documentation/devicetree/bindings/arm/cix.yaml
> +F:	Documentation/devicetree/bindings/dma/cix,sky1-dma350.yaml
>  F:	Documentation/devicetree/bindings/mailbox/cix,sky1-mbox.yaml
>  F:	arch/arm64/boot/dts/cix/
>  F:	drivers/mailbox/cix-mailbox.c
> -- 
> 2.54.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
  2026-09-07 17:15   ` Conor Dooley
@ 2026-09-09  6:05     ` Jelly Jia
  2026-09-09 10:45       ` Conor Dooley
  0 siblings, 1 reply; 9+ messages in thread
From: Jelly Jia @ 2026-09-09  6:05 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Jelly Jia, vkoul, robh, krzk+dt, conor+dt, devicetree, Frank.Li,
	robin.murphy, cix-kernel-upstream, dmaengine, linux-arm-kernel,
	linux-kernel

Hi Conor,

Thanks for the review.

> I cannot really speak to whether this is a correct thing to do with a
> dma-350, but it seems to me like something that should be resolved with
> a device specific comaptible in the dma-350 node. Someone more familar
> with the IP will have to comment on that.

The wrapper is there to keep the platform integration bits (clocks,
resets, interrupt routing) out of the generic driver: the arm-dma-350
child stays plain so the existing driver binds to it unchanged. I don't
know whether other dma350 integrations need the same resources, so I
did not want to push them into the generic node.

> However I would like to know how this impacts the existing dma-350 in he
> sky1 devicetree.

Patch 5 converts the existing FCH node to this form: the register window
and the eight GIC interrupts are unchanged, the arm-dma-350 controller
becomes the dma-controller@0 child, and the SCMI clock feeding the
instance is added. The AUDSS instance is new. I'll describe this
conversion in the patch 5 commit message in v2.

Best regards,
Jelly

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

* Re: [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
  2026-09-09  6:05     ` Jelly Jia
@ 2026-09-09 10:45       ` Conor Dooley
  0 siblings, 0 replies; 9+ messages in thread
From: Conor Dooley @ 2026-09-09 10:45 UTC (permalink / raw)
  To: Jelly Jia
  Cc: vkoul, robh, krzk+dt, conor+dt, devicetree, Frank.Li,
	robin.murphy, cix-kernel-upstream, dmaengine, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1481 bytes --]

On Wed, Sep 09, 2026 at 02:05:12PM +0800, Jelly Jia wrote:
> Hi Conor,
> 
> Thanks for the review.
> 
> > I cannot really speak to whether this is a correct thing to do with a
> > dma-350, but it seems to me like something that should be resolved with
> > a device specific comaptible in the dma-350 node. Someone more familar
> > with the IP will have to comment on that.
> 
> The wrapper is there to keep the platform integration bits (clocks,
> resets, interrupt routing) out of the generic driver: the arm-dma-350
> child stays plain so the existing driver binds to it unchanged. I don't
> know whether other dma350 integrations need the same resources, so I
> did not want to push them into the generic node.

Don't worry about this, given the limited extent of the wrapper driver,
at worst you will end up with a different probe function. The specific
compatible that you'll use will prevent the code relating to these
resources running on other platforms.

Thanks,
Conor.

> 
> > However I would like to know how this impacts the existing dma-350 in he
> > sky1 devicetree.
> 
> Patch 5 converts the existing FCH node to this form: the register window
> and the eight GIC interrupts are unchanged, the arm-dma-350 controller
> becomes the dma-controller@0 child, and the SCMI clock feeding the
> instance is added. The AUDSS instance is new. I'll describe this
> conversion in the patch 5 commit message in v2.
> 
> Best regards,
> Jelly

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

end of thread, other threads:[~2026-09-09 10:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-07  3:33 [PATCH v1 0/5] dmaengine: arm-dma350: Add slave support and CIX Sky1 integration Jelly Jia
2026-09-07  3:34 ` [PATCH v1 1/5] dmaengine: arm-dma350: Fix source trigger bit Jelly Jia
2026-09-07  3:34 ` [PATCH v1 2/5] dmaengine: arm-dma350: Add slave transfer support Jelly Jia
2026-09-07  3:34 ` [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration Jelly Jia
2026-09-07 17:15   ` Conor Dooley
2026-09-09  6:05     ` Jelly Jia
2026-09-09 10:45       ` Conor Dooley
2026-09-07  3:34 ` [PATCH v1 4/5] dmaengine: cix-sky1-dma350: Add Sky1 integration driver Jelly Jia
2026-09-07  3:34 ` [PATCH v1 5/5] arm64: dts: cix: Add Sky1 DMA-350 nodes Jelly Jia

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

all inboxes | Powered by JetHome®