* [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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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
2026-09-20 5:15 ` Jelly Jia
0 siblings, 1 reply; 12+ 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] 12+ messages in thread
* Re: [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
2026-09-09 10:45 ` Conor Dooley
@ 2026-09-20 5:15 ` Jelly Jia
2026-09-22 17:04 ` Conor Dooley
0 siblings, 1 reply; 12+ messages in thread
From: Jelly Jia @ 2026-09-20 5:15 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, understood: with the SoC-specific compatible scoping the
integration code, other platforms are unaffected either way.
For v2 my preference is to keep the wrapper, since it leaves the
generic arm-dma350 driver and its binding untouched. Does that work
for you, or would you rather see the dma-350 node itself carry a
device-specific compatible, with the clocks, resets and
memory-region described on it? I'd also like Robin's take on the
arm-dma350 side before restructuring that far.
Best regards,
Jelly
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
2026-09-20 5:15 ` Jelly Jia
@ 2026-09-22 17:04 ` Conor Dooley
2026-09-23 8:34 ` Krzysztof Kozlowski
0 siblings, 1 reply; 12+ messages in thread
From: Conor Dooley @ 2026-09-22 17:04 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: 843 bytes --]
On Sun, Sep 20, 2026 at 01:15:01PM +0800, Jelly Jia wrote:
> Hi Conor,
>
> Thanks, understood: with the SoC-specific compatible scoping the
> integration code, other platforms are unaffected either way.
>
> For v2 my preference is to keep the wrapper, since it leaves the
> generic arm-dma350 driver and its binding untouched. Does that work
> for you, or would you rather see the dma-350 node itself carry a
> device-specific compatible, with the clocks, resets and
> memory-region described on it? I'd also like Robin's take on the
> arm-dma350 side before restructuring that far.
The latter, since that's what we do for almost every other device under
the sun. Robin's take would probably be worth hearing, but you removed
all the context while replying which makes that more difficult...
>
> Best regards,
> Jelly
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 3/5] dt-bindings: dma: Add CIX Sky1 DMA-350 integration
2026-09-22 17:04 ` Conor Dooley
@ 2026-09-23 8:34 ` Krzysztof Kozlowski
0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-23 8:34 UTC (permalink / raw)
To: Conor Dooley, Jelly Jia
Cc: vkoul, robh, krzk+dt, conor+dt, devicetree, Frank.Li,
robin.murphy, cix-kernel-upstream, dmaengine, linux-arm-kernel,
linux-kernel
On 22/09/2026 19:04, Conor Dooley wrote:
> On Sun, Sep 20, 2026 at 01:15:01PM +0800, Jelly Jia wrote:
>> Hi Conor,
>>
>> Thanks, understood: with the SoC-specific compatible scoping the
>> integration code, other platforms are unaffected either way.
>>
>> For v2 my preference is to keep the wrapper, since it leaves the
>> generic arm-dma350 driver and its binding untouched. Does that work
>> for you, or would you rather see the dma-350 node itself carry a
>> device-specific compatible, with the clocks, resets and
>> memory-region described on it? I'd also like Robin's take on the
>> arm-dma350 side before restructuring that far.
>
> The latter, since that's what we do for almost every other device under
> the sun. Robin's take would probably be worth hearing, but you removed
> all the context while replying which makes that more difficult...
Following DWC USB example, I think wrappers are discouraged. The
integration of a block is together with that block an entire device.
Integration is not something separate, at least usually. If it is,
author should provide some arguments in terms of hardware. The arguments
of driver are unconvincing.
And to prove this is same device (integration = block), the MMIO is the
same.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-23 8:34 UTC | newest]
Thread overview: 12+ 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-20 5:15 ` Jelly Jia
2026-09-22 17:04 ` Conor Dooley
2026-09-23 8:34 ` Krzysztof Kozlowski
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®