Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma
@ 2026-11-02  9:06 Peter Robinson
  2026-11-02  9:06 ` [PATCH 1/9] dt-bindings: dma: brcm,bcm2835-dma: Add BCM2711 and BCM2712 Peter Robinson
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

The upstream bcm2835-dma driver only handles the older BCM2835 SoCs
up to the Raspberry Pi 3. The later BCM2711/BCM2712 add extra channels
that support 40-bit DMA4 channels so add support so this works upstream.

The first patch updates the bindings, them patches 2-5 do some
refactoring and add the support for the newer SoCs.

Finally patches 6 and 7 add the nodes to the base device tree and
patches 8 and 9 enable it and configure HDMI audio to use them as
per the down stream device trees.

The series was assisted considerably by Claude Opus 5.5 based on the
various downstream Raspberry Pi patches and tested on a number of
RPi5B revC/D, RPi4B and a RPi3B+ all running Fedora 45. Checkpatch
and dtbs_check pass clean.

Peter Robinson (9):
  dt-bindings: dma: brcm,bcm2835-dma: Add BCM2711 and BCM2712
  dmaengine: bcm2835: Refactor control block handling
  dmaengine: bcm2835: Support controllers split across several nodes
  dmaengine: bcm2835: Add BCM2711 40-bit channel support
  dmaengine: bcm2835: Add BCM2712 support
  ARM: dts: bcm2711: Add 40-bit DMA controller
  ARM: dts: bcm2711-rpi: Use 40-bit DMA for HDMI audio
  arm64: dts: broadcom: bcm2712: Add DMA controllers
  arm64: dts: broadcom: bcm2712-rpi-5-b: Enable HDMI audio

 .../bindings/dma/brcm,bcm2835-dma.yaml        |  31 +-
 arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi   |   8 +
 arch/arm/boot/dts/broadcom/bcm2711.dtsi       |  16 +
 .../boot/dts/broadcom/bcm2712-d-rpi-5-b.dts   |   8 +
 .../dts/broadcom/bcm2712-rpi-5-b-base.dtsi    |  10 +
 arch/arm64/boot/dts/broadcom/bcm2712.dtsi     |  40 ++
 drivers/dma/bcm2835-dma.c                     | 496 +++++++++++++++---
 7 files changed, 534 insertions(+), 75 deletions(-)

-- 
2.56.0



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

* [PATCH 1/9] dt-bindings: dma: brcm,bcm2835-dma: Add BCM2711 and BCM2712
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 2/9] dmaengine: bcm2835: Refactor control block handling Peter Robinson
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson, Rob Herring, Krzysztof Kozlowski, Conor Dooley

Add compatibles for the BCM2711 40-bit DMA4 channels, which are
described by a separate node covering channels 11-14, and for the
BCM2712 DMA controllers. The register address of a node identifies its
first channel, allowing a controller to be split across nodes.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>

---
 .../bindings/dma/brcm,bcm2835-dma.yaml        | 31 +++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml
index c9b9a5490826c..31d97a10a0ea9 100644
--- a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml
+++ b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml
@@ -9,18 +9,27 @@ title: BCM2835 DMA controller
 maintainers:
   - Nicolas Saenz Julienne <nsaenz@kernel.org>
 
-description:
+description: |
   The BCM2835 DMA controller has 16 channels in total. Only the lower
   13 channels have an associated IRQ. Some arbitrary channels are used by the
   VideoCore firmware (1,3,6,7 in the current firmware version). The channels
   0, 2 and 3 have special functionality and should not be used by the driver.
 
+  BCM2711 channels 11 to 14 are 40-bit capable DMA4 channels, described by a
+  separate brcm,bcm2711-dma node. BCM2712 has 40-bit addressing on all
+  channels, with channels 6 to 11 being DMA4 channels. A controller may be
+  split across several nodes, the register address identifies the first
+  channel of a node.
+
 allOf:
   - $ref: dma-controller.yaml#
 
 properties:
   compatible:
-    const: brcm,bcm2835-dma
+    enum:
+      - brcm,bcm2835-dma
+      - brcm,bcm2711-dma
+      - brcm,bcm2712-dma
 
   reg:
     maxItems: 1
@@ -99,4 +108,22 @@ examples:
         brcm,dma-channel-mask = <0x7f35>;
     };
 
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    dma-controller@7e007b00 {
+      compatible = "brcm,bcm2711-dma";
+      reg = <0x7e007b00 0x400>;
+      interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-names = "dma11",
+                        "dma12",
+                        "dma13",
+                        "dma14";
+      #dma-cells = <1>;
+      brcm,dma-channel-mask = <0x7000>;
+    };
+
 ...
-- 
2.56.0



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

* [PATCH 2/9] dmaengine: bcm2835: Refactor control block handling
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
  2026-11-02  9:06 ` [PATCH 1/9] dt-bindings: dma: brcm,bcm2835-dma: Add BCM2711 and BCM2712 Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 3/9] dmaengine: bcm2835: Support controllers split across several nodes Peter Robinson
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

Access control blocks through small helpers and pass struct
bcm2835_chan to the internal chain builders, and add per-compatible
match data holding the DMA mask. This prepares for channels with a
different control block layout.

No functional change.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 drivers/dma/bcm2835-dma.c | 185 +++++++++++++++++++++++++++-----------
 1 file changed, 134 insertions(+), 51 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 06d830d368822..96a39eb24559f 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -37,17 +37,27 @@
 #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
 #define BCM2835_DMA_CHAN_NAME_SIZE 8
 
+/**
+ * struct bcm2835_dma_cfg - SoC specific controller properties
+ * @dma_mask: addressing capability of the controller
+ */
+struct bcm2835_dma_cfg {
+	u64 dma_mask;
+};
+
 /**
  * struct bcm2835_dmadev - BCM2835 DMA controller
  * @ddev: DMA device
  * @base: base address of register map
  * @zero_page: bus address of zero page (to detect transactions copying from
  *	zero page and avoid accessing memory if so)
+ * @cfg: SoC specific controller properties
  */
 struct bcm2835_dmadev {
 	struct dma_device ddev;
 	void __iomem *base;
 	dma_addr_t zero_page;
+	const struct bcm2835_dma_cfg *cfg;
 };
 
 struct bcm2835_dma_cb {
@@ -172,6 +182,10 @@ struct bcm2835_desc {
 #define MAX_DMA_LEN SZ_1G
 #define MAX_LITE_DMA_LEN (SZ_64K - 4)
 
+static const struct bcm2835_dma_cfg bcm2835_dma_cfg = {
+	.dma_mask = DMA_BIT_MASK(32),
+};
+
 static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
 {
 	/* lite and normal channels have different max frame length */
@@ -201,6 +215,76 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc(
 	return container_of(t, struct bcm2835_desc, vd.tx);
 }
 
+static void bcm2835_dma_cb_set_src(struct bcm2835_chan *c,
+				   struct bcm2835_cb_entry *e, dma_addr_t addr)
+{
+	e->cb->src = addr;
+}
+
+static void bcm2835_dma_cb_set_dst(struct bcm2835_chan *c,
+				   struct bcm2835_cb_entry *e, dma_addr_t addr)
+{
+	e->cb->dst = addr;
+}
+
+static void bcm2835_dma_cb_init(struct bcm2835_chan *c,
+				struct bcm2835_cb_entry *e, u32 info,
+				dma_addr_t src, dma_addr_t dst)
+{
+	struct bcm2835_dma_cb *cb = e->cb;
+
+	cb->info = info;
+	cb->length = 0;
+	cb->stride = 0;
+	cb->next = 0;
+
+	bcm2835_dma_cb_set_src(c, e, src);
+	bcm2835_dma_cb_set_dst(c, e, dst);
+}
+
+static u32 bcm2835_dma_cb_get_len(struct bcm2835_chan *c,
+				  struct bcm2835_cb_entry *e)
+{
+	return e->cb->length;
+}
+
+static void bcm2835_dma_cb_set_len(struct bcm2835_chan *c,
+				   struct bcm2835_cb_entry *e, u32 len)
+{
+	e->cb->length = len;
+}
+
+static void bcm2835_dma_cb_add_info(struct bcm2835_chan *c,
+				    struct bcm2835_cb_entry *e, u32 info)
+{
+	e->cb->info |= info;
+}
+
+static void bcm2835_dma_cb_set_next(struct bcm2835_chan *c,
+				    struct bcm2835_cb_entry *e,
+				    dma_addr_t next)
+{
+	e->cb->next = next;
+}
+
+/* Memory side address of a control block */
+static dma_addr_t bcm2835_dma_cb_mem_addr(struct bcm2835_chan *c,
+					  struct bcm2835_cb_entry *e,
+					  enum dma_transfer_direction dir)
+{
+	return dir == DMA_DEV_TO_MEM ? e->cb->dst : e->cb->src;
+}
+
+static dma_addr_t bcm2835_dma_get_pos(struct bcm2835_chan *c,
+				      enum dma_transfer_direction dir)
+{
+	void __iomem *base = c->chan_base;
+
+	if (dir == DMA_DEV_TO_MEM)
+		return readl(base + BCM2835_DMA_DEST_AD);
+	return readl(base + BCM2835_DMA_SOURCE_AD);
+}
+
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
 {
 	size_t i;
@@ -220,16 +304,18 @@ static void bcm2835_dma_desc_free(struct virt_dma_desc *vd)
 
 static void bcm2835_dma_create_cb_set_length(
 	struct bcm2835_chan *chan,
-	struct bcm2835_dma_cb *control_block,
+	struct bcm2835_cb_entry *cb_entry,
 	size_t len,
 	size_t period_len,
 	size_t *total_len,
 	u32 finalextrainfo)
 {
 	size_t max_len = bcm2835_dma_max_frame_length(chan);
+	u32 cb_len;
 
 	/* set the length taking lite-channel limitations into account */
-	control_block->length = min_t(u32, len, max_len);
+	cb_len = min_t(u32, len, max_len);
+	bcm2835_dma_cb_set_len(chan, cb_entry, cb_len);
 
 	/* finished if we have no period_length */
 	if (!period_len)
@@ -244,26 +330,26 @@ static void bcm2835_dma_create_cb_set_length(
 	 */
 
 	/* have we filled in period_length yet? */
-	if (*total_len + control_block->length < period_len) {
+	if (*total_len + cb_len < period_len) {
 		/* update number of bytes in this period so far */
-		*total_len += control_block->length;
+		*total_len += cb_len;
 		return;
 	}
 
 	/* calculate the length that remains to reach period_length */
-	control_block->length = period_len - *total_len;
+	bcm2835_dma_cb_set_len(chan, cb_entry, period_len - *total_len);
 
 	/* reset total_length for next period */
 	*total_len = 0;
 
 	/* add extrainfo bits in info */
-	control_block->info |= finalextrainfo;
+	bcm2835_dma_cb_add_info(chan, cb_entry, finalextrainfo);
 }
 
 /**
  * bcm2835_dma_create_cb_chain - create a control block and fills data in
  *
- * @chan:           the @dma_chan for which we run this
+ * @c:              the channel for which we run this
  * @direction:      the direction in which we transfer
  * @cyclic:         it is a cyclic transfer
  * @info:           the default info bits to apply per controlblock
@@ -281,17 +367,16 @@ static void bcm2835_dma_create_cb_set_length(
  * @gfp:            the GFP flag to use for allocation
  */
 static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
-	struct dma_chan *chan, enum dma_transfer_direction direction,
+	struct bcm2835_chan *c, enum dma_transfer_direction direction,
 	bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
 	dma_addr_t src, dma_addr_t dst, size_t buf_len,
 	size_t period_len, gfp_t gfp)
 {
-	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
 	size_t len = buf_len, total_len;
 	size_t frame;
 	struct bcm2835_desc *d;
 	struct bcm2835_cb_entry *cb_entry;
-	struct bcm2835_dma_cb *control_block;
+	u32 cb_len;
 
 	if (!frames)
 		return NULL;
@@ -317,40 +402,38 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
 			goto error_cb;
 
 		/* fill in the control block */
-		control_block = cb_entry->cb;
-		control_block->info = info;
-		control_block->src = src;
-		control_block->dst = dst;
-		control_block->stride = 0;
-		control_block->next = 0;
+		bcm2835_dma_cb_init(c, cb_entry, info, src, dst);
+
 		/* set up length in control_block if requested */
 		if (buf_len) {
 			/* calculate length honoring period_length */
 			bcm2835_dma_create_cb_set_length(
-				c, control_block,
+				c, cb_entry,
 				len, period_len, &total_len,
 				cyclic ? finalextrainfo : 0);
-
-			/* calculate new remaining length */
-			len -= control_block->length;
 		}
+		cb_len = bcm2835_dma_cb_get_len(c, cb_entry);
+
+		/* calculate new remaining length */
+		len -= cb_len;
 
 		/* link this the last controlblock */
 		if (frame)
-			d->cb_list[frame - 1].cb->next = cb_entry->paddr;
+			bcm2835_dma_cb_set_next(c, &d->cb_list[frame - 1],
+						cb_entry->paddr);
 
 		/* update src and dst and length */
 		if (src && (info & BCM2835_DMA_S_INC))
-			src += control_block->length;
+			src += cb_len;
 		if (dst && (info & BCM2835_DMA_D_INC))
-			dst += control_block->length;
+			dst += cb_len;
 
 		/* Length of total transfer */
-		d->size += control_block->length;
+		d->size += cb_len;
 	}
 
 	/* the last frame requires extra flags */
-	d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
+	bcm2835_dma_cb_add_info(c, &d->cb_list[d->frames - 1], finalextrainfo);
 
 	/* detect a size mismatch */
 	if (buf_len && (d->size != buf_len))
@@ -364,14 +447,13 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
 }
 
 static void bcm2835_dma_fill_cb_chain_with_sg(
-	struct dma_chan *chan,
+	struct bcm2835_chan *c,
 	enum dma_transfer_direction direction,
 	struct bcm2835_cb_entry *cb,
 	struct scatterlist *sgl,
 	unsigned int sg_len)
 {
-	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
-	size_t len, max_len;
+	size_t len, max_len, cb_len;
 	unsigned int i;
 	dma_addr_t addr;
 	struct scatterlist *sgent;
@@ -380,12 +462,13 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
 	for_each_sg(sgl, sgent, sg_len, i) {
 		for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
 		     len > 0;
-		     addr += cb->cb->length, len -= cb->cb->length, cb++) {
+		     addr += cb_len, len -= cb_len, cb++) {
 			if (direction == DMA_DEV_TO_MEM)
-				cb->cb->dst = addr;
+				bcm2835_dma_cb_set_dst(c, cb, addr);
 			else
-				cb->cb->src = addr;
-			cb->cb->length = min(len, max_len);
+				bcm2835_dma_cb_set_src(c, cb, addr);
+			cb_len = min(len, max_len);
+			bcm2835_dma_cb_set_len(c, cb, cb_len);
 		}
 	}
 }
@@ -524,14 +607,9 @@ static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr)
 	size_t size;
 
 	for (size = i = 0; i < d->frames; i++) {
-		struct bcm2835_dma_cb *control_block = d->cb_list[i].cb;
-		size_t this_size = control_block->length;
-		dma_addr_t dma;
-
-		if (d->dir == DMA_DEV_TO_MEM)
-			dma = control_block->dst;
-		else
-			dma = control_block->src;
+		struct bcm2835_cb_entry *e = &d->cb_list[i];
+		size_t this_size = bcm2835_dma_cb_get_len(d->c, e);
+		dma_addr_t dma = bcm2835_dma_cb_mem_addr(d->c, e, d->dir);
 
 		if (size)
 			size += this_size;
@@ -563,10 +641,8 @@ static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan,
 		struct bcm2835_desc *d = c->desc;
 		dma_addr_t pos;
 
-		if (d->dir == DMA_MEM_TO_DEV)
-			pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
-		else if (d->dir == DMA_DEV_TO_MEM)
-			pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
+		if (is_slave_direction(d->dir))
+			pos = bcm2835_dma_get_pos(c, d->dir);
 		else
 			pos = 0;
 
@@ -611,7 +687,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy(
 	frames = bcm2835_dma_frames_for_length(len, max_len);
 
 	/* allocate the CB chain - this also fills in the pointers */
-	d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false,
+	d = bcm2835_dma_create_cb_chain(c, DMA_MEM_TO_MEM, false,
 					info, extra, frames,
 					src, dst, len, 0, GFP_KERNEL);
 	if (!d)
@@ -658,7 +734,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg(
 	frames = sg_nents_for_dma(sgl, sg_len, bcm2835_dma_max_frame_length(c));
 
 	/* allocate the CB chain */
-	d = bcm2835_dma_create_cb_chain(chan, direction, false,
+	d = bcm2835_dma_create_cb_chain(c, direction, false,
 					info, extra,
 					frames, src, dst, 0, 0,
 					GFP_NOWAIT);
@@ -666,7 +742,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg(
 		return NULL;
 
 	/* fill in frames with scatterlist pointers */
-	bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
+	bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list,
 					  sgl, sg_len);
 
 	return vchan_tx_prep(&c->vc, &d->vd, flags);
@@ -745,7 +821,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
 	 * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine
 	 * implementation calls prep_dma_cyclic with interrupts disabled.
 	 */
-	d = bcm2835_dma_create_cb_chain(chan, direction, true,
+	d = bcm2835_dma_create_cb_chain(c, direction, true,
 					info, extra,
 					frames, src, dst, buf_len,
 					period_len, GFP_NOWAIT);
@@ -753,7 +829,8 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
 		return NULL;
 
 	/* wrap around into a loop */
-	d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
+	bcm2835_dma_cb_set_next(c, &d->cb_list[d->frames - 1],
+				d->cb_list[0].paddr);
 
 	return vchan_tx_prep(&c->vc, &d->vd, flags);
 }
@@ -837,7 +914,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
 }
 
 static const struct of_device_id bcm2835_dma_of_match[] = {
-	{ .compatible = "brcm,bcm2835-dma", },
+	{ .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
 	{},
 };
 MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
@@ -881,6 +958,7 @@ static const struct dev_pm_ops bcm2835_dma_pm_ops = {
 
 static int bcm2835_dma_probe(struct platform_device *pdev)
 {
+	const struct bcm2835_dma_cfg *cfg;
 	struct bcm2835_dmadev *od;
 	void __iomem *base;
 	int rc;
@@ -890,10 +968,14 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 	uint32_t chans_available;
 	char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
 
+	cfg = of_device_get_match_data(&pdev->dev);
+	if (!cfg)
+		return -EINVAL;
+
 	if (!pdev->dev.dma_mask)
 		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
 
-	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+	rc = dma_set_mask_and_coherent(&pdev->dev, cfg->dma_mask);
 	if (rc) {
 		dev_err(&pdev->dev, "Unable to set DMA mask\n");
 		return rc;
@@ -910,6 +992,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 		return PTR_ERR(base);
 
 	od->base = base;
+	od->cfg = cfg;
 
 	dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
 	dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask);
-- 
2.56.0



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

* [PATCH 3/9] dmaengine: bcm2835: Support controllers split across several nodes
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
  2026-11-02  9:06 ` [PATCH 1/9] dt-bindings: dma: brcm,bcm2835-dma: Add BCM2711 and BCM2712 Peter Robinson
  2026-11-02  9:06 ` [PATCH 2/9] dmaengine: bcm2835: Refactor control block handling Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 4/9] dmaengine: bcm2835: Add BCM2711 40-bit channel support Peter Robinson
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

Derive the index of the first channel from the register resource and
only probe the channels it covers, so a controller can be described by
several nodes. Initialise all IRQ slots, as the shared IRQ check scans
the whole array.

Existing device trees start at channel 0 and are unaffected.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 drivers/dma/bcm2835-dma.c | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 96a39eb24559f..83ad8815759e8 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -52,12 +52,14 @@ struct bcm2835_dma_cfg {
  * @zero_page: bus address of zero page (to detect transactions copying from
  *	zero page and avoid accessing memory if so)
  * @cfg: SoC specific controller properties
+ * @first_chan: hardware index of the first channel covered by @base
  */
 struct bcm2835_dmadev {
 	struct dma_device ddev;
 	void __iomem *base;
 	dma_addr_t zero_page;
 	const struct bcm2835_dma_cfg *cfg;
+	unsigned int first_chan;
 };
 
 struct bcm2835_dma_cb {
@@ -175,8 +177,8 @@ struct bcm2835_desc {
 #define BCM2835_DMA_DATA_TYPE_S128	16
 
 /* Valid only for channels 0 - 14, 15 has its own base address */
-#define BCM2835_DMA_CHAN(n)	((n) << 8) /* Base address */
-#define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
+#define BCM2835_DMA_CHAN_SIZE	0x100
+#define BCM2835_DMA_CHAN(n)	((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */
 
 /* the max dma length for different channels */
 #define MAX_DMA_LEN SZ_1G
@@ -886,7 +888,7 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id,
 	c->vc.desc_free = bcm2835_dma_desc_free;
 	vchan_init(&c->vc, &d->ddev);
 
-	c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id);
+	c->chan_base = d->base + BCM2835_DMA_CHAN(chan_id - d->first_chan);
 	c->ch = chan_id;
 	c->irq_number = irq;
 	c->irq_flags = irq_flags;
@@ -960,6 +962,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 {
 	const struct bcm2835_dma_cfg *cfg;
 	struct bcm2835_dmadev *od;
+	struct resource *res;
 	void __iomem *base;
 	int rc;
 	int i, j;
@@ -967,6 +970,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 	int irq_flags;
 	uint32_t chans_available;
 	char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
+	unsigned int chan_start, chan_end;
 
 	cfg = of_device_get_match_data(&pdev->dev);
 	if (!cfg)
@@ -987,12 +991,18 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 
 	dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
 
-	base = devm_platform_ioremap_resource(pdev, 0);
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
+	chan_start = (res->start / BCM2835_DMA_CHAN_SIZE) & 0xf;
+	chan_end = min_t(unsigned int,
+			 chan_start + resource_size(res) / BCM2835_DMA_CHAN_SIZE,
+			 BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1);
+
 	od->base = base;
 	od->cfg = cfg;
+	od->first_chan = chan_start;
 
 	dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
 	dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask);
@@ -1037,12 +1047,13 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 	}
 
 	/* get irqs for each channel that we support */
-	for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
+	for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++)
+		irq[i] = -1;
+
+	for (i = chan_start; i < chan_end; i++) {
 		/* skip masked out channels */
-		if (!(chans_available & (1 << i))) {
-			irq[i] = -1;
+		if (!(chans_available & (1 << i)))
 			continue;
-		}
 
 		/* get the named irq */
 		snprintf(chan_name, sizeof(chan_name), "dma%i", i);
@@ -1057,11 +1068,11 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 		 * in case of channel >= 11
 		 * use the 11th interrupt and that is shared
 		 */
-		irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
+		irq[i] = platform_get_irq(pdev, min(i - chan_start, 11U));
 	}
 
 	/* get irqs for each channel */
-	for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
+	for (i = chan_start; i < chan_end; i++) {
 		/* skip channels without irq */
 		if (irq[i] < 0)
 			continue;
@@ -1080,7 +1091,8 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
 			goto err_no_dma;
 	}
 
-	dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
+	dev_dbg(&pdev->dev, "Initialized DMA channels %u-%u\n", chan_start,
+		chan_end - 1);
 
 	/* Device-tree DMA controller registration */
 	rc = of_dma_controller_register(pdev->dev.of_node,
-- 
2.56.0



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

* [PATCH 4/9] dmaengine: bcm2835: Add BCM2711 40-bit channel support
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
                   ` (2 preceding siblings ...)
  2026-11-02  9:06 ` [PATCH 3/9] dmaengine: bcm2835: Support controllers split across several nodes Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 5/9] dmaengine: bcm2835: Add BCM2712 support Peter Robinson
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

BCM2711 channels 11-14 are DMA4 engines with a 40-bit capable register
and control block layout. They see the legacy 0x7c000000 peripheral
window at 0x4_7c000000, so translate client FIFO addresses accordingly.
Add the brcm,bcm2711-dma compatible for covering these channels.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 drivers/dma/bcm2835-dma.c | 278 +++++++++++++++++++++++++++++++++++---
 1 file changed, 256 insertions(+), 22 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 83ad8815759e8..35f8c47dea89f 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -17,6 +17,7 @@
  *	MARVELL MMP Peripheral DMA Driver
  *	Copyright 2012 Marvell International Ltd.
  */
+#include <linux/bitfield.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
@@ -40,9 +41,14 @@
 /**
  * struct bcm2835_dma_cfg - SoC specific controller properties
  * @dma_mask: addressing capability of the controller
+ * @chan_40bit_mask: channels implementing the BCM2711 40-bit register layout
+ * @periph_offset: offset at which channels with extended addressing see the
+ *	legacy 0x7c000000 - 0x7fffffff peripheral window
  */
 struct bcm2835_dma_cfg {
 	u64 dma_mask;
+	u32 chan_40bit_mask;
+	u64 periph_offset;
 };
 
 /**
@@ -72,8 +78,25 @@ struct bcm2835_dma_cb {
 	uint32_t pad[2];
 };
 
+/* Control block layout used by BCM2711 40-bit channels */
+struct bcm2711_dma40_cb {
+	u32 ti;
+	u32 src;
+	u32 srci;
+	u32 dst;
+	u32 dsti;
+	u32 len;
+	u32 next_cb;
+	u32 rsvd;
+};
+
+static_assert(sizeof(struct bcm2835_dma_cb) == sizeof(struct bcm2711_dma40_cb));
+
 struct bcm2835_cb_entry {
-	struct bcm2835_dma_cb *cb;
+	union {
+		struct bcm2835_dma_cb *cb;
+		struct bcm2711_dma40_cb *cb40;
+	};
 	dma_addr_t paddr;
 };
 
@@ -92,6 +115,9 @@ struct bcm2835_chan {
 	unsigned int irq_flags;
 
 	bool is_lite_channel;
+	bool is_40bit_channel;
+	bool ext_addr;
+	u64 periph_offset;
 };
 
 struct bcm2835_desc {
@@ -148,7 +174,9 @@ struct bcm2835_desc {
 #define BCM2835_DMA_S_WIDTH	BIT(9) /* 128bit writes if set */
 #define BCM2835_DMA_S_DREQ	BIT(10) /* enable SREQ for source */
 #define BCM2835_DMA_S_IGNORE	BIT(11) /* ignore source reads - read 0 */
+#define BCM2835_DMA_BURST_LENGTH_MASK	GENMASK(15, 12)
 #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12)
+#define BCM2835_DMA_PER_MAP_MASK	GENMASK(20, 16)
 #define BCM2835_DMA_PER_MAP(x)	((x & 31) << 16) /* REQ source */
 #define BCM2835_DMA_WAIT(x)	((x & 31) << 21) /* add DMA-wait cycles */
 #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */
@@ -184,10 +212,65 @@ struct bcm2835_desc {
 #define MAX_DMA_LEN SZ_1G
 #define MAX_LITE_DMA_LEN (SZ_64K - 4)
 
+/* Legacy peripheral bus window used by DMA clients for FIFO addresses */
+#define BCM2835_DMA_PERIPH_BASE		0x7c000000
+#define BCM2835_DMA_PERIPH_END		0x80000000
+
+/* BCM2711 40-bit channel registers */
+#define BCM2711_DMA40_CS	0x00
+#define BCM2711_DMA40_CB	0x04
+#define BCM2711_DMA40_DEBUG	0x0c
+#define BCM2711_DMA40_SRC	0x14
+#define BCM2711_DMA40_SRCI	0x18
+#define BCM2711_DMA40_DEST	0x1c
+#define BCM2711_DMA40_DESTI	0x20
+
+/* BCM2711 40-bit CS bits */
+#define BCM2711_DMA40_ACTIVE		BIT(0)
+#define BCM2711_DMA40_END		BIT(1)
+#define BCM2711_DMA40_INT		BIT(2)
+#define BCM2711_DMA40_DREQ		BIT(3)
+#define BCM2711_DMA40_RD_PAUSED		BIT(4)
+#define BCM2711_DMA40_WR_PAUSED		BIT(5)
+#define BCM2711_DMA40_DREQ_PAUSED	BIT(6)
+#define BCM2711_DMA40_WAITING_FOR_WRITES BIT(7)
+#define BCM2711_DMA40_PROT		GENMASK(9, 8) /* secure, supervisor */
+#define BCM2711_DMA40_ERR		BIT(10)
+#define BCM2711_DMA40_TRANSACTIONS	BIT(25)
+#define BCM2711_DMA40_WAIT_FOR_WRITES	BIT(28)
+#define BCM2711_DMA40_DISDEBUG		BIT(29)
+#define BCM2711_DMA40_ABORT		BIT(30)
+#define BCM2711_DMA40_HALT		BIT(31)
+
+/* BCM2711 40-bit TI bits */
+#define BCM2711_DMA40_INTEN		BIT(0)
+#define BCM2711_DMA40_TDMODE		BIT(1) /* 2D-Mode */
+#define BCM2711_DMA40_WAIT_RESP		BIT(2) /* wait for AXI write ack */
+#define BCM2711_DMA40_WAIT_RD_RESP	BIT(3) /* wait for AXI read to complete */
+#define BCM2711_DMA40_PER_MAP(x)	(((x) & 31) << 9) /* REQ source */
+#define BCM2711_DMA40_S_DREQ		BIT(14)
+#define BCM2711_DMA40_D_DREQ		BIT(15)
+
+/* BCM2711 40-bit SRCI/DESTI bits */
+#define BCM2711_DMA40_ADDR_HI		GENMASK(7, 0)
+#define BCM2711_DMA40_BURST_LEN(x)	(((x) & 15) << 8)
+#define BCM2711_DMA40_INC		BIT(12)
+#define BCM2711_DMA40_SIZE_128		FIELD_PREP_CONST(GENMASK(14, 13), 2)
+#define BCM2711_DMA40_IGNORE		BIT(15)
+
+/* BCM2711 40-bit DEBUG bits */
+#define BCM2711_DMA40_DEBUG_RESET		BIT(23)
+
 static const struct bcm2835_dma_cfg bcm2835_dma_cfg = {
 	.dma_mask = DMA_BIT_MASK(32),
 };
 
+static const struct bcm2835_dma_cfg bcm2711_dma_cfg = {
+	.dma_mask = DMA_BIT_MASK(36),
+	.chan_40bit_mask = GENMASK(14, 11),
+	.periph_offset = 0x400000000ULL,
+};
+
 static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
 {
 	/* lite and normal channels have different max frame length */
@@ -217,28 +300,95 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc(
 	return container_of(t, struct bcm2835_desc, vd.tx);
 }
 
+/* Translate legacy BCM2835 TI bits into the 40-bit channel TI format */
+static u32 bcm2711_dma40_ti(u32 info)
+{
+	u32 ti = BCM2711_DMA40_PER_MAP(FIELD_GET(BCM2835_DMA_PER_MAP_MASK, info));
+
+	if (info & BCM2835_DMA_INT_EN)
+		ti |= BCM2711_DMA40_INTEN;
+	if (info & BCM2835_DMA_WAIT_RESP)
+		ti |= BCM2711_DMA40_WAIT_RESP;
+	if (info & BCM2835_DMA_S_DREQ)
+		ti |= BCM2711_DMA40_S_DREQ | BCM2711_DMA40_WAIT_RD_RESP;
+	if (info & BCM2835_DMA_D_DREQ)
+		ti |= BCM2711_DMA40_D_DREQ;
+
+	return ti;
+}
+
+static u32 bcm2711_dma40_xi(u32 info, u32 inc, u32 width, u32 ignore)
+{
+	u32 xi = BCM2711_DMA40_BURST_LEN(FIELD_GET(BCM2835_DMA_BURST_LENGTH_MASK,
+						   info));
+
+	if (info & inc)
+		xi |= BCM2711_DMA40_INC;
+	if (info & width)
+		xi |= BCM2711_DMA40_SIZE_128;
+	if (info & ignore)
+		xi |= BCM2711_DMA40_IGNORE;
+
+	return xi;
+}
+
+/* Control block pointers of extended channels are 32 byte units */
+static u32 bcm2835_dma_cb_ptr(struct bcm2835_chan *c, dma_addr_t paddr)
+{
+	return c->ext_addr ? paddr >> 5 : paddr;
+}
+
 static void bcm2835_dma_cb_set_src(struct bcm2835_chan *c,
 				   struct bcm2835_cb_entry *e, dma_addr_t addr)
 {
-	e->cb->src = addr;
+	if (c->is_40bit_channel) {
+		e->cb40->src = lower_32_bits(addr);
+		FIELD_MODIFY(BCM2711_DMA40_ADDR_HI, &e->cb40->srci,
+			     upper_32_bits(addr));
+		return;
+	}
+
+	e->cb->src = lower_32_bits(addr);
 }
 
 static void bcm2835_dma_cb_set_dst(struct bcm2835_chan *c,
 				   struct bcm2835_cb_entry *e, dma_addr_t addr)
 {
-	e->cb->dst = addr;
+	if (c->is_40bit_channel) {
+		e->cb40->dst = lower_32_bits(addr);
+		FIELD_MODIFY(BCM2711_DMA40_ADDR_HI, &e->cb40->dsti,
+			     upper_32_bits(addr));
+		return;
+	}
+
+	e->cb->dst = lower_32_bits(addr);
 }
 
 static void bcm2835_dma_cb_init(struct bcm2835_chan *c,
 				struct bcm2835_cb_entry *e, u32 info,
 				dma_addr_t src, dma_addr_t dst)
 {
-	struct bcm2835_dma_cb *cb = e->cb;
+	if (c->is_40bit_channel) {
+		struct bcm2711_dma40_cb *cb = e->cb40;
+
+		cb->ti = bcm2711_dma40_ti(info);
+		cb->srci = bcm2711_dma40_xi(info, BCM2835_DMA_S_INC,
+					    BCM2835_DMA_S_WIDTH,
+					    BCM2835_DMA_S_IGNORE);
+		cb->dsti = bcm2711_dma40_xi(info, BCM2835_DMA_D_INC,
+					    BCM2835_DMA_D_WIDTH,
+					    BCM2835_DMA_D_IGNORE);
+		cb->len = 0;
+		cb->next_cb = 0;
+		cb->rsvd = 0;
+	} else {
+		struct bcm2835_dma_cb *cb = e->cb;
 
-	cb->info = info;
-	cb->length = 0;
-	cb->stride = 0;
-	cb->next = 0;
+		cb->info = info;
+		cb->length = 0;
+		cb->stride = 0;
+		cb->next = 0;
+	}
 
 	bcm2835_dma_cb_set_src(c, e, src);
 	bcm2835_dma_cb_set_dst(c, e, dst);
@@ -247,26 +397,40 @@ static void bcm2835_dma_cb_init(struct bcm2835_chan *c,
 static u32 bcm2835_dma_cb_get_len(struct bcm2835_chan *c,
 				  struct bcm2835_cb_entry *e)
 {
-	return e->cb->length;
+	return c->is_40bit_channel ? e->cb40->len : e->cb->length;
 }
 
 static void bcm2835_dma_cb_set_len(struct bcm2835_chan *c,
 				   struct bcm2835_cb_entry *e, u32 len)
 {
-	e->cb->length = len;
+	if (c->is_40bit_channel)
+		e->cb40->len = len;
+	else
+		e->cb->length = len;
 }
 
 static void bcm2835_dma_cb_add_info(struct bcm2835_chan *c,
 				    struct bcm2835_cb_entry *e, u32 info)
 {
-	e->cb->info |= info;
+	if (c->is_40bit_channel)
+		e->cb40->ti |= bcm2711_dma40_ti(info);
+	else
+		e->cb->info |= info;
 }
 
 static void bcm2835_dma_cb_set_next(struct bcm2835_chan *c,
 				    struct bcm2835_cb_entry *e,
 				    dma_addr_t next)
 {
-	e->cb->next = next;
+	if (c->is_40bit_channel)
+		e->cb40->next_cb = bcm2835_dma_cb_ptr(c, next);
+	else
+		e->cb->next = bcm2835_dma_cb_ptr(c, next);
+}
+
+static dma_addr_t bcm2711_dma40_addr(u32 lo, u32 xi)
+{
+	return (u64)FIELD_GET(BCM2711_DMA40_ADDR_HI, xi) << 32 | lo;
 }
 
 /* Memory side address of a control block */
@@ -274,6 +438,12 @@ static dma_addr_t bcm2835_dma_cb_mem_addr(struct bcm2835_chan *c,
 					  struct bcm2835_cb_entry *e,
 					  enum dma_transfer_direction dir)
 {
+	if (c->is_40bit_channel) {
+		if (dir == DMA_DEV_TO_MEM)
+			return bcm2711_dma40_addr(e->cb40->dst, e->cb40->dsti);
+		return bcm2711_dma40_addr(e->cb40->src, e->cb40->srci);
+	}
+
 	return dir == DMA_DEV_TO_MEM ? e->cb->dst : e->cb->src;
 }
 
@@ -282,11 +452,32 @@ static dma_addr_t bcm2835_dma_get_pos(struct bcm2835_chan *c,
 {
 	void __iomem *base = c->chan_base;
 
+	if (c->is_40bit_channel) {
+		if (dir == DMA_DEV_TO_MEM)
+			return bcm2711_dma40_addr(readl(base + BCM2711_DMA40_DEST),
+						  readl(base + BCM2711_DMA40_DESTI));
+		return bcm2711_dma40_addr(readl(base + BCM2711_DMA40_SRC),
+					  readl(base + BCM2711_DMA40_SRCI));
+	}
+
 	if (dir == DMA_DEV_TO_MEM)
 		return readl(base + BCM2835_DMA_DEST_AD);
 	return readl(base + BCM2835_DMA_SOURCE_AD);
 }
 
+/*
+ * Clients describe peripheral FIFOs by their legacy bus address. Channels
+ * with extended addressing see that window at a SoC specific offset.
+ */
+static dma_addr_t bcm2835_dma_periph_addr(struct bcm2835_chan *c,
+					  dma_addr_t addr)
+{
+	if (addr >= BCM2835_DMA_PERIPH_BASE && addr < BCM2835_DMA_PERIPH_END)
+		addr += c->periph_offset;
+
+	return addr;
+}
+
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
 {
 	size_t i;
@@ -475,6 +666,27 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
 	}
 }
 
+static void bcm2711_dma40_abort(struct bcm2835_chan *c)
+{
+	void __iomem *chan_base = c->chan_base;
+	long timeout = 10000;
+
+	writel(readl(chan_base + BCM2711_DMA40_CS) & ~BCM2711_DMA40_ACTIVE,
+	       chan_base + BCM2711_DMA40_CS);
+
+	while ((readl(chan_base + BCM2711_DMA40_CS) &
+		BCM2711_DMA40_TRANSACTIONS) && --timeout)
+		cpu_relax();
+
+	if (!timeout)
+		dev_err(c->vc.chan.device->dev,
+			"failed to complete outstanding transactions\n");
+
+	writel(BCM2711_DMA40_PROT, chan_base + BCM2711_DMA40_CS);
+	writel(readl(chan_base + BCM2711_DMA40_DEBUG) | BCM2711_DMA40_DEBUG_RESET,
+	       chan_base + BCM2711_DMA40_DEBUG);
+}
+
 static void bcm2835_dma_abort(struct bcm2835_chan *c)
 {
 	void __iomem *chan_base = c->chan_base;
@@ -483,10 +695,16 @@ static void bcm2835_dma_abort(struct bcm2835_chan *c)
 	/*
 	 * A zero control block address means the channel is idle.
 	 * (The ACTIVE flag in the CS register is not a reliable indicator.)
+	 * The CB register of 40-bit channels is at the same offset.
 	 */
 	if (!readl(chan_base + BCM2835_DMA_ADDR))
 		return;
 
+	if (c->is_40bit_channel) {
+		bcm2711_dma40_abort(c);
+		return;
+	}
+
 	/* Write 0 to the active bit - Pause the DMA */
 	writel(0, chan_base + BCM2835_DMA_CS);
 
@@ -517,8 +735,13 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
 
 	c->desc = d = to_bcm2835_dma_desc(&vd->tx);
 
-	writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-	writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
+	writel(bcm2835_dma_cb_ptr(c, d->cb_list[0].paddr),
+	       c->chan_base + BCM2835_DMA_ADDR);
+	if (c->is_40bit_channel)
+		writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT,
+		       c->chan_base + BCM2711_DMA40_CS);
+	else
+		writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
 }
 
 static irqreturn_t bcm2835_dma_callback(int irq, void *data)
@@ -545,8 +768,12 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
 	 * if this IRQ handler is threaded.) If the channel is finished, it
 	 * will remain idle despite the ACTIVE flag being set.
 	 */
-	writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE,
-	       c->chan_base + BCM2835_DMA_CS);
+	if (c->is_40bit_channel)
+		writel(BCM2711_DMA40_INT | BCM2711_DMA40_ACTIVE |
+		       BCM2711_DMA40_PROT, c->chan_base + BCM2711_DMA40_CS);
+	else
+		writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE,
+		       c->chan_base + BCM2835_DMA_CS);
 
 	d = c->desc;
 
@@ -723,12 +950,12 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg(
 	if (direction == DMA_DEV_TO_MEM) {
 		if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
-		src = c->cfg.src_addr;
+		src = bcm2835_dma_periph_addr(c, c->cfg.src_addr);
 		info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
 	} else {
 		if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
-		dst = c->cfg.dst_addr;
+		dst = bcm2835_dma_periph_addr(c, c->cfg.dst_addr);
 		info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
 	}
 
@@ -797,13 +1024,13 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
 	if (direction == DMA_DEV_TO_MEM) {
 		if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
-		src = c->cfg.src_addr;
+		src = bcm2835_dma_periph_addr(c, c->cfg.src_addr);
 		dst = buf_addr;
 		info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
 	} else {
 		if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
 			return NULL;
-		dst = c->cfg.dst_addr;
+		dst = bcm2835_dma_periph_addr(c, c->cfg.dst_addr);
 		src = buf_addr;
 		info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
 
@@ -893,11 +1120,17 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id,
 	c->irq_number = irq;
 	c->irq_flags = irq_flags;
 
+	if (d->cfg->chan_40bit_mask & BIT(chan_id))
+		c->is_40bit_channel = true;
 	/* check in DEBUG register if this is a LITE channel */
-	if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-		BCM2835_DMA_DEBUG_LITE)
+	else if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
+		 BCM2835_DMA_DEBUG_LITE)
 		c->is_lite_channel = true;
 
+	c->ext_addr = c->is_40bit_channel;
+	if (c->ext_addr)
+		c->periph_offset = d->cfg->periph_offset;
+
 	return 0;
 }
 
@@ -917,6 +1150,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
 
 static const struct of_device_id bcm2835_dma_of_match[] = {
 	{ .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
+	{ .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg },
 	{},
 };
 MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-- 
2.56.0



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

* [PATCH 5/9] dmaengine: bcm2835: Add BCM2712 support
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
                   ` (3 preceding siblings ...)
  2026-11-02  9:06 ` [PATCH 4/9] dmaengine: bcm2835: Add BCM2711 40-bit channel support Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 6/9] ARM: dts: bcm2711: Add 40-bit DMA controller Peter Robinson
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

BCM2712 legacy layout channels carry address bits [39:32] in the
STRIDE field and use 32-byte units for control block pointers.
Channels 6-11 are DMA4 engines. Peripherals are seen at 0x10_7c000000.
Add the brcm,bcm2712-dma compatible with a 40-bit DMA mask.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 drivers/dma/bcm2835-dma.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 35f8c47dea89f..f06609b04a098 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -44,11 +44,14 @@
  * @chan_40bit_mask: channels implementing the BCM2711 40-bit register layout
  * @periph_offset: offset at which channels with extended addressing see the
  *	legacy 0x7c000000 - 0x7fffffff peripheral window
+ * @ext_addr: legacy layout channels carry address bits [39:32] in the STRIDE
+ *	field and control block pointers are stored right-shifted by 5
  */
 struct bcm2835_dma_cfg {
 	u64 dma_mask;
 	u32 chan_40bit_mask;
 	u64 periph_offset;
+	bool ext_addr;
 };
 
 /**
@@ -212,6 +215,10 @@ struct bcm2835_desc {
 #define MAX_DMA_LEN SZ_1G
 #define MAX_LITE_DMA_LEN (SZ_64K - 4)
 
+/* BCM2712 legacy layout channels: address bits [39:32] in the STRIDE field */
+#define BCM2712_DMA_STRIDE_SRC_HI	GENMASK(7, 0)
+#define BCM2712_DMA_STRIDE_DST_HI	GENMASK(15, 8)
+
 /* Legacy peripheral bus window used by DMA clients for FIFO addresses */
 #define BCM2835_DMA_PERIPH_BASE		0x7c000000
 #define BCM2835_DMA_PERIPH_END		0x80000000
@@ -271,6 +278,13 @@ static const struct bcm2835_dma_cfg bcm2711_dma_cfg = {
 	.periph_offset = 0x400000000ULL,
 };
 
+static const struct bcm2835_dma_cfg bcm2712_dma_cfg = {
+	.dma_mask = DMA_BIT_MASK(40),
+	.chan_40bit_mask = GENMASK(11, 6),
+	.periph_offset = 0x1000000000ULL,
+	.ext_addr = true,
+};
+
 static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
 {
 	/* lite and normal channels have different max frame length */
@@ -349,6 +363,9 @@ static void bcm2835_dma_cb_set_src(struct bcm2835_chan *c,
 	}
 
 	e->cb->src = lower_32_bits(addr);
+	if (c->ext_addr)
+		FIELD_MODIFY(BCM2712_DMA_STRIDE_SRC_HI, &e->cb->stride,
+			     upper_32_bits(addr));
 }
 
 static void bcm2835_dma_cb_set_dst(struct bcm2835_chan *c,
@@ -362,6 +379,9 @@ static void bcm2835_dma_cb_set_dst(struct bcm2835_chan *c,
 	}
 
 	e->cb->dst = lower_32_bits(addr);
+	if (c->ext_addr)
+		FIELD_MODIFY(BCM2712_DMA_STRIDE_DST_HI, &e->cb->stride,
+			     upper_32_bits(addr));
 }
 
 static void bcm2835_dma_cb_init(struct bcm2835_chan *c,
@@ -1127,7 +1147,7 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id,
 		 BCM2835_DMA_DEBUG_LITE)
 		c->is_lite_channel = true;
 
-	c->ext_addr = c->is_40bit_channel;
+	c->ext_addr = c->is_40bit_channel || d->cfg->ext_addr;
 	if (c->ext_addr)
 		c->periph_offset = d->cfg->periph_offset;
 
@@ -1151,6 +1171,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
 static const struct of_device_id bcm2835_dma_of_match[] = {
 	{ .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
 	{ .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg },
+	{ .compatible = "brcm,bcm2712-dma", .data = &bcm2712_dma_cfg },
 	{},
 };
 MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-- 
2.56.0



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

* [PATCH 6/9] ARM: dts: bcm2711: Add 40-bit DMA controller
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
                   ` (4 preceding siblings ...)
  2026-11-02  9:06 ` [PATCH 5/9] dmaengine: bcm2835: Add BCM2712 support Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 7/9] ARM: dts: bcm2711-rpi: Use 40-bit DMA for HDMI audio Peter Robinson
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

Describe the four DMA4 channels (11-14) of BCM2711. They sit
on the SCB so they can reach all of memory.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 arch/arm/boot/dts/broadcom/bcm2711.dtsi | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
index 5e3b4bb393967..9d70bea17b11c 100644
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -602,6 +602,22 @@ genet_mdio: mdio@e14 {
 			};
 		};
 
+		dma40: dma-controller@7e007b00 {
+			compatible = "brcm,bcm2711-dma";
+			reg = <0x0 0x7e007b00 0x400>;
+			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
+				     <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
+				     <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
+				     <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
+			interrupt-names = "dma11",
+					  "dma12",
+					  "dma13",
+					  "dma14";
+			#dma-cells = <1>;
+			brcm,dma-channel-mask = <0x7800>;
+			status = "disabled";
+		};
+
 		xhci: usb@7e9c0000 {
 			compatible = "brcm,bcm2711-xhci", "brcm,xhci-brcm-v2";
 			reg = <0x0 0x7e9c0000 0x100000>;
-- 
2.56.0



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

* [PATCH 7/9] ARM: dts: bcm2711-rpi: Use 40-bit DMA for HDMI audio
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
                   ` (5 preceding siblings ...)
  2026-11-02  9:06 ` [PATCH 6/9] ARM: dts: bcm2711: Add 40-bit DMA controller Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 8/9] arm64: dts: broadcom: bcm2712: Add DMA controllers Peter Robinson
  2026-11-02  9:06 ` [PATCH 9/9] arm64: dts: broadcom: bcm2712-rpi-5-b: Enable HDMI audio Peter Robinson
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

Enable the dma40 controller on the Raspberry Pi 4, ch 11
is reserved for the VPU firmware for VCHIQ communication,
and add the DMA channels for HDMI audio.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
index 1eb6406449d19..a49a732d3f64e 100644
--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
@@ -42,6 +42,12 @@ i2c0_1: i2c@1 {
 	};
 };
 
+&dma40 {
+	/* The VPU firmware uses DMA channel 11 for VCHIQ */
+	brcm,dma-channel-mask = <0x7000>;
+	status = "okay";
+};
+
 &firmware {
 	expgpio: gpio {
 		compatible = "raspberrypi,firmware-gpio";
@@ -59,12 +65,14 @@ reset: reset {
 &hdmi0 {
 	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
 	clock-names = "hdmi", "bvb", "audio", "cec";
+	dmas = <&dma40 10>;
 	wifi-2.4ghz-coexistence;
 };
 
 &hdmi1 {
 	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
 	clock-names = "hdmi", "bvb", "audio", "cec";
+	dmas = <&dma40 17>;
 	wifi-2.4ghz-coexistence;
 };
 
-- 
2.56.0



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

* [PATCH 8/9] arm64: dts: broadcom: bcm2712: Add DMA controllers
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
                   ` (6 preceding siblings ...)
  2026-11-02  9:06 ` [PATCH 7/9] ARM: dts: bcm2711-rpi: Use 40-bit DMA for HDMI audio Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  2026-11-02  9:06 ` [PATCH 9/9] arm64: dts: broadcom: bcm2712-rpi-5-b: Enable HDMI audio Peter Robinson
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

Describe the BCM2712 legacy DMA channels (0-5) and the DMA4
channels (6-11) as separate nodes, both disabled for boards
to enable. Node labels follow the Raspberry Pi downstream tree.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 40 +++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
index edae2f3584a8d..be4e94c9e7695 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
@@ -546,6 +546,46 @@ axi: axi {
 			     <0x18 0x00000000  0x18 0x00000000  0x04 0x00000000>,
 			     <0x1c 0x00000000  0x1c 0x00000000  0x04 0x00000000>;
 
+		dma32: dma-controller@1000010000 {
+			compatible = "brcm,bcm2712-dma";
+			reg = <0x10 0x00010000 0x0 0x600>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "dma0",
+					  "dma1",
+					  "dma2",
+					  "dma3",
+					  "dma4",
+					  "dma5";
+			#dma-cells = <1>;
+			brcm,dma-channel-mask = <0x0035>;
+			status = "disabled";
+		};
+
+		dma40: dma-controller@1000010600 {
+			compatible = "brcm,bcm2712-dma";
+			reg = <0x10 0x00010600 0x0 0x600>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>, /* dma4 6 */
+				     <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dma4 7 */
+				     <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dma4 8 */
+				     <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 9 */
+				     <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 10 */
+				     <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; /* dma4 11 */
+			interrupt-names = "dma6",
+					  "dma7",
+					  "dma8",
+					  "dma9",
+					  "dma10",
+					  "dma11";
+			#dma-cells = <1>;
+			brcm,dma-channel-mask = <0x0fc0>;
+			status = "disabled";
+		};
+
 		pcie0: pcie@1000100000 {
 			compatible = "brcm,bcm2712-pcie";
 			reg = <0x10 0x00100000 0x00 0x9310>;
-- 
2.56.0



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

* [PATCH 9/9] arm64: dts: broadcom: bcm2712-rpi-5-b: Enable HDMI audio
  2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
                   ` (7 preceding siblings ...)
  2026-11-02  9:06 ` [PATCH 8/9] arm64: dts: broadcom: bcm2712: Add DMA controllers Peter Robinson
@ 2026-11-02  9:06 ` Peter Robinson
  8 siblings, 0 replies; 10+ messages in thread
From: Peter Robinson @ 2026-11-02  9:06 UTC (permalink / raw)
  To: Florian Fainelli, Dave Stevenson, Ray Jui, Scott Branden,
	Vinod Koul, Frank Li, dmaengine, devicetree, linux-rpi-kernel,
	linux-arm-kernel, bcm-kernel-feedback-list
  Cc: Peter Robinson

Enable the DMA4 controller, excluding channel 11 which the VPU
firmware uses for VCHIQ, and hook up HDMI audio to it. The D0
stepping uses different DREQ lines for the HDMI controllers.
DREQ numbers and channel mask match Raspberry Pi downstream.

Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
 arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts     |  8 ++++++++
 arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi | 10 ++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
index ae4b7c587dbc5..3322862906f62 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-d-rpi-5-b.dts
@@ -51,6 +51,14 @@ &pinctrl_aon {
 	reg = <0x7d510700 0x1c>;
 };
 
+&hdmi0 {
+	dmas = <&dma40 12>;
+};
+
+&hdmi1 {
+	dmas = <&dma40 13>;
+};
+
 &uart10 {
 	interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
 };
diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi
index e5030da60f9e7..3b55840414975 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b-base.dtsi
@@ -117,6 +117,12 @@ &disp_intr {
 	status = "okay";
 };
 
+&dma40 {
+	/* The VPU firmware uses DMA channel 11 for VCHIQ */
+	brcm,dma-channel-mask = <0x07c0>;
+	status = "okay";
+};
+
 &pinctrl {
 	bt_shutdown_default: bt-shutdown-default-state {
 		function = "gpio";
@@ -254,12 +260,16 @@ &hvs {
 &hdmi0 {
 	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>;
 	clock-names = "hdmi", "bvb", "audio", "cec";
+	dmas = <&dma40 10>;
+	dma-names = "audio-rx";
 	status = "okay";
 };
 
 &hdmi1 {
 	clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
 	clock-names = "hdmi", "bvb", "audio", "cec";
+	dmas = <&dma40 17>;
+	dma-names = "audio-rx";
 	status = "okay";
 };
 
-- 
2.56.0



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

end of thread, other threads:[~2026-11-02  9:38 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02  9:06 [PATCH 0/9] dma: Add BCM2711 and BCM2712 support to bcm2835-dma Peter Robinson
2026-11-02  9:06 ` [PATCH 1/9] dt-bindings: dma: brcm,bcm2835-dma: Add BCM2711 and BCM2712 Peter Robinson
2026-11-02  9:06 ` [PATCH 2/9] dmaengine: bcm2835: Refactor control block handling Peter Robinson
2026-11-02  9:06 ` [PATCH 3/9] dmaengine: bcm2835: Support controllers split across several nodes Peter Robinson
2026-11-02  9:06 ` [PATCH 4/9] dmaengine: bcm2835: Add BCM2711 40-bit channel support Peter Robinson
2026-11-02  9:06 ` [PATCH 5/9] dmaengine: bcm2835: Add BCM2712 support Peter Robinson
2026-11-02  9:06 ` [PATCH 6/9] ARM: dts: bcm2711: Add 40-bit DMA controller Peter Robinson
2026-11-02  9:06 ` [PATCH 7/9] ARM: dts: bcm2711-rpi: Use 40-bit DMA for HDMI audio Peter Robinson
2026-11-02  9:06 ` [PATCH 8/9] arm64: dts: broadcom: bcm2712: Add DMA controllers Peter Robinson
2026-11-02  9:06 ` [PATCH 9/9] arm64: dts: broadcom: bcm2712-rpi-5-b: Enable HDMI audio Peter Robinson

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