[PATCH 3/9] dmaengine: bcm2835: Support controllers split across several nodes
Peter Robinson
pbrobinson at gmail.com
Mon Nov 2 01:06:53 PST 2026
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 at 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
More information about the linux-arm-kernel
mailing list