[PATCH v2 4/4] dma: dw-axi-dmac: Add support for Agilex5 and dynamic bus width

Khairul Anuar Romli
2025-12-08T01:58:06Z

Add device tree compatible string support for the Altera Agilex5 AXI DMA
controller.

Introduces logic to parse the "dma-ranges" property and calculate the
actual number of addressable bits (bus width) for the DMA engine. This
calculated value is then used to set the coherent mask via
'dma_set_mask_and_coherent()', allowing the driver to correctly handle
devices with bus widths less than 64 bits. The addressable bits default to
64 if 'dma-ranges' is not specified or cannot be parsed.

Introduce 'addressable_bits' to 'struct axi_dma_chip' to store this value.

Signed-off-by: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
---
Changes in v2:
- Add driver implementation to set the DMA BIT MAST to 40 based on
dma-ranges defined in DT.
- Add glue for driver and DT.
---
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 63 ++++++++++++++++++-
drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 +
2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index b23536645ff7..165481b4dde1 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -271,7 +271,9 @@ static void axi_dma_hw_init(struct axi_dma_chip *chip)
axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL);
axi_chan_disable(&chip->dw->chan[i]);
}
- ret = dma_set_mask_and_coherent(chip->dev, DMA_BIT_MASK(64));
+
+ dev_dbg(chip->dev, "Adressable bus width: %u\n", chip->addressable_bits);
+ ret = dma_set_mask_and_coherent(chip->dev, DMA_BIT_MASK(chip->addressable_bits));
if (ret)
dev_warn(chip->dev, "Unable to set coherent mask\n");
}
@@ -1461,13 +1463,23 @@ static int axi_req_irqs(struct platform_device *pdev, struct axi_dma_chip *chip)
return 0;
}

+/* Forward declaration (no size required) */
+static const struct of_device_id dw_dma_of_id_table[];
+
static int dw_probe(struct platform_device *pdev)
{
struct axi_dma_chip *chip;
struct dw_axi_dma *dw;
struct dw_axi_dma_hcfg *hdata;
struct reset_control *resets;
+ const struct of_device_id *match;
unsigned int flags;
+ unsigned int addressable_bits = 64;
+ unsigned int len_bytes;
+ unsigned int num_cells;
+ const __be32 *prop;
+ u64 bus_width;
+ u32 *cells;
u32 i;
int ret;

@@ -1483,9 +1495,56 @@ static int dw_probe(struct platform_device *pdev)
if (!hdata)
return -ENOMEM;

+ match = of_match_node(dw_dma_of_id_table, pdev->dev.of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "Unsupported AXI DMA device\n");
+ return -ENODEV;
+ }
+
+ prop = of_get_property(pdev->dev.of_node, "dma-ranges", &len_bytes);
+ if (prop) {
+ num_cells = len_bytes / sizeof(__be32);
+ cells = kcalloc(num_cells, sizeof(*cells), GFP_KERNEL);
+ if (!cells)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "#address-cells", &i);
+ if (ret) {
+ dev_err(&pdev->dev, "missing #address-cells property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, "#size-cells", &i);
+ if (ret) {
+ dev_err(&pdev->dev, "missing #size-cells property\n");
+ return ret;
+ }
+
+ if (!of_property_read_u32_array(pdev->dev.of_node,
+ "dma-ranges", cells, num_cells)) {
+ dev_dbg(&pdev->dev, "dma-ranges numbe of cells: %u\n", num_cells);
+ // Check if size-cells is 2 cells.
+ if (i == 2 && num_cells > 3) {
+ // Combine size cells into 64-bit length
+ dev_dbg(&pdev->dev, "size-cells MSB: %u\n", cells[num_cells - 2]);
+ dev_dbg(&pdev->dev, "size-cells LSB: %u\n", cells[num_cells - 1]);
+ bus_width = ((u64)cells[num_cells - 2] << 32) |
+cells[num_cells - 1];
+ }
+
+ // Count number of bits in bus_width
+ if (bus_width)
+ addressable_bits = fls64(bus_width) - 1;
+
+ dev_dbg(&pdev->dev, "Bus width: %u bits (length: 0x%llx)\n",
+ addressable_bits, bus_width);
+ }
+ }
+
chip->dw = dw;
chip->dev = &pdev->dev;
chip->dw->hdata = hdata;
+ chip->addressable_bits = addressable_bits;

chip->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->regs))
@@ -1669,6 +1728,8 @@ static const struct of_device_id dw_dma_of_id_table[] = {
}, {
.compatible = "starfive,jh8100-axi-dma",
.data = (void *)AXI_DMA_FLAG_HAS_RESETS,
+ }, {
+ .compatible = "altr,agilex5-axi-dma"
},
{}
};
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index b842e6a8d90d..f8152f8b3798 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -71,6 +71,7 @@ struct axi_dma_chip {
struct clk *core_clk;
struct clk *cfgr_clk;
struct dw_axi_dma *dw;
+ u32 addressable_bits;
};

/* LLI == Linked List Item */
--
2.43.7