Skip to content

Commit b244044

Browse files
nunojsavinodkoul
authored andcommitted
dma: dma-axi-dmac: support bigger than 32bits addresses
In some supported platforms as ARCH_ZYNQMP, part of the memory is mapped above 32bit addresses and since the DMA mask, by default, is set to 32bits, we would need to rely on swiotlb (which incurs a performance penalty) for the DMA mappings. Thus, we can write either the SRC or DEST high addresses with 1's and read them back. The last bit set on the return value will reflect the IP address bus width and so we can update the device DMA mask accordingly. While at it, support bigger that 32 bits transfers in IP without HW scatter gather support. Signed-off-by: Nuno Sá <nuno.sa@analog.com> base-commit: 3980351 change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c Acked-by: Michael Hennerich <michael.hennerich@analog.com> Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-3-3e6fd9328f72@analog.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent bbcbafb commit b244044

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

drivers/dma/dma-axi-dmac.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@
6969
#define AXI_DMAC_REG_START_TRANSFER 0x408
7070
#define AXI_DMAC_REG_FLAGS 0x40c
7171
#define AXI_DMAC_REG_DEST_ADDRESS 0x410
72+
#define AXI_DMAC_REG_DEST_ADDRESS_HIGH 0x490
7273
#define AXI_DMAC_REG_SRC_ADDRESS 0x414
74+
#define AXI_DMAC_REG_SRC_ADDRESS_HIGH 0x494
7375
#define AXI_DMAC_REG_X_LENGTH 0x418
7476
#define AXI_DMAC_REG_Y_LENGTH 0x41c
7577
#define AXI_DMAC_REG_DEST_STRIDE 0x420
@@ -271,11 +273,14 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
271273
if (!chan->hw_sg) {
272274
if (axi_dmac_dest_is_mem(chan)) {
273275
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->hw->dest_addr);
276+
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH,
277+
sg->hw->dest_addr >> 32);
274278
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->hw->dst_stride);
275279
}
276280

277281
if (axi_dmac_src_is_mem(chan)) {
278282
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->hw->src_addr);
283+
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH, sg->hw->src_addr >> 32);
279284
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->hw->src_stride);
280285
}
281286
}
@@ -990,6 +995,9 @@ static int axi_dmac_read_chan_config(struct device *dev, struct axi_dmac *dmac)
990995
static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
991996
{
992997
struct axi_dmac_chan *chan = &dmac->chan;
998+
struct device *dev = dmac->dma_dev.dev;
999+
u32 mask;
1000+
int ret;
9931001

9941002
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC);
9951003
if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC)
@@ -1024,6 +1032,22 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
10241032
return -ENODEV;
10251033
}
10261034

1035+
if (axi_dmac_dest_is_mem(chan)) {
1036+
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH, 0xffffffff);
1037+
mask = axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH);
1038+
} else {
1039+
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH, 0xffffffff);
1040+
mask = axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH);
1041+
}
1042+
1043+
mask = 32 + fls(mask);
1044+
1045+
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(mask));
1046+
if (ret) {
1047+
dev_err(dev, "DMA mask set error %d\n", ret);
1048+
return ret;
1049+
}
1050+
10271051
if (version >= ADI_AXI_PCORE_VER(4, 2, 'a'))
10281052
chan->hw_partial_xfer = true;
10291053

0 commit comments

Comments
 (0)