Skip to content

Commit d158f8c

Browse files
nunojsagastmaier
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á <[email protected]> (cherry picked from commit 86940fd)
1 parent eac189c commit d158f8c

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

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
@@ -274,11 +276,14 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
274276
if (!chan->hw_sg) {
275277
if (axi_dmac_dest_is_mem(chan)) {
276278
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->hw->dest_addr);
279+
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH,
280+
sg->hw->dest_addr >> 32);
277281
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->hw->dst_stride);
278282
}
279283

280284
if (axi_dmac_src_is_mem(chan)) {
281285
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->hw->src_addr);
286+
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH, sg->hw->src_addr >> 32);
282287
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->hw->src_stride);
283288
}
284289
}
@@ -1016,6 +1021,9 @@ static int axi_dmac_read_chan_config(struct device *dev, struct axi_dmac *dmac)
10161021
static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
10171022
{
10181023
struct axi_dmac_chan *chan = &dmac->chan;
1024+
struct device *dev = dmac->dma_dev.dev;
1025+
u32 mask;
1026+
int ret;
10191027

10201028
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC);
10211029
if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC)
@@ -1050,6 +1058,22 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
10501058
return -ENODEV;
10511059
}
10521060

1061+
if (axi_dmac_dest_is_mem(chan)) {
1062+
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH, 0xffffffff);
1063+
mask = axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH);
1064+
} else {
1065+
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH, 0xffffffff);
1066+
mask = axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH);
1067+
}
1068+
1069+
mask = 32 + fls(mask);
1070+
1071+
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(mask));
1072+
if (ret) {
1073+
dev_err(dev, "DMA mask set error %d\n", ret);
1074+
return ret;
1075+
}
1076+
10531077
if (version >= ADI_AXI_PCORE_VER(4, 2, 'a'))
10541078
chan->hw_partial_xfer = true;
10551079

0 commit comments

Comments
 (0)