dmaengine: dw-axi-dmac: Per-channel burst limits

The DesignWare AXI DMAC IP can be configured with heterogeneous channel
parameters. Allow maximum burst length to be set per-channel by making
snps,axi-max-burst-len an array.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
This commit is contained in:
Phil Elwell
2025-01-30 15:29:31 +00:00
committed by Dom Cobley
parent 216e79bf7c
commit df647ac3ba
2 changed files with 19 additions and 12 deletions

View File

@@ -809,7 +809,7 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
ctlhi = CH_CTL_H_LLI_VALID; ctlhi = CH_CTL_H_LLI_VALID;
if (chan->chip->dw->hdata->restrict_axi_burst_len) { if (chan->chip->dw->hdata->restrict_axi_burst_len) {
burst_len = chan->chip->dw->hdata->axi_rw_burst_len; burst_len = chan->chip->dw->hdata->axi_rw_burst_len[chan->id];
ctlhi |= CH_CTL_H_ARLEN_EN | CH_CTL_H_AWLEN_EN | ctlhi |= CH_CTL_H_ARLEN_EN | CH_CTL_H_AWLEN_EN |
burst_len << CH_CTL_H_ARLEN_POS | burst_len << CH_CTL_H_ARLEN_POS |
burst_len << CH_CTL_H_AWLEN_POS; burst_len << CH_CTL_H_AWLEN_POS;
@@ -1087,7 +1087,7 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
reg = CH_CTL_H_LLI_VALID; reg = CH_CTL_H_LLI_VALID;
if (chan->chip->dw->hdata->restrict_axi_burst_len) { if (chan->chip->dw->hdata->restrict_axi_burst_len) {
u32 burst_len = chan->chip->dw->hdata->axi_rw_burst_len; u32 burst_len = chan->chip->dw->hdata->axi_rw_burst_len[chan->id];
reg |= (CH_CTL_H_ARLEN_EN | reg |= (CH_CTL_H_ARLEN_EN |
burst_len << CH_CTL_H_ARLEN_POS | burst_len << CH_CTL_H_ARLEN_POS |
@@ -1496,6 +1496,7 @@ static int parse_device_properties(struct axi_dma_chip *chip)
{ {
struct device *dev = chip->dev; struct device *dev = chip->dev;
u32 tmp, carr[DMAC_MAX_CHANNELS]; u32 tmp, carr[DMAC_MAX_CHANNELS];
u32 val;
int ret; int ret;
ret = device_property_read_u32(dev, "dma-channels", &tmp); ret = device_property_read_u32(dev, "dma-channels", &tmp);
@@ -1552,15 +1553,21 @@ static int parse_device_properties(struct axi_dma_chip *chip)
} }
/* axi-max-burst-len is optional property */ /* axi-max-burst-len is optional property */
ret = device_property_read_u32(dev, "snps,axi-max-burst-len", &tmp); ret = device_property_read_u32_array(dev, "snps,axi-max-burst-len", NULL,
if (!ret) { chip->dw->hdata->nr_channels);
if (tmp > DWAXIDMAC_ARWLEN_MAX + 1) if ((ret > 0) &&
return -EINVAL; !device_property_read_u32_array(dev, "snps,axi-max-burst-len",
if (tmp < DWAXIDMAC_ARWLEN_MIN + 1) carr, ret)) {
return -EINVAL;
chip->dw->hdata->restrict_axi_burst_len = true; chip->dw->hdata->restrict_axi_burst_len = true;
chip->dw->hdata->axi_rw_burst_len = tmp; for (tmp = 0; tmp < chip->dw->hdata->nr_channels; tmp++) {
// Replicate the last value to any remaining channels
val = carr[min(tmp, (u32)ret - 1)];
if (val > DWAXIDMAC_ARWLEN_MAX + 1)
return -EINVAL;
if (val < DWAXIDMAC_ARWLEN_MIN + 1)
return -EINVAL;
chip->dw->hdata->axi_rw_burst_len[tmp] = val;
}
} }
return 0; return 0;
@@ -1674,7 +1681,7 @@ static int dw_probe(struct platform_device *pdev)
dma_cap_set(DMA_CYCLIC, dw->dma.cap_mask); dma_cap_set(DMA_CYCLIC, dw->dma.cap_mask);
/* DMA capabilities */ /* DMA capabilities */
dw->dma.max_burst = hdata->axi_rw_burst_len; dw->dma.max_burst = hdata->axi_rw_burst_len[0];
dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS; dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS;
dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS; dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
dw->dma.directions = BIT(DMA_MEM_TO_MEM); dw->dma.directions = BIT(DMA_MEM_TO_MEM);

View File

@@ -29,7 +29,7 @@ struct dw_axi_dma_hcfg {
u32 block_size[DMAC_MAX_CHANNELS]; u32 block_size[DMAC_MAX_CHANNELS];
u32 priority[DMAC_MAX_CHANNELS]; u32 priority[DMAC_MAX_CHANNELS];
/* maximum supported axi burst length */ /* maximum supported axi burst length */
u32 axi_rw_burst_len; u32 axi_rw_burst_len[DMAC_MAX_CHANNELS];
/* Register map for DMAX_NUM_CHANNELS <= 8 */ /* Register map for DMAX_NUM_CHANNELS <= 8 */
bool reg_map_8_channels; bool reg_map_8_channels;
bool restrict_axi_burst_len; bool restrict_axi_burst_len;