Skip to content

Commit

Permalink
dmaengine: axi-dmac: add support for reading bus attributes from regi…
Browse files Browse the repository at this point in the history
…sters

Starting with core version 4.3.a the DMA bus attributes can (and should) be
read from the INTERFACE_DESCRIPTION (0x10) register.

For older core versions, this will still need to be provided from the
device-tree.

The bus-type values are identical to the ones stored in the device-trees,
so we just need to read them. Bus-width values are stored in log2 values,
so we just need to use them as shift values to make them equivalent to the
current format.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
  • Loading branch information
commodo committed Aug 19, 2020
1 parent 2d06591 commit acfc706
Showing 1 changed file with 63 additions and 3 deletions.
66 changes: 63 additions & 3 deletions drivers/dma/dma-axi-dmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
Expand Down Expand Up @@ -45,6 +46,16 @@
* there is no address than can or needs to be configured for the device side.
*/

#define AXI_DMAC_REG_INTERFACE_DESC 0x10
#define AXI_DMAC_DMA_SRC_TYPE_MSK GENMASK(13, 12)
#define AXI_DMAC_DMA_SRC_TYPE_GET(x) FIELD_GET(AXI_DMAC_DMA_SRC_TYPE_MSK, x)
#define AXI_DMAC_DMA_SRC_WIDTH_MSK GENMASK(11, 8)
#define AXI_DMAC_DMA_SRC_WIDTH_GET(x) FIELD_GET(AXI_DMAC_DMA_SRC_WIDTH_MSK, x)
#define AXI_DMAC_DMA_DST_TYPE_MSK GENMASK(5, 4)
#define AXI_DMAC_DMA_DST_TYPE_GET(x) FIELD_GET(AXI_DMAC_DMA_DST_TYPE_MSK, x)
#define AXI_DMAC_DMA_DST_WIDTH_MSK GENMASK(3, 0)
#define AXI_DMAC_DMA_DST_WIDTH_GET(x) FIELD_GET(AXI_DMAC_DMA_DST_WIDTH_MSK, x)

#define AXI_DMAC_REG_IRQ_MASK 0x80
#define AXI_DMAC_REG_IRQ_PENDING 0x84
#define AXI_DMAC_REG_IRQ_SOURCE 0x88
Expand Down Expand Up @@ -865,6 +876,51 @@ static int axi_dmac_parse_dt(struct device *dev, struct axi_dmac *dmac)
return 0;
}

static int axi_dmac_read_chan_config(struct device *dev, struct axi_dmac *dmac)
{
struct axi_dmac_chan *chan = &dmac->chan;
unsigned int val, desc;

desc = axi_dmac_read(dmac, AXI_DMAC_REG_INTERFACE_DESC);
if (desc == 0) {
dev_err(dev, "DMA interface register reads zero\n");
return -EFAULT;
}

val = AXI_DMAC_DMA_SRC_TYPE_GET(desc);
if (val > AXI_DMAC_BUS_TYPE_FIFO) {
dev_err(dev, "Invalid source bus type read: %d\n", val);
return -EINVAL;
}
chan->src_type = val;

val = AXI_DMAC_DMA_DST_TYPE_GET(desc);
if (val > AXI_DMAC_BUS_TYPE_FIFO) {
dev_err(dev, "Invalid destination bus type read: %d\n", val);
return -EINVAL;
}
chan->dest_type = val;

val = AXI_DMAC_DMA_SRC_WIDTH_GET(desc);
if (val == 0) {
dev_err(dev, "Source bus width is zero\n");
return -EINVAL;
}
/* widths are stored in log2 */
chan->src_width = 1 << val;

val = AXI_DMAC_DMA_DST_WIDTH_GET(desc);
if (val == 0) {
dev_err(dev, "Destination bus width is zero\n");
return -EINVAL;
}
chan->dest_width = 1 << val;

axi_dmac_adjust_chan_params(chan);

return 0;
}

static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
{
struct axi_dmac_chan *chan = &dmac->chan;
Expand Down Expand Up @@ -945,7 +1001,13 @@ static int axi_dmac_probe(struct platform_device *pdev)

INIT_LIST_HEAD(&dmac->chan.active_descs);

ret = axi_dmac_parse_dt(&pdev->dev, dmac);
version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION);

if (version >= ADI_AXI_PCORE_VER(4, 3, 'a'))
ret = axi_dmac_read_chan_config(&pdev->dev, dmac);
else
ret = axi_dmac_parse_dt(&pdev->dev, dmac);

if (ret < 0)
return ret;

Expand Down Expand Up @@ -976,8 +1038,6 @@ static int axi_dmac_probe(struct platform_device *pdev)
dmac->chan.vchan.desc_free = axi_dmac_desc_free;
vchan_init(&dmac->chan.vchan, dma_dev);

version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION);

ret = axi_dmac_detect_caps(dmac, version);
if (ret)
goto err_clk_disable;
Expand Down

0 comments on commit acfc706

Please sign in to comment.