-
Notifications
You must be signed in to change notification settings - Fork 845
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dmaengine: axi-dmac: add support for reading bus attributes from regi…
…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 <[email protected]>
- Loading branch information
Showing
1 changed file
with
63 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
* Author: Lars-Peter Clausen <[email protected]> | ||
*/ | ||
|
||
#include <linux/bitfield.h> | ||
#include <linux/clk.h> | ||
#include <linux/device.h> | ||
#include <linux/dma-mapping.h> | ||
|
@@ -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 | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
||
|
@@ -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; | ||
|