dmaengine: axi-dmac: add support for reading bus attributes from registers
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> Link: https://lore.kernel.org/r/20200825151950.57605-7-alexandru.ardelean@analog.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
3061a65c1b
commit
78a2f92e4c
|
@ -6,6 +6,7 @@
|
||||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/dma-mapping.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.
|
* 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_MASK 0x80
|
||||||
#define AXI_DMAC_REG_IRQ_PENDING 0x84
|
#define AXI_DMAC_REG_IRQ_PENDING 0x84
|
||||||
#define AXI_DMAC_REG_IRQ_SOURCE 0x88
|
#define AXI_DMAC_REG_IRQ_SOURCE 0x88
|
||||||
|
@ -801,6 +812,51 @@ static int axi_dmac_parse_dt(struct device *dev, struct axi_dmac *dmac)
|
||||||
return 0;
|
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)
|
static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
|
||||||
{
|
{
|
||||||
struct axi_dmac_chan *chan = &dmac->chan;
|
struct axi_dmac_chan *chan = &dmac->chan;
|
||||||
|
@ -880,7 +936,13 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
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)
|
if (ret < 0)
|
||||||
goto err_clk_disable;
|
goto err_clk_disable;
|
||||||
|
|
||||||
|
@ -912,8 +974,6 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||||
dmac->chan.vchan.desc_free = axi_dmac_desc_free;
|
dmac->chan.vchan.desc_free = axi_dmac_desc_free;
|
||||||
vchan_init(&dmac->chan.vchan, dma_dev);
|
vchan_init(&dmac->chan.vchan, dma_dev);
|
||||||
|
|
||||||
version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION);
|
|
||||||
|
|
||||||
ret = axi_dmac_detect_caps(dmac, version);
|
ret = axi_dmac_detect_caps(dmac, version);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_clk_disable;
|
goto err_clk_disable;
|
||||||
|
|
Loading…
Reference in New Issue