Commit 2bec35a5 authored by Eugen Hristev's avatar Eugen Hristev Committed by Vinod Koul

dmaengine: at_xdmac: add support for sama7g5 based at_xdmac

SAMA7G5 SoC uses a slightly different variant of the AT_XDMAC.
Added support by a new compatible and a layout struct that copes
to the specific version considering the compatible string.
Only the differences in register map are present in the layout struct.
I reworked the register access for this part that has the differences.
Also the Source/Destination Interface bits are no longer valid for this
variant of the XDMAC. Thus, the layout also has a bool for specifying
whether these bits are required or not.
Signed-off-by: default avatarEugen Hristev <eugen.hristev@microchip.com>
Link: https://lore.kernel.org/r/20201016093850.290053-1-eugen.hristev@microchip.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 60f88c03
...@@ -38,13 +38,6 @@ ...@@ -38,13 +38,6 @@
#define AT_XDMAC_GE 0x1C /* Global Channel Enable Register */ #define AT_XDMAC_GE 0x1C /* Global Channel Enable Register */
#define AT_XDMAC_GD 0x20 /* Global Channel Disable Register */ #define AT_XDMAC_GD 0x20 /* Global Channel Disable Register */
#define AT_XDMAC_GS 0x24 /* Global Channel Status Register */ #define AT_XDMAC_GS 0x24 /* Global Channel Status Register */
#define AT_XDMAC_GRS 0x28 /* Global Channel Read Suspend Register */
#define AT_XDMAC_GWS 0x2C /* Global Write Suspend Register */
#define AT_XDMAC_GRWS 0x30 /* Global Channel Read Write Suspend Register */
#define AT_XDMAC_GRWR 0x34 /* Global Channel Read Write Resume Register */
#define AT_XDMAC_GSWR 0x38 /* Global Channel Software Request Register */
#define AT_XDMAC_GSWS 0x3C /* Global channel Software Request Status Register */
#define AT_XDMAC_GSWF 0x40 /* Global Channel Software Flush Request Register */
#define AT_XDMAC_VERSION 0xFFC /* XDMAC Version Register */ #define AT_XDMAC_VERSION 0xFFC /* XDMAC Version Register */
/* Channel relative registers offsets */ /* Channel relative registers offsets */
...@@ -150,8 +143,6 @@ ...@@ -150,8 +143,6 @@
#define AT_XDMAC_CSUS 0x30 /* Channel Source Microblock Stride */ #define AT_XDMAC_CSUS 0x30 /* Channel Source Microblock Stride */
#define AT_XDMAC_CDUS 0x34 /* Channel Destination Microblock Stride */ #define AT_XDMAC_CDUS 0x34 /* Channel Destination Microblock Stride */
#define AT_XDMAC_CHAN_REG_BASE 0x50 /* Channel registers base address */
/* Microblock control members */ /* Microblock control members */
#define AT_XDMAC_MBR_UBC_UBLEN_MAX 0xFFFFFFUL /* Maximum Microblock Length */ #define AT_XDMAC_MBR_UBC_UBLEN_MAX 0xFFFFFFUL /* Maximum Microblock Length */
#define AT_XDMAC_MBR_UBC_NDE (0x1 << 24) /* Next Descriptor Enable */ #define AT_XDMAC_MBR_UBC_NDE (0x1 << 24) /* Next Descriptor Enable */
...@@ -179,6 +170,27 @@ enum atc_status { ...@@ -179,6 +170,27 @@ enum atc_status {
AT_XDMAC_CHAN_IS_PAUSED, AT_XDMAC_CHAN_IS_PAUSED,
}; };
struct at_xdmac_layout {
/* Global Channel Read Suspend Register */
u8 grs;
/* Global Write Suspend Register */
u8 gws;
/* Global Channel Read Write Suspend Register */
u8 grws;
/* Global Channel Read Write Resume Register */
u8 grwr;
/* Global Channel Software Request Register */
u8 gswr;
/* Global channel Software Request Status Register */
u8 gsws;
/* Global Channel Software Flush Request Register */
u8 gswf;
/* Channel reg base */
u8 chan_cc_reg_base;
/* Source/Destination Interface must be specified or not */
bool sdif;
};
/* ----- Channels ----- */ /* ----- Channels ----- */
struct at_xdmac_chan { struct at_xdmac_chan {
struct dma_chan chan; struct dma_chan chan;
...@@ -212,6 +224,7 @@ struct at_xdmac { ...@@ -212,6 +224,7 @@ struct at_xdmac {
struct clk *clk; struct clk *clk;
u32 save_gim; u32 save_gim;
struct dma_pool *at_xdmac_desc_pool; struct dma_pool *at_xdmac_desc_pool;
const struct at_xdmac_layout *layout;
struct at_xdmac_chan chan[]; struct at_xdmac_chan chan[];
}; };
...@@ -244,9 +257,33 @@ struct at_xdmac_desc { ...@@ -244,9 +257,33 @@ struct at_xdmac_desc {
struct list_head xfer_node; struct list_head xfer_node;
} __aligned(sizeof(u64)); } __aligned(sizeof(u64));
static const struct at_xdmac_layout at_xdmac_sama5d4_layout = {
.grs = 0x28,
.gws = 0x2C,
.grws = 0x30,
.grwr = 0x34,
.gswr = 0x38,
.gsws = 0x3C,
.gswf = 0x40,
.chan_cc_reg_base = 0x50,
.sdif = true,
};
static const struct at_xdmac_layout at_xdmac_sama7g5_layout = {
.grs = 0x30,
.gws = 0x38,
.grws = 0x40,
.grwr = 0x44,
.gswr = 0x48,
.gsws = 0x4C,
.gswf = 0x50,
.chan_cc_reg_base = 0x60,
.sdif = false,
};
static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb) static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb)
{ {
return atxdmac->regs + (AT_XDMAC_CHAN_REG_BASE + chan_nb * 0x40); return atxdmac->regs + (atxdmac->layout->chan_cc_reg_base + chan_nb * 0x40);
} }
#define at_xdmac_read(atxdmac, reg) readl_relaxed((atxdmac)->regs + (reg)) #define at_xdmac_read(atxdmac, reg) readl_relaxed((atxdmac)->regs + (reg))
...@@ -345,8 +382,10 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan, ...@@ -345,8 +382,10 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
first->active_xfer = true; first->active_xfer = true;
/* Tell xdmac where to get the first descriptor. */ /* Tell xdmac where to get the first descriptor. */
reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys) reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys);
| AT_XDMAC_CNDA_NDAIF(atchan->memif); if (atxdmac->layout->sdif)
reg |= AT_XDMAC_CNDA_NDAIF(atchan->memif);
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg); at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg);
/* /*
...@@ -541,6 +580,7 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan, ...@@ -541,6 +580,7 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
enum dma_transfer_direction direction) enum dma_transfer_direction direction)
{ {
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
int csize, dwidth; int csize, dwidth;
if (direction == DMA_DEV_TO_MEM) { if (direction == DMA_DEV_TO_MEM) {
...@@ -548,12 +588,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan, ...@@ -548,12 +588,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
AT91_XDMAC_DT_PERID(atchan->perid) AT91_XDMAC_DT_PERID(atchan->perid)
| AT_XDMAC_CC_DAM_INCREMENTED_AM | AT_XDMAC_CC_DAM_INCREMENTED_AM
| AT_XDMAC_CC_SAM_FIXED_AM | AT_XDMAC_CC_SAM_FIXED_AM
| AT_XDMAC_CC_DIF(atchan->memif)
| AT_XDMAC_CC_SIF(atchan->perif)
| AT_XDMAC_CC_SWREQ_HWR_CONNECTED | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
| AT_XDMAC_CC_DSYNC_PER2MEM | AT_XDMAC_CC_DSYNC_PER2MEM
| AT_XDMAC_CC_MBSIZE_SIXTEEN | AT_XDMAC_CC_MBSIZE_SIXTEEN
| AT_XDMAC_CC_TYPE_PER_TRAN; | AT_XDMAC_CC_TYPE_PER_TRAN;
if (atxdmac->layout->sdif)
atchan->cfg |= AT_XDMAC_CC_DIF(atchan->memif) |
AT_XDMAC_CC_SIF(atchan->perif);
csize = ffs(atchan->sconfig.src_maxburst) - 1; csize = ffs(atchan->sconfig.src_maxburst) - 1;
if (csize < 0) { if (csize < 0) {
dev_err(chan2dev(chan), "invalid src maxburst value\n"); dev_err(chan2dev(chan), "invalid src maxburst value\n");
...@@ -571,12 +613,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan, ...@@ -571,12 +613,14 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
AT91_XDMAC_DT_PERID(atchan->perid) AT91_XDMAC_DT_PERID(atchan->perid)
| AT_XDMAC_CC_DAM_FIXED_AM | AT_XDMAC_CC_DAM_FIXED_AM
| AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM
| AT_XDMAC_CC_DIF(atchan->perif)
| AT_XDMAC_CC_SIF(atchan->memif)
| AT_XDMAC_CC_SWREQ_HWR_CONNECTED | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
| AT_XDMAC_CC_DSYNC_MEM2PER | AT_XDMAC_CC_DSYNC_MEM2PER
| AT_XDMAC_CC_MBSIZE_SIXTEEN | AT_XDMAC_CC_MBSIZE_SIXTEEN
| AT_XDMAC_CC_TYPE_PER_TRAN; | AT_XDMAC_CC_TYPE_PER_TRAN;
if (atxdmac->layout->sdif)
atchan->cfg |= AT_XDMAC_CC_DIF(atchan->perif) |
AT_XDMAC_CC_SIF(atchan->memif);
csize = ffs(atchan->sconfig.dst_maxburst) - 1; csize = ffs(atchan->sconfig.dst_maxburst) - 1;
if (csize < 0) { if (csize < 0) {
dev_err(chan2dev(chan), "invalid src maxburst value\n"); dev_err(chan2dev(chan), "invalid src maxburst value\n");
...@@ -866,10 +910,12 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, ...@@ -866,10 +910,12 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
* ERRATA: Even if useless for memory transfers, the PERID has to not * ERRATA: Even if useless for memory transfers, the PERID has to not
* match the one of another channel. If not, it could lead to spurious * match the one of another channel. If not, it could lead to spurious
* flag status. * flag status.
* For SAMA7G5x case, the SIF and DIF fields are no longer used.
* Thus, no need to have the SIF/DIF interfaces here.
* For SAMA5D4x and SAMA5D2x the SIF and DIF are already configured as
* zero.
*/ */
u32 chan_cc = AT_XDMAC_CC_PERID(0x7f) u32 chan_cc = AT_XDMAC_CC_PERID(0x7f)
| AT_XDMAC_CC_DIF(0)
| AT_XDMAC_CC_SIF(0)
| AT_XDMAC_CC_MBSIZE_SIXTEEN | AT_XDMAC_CC_MBSIZE_SIXTEEN
| AT_XDMAC_CC_TYPE_MEM_TRAN; | AT_XDMAC_CC_TYPE_MEM_TRAN;
...@@ -1048,12 +1094,14 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, ...@@ -1048,12 +1094,14 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
* ERRATA: Even if useless for memory transfers, the PERID has to not * ERRATA: Even if useless for memory transfers, the PERID has to not
* match the one of another channel. If not, it could lead to spurious * match the one of another channel. If not, it could lead to spurious
* flag status. * flag status.
* For SAMA7G5x case, the SIF and DIF fields are no longer used.
* Thus, no need to have the SIF/DIF interfaces here.
* For SAMA5D4x and SAMA5D2x the SIF and DIF are already configured as
* zero.
*/ */
u32 chan_cc = AT_XDMAC_CC_PERID(0x7f) u32 chan_cc = AT_XDMAC_CC_PERID(0x7f)
| AT_XDMAC_CC_DAM_INCREMENTED_AM | AT_XDMAC_CC_DAM_INCREMENTED_AM
| AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM
| AT_XDMAC_CC_DIF(0)
| AT_XDMAC_CC_SIF(0)
| AT_XDMAC_CC_MBSIZE_SIXTEEN | AT_XDMAC_CC_MBSIZE_SIXTEEN
| AT_XDMAC_CC_TYPE_MEM_TRAN; | AT_XDMAC_CC_TYPE_MEM_TRAN;
unsigned long irqflags; unsigned long irqflags;
...@@ -1154,12 +1202,14 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, ...@@ -1154,12 +1202,14 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
* ERRATA: Even if useless for memory transfers, the PERID has to not * ERRATA: Even if useless for memory transfers, the PERID has to not
* match the one of another channel. If not, it could lead to spurious * match the one of another channel. If not, it could lead to spurious
* flag status. * flag status.
* For SAMA7G5x case, the SIF and DIF fields are no longer used.
* Thus, no need to have the SIF/DIF interfaces here.
* For SAMA5D4x and SAMA5D2x the SIF and DIF are already configured as
* zero.
*/ */
u32 chan_cc = AT_XDMAC_CC_PERID(0x7f) u32 chan_cc = AT_XDMAC_CC_PERID(0x7f)
| AT_XDMAC_CC_DAM_UBS_AM | AT_XDMAC_CC_DAM_UBS_AM
| AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM
| AT_XDMAC_CC_DIF(0)
| AT_XDMAC_CC_SIF(0)
| AT_XDMAC_CC_MBSIZE_SIXTEEN | AT_XDMAC_CC_MBSIZE_SIXTEEN
| AT_XDMAC_CC_MEMSET_HW_MODE | AT_XDMAC_CC_MEMSET_HW_MODE
| AT_XDMAC_CC_TYPE_MEM_TRAN; | AT_XDMAC_CC_TYPE_MEM_TRAN;
...@@ -1438,7 +1488,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ...@@ -1438,7 +1488,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC; mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM; value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
if ((desc->lld.mbr_cfg & mask) == value) { if ((desc->lld.mbr_cfg & mask) == value) {
at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask); at_xdmac_write(atxdmac, atxdmac->layout->gswf, atchan->mask);
while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS)) while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
cpu_relax(); cpu_relax();
} }
...@@ -1496,7 +1546,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ...@@ -1496,7 +1546,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
* FIFO flush ensures that data are really written. * FIFO flush ensures that data are really written.
*/ */
if ((desc->lld.mbr_cfg & mask) == value) { if ((desc->lld.mbr_cfg & mask) == value) {
at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask); at_xdmac_write(atxdmac, atxdmac->layout->gswf, atchan->mask);
while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS)) while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
cpu_relax(); cpu_relax();
} }
...@@ -1761,7 +1811,7 @@ static int at_xdmac_device_pause(struct dma_chan *chan) ...@@ -1761,7 +1811,7 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
return 0; return 0;
spin_lock_irqsave(&atchan->lock, flags); spin_lock_irqsave(&atchan->lock, flags);
at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask); at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask);
while (at_xdmac_chan_read(atchan, AT_XDMAC_CC) while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
& (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP)) & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
cpu_relax(); cpu_relax();
...@@ -1784,7 +1834,7 @@ static int at_xdmac_device_resume(struct dma_chan *chan) ...@@ -1784,7 +1834,7 @@ static int at_xdmac_device_resume(struct dma_chan *chan)
return 0; return 0;
} }
at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask); at_xdmac_write(atxdmac, atxdmac->layout->grwr, atchan->mask);
clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status); clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
spin_unlock_irqrestore(&atchan->lock, flags); spin_unlock_irqrestore(&atchan->lock, flags);
...@@ -1986,6 +2036,10 @@ static int at_xdmac_probe(struct platform_device *pdev) ...@@ -1986,6 +2036,10 @@ static int at_xdmac_probe(struct platform_device *pdev)
atxdmac->regs = base; atxdmac->regs = base;
atxdmac->irq = irq; atxdmac->irq = irq;
atxdmac->layout = of_device_get_match_data(&pdev->dev);
if (!atxdmac->layout)
return -ENODEV;
atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk"); atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk");
if (IS_ERR(atxdmac->clk)) { if (IS_ERR(atxdmac->clk)) {
dev_err(&pdev->dev, "can't get dma_clk\n"); dev_err(&pdev->dev, "can't get dma_clk\n");
...@@ -2128,6 +2182,10 @@ static const struct dev_pm_ops atmel_xdmac_dev_pm_ops = { ...@@ -2128,6 +2182,10 @@ static const struct dev_pm_ops atmel_xdmac_dev_pm_ops = {
static const struct of_device_id atmel_xdmac_dt_ids[] = { static const struct of_device_id atmel_xdmac_dt_ids[] = {
{ {
.compatible = "atmel,sama5d4-dma", .compatible = "atmel,sama5d4-dma",
.data = &at_xdmac_sama5d4_layout,
}, {
.compatible = "microchip,sama7g5-dma",
.data = &at_xdmac_sama7g5_layout,
}, { }, {
/* sentinel */ /* sentinel */
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment