123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- From 613af756b93fe005d9db11ea26fd0318f239d5a2 Mon Sep 17 00:00:00 2001
- From: Eugen Hristev <[email protected]>
- Date: Fri, 16 Oct 2020 12:38:50 +0300
- Subject: [PATCH 133/247] 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: Eugen Hristev <[email protected]>
- Link: https://lore.kernel.org/r/[email protected]
- Signed-off-by: Vinod Koul <[email protected]>
- ---
- drivers/dma/at_xdmac.c | 110 +++++++++++++++++++++++++++++++----------
- 1 file changed, 84 insertions(+), 26 deletions(-)
- --- a/drivers/dma/at_xdmac.c
- +++ b/drivers/dma/at_xdmac.c
- @@ -38,13 +38,6 @@
- #define AT_XDMAC_GE 0x1C /* Global Channel Enable Register */
- #define AT_XDMAC_GD 0x20 /* Global Channel Disable 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 */
-
- /* Channel relative registers offsets */
- @@ -151,8 +144,6 @@
- #define AT_XDMAC_CSUS 0x30 /* Channel Source 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 */
- #define AT_XDMAC_MBR_UBC_UBLEN_MAX 0xFFFFFFUL /* Maximum Microblock Length */
- #define AT_XDMAC_MBR_UBC_NDE (0x1 << 24) /* Next Descriptor Enable */
- @@ -180,6 +171,27 @@ enum atc_status {
- 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 ----- */
- struct at_xdmac_chan {
- struct dma_chan chan;
- @@ -213,6 +225,7 @@ struct at_xdmac {
- struct clk *clk;
- u32 save_gim;
- struct dma_pool *at_xdmac_desc_pool;
- + const struct at_xdmac_layout *layout;
- struct at_xdmac_chan chan[];
- };
-
- @@ -245,9 +258,33 @@ struct at_xdmac_desc {
- struct list_head xfer_node;
- } __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)
- {
- - 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))
- @@ -343,8 +380,10 @@ static void at_xdmac_start_xfer(struct a
- first->active_xfer = true;
-
- /* Tell xdmac where to get the first descriptor. */
- - reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys)
- - | AT_XDMAC_CNDA_NDAIF(atchan->memif);
- + reg = AT_XDMAC_CNDA_NDA(first->tx_dma_desc.phys);
- + if (atxdmac->layout->sdif)
- + reg |= AT_XDMAC_CNDA_NDAIF(atchan->memif);
- +
- at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg);
-
- /*
- @@ -539,6 +578,7 @@ static int at_xdmac_compute_chan_conf(st
- enum dma_transfer_direction direction)
- {
- struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
- + struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
- int csize, dwidth;
-
- if (direction == DMA_DEV_TO_MEM) {
- @@ -546,12 +586,14 @@ static int at_xdmac_compute_chan_conf(st
- AT91_XDMAC_DT_PERID(atchan->perid)
- | AT_XDMAC_CC_DAM_INCREMENTED_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_DSYNC_PER2MEM
- | AT_XDMAC_CC_MBSIZE_SIXTEEN
- | 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;
- if (csize < 0) {
- dev_err(chan2dev(chan), "invalid src maxburst value\n");
- @@ -569,12 +611,14 @@ static int at_xdmac_compute_chan_conf(st
- AT91_XDMAC_DT_PERID(atchan->perid)
- | AT_XDMAC_CC_DAM_FIXED_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_DSYNC_MEM2PER
- | AT_XDMAC_CC_MBSIZE_SIXTEEN
- | 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;
- if (csize < 0) {
- dev_err(chan2dev(chan), "invalid src maxburst value\n");
- @@ -864,10 +908,12 @@ at_xdmac_interleaved_queue_desc(struct d
- * 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
- * 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)
- - | AT_XDMAC_CC_DIF(0)
- - | AT_XDMAC_CC_SIF(0)
- | AT_XDMAC_CC_MBSIZE_SIXTEEN
- | AT_XDMAC_CC_TYPE_MEM_TRAN;
-
- @@ -1046,12 +1092,14 @@ at_xdmac_prep_dma_memcpy(struct dma_chan
- * 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
- * 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)
- | AT_XDMAC_CC_DAM_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_TYPE_MEM_TRAN;
- unsigned long irqflags;
- @@ -1152,12 +1200,14 @@ static struct at_xdmac_desc *at_xdmac_me
- * 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
- * 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)
- | AT_XDMAC_CC_DAM_UBS_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_MEMSET_HW_MODE
- | AT_XDMAC_CC_TYPE_MEM_TRAN;
- @@ -1436,7 +1486,7 @@ at_xdmac_tx_status(struct dma_chan *chan
- mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
- value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
- 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))
- cpu_relax();
- }
- @@ -1494,7 +1544,7 @@ at_xdmac_tx_status(struct dma_chan *chan
- * FIFO flush ensures that data are really written.
- */
- 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))
- cpu_relax();
- }
- @@ -1762,7 +1812,7 @@ static int at_xdmac_device_pause(struct
- return 0;
-
- 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)
- & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
- cpu_relax();
- @@ -1785,7 +1835,7 @@ static int at_xdmac_device_resume(struct
- 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);
- spin_unlock_irqrestore(&atchan->lock, flags);
-
- @@ -1992,6 +2042,10 @@ static int at_xdmac_probe(struct platfor
- atxdmac->regs = base;
- 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");
- if (IS_ERR(atxdmac->clk)) {
- dev_err(&pdev->dev, "can't get dma_clk\n");
- @@ -2134,6 +2188,10 @@ static const struct dev_pm_ops atmel_xdm
- static const struct of_device_id atmel_xdmac_dt_ids[] = {
- {
- .compatible = "atmel,sama5d4-dma",
- + .data = &at_xdmac_sama5d4_layout,
- + }, {
- + .compatible = "microchip,sama7g5-dma",
- + .data = &at_xdmac_sama7g5_layout,
- }, {
- /* sentinel */
- }
|