diff options
Diffstat (limited to 'target/linux/at91/patches-5.10/133-dmaengine-at_xdmac-add-support-for-sama7g5-based-at_.patch')
-rw-r--r-- | target/linux/at91/patches-5.10/133-dmaengine-at_xdmac-add-support-for-sama7g5-based-at_.patch | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/target/linux/at91/patches-5.10/133-dmaengine-at_xdmac-add-support-for-sama7g5-based-at_.patch b/target/linux/at91/patches-5.10/133-dmaengine-at_xdmac-add-support-for-sama7g5-based-at_.patch new file mode 100644 index 0000000000..5ddc90c044 --- /dev/null +++ b/target/linux/at91/patches-5.10/133-dmaengine-at_xdmac-add-support-for-sama7g5-based-at_.patch @@ -0,0 +1,285 @@ +From 613af756b93fe005d9db11ea26fd0318f239d5a2 Mon Sep 17 00:00:00 2001 +From: Eugen Hristev <eugen.hristev@microchip.com> +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 <eugen.hristev@microchip.com> +Link: https://lore.kernel.org/r/20201016093850.290053-1-eugen.hristev@microchip.com +Signed-off-by: Vinod Koul <vkoul@kernel.org> +--- + drivers/dma/at_xdmac.c | 110 +++++++++++++++++++++++++++++++---------- + 1 file changed, 84 insertions(+), 26 deletions(-) + +diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c +index 85fe260ccd07..2b096ea04018 100644 +--- 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 at_xdmac_chan *atchan, + 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(struct dma_chan *chan, + 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(struct dma_chan *chan, + 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(struct dma_chan *chan, + 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 dma_chan *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_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 *chan, dma_addr_t dest, dma_addr_t src, + * 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_memset_create_desc(struct dma_chan *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_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, dma_cookie_t cookie, + 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, dma_cookie_t cookie, + * 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(); + } +@@ -1760,7 +1810,7 @@ static int at_xdmac_device_pause(struct dma_chan *chan) + 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(); +@@ -1783,7 +1833,7 @@ static int at_xdmac_device_resume(struct dma_chan *chan) + 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); + +@@ -1985,6 +2035,10 @@ static int at_xdmac_probe(struct platform_device *pdev) + 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"); +@@ -2127,6 +2181,10 @@ static const struct dev_pm_ops atmel_xdmac_dev_pm_ops = { + 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 */ + } +-- +2.32.0 + |