On 23.09.2020 10:08, Tudor Ambarus - M18064 wrote:
> On 9/14/20 5:09 PM, Eugen Hristev wrote:
>> 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.hris...@microchip.com>
>> ---
>>   drivers/dma/at_xdmac.c      | 99 ++++++++++++++++++++++++++++++-------
>>   drivers/dma/at_xdmac_regs.h |  9 ----
>>   2 files changed, 82 insertions(+), 26 deletions(-)
>>
>> diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
>> index 81bb90206092..874484a4e79f 100644
>> --- a/drivers/dma/at_xdmac.c
>> +++ b/drivers/dma/at_xdmac.c
>> @@ -38,6 +38,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;
>> @@ -71,6 +92,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[];
>>   };
>>   
>> @@ -103,9 +125,33 @@ struct at_xdmac_desc {
>>      struct list_head                xfer_node;
>>   } __aligned(sizeof(u64));
>>   
>> +static struct at_xdmac_layout at_xdmac_sama5d4_layout = {
> 
> static const struct
> 
>> +    .grs = 0x28,
>> +    .gws = 0x2C,
>> +    .grws = 0x30,
>> +    .grwr = 0x34,
>> +    .gswr = 0x38,
>> +    .gsws = 0x3C,
>> +    .gswf = 0x40,
>> +    .chan_cc_reg_base = 0x50,
>> +    .sdif = true,
>> +};
>> +
>> +static struct at_xdmac_layout at_xdmac_sama7g5_layout = {
> 
> static const struct
> 
>> +    .grs = 0x30,
>> +    .gws = 0x38,
>> +    .grws = 0x40,
>> +    .grwr = 0x44,
>> +    .gswr = 0x48,
>> +    .gsws = 0x4C,
>> +    .gswf = 0x50,
>> +    .chan_cc_reg_base = 0x60,
> 
> one may find these plain offsets as too raw and probably prefer some defines
> for them, but I too think that the members of the struct are self-explanatory,
> so I'm ok either way.
> 
>> +    .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))
>> @@ -204,8 +250,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);
>>   
>>      /*
>> @@ -400,6 +448,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) {
>> @@ -407,12 +456,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);
> 
> very odd for me to see the "|" operator on the next line. I find it hard to
> read and somehow exhausting. I would put it on the first line even if 
> throughout
> the driver it's on the next line.
> 
>> +
>>              csize = ffs(atchan->sconfig.src_maxburst) - 1;
>>              if (csize < 0) {
>>                      dev_err(chan2dev(chan), "invalid src maxburst value\n");
>> @@ -430,12 +481,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");
>> @@ -711,6 +764,7 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
>>                              struct data_chunk *chunk)
>>   {
>>      struct at_xdmac_desc    *desc;
>> +    struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
>>      u32                     dwidth;
>>      unsigned long           flags;
>>      size_t                  ublen;
>> @@ -727,10 +781,10 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
>>       * flag status.
>>       */
>>      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;
>> +    if (atxdmac->layout->sdif)
>> +            chan_cc |= AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0);
> 
> there is a comment above chan_cc init that explains that we have to use
> interface 0 for both source and destination, so maybe we can get rid of
> this explicit OR with zero and update the comment for sama7g5 case.
> 
>>   
>>      dwidth = at_xdmac_align_width(chan, src | dst | chunk->size);
>>      if (chunk->size >= (AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth)) {
>> @@ -893,6 +947,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, 
>> dma_addr_t dest, dma_addr_t src,
>>                       size_t len, unsigned long flags)
>>   {
>>      struct at_xdmac_chan    *atchan = to_at_xdmac_chan(chan);
>> +    struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
>>      struct at_xdmac_desc    *first = NULL, *prev = NULL;
>>      size_t                  remaining_size = len, xfer_size = 0, ublen;
>>      dma_addr_t              src_addr = src, dst_addr = dest;
>> @@ -911,12 +966,13 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, 
>> dma_addr_t dest, dma_addr_t src,
>>      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;
>>   
>> +    if (atxdmac->layout->sdif)
>> +            chan_cc |= AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0);
> 
> same here
> 
>> +
>>      dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, len=%zd, 
>> flags=0x%lx\n",
>>              __func__, &src, &dest, len, flags);
>>   
>> @@ -999,6 +1055,7 @@ static struct at_xdmac_desc 
>> *at_xdmac_memset_create_desc(struct dma_chan *chan,
>>                                                       int value)
>>   {
>>      struct at_xdmac_desc    *desc;
>> +    struct at_xdmac         *atxdmac = to_at_xdmac(atchan->chan.device);
>>      unsigned long           flags;
>>      size_t                  ublen;
>>      u32                     dwidth;
>> @@ -1017,11 +1074,11 @@ static struct at_xdmac_desc 
>> *at_xdmac_memset_create_desc(struct dma_chan *chan,
>>      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;
>> +    if (atxdmac->layout->sdif)
>> +            chan_cc |= AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0);
> 
> same here
> 
>>   
>>      dwidth = at_xdmac_align_width(chan, dst_addr);
>>   
>> @@ -1297,7 +1354,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();
>>      }
>> @@ -1355,7 +1412,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();
>>      }
>> @@ -1620,7 +1677,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();
>> @@ -1643,7 +1700,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);
>>   
>> @@ -1845,6 +1902,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;
> 
> I would get the data upper in the function, after getting irq. If data is
> not provided, you would spare some ops that will be done gratuitously.

Hi Tudor,

This would be difficult to do as atxdmac is allocated just a few lines 
before.
Also, actually the get_match_data should not fail normally. If this 
would fail it would mean that the driver is probed to a wrong driver 
compatible... which should not happen.

Thanks for reviewing. I am sending v2.

Eugen

> 
> With these addressed one may add:
> Reviewed-by: Tudor Ambarus <tudor.amba...@microchip.com>
>> +
>>      atxdmac->clk = devm_clk_get(&pdev->dev, "dma_clk");
>>      if (IS_ERR(atxdmac->clk)) {
>>              dev_err(&pdev->dev, "can't get dma_clk\n");
>> @@ -1988,6 +2049,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 */
>>      }
>> diff --git a/drivers/dma/at_xdmac_regs.h b/drivers/dma/at_xdmac_regs.h
>> index 3f7dda4c5743..7b4b4e24de70 100644
>> --- a/drivers/dma/at_xdmac_regs.h
>> +++ b/drivers/dma/at_xdmac_regs.h
>> @@ -22,13 +22,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 */
>> @@ -134,8 +127,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 */
>>
> 

Reply via email to