aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLudovic Desroches <ludovic.desroches@atmel.com>2015-06-08 04:33:15 -0400
committerVinod Koul <vinod.koul@intel.com>2015-06-08 06:57:09 -0400
commit765c37d876698268eea8b820081ac8fc9d0fc8bc (patch)
treef3c746b11069e14f6e80e3015aa4e334085511ff
parent4c374fc7ce944024936a6d9804daec85207d9384 (diff)
dmaengine: at_xdmac: rework slave configuration part
Rework slave configuration part in order to more report wrong errors about the configuration. Only maxburst and addr width values are checked when doing the slave configuration. The validity of the channel configuration is done at prepare time. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Cc: stable@vger.kernel.org # 4.0 and later Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/at_xdmac.c156
1 files changed, 96 insertions, 60 deletions
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 0dcc9a7a90af..7992164ea9ec 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -174,6 +174,8 @@
174#define AT_XDMAC_MBR_UBC_NDV3 (0x3 << 27) /* Next Descriptor View 3 */ 174#define AT_XDMAC_MBR_UBC_NDV3 (0x3 << 27) /* Next Descriptor View 3 */
175 175
176#define AT_XDMAC_MAX_CHAN 0x20 176#define AT_XDMAC_MAX_CHAN 0x20
177#define AT_XDMAC_MAX_CSIZE 16 /* 16 data */
178#define AT_XDMAC_MAX_DWIDTH 8 /* 64 bits */
177 179
178#define AT_XDMAC_DMA_BUSWIDTHS\ 180#define AT_XDMAC_DMA_BUSWIDTHS\
179 (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\ 181 (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
@@ -192,20 +194,17 @@ struct at_xdmac_chan {
192 struct dma_chan chan; 194 struct dma_chan chan;
193 void __iomem *ch_regs; 195 void __iomem *ch_regs;
194 u32 mask; /* Channel Mask */ 196 u32 mask; /* Channel Mask */
195 u32 cfg[2]; /* Channel Configuration Register */ 197 u32 cfg; /* Channel Configuration Register */
196 #define AT_XDMAC_DEV_TO_MEM_CFG 0 /* Predifined dev to mem channel conf */
197 #define AT_XDMAC_MEM_TO_DEV_CFG 1 /* Predifined mem to dev channel conf */
198 u8 perid; /* Peripheral ID */ 198 u8 perid; /* Peripheral ID */
199 u8 perif; /* Peripheral Interface */ 199 u8 perif; /* Peripheral Interface */
200 u8 memif; /* Memory Interface */ 200 u8 memif; /* Memory Interface */
201 u32 per_src_addr;
202 u32 per_dst_addr;
203 u32 save_cc; 201 u32 save_cc;
204 u32 save_cim; 202 u32 save_cim;
205 u32 save_cnda; 203 u32 save_cnda;
206 u32 save_cndc; 204 u32 save_cndc;
207 unsigned long status; 205 unsigned long status;
208 struct tasklet_struct tasklet; 206 struct tasklet_struct tasklet;
207 struct dma_slave_config sconfig;
209 208
210 spinlock_t lock; 209 spinlock_t lock;
211 210
@@ -495,61 +494,94 @@ static struct dma_chan *at_xdmac_xlate(struct of_phandle_args *dma_spec,
495 return chan; 494 return chan;
496} 495}
497 496
497static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
498 enum dma_transfer_direction direction)
499{
500 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
501 int csize, dwidth;
502
503 if (direction == DMA_DEV_TO_MEM) {
504 atchan->cfg =
505 AT91_XDMAC_DT_PERID(atchan->perid)
506 | AT_XDMAC_CC_DAM_INCREMENTED_AM
507 | AT_XDMAC_CC_SAM_FIXED_AM
508 | AT_XDMAC_CC_DIF(atchan->memif)
509 | AT_XDMAC_CC_SIF(atchan->perif)
510 | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
511 | AT_XDMAC_CC_DSYNC_PER2MEM
512 | AT_XDMAC_CC_MBSIZE_SIXTEEN
513 | AT_XDMAC_CC_TYPE_PER_TRAN;
514 csize = ffs(atchan->sconfig.src_maxburst) - 1;
515 if (csize < 0) {
516 dev_err(chan2dev(chan), "invalid src maxburst value\n");
517 return -EINVAL;
518 }
519 atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
520 dwidth = ffs(atchan->sconfig.src_addr_width) - 1;
521 if (dwidth < 0) {
522 dev_err(chan2dev(chan), "invalid src addr width value\n");
523 return -EINVAL;
524 }
525 atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
526 } else if (direction == DMA_MEM_TO_DEV) {
527 atchan->cfg =
528 AT91_XDMAC_DT_PERID(atchan->perid)
529 | AT_XDMAC_CC_DAM_FIXED_AM
530 | AT_XDMAC_CC_SAM_INCREMENTED_AM
531 | AT_XDMAC_CC_DIF(atchan->perif)
532 | AT_XDMAC_CC_SIF(atchan->memif)
533 | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
534 | AT_XDMAC_CC_DSYNC_MEM2PER
535 | AT_XDMAC_CC_MBSIZE_SIXTEEN
536 | AT_XDMAC_CC_TYPE_PER_TRAN;
537 csize = ffs(atchan->sconfig.dst_maxburst) - 1;
538 if (csize < 0) {
539 dev_err(chan2dev(chan), "invalid src maxburst value\n");
540 return -EINVAL;
541 }
542 atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
543 dwidth = ffs(atchan->sconfig.dst_addr_width) - 1;
544 if (dwidth < 0) {
545 dev_err(chan2dev(chan), "invalid dst addr width value\n");
546 return -EINVAL;
547 }
548 atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
549 }
550
551 dev_dbg(chan2dev(chan), "%s: cfg=0x%08x\n", __func__, atchan->cfg);
552
553 return 0;
554}
555
556/*
557 * Only check that maxburst and addr width values are supported by the
558 * the controller but not that the configuration is good to perform the
559 * transfer since we don't know the direction at this stage.
560 */
561static int at_xdmac_check_slave_config(struct dma_slave_config *sconfig)
562{
563 if ((sconfig->src_maxburst > AT_XDMAC_MAX_CSIZE)
564 || (sconfig->dst_maxburst > AT_XDMAC_MAX_CSIZE))
565 return -EINVAL;
566
567 if ((sconfig->src_addr_width > AT_XDMAC_MAX_DWIDTH)
568 || (sconfig->dst_addr_width > AT_XDMAC_MAX_DWIDTH))
569 return -EINVAL;
570
571 return 0;
572}
573
498static int at_xdmac_set_slave_config(struct dma_chan *chan, 574static int at_xdmac_set_slave_config(struct dma_chan *chan,
499 struct dma_slave_config *sconfig) 575 struct dma_slave_config *sconfig)
500{ 576{
501 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); 577 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
502 u8 dwidth;
503 int csize;
504 578
505 atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] = 579 if (at_xdmac_check_slave_config(sconfig)) {
506 AT91_XDMAC_DT_PERID(atchan->perid) 580 dev_err(chan2dev(chan), "invalid slave configuration\n");
507 | AT_XDMAC_CC_DAM_INCREMENTED_AM
508 | AT_XDMAC_CC_SAM_FIXED_AM
509 | AT_XDMAC_CC_DIF(atchan->memif)
510 | AT_XDMAC_CC_SIF(atchan->perif)
511 | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
512 | AT_XDMAC_CC_DSYNC_PER2MEM
513 | AT_XDMAC_CC_MBSIZE_SIXTEEN
514 | AT_XDMAC_CC_TYPE_PER_TRAN;
515 csize = at_xdmac_csize(sconfig->src_maxburst);
516 if (csize < 0) {
517 dev_err(chan2dev(chan), "invalid src maxburst value\n");
518 return -EINVAL; 581 return -EINVAL;
519 } 582 }
520 atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_CSIZE(csize);
521 dwidth = ffs(sconfig->src_addr_width) - 1;
522 atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth);
523
524
525 atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] =
526 AT91_XDMAC_DT_PERID(atchan->perid)
527 | AT_XDMAC_CC_DAM_FIXED_AM
528 | AT_XDMAC_CC_SAM_INCREMENTED_AM
529 | AT_XDMAC_CC_DIF(atchan->perif)
530 | AT_XDMAC_CC_SIF(atchan->memif)
531 | AT_XDMAC_CC_SWREQ_HWR_CONNECTED
532 | AT_XDMAC_CC_DSYNC_MEM2PER
533 | AT_XDMAC_CC_MBSIZE_SIXTEEN
534 | AT_XDMAC_CC_TYPE_PER_TRAN;
535 csize = at_xdmac_csize(sconfig->dst_maxburst);
536 if (csize < 0) {
537 dev_err(chan2dev(chan), "invalid src maxburst value\n");
538 return -EINVAL;
539 }
540 atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_CSIZE(csize);
541 dwidth = ffs(sconfig->dst_addr_width) - 1;
542 atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth);
543
544 /* Src and dst addr are needed to configure the link list descriptor. */
545 atchan->per_src_addr = sconfig->src_addr;
546 atchan->per_dst_addr = sconfig->dst_addr;
547 583
548 dev_dbg(chan2dev(chan), 584 memcpy(&atchan->sconfig, sconfig, sizeof(atchan->sconfig));
549 "%s: cfg[dev2mem]=0x%08x, cfg[mem2dev]=0x%08x, per_src_addr=0x%08x, per_dst_addr=0x%08x\n",
550 __func__, atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG],
551 atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG],
552 atchan->per_src_addr, atchan->per_dst_addr);
553 585
554 return 0; 586 return 0;
555} 587}
@@ -583,6 +615,9 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
583 /* Protect dma_sconfig field that can be modified by set_slave_conf. */ 615 /* Protect dma_sconfig field that can be modified by set_slave_conf. */
584 spin_lock_irqsave(&atchan->lock, irqflags); 616 spin_lock_irqsave(&atchan->lock, irqflags);
585 617
618 if (at_xdmac_compute_chan_conf(chan, direction))
619 goto spin_unlock;
620
586 /* Prepare descriptors. */ 621 /* Prepare descriptors. */
587 for_each_sg(sgl, sg, sg_len, i) { 622 for_each_sg(sgl, sg, sg_len, i) {
588 struct at_xdmac_desc *desc = NULL; 623 struct at_xdmac_desc *desc = NULL;
@@ -607,14 +642,13 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
607 642
608 /* Linked list descriptor setup. */ 643 /* Linked list descriptor setup. */
609 if (direction == DMA_DEV_TO_MEM) { 644 if (direction == DMA_DEV_TO_MEM) {
610 desc->lld.mbr_sa = atchan->per_src_addr; 645 desc->lld.mbr_sa = atchan->sconfig.src_addr;
611 desc->lld.mbr_da = mem; 646 desc->lld.mbr_da = mem;
612 desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
613 } else { 647 } else {
614 desc->lld.mbr_sa = mem; 648 desc->lld.mbr_sa = mem;
615 desc->lld.mbr_da = atchan->per_dst_addr; 649 desc->lld.mbr_da = atchan->sconfig.dst_addr;
616 desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
617 } 650 }
651 desc->lld.mbr_cfg = atchan->cfg;
618 dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg); 652 dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
619 fixed_dwidth = IS_ALIGNED(len, 1 << dwidth) 653 fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
620 ? at_xdmac_get_dwidth(desc->lld.mbr_cfg) 654 ? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
@@ -683,6 +717,9 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
683 return NULL; 717 return NULL;
684 } 718 }
685 719
720 if (at_xdmac_compute_chan_conf(chan, direction))
721 return NULL;
722
686 for (i = 0; i < periods; i++) { 723 for (i = 0; i < periods; i++) {
687 struct at_xdmac_desc *desc = NULL; 724 struct at_xdmac_desc *desc = NULL;
688 725
@@ -701,14 +738,13 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
701 __func__, desc, &desc->tx_dma_desc.phys); 738 __func__, desc, &desc->tx_dma_desc.phys);
702 739
703 if (direction == DMA_DEV_TO_MEM) { 740 if (direction == DMA_DEV_TO_MEM) {
704 desc->lld.mbr_sa = atchan->per_src_addr; 741 desc->lld.mbr_sa = atchan->sconfig.src_addr;
705 desc->lld.mbr_da = buf_addr + i * period_len; 742 desc->lld.mbr_da = buf_addr + i * period_len;
706 desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
707 } else { 743 } else {
708 desc->lld.mbr_sa = buf_addr + i * period_len; 744 desc->lld.mbr_sa = buf_addr + i * period_len;
709 desc->lld.mbr_da = atchan->per_dst_addr; 745 desc->lld.mbr_da = atchan->sconfig.dst_addr;
710 desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
711 } 746 }
747 desc->lld.mbr_cfg = atchan->cfg;
712 desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1 748 desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1
713 | AT_XDMAC_MBR_UBC_NDEN 749 | AT_XDMAC_MBR_UBC_NDEN
714 | AT_XDMAC_MBR_UBC_NSEN 750 | AT_XDMAC_MBR_UBC_NSEN