+96
-60
drivers/dma/at_xdmac.c
+96
-60
drivers/dma/at_xdmac.c
···
174
174
#define AT_XDMAC_MBR_UBC_NDV3 (0x3 << 27) /* Next Descriptor View 3 */
175
175
176
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
180
#define AT_XDMAC_DMA_BUSWIDTHS\
179
181
(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
···
194
192
struct dma_chan chan;
195
193
void __iomem *ch_regs;
196
194
u32 mask; /* Channel Mask */
197
-
u32 cfg[2]; /* Channel Configuration Register */
198
-
#define AT_XDMAC_DEV_TO_MEM_CFG 0 /* Predifined dev to mem channel conf */
199
-
#define AT_XDMAC_MEM_TO_DEV_CFG 1 /* Predifined mem to dev channel conf */
195
+
u32 cfg; /* Channel Configuration Register */
200
196
u8 perid; /* Peripheral ID */
201
197
u8 perif; /* Peripheral Interface */
202
198
u8 memif; /* Memory Interface */
203
-
u32 per_src_addr;
204
-
u32 per_dst_addr;
205
199
u32 save_cc;
206
200
u32 save_cim;
207
201
u32 save_cnda;
208
202
u32 save_cndc;
209
203
unsigned long status;
210
204
struct tasklet_struct tasklet;
205
+
struct dma_slave_config sconfig;
211
206
212
207
spinlock_t lock;
213
208
···
494
495
return chan;
495
496
}
496
497
498
+
static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
499
+
enum dma_transfer_direction direction)
500
+
{
501
+
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
502
+
int csize, dwidth;
503
+
504
+
if (direction == DMA_DEV_TO_MEM) {
505
+
atchan->cfg =
506
+
AT91_XDMAC_DT_PERID(atchan->perid)
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 = ffs(atchan->sconfig.src_maxburst) - 1;
516
+
if (csize < 0) {
517
+
dev_err(chan2dev(chan), "invalid src maxburst value\n");
518
+
return -EINVAL;
519
+
}
520
+
atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
521
+
dwidth = ffs(atchan->sconfig.src_addr_width) - 1;
522
+
if (dwidth < 0) {
523
+
dev_err(chan2dev(chan), "invalid src addr width value\n");
524
+
return -EINVAL;
525
+
}
526
+
atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
527
+
} else if (direction == DMA_MEM_TO_DEV) {
528
+
atchan->cfg =
529
+
AT91_XDMAC_DT_PERID(atchan->perid)
530
+
| AT_XDMAC_CC_DAM_FIXED_AM
531
+
| AT_XDMAC_CC_SAM_INCREMENTED_AM
532
+
| AT_XDMAC_CC_DIF(atchan->perif)
533
+
| AT_XDMAC_CC_SIF(atchan->memif)
534
+
| AT_XDMAC_CC_SWREQ_HWR_CONNECTED
535
+
| AT_XDMAC_CC_DSYNC_MEM2PER
536
+
| AT_XDMAC_CC_MBSIZE_SIXTEEN
537
+
| AT_XDMAC_CC_TYPE_PER_TRAN;
538
+
csize = ffs(atchan->sconfig.dst_maxburst) - 1;
539
+
if (csize < 0) {
540
+
dev_err(chan2dev(chan), "invalid src maxburst value\n");
541
+
return -EINVAL;
542
+
}
543
+
atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
544
+
dwidth = ffs(atchan->sconfig.dst_addr_width) - 1;
545
+
if (dwidth < 0) {
546
+
dev_err(chan2dev(chan), "invalid dst addr width value\n");
547
+
return -EINVAL;
548
+
}
549
+
atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
550
+
}
551
+
552
+
dev_dbg(chan2dev(chan), "%s: cfg=0x%08x\n", __func__, atchan->cfg);
553
+
554
+
return 0;
555
+
}
556
+
557
+
/*
558
+
* Only check that maxburst and addr width values are supported by the
559
+
* the controller but not that the configuration is good to perform the
560
+
* transfer since we don't know the direction at this stage.
561
+
*/
562
+
static int at_xdmac_check_slave_config(struct dma_slave_config *sconfig)
563
+
{
564
+
if ((sconfig->src_maxburst > AT_XDMAC_MAX_CSIZE)
565
+
|| (sconfig->dst_maxburst > AT_XDMAC_MAX_CSIZE))
566
+
return -EINVAL;
567
+
568
+
if ((sconfig->src_addr_width > AT_XDMAC_MAX_DWIDTH)
569
+
|| (sconfig->dst_addr_width > AT_XDMAC_MAX_DWIDTH))
570
+
return -EINVAL;
571
+
572
+
return 0;
573
+
}
574
+
497
575
static int at_xdmac_set_slave_config(struct dma_chan *chan,
498
576
struct dma_slave_config *sconfig)
499
577
{
500
578
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
501
-
u8 dwidth;
502
-
int csize;
503
579
504
-
atchan->cfg[AT_XDMAC_DEV_TO_MEM_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 = at_xdmac_csize(sconfig->src_maxburst);
515
-
if (csize < 0) {
516
-
dev_err(chan2dev(chan), "invalid src maxburst value\n");
580
+
if (at_xdmac_check_slave_config(sconfig)) {
581
+
dev_err(chan2dev(chan), "invalid slave configuration\n");
517
582
return -EINVAL;
518
583
}
519
-
atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_CSIZE(csize);
520
-
dwidth = ffs(sconfig->src_addr_width) - 1;
521
-
atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth);
522
584
523
-
524
-
atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] =
525
-
AT91_XDMAC_DT_PERID(atchan->perid)
526
-
| AT_XDMAC_CC_DAM_FIXED_AM
527
-
| AT_XDMAC_CC_SAM_INCREMENTED_AM
528
-
| AT_XDMAC_CC_DIF(atchan->perif)
529
-
| AT_XDMAC_CC_SIF(atchan->memif)
530
-
| AT_XDMAC_CC_SWREQ_HWR_CONNECTED
531
-
| AT_XDMAC_CC_DSYNC_MEM2PER
532
-
| AT_XDMAC_CC_MBSIZE_SIXTEEN
533
-
| AT_XDMAC_CC_TYPE_PER_TRAN;
534
-
csize = at_xdmac_csize(sconfig->dst_maxburst);
535
-
if (csize < 0) {
536
-
dev_err(chan2dev(chan), "invalid src maxburst value\n");
537
-
return -EINVAL;
538
-
}
539
-
atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_CSIZE(csize);
540
-
dwidth = ffs(sconfig->dst_addr_width) - 1;
541
-
atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth);
542
-
543
-
/* Src and dst addr are needed to configure the link list descriptor. */
544
-
atchan->per_src_addr = sconfig->src_addr;
545
-
atchan->per_dst_addr = sconfig->dst_addr;
546
-
547
-
dev_dbg(chan2dev(chan),
548
-
"%s: cfg[dev2mem]=0x%08x, cfg[mem2dev]=0x%08x, per_src_addr=0x%08x, per_dst_addr=0x%08x\n",
549
-
__func__, atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG],
550
-
atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG],
551
-
atchan->per_src_addr, atchan->per_dst_addr);
585
+
memcpy(&atchan->sconfig, sconfig, sizeof(atchan->sconfig));
552
586
553
587
return 0;
554
588
}
···
615
583
/* Protect dma_sconfig field that can be modified by set_slave_conf. */
616
584
spin_lock_irqsave(&atchan->lock, irqflags);
617
585
586
+
if (at_xdmac_compute_chan_conf(chan, direction))
587
+
goto spin_unlock;
588
+
618
589
/* Prepare descriptors. */
619
590
for_each_sg(sgl, sg, sg_len, i) {
620
591
struct at_xdmac_desc *desc = NULL;
···
642
607
643
608
/* Linked list descriptor setup. */
644
609
if (direction == DMA_DEV_TO_MEM) {
645
-
desc->lld.mbr_sa = atchan->per_src_addr;
610
+
desc->lld.mbr_sa = atchan->sconfig.src_addr;
646
611
desc->lld.mbr_da = mem;
647
-
desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
648
612
} else {
649
613
desc->lld.mbr_sa = mem;
650
-
desc->lld.mbr_da = atchan->per_dst_addr;
651
-
desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
614
+
desc->lld.mbr_da = atchan->sconfig.dst_addr;
652
615
}
616
+
desc->lld.mbr_cfg = atchan->cfg;
653
617
dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
654
618
fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
655
619
? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
···
717
683
return NULL;
718
684
}
719
685
686
+
if (at_xdmac_compute_chan_conf(chan, direction))
687
+
return NULL;
688
+
720
689
for (i = 0; i < periods; i++) {
721
690
struct at_xdmac_desc *desc = NULL;
722
691
···
738
701
__func__, desc, &desc->tx_dma_desc.phys);
739
702
740
703
if (direction == DMA_DEV_TO_MEM) {
741
-
desc->lld.mbr_sa = atchan->per_src_addr;
704
+
desc->lld.mbr_sa = atchan->sconfig.src_addr;
742
705
desc->lld.mbr_da = buf_addr + i * period_len;
743
-
desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
744
706
} else {
745
707
desc->lld.mbr_sa = buf_addr + i * period_len;
746
-
desc->lld.mbr_da = atchan->per_dst_addr;
747
-
desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
708
+
desc->lld.mbr_da = atchan->sconfig.dst_addr;
748
709
}
710
+
desc->lld.mbr_cfg = atchan->cfg;
749
711
desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1
750
712
| AT_XDMAC_MBR_UBC_NDEN
751
713
| AT_XDMAC_MBR_UBC_NSEN