Skip to content

Commit d26ab6a

Browse files
committed
Enable Synopsys DesignWare AXI DMA support for StarFive SOC
Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
1 parent cd28d6f commit d26ab6a

3 files changed

Lines changed: 123 additions & 42 deletions

File tree

arch/riscv/configs/visionfive_defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ CONFIG_LEDS_TRIGGERS=y
161161
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
162162
CONFIG_DMADEVICES=y
163163
CONFIG_DW_AXI_DMAC=y
164+
CONFIG_DW_AXI_DMAC_STARFIVE=y
164165
CONFIG_DMABUF_HEAPS=y
165166
CONFIG_DMABUF_HEAPS_SYSTEM=y
166167
# CONFIG_VIRTIO_MENU is not set

drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c

Lines changed: 108 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -360,17 +360,44 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
360360
u32 reg, irq_mask;
361361
u8 lms = 0; /* Select AXI0 master for LLI fetching */
362362

363+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
364+
chan->is_err = false;
365+
if (unlikely(axi_chan_is_hw_enable(chan))) {
366+
dev_dbg(chan2dev(chan), "%s is non-idle!\n",
367+
axi_chan_name(chan));
368+
369+
axi_chan_disable(chan);
370+
chan->is_err = true;
371+
}
372+
#else
363373
if (unlikely(axi_chan_is_hw_enable(chan))) {
364374
dev_err(chan2dev(chan), "%s is non-idle!\n",
365375
axi_chan_name(chan));
366376

367377
return;
368378
}
379+
#endif
369380

370381
axi_dma_enable(chan->chip);
371382

372383
reg = (DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_DST_MULTBLK_TYPE_POS |
373384
DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
385+
386+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
387+
if (chan->hw_handshake_num) {
388+
switch (chan->direction) {
389+
case DMA_MEM_TO_DEV:
390+
reg |= chan->hw_handshake_num << CH_CFG_L_SRC_PER_POS;
391+
break;
392+
case DMA_DEV_TO_MEM:
393+
reg |= chan->hw_handshake_num << CH_CFG_L_DST_PER_POS;
394+
break;
395+
default:
396+
break;
397+
}
398+
}
399+
#endif
400+
374401
axi_chan_iowrite32(chan, CH_CFG_L, reg);
375402

376403
reg = (DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC << CH_CFG_H_TT_FC_POS |
@@ -384,16 +411,12 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
384411
DWAXIDMAC_TT_FC_MEM_TO_PER_DST :
385412
DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC)
386413
<< CH_CFG_H_TT_FC_POS;
387-
if (chan->chip->apb_regs)
388-
reg |= (chan->id << CH_CFG_H_DST_PER_POS);
389414
break;
390415
case DMA_DEV_TO_MEM:
391416
reg |= (chan->config.device_fc ?
392417
DWAXIDMAC_TT_FC_PER_TO_MEM_SRC :
393418
DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC)
394419
<< CH_CFG_H_TT_FC_POS;
395-
if (chan->chip->apb_regs)
396-
reg |= (chan->id << CH_CFG_H_SRC_PER_POS);
397420
break;
398421
default:
399422
break;
@@ -410,7 +433,7 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
410433
axi_chan_irq_set(chan, irq_mask);
411434

412435
/* flush all the desc */
413-
#ifdef CONFIG_SOC_STARFIVE
436+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
414437
if (chan->chip->flag->need_flush) {
415438
int count = atomic_read(&chan->descs_allocated);
416439
int i;
@@ -516,10 +539,15 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan)
516539
pm_runtime_put(chan->chip->dev);
517540
}
518541

519-
static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set)
542+
static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip,
543+
u32 handshake_num, bool set)
520544
{
521-
struct axi_dma_chip *chip = chan->chip;
522-
unsigned long reg_value, val;
545+
unsigned long start = 0;
546+
unsigned long reg_value;
547+
unsigned long reg_mask;
548+
unsigned long reg_set;
549+
unsigned long mask;
550+
unsigned long val;
523551

524552
if (!chip->apb_regs) {
525553
dev_err(chip->dev, "apb_regs not initialized\n");
@@ -531,22 +559,26 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set)
531559
* Lock the DMA channel by assign a handshake number to the channel.
532560
* Unlock the DMA channel by assign 0x3F to the channel.
533561
*/
534-
if (set)
535-
val = chan->hw_handshake_num;
536-
else
562+
if (set) {
563+
reg_set = UNUSED_CHANNEL;
564+
val = handshake_num;
565+
} else {
566+
reg_set = handshake_num;
537567
val = UNUSED_CHANNEL;
568+
}
538569

539570
reg_value = lo_hi_readq(chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
540571

541-
/* Channel is already allocated, set handshake as per channel ID */
542-
/* 64 bit write should handle for 8 channels */
543-
544-
reg_value &= ~(DMA_APB_HS_SEL_MASK <<
545-
(chan->id * DMA_APB_HS_SEL_BIT_SIZE));
546-
reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE));
547-
lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
548-
549-
return;
572+
for_each_set_clump8(start, reg_mask, &reg_value, 64) {
573+
if (reg_mask == reg_set) {
574+
mask = GENMASK_ULL(start + 7, start);
575+
reg_value &= ~mask;
576+
reg_value |= rol64(val, start);
577+
lo_hi_writeq(reg_value,
578+
chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
579+
break;
580+
}
581+
}
550582
}
551583

552584
/*
@@ -674,8 +706,13 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
674706

675707
hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
676708

709+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
710+
ctllo |= DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_DST_MSIZE_POS |
711+
DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_SRC_MSIZE_POS;
712+
#else
677713
ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
678714
DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
715+
#endif
679716
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
680717

681718
set_desc_src_master(hw_desc);
@@ -779,7 +816,7 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr,
779816
llp = hw_desc->llp;
780817
} while (total_segments);
781818

782-
dw_axi_dma_set_hw_channel(chan, true);
819+
dw_axi_dma_set_hw_channel(chan->chip, chan->hw_handshake_num, true);
783820

784821
return vchan_tx_prep(&chan->vc, &desc->vd, flags);
785822

@@ -859,7 +896,7 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
859896
llp = hw_desc->llp;
860897
} while (num_sgs);
861898

862-
dw_axi_dma_set_hw_channel(chan, true);
899+
dw_axi_dma_set_hw_channel(chan->chip, chan->hw_handshake_num, true);
863900

864901
return vchan_tx_prep(&chan->vc, &desc->vd, flags);
865902

@@ -1010,26 +1047,44 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
10101047
{
10111048
struct virt_dma_desc *vd;
10121049
unsigned long flags;
1013-
1050+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
1051+
struct axi_dma_desc *desc;
1052+
#endif
10141053
spin_lock_irqsave(&chan->vc.lock, flags);
10151054

10161055
axi_chan_disable(chan);
10171056

10181057
/* The bad descriptor currently is in the head of vc list */
10191058
vd = vchan_next_desc(&chan->vc);
1020-
/* Remove the completed descriptor from issued list */
1021-
list_del(&vd->node);
1059+
if (!vd) {
1060+
dev_warn(chan2dev(chan),
1061+
"%s vd is null\n", axi_chan_name(chan));
1062+
spin_unlock_irqrestore(&chan->vc.lock, flags);
1063+
return;
1064+
}
1065+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
1066+
if (chan->is_err) {
1067+
desc = vd_to_axi_desc(vd);
1068+
axi_chan_block_xfer_start(chan, desc);
1069+
chan->is_err = false;
1070+
} else {
1071+
#endif
1072+
/* Remove the completed descriptor from issued list */
1073+
list_del(&vd->node);
10221074

1023-
/* WARN about bad descriptor */
1024-
dev_err(chan2dev(chan),
1025-
"Bad descriptor submitted for %s, cookie: %d, irq: 0x%08x\n",
1026-
axi_chan_name(chan), vd->tx.cookie, status);
1027-
axi_chan_list_dump_lli(chan, vd_to_axi_desc(vd));
1075+
/* WARN about bad descriptor */
1076+
dev_err(chan2dev(chan),
1077+
"Bad descriptor submitted for %s, cookie: %d, irq: 0x%08x\n",
1078+
axi_chan_name(chan), vd->tx.cookie, status);
1079+
axi_chan_list_dump_lli(chan, vd_to_axi_desc(vd));
10281080

1029-
vchan_cookie_complete(vd);
1081+
vchan_cookie_complete(vd);
10301082

1031-
/* Try to restart the controller */
1032-
axi_chan_start_first_queued(chan);
1083+
/* Try to restart the controller */
1084+
axi_chan_start_first_queued(chan);
1085+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
1086+
}
1087+
#endif
10331088

10341089
spin_unlock_irqrestore(&chan->vc.lock, flags);
10351090
}
@@ -1053,6 +1108,12 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
10531108

10541109
/* The completed descriptor currently is in the head of vc list */
10551110
vd = vchan_next_desc(&chan->vc);
1111+
if (!vd) {
1112+
dev_err(chan2dev(chan),
1113+
"%s vd is null\n", axi_chan_name(chan));
1114+
spin_unlock_irqrestore(&chan->vc.lock, flags);
1115+
return;
1116+
}
10561117

10571118
if (chan->cyclic) {
10581119
desc = vd_to_axi_desc(vd);
@@ -1110,7 +1171,7 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id)
11101171
else if (status & DWAXIDMAC_IRQ_DMA_TRF) {
11111172
axi_chan_block_xfer_complete(chan);
11121173
dev_dbg(chip->dev, "axi_chan_block_xfer_complete.\n");
1113-
}
1174+
}
11141175
}
11151176

11161177
/* Re-enable interrupts */
@@ -1133,11 +1194,17 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)
11331194
ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val,
11341195
!(val & chan_active), 1000, 10000);
11351196
if (ret == -ETIMEDOUT)
1197+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
1198+
dev_dbg(dchan2dev(dchan),
1199+
"%s failed to stop\n", axi_chan_name(chan));
1200+
#else
11361201
dev_warn(dchan2dev(dchan),
11371202
"%s failed to stop\n", axi_chan_name(chan));
1203+
#endif
11381204

11391205
if (chan->direction != DMA_MEM_TO_MEM)
1140-
dw_axi_dma_set_hw_channel(chan, false);
1206+
dw_axi_dma_set_hw_channel(chan->chip,
1207+
chan->hw_handshake_num, false);
11411208
if (chan->direction == DMA_MEM_TO_DEV)
11421209
dw_axi_dma_set_byte_halfword(chan, false);
11431210

@@ -1301,7 +1368,7 @@ static int parse_device_properties(struct axi_dma_chip *chip)
13011368

13021369
if(chip->dw->hdata->nr_channels > 8){
13031370
chip->flag->nr_chan_8 = true;
1304-
#ifdef CONFIG_SOC_STARFIVE
1371+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
13051372
chip->flag->need_flush = true;
13061373
#endif
13071374
}
@@ -1354,7 +1421,7 @@ static int parse_device_properties(struct axi_dma_chip *chip)
13541421
return -EINVAL;
13551422

13561423
chip->dw->hdata->restrict_axi_burst_len = true;
1357-
chip->dw->hdata->axi_rw_burst_len = tmp;
1424+
chip->dw->hdata->axi_rw_burst_len = tmp - 1;
13581425
}
13591426

13601427
return 0;
@@ -1449,7 +1516,6 @@ static int dw_probe(struct platform_device *pdev)
14491516

14501517
/* DMA capabilities */
14511518
dw->dma.chancnt = hdata->nr_channels;
1452-
dw->dma.max_burst = hdata->axi_rw_burst_len;
14531519
dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS;
14541520
dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
14551521
dw->dma.directions = BIT(DMA_MEM_TO_MEM);
@@ -1478,7 +1544,11 @@ static int dw_probe(struct platform_device *pdev)
14781544
* Therefore, set constraint to 1024 * 4.
14791545
*/
14801546
dw->dma.dev->dma_parms = &dw->dma_parms;
1547+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
1548+
dma_set_max_seg_size(&pdev->dev, DMAC_MAX_BLK_SIZE);
1549+
#else
14811550
dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE);
1551+
#endif
14821552
platform_set_drvdata(pdev, chip);
14831553

14841554
pm_runtime_enable(chip->dev);

drivers/dma/dw-axi-dmac/dw-axi-dmac.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct axi_dma_chan {
5656
struct dma_slave_config config;
5757
enum dma_transfer_direction direction;
5858
bool cyclic;
59+
bool is_err;
5960
/* these other elements are all protected by vc.lock */
6061
bool is_paused;
6162
};
@@ -203,8 +204,6 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
203204
#define DMAC_APB_HALFWORD_WR_CH_EN 0x020 /* DMAC Halfword write enables */
204205

205206
#define UNUSED_CHANNEL 0x3F /* Set unused DMA channel to 0x3F */
206-
#define DMA_APB_HS_SEL_BIT_SIZE 0x08 /* HW handshake bits per channel */
207-
#define DMA_APB_HS_SEL_MASK 0xFF /* HW handshake select masks */
208207
#define MAX_BLOCK_SIZE 0x1000 /* 1024 blocks * 4 bytes data width */
209208

210209
/* DMAC_CFG */
@@ -290,8 +289,14 @@ enum {
290289

291290
/* CH_CFG_H */
292291
#define CH_CFG_H_PRIORITY_POS 15
293-
#define CH_CFG_H_DST_PER_POS 12
294-
#define CH_CFG_H_SRC_PER_POS 7
292+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
293+
#define CH_CFG_H_DST_HWHS_POL 6
294+
#define CH_CFG_H_SRC_HWHS_POL 5
295+
enum {
296+
DWAXIDMAC_HWHS_POL_ACTIVE_HIGH = 0,
297+
DWAXIDMAC_HWHS_POL_ACTIVE_LOW
298+
};
299+
#endif
295300
#define CH_CFG_H_HS_SEL_DST_POS 4
296301
#define CH_CFG_H_HS_SEL_SRC_POS 3
297302
enum {
@@ -314,6 +319,11 @@ enum {
314319
/* CH_CFG_L */
315320
#define CH_CFG_L_DST_MULTBLK_TYPE_POS 2
316321
#define CH_CFG_L_SRC_MULTBLK_TYPE_POS 0
322+
#ifdef CONFIG_DW_AXI_DMAC_STARFIVE
323+
#define CH_CFG_L_DST_PER_POS 4
324+
#define CH_CFG_L_SRC_PER_POS 11
325+
#endif
326+
317327
enum {
318328
DWAXIDMAC_MBLK_TYPE_CONTIGUOUS = 0,
319329
DWAXIDMAC_MBLK_TYPE_RELOAD,

0 commit comments

Comments
 (0)