Skip to content

Commit 148ecfe

Browse files
committed
dw-dma: use done bit for linked list transfers
Changes settings of GPDMA linked lists transfers to use done bit to let the DMA know, that the next data block is ready to be sent/received. This way we are sure, that there will be no additional data transferred between receiving interrupt and disabling GPDMA channel. Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
1 parent 7a2f8c2 commit 148ecfe

1 file changed

Lines changed: 51 additions & 10 deletions

File tree

src/drivers/dw-dma.c

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@
151151
#if defined (CONFIG_HASWELL) || defined (CONFIG_BROADWELL)
152152

153153
/* CTL_HI */
154-
#define DW_CTLH_DONE 0x00001000
154+
#define DW_CTLH_DONE(x) ((x) << 12)
155155
#define DW_CTLH_BLOCK_TS_MASK 0x00000fff
156156

157157
/* CFG_LO */
@@ -173,7 +173,7 @@
173173
#define DW_CTLL_D_SCAT_EN (1 << 18)
174174

175175
/* CTL_HI */
176-
#define DW_CTLH_DONE 0x00020000
176+
#define DW_CTLH_DONE(x) ((x) << 17)
177177
#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff
178178
#define DW_CTLH_CLASS(x) ((x) << 29)
179179
#define DW_CTLH_WEIGHT(x) ((x) << 18)
@@ -204,13 +204,16 @@
204204
#define DW_CTLL_D_SCAT_EN (1 << 18)
205205

206206
/* CTL_HI */
207-
#define DW_CTLH_DONE 0x00020000
207+
#define DW_CTLH_DONE(x) ((x) << 17)
208208
#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff
209-
#define DW_CTLH_CLASS(x) (x << 29)
210-
#define DW_CTLH_WEIGHT(x) (x << 18)
209+
#define DW_CTLH_CLASS(x) ((x) << 29)
210+
#define DW_CTLH_WEIGHT(x) ((x) << 18)
211211

212212
/* CFG_LO */
213-
#define DW_CFG_CH_DRAIN 0x400
213+
#define DW_CFG_CTL_HI_UPD_EN (1 << 5)
214+
#define DW_CFG_CH_DRAIN (1 << 10)
215+
#define DW_CFG_RELOAD_SRC (1 << 30)
216+
#define DW_CFG_RELOAD_DST (1 << 31)
214217

215218
/* CFG_HI */
216219
#define DW_CFGH_SRC_PER(x) (x << 0)
@@ -227,7 +230,7 @@
227230

228231
/* default initial setup register values */
229232
#define DW_CFG_LOW_DEF 0x00000003
230-
#define DW_CFG_HIGH_DEF 0x0
233+
#define DW_CFG_HIGH_DEF 0x0
231234

232235
#define DW_REG_MAX DW_DMA_GLB_CFG
233236
#endif
@@ -657,26 +660,43 @@ static int dw_dma_set_config(struct dma *dma, int channel,
657660
case DMA_DIR_LMEM_TO_HMEM:
658661
lli_desc->ctrl_lo |= DW_CTLL_FC_M2M;
659662
lli_desc->ctrl_lo |= DW_CTLL_SRC_INC | DW_CTLL_DST_INC;
663+
#if DW_USE_HW_LLI
664+
lli_desc->ctrl_lo |=
665+
DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN;
666+
#endif
660667
lli_desc->sar =
661668
(uint32_t)sg_elem->src | PLATFORM_HOST_DMA_MASK;
662669
lli_desc->dar = (uint32_t)sg_elem->dest;
663670
break;
664671
case DMA_DIR_HMEM_TO_LMEM:
665672
lli_desc->ctrl_lo |= DW_CTLL_FC_M2M;
666673
lli_desc->ctrl_lo |= DW_CTLL_SRC_INC | DW_CTLL_DST_INC;
674+
#if DW_USE_HW_LLI
675+
lli_desc->ctrl_lo |=
676+
DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN;
677+
#endif
667678
lli_desc->dar =
668679
(uint32_t)sg_elem->dest | PLATFORM_HOST_DMA_MASK;
669680
lli_desc->sar = (uint32_t)sg_elem->src;
670681
break;
671682
case DMA_DIR_MEM_TO_MEM:
672683
lli_desc->ctrl_lo |= DW_CTLL_FC_M2M;
673684
lli_desc->ctrl_lo |= DW_CTLL_SRC_INC | DW_CTLL_DST_INC;
685+
#if DW_USE_HW_LLI
686+
lli_desc->ctrl_lo |=
687+
DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN;
688+
#endif
674689
lli_desc->sar = (uint32_t)sg_elem->src | PLATFORM_HOST_DMA_MASK;
675690
lli_desc->dar = (uint32_t)sg_elem->dest | PLATFORM_HOST_DMA_MASK;
676691
break;
677692
case DMA_DIR_MEM_TO_DEV:
678693
lli_desc->ctrl_lo |= DW_CTLL_FC_M2P;
679694
lli_desc->ctrl_lo |= DW_CTLL_SRC_INC | DW_CTLL_DST_FIX;
695+
#if DW_USE_HW_LLI
696+
lli_desc->ctrl_lo |= DW_CTLL_LLP_S_EN;
697+
lli_desc->ctrl_hi |= DW_CTLH_DONE(1);
698+
p->chan[channel].cfg_lo |= DW_CFG_RELOAD_DST;
699+
#endif
680700
p->chan[channel].cfg_hi |=
681701
DW_CFGH_DST_PER(config->dest_dev);
682702
lli_desc->sar = (uint32_t)sg_elem->src | PLATFORM_HOST_DMA_MASK;
@@ -685,6 +705,11 @@ static int dw_dma_set_config(struct dma *dma, int channel,
685705
case DMA_DIR_DEV_TO_MEM:
686706
lli_desc->ctrl_lo |= DW_CTLL_FC_P2M;
687707
lli_desc->ctrl_lo |= DW_CTLL_SRC_FIX | DW_CTLL_DST_INC;
708+
#if DW_USE_HW_LLI
709+
lli_desc->ctrl_lo |= DW_CTLL_LLP_D_EN;
710+
lli_desc->ctrl_hi |= DW_CTLH_DONE(0);
711+
p->chan[channel].cfg_lo |= DW_CFG_RELOAD_SRC;
712+
#endif
688713
p->chan[channel].cfg_hi |=
689714
DW_CFGH_SRC_PER(config->src_dev);
690715
lli_desc->sar = (uint32_t)sg_elem->src;
@@ -693,6 +718,10 @@ static int dw_dma_set_config(struct dma *dma, int channel,
693718
case DMA_DIR_DEV_TO_DEV:
694719
lli_desc->ctrl_lo |= DW_CTLL_FC_P2P;
695720
lli_desc->ctrl_lo |= DW_CTLL_SRC_FIX | DW_CTLL_DST_FIX;
721+
#if DW_USE_HW_LLI
722+
lli_desc->ctrl_lo |=
723+
DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN;
724+
#endif
696725
p->chan[channel].cfg_hi |=
697726
DW_CFGH_SRC_PER(config->src_dev) |
698727
DW_CFGH_DST_PER(config->dest_dev);
@@ -724,13 +753,15 @@ static int dw_dma_set_config(struct dma *dma, int channel,
724753

725754
/* set next descriptor in list */
726755
lli_desc->llp = (uint32_t)(lli_desc + 1);
727-
#if DW_USE_HW_LLI
728-
lli_desc->ctrl_lo |= DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN;
729-
#endif
756+
730757
/* next descriptor */
731758
lli_desc++;
732759
}
733760

761+
#if DW_USE_HW_LLI
762+
p->chan[channel].cfg_lo |= DW_CFG_CTL_HI_UPD_EN;
763+
#endif
764+
734765
/* end of list or cyclic buffer ? */
735766
if (config->cyclic) {
736767
lli_desc_tail->llp = (uint32_t)lli_desc_head;
@@ -968,6 +999,11 @@ static void dw_dma_irq_handler(void *data)
968999
dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(i));
9691000
p->chan[i].status = COMP_STATE_PREPARE;
9701001
}
1002+
1003+
p->chan[i].lli_current->ctrl_hi &= ~DW_CTLH_DONE(1);
1004+
dcache_writeback_region(p->chan[i].lli_current,
1005+
sizeof(*p->chan[i].lli_current));
1006+
9711007
p->chan[i].lli_current =
9721008
(struct dw_lli2 *)p->chan[i].lli_current->llp;
9731009
}
@@ -1121,6 +1157,11 @@ static void dw_dma_irq_handler(void *data)
11211157
dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(i));
11221158
p->chan[i].status = COMP_STATE_PREPARE;
11231159
}
1160+
1161+
p->chan[i].lli_current->ctrl_hi &= ~DW_CTLH_DONE(1);
1162+
dcache_writeback_region(p->chan[i].lli_current,
1163+
sizeof(*p->chan[i].lli_current));
1164+
11241165
p->chan[i].lli_current =
11251166
(struct dw_lli2 *)p->chan[i].lli_current->llp;
11261167
}

0 commit comments

Comments
 (0)