[PATCH v3 05/15] dmaengine: dw: set LMS field in descriptors

From: Andy Shevchenko
Date: Fri Mar 18 2016 - 10:30:40 EST


From: Mans Rullgard <mans@xxxxxxxxx>

The LMS field indicates from which master the descriptor is to be
read. This patch assumes this is always the same as the memory
side in a peripheral transfer which is true for all known systems.

Signed-off-by: Mans Rullgard <mans@xxxxxxxxx>
Acked-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
---
drivers/dma/dw/core.c | 26 ++++++++++++++------------
drivers/dma/dw/regs.h | 4 ++++
2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 279abff..7cbc2a9 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -217,6 +217,7 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
{
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+ u8 lms = DWC_LLP_LMS(dwc->m_master);
unsigned long was_soft_llp;

/* ASSERT: channel is idle */
@@ -252,9 +253,8 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)

dwc_initialize(dwc);

- channel_writel(dwc, LLP, first->txd.phys);
- channel_writel(dwc, CTL_LO,
- DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
+ channel_writel(dwc, LLP, first->txd.phys | lms);
+ channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
channel_writel(dwc, CTL_HI, 0);
channel_set_bit(dw, CH_EN, dwc->mask);
}
@@ -418,7 +418,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
dwc->residue = desc->total_len;

/* Check first descriptors addr */
- if (desc->txd.phys == llp) {
+ if (desc->txd.phys == DWC_LLP_LOC(llp)) {
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
@@ -705,6 +705,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
unsigned int dst_width;
unsigned int data_width;
u32 ctllo;
+ u8 lms = DWC_LLP_LMS(dwc->m_master);

dev_vdbg(chan2dev(chan),
"%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
@@ -747,7 +748,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
if (!first) {
first = desc;
} else {
- lli_write(prev, llp, desc->txd.phys);
+ lli_write(prev, llp, desc->txd.phys | lms);
list_add_tail(&desc->desc_node, &first->tx_list);
}
prev = desc;
@@ -779,6 +780,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct dw_desc *prev;
struct dw_desc *first;
u32 ctllo;
+ u8 lms = DWC_LLP_LMS(dwc->m_master);
dma_addr_t reg;
unsigned int reg_width;
unsigned int mem_width;
@@ -843,7 +845,7 @@ slave_sg_todev_fill_desc:
if (!first) {
first = desc;
} else {
- lli_write(prev, llp, desc->txd.phys);
+ lli_write(prev, llp, desc->txd.phys | lms);
list_add_tail(&desc->desc_node, &first->tx_list);
}
prev = desc;
@@ -898,7 +900,7 @@ slave_sg_fromdev_fill_desc:
if (!first) {
first = desc;
} else {
- lli_write(prev, llp, desc->txd.phys);
+ lli_write(prev, llp, desc->txd.phys | lms);
list_add_tail(&desc->desc_node, &first->tx_list);
}
prev = desc;
@@ -1327,6 +1329,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
struct dw_cyclic_desc *retval = NULL;
struct dw_desc *desc;
struct dw_desc *last = NULL;
+ u8 lms = DWC_LLP_LMS(dwc->m_master);
unsigned long was_cyclic;
unsigned int reg_width;
unsigned int periods;
@@ -1435,13 +1438,13 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
cdesc->desc[i] = desc;

if (last)
- lli_write(last, llp, desc->txd.phys);
+ lli_write(last, llp, desc->txd.phys | lms);

last = desc;
}

/* Let's make a cyclic list */
- lli_write(last, llp, cdesc->desc[0]->txd.phys);
+ lli_write(last, llp, cdesc->desc[0]->txd.phys | lms);

dev_dbg(chan2dev(&dwc->chan),
"cyclic prepared buf %pad len %zu period %zu periods %d\n",
@@ -1643,9 +1646,8 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
dwc->block_size = pdata->block_size;

/* Check if channel supports multi block transfer */
- channel_writel(dwc, LLP, 0xfffffffc);
- dwc->nollp =
- (channel_readl(dwc, LLP) & 0xfffffffc) == 0;
+ channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff));
+ dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0;
channel_writel(dwc, LLP, 0);
}
}
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 6571100..59d6cec 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -143,6 +143,10 @@ enum dw_dma_msize {
DW_DMA_MSIZE_256,
};

+/* Bitfields in LLP */
+#define DWC_LLP_LMS(x) ((x) & 3) /* list master select */
+#define DWC_LLP_LOC(x) ((x) & ~3) /* next lli */
+
/* Bitfields in CTL_LO */
#define DWC_CTLL_INT_EN (1 << 0) /* irqs enabled? */
#define DWC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */
--
2.7.0