Commit 56214883 authored by Vinod Koul's avatar Vinod Koul

Merge branch 'topic/dw' into for-linus

parents 95c4dc7b 3a14c66d
......@@ -13,6 +13,11 @@ Required properties:
- chan_priority: priority of channels. 0 (default): increase from chan 0->n, 1:
increase from chan n->0
- block_size: Maximum block size supported by the controller
- data-width: Maximum data width supported by hardware per AHB master
(in bytes, power of 2)
Deprecated properties:
- data_width: Maximum data width supported by hardware per AHB master
(0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
......@@ -38,7 +43,7 @@ Example:
chan_allocation_order = <1>;
chan_priority = <1>;
block_size = <0xfff>;
data_width = <3 3>;
data-width = <8 8>;
};
DMA clients connected to the Designware DMA controller must use the format
......@@ -47,8 +52,8 @@ The four cells in order are:
1. A phandle pointing to the DMA controller
2. The DMA request line number
3. Source master for transfers on allocated channel
4. Destination master for transfers on allocated channel
3. Memory master for transfers on allocated channel
4. Peripheral master for transfers on allocated channel
Example:
......
......@@ -112,7 +112,7 @@ dma@FE000000 {
chan_allocation_order = <0>;
chan_priority = <1>;
block_size = <0x7ff>;
data_width = <2>;
data-width = <4>;
clocks = <&ahb_clk>;
clock-names = "hclk";
};
......
......@@ -117,7 +117,7 @@ dwdma0: dma@ea800000 {
chan_priority = <1>;
block_size = <0xfff>;
dma-masters = <2>;
data_width = <3 3>;
data-width = <8 8>;
};
dma@eb000000 {
......@@ -133,7 +133,7 @@ dma@eb000000 {
chan_allocation_order = <1>;
chan_priority = <1>;
block_size = <0xfff>;
data_width = <3 3>;
data-width = <8 8>;
};
fsmc: flash@b0000000 {
......
......@@ -1365,8 +1365,8 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
slave->dma_dev = &dw_dmac0_device.dev;
slave->src_id = 0;
slave->dst_id = 1;
slave->src_master = 1;
slave->dst_master = 0;
slave->m_master = 1;
slave->p_master = 0;
data->dma_slave = slave;
data->dma_filter = at32_mci_dma_filter;
......@@ -2061,16 +2061,16 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data,
if (flags & AC97C_CAPTURE) {
rx_dws->dma_dev = &dw_dmac0_device.dev;
rx_dws->src_id = 3;
rx_dws->src_master = 0;
rx_dws->dst_master = 1;
rx_dws->m_master = 0;
rx_dws->p_master = 1;
}
/* Check if DMA slave interface for playback should be configured. */
if (flags & AC97C_PLAYBACK) {
tx_dws->dma_dev = &dw_dmac0_device.dev;
tx_dws->dst_id = 4;
tx_dws->src_master = 0;
tx_dws->dst_master = 1;
tx_dws->m_master = 0;
tx_dws->p_master = 1;
}
if (platform_device_add_data(pdev, data,
......@@ -2141,8 +2141,8 @@ at32_add_device_abdac(unsigned int id, struct atmel_abdac_pdata *data)
dws->dma_dev = &dw_dmac0_device.dev;
dws->dst_id = 2;
dws->src_master = 0;
dws->dst_master = 1;
dws->m_master = 0;
dws->p_master = 1;
if (platform_device_add_data(pdev, data,
sizeof(struct atmel_abdac_pdata)))
......
......@@ -201,8 +201,8 @@ static struct sata_dwc_host_priv host_pvt;
static struct dw_dma_slave sata_dwc_dma_dws = {
.src_id = 0,
.dst_id = 0,
.src_master = 0,
.dst_master = 1,
.m_master = 1,
.p_master = 0,
};
/*
......@@ -1248,7 +1248,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
hsdev->dma->dev = &ofdev->dev;
/* Initialize AHB DMAC */
err = dw_dma_probe(hsdev->dma, NULL);
err = dw_dma_probe(hsdev->dma);
if (err)
goto error_dma_iomap;
......
......@@ -45,22 +45,19 @@
DW_DMA_MSIZE_16; \
u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \
DW_DMA_MSIZE_16; \
u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ? \
_dwc->p_master : _dwc->m_master; \
u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ? \
_dwc->p_master : _dwc->m_master; \
\
(DWC_CTLL_DST_MSIZE(_dmsize) \
| DWC_CTLL_SRC_MSIZE(_smsize) \
| DWC_CTLL_LLP_D_EN \
| DWC_CTLL_LLP_S_EN \
| DWC_CTLL_DMS(_dwc->dst_master) \
| DWC_CTLL_SMS(_dwc->src_master)); \
| DWC_CTLL_DMS(_dms) \
| DWC_CTLL_SMS(_sms)); \
})
/*
* Number of descriptors to allocate for each channel. This should be
* made configurable somehow; preferably, the clients (at least the
* ones using slave transfers) should be able to give us a hint.
*/
#define NR_DESCS_PER_CHANNEL 64
/* The set of bus widths supported by the DMA controller */
#define DW_DMA_BUSWIDTHS \
BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
......@@ -80,76 +77,78 @@ static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc)
return to_dw_desc(dwc->active_list.next);
}
static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct dw_desc *desc, *_desc;
struct dw_desc *ret = NULL;
unsigned int i = 0;
struct dw_desc *desc = txd_to_dw_desc(tx);
struct dw_dma_chan *dwc = to_dw_dma_chan(tx->chan);
dma_cookie_t cookie;
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry_safe(desc, _desc, &dwc->free_list, desc_node) {
i++;
if (async_tx_test_ack(&desc->txd)) {
list_del(&desc->desc_node);
ret = desc;
break;
}
dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc);
}
cookie = dma_cookie_assign(tx);
/*
* REVISIT: We should attempt to chain as many descriptors as
* possible, perhaps even appending to those already submitted
* for DMA. But this is hard to do in a race-free manner.
*/
list_add_tail(&desc->desc_node, &dwc->queue);
spin_unlock_irqrestore(&dwc->lock, flags);
dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n",
__func__, desc->txd.cookie);
dev_vdbg(chan2dev(&dwc->chan), "scanned %u descriptors on freelist\n", i);
return cookie;
}
return ret;
static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
{
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
struct dw_desc *desc;
dma_addr_t phys;
desc = dma_pool_zalloc(dw->desc_pool, GFP_ATOMIC, &phys);
if (!desc)
return NULL;
dwc->descs_allocated++;
INIT_LIST_HEAD(&desc->tx_list);
dma_async_tx_descriptor_init(&desc->txd, &dwc->chan);
desc->txd.tx_submit = dwc_tx_submit;
desc->txd.flags = DMA_CTRL_ACK;
desc->txd.phys = phys;
return desc;
}
/*
* Move a descriptor, including any children, to the free list.
* `desc' must not be on any lists.
*/
static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
{
unsigned long flags;
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
struct dw_desc *child, *_next;
if (desc) {
struct dw_desc *child;
if (unlikely(!desc))
return;
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(child, &desc->tx_list, desc_node)
dev_vdbg(chan2dev(&dwc->chan),
"moving child desc %p to freelist\n",
child);
list_splice_init(&desc->tx_list, &dwc->free_list);
dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc);
list_add(&desc->desc_node, &dwc->free_list);
spin_unlock_irqrestore(&dwc->lock, flags);
list_for_each_entry_safe(child, _next, &desc->tx_list, desc_node) {
list_del(&child->desc_node);
dma_pool_free(dw->desc_pool, child, child->txd.phys);
dwc->descs_allocated--;
}
dma_pool_free(dw->desc_pool, desc, desc->txd.phys);
dwc->descs_allocated--;
}
static void dwc_initialize(struct dw_dma_chan *dwc)
{
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
struct dw_dma_slave *dws = dwc->chan.private;
u32 cfghi = DWC_CFGH_FIFO_MODE;
u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
if (dwc->initialized == true)
if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
return;
if (dws) {
/*
* We need controller-specific data to set up slave
* transfers.
*/
BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
cfghi |= DWC_CFGH_DST_PER(dws->dst_id);
cfghi |= DWC_CFGH_SRC_PER(dws->src_id);
} else {
cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
}
channel_writel(dwc, CFG_LO, cfglo);
channel_writel(dwc, CFG_HI, cfghi);
......@@ -158,26 +157,11 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
channel_set_bit(dw, MASK.XFER, dwc->mask);
channel_set_bit(dw, MASK.ERROR, dwc->mask);
dwc->initialized = true;
set_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
}
/*----------------------------------------------------------------------*/
static inline unsigned int dwc_fast_ffs(unsigned long long v)
{
/*
* We can be a lot more clever here, but this should take care
* of the most common optimization.
*/
if (!(v & 7))
return 3;
else if (!(v & 3))
return 2;
else if (!(v & 1))
return 1;
return 0;
}
static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
{
dev_err(chan2dev(&dwc->chan),
......@@ -209,12 +193,12 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
* Software emulation of LLP mode relies on interrupts to continue
* multi block transfer.
*/
ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
ctllo = lli_read(desc, ctllo) | DWC_CTLL_INT_EN;
channel_writel(dwc, SAR, desc->lli.sar);
channel_writel(dwc, DAR, desc->lli.dar);
channel_writel(dwc, SAR, lli_read(desc, sar));
channel_writel(dwc, DAR, lli_read(desc, dar));
channel_writel(dwc, CTL_LO, ctllo);
channel_writel(dwc, CTL_HI, desc->lli.ctlhi);
channel_writel(dwc, CTL_HI, lli_read(desc, ctlhi));
channel_set_bit(dw, CH_EN, dwc->mask);
/* Move pointer to next descriptor */
......@@ -225,6 +209,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 */
......@@ -249,7 +234,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
dwc_initialize(dwc);
dwc->residue = first->total_len;
first->residue = first->total_len;
dwc->tx_node_active = &first->tx_list;
/* Submit first block */
......@@ -260,9 +245,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);
}
......@@ -305,11 +289,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
list_for_each_entry(child, &desc->tx_list, desc_node)
async_tx_ack(&child->txd);
async_tx_ack(&desc->txd);
list_splice_init(&desc->tx_list, &dwc->free_list);
list_move(&desc->desc_node, &dwc->free_list);
dma_descriptor_unmap(txd);
dwc_desc_put(dwc, desc);
spin_unlock_irqrestore(&dwc->lock, flags);
if (callback)
......@@ -380,11 +360,11 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
head = &desc->tx_list;
if (active != head) {
/* Update desc to reflect last sent one */
if (active != head->next)
desc = to_dw_desc(active->prev);
dwc->residue -= desc->len;
/* Update residue to reflect last sent descriptor */
if (active == head->next)
desc->residue -= desc->len;
else
desc->residue -= to_dw_desc(active->prev)->len;
child = to_dw_desc(active);
......@@ -399,8 +379,6 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
}
dwc->residue = 0;
spin_unlock_irqrestore(&dwc->lock, flags);
dwc_complete_all(dw, dwc);
......@@ -408,7 +386,6 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
}
if (list_empty(&dwc->active_list)) {
dwc->residue = 0;
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
......@@ -423,31 +400,31 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
/* Initial residue value */
dwc->residue = desc->total_len;
desc->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;
}
/* Check first descriptors llp */
if (desc->lli.llp == llp) {
if (lli_read(desc, llp) == llp) {
/* This one is currently in progress */
dwc->residue -= dwc_get_sent(dwc);
desc->residue -= dwc_get_sent(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
dwc->residue -= desc->len;
desc->residue -= desc->len;
list_for_each_entry(child, &desc->tx_list, desc_node) {
if (child->lli.llp == llp) {
if (lli_read(child, llp) == llp) {
/* Currently in progress */
dwc->residue -= dwc_get_sent(dwc);
desc->residue -= dwc_get_sent(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
dwc->residue -= child->len;
desc->residue -= child->len;
}
/*
......@@ -469,10 +446,14 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
spin_unlock_irqrestore(&dwc->lock, flags);
}
static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_desc *desc)
{
dev_crit(chan2dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo);
lli_read(desc, sar),
lli_read(desc, dar),
lli_read(desc, llp),
lli_read(desc, ctlhi),
lli_read(desc, ctllo));
}
static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
......@@ -508,9 +489,9 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
*/
dev_WARN(chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"
" cookie: %d\n", bad_desc->txd.cookie);
dwc_dump_lli(dwc, &bad_desc->lli);
dwc_dump_lli(dwc, bad_desc);
list_for_each_entry(child, &bad_desc->tx_list, desc_node)
dwc_dump_lli(dwc, &child->lli);
dwc_dump_lli(dwc, child);
spin_unlock_irqrestore(&dwc->lock, flags);
......@@ -561,7 +542,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
*/
if (unlikely(status_err & dwc->mask) ||
unlikely(status_xfer & dwc->mask)) {
int i;
unsigned int i;
dev_err(chan2dev(&dwc->chan),
"cyclic DMA unexpected %s interrupt, stopping DMA transfer\n",
......@@ -583,7 +564,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
dma_writel(dw, CLEAR.XFER, dwc->mask);
for (i = 0; i < dwc->cdesc->periods; i++)
dwc_dump_lli(dwc, &dwc->cdesc->desc[i]->lli);
dwc_dump_lli(dwc, dwc->cdesc->desc[i]);
spin_unlock_irqrestore(&dwc->lock, flags);
}
......@@ -601,7 +582,7 @@ static void dw_dma_tasklet(unsigned long data)
u32 status_block;
u32 status_xfer;
u32 status_err;
int i;
unsigned int i;
status_block = dma_readl(dw, RAW.BLOCK);
status_xfer = dma_readl(dw, RAW.XFER);
......@@ -670,30 +651,6 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
/*----------------------------------------------------------------------*/
static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct dw_desc *desc = txd_to_dw_desc(tx);
struct dw_dma_chan *dwc = to_dw_dma_chan(tx->chan);
dma_cookie_t cookie;
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
cookie = dma_cookie_assign(tx);
/*
* REVISIT: We should attempt to chain as many descriptors as
* possible, perhaps even appending to those already submitted
* for DMA. But this is hard to do in a race-free manner.
*/
dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__, desc->txd.cookie);
list_add_tail(&desc->desc_node, &dwc->queue);
spin_unlock_irqrestore(&dwc->lock, flags);
return cookie;
}
static struct dma_async_tx_descriptor *
dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
......@@ -705,10 +662,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
struct dw_desc *prev;
size_t xfer_count;
size_t offset;
u8 m_master = dwc->m_master;
unsigned int src_width;
unsigned int dst_width;
unsigned int data_width;
unsigned int data_width = dw->pdata->data_width[m_master];
u32 ctllo;
u8 lms = DWC_LLP_LMS(m_master);
dev_vdbg(chan2dev(chan),
"%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
......@@ -721,11 +680,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
dwc->direction = DMA_MEM_TO_MEM;
data_width = min_t(unsigned int, dw->data_width[dwc->src_master],
dw->data_width[dwc->dst_master]);
src_width = dst_width = min_t(unsigned int, data_width,
dwc_fast_ffs(src | dest | len));
src_width = dst_width = __ffs(data_width | src | dest | len);
ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width)
......@@ -743,27 +698,27 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
if (!desc)
goto err_desc_get;
desc->lli.sar = src + offset;
desc->lli.dar = dest + offset;
desc->lli.ctllo = ctllo;
desc->lli.ctlhi = xfer_count;
lli_write(desc, sar, src + offset);
lli_write(desc, dar, dest + offset);
lli_write(desc, ctllo, ctllo);
lli_write(desc, ctlhi, xfer_count);
desc->len = xfer_count << src_width;
if (!first) {
first = desc;
} else {
prev->lli.llp = desc->txd.phys;
list_add_tail(&desc->desc_node,
&first->tx_list);
lli_write(prev, llp, desc->txd.phys | lms);
list_add_tail(&desc->desc_node, &first->tx_list);
}
prev = desc;
}
if (flags & DMA_PREP_INTERRUPT)
/* Trigger interrupt after last block */
prev->lli.ctllo |= DWC_CTLL_INT_EN;
lli_set(prev, ctllo, DWC_CTLL_INT_EN);
prev->lli.llp = 0;
lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
first->txd.flags = flags;
first->total_len = len;
......@@ -785,10 +740,12 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct dw_desc *prev;
struct dw_desc *first;
u32 ctllo;
u8 m_master = dwc->m_master;
u8 lms = DWC_LLP_LMS(m_master);
dma_addr_t reg;
unsigned int reg_width;
unsigned int mem_width;
unsigned int data_width;
unsigned int data_width = dw->pdata->data_width[m_master];
unsigned int i;
struct scatterlist *sg;
size_t total_len = 0;
......@@ -814,8 +771,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
DWC_CTLL_FC(DW_DMA_FC_D_M2P);
data_width = dw->data_width[dwc->src_master];
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len, dlen, mem;
......@@ -823,17 +778,16 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
mem_width = min_t(unsigned int,
data_width, dwc_fast_ffs(mem | len));
mem_width = __ffs(data_width | mem | len);
slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc);
if (!desc)
goto err_desc_get;
desc->lli.sar = mem;
desc->lli.dar = reg;
desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
lli_write(desc, sar, mem);
lli_write(desc, dar, reg);
lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
if ((len >> mem_width) > dwc->block_size) {
dlen = dwc->block_size << mem_width;
mem += dlen;
......@@ -843,15 +797,14 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
len = 0;
}
desc->lli.ctlhi = dlen >> mem_width;
lli_write(desc, ctlhi, dlen >> mem_width);
desc->len = dlen;
if (!first) {
first = desc;
} else {
prev->lli.llp = desc->txd.phys;
list_add_tail(&desc->desc_node,
&first->tx_list);
lli_write(prev, llp, desc->txd.phys | lms);
list_add_tail(&desc->desc_node, &first->tx_list);
}
prev = desc;
total_len += dlen;
......@@ -871,8 +824,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
DWC_CTLL_FC(DW_DMA_FC_D_P2M);
data_width = dw->data_width[dwc->dst_master];
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len, dlen, mem;
......@@ -880,17 +831,16 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
mem_width = min_t(unsigned int,
data_width, dwc_fast_ffs(mem | len));
mem_width = __ffs(data_width | mem | len);
slave_sg_fromdev_fill_desc:
desc = dwc_desc_get(dwc);
if (!desc)
goto err_desc_get;
desc->lli.sar = reg;
desc->lli.dar = mem;
desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
lli_write(desc, sar, reg);
lli_write(desc, dar, mem);
lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
if ((len >> reg_width) > dwc->block_size) {
dlen = dwc->block_size << reg_width;
mem += dlen;
......@@ -899,15 +849,14 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
dlen = len;
len = 0;
}
desc->lli.ctlhi = dlen >> reg_width;
lli_write(desc, ctlhi, dlen >> reg_width);
desc->len = dlen;
if (!first) {
first = desc;
} else {
prev->lli.llp = desc->txd.phys;
list_add_tail(&desc->desc_node,
&first->tx_list);
lli_write(prev, llp, desc->txd.phys | lms);
list_add_tail(&desc->desc_node, &first->tx_list);
}
prev = desc;
total_len += dlen;
......@@ -922,9 +871,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (flags & DMA_PREP_INTERRUPT)
/* Trigger interrupt after last block */
prev->lli.ctllo |= DWC_CTLL_INT_EN;
lli_set(prev, ctllo, DWC_CTLL_INT_EN);
prev->lli.llp = 0;
lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
first->total_len = total_len;
return &first->txd;
......@@ -941,7 +891,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma_slave *dws = param;
if (!dws || dws->dma_dev != chan->device->dev)
if (dws->dma_dev != chan->device->dev)
return false;
/* We have to copy data since dws can be temporary storage */
......@@ -949,8 +899,8 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
dwc->src_id = dws->src_id;
dwc->dst_id = dws->dst_id;
dwc->src_master = dws->src_master;
dwc->dst_master = dws->dst_master;
dwc->m_master = dws->m_master;
dwc->p_master = dws->p_master;
return true;
}
......@@ -1003,7 +953,7 @@ static int dwc_pause(struct dma_chan *chan)
while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
udelay(2);
dwc->paused = true;
set_bit(DW_DMA_IS_PAUSED, &dwc->flags);
spin_unlock_irqrestore(&dwc->lock, flags);
......@@ -1016,7 +966,7 @@ static inline void dwc_chan_resume(struct dw_dma_chan *dwc)
channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP);
dwc->paused = false;
clear_bit(DW_DMA_IS_PAUSED, &dwc->flags);
}
static int dwc_resume(struct dma_chan *chan)
......@@ -1024,11 +974,9 @@ static int dwc_resume(struct dma_chan *chan)
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
unsigned long flags;
if (!dwc->paused)
return 0;
spin_lock_irqsave(&dwc->lock, flags);
if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags))
dwc_chan_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
......@@ -1065,16 +1013,37 @@ static int dwc_terminate_all(struct dma_chan *chan)
return 0;
}
static inline u32 dwc_get_residue(struct dw_dma_chan *dwc)
static struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
{
struct dw_desc *desc;
list_for_each_entry(desc, &dwc->active_list, desc_node)
if (desc->txd.cookie == c)
return desc;
return NULL;
}
static u32 dwc_get_residue(struct dw_dma_chan *dwc, dma_cookie_t cookie)
{
struct dw_desc *desc;
unsigned long flags;
u32 residue;
spin_lock_irqsave(&dwc->lock, flags);
residue = dwc->residue;
desc = dwc_find_desc(dwc, cookie);
if (desc) {
if (desc == dwc_first_active(dwc)) {
residue = desc->residue;
if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue)
residue -= dwc_get_sent(dwc);
} else {
residue = desc->total_len;
}
} else {
residue = 0;
}
spin_unlock_irqrestore(&dwc->lock, flags);
return residue;
......@@ -1095,10 +1064,12 @@ dwc_tx_status(struct dma_chan *chan,
dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
ret = dma_cookie_status(chan, cookie, txstate);
if (ret != DMA_COMPLETE)
dma_set_residue(txstate, dwc_get_residue(dwc));
if (ret == DMA_COMPLETE)
return ret;
dma_set_residue(txstate, dwc_get_residue(dwc, cookie));
if (dwc->paused && ret == DMA_IN_PROGRESS)
if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags) && ret == DMA_IN_PROGRESS)
return DMA_PAUSED;
return ret;
......@@ -1119,7 +1090,7 @@ static void dwc_issue_pending(struct dma_chan *chan)
static void dw_dma_off(struct dw_dma *dw)
{
int i;
unsigned int i;
dma_writel(dw, CFG, 0);
......@@ -1133,7 +1104,7 @@ static void dw_dma_off(struct dw_dma *dw)
cpu_relax();
for (i = 0; i < dw->dma.chancnt; i++)
dw->chan[i].initialized = false;
clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags);
}
static void dw_dma_on(struct dw_dma *dw)
......@@ -1145,9 +1116,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(chan->device);
struct dw_desc *desc;
int i;
unsigned long flags;
dev_vdbg(chan2dev(chan), "%s\n", __func__);
......@@ -1165,53 +1133,26 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
* doesn't mean what you think it means), and status writeback.
*/
/*
* We need controller-specific data to set up slave transfers.
*/
if (chan->private && !dw_dma_filter(chan, chan->private)) {
dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
return -EINVAL;
}
/* Enable controller here if needed */
if (!dw->in_use)
dw_dma_on(dw);
dw->in_use |= dwc->mask;
spin_lock_irqsave(&dwc->lock, flags);
i = dwc->descs_allocated;
while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) {
dma_addr_t phys;
spin_unlock_irqrestore(&dwc->lock, flags);
desc = dma_pool_alloc(dw->desc_pool, GFP_ATOMIC, &phys);
if (!desc)
goto err_desc_alloc;
memset(desc, 0, sizeof(struct dw_desc));
INIT_LIST_HEAD(&desc->tx_list);
dma_async_tx_descriptor_init(&desc->txd, chan);
desc->txd.tx_submit = dwc_tx_submit;
desc->txd.flags = DMA_CTRL_ACK;
desc->txd.phys = phys;
dwc_desc_put(dwc, desc);
spin_lock_irqsave(&dwc->lock, flags);
i = ++dwc->descs_allocated;
}
spin_unlock_irqrestore(&dwc->lock, flags);
dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);
return i;
err_desc_alloc:
dev_info(chan2dev(chan), "only allocated %d descriptors\n", i);
return i;
return 0;
}
static void dwc_free_chan_resources(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(chan->device);
struct dw_desc *desc, *_desc;
unsigned long flags;
LIST_HEAD(list);
......@@ -1224,9 +1165,15 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
BUG_ON(dma_readl(to_dw_dma(chan->device), CH_EN) & dwc->mask);
spin_lock_irqsave(&dwc->lock, flags);
list_splice_init(&dwc->free_list, &list);
dwc->descs_allocated = 0;
dwc->initialized = false;
/* Clear custom channel configuration */
dwc->src_id = 0;
dwc->dst_id = 0;
dwc->m_master = 0;
dwc->p_master = 0;
clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
/* Disable interrupts */
channel_clear_bit(dw, MASK.XFER, dwc->mask);
......@@ -1240,11 +1187,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
if (!dw->in_use)
dw_dma_off(dw);
list_for_each_entry_safe(desc, _desc, &list, desc_node) {
dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc);
dma_pool_free(dw->desc_pool, desc, desc->txd.phys);
}
dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}
......@@ -1322,6 +1264,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;
......@@ -1375,9 +1318,6 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
retval = ERR_PTR(-ENOMEM);
if (periods > NR_DESCS_PER_CHANNEL)
goto out_err;
cdesc = kzalloc(sizeof(struct dw_cyclic_desc), GFP_KERNEL);
if (!cdesc)
goto out_err;
......@@ -1393,50 +1333,50 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
switch (direction) {
case DMA_MEM_TO_DEV:
desc->lli.dar = sconfig->dst_addr;
desc->lli.sar = buf_addr + (period_len * i);
desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
lli_write(desc, dar, sconfig->dst_addr);
lli_write(desc, sar, buf_addr + period_len * i);
lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_FIX
| DWC_CTLL_SRC_INC
| DWC_CTLL_INT_EN);
| DWC_CTLL_INT_EN));
desc->lli.ctllo |= sconfig->device_fc ?
lli_set(desc, ctllo, sconfig->device_fc ?
DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
DWC_CTLL_FC(DW_DMA_FC_D_M2P);
DWC_CTLL_FC(DW_DMA_FC_D_M2P));
break;
case DMA_DEV_TO_MEM:
desc->lli.dar = buf_addr + (period_len * i);
desc->lli.sar = sconfig->src_addr;
desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
lli_write(desc, dar, buf_addr + period_len * i);
lli_write(desc, sar, sconfig->src_addr);
lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_DST_INC
| DWC_CTLL_SRC_FIX
| DWC_CTLL_INT_EN);
| DWC_CTLL_INT_EN));
desc->lli.ctllo |= sconfig->device_fc ?
lli_set(desc, ctllo, sconfig->device_fc ?
DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
DWC_CTLL_FC(DW_DMA_FC_D_P2M);
DWC_CTLL_FC(DW_DMA_FC_D_P2M));
break;
default:
break;
}
desc->lli.ctlhi = (period_len >> reg_width);
lli_write(desc, ctlhi, period_len >> reg_width);
cdesc->desc[i] = desc;
if (last)
last->lli.llp = desc->txd.phys;
lli_write(last, llp, desc->txd.phys | lms);
last = desc;
}
/* Let's make a cyclic list */
last->lli.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",
......@@ -1467,7 +1407,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
struct dw_cyclic_desc *cdesc = dwc->cdesc;
int i;
unsigned int i;
unsigned long flags;
dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);
......@@ -1491,32 +1431,38 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
kfree(cdesc->desc);
kfree(cdesc);
dwc->cdesc = NULL;
clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
}
EXPORT_SYMBOL(dw_dma_cyclic_free);
/*----------------------------------------------------------------------*/
int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
int dw_dma_probe(struct dw_dma_chip *chip)
{
struct dw_dma_platform_data *pdata;
struct dw_dma *dw;
bool autocfg = false;
unsigned int dw_params;
unsigned int max_blk_size = 0;
unsigned int i;
int err;
int i;
dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
if (!dw)
return -ENOMEM;
dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
if (!dw->pdata)
return -ENOMEM;
dw->regs = chip->regs;
chip->dw = dw;
pm_runtime_get_sync(chip->dev);
if (!pdata) {
dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
if (!chip->pdata) {
dw_params = dma_readl(dw, DW_PARAMS);
dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
autocfg = dw_params >> DW_PARAMS_EN & 1;
......@@ -1525,29 +1471,31 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
goto err_pdata;
}
pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
err = -ENOMEM;
goto err_pdata;
}
/* Reassign the platform data pointer */
pdata = dw->pdata;
/* Get hardware configuration parameters */
pdata->nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 7) + 1;
pdata->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
for (i = 0; i < pdata->nr_masters; i++) {
pdata->data_width[i] =
(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
4 << (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3);
}
max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
pdata->block_size = dma_readl(dw, MAX_BLK_SIZE);
/* Fill platform data with the default values */
pdata->is_private = true;
pdata->is_memcpy = true;
pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING;
pdata->chan_priority = CHAN_PRIORITY_ASCENDING;
} else if (pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
} else if (chip->pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
err = -EINVAL;
goto err_pdata;
} else {
memcpy(dw->pdata, chip->pdata, sizeof(*dw->pdata));
/* Reassign the platform data pointer */
pdata = dw->pdata;
}
dw->chan = devm_kcalloc(chip->dev, pdata->nr_channels, sizeof(*dw->chan),
......@@ -1557,11 +1505,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
goto err_pdata;
}
/* Get hardware configuration parameters */
dw->nr_masters = pdata->nr_masters;
for (i = 0; i < dw->nr_masters; i++)
dw->data_width[i] = pdata->data_width[i];
/* Calculate all channel mask before DMA setup */
dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
......@@ -1608,7 +1551,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
INIT_LIST_HEAD(&dwc->active_list);
INIT_LIST_HEAD(&dwc->queue);
INIT_LIST_HEAD(&dwc->free_list);
channel_clear_bit(dw, CH_EN, dwc->mask);
......@@ -1616,11 +1558,9 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
/* Hardware configuration */
if (autocfg) {
unsigned int dwc_params;
unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1;
void __iomem *addr = chip->regs + r * sizeof(u32);
dwc_params = dma_read_byaddr(addr, DWC_PARAMS);
void __iomem *addr = &__dw_regs(dw)->DWC_PARAMS[r];
unsigned int dwc_params = dma_readl_native(addr);
dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
dwc_params);
......@@ -1631,16 +1571,15 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
* up to 0x0a for 4095.
*/
dwc->block_size =
(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
(4 << ((pdata->block_size >> 4 * i) & 0xf)) - 1;
dwc->nollp =
(dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
} else {
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);
}
}
......
......@@ -17,8 +17,8 @@
static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
{
const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
struct dw_dma_chip *chip;
struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
int ret;
ret = pcim_enable_device(pdev);
......@@ -49,8 +49,9 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
chip->dev = &pdev->dev;
chip->regs = pcim_iomap_table(pdev)[0];
chip->irq = pdev->irq;
chip->pdata = pdata;
ret = dw_dma_probe(chip, pdata);
ret = dw_dma_probe(chip);
if (ret)
return ret;
......
......@@ -42,13 +42,13 @@ static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
slave.src_id = dma_spec->args[0];
slave.dst_id = dma_spec->args[0];
slave.src_master = dma_spec->args[1];
slave.dst_master = dma_spec->args[2];
slave.m_master = dma_spec->args[1];
slave.p_master = dma_spec->args[2];
if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS ||
slave.dst_id >= DW_DMA_MAX_NR_REQUESTS ||
slave.src_master >= dw->nr_masters ||
slave.dst_master >= dw->nr_masters))
slave.m_master >= dw->pdata->nr_masters ||
slave.p_master >= dw->pdata->nr_masters))
return NULL;
dma_cap_zero(cap);
......@@ -66,8 +66,8 @@ static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
.dma_dev = dma_spec->dev,
.src_id = dma_spec->slave_id,
.dst_id = dma_spec->slave_id,
.src_master = 1,
.dst_master = 0,
.m_master = 0,
.p_master = 1,
};
return dw_dma_filter(chan, &slave);
......@@ -103,6 +103,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct dw_dma_platform_data *pdata;
u32 tmp, arr[DW_DMA_MAX_NR_MASTERS];
u32 nr_masters;
u32 nr_channels;
if (!np) {
......@@ -110,6 +111,11 @@ dw_dma_parse_dt(struct platform_device *pdev)
return NULL;
}
if (of_property_read_u32(np, "dma-masters", &nr_masters))
return NULL;
if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS)
return NULL;
if (of_property_read_u32(np, "dma-channels", &nr_channels))
return NULL;
......@@ -117,6 +123,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
if (!pdata)
return NULL;
pdata->nr_masters = nr_masters;
pdata->nr_channels = nr_channels;
if (of_property_read_bool(np, "is_private"))
......@@ -131,17 +138,13 @@ dw_dma_parse_dt(struct platform_device *pdev)
if (!of_property_read_u32(np, "block_size", &tmp))
pdata->block_size = tmp;
if (!of_property_read_u32(np, "dma-masters", &tmp)) {
if (tmp > DW_DMA_MAX_NR_MASTERS)
return NULL;
pdata->nr_masters = tmp;
}
if (!of_property_read_u32_array(np, "data_width", arr,
pdata->nr_masters))
for (tmp = 0; tmp < pdata->nr_masters; tmp++)
if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) {
for (tmp = 0; tmp < nr_masters; tmp++)
pdata->data_width[tmp] = arr[tmp];
} else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) {
for (tmp = 0; tmp < nr_masters; tmp++)
pdata->data_width[tmp] = BIT(arr[tmp] & 0x07);
}
return pdata;
}
......@@ -158,7 +161,7 @@ static int dw_probe(struct platform_device *pdev)
struct dw_dma_chip *chip;
struct device *dev = &pdev->dev;
struct resource *mem;
struct dw_dma_platform_data *pdata;
const struct dw_dma_platform_data *pdata;
int err;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
......@@ -183,6 +186,7 @@ static int dw_probe(struct platform_device *pdev)
pdata = dw_dma_parse_dt(pdev);
chip->dev = dev;
chip->pdata = pdata;
chip->clk = devm_clk_get(chip->dev, "hclk");
if (IS_ERR(chip->clk))
......@@ -193,7 +197,7 @@ static int dw_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
err = dw_dma_probe(chip, pdata);
err = dw_dma_probe(chip);
if (err)
goto err_dw_dma_probe;
......
......@@ -114,10 +114,6 @@ struct dw_dma_regs {
#define dma_writel_native writel
#endif
/* To access the registers in early stage of probe */
#define dma_read_byaddr(addr, name) \
dma_readl_native((addr) + offsetof(struct dw_dma_regs, name))
/* Bitfields in DW_PARAMS */
#define DW_PARAMS_NR_CHAN 8 /* number of channels */
#define DW_PARAMS_NR_MASTER 11 /* number of AHB masters */
......@@ -143,6 +139,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 */
......@@ -216,6 +216,8 @@ enum dw_dma_msize {
enum dw_dmac_flags {
DW_DMA_IS_CYCLIC = 0,
DW_DMA_IS_SOFT_LLP = 1,
DW_DMA_IS_PAUSED = 2,
DW_DMA_IS_INITIALIZED = 3,
};
struct dw_dma_chan {
......@@ -224,8 +226,6 @@ struct dw_dma_chan {
u8 mask;
u8 priority;
enum dma_transfer_direction direction;
bool paused;
bool initialized;
/* software emulation of the LLP transfers */
struct list_head *tx_node_active;
......@@ -236,8 +236,6 @@ struct dw_dma_chan {
unsigned long flags;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
u32 residue;
struct dw_cyclic_desc *cdesc;
unsigned int descs_allocated;
......@@ -249,8 +247,8 @@ struct dw_dma_chan {
/* custom slave configuration */
u8 src_id;
u8 dst_id;
u8 src_master;
u8 dst_master;
u8 m_master;
u8 p_master;
/* configuration passed via .device_config */
struct dma_slave_config dma_sconfig;
......@@ -283,9 +281,8 @@ struct dw_dma {
u8 all_chan_mask;
u8 in_use;
/* hardware configuration */
unsigned char nr_masters;
unsigned char data_width[DW_DMA_MAX_NR_MASTERS];
/* platform data */
struct dw_dma_platform_data *pdata;
};
static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
......@@ -308,32 +305,51 @@ static inline struct dw_dma *to_dw_dma(struct dma_device *ddev)
return container_of(ddev, struct dw_dma, dma);
}
#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
typedef __be32 __dw32;
#else
typedef __le32 __dw32;
#endif
/* LLI == Linked List Item; a.k.a. DMA block descriptor */
struct dw_lli {
/* values that are not changed by hardware */
u32 sar;
u32 dar;
u32 llp; /* chain to next lli */
u32 ctllo;
__dw32 sar;
__dw32 dar;
__dw32 llp; /* chain to next lli */
__dw32 ctllo;
/* values that may get written back: */
u32 ctlhi;
__dw32 ctlhi;
/* sstat and dstat can snapshot peripheral register state.
* silicon config may discard either or both...
*/
u32 sstat;
u32 dstat;
__dw32 sstat;
__dw32 dstat;
};
struct dw_desc {
/* FIRST values the hardware uses */
struct dw_lli lli;
#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
#define lli_set(d, reg, v) ((d)->lli.reg |= cpu_to_be32(v))
#define lli_clear(d, reg, v) ((d)->lli.reg &= ~cpu_to_be32(v))
#define lli_read(d, reg) be32_to_cpu((d)->lli.reg)
#define lli_write(d, reg, v) ((d)->lli.reg = cpu_to_be32(v))
#else
#define lli_set(d, reg, v) ((d)->lli.reg |= cpu_to_le32(v))
#define lli_clear(d, reg, v) ((d)->lli.reg &= ~cpu_to_le32(v))
#define lli_read(d, reg) le32_to_cpu((d)->lli.reg)
#define lli_write(d, reg, v) ((d)->lli.reg = cpu_to_le32(v))
#endif
/* THEN values for driver housekeeping */
struct list_head desc_node;
struct list_head tx_list;
struct dma_async_tx_descriptor txd;
size_t len;
size_t total_len;
u32 residue;
};
#define to_dw_desc(h) list_entry(h, struct dw_desc, desc_node)
......
......@@ -144,16 +144,16 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
struct dw_dma_slave *slave = c->tx_param;
slave->dma_dev = &dma_dev->dev;
slave->src_master = 1;
slave->dst_master = 0;
slave->m_master = 0;
slave->p_master = 1;
}
if (c->rx_param) {
struct dw_dma_slave *slave = c->rx_param;
slave->dma_dev = &dma_dev->dev;
slave->src_master = 1;
slave->dst_master = 0;
slave->m_master = 0;
slave->p_master = 1;
}
spi_pdata.dma_filter = lpss_dma_filter;
......
......@@ -1454,13 +1454,13 @@ byt_serial_setup(struct serial_private *priv,
return -EINVAL;
}
rx_param->src_master = 1;
rx_param->dst_master = 0;
rx_param->m_master = 0;
rx_param->p_master = 1;
dma->rxconf.src_maxburst = 16;
tx_param->src_master = 1;
tx_param->dst_master = 0;
tx_param->m_master = 0;
tx_param->p_master = 1;
dma->txconf.dst_maxburst = 16;
......
......@@ -27,6 +27,7 @@ struct dw_dma;
* @regs: memory mapped I/O space
* @clk: hclk clock
* @dw: struct dw_dma that is filed by dw_dma_probe()
* @pdata: pointer to platform data
*/
struct dw_dma_chip {
struct device *dev;
......@@ -34,10 +35,12 @@ struct dw_dma_chip {
void __iomem *regs;
struct clk *clk;
struct dw_dma *dw;
const struct dw_dma_platform_data *pdata;
};
/* Export to the platform drivers */
int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata);
int dw_dma_probe(struct dw_dma_chip *chip);
int dw_dma_remove(struct dw_dma_chip *chip);
/* DMA API extensions */
......
......@@ -21,15 +21,15 @@
* @dma_dev: required DMA master device
* @src_id: src request line
* @dst_id: dst request line
* @src_master: src master for transfers on allocated channel.
* @dst_master: dest master for transfers on allocated channel.
* @m_master: memory master for transfers on allocated channel
* @p_master: peripheral master for transfers on allocated channel
*/
struct dw_dma_slave {
struct device *dma_dev;
u8 src_id;
u8 dst_id;
u8 src_master;
u8 dst_master;
u8 m_master;
u8 p_master;
};
/**
......@@ -43,7 +43,7 @@ struct dw_dma_slave {
* @block_size: Maximum block size supported by the controller
* @nr_masters: Number of AHB masters supported by the controller
* @data_width: Maximum data width supported by hardware per AHB master
* (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
* (in bytes, power of 2)
*/
struct dw_dma_platform_data {
unsigned int nr_channels;
......@@ -55,7 +55,7 @@ struct dw_dma_platform_data {
#define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */
#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */
unsigned char chan_priority;
unsigned short block_size;
unsigned int block_size;
unsigned char nr_masters;
unsigned char data_width[DW_DMA_MAX_NR_MASTERS];
};
......
......@@ -203,7 +203,7 @@ static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
chip->dev = dev;
err = dw_dma_probe(chip, NULL);
err = dw_dma_probe(chip);
if (err)
return ERR_PTR(err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment