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