Skip to content

Commit

Permalink
Merge branch 'for_dan' of git://git.infradead.org/users/vkoul/slave-d…
Browse files Browse the repository at this point in the history
…ma into dmaengine

* 'for_dan' of git://git.infradead.org/users/vkoul/slave-dma:
  drivers, pch_dma: Fix warning when CONFIG_PM=n.
  dmaengine/dw_dmac fix: use readl & writel instead of __raw_readl & __raw_writel
  avr32: at32ap700x: Specify DMA Flow Controller, Src and Dst msize
  dw_dmac: Setting Default Burst length for transfers as 16.
  dw_dmac: Allow src/dst msize & flow controller to be configured at runtime
  dw_dmac: Changing type of src_master and dest_master to u8.
  dw_dmac: Pass Channel Priority from platform_data
  dw_dmac: Pass Channel Allocation Order from platform_data
  dw_dmac: Mark all tx_descriptors with DMA_CRTL_ACK after xfer finish
  dw_dmac: Change value of DWC_MAX_COUNT to 4095.
  dw_dmac: Adding support for 64 bit access width for memcpy xfers
  dw_dmac: Calling dwc_scan_descriptors from dwc_tx_status() after taking lock
  dw_dmac: Move single descriptor from dwc->queue to dwc->active_list in dwc_complete_all
  dw_dmac: Replace module_init() with subsys_initcall()
  dw_dmac: Remove compilation dependency from AVR32 and put on HAVE_CLK
  dmaengine: mxs-dma: add dma support for i.MX23/28
  pch_dma: set the number of array correctly
  pch_dma: fix kernel error issue
  • Loading branch information
Dan Williams committed Mar 11, 2011
2 parents f5539af + 0b863b3 commit 6c11371
Show file tree
Hide file tree
Showing 9 changed files with 881 additions and 50 deletions.
26 changes: 26 additions & 0 deletions arch/arm/mach-mxs/include/mach/dma.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#ifndef __MACH_MXS_DMA_H__
#define __MACH_MXS_DMA_H__

struct mxs_dma_data {
int chan_irq;
};

static inline int mxs_dma_is_apbh(struct dma_chan *chan)
{
return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbh");
}

static inline int mxs_dma_is_apbx(struct dma_chan *chan)
{
return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbx");
}

#endif /* __MACH_MXS_DMA_H__ */
9 changes: 9 additions & 0 deletions arch/avr32/mach-at32ap/at32ap700x.c
Original file line number Diff line number Diff line change
Expand Up @@ -2050,6 +2050,9 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data,
rx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
rx_dws->src_master = 0;
rx_dws->dst_master = 1;
rx_dws->src_msize = DW_DMA_MSIZE_1;
rx_dws->dst_msize = DW_DMA_MSIZE_1;
rx_dws->fc = DW_DMA_FC_D_P2M;
}

/* Check if DMA slave interface for playback should be configured. */
Expand All @@ -2060,6 +2063,9 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data,
tx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
rx_dws->src_master = 0;
rx_dws->dst_master = 1;
tx_dws->src_msize = DW_DMA_MSIZE_1;
tx_dws->dst_msize = DW_DMA_MSIZE_1;
tx_dws->fc = DW_DMA_FC_D_M2P;
}

if (platform_device_add_data(pdev, data,
Expand Down Expand Up @@ -2134,6 +2140,9 @@ at32_add_device_abdac(unsigned int id, struct atmel_abdac_pdata *data)
dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
dws->src_master = 0;
dws->dst_master = 1;
dws->src_msize = DW_DMA_MSIZE_1;
dws->dst_msize = DW_DMA_MSIZE_1;
dws->fc = DW_DMA_FC_D_M2P;

if (platform_device_add_data(pdev, data,
sizeof(struct atmel_abdac_pdata)))
Expand Down
10 changes: 9 additions & 1 deletion drivers/dma/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ config INTEL_IOP_ADMA

config DW_DMAC
tristate "Synopsys DesignWare AHB DMA support"
depends on AVR32
depends on HAVE_CLK
select DMA_ENGINE
default y if CPU_AT32AP7000
help
Expand Down Expand Up @@ -227,6 +227,14 @@ config IMX_DMA
Support the i.MX DMA engine. This engine is integrated into
Freescale i.MX1/21/27 chips.

config MXS_DMA
bool "MXS DMA support"
depends on SOC_IMX23 || SOC_IMX28
select DMA_ENGINE
help
Support the MXS DMA engine. This engine including APBH-DMA
and APBX-DMA is integrated into Freescale i.MX23/28 chips.

config DMA_ENGINE
bool

Expand Down
1 change: 1 addition & 0 deletions drivers/dma/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
obj-$(CONFIG_IMX_DMA) += imx-dma.o
obj-$(CONFIG_MXS_DMA) += mxs-dma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_PL330_DMA) += pl330.o
Expand Down
71 changes: 46 additions & 25 deletions drivers/dma/dw_dmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
struct dw_dma_slave *__slave = (private); \
int dms = __slave ? __slave->dst_master : 0; \
int sms = __slave ? __slave->src_master : 1; \
u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \
u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \
\
(DWC_CTLL_DST_MSIZE(0) \
| DWC_CTLL_SRC_MSIZE(0) \
(DWC_CTLL_DST_MSIZE(dmsize) \
| DWC_CTLL_SRC_MSIZE(smsize) \
| DWC_CTLL_LLP_D_EN \
| DWC_CTLL_LLP_S_EN \
| DWC_CTLL_DMS(dms) \
Expand All @@ -47,14 +49,13 @@

/*
* This is configuration-dependent and usually a funny size like 4095.
* Let's round it down to the nearest power of two.
*
* Note that this is a transfer count, i.e. if we transfer 32-bit
* words, we can do 8192 bytes per descriptor.
* words, we can do 16380 bytes per descriptor.
*
* This parameter is also system-specific.
*/
#define DWC_MAX_COUNT 2048U
#define DWC_MAX_COUNT 4095U

/*
* Number of descriptors to allocate for each channel. This should be
Expand Down Expand Up @@ -87,11 +88,6 @@ static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc)
return list_entry(dwc->active_list.next, struct dw_desc, desc_node);
}

static struct dw_desc *dwc_first_queued(struct dw_dma_chan *dwc)
{
return list_entry(dwc->queue.next, struct dw_desc, desc_node);
}

static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
{
struct dw_desc *desc, *_desc;
Expand Down Expand Up @@ -204,6 +200,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
dma_async_tx_callback callback;
void *param;
struct dma_async_tx_descriptor *txd = &desc->txd;
struct dw_desc *child;

dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);

Expand All @@ -212,6 +209,12 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
param = txd->callback_param;

dwc_sync_desc_for_cpu(dwc, desc);

/* async_tx_ack */
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);

Expand Down Expand Up @@ -262,10 +265,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
* Submit queued descriptors ASAP, i.e. before we go through
* the completed ones.
*/
if (!list_empty(&dwc->queue))
dwc_dostart(dwc, dwc_first_queued(dwc));
list_splice_init(&dwc->active_list, &list);
list_splice_init(&dwc->queue, &dwc->active_list);
if (!list_empty(&dwc->queue)) {
list_move(dwc->queue.next, &dwc->active_list);
dwc_dostart(dwc, dwc_first_active(dwc));
}

list_for_each_entry_safe(desc, _desc, &list, desc_node)
dwc_descriptor_complete(dwc, desc);
Expand Down Expand Up @@ -325,8 +329,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
cpu_relax();

if (!list_empty(&dwc->queue)) {
dwc_dostart(dwc, dwc_first_queued(dwc));
list_splice_init(&dwc->queue, &dwc->active_list);
list_move(dwc->queue.next, &dwc->active_list);
dwc_dostart(dwc, dwc_first_active(dwc));
}
}

Expand All @@ -352,7 +356,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
*/
bad_desc = dwc_first_active(dwc);
list_del_init(&bad_desc->desc_node);
list_splice_init(&dwc->queue, dwc->active_list.prev);
list_move(dwc->queue.next, dwc->active_list.prev);

/* Clear the error flag and try to restart the controller */
dma_writel(dw, CLEAR.ERROR, dwc->mask);
Expand Down Expand Up @@ -547,8 +551,8 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
if (list_empty(&dwc->active_list)) {
dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
desc->txd.cookie);
dwc_dostart(dwc, desc);
list_add_tail(&desc->desc_node, &dwc->active_list);
dwc_dostart(dwc, dwc_first_active(dwc));
} else {
dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
desc->txd.cookie);
Expand Down Expand Up @@ -587,7 +591,9 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
* We can be a lot more clever here, but this should take care
* of the most common optimization.
*/
if (!((src | dest | len) & 3))
if (!((src | dest | len) & 7))
src_width = dst_width = 3;
else if (!((src | dest | len) & 3))
src_width = dst_width = 2;
else if (!((src | dest | len) & 1))
src_width = dst_width = 1;
Expand Down Expand Up @@ -679,7 +685,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_DST_FIX
| DWC_CTLL_SRC_INC
| DWC_CTLL_FC_M2P);
| DWC_CTLL_FC(dws->fc));
reg = dws->tx_reg;
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
Expand Down Expand Up @@ -724,7 +730,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_INC
| DWC_CTLL_SRC_FIX
| DWC_CTLL_FC_P2M);
| DWC_CTLL_FC(dws->fc));

reg = dws->rx_reg;
for_each_sg(sgl, sg, sg_len, i) {
Expand Down Expand Up @@ -840,7 +846,9 @@ dwc_tx_status(struct dma_chan *chan,

ret = dma_async_is_complete(cookie, last_complete, last_used);
if (ret != DMA_SUCCESS) {
spin_lock_bh(&dwc->lock);
dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
spin_unlock_bh(&dwc->lock);

last_complete = dwc->completed;
last_used = chan->cookie;
Expand Down Expand Up @@ -895,8 +903,11 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);

cfghi = dws->cfg_hi;
cfglo = dws->cfg_lo;
cfglo = dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
}

cfglo |= DWC_CFGL_CH_PRIOR(dwc->priority);

channel_writel(dwc, CFG_LO, cfglo);
channel_writel(dwc, CFG_HI, cfghi);

Expand Down Expand Up @@ -1137,7 +1148,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_FIX
| DWC_CTLL_SRC_INC
| DWC_CTLL_FC_M2P
| DWC_CTLL_FC(dws->fc)
| DWC_CTLL_INT_EN);
break;
case DMA_FROM_DEVICE:
Expand All @@ -1148,7 +1159,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_DST_INC
| DWC_CTLL_SRC_FIX
| DWC_CTLL_FC_P2M
| DWC_CTLL_FC(dws->fc)
| DWC_CTLL_INT_EN);
break;
default:
Expand Down Expand Up @@ -1313,7 +1324,17 @@ static int __init dw_probe(struct platform_device *pdev)
dwc->chan.device = &dw->dma;
dwc->chan.cookie = dwc->completed = 1;
dwc->chan.chan_id = i;
list_add_tail(&dwc->chan.device_node, &dw->dma.channels);
if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING)
list_add_tail(&dwc->chan.device_node,
&dw->dma.channels);
else
list_add(&dwc->chan.device_node, &dw->dma.channels);

/* 7 is highest priority & 0 is lowest. */
if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
dwc->priority = 7 - i;
else
dwc->priority = i;

dwc->ch_regs = &__dw_regs(dw)->CHAN[i];
spin_lock_init(&dwc->lock);
Expand Down Expand Up @@ -1455,7 +1476,7 @@ static int __init dw_init(void)
{
return platform_driver_probe(&dw_driver, dw_probe);
}
module_init(dw_init);
subsys_initcall(dw_init);

static void __exit dw_exit(void)
{
Expand Down
12 changes: 8 additions & 4 deletions drivers/dma/dw_dmac_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct dw_dma_regs {
#define DWC_CTLL_SRC_MSIZE(n) ((n)<<14)
#define DWC_CTLL_S_GATH_EN (1 << 17) /* src gather, !FIX */
#define DWC_CTLL_D_SCAT_EN (1 << 18) /* dst scatter, !FIX */
#define DWC_CTLL_FC(n) ((n) << 20)
#define DWC_CTLL_FC_M2M (0 << 20) /* mem-to-mem */
#define DWC_CTLL_FC_M2P (1 << 20) /* mem-to-periph */
#define DWC_CTLL_FC_P2M (2 << 20) /* periph-to-mem */
Expand All @@ -101,6 +102,8 @@ struct dw_dma_regs {
#define DWC_CTLH_BLOCK_TS_MASK 0x00000fff

/* Bitfields in CFG_LO. Platform-configurable bits are in <linux/dw_dmac.h> */
#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */
#define DWC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */
#define DWC_CFGL_CH_SUSP (1 << 8) /* pause xfer */
#define DWC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */
#define DWC_CFGL_HS_DST (1 << 10) /* handshake w/dst */
Expand Down Expand Up @@ -134,6 +137,7 @@ struct dw_dma_chan {
struct dma_chan chan;
void __iomem *ch_regs;
u8 mask;
u8 priority;

spinlock_t lock;

Expand All @@ -155,9 +159,9 @@ __dwc_regs(struct dw_dma_chan *dwc)
}

#define channel_readl(dwc, name) \
__raw_readl(&(__dwc_regs(dwc)->name))
readl(&(__dwc_regs(dwc)->name))
#define channel_writel(dwc, name, val) \
__raw_writel((val), &(__dwc_regs(dwc)->name))
writel((val), &(__dwc_regs(dwc)->name))

static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
{
Expand All @@ -181,9 +185,9 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
}

#define dma_readl(dw, name) \
__raw_readl(&(__dw_regs(dw)->name))
readl(&(__dw_regs(dw)->name))
#define dma_writel(dw, name, val) \
__raw_writel((val), &(__dw_regs(dw)->name))
writel((val), &(__dw_regs(dw)->name))

#define channel_set_bit(dw, reg, mask) \
dma_writel(dw, reg, ((mask) << 8) | (mask))
Expand Down
Loading

0 comments on commit 6c11371

Please sign in to comment.