Following set of patches extends dw_dmac support and fixes minor bugs.
Changes since V1:
I had few more patches that i prepared today. I wasn't sure if i should
add them to existing patchset, but as they are very much associated to this
patchset, i added them here.
Following new patches have been added in V2:
- dw_dmac: Replace module_init() with subsys_initcall()
- dw_dmac: Change value of DWC_MAX_COUNT to 4095
- dw_dmac: Changing type of src_master and dest_master to u8
- dw_dmac: Setting Default Burst length for transfers as 16
- Allow src/dst msize & flow controller to be configured at runtime
- at32ap700x: Specify DMA Flow Controller, Src and Dst msize or burst size
Other than this following are changes after getting review comments on V1:
- Added driver dependency on HAVE_CLK & fixed commit message issues
- Added descriptive commit message in: "Calling dwc_scan_descriptors from..."
- Aligned struct instance in: "Mark all tx_descriptors with..."
- Removed: "dw_dmac: call dwc_scan_descriptor from dwc_issue_pending..." as it
was already commited in linux-next.
Viresh KUMAR (1):
dw_dmac: Allow src/dst msize & flow controller to be configured at
runtime
Viresh Kumar (12):
dw_dmac: Remove compilation dependency from AVR32 and put on HAVE_CLK
dw_dmac: Replace module_init() with subsys_initcall()
dw_dmac: Move single descriptor from dwc->queue to dwc->active_list
in dwc_complete_all
dw_dmac: Calling dwc_scan_descriptors from dwc_tx_status() after
taking lock
dw_dmac: Adding support for 64 bit access width for memcpy xfers
dw_dmac: Change value of DWC_MAX_COUNT to 4095.
dw_dmac: Mark all tx_descriptors with DMA_CRTL_ACK after xfer finish
dw_dmac: Pass Channel Allocation Order from platform_data
dw_dmac: Pass Channel Priority from platform_data
dw_dmac: Changing type of src_master and dest_master to u8.
dw_dmac: Setting Default Burst length for transfers as 16.
avr32: at32ap700x: Specify DMA Flow Controller, Src and Dst msize or
burst size
arch/avr32/mach-at32ap/at32ap700x.c | 9 +++++
drivers/dma/Kconfig | 2 +-
drivers/dma/dw_dmac.c | 67 +++++++++++++++++++++++------------
drivers/dma/dw_dmac_regs.h | 4 ++
include/linux/dw_dmac.h | 43 +++++++++++++++++++++--
5 files changed, 98 insertions(+), 27 deletions(-)
--
1.7.2.2
This driver will now be used in atleast two platforms AVR32 & ARM. And there is
no actual hardware dependency of this driver over AVR32 or ARM. So this
dependency can be removed altogether.
Also dw_dmac driver uses clk framework and must have compilation dependency on
HAVE_CLK
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1c28816..3822fe1 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -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
--
1.7.2.2
In some cases users of dw_dmac are initialized before dw_dmac, and if they try
to use dw_dmac, they simply fail. So its better we register init() routine
of driver using subsys_initcall() instead of module_init(), so that dma driver
is available at the earliest possible.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 08dab3b..064a183 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1455,7 +1455,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)
{
--
1.7.2.2
Lock must be taken before calling dwc_scan_descriptors, as this may
access/modify shared data and queues. dwc_tx_status wasn't taking lock before
calling this routine. This patch add code that takes lock before calling
dwc_scan_descriptors.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 942b50f..2b0d5e9 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -836,7 +836,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;
--
1.7.2.2
dwc_desc_get checks all descriptors for DMA_CTRL_ACK before allocating them for
transfers. And descriptors are not marked with DMA_CRTL_ACK after transfer
finishes. Thus descriptor once used is not usable again. This patch marks
descriptors with DMA_CRTL_ACK after dma xfer finishes
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 734829f..836c299 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -198,6 +198,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);
@@ -206,6 +207,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);
--
1.7.2.2
From: Viresh KUMAR <[email protected]>
Msize or Burst Size is peripheral dependent in case of slave_sg transfers, and
in case of memcpy transfers it is platform dependent. So msize configuration
must come from platform data.
Also some peripherals (ex: JPEG), need to be flow controller for dma transfers,
so this information in case of slave_sg transfers must come from platform data.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 10 ++++++----
drivers/dma/dw_dmac_regs.h | 1 +
include/linux/dw_dmac.h | 30 ++++++++++++++++++++++++++++++
3 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index b1e099e..5f5b28b 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -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 : 0; \
+ u8 dmsize = __slave ? __slave->dst_msize : 0; \
\
- (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) \
@@ -683,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;
@@ -728,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) {
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 6a8e6d3..9a32964 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -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 */
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 3ba2f06..6998d93 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -42,6 +42,30 @@ enum dw_dma_slave_width {
DW_DMA_SLAVE_WIDTH_32BIT,
};
+/* bursts size */
+enum dw_dma_msize {
+ DW_DMA_MSIZE_1,
+ DW_DMA_MSIZE_4,
+ DW_DMA_MSIZE_8,
+ DW_DMA_MSIZE_16,
+ DW_DMA_MSIZE_32,
+ DW_DMA_MSIZE_64,
+ DW_DMA_MSIZE_128,
+ DW_DMA_MSIZE_256,
+};
+
+/* flow controller */
+enum dw_dma_fc {
+ DW_DMA_FC_D_M2M,
+ DW_DMA_FC_D_M2P,
+ DW_DMA_FC_D_P2M,
+ DW_DMA_FC_D_P2P,
+ DW_DMA_FC_P_P2M,
+ DW_DMA_FC_SP_P2P,
+ DW_DMA_FC_P_M2P,
+ DW_DMA_FC_DP_P2P,
+};
+
/**
* struct dw_dma_slave - Controller-specific information about a slave
*
@@ -55,6 +79,9 @@ enum dw_dma_slave_width {
* @cfg_lo: Platform-specific initializer for the CFG_LO register
* @src_master: src master for transfers on allocated channel.
* @dst_master: dest master for transfers on allocated channel.
+ * @src_msize: src burst size.
+ * @dst_msize: dest burst size.
+ * @fc: flow controller for DMA transfer
*/
struct dw_dma_slave {
struct device *dma_dev;
@@ -65,6 +92,9 @@ struct dw_dma_slave {
u32 cfg_lo;
u8 src_master;
u8 dst_master;
+ u8 src_msize;
+ u8 dst_msize;
+ u8 fc;
};
/* Platform-configurable bits in CFG_HI */
--
1.7.2.2
Now that the dw_dmac DMA driver supports configurable Flow Controller, source
and destination burst or msize, we need to specify which ones to use. Msize or
burst size was previously hardcoded to 1, Flow controller was DMA for both
M2P & P2M transfers.
Signed-off-by: Viresh Kumar <[email protected]>
---
arch/avr32/mach-at32ap/at32ap700x.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 2747cde..b4aaebd 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -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. */
@@ -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,
@@ -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)))
--
1.7.2.2
dwc_complete_all and other routines was removing all descriptors from dwc->queue
and pushing them to dwc->active_list. Only one was required to be removed. Also
we are calling dwc_dostart, once list is fixed.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 20 ++++++++------------
1 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 064a183..942b50f 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -87,11 +87,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;
@@ -262,10 +257,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);
@@ -325,8 +321,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));
}
}
@@ -352,7 +348,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);
@@ -547,8 +543,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);
--
1.7.2.2
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 2b0d5e9..e5d97bf 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -583,7 +583,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;
--
1.7.2.2
In Synopsys designware, channel priority is programmable. This patch adds
support for passing channel priority through platform data. By default Ascending
channel priority will be followed, i.e. channel 0 will get highest priority and
channel 7 will get lowest.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 11 ++++++++++-
drivers/dma/dw_dmac_regs.h | 3 +++
include/linux/dw_dmac.h | 4 +++-
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 076a2fa..b1e099e 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -901,8 +901,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);
@@ -1325,6 +1328,12 @@ static int __init dw_probe(struct platform_device *pdev)
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);
dwc->mask = 1 << i;
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index d9a939f6..6a8e6d3 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -101,6 +101,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 */
@@ -134,6 +136,7 @@ struct dw_dma_chan {
struct dma_chan chan;
void __iomem *ch_regs;
u8 mask;
+ u8 priority;
spinlock_t lock;
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index a18c498..64c76da 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -25,6 +25,9 @@ struct dw_dma_platform_data {
#define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */
#define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */
unsigned char chan_allocation_order;
+#define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */
+#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */
+ unsigned char chan_priority;
};
/**
@@ -70,7 +73,6 @@ struct dw_dma_slave {
#define DWC_CFGH_DST_PER(x) ((x) << 11)
/* Platform-configurable bits in CFG_LO */
-#define DWC_CFGL_PRIO(x) ((x) << 5) /* priority */
#define DWC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */
#define DWC_CFGL_LOCK_CH_BLOCK (1 << 12)
#define DWC_CFGL_LOCK_CH_XACT (2 << 12)
--
1.7.2.2
This patch sets default Burst length for all transfer to 16. This will
enhance performance when user doesn't have any chan->private data.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 5f5b28b..cf07539 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -36,8 +36,8 @@
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 : 0; \
- u8 dmsize = __slave ? __slave->dst_msize : 0; \
+ u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \
+ u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \
\
(DWC_CTLL_DST_MSIZE(dmsize) \
| DWC_CTLL_SRC_MSIZE(smsize) \
--
1.7.2.2
src_master & dest_master don't required u32 as they have values limited to u8
only. Also their description is missing from doc style comment. This patch
fixes above mentioned issues.
Signed-off-by: Viresh Kumar <[email protected]>
---
include/linux/dw_dmac.h | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 64c76da..3ba2f06 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -53,6 +53,8 @@ enum dw_dma_slave_width {
* @reg_width: peripheral register width
* @cfg_hi: Platform-specific initializer for the CFG_HI register
* @cfg_lo: Platform-specific initializer for the CFG_LO register
+ * @src_master: src master for transfers on allocated channel.
+ * @dst_master: dest master for transfers on allocated channel.
*/
struct dw_dma_slave {
struct device *dma_dev;
@@ -61,8 +63,8 @@ struct dw_dma_slave {
enum dw_dma_slave_width reg_width;
u32 cfg_hi;
u32 cfg_lo;
- int src_master;
- int dst_master;
+ u8 src_master;
+ u8 dst_master;
};
/* Platform-configurable bits in CFG_HI */
--
1.7.2.2
In SPEAr Platform channels 4-7 have more Fifo depth. So we must get better
channel first. This patch introduces concept of channel allocation order in
dw_dmac. If user doesn't pass anything or 0, than normal (ascending) channel
allocation will follow, else channels will be allocated in descending order.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 6 +++++-
include/linux/dw_dmac.h | 3 +++
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 836c299..076a2fa 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1319,7 +1319,11 @@ 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);
dwc->ch_regs = &__dw_regs(dw)->CHAN[i];
spin_lock_init(&dwc->lock);
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index deec66b..a18c498 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -22,6 +22,9 @@
struct dw_dma_platform_data {
unsigned int nr_channels;
bool is_private;
+#define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */
+#define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */
+ unsigned char chan_allocation_order;
};
/**
--
1.7.2.2
Every descriptor can transfer a maximum count of 4095 (12 bits, in control reg),
So we must have DWC_MAX_COUNT as 4095 instead of 2048 for better performance.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index e5d97bf..734829f 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -47,14 +47,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 16480 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
--
1.7.2.2
On 03/03/2011 03:47 PM, Viresh KUMAR wrote:
> - * words, we can do 8192 bytes per descriptor.
> + * words, we can do 16480 bytes per descriptor.
> *
Sorry this should be 16380. Will resend this patch.
--
viresh
On 03/03/2011 03:47 PM, Viresh KUMAR wrote:
> From: Viresh KUMAR <[email protected]>
>
> Msize or Burst Size is peripheral dependent in case of slave_sg transfers, and
> in case of memcpy transfers it is platform dependent. So msize configuration
> must come from platform data.
>
> Also some peripherals (ex: JPEG), need to be flow controller for dma transfers,
> so this information in case of slave_sg transfers must come from platform data.
>
> Signed-off-by: Viresh Kumar <[email protected]>
> ---
> drivers/dma/dw_dmac.c | 10 ++++++----
> drivers/dma/dw_dmac_regs.h | 1 +
> include/linux/dw_dmac.h | 30 ++++++++++++++++++++++++++++++
> 3 files changed, 37 insertions(+), 4 deletions(-)
>
Sorry, i missed similar changes for dw_dma_cyclic_prep(). Will resend it.
--
viresh
Every descriptor can transfer a maximum count of 4095 (12 bits, in control reg),
So we must have DWC_MAX_COUNT as 4095 instead of 2048.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index e5d97bf..711ebe9 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -47,14 +47,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
--
1.7.2.2
From: Viresh KUMAR <[email protected]>
Msize or Burst Size is peripheral dependent in case of prep_slave_sg and
cyclic_prep transfers, and in case of memcpy transfers it is platform dependent.
So msize configuration must come from platform data.
Also some peripherals (ex: JPEG), need to be flow controller for dma transfers,
so this information in case of slave_sg & cyclic_prep transfers must come from
platform data.
Signed-off-by: Viresh Kumar <[email protected]>
---
drivers/dma/dw_dmac.c | 14 ++++++++------
drivers/dma/dw_dmac_regs.h | 1 +
include/linux/dw_dmac.h | 30 ++++++++++++++++++++++++++++++
3 files changed, 39 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 318a342..90ea08a 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -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 : 0; \
+ u8 dmsize = __slave ? __slave->dst_msize : 0; \
\
- (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) \
@@ -683,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;
@@ -728,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) {
@@ -1146,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:
@@ -1157,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:
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 6a8e6d3..9a32964 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -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 */
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 3ba2f06..6998d93 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -42,6 +42,30 @@ enum dw_dma_slave_width {
DW_DMA_SLAVE_WIDTH_32BIT,
};
+/* bursts size */
+enum dw_dma_msize {
+ DW_DMA_MSIZE_1,
+ DW_DMA_MSIZE_4,
+ DW_DMA_MSIZE_8,
+ DW_DMA_MSIZE_16,
+ DW_DMA_MSIZE_32,
+ DW_DMA_MSIZE_64,
+ DW_DMA_MSIZE_128,
+ DW_DMA_MSIZE_256,
+};
+
+/* flow controller */
+enum dw_dma_fc {
+ DW_DMA_FC_D_M2M,
+ DW_DMA_FC_D_M2P,
+ DW_DMA_FC_D_P2M,
+ DW_DMA_FC_D_P2P,
+ DW_DMA_FC_P_P2M,
+ DW_DMA_FC_SP_P2P,
+ DW_DMA_FC_P_M2P,
+ DW_DMA_FC_DP_P2P,
+};
+
/**
* struct dw_dma_slave - Controller-specific information about a slave
*
@@ -55,6 +79,9 @@ enum dw_dma_slave_width {
* @cfg_lo: Platform-specific initializer for the CFG_LO register
* @src_master: src master for transfers on allocated channel.
* @dst_master: dest master for transfers on allocated channel.
+ * @src_msize: src burst size.
+ * @dst_msize: dest burst size.
+ * @fc: flow controller for DMA transfer
*/
struct dw_dma_slave {
struct device *dma_dev;
@@ -65,6 +92,9 @@ struct dw_dma_slave {
u32 cfg_lo;
u8 src_master;
u8 dst_master;
+ u8 src_msize;
+ u8 dst_msize;
+ u8 fc;
};
/* Platform-configurable bits in CFG_HI */
--
1.7.2.2
On Thu, 2011-03-03 at 15:47 +0530, Viresh Kumar wrote:
> Following set of patches extends dw_dmac support and fixes minor bugs.
>
> Changes since V1:
> I had few more patches that i prepared today. I wasn't sure if i should
> add them to existing patchset, but as they are very much associated to this
> patchset, i added them here.
>
> Following new patches have been added in V2:
> - dw_dmac: Replace module_init() with subsys_initcall()
> - dw_dmac: Change value of DWC_MAX_COUNT to 4095
> - dw_dmac: Changing type of src_master and dest_master to u8
> - dw_dmac: Setting Default Burst length for transfers as 16
> - Allow src/dst msize & flow controller to be configured at runtime
> - at32ap700x: Specify DMA Flow Controller, Src and Dst msize or burst size
>
> Other than this following are changes after getting review comments on V1:
> - Added driver dependency on HAVE_CLK & fixed commit message issues
> - Added descriptive commit message in: "Calling dwc_scan_descriptors from..."
> - Aligned struct instance in: "Mark all tx_descriptors with..."
> - Removed: "dw_dmac: call dwc_scan_descriptor from dwc_issue_pending..." as it
> was already commited in linux-next.
>
> Viresh KUMAR (1):
> dw_dmac: Allow src/dst msize & flow controller to be configured at
> runtime
>
> Viresh Kumar (12):
> dw_dmac: Remove compilation dependency from AVR32 and put on HAVE_CLK
> dw_dmac: Replace module_init() with subsys_initcall()
> dw_dmac: Move single descriptor from dwc->queue to dwc->active_list
> in dwc_complete_all
> dw_dmac: Calling dwc_scan_descriptors from dwc_tx_status() after
> taking lock
> dw_dmac: Adding support for 64 bit access width for memcpy xfers
> dw_dmac: Change value of DWC_MAX_COUNT to 4095.
> dw_dmac: Mark all tx_descriptors with DMA_CRTL_ACK after xfer finish
> dw_dmac: Pass Channel Allocation Order from platform_data
> dw_dmac: Pass Channel Priority from platform_data
> dw_dmac: Changing type of src_master and dest_master to u8.
> dw_dmac: Setting Default Burst length for transfers as 16.
> avr32: at32ap700x: Specify DMA Flow Controller, Src and Dst msize or
> burst size
>
> arch/avr32/mach-at32ap/at32ap700x.c | 9 +++++
> drivers/dma/Kconfig | 2 +-
> drivers/dma/dw_dmac.c | 67 +++++++++++++++++++++++------------
> drivers/dma/dw_dmac_regs.h | 4 ++
> include/linux/dw_dmac.h | 43 +++++++++++++++++++++--
> 5 files changed, 98 insertions(+), 27 deletions(-)
>
Thanks, Applied this series (13) and readl/writel fixes patch
--
~Vinod