diff options
author | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2012-09-21 16:05:47 +0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@linux.intel.com> | 2012-09-27 14:05:23 +0400 |
commit | 4a63a8b3e8d2e4f56174deb728085010aa3ac2a1 (patch) | |
tree | 0c6d4fb4cd88f9c7fff748909e5956ea55793ef0 | |
parent | 482c67ea7bab80b956185a3e7553151820bc5876 (diff) | |
download | linux-4a63a8b3e8d2e4f56174deb728085010aa3ac2a1.tar.xz |
dw_dmac: autoconfigure block_size or use platform data
The maximum block size is a configurable parameter for the chip. So, driver
will try to get it from the encoded component parameters. Otherwise it will
come from the platform data.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
-rw-r--r-- | arch/arm/mach-spear13xx/spear13xx.c | 1 | ||||
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap700x.c | 1 | ||||
-rw-r--r-- | drivers/dma/dw_dmac.c | 37 | ||||
-rw-r--r-- | drivers/dma/dw_dmac_regs.h | 3 | ||||
-rw-r--r-- | include/linux/dw_dmac.h | 2 |
5 files changed, 28 insertions, 16 deletions
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c index cf936b106e27..c64d8123518f 100644 --- a/arch/arm/mach-spear13xx/spear13xx.c +++ b/arch/arm/mach-spear13xx/spear13xx.c @@ -78,6 +78,7 @@ struct dw_dma_platform_data dmac_plat_data = { .nr_channels = 8, .chan_allocation_order = CHAN_ALLOCATION_DESCENDING, .chan_priority = CHAN_PRIORITY_DESCENDING, + .block_size = 4095U, }; void __init spear13xx_l2x0_init(void) diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index 0445c4fd67e3..2c4aefeb86b5 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -605,6 +605,7 @@ static void __init genclk_init_parent(struct clk *clk) static struct dw_dma_platform_data dw_dmac0_data = { .nr_channels = 3, + .block_size = 4095U, }; static struct resource dw_dmac0_resource[] = { diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index d71bc7167891..c143b7e40716 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -56,16 +56,6 @@ }) /* - * This is configuration-dependent and usually a funny size like 4095. - * - * Note that this is a transfer count, i.e. if we transfer 32-bit - * words, we can do 16380 bytes per descriptor. - * - * This parameter is also system-specific. - */ -#define DWC_MAX_COUNT 4095U - -/* * 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. @@ -672,7 +662,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, for (offset = 0; offset < len; offset += xfer_count << src_width) { xfer_count = min_t(size_t, (len - offset) >> src_width, - DWC_MAX_COUNT); + dwc->block_size); desc = dwc_desc_get(dwc); if (!desc) @@ -773,8 +763,8 @@ slave_sg_todev_fill_desc: desc->lli.sar = mem; desc->lli.dar = reg; desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width); - if ((len >> mem_width) > DWC_MAX_COUNT) { - dlen = DWC_MAX_COUNT << mem_width; + if ((len >> mem_width) > dwc->block_size) { + dlen = dwc->block_size << mem_width; mem += dlen; len -= dlen; } else { @@ -833,8 +823,8 @@ slave_sg_fromdev_fill_desc: desc->lli.sar = reg; desc->lli.dar = mem; desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width); - if ((len >> reg_width) > DWC_MAX_COUNT) { - dlen = DWC_MAX_COUNT << reg_width; + if ((len >> reg_width) > dwc->block_size) { + dlen = dwc->block_size << reg_width; mem += dlen; len -= dlen; } else { @@ -1217,7 +1207,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, periods = buf_len / period_len; /* Check for too big/unaligned periods and unaligned DMA buffer. */ - if (period_len > (DWC_MAX_COUNT << reg_width)) + if (period_len > (dwc->block_size << reg_width)) goto out_err; if (unlikely(period_len & ((1 << reg_width) - 1))) goto out_err; @@ -1383,6 +1373,7 @@ static int __devinit dw_probe(struct platform_device *pdev) bool autocfg; unsigned int dw_params; unsigned int nr_channels; + unsigned int max_blk_size = 0; int irq; int err; int i; @@ -1423,6 +1414,10 @@ static int __devinit dw_probe(struct platform_device *pdev) dw->regs = regs; + /* get hardware configuration parameters */ + if (autocfg) + max_blk_size = dma_readl(dw, MAX_BLK_SIZE); + /* Calculate all channel mask before DMA setup */ dw->all_chan_mask = (1 << nr_channels) - 1; @@ -1468,6 +1463,16 @@ static int __devinit dw_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dwc->free_list); channel_clear_bit(dw, CH_EN, dwc->mask); + + /* hardware configuration */ + if (autocfg) + /* Decode maximum block size for given channel. The + * stored 4 bit value represents blocks from 0x00 for 3 + * up to 0x0a for 4095. */ + dwc->block_size = + (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1; + else + dwc->block_size = pdata->block_size; } /* Clear all interrupts on all channels. */ diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 8a3a81adbf78..2a1cc533f0c8 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -193,6 +193,9 @@ struct dw_dma_chan { unsigned int descs_allocated; + /* hardware configuration */ + unsigned int block_size; + /* configuration passed via DMA_SLAVE_CONFIG */ struct dma_slave_config dma_sconfig; }; diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h index 2412e02d7c0f..3315ef9c785b 100644 --- a/include/linux/dw_dmac.h +++ b/include/linux/dw_dmac.h @@ -19,6 +19,7 @@ * @nr_channels: Number of channels supported by hardware (max 8) * @is_private: The device channels should be marked as private and not for * by the general purpose DMA channel allocator. + * @block_size: Maximum block size supported by the controller */ struct dw_dma_platform_data { unsigned int nr_channels; @@ -29,6 +30,7 @@ struct dw_dma_platform_data { #define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */ #define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */ unsigned char chan_priority; + unsigned short block_size; }; /* bursts size */ |