dw_dmac: autoconfigure data_width or get it via platform data

Not all of the controllers support the 64 bit data width. Make it configurable
via platform data. The driver will try to get a value from the component
parameters, otherwise it will use 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>
This commit is contained in:
Andy Shevchenko 2012-09-21 15:05:48 +03:00 коммит произвёл Vinod Koul
Родитель 4a63a8b3e8
Коммит a09820043c
5 изменённых файлов: 56 добавлений и 6 удалений

Просмотреть файл

@ -79,6 +79,8 @@ struct dw_dma_platform_data dmac_plat_data = {
.chan_allocation_order = CHAN_ALLOCATION_DESCENDING, .chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
.chan_priority = CHAN_PRIORITY_DESCENDING, .chan_priority = CHAN_PRIORITY_DESCENDING,
.block_size = 4095U, .block_size = 4095U,
.nr_masters = 2,
.data_width = { 3, 3, 0, 0 },
}; };
void __init spear13xx_l2x0_init(void) void __init spear13xx_l2x0_init(void)

Просмотреть файл

@ -606,6 +606,8 @@ static void __init genclk_init_parent(struct clk *clk)
static struct dw_dma_platform_data dw_dmac0_data = { static struct dw_dma_platform_data dw_dmac0_data = {
.nr_channels = 3, .nr_channels = 3,
.block_size = 4095U, .block_size = 4095U,
.nr_masters = 2,
.data_width = { 2, 2, 0, 0 },
}; };
static struct resource dw_dmac0_resource[] = { static struct resource dw_dmac0_resource[] = {

Просмотреть файл

@ -36,12 +36,22 @@
* which does not support descriptor writeback. * which does not support descriptor writeback.
*/ */
static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
{
return slave ? slave->dst_master : 0;
}
static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
{
return slave ? slave->src_master : 1;
}
#define DWC_DEFAULT_CTLLO(_chan) ({ \ #define DWC_DEFAULT_CTLLO(_chan) ({ \
struct dw_dma_slave *__slave = (_chan->private); \ struct dw_dma_slave *__slave = (_chan->private); \
struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \
struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \
int _dms = __slave ? __slave->dst_master : 0; \ int _dms = dwc_get_dms(__slave); \
int _sms = __slave ? __slave->src_master : 1; \ int _sms = dwc_get_sms(__slave); \
u8 _smsize = __slave ? _sconfig->src_maxburst : \ u8 _smsize = __slave ? _sconfig->src_maxburst : \
DW_DMA_MSIZE_16; \ DW_DMA_MSIZE_16; \
u8 _dmsize = __slave ? _sconfig->dst_maxburst : \ u8 _dmsize = __slave ? _sconfig->dst_maxburst : \
@ -631,6 +641,7 @@ 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)
{ {
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 = chan->private;
struct dw_desc *desc; struct dw_desc *desc;
struct dw_desc *first; struct dw_desc *first;
struct dw_desc *prev; struct dw_desc *prev;
@ -650,7 +661,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
return NULL; return NULL;
} }
src_width = dst_width = dwc_fast_fls(src | dest | len); src_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_sms(dws)],
dwc_fast_fls(src | len));
dst_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_dms(dws)],
dwc_fast_fls(dest | len));
ctllo = DWC_DEFAULT_CTLLO(chan) ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width) | DWC_CTLL_DST_WIDTH(dst_width)
@ -720,6 +735,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
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 i; unsigned int i;
struct scatterlist *sg; struct scatterlist *sg;
size_t total_len = 0; size_t total_len = 0;
@ -743,6 +759,8 @@ 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 = dwc->dw->data_width[dwc_get_sms(dws)];
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;
@ -750,7 +768,8 @@ 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 = dwc_fast_fls(mem | len); mem_width = min_t(unsigned int,
data_width, dwc_fast_fls(mem | len));
slave_sg_todev_fill_desc: slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc); desc = dwc_desc_get(dwc);
@ -803,6 +822,8 @@ slave_sg_todev_fill_desc:
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 = dwc->dw->data_width[dwc_get_dms(dws)];
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;
@ -810,7 +831,8 @@ slave_sg_todev_fill_desc:
mem = sg_dma_address(sg); mem = sg_dma_address(sg);
len = sg_dma_len(sg); len = sg_dma_len(sg);
mem_width = dwc_fast_fls(mem | len); mem_width = min_t(unsigned int,
data_width, dwc_fast_fls(mem | len));
slave_sg_fromdev_fill_desc: slave_sg_fromdev_fill_desc:
desc = dwc_desc_get(dwc); desc = dwc_desc_get(dwc);
@ -1415,9 +1437,19 @@ static int __devinit dw_probe(struct platform_device *pdev)
dw->regs = regs; dw->regs = regs;
/* get hardware configuration parameters */ /* get hardware configuration parameters */
if (autocfg) if (autocfg) {
max_blk_size = dma_readl(dw, MAX_BLK_SIZE); max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
for (i = 0; i < dw->nr_masters; i++) {
dw->data_width[i] =
(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
}
} else {
dw->nr_masters = pdata->nr_masters;
memcpy(dw->data_width, pdata->data_width, 4);
}
/* Calculate all channel mask before DMA setup */ /* Calculate all channel mask before DMA setup */
dw->all_chan_mask = (1 << nr_channels) - 1; dw->all_chan_mask = (1 << nr_channels) - 1;
@ -1464,6 +1496,8 @@ static int __devinit dw_probe(struct platform_device *pdev)
channel_clear_bit(dw, CH_EN, dwc->mask); channel_clear_bit(dw, CH_EN, dwc->mask);
dwc->dw = dw;
/* hardware configuration */ /* hardware configuration */
if (autocfg) if (autocfg)
/* Decode maximum block size for given channel. The /* Decode maximum block size for given channel. The

Просмотреть файл

@ -198,6 +198,9 @@ struct dw_dma_chan {
/* configuration passed via DMA_SLAVE_CONFIG */ /* configuration passed via DMA_SLAVE_CONFIG */
struct dma_slave_config dma_sconfig; struct dma_slave_config dma_sconfig;
/* backlink to dw_dma */
struct dw_dma *dw;
}; };
static inline struct dw_dma_chan_regs __iomem * static inline struct dw_dma_chan_regs __iomem *
@ -224,6 +227,10 @@ struct dw_dma {
u8 all_chan_mask; u8 all_chan_mask;
/* hardware configuration */
unsigned char nr_masters;
unsigned char data_width[4];
struct dw_dma_chan chan[0]; struct dw_dma_chan chan[0];
}; };

Просмотреть файл

@ -20,6 +20,9 @@
* @is_private: The device channels should be marked as private and not for * @is_private: The device channels should be marked as private and not for
* by the general purpose DMA channel allocator. * by the general purpose DMA channel allocator.
* @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
* @data_width: Maximum data width supported by hardware per AHB master
* (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
*/ */
struct dw_dma_platform_data { struct dw_dma_platform_data {
unsigned int nr_channels; unsigned int nr_channels;
@ -31,6 +34,8 @@ struct dw_dma_platform_data {
#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 short block_size;
unsigned char nr_masters;
unsigned char data_width[4];
}; };
/* bursts size */ /* bursts size */