Skip to content

Commit

Permalink
dw_dmac: autoconfigure data_width or get it via platform data
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
andy-shev authored and Vinod Koul committed Sep 27, 2012
1 parent 4a63a8b commit a098200
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 6 deletions.
2 changes: 2 additions & 0 deletions arch/arm/mach-spear13xx/spear13xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct dw_dma_platform_data dmac_plat_data = {
.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
.chan_priority = CHAN_PRIORITY_DESCENDING,
.block_size = 4095U,
.nr_masters = 2,
.data_width = { 3, 3, 0, 0 },
};

void __init spear13xx_l2x0_init(void)
Expand Down
2 changes: 2 additions & 0 deletions arch/avr32/mach-at32ap/at32ap700x.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ static void __init genclk_init_parent(struct clk *clk)
static struct dw_dma_platform_data dw_dmac0_data = {
.nr_channels = 3,
.block_size = 4095U,
.nr_masters = 2,
.data_width = { 2, 2, 0, 0 },
};

static struct resource dw_dmac0_resource[] = {
Expand Down
46 changes: 40 additions & 6 deletions drivers/dma/dw_dmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,22 @@
* 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) ({ \
struct dw_dma_slave *__slave = (_chan->private); \
struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \
struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \
int _dms = __slave ? __slave->dst_master : 0; \
int _sms = __slave ? __slave->src_master : 1; \
int _dms = dwc_get_dms(__slave); \
int _sms = dwc_get_sms(__slave); \
u8 _smsize = __slave ? _sconfig->src_maxburst : \
DW_DMA_MSIZE_16; \
u8 _dmsize = __slave ? _sconfig->dst_maxburst : \
Expand Down Expand Up @@ -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)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma_slave *dws = chan->private;
struct dw_desc *desc;
struct dw_desc *first;
struct dw_desc *prev;
Expand All @@ -650,7 +661,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
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)
| DWC_CTLL_DST_WIDTH(dst_width)
Expand Down Expand Up @@ -720,6 +735,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
dma_addr_t reg;
unsigned int reg_width;
unsigned int mem_width;
unsigned int data_width;
unsigned int i;
struct scatterlist *sg;
size_t total_len = 0;
Expand All @@ -743,14 +759,17 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_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) {
struct dw_desc *desc;
u32 len, dlen, mem;

mem = sg_dma_address(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:
desc = dwc_desc_get(dwc);
Expand Down Expand Up @@ -803,14 +822,17 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_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) {
struct dw_desc *desc;
u32 len, dlen, mem;

mem = sg_dma_address(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:
desc = dwc_desc_get(dwc);
Expand Down Expand Up @@ -1415,9 +1437,19 @@ static int __devinit dw_probe(struct platform_device *pdev)
dw->regs = regs;

/* get hardware configuration parameters */
if (autocfg)
if (autocfg) {
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 */
dw->all_chan_mask = (1 << nr_channels) - 1;

Expand Down Expand Up @@ -1464,6 +1496,8 @@ static int __devinit dw_probe(struct platform_device *pdev)

channel_clear_bit(dw, CH_EN, dwc->mask);

dwc->dw = dw;

/* hardware configuration */
if (autocfg)
/* Decode maximum block size for given channel. The
Expand Down
7 changes: 7 additions & 0 deletions drivers/dma/dw_dmac_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ struct dw_dma_chan {

/* configuration passed via DMA_SLAVE_CONFIG */
struct dma_slave_config dma_sconfig;

/* backlink to dw_dma */
struct dw_dma *dw;
};

static inline struct dw_dma_chan_regs __iomem *
Expand All @@ -224,6 +227,10 @@ struct dw_dma {

u8 all_chan_mask;

/* hardware configuration */
unsigned char nr_masters;
unsigned char data_width[4];

struct dw_dma_chan chan[0];
};

Expand Down
5 changes: 5 additions & 0 deletions include/linux/dw_dmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
* @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
* @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 {
unsigned int nr_channels;
Expand All @@ -31,6 +34,8 @@ struct dw_dma_platform_data {
#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */
unsigned char chan_priority;
unsigned short block_size;
unsigned char nr_masters;
unsigned char data_width[4];
};

/* bursts size */
Expand Down

0 comments on commit a098200

Please sign in to comment.