Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0982004 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Vinod Koul
Browse files

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: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarVinod Koul <vinod.koul@linux.intel.com>
parent 4a63a8b3
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -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)
+2 −0
Original line number Original line Diff line number Diff line
@@ -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[] = {
+40 −6
Original line number Original line Diff line number Diff line
@@ -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 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
		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 @@ 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_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
+7 −0
Original line number Original line Diff line number Diff line
@@ -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];
};
};


+5 −0
Original line number Original line Diff line number Diff line
@@ -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 */