All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: Viresh Kumar <vireshk@kernel.org>,
	dmaengine@vger.kernel.org, Vinod Koul <vkoul@kernel.org>
Subject: [v1,3/5] dmaengine: dw: Split DW and iDMA 32-bit operations
Date: Fri, 30 Nov 2018 22:54:59 +0200	[thread overview]
Message-ID: <20181130205459.GW10650@smile.fi.intel.com> (raw)

On Fri, Nov 30, 2018 at 10:36:44PM +0200, Andy Shevchenko wrote:
> Here is a kinda big refactoring that should have been done
> in the first place, when Intel iDMA 32-bit support appeared.
> 
> It splits operations which are different to Synopsys DesignWare and
> Intel iDMA 32-bit controllers.
> 
> No functional change intended.

While first two are real bug fixes and really small, this one bigger and
suddenly has a typo which I didn't notice during my tests.

Vinod, please, consider applying first two until I will come with better this
one and might be something more.

> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw/Makefile              |   2 +-
>  drivers/dma/dw/core.c                | 188 +++++----------------------
>  drivers/dma/dw/dw.c                  | 109 ++++++++++++++++
>  drivers/dma/dw/idma32.c              | 137 +++++++++++++++++++
>  drivers/dma/dw/internal.h            |  10 +-
>  drivers/dma/dw/pci.c                 |  45 ++++---
>  drivers/dma/dw/platform.c            |   8 +-
>  drivers/dma/dw/regs.h                |  13 ++
>  include/linux/dma/dw.h               |   4 +
>  include/linux/platform_data/dma-dw.h |   2 -
>  10 files changed, 339 insertions(+), 179 deletions(-)
>  create mode 100644 drivers/dma/dw/dw.c
>  create mode 100644 drivers/dma/dw/idma32.c
> 
> diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile
> index 2b949c2e4504..63ed895c09aa 100644
> --- a/drivers/dma/dw/Makefile
> +++ b/drivers/dma/dw/Makefile
> @@ -1,6 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  obj-$(CONFIG_DW_DMAC_CORE)	+= dw_dmac_core.o
> -dw_dmac_core-objs	:= core.o
> +dw_dmac_core-objs	:= core.o dw.o idma32.o
>  
>  obj-$(CONFIG_DW_DMAC)		+= dw_dmac.o
>  dw_dmac-objs		:= platform.o
> diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> index e85b078fc207..711f4d19bbf1 100644
> --- a/drivers/dma/dw/core.c
> +++ b/drivers/dma/dw/core.c
> @@ -138,42 +138,6 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
>  	dwc->descs_allocated--;
>  }
>  
> -static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc)
> -{
> -	u32 cfghi = 0;
> -	u32 cfglo = 0;
> -
> -	/* Set default burst alignment */
> -	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
> -
> -	/* Low 4 bits of the request lines */
> -	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
> -	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
> -
> -	/* Request line extension (2 bits) */
> -	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
> -	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
> -
> -	channel_writel(dwc, CFG_LO, cfglo);
> -	channel_writel(dwc, CFG_HI, cfghi);
> -}
> -
> -static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc)
> -{
> -	u32 cfghi = DWC_CFGH_FIFO_MODE;
> -	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
> -	bool hs_polarity = dwc->dws.hs_polarity;
> -
> -	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
> -	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
> -
> -	/* Set polarity of handshake interface */
> -	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
> -
> -	channel_writel(dwc, CFG_LO, cfglo);
> -	channel_writel(dwc, CFG_HI, cfghi);
> -}
> -
>  static void dwc_initialize(struct dw_dma_chan *dwc)
>  {
>  	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
> @@ -181,10 +145,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
>  	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
>  		return;
>  
> -	if (dw->pdata->is_idma32)
> -		dwc_initialize_chan_idma32(dwc);
> -	else
> -		dwc_initialize_chan_dw(dwc);
> +	dw->initialize_chan(dwc);
>  
>  	/* Enable interrupts */
>  	channel_set_bit(dw, MASK.XFER, dwc->mask);
> @@ -213,37 +174,6 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
>  		cpu_relax();
>  }
>  
> -static u32 bytes2block(struct dw_dma_chan *dwc, size_t bytes,
> -			  unsigned int width, size_t *len)
> -{
> -	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
> -	u32 block;
> -
> -	/* Always in bytes for iDMA 32-bit */
> -	if (dw->pdata->is_idma32)
> -		width = 0;
> -
> -	if ((bytes >> width) > dwc->block_size) {
> -		block = dwc->block_size;
> -		*len = block << width;
> -	} else {
> -		block = bytes >> width;
> -		*len = bytes;
> -	}
> -
> -	return block;
> -}
> -
> -static size_t block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
> -{
> -	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
> -
> -	if (dw->pdata->is_idma32)
> -		return IDMA32C_CTLH_BLOCK_TS(block);
> -
> -	return DWC_CTLH_BLOCK_TS(block) << width;
> -}
> -
>  /*----------------------------------------------------------------------*/
>  
>  /* Perform single block transfer */
> @@ -389,10 +319,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
>  /* Returns how many bytes were already received from source */
>  static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
>  {
> +	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
>  	u32 ctlhi = channel_readl(dwc, CTL_HI);
>  	u32 ctllo = channel_readl(dwc, CTL_LO);
>  
> -	return block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
> +	return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
>  }
>  
>  static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
> @@ -649,7 +580,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>  	unsigned int		src_width;
>  	unsigned int		dst_width;
>  	unsigned int		data_width = dw->pdata->data_width[m_master];
> -	u32			ctllo;
> +	u32			ctllo, ctlhi;
>  	u8			lms = DWC_LLP_LMS(m_master);
>  
>  	dev_vdbg(chan2dev(chan),
> @@ -678,10 +609,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>  		if (!desc)
>  			goto err_desc_get;
>  
> +		ctlhi = dw->bytes2block(dwc, len - offset, src_width, &xfer_count);
> +
>  		lli_write(desc, sar, src + offset);
>  		lli_write(desc, dar, dest + offset);
>  		lli_write(desc, ctllo, ctllo);
> -		lli_write(desc, ctlhi, bytes2block(dwc, len - offset, src_width, &xfer_count));
> +		lli_write(desc, ctlhi, ctlhi);
>  		desc->len = xfer_count;
>  
>  		if (!first) {
> @@ -719,7 +652,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>  	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
>  	struct dw_desc		*prev;
>  	struct dw_desc		*first;
> -	u32			ctllo;
> +	u32			ctllo, ctlhi;
>  	u8			m_master = dwc->dws.m_master;
>  	u8			lms = DWC_LLP_LMS(m_master);
>  	dma_addr_t		reg;
> @@ -766,9 +699,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>  			if (!desc)
>  				goto err_desc_get;
>  
> +			ctlhi = dw->bytes2block(dwc, len, mem_width, &dlen);
> +
>  			lli_write(desc, sar, mem);
>  			lli_write(desc, dar, reg);
> -			lli_write(desc, ctlhi, bytes2block(dwc, len, mem_width, &dlen));
> +			lli_write(desc, ctlhi, ctlhi);
>  			lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
>  			desc->len = dlen;
>  
> @@ -812,9 +747,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>  			if (!desc)
>  				goto err_desc_get;
>  
> +			ctlhi = dw->bytes2block(dwc, len, reg_width, &dlen);
> +
>  			lli_write(desc, sar, reg);
>  			lli_write(desc, dar, mem);
> -			lli_write(desc, ctlhi, bytes2block(dwc, len, reg_width, &dlen));
> +			lli_write(desc, ctlhi, ctlhi);
>  			mem_width = __ffs(data_width | mem | dlen);
>  			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
>  			desc->len = dlen;
> @@ -874,22 +811,12 @@ EXPORT_SYMBOL_GPL(dw_dma_filter);
>  static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
>  {
>  	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
> -	struct dma_slave_config *sc = &dwc->dma_sconfig;
>  	struct dw_dma *dw = to_dw_dma(chan->device);
> -	/*
> -	 * Fix sconfig's burst size according to dw_dmac. We need to convert
> -	 * them as:
> -	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
> -	 *
> -	 * NOTE: burst size 2 is not supported by DesignWare controller.
> -	 *       iDMA 32-bit supports it.
> -	 */
> -	u32 s = dw->pdata->is_idma32 ? 1 : 2;
>  
>  	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
>  
> -	sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
> -	sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;
> +	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
> +	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
>  
>  	return 0;
>  }
> @@ -898,16 +825,9 @@ static void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain)
>  {
>  	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
>  	unsigned int		count = 20;	/* timeout iterations */
> -	u32			cfglo;
>  
> -	cfglo = channel_readl(dwc, CFG_LO);
> -	if (dw->pdata->is_idma32) {
> -		if (drain)
> -			cfglo |= IDMA32C_CFGL_CH_DRAIN;
> -		else
> -			cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
> -	}
> -	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
> +	dw->suspend_chan(dwc, drain);
> +
>  	while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
>  		udelay(2);
>  
> @@ -1056,33 +976,7 @@ static void dwc_issue_pending(struct dma_chan *chan)
>  
>  /*----------------------------------------------------------------------*/
>  
> -/*
> - * Program FIFO size of channels.
> - *
> - * By default full FIFO (512 bytes) is assigned to channel 0. Here we
> - * slice FIFO on equal parts between channels.
> - */
> -static void idma32_fifo_partition(struct dw_dma *dw)
> -{
> -	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
> -		    IDMA32C_FP_UPDATE;
> -	u64 fifo_partition = 0;
> -
> -	if (!dw->pdata->is_idma32)
> -		return;
> -
> -	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
> -	fifo_partition |= value << 0;
> -
> -	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
> -	fifo_partition |= value << 32;
> -
> -	/* Program FIFO Partition registers - 128 bytes for each channel */
> -	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
> -	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
> -}
> -
> -static void dw_dma_off(struct dw_dma *dw)
> +void do_dma_off(struct dw_dma *dw)
>  {
>  	unsigned int i;
>  
> @@ -1101,7 +995,7 @@ static void dw_dma_off(struct dw_dma *dw)
>  		clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags);
>  }
>  
> -static void dw_dma_on(struct dw_dma *dw)
> +void do_dma_on(struct dw_dma *dw)
>  {
>  	dma_writel(dw, CFG, DW_CFG_DMA_EN);
>  }
> @@ -1137,7 +1031,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
>  
>  	/* Enable controller here if needed */
>  	if (!dw->in_use)
> -		dw_dma_on(dw);
> +		do_dma_on(dw);
>  	dw->in_use |= dwc->mask;
>  
>  	return 0;
> @@ -1175,30 +1069,25 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
>  	/* Disable controller in case it was a last user */
>  	dw->in_use &= ~dwc->mask;
>  	if (!dw->in_use)
> -		dw_dma_off(dw);
> +		do_dma_off(dw);
>  
>  	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
>  }
>  
> -int dw_dma_probe(struct dw_dma_chip *chip)
> +int do_dma_probe(struct dw_dma_chip *chip)
>  {
> +	struct dw_dma *dw = chip->dw;
>  	struct dw_dma_platform_data *pdata;
> -	struct dw_dma		*dw;
>  	bool			autocfg = false;
>  	unsigned int		dw_params;
>  	unsigned int		i;
>  	int			err;
>  
> -	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
> -	if (!dw)
> -		return -ENOMEM;
> -
>  	dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
>  	if (!dw->pdata)
>  		return -ENOMEM;
>  
>  	dw->regs = chip->regs;
> -	chip->dw = dw;
>  
>  	pm_runtime_get_sync(chip->dev);
>  
> @@ -1250,15 +1139,10 @@ int dw_dma_probe(struct dw_dma_chip *chip)
>  	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
>  
>  	/* Force dma off, just in case */
> -	dw_dma_off(dw);
> -
> -	idma32_fifo_partition(dw);
> +	dw->disable(dw);
>  
>  	/* Device and instance ID for IRQ and DMA pool */
> -	if (pdata->is_idma32)
> -		snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", chip->id);
> -	else
> -		snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", chip->id);
> +	dw->set_device_name(dw, chip->id);
>  
>  	/* Create a pool of consistent memory blocks for hardware descriptors */
>  	dw->desc_pool = dmam_pool_create(dw->name, chip->dev,
> @@ -1382,16 +1266,15 @@ int dw_dma_probe(struct dw_dma_chip *chip)
>  	pm_runtime_put_sync_suspend(chip->dev);
>  	return err;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_probe);
>  
> -int dw_dma_remove(struct dw_dma_chip *chip)
> +int do_dma_remove(struct dw_dma_chip *chip)
>  {
>  	struct dw_dma		*dw = chip->dw;
>  	struct dw_dma_chan	*dwc, *_dwc;
>  
>  	pm_runtime_get_sync(chip->dev);
>  
> -	dw_dma_off(dw);
> +	do_dma_off(dw);
>  	dma_async_device_unregister(&dw->dma);
>  
>  	free_irq(chip->irq, dw);
> @@ -1406,27 +1289,24 @@ int dw_dma_remove(struct dw_dma_chip *chip)
>  	pm_runtime_put_sync_suspend(chip->dev);
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_remove);
>  
> -int dw_dma_disable(struct dw_dma_chip *chip)
> +int do_dw_dma_disable(struct dw_dma_chip *chip)
>  {
>  	struct dw_dma *dw = chip->dw;
>  
> -	dw_dma_off(dw);
> +	dw->disable(dw);
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_disable);
> +EXPORT_SYMBOL_GPL(do_dw_dma_disable);
>  
> -int dw_dma_enable(struct dw_dma_chip *chip)
> +int do_dw_dma_enable(struct dw_dma_chip *chip)
>  {
>  	struct dw_dma *dw = chip->dw;
>  
> -	idma32_fifo_partition(dw);
> -
> -	dw_dma_on(dw);
> +	dw->disable(dw);
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_enable);
> +EXPORT_SYMBOL_GPL(do_dw_dma_enable);
>  
>  MODULE_LICENSE("GPL v2");
>  MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
> diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c
> new file mode 100644
> index 000000000000..998a9eeb561d
> --- /dev/null
> +++ b/drivers/dma/dw/dw.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2007-2008 Atmel Corporation
> +// Copyright (C) 2010-2011 ST Microelectronics
> +// Copyright (C) 2013,2018 Intel Corporation
> +
> +#include <linux/bitops.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +
> +#include "internal.h"
> +
> +static void dw_dma_initialize_chan(struct dw_dma_chan *dwc)
> +{
> +	u32 cfghi = DWC_CFGH_FIFO_MODE;
> +	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
> +	bool hs_polarity = dwc->dws.hs_polarity;
> +
> +	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
> +	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
> +
> +	/* Set polarity of handshake interface */
> +	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
> +
> +	channel_writel(dwc, CFG_LO, cfglo);
> +	channel_writel(dwc, CFG_HI, cfghi);
> +}
> +
> +static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain)
> +{
> +	u32 cfglo = channel_readl(dwc, CFG_LO);
> +
> +	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
> +}
> +
> +static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc,
> +			      size_t bytes, unsigned int width, size_t *len)
> +{
> +	u32 block;
> +
> +	if ((bytes >> width) > dwc->block_size) {
> +		block = dwc->block_size;
> +		*len = block << width;
> +	} else {
> +		block = bytes >> width;
> +		*len = bytes;
> +	}
> +
> +	return block;
> +}
> +
> +static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
> +{
> +	return DWC_CTLH_BLOCK_TS(block) << width;
> +}
> +
> +static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
> +{
> +	/*
> +	 * Fix burst size according to dw_dmac. We need to convert them as:
> +	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
> +	 */
> +	*maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0;
> +}
> +
> +static void dw_dma_set_device_name(struct dw_dma *dw, int id)
> +{
> +	snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", id);
> +}
> +
> +static void dw_dma_disable(struct dw_dma *dw)
> +{
> +	do_dma_off(dw);
> +}
> +
> +static void dw_dma_enable(struct dw_dma *dw)
> +{
> +	do_dma_on(dw);
> +}
> +
> +int dw_dma_probe(struct dw_dma_chip *chip)
> +{
> +	struct dw_dma *dw;
> +
> +	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	/* Channel operations */
> +	dw->initialize_chan = dw_dma_initialize_chan;
> +	dw->suspend_chan = dw_dma_suspend_chan;
> +	dw->encode_maxburst = dw_dma_encode_maxburst;
> +	dw->bytes2block = dw_dma_bytes2block;
> +	dw->block2bytes = dw_dma_block2bytes;
> +
> +	/* Device operations */
> +	dw->set_device_name = dw_dma_set_device_name;
> +	dw->disable = dw_dma_disable;
> +	dw->enable = dw_dma_enable;
> +
> +	chip->dw = dw;
> +	return do_dma_probe(chip);
> +}
> +EXPORT_SYMBOL_GPL(dw_dma_probe);
> +
> +int dw_dma_remove(struct dw_dma_chip *chip)
> +{
> +	return do_dma_remove(chip);
> +}
> +EXPORT_SYMBOL_GPL(dw_dma_remove);
> diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c
> new file mode 100644
> index 000000000000..d06fb00fb862
> --- /dev/null
> +++ b/drivers/dma/dw/idma32.c
> @@ -0,0 +1,137 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2013,2018 Intel Corporation
> +
> +#include <linux/bitops.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +
> +#include "internal.h"
> +
> +static void idma32_initialize_chan(struct dw_dma_chan *dwc)
> +{
> +	u32 cfghi = 0;
> +	u32 cfglo = 0;
> +
> +	/* Set default burst alignment */
> +	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
> +
> +	/* Low 4 bits of the request lines */
> +	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
> +	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
> +
> +	/* Request line extension (2 bits) */
> +	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
> +	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
> +
> +	channel_writel(dwc, CFG_LO, cfglo);
> +	channel_writel(dwc, CFG_HI, cfghi);
> +}
> +
> +static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain)
> +{
> +	u32 cfglo = channel_readl(dwc, CFG_LO);
> +
> +	if (drain)
> +		cfglo |= IDMA32C_CFGL_CH_DRAIN;
> +	else
> +		cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
> +
> +	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
> +}
> +
> +static u32 idma32_bytes2block(struct dw_dma_chan *dwc,
> +			      size_t bytes, unsigned int width, size_t *len)
> +{
> +	u32 block;
> +
> +	if (bytes > dwc->block_size) {
> +		block = dwc->block_size;
> +		*len = dwc->block_size;
> +	} else {
> +		block = bytes;
> +		*len = bytes;
> +	}
> +
> +	return block;
> +}
> +
> +static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
> +{
> +	return IDMA32C_CTLH_BLOCK_TS(block);
> +}
> +
> +static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
> +{
> +	*maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0;
> +}
> +
> +static void idma32_set_device_name(struct dw_dma *dw, int id)
> +{
> +	snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", id);
> +}
> +
> +/*
> + * Program FIFO size of channels.
> + *
> + * By default full FIFO (512 bytes) is assigned to channel 0. Here we
> + * slice FIFO on equal parts between channels.
> + */
> +static void idma32_fifo_partition(struct dw_dma *dw)
> +{
> +	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
> +		    IDMA32C_FP_UPDATE;
> +	u64 fifo_partition = 0;
> +
> +	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
> +	fifo_partition |= value << 0;
> +
> +	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
> +	fifo_partition |= value << 32;
> +
> +	/* Program FIFO Partition registers - 128 bytes for each channel */
> +	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
> +	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
> +}
> +
> +static void idma32_disable(struct dw_dma *dw)
> +{
> +	do_dma_off(dw);
> +	idma32_fifo_partition(dw);
> +}
> +
> +static void idma32_enable(struct dw_dma *dw)
> +{
> +	idma32_fifo_partition(dw);
> +	do_dma_on(dw);
> +}
> +
> +int idma32_dma_probe(struct dw_dma_chip *chip)
> +{
> +	struct dw_dma *dw;
> +
> +	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	/* Channel operations */
> +	dw->initialize_chan = idma32_initialize_chan;
> +	dw->suspend_chan = idma32_suspend_chan;
> +	dw->encode_maxburst = idma32_encode_maxburst;
> +	dw->bytes2block = idma32_bytes2block;
> +	dw->block2bytes = idma32_block2bytes;
> +
> +	/* Device operations */
> +	dw->set_device_name = idma32_set_device_name;
> +	dw->disable = idma32_disable;
> +	dw->enable = idma32_enable;
> +
> +	chip->dw = dw;
> +	return do_dma_probe(chip);
> +}
> +EXPORT_SYMBOL_GPL(idma32_dma_probe);
> +
> +int idma32_dma_remove(struct dw_dma_chip *chip)
> +{
> +	return do_dma_remove(chip);
> +}
> +EXPORT_SYMBOL_GPL(idma32_dma_remove);
> diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h
> index 41439732ff6b..1f2ddfe745bb 100644
> --- a/drivers/dma/dw/internal.h
> +++ b/drivers/dma/dw/internal.h
> @@ -15,8 +15,14 @@
>  
>  #include "regs.h"
>  
> -int dw_dma_disable(struct dw_dma_chip *chip);
> -int dw_dma_enable(struct dw_dma_chip *chip);
> +int do_dma_probe(struct dw_dma_chip *chip);
> +int do_dma_remove(struct dw_dma_chip *chip);
> +
> +void do_dma_on(struct dw_dma *dw);
> +void do_dma_off(struct dw_dma *dw);
> +
> +int do_dw_dma_disable(struct dw_dma_chip *chip);
> +int do_dw_dma_enable(struct dw_dma_chip *chip);
>  
>  extern bool dw_dma_filter(struct dma_chan *chan, void *param);
>  
> diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
> index 61f2274f6dd4..f5ea58cc027b 100644
> --- a/drivers/dma/dw/pci.c
> +++ b/drivers/dma/dw/pci.c
> @@ -15,11 +15,19 @@
>  
>  #include "internal.h"
>  
> -static struct dw_dma_platform_data mrfld_pdata = {
> +static struct dw_dma_pci_data {
> +	const struct dw_dma_platform_data *pdata;
> +	int (*probe)(struct dw_dma_chip *chip);
> +};
> +
> +static const struct dw_dma_pci_data dw_pci_data = {
> +	.probe = dw_dma_probe,
> +};
> +
> +static const struct dw_dma_platform_data idma32_pdata = {
>  	.nr_channels = 8,
>  	.is_private = true,
>  	.is_memcpy = true,
> -	.is_idma32 = true,
>  	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
>  	.chan_priority = CHAN_PRIORITY_ASCENDING,
>  	.block_size = 131071,
> @@ -28,9 +36,14 @@ static struct dw_dma_platform_data mrfld_pdata = {
>  	.multi_block = {true, true, true, true, true, true, true, true},
>  };
>  
> +static const struct dw_dma_pci_data idma32_pci_data = {
> +	.pdata = &idma32_pdata,
> +	.probe = idma32_dma_probe,
> +};
> +
>  static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
>  {
> -	const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
> +	const struct dw_dma_pci_data *data = (void *)pid->driver_data;
>  	struct dw_dma_chip *chip;
>  	int ret;
>  
> @@ -63,9 +76,9 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
>  	chip->id = pdev->devfn;
>  	chip->regs = pcim_iomap_table(pdev)[0];
>  	chip->irq = pdev->irq;
> -	chip->pdata = pdata;
> +	chip->pdata = data->pdata;
>  
> -	ret = dw_dma_probe(chip);
> +	ret = data->probe(chip);
>  	if (ret)
>  		return ret;
>  
> @@ -91,7 +104,7 @@ static int dw_pci_suspend_late(struct device *dev)
>  	struct pci_dev *pci = to_pci_dev(dev);
>  	struct dw_dma_chip *chip = pci_get_drvdata(pci);
>  
> -	return dw_dma_disable(chip);
> +	return do_dw_dma_disable(chip);
>  };
>  
>  static int dw_pci_resume_early(struct device *dev)
> @@ -99,7 +112,7 @@ static int dw_pci_resume_early(struct device *dev)
>  	struct pci_dev *pci = to_pci_dev(dev);
>  	struct dw_dma_chip *chip = pci_get_drvdata(pci);
>  
> -	return dw_dma_enable(chip);
> +	return do_dw_dma_enable(chip);
>  };
>  
>  #endif /* CONFIG_PM_SLEEP */
> @@ -110,24 +123,24 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
>  
>  static const struct pci_device_id dw_pci_id_table[] = {
>  	/* Medfield (GPDMA) */
> -	{ PCI_VDEVICE(INTEL, 0x0827) },
> +	{ PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data },
>  
>  	/* BayTrail */
> -	{ PCI_VDEVICE(INTEL, 0x0f06) },
> -	{ PCI_VDEVICE(INTEL, 0x0f40) },
> +	{ PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data },
> +	{ PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data },
>  
> -	/* Merrifield iDMA 32-bit (GPDMA) */
> -	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&mrfld_pdata },
> +	/* Merrifield */
> +	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data },
>  
>  	/* Braswell */
> -	{ PCI_VDEVICE(INTEL, 0x2286) },
> -	{ PCI_VDEVICE(INTEL, 0x22c0) },
> +	{ PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data },
> +	{ PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data },
>  
>  	/* Haswell */
> -	{ PCI_VDEVICE(INTEL, 0x9c60) },
> +	{ PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data },
>  
>  	/* Broadwell */
> -	{ PCI_VDEVICE(INTEL, 0x9ce0) },
> +	{ PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data },
>  
>  	{ }
>  };
> diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
> index f01b2c173fa6..6bf46c9b7ee4 100644
> --- a/drivers/dma/dw/platform.c
> +++ b/drivers/dma/dw/platform.c
> @@ -258,7 +258,7 @@ static void dw_shutdown(struct platform_device *pdev)
>  	struct dw_dma_chip *chip = platform_get_drvdata(pdev);
>  
>  	/*
> -	 * We have to call dw_dma_disable() to stop any ongoing transfer. On
> +	 * We have to call do_dw_dma_disable() to stop any ongoing transfer. On
>  	 * some platforms we can't do that since DMA device is powered off.
>  	 * Moreover we have no possibility to check if the platform is affected
>  	 * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put()
> @@ -267,7 +267,7 @@ static void dw_shutdown(struct platform_device *pdev)
>  	 * used by the driver.
>  	 */
>  	pm_runtime_get_sync(chip->dev);
> -	dw_dma_disable(chip);
> +	do_dw_dma_disable(chip);
>  	pm_runtime_put_sync_suspend(chip->dev);
>  
>  	clk_disable_unprepare(chip->clk);
> @@ -297,7 +297,7 @@ static int dw_suspend_late(struct device *dev)
>  {
>  	struct dw_dma_chip *chip = dev_get_drvdata(dev);
>  
> -	dw_dma_disable(chip);
> +	do_dw_dma_disable(chip);
>  	clk_disable_unprepare(chip->clk);
>  
>  	return 0;
> @@ -312,7 +312,7 @@ static int dw_resume_early(struct device *dev)
>  	if (ret)
>  		return ret;
>  
> -	return dw_dma_enable(chip);
> +	return do_dw_dma_enable(chip);
>  }
>  
>  #endif /* CONFIG_PM_SLEEP */
> diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
> index 09e7dfdbb790..90e46e69c047 100644
> --- a/drivers/dma/dw/regs.h
> +++ b/drivers/dma/dw/regs.h
> @@ -308,6 +308,19 @@ struct dw_dma {
>  	u8			all_chan_mask;
>  	u8			in_use;
>  
> +	/* Channel operations */
> +	void	(*initialize_chan)(struct dw_dma_chan *dwc);
> +	void	(*suspend_chan)(struct dw_dma_chan *dwc, bool drain);
> +	void	(*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst);
> +	u32	(*bytes2block)(struct dw_dma_chan *dwc, size_t bytes,
> +			       unsigned int width, size_t *len);
> +	size_t	(*block2bytes)(struct dw_dma_chan *dwc, u32 block, u32 width);
> +
> +	/* Device operations */
> +	void (*set_device_name)(struct dw_dma *dw, int id);
> +	void (*disable)(struct dw_dma *dw);
> +	void (*enable)(struct dw_dma *dw);
> +
>  	/* platform data */
>  	struct dw_dma_platform_data	*pdata;
>  };
> diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h
> index e166cac8e870..d643d331c20e 100644
> --- a/include/linux/dma/dw.h
> +++ b/include/linux/dma/dw.h
> @@ -45,9 +45,13 @@ struct dw_dma_chip {
>  #if IS_ENABLED(CONFIG_DW_DMAC_CORE)
>  int dw_dma_probe(struct dw_dma_chip *chip);
>  int dw_dma_remove(struct dw_dma_chip *chip);
> +int idma32_dma_probe(struct dw_dma_chip *chip);
> +int idma32_dma_remove(struct dw_dma_chip *chip);
>  #else
>  static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
>  static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; }
> +static inline int idma32_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
> +static inline int idma32_dma_remove(struct dw_dma_chip *chip) { return 0; }
>  #endif /* CONFIG_DW_DMAC_CORE */
>  
>  #endif /* _DMA_DW_H */
> diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h
> index 896cb71a382c..e69e415d0d98 100644
> --- a/include/linux/platform_data/dma-dw.h
> +++ b/include/linux/platform_data/dma-dw.h
> @@ -41,7 +41,6 @@ struct dw_dma_slave {
>   * @is_private: The device channels should be marked as private and not for
>   *	by the general purpose DMA channel allocator.
>   * @is_memcpy: The device channels do support memory-to-memory transfers.
> - * @is_idma32: The type of the DMA controller is iDMA32
>   * @chan_allocation_order: Allocate channels starting from 0 or 7
>   * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
>   * @block_size: Maximum block size supported by the controller
> @@ -54,7 +53,6 @@ struct dw_dma_platform_data {
>  	unsigned int	nr_channels;
>  	bool		is_private;
>  	bool		is_memcpy;
> -	bool		is_idma32;
>  #define CHAN_ALLOCATION_ASCENDING	0	/* zero to seven */
>  #define CHAN_ALLOCATION_DESCENDING	1	/* seven to zero */
>  	unsigned char	chan_allocation_order;
> -- 
> 2.19.2
>

             reply	other threads:[~2018-11-30 20:54 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-30 20:54 Andy Shevchenko [this message]
  -- strict thread matches above, loose matches on Subject: below --
2018-12-01  3:30 [v1,3/5] dmaengine: dw: Split DW and iDMA 32-bit operations kbuild test robot
2018-11-30 20:36 Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181130205459.GW10650@smile.fi.intel.com \
    --to=andriy.shevchenko@linux.intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=vireshk@kernel.org \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.