[RFC PATCH 2/3] mmc: host: omap_hsmmc: Enable ADMA2

Peter Ujfalusi peter.ujfalusi at ti.com
Thu May 19 01:25:06 PDT 2016


On 05/18/2016 11:45 AM, Kishon Vijay Abraham I wrote:
> omap hsmmc host controller has ADMA2 feature. Enable it here
> for better read and write throughput. Add a new dt binding
> "ti,use_adma" to enable ADMA2.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon at ti.com>
> ---
>  .../devicetree/bindings/mmc/ti-omap-hsmmc.txt      |    1 +
>  drivers/mmc/host/omap_hsmmc.c                      |  320 ++++++++++++++++----
>  include/linux/platform_data/hsmmc-omap.h           |    1 +
>  3 files changed, 256 insertions(+), 66 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
> index 74166a0..eb5ceec2 100644
> --- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
> +++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
> @@ -28,6 +28,7 @@ specifier is required.
>  dma-names: List of DMA request names. These strings correspond
>  1:1 with the DMA specifiers listed in dmas. The string naming is
>  to be "rx" and "tx" for RX and TX DMA requests, respectively.
> +ti,use_adma: enable adma2 feature
>  
>  Examples:
>  
> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
> index cc916d5..b4a7d18 100644
> --- a/drivers/mmc/host/omap_hsmmc.c
> +++ b/drivers/mmc/host/omap_hsmmc.c
> @@ -66,6 +66,8 @@
>  #define OMAP_HSMMC_ISE		0x0138
>  #define OMAP_HSMMC_AC12		0x013C
>  #define OMAP_HSMMC_CAPA		0x0140
> +#define OMAP_HSMMC_ADMAES	0x0154
> +#define OMAP_HSMMC_ADMASAL	0x0158
>  
>  #define VS18			(1 << 26)
>  #define VS30			(1 << 25)
> @@ -76,6 +78,7 @@
>  #define SDVS_MASK		0x00000E00
>  #define SDVSCLR			0xFFFFF1FF
>  #define SDVSDET			0x00000400
> +#define DMA_SELECT		(2 << 3)
>  #define AUTOIDLE		0x1
>  #define SDBP			(1 << 8)
>  #define DTO			0xe
> @@ -97,6 +100,7 @@
>  #define FOUR_BIT		(1 << 1)
>  #define HSPE			(1 << 2)
>  #define IWE			(1 << 24)
> +#define DMA_MASTER		(1 << 20)
>  #define DDR			(1 << 19)
>  #define CLKEXTFREE		(1 << 16)
>  #define CTPL			(1 << 11)
> @@ -127,10 +131,11 @@
>  #define DCRC_EN			(1 << 21)
>  #define DEB_EN			(1 << 22)
>  #define ACE_EN			(1 << 24)
> +#define ADMAE_EN		(1 << 24)
>  #define CERR_EN			(1 << 28)
>  #define BADA_EN			(1 << 29)
>  
> -#define INT_EN_MASK (BADA_EN | CERR_EN | ACE_EN | DEB_EN | DCRC_EN |\
> +#define INT_EN_MASK (BADA_EN | CERR_EN | ADMAE_EN | ACE_EN | DEB_EN | DCRC_EN |\
>  		DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
>  		BRR_EN | BWR_EN | TC_EN | CC_EN)
>  
> @@ -168,6 +173,25 @@
>  #define OMAP_HSMMC_WRITE(base, reg, val) \
>  	__raw_writel((val), (base) + OMAP_HSMMC_##reg)
>  
> +struct omap_hsmmc_adma_desc {
> +	u8 attr;
> +	u8 reserved;
> +	u16 len;
> +	u32 addr;
> +} __packed;
> +
> +#define ADMA_MAX_LEN			65532
> +
> +/* Decriptor table defines */
> +#define ADMA_DESC_ATTR_VALID		BIT(0)
> +#define ADMA_DESC_ATTR_END		BIT(1)
> +#define ADMA_DESC_ATTR_INT		BIT(2)
> +#define ADMA_DESC_ATTR_ACT1		BIT(4)
> +#define ADMA_DESC_ATTR_ACT2		BIT(5)
> +
> +#define ADMA_DESC_TRANSFER_DATA		ADMA_DESC_ATTR_ACT2
> +#define ADMA_DESC_LINK_DESC	(ADMA_DESC_ATTR_ACT1 | ADMA_DESC_ATTR_ACT2)
> +
>  struct omap_hsmmc_next {
>  	unsigned int	dma_len;
>  	s32		cookie;
> @@ -213,6 +237,9 @@ struct omap_hsmmc_host {
>  	struct omap_hsmmc_next	next_data;
>  	struct	omap_hsmmc_platform_data	*pdata;
>  
> +	struct omap_hsmmc_adma_desc *adma_desc_table;
> +	dma_addr_t              adma_desc_table_addr;
> +
>  	/* return MMC cover switch state, can be NULL if not supported.
>  	 *
>  	 * possible return values:
> @@ -951,6 +978,19 @@ static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
>  	return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
>  }
>  
> +static void omap_hsmmc_adma_cleanup(struct omap_hsmmc_host *host)
> +{
> +	u32 val;
> +
> +	val = OMAP_HSMMC_READ(host->base, HCTL);
> +	val &= ~DMA_SELECT;
> +	OMAP_HSMMC_WRITE(host->base, HCTL, val);
> +
> +	val = OMAP_HSMMC_READ(host->base, CON);
> +	val &= ~DMA_MASTER;
> +	OMAP_HSMMC_WRITE(host->base, CON, val);
> +}
> +
>  static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
>  {
>  	int dma_ch;
> @@ -963,8 +1003,11 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
>  
>  	omap_hsmmc_disable_irq(host);
>  	/* Do not complete the request if DMA is still in progress */
> -	if (mrq->data && dma_ch != -1)
> +	if (host->pdata->controller_flags == OMAP_HSMMC_USE_ADMA)

host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA

and I would probably name the flag to OMAP_HSMMC_MASTER_DMA_SUPPORTED

> +		omap_hsmmc_adma_cleanup(host);
> +	else if (mrq->data && dma_ch != -1)
>  		return;
> +
>  	host->mrq = NULL;
>  	mmc_request_done(host->mmc, mrq);
>  	pm_runtime_mark_last_busy(host->dev);
> @@ -1052,15 +1095,22 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
>  	host->dma_ch = -1;
>  	spin_unlock_irqrestore(&host->irq_lock, flags);
>  
> -	if (dma_ch != -1) {
> -		struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data);
> -
> -		dmaengine_terminate_all(chan);
> -		dma_unmap_sg(chan->device->dev,
> -			host->data->sg, host->data->sg_len,
> +	if (!(host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA)) {

it might be better to use the same order in the driver for Master and Slave
DMA cases:

if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA) {
	/* Master DMA case */
} else {
	/* Slave DMA case */
}

It will make the driver easier to read.

> +		if (dma_ch != -1) {
> +			struct dma_chan *chan = omap_hsmmc_get_dma_chan(host,
> +								host->data);
> +			dmaengine_terminate_all(chan);
> +			dma_unmap_sg(chan->device->dev,
> +				     host->data->sg, host->data->sg_len,
>  			omap_hsmmc_get_dma_dir(host, host->data));
>  
> +			host->data->host_cookie = 0;
> +		}
> +	} else {
> +		dma_unmap_sg(host->dev, host->data->sg, host->data->sg_len,
> +			     omap_hsmmc_get_dma_dir(host, host->data));
>  		host->data->host_cookie = 0;
> +
>  	}
>  	host->data = NULL;
>  }
> @@ -1191,6 +1241,14 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
>  			}
>  			dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
>  		}
> +
> +		if (status & ADMAE_EN) {
> +			u32 val;
> +
> +			val = OMAP_HSMMC_READ(host->base, ADMAES);
> +			dev_dbg(mmc_dev(host->mmc), "ADMA error status: 0x%x\n",
> +				val);
> +		}
>  	}
>  
>  	OMAP_HSMMC_WRITE(host->base, STAT, status);
> @@ -1378,6 +1436,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
>  				       struct dma_chan *chan)
>  {
>  	int dma_len;
> +	struct device *dev;
>  
>  	if (!next && data->host_cookie &&
>  	    data->host_cookie != host->next_data.cookie) {
> @@ -1387,9 +1446,14 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
>  		data->host_cookie = 0;
>  	}
>  
> +	if (chan)
> +		dev = chan->device->dev;
> +	else
> +		dev = mmc_dev(host->mmc);
> +
>  	/* Check if next job is already prepared */
>  	if (next || data->host_cookie != host->next_data.cookie) {
> -		dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
> +		dma_len = dma_map_sg(dev, data->sg, data->sg_len,
>  				     omap_hsmmc_get_dma_dir(host, data));
>  
>  	} else {
> @@ -1516,6 +1580,7 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host)
>  {
>  	struct mmc_request *req = host->mrq;
>  	struct dma_chan *chan;
> +	int val;
>  
>  	if (!req->data)
>  		return;
> @@ -1523,10 +1588,66 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host)
>  				| (req->data->blocks << 16));
>  	set_data_timeout(host, req->data->timeout_ns,
>  				req->data->timeout_clks);
> -	chan = omap_hsmmc_get_dma_chan(host, req->data);
> -	dma_async_issue_pending(chan);
> +
> +	if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA) {
> +		val = OMAP_HSMMC_READ(host->base, HCTL);
> +		val |= DMA_SELECT;
> +		OMAP_HSMMC_WRITE(host->base, HCTL, val);
> +
> +		val = OMAP_HSMMC_READ(host->base, CON);
> +		val |= DMA_MASTER;
> +		OMAP_HSMMC_WRITE(host->base, CON, val);
> +
> +		OMAP_HSMMC_WRITE(host->base, ADMASAL,
> +				 (u32)host->adma_desc_table_addr);
> +	} else {
> +		chan = omap_hsmmc_get_dma_chan(host, req->data);
> +		dma_async_issue_pending(chan);
> +	}
> +}
> +
> +static int omap_hsmmc_write_adma_desc(struct omap_hsmmc_host *host, void *desc,
> +				      dma_addr_t addr, u16 len, u8 attr)
> +{
> +	struct omap_hsmmc_adma_desc *dma_desc = desc;
> +
> +	dma_desc->len = len;
> +	dma_desc->addr = (u32)addr;
> +	dma_desc->reserved = 0;
> +	dma_desc->attr = attr;
> +
> +	return 0;
>  }
>  
> +static int omap_hsmmc_setup_adma_transfer(struct omap_hsmmc_host *host,
> +					  struct mmc_request *req)
> +{
> +	struct mmc_data *data = req->data;
> +	struct scatterlist *sg;
> +	int i;
> +	int len;
> +	int ret;
> +	dma_addr_t addr;
> +	struct omap_hsmmc_adma_desc *dma_desc;
> +
> +	ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, NULL);
> +	if (ret)
> +		return ret;
> +
> +	dma_desc = host->adma_desc_table;
> +	for_each_sg(data->sg, sg, host->dma_len, i) {
> +		addr = sg_dma_address(sg);
> +		len = sg_dma_len(sg);
> +		WARN_ON(len > ADMA_MAX_LEN);
> +		omap_hsmmc_write_adma_desc(host, dma_desc, addr, len,
> +					   ADMA_DESC_ATTR_VALID |
> +					   ADMA_DESC_TRANSFER_DATA);
> +		dma_desc++;
> +	}
> +	omap_hsmmc_write_adma_desc(host, dma_desc, 0, 0, ADMA_DESC_ATTR_END);
> +
> +	return 0;
> +}

Would be nice to group the ADMA functions in one section, not scattering it
around the driver.

>  /*
>   * Configure block length for MMC/SD cards and initiate the transfer.
>   */
> @@ -1547,10 +1668,18 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
>  		return 0;
>  	}
>  
> -	ret = omap_hsmmc_setup_dma_transfer(host, req);
> -	if (ret != 0) {
> -		dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
> -		return ret;
> +	if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA) {
> +		ret = omap_hsmmc_setup_adma_transfer(host, req);
> +		if (ret != 0) {
> +			dev_err(mmc_dev(host->mmc), "MMC adma setup failed\n");
> +			return ret;
> +		}
> +	} else {
> +		ret = omap_hsmmc_setup_dma_transfer(host, req);
> +		if (ret != 0) {
> +			dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
> +			return ret;

the error checking can go outside

> +		}
>  	}
>  	return 0;

	if (ret != 0)
		dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
	return ret;

if compiler complains about ret not beeing initialized
int rer = 0;

>  }
> @@ -1560,11 +1689,18 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
>  {
>  	struct omap_hsmmc_host *host = mmc_priv(mmc);
>  	struct mmc_data *data = mrq->data;
> +	struct device *dev;
> +	struct dma_chan *c;
>  
>  	if (data->host_cookie) {
> -		struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data);
> +		if (!(host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA)) {
> +			c = omap_hsmmc_get_dma_chan(host, mrq->data);
> +			dev = c->device->dev;
> +		} else {
> +			dev = mmc_dev(mmc);
> +		}
>  
> -		dma_unmap_sg(c->device->dev, data->sg, data->sg_len,
> +		dma_unmap_sg(dev, data->sg, data->sg_len,
>  			     omap_hsmmc_get_dma_dir(host, data));
>  		data->host_cookie = 0;
>  	}
> @@ -1574,13 +1710,15 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
>  			       bool is_first_req)
>  {
>  	struct omap_hsmmc_host *host = mmc_priv(mmc);
> +	struct dma_chan *c = NULL;
>  
>  	if (mrq->data->host_cookie) {
>  		mrq->data->host_cookie = 0;
>  		return ;
>  	}
>  
> -	struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data);
> +	if (!(host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA))
> +		c = omap_hsmmc_get_dma_chan(host, mrq->data);
>  
>  	if (omap_hsmmc_pre_dma_transfer(host, mrq->data,
>  					&host->next_data, c))
> @@ -1967,6 +2105,9 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
>  	if (of_find_property(np, "ti,dual-volt", NULL))
>  		pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
>  
> +	if (of_find_property(np, "ti,use_adma", NULL))
> +		pdata->controller_flags |= OMAP_HSMMC_USE_ADMA;
> +
>  	pdata->gpio_cd = -EINVAL;
>  	pdata->gpio_cod = -EINVAL;
>  	pdata->gpio_wp = -EINVAL;
> @@ -1992,6 +2133,84 @@ static inline struct omap_hsmmc_platform_data
>  }
>  #endif
>  
> +static int omap_hsmmc_adma_init(struct omap_hsmmc_host *host)
> +{
> +	struct mmc_host *mmc = host->mmc;
> +
> +	host->adma_desc_table = dma_alloc_coherent(host->dev, mmc->max_segs + 1,
> +						   &host->adma_desc_table_addr,
> +						   GFP_KERNEL);
> +	if (!host->adma_desc_table) {
> +		dev_err(host->dev, "failed to allocate adma desc table\n");
> +		return -ENOMEM;

Fall back to Slave DMA?

> +	}
> +
> +	return 0;
> +}
> +
> +static void omap_hsmmc_adma_exit(struct omap_hsmmc_host *host)
> +{
> +	struct mmc_host *mmc = host->mmc;
> +
> +	dma_free_coherent(host->dev, mmc->max_segs + 1,
> +			  host->adma_desc_table, host->adma_desc_table_addr);
> +}
> +
> +static int omap_hsmmc_dma_init(struct omap_hsmmc_host *host)
> +{
> +	dma_cap_mask_t mask;
> +	unsigned int tx_req, rx_req;
> +	struct resource *res;
> +	struct platform_device *pdev = to_platform_device(host->dev);
> +
> +	dma_cap_zero(mask);
> +	dma_cap_set(DMA_SLAVE, mask);
> +
> +	if (!pdev->dev.of_node) {
> +		res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
> +		if (!res) {
> +			dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
> +			return -ENXIO;
> +		}
> +		tx_req = res->start;
> +
> +		res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
> +		if (!res) {
> +			dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
> +			return -ENXIO;
> +		}
> +		rx_req = res->start;
> +	}
> +
> +	host->rx_chan =
> +		dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
> +						 &rx_req, &pdev->dev, "rx");
> +
> +	if (!host->rx_chan) {
> +		dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel\n");
> +		return -ENXIO;
> +	}
> +
> +	host->tx_chan =
> +		dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
> +						 &tx_req, &pdev->dev, "tx");
> +
> +	if (!host->tx_chan) {
> +		dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel\n");
> +		return -ENXIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static void omap_hsmmc_dma_exit(struct omap_hsmmc_host *host)
> +{
> +	if (host->tx_chan)
> +		dma_release_channel(host->tx_chan);
> +	if (host->rx_chan)
> +		dma_release_channel(host->rx_chan);
> +}
> +
>  static int omap_hsmmc_probe(struct platform_device *pdev)
>  {
>  	struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data;
> @@ -2000,8 +2219,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
>  	struct resource *res;
>  	int ret, irq;
>  	const struct of_device_id *match;
> -	dma_cap_mask_t mask;
> -	unsigned tx_req, rx_req;
>  	const struct omap_mmc_of_data *data;
>  	void __iomem *base;
>  
> @@ -2114,7 +2331,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
>  	mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
>  	mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
>  	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
> -	mmc->max_seg_size = mmc->max_req_size;
> +	if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA)
> +		mmc->max_seg_size = ADMA_MAX_LEN;
> +	else
> +		mmc->max_seg_size = mmc->max_req_size;
>  
>  	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
>  		     MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
> @@ -2130,46 +2350,12 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
>  
>  	omap_hsmmc_conf_bus_power(host);
>  
> -	if (!pdev->dev.of_node) {
> -		res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
> -		if (!res) {
> -			dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
> -			ret = -ENXIO;
> -			goto err_irq;
> -		}
> -		tx_req = res->start;
> -
> -		res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
> -		if (!res) {
> -			dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
> -			ret = -ENXIO;
> -			goto err_irq;
> -		}
> -		rx_req = res->start;
> -	}
> -
> -	dma_cap_zero(mask);
> -	dma_cap_set(DMA_SLAVE, mask);
> -
> -	host->rx_chan =
> -		dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
> -						 &rx_req, &pdev->dev, "rx");
> -
> -	if (!host->rx_chan) {
> -		dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel\n");
> -		ret = -ENXIO;
> -		goto err_irq;
> -	}
> -
> -	host->tx_chan =
> -		dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
> -						 &tx_req, &pdev->dev, "tx");
> -
> -	if (!host->tx_chan) {
> -		dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel\n");
> -		ret = -ENXIO;
> +	if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA)
> +		ret = omap_hsmmc_adma_init(host);
> +	else
> +		ret = omap_hsmmc_dma_init(host);
> +	if (ret)
>  		goto err_irq;
> -	}
>  
>  	/* Request IRQ for MMC operations */
>  	ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
> @@ -2225,11 +2411,11 @@ err_slot_name:
>  	mmc_remove_host(mmc);
>  err_irq:
>  	device_init_wakeup(&pdev->dev, false);
> -	if (host->tx_chan)
> -		dma_release_channel(host->tx_chan);
> -	if (host->rx_chan)
> -		dma_release_channel(host->rx_chan);
>  	pm_runtime_dont_use_autosuspend(host->dev);
> +	if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA)
> +		omap_hsmmc_adma_exit(host);
> +	else
> +		omap_hsmmc_dma_exit(host);
>  	pm_runtime_put_sync(host->dev);
>  	pm_runtime_disable(host->dev);
>  	if (host->dbclk)
> @@ -2248,8 +2434,10 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
>  	pm_runtime_get_sync(host->dev);
>  	mmc_remove_host(host->mmc);
>  
> -	dma_release_channel(host->tx_chan);
> -	dma_release_channel(host->rx_chan);
> +	if (host->pdata->controller_flags & OMAP_HSMMC_USE_ADMA)
> +		omap_hsmmc_adma_exit(host);
> +	else
> +		omap_hsmmc_dma_exit(host);
>  
>  	pm_runtime_dont_use_autosuspend(host->dev);
>  	pm_runtime_put_sync(host->dev);
> diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h
> index 8e981be..e26013d 100644
> --- a/include/linux/platform_data/hsmmc-omap.h
> +++ b/include/linux/platform_data/hsmmc-omap.h
> @@ -27,6 +27,7 @@
>  #define OMAP_HSMMC_SUPPORTS_DUAL_VOLT		BIT(0)
>  #define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ	BIT(1)
>  #define OMAP_HSMMC_SWAKEUP_MISSING		BIT(2)
> +#define OMAP_HSMMC_USE_ADMA			BIT(3)
>  
>  struct omap_hsmmc_dev_attr {
>  	u8 flags;
> 


-- 
Péter



More information about the linux-arm-kernel mailing list