linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 10/12] spi: omap2-mcspi: add DMA engine support
       [not found] <20120423160409.GE24299@n2100.arm.linux.org.uk>
@ 2012-04-23 16:07 ` Russell King
  2012-04-27 17:20   ` Grant Likely
  2012-04-23 16:07 ` [PATCH 11/12] spi: omap2-mcspi: remove private DMA API implementation Russell King
  1 sibling, 1 reply; 3+ messages in thread
From: Russell King @ 2012-04-23 16:07 UTC (permalink / raw)
  To: linux-arm-kernel, linux-omap, linux-mmc; +Cc: Grant Likely, spi-devel-general

Add DMA engine support to the OMAP SPI driver.  This supplements the
private DMA API implementation contained within this driver, and the
driver can be independently switched at build time between using DMA
engine and the private DMA API for the transmit and receive sides.

Tested-by: Shubhrajyoti <shubhrajyoti@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/spi/spi-omap2-mcspi.c |  184 ++++++++++++++++++++++++++++++++++-------
 1 files changed, 152 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index bb9274c..b2461d7 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -20,6 +20,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
+#define USE_DMA_ENGINE_RX
+#define USE_DMA_ENGINE_TX
 
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -28,6 +30,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -95,6 +98,8 @@
 
 /* We have 2 DMA channels per CS, one for RX and one for TX */
 struct omap2_mcspi_dma {
+	struct dma_chan *dma_tx;
+	struct dma_chan *dma_rx;
 	int dma_tx_channel;
 	int dma_rx_channel;
 
@@ -290,6 +295,30 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
 	return 0;
 }
 
+static void omap2_mcspi_rx_callback(void *data)
+{
+	struct spi_device *spi = data;
+	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+	complete(&mcspi_dma->dma_rx_completion);
+
+	/* We must disable the DMA RX request */
+	omap2_mcspi_set_dma_req(spi, 1, 0);
+}
+
+static void omap2_mcspi_tx_callback(void *data)
+{
+	struct spi_device *spi = data;
+	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+	complete(&mcspi_dma->dma_tx_completion);
+
+	/* We must disable the DMA TX request */
+	omap2_mcspi_set_dma_req(spi, 0, 0);
+}
+
 static unsigned
 omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 {
@@ -304,6 +333,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 	u8			* rx;
 	const u8		* tx;
 	void __iomem		*chstat_reg;
+	struct dma_slave_config	cfg;
+	enum dma_slave_buswidth width;
+	unsigned es;
 
 	mcspi = spi_master_get_devdata(spi->master);
 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -311,6 +343,71 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
 	chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
 
+	if (cs->word_len <= 8) {
+		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		es = 1;
+	} else if (cs->word_len <= 16) {
+		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		es = 2;
+	} else {
+		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		es = 4;
+	}
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
+	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
+	cfg.src_addr_width = width;
+	cfg.dst_addr_width = width;
+	cfg.src_maxburst = 1;
+	cfg.dst_maxburst = 1;
+
+	if (xfer->tx_buf && mcspi_dma->dma_tx) {
+		struct dma_async_tx_descriptor *tx;
+		struct scatterlist sg;
+
+		dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
+
+		sg_init_table(&sg, 1);
+		sg_dma_address(&sg) = xfer->tx_dma;
+		sg_dma_len(&sg) = xfer->len;
+
+		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
+			DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (tx) {
+			tx->callback = omap2_mcspi_tx_callback;
+			tx->callback_param = spi;
+			dmaengine_submit(tx);
+		} else {
+			/* FIXME: fall back to PIO? */
+		}
+	}
+
+	if (xfer->rx_buf && mcspi_dma->dma_rx) {
+		struct dma_async_tx_descriptor *tx;
+		struct scatterlist sg;
+		size_t len = xfer->len - es;
+
+		dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
+
+		if (l & OMAP2_MCSPI_CHCONF_TURBO)
+			len -= es;
+
+		sg_init_table(&sg, 1);
+		sg_dma_address(&sg) = xfer->rx_dma;
+		sg_dma_len(&sg) = len;
+
+		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
+			DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (tx) {
+			tx->callback = omap2_mcspi_rx_callback;
+			tx->callback_param = spi;
+			dmaengine_submit(tx);
+		} else {
+			/* FIXME: fall back to PIO? */
+		}
+	}
+
 	count = xfer->len;
 	c = count;
 	word_len = cs->word_len;
@@ -332,7 +429,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 		element_count = count >> 2;
 	}
 
-	if (tx != NULL) {
+	if (tx != NULL && mcspi_dma->dma_tx_channel != -1) {
 		omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
 				data_type, element_count, 1,
 				OMAP_DMA_SYNC_ELEMENT,
@@ -347,7 +444,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 				xfer->tx_dma, 0, 0);
 	}
 
-	if (rx != NULL) {
+	if (rx != NULL && mcspi_dma->dma_rx_channel != -1) {
 		elements = element_count - 1;
 		if (l & OMAP2_MCSPI_CHCONF_TURBO)
 			elements--;
@@ -367,12 +464,18 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 	}
 
 	if (tx != NULL) {
-		omap_start_dma(mcspi_dma->dma_tx_channel);
+		if (mcspi_dma->dma_tx)
+			dma_async_issue_pending(mcspi_dma->dma_tx);
+		else
+			omap_start_dma(mcspi_dma->dma_tx_channel);
 		omap2_mcspi_set_dma_req(spi, 0, 1);
 	}
 
 	if (rx != NULL) {
-		omap_start_dma(mcspi_dma->dma_rx_channel);
+		if (mcspi_dma->dma_rx)
+			dma_async_issue_pending(mcspi_dma->dma_rx);
+		else
+			omap_start_dma(mcspi_dma->dma_rx_channel);
 		omap2_mcspi_set_dma_req(spi, 1, 1);
 	}
 
@@ -396,7 +499,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 		dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
 		omap2_mcspi_set_enable(spi, 0);
 
+		elements = element_count - 1;
+
 		if (l & OMAP2_MCSPI_CHCONF_TURBO) {
+			elements--;
 
 			if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
 				   & OMAP2_MCSPI_CHSTAT_RXS)) {
@@ -715,50 +821,58 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
 
 static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
 {
-	struct spi_device	*spi = data;
-	struct omap2_mcspi	*mcspi;
-	struct omap2_mcspi_dma	*mcspi_dma;
-
-	mcspi = spi_master_get_devdata(spi->master);
-	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
-
-	complete(&mcspi_dma->dma_rx_completion);
-
-	/* We must disable the DMA RX request */
-	omap2_mcspi_set_dma_req(spi, 1, 0);
+	omap2_mcspi_rx_callback(data);
 }
 
 static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
 {
-	struct spi_device	*spi = data;
-	struct omap2_mcspi	*mcspi;
-	struct omap2_mcspi_dma	*mcspi_dma;
-
-	mcspi = spi_master_get_devdata(spi->master);
-	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
-
-	complete(&mcspi_dma->dma_tx_completion);
-
-	/* We must disable the DMA TX request */
-	omap2_mcspi_set_dma_req(spi, 0, 0);
+	omap2_mcspi_tx_callback(data);
 }
 
+extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param);
+
 static int omap2_mcspi_request_dma(struct spi_device *spi)
 {
 	struct spi_master	*master = spi->master;
 	struct omap2_mcspi	*mcspi;
 	struct omap2_mcspi_dma	*mcspi_dma;
+	dma_cap_mask_t mask;
+	unsigned sig;
 
 	mcspi = spi_master_get_devdata(master);
 	mcspi_dma = mcspi->dma_channels + spi->chip_select;
 
+	init_completion(&mcspi_dma->dma_rx_completion);
+	init_completion(&mcspi_dma->dma_tx_completion);
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+#ifdef USE_DMA_ENGINE_RX
+	sig = mcspi_dma->dma_rx_sync_dev;
+	mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+	if (!mcspi_dma->dma_rx) {
+		dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n");
+		return -EAGAIN;
+	}
+#else
 	if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
 			omap2_mcspi_dma_rx_callback, spi,
 			&mcspi_dma->dma_rx_channel)) {
 		dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
 		return -EAGAIN;
 	}
+#endif
 
+#ifdef USE_DMA_ENGINE_TX
+	sig = mcspi_dma->dma_tx_sync_dev;
+	mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+	if (!mcspi_dma->dma_tx) {
+		dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n");
+		dma_release_channel(mcspi_dma->dma_rx);
+		mcspi_dma->dma_rx = NULL;
+		return -EAGAIN;
+	}
+#else
 	if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
 			omap2_mcspi_dma_tx_callback, spi,
 			&mcspi_dma->dma_tx_channel)) {
@@ -767,9 +881,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
 		dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
 		return -EAGAIN;
 	}
-
-	init_completion(&mcspi_dma->dma_rx_completion);
-	init_completion(&mcspi_dma->dma_tx_completion);
+#endif
 
 	return 0;
 }
@@ -803,8 +915,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
 			&omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs);
 	}
 
-	if (mcspi_dma->dma_rx_channel == -1
-			|| mcspi_dma->dma_tx_channel == -1) {
+	if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel == -1) ||
+	    (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel == -1)) {
 		ret = omap2_mcspi_request_dma(spi);
 		if (ret < 0)
 			return ret;
@@ -839,6 +951,14 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
 	if (spi->chip_select < spi->master->num_chipselect) {
 		mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
+		if (mcspi_dma->dma_rx) {
+			dma_release_channel(mcspi_dma->dma_rx);
+			mcspi_dma->dma_rx = NULL;
+		}
+		if (mcspi_dma->dma_tx) {
+			dma_release_channel(mcspi_dma->dma_tx);
+			mcspi_dma->dma_tx = NULL;
+		}
 		if (mcspi_dma->dma_rx_channel != -1) {
 			omap_free_dma(mcspi_dma->dma_rx_channel);
 			mcspi_dma->dma_rx_channel = -1;
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 11/12] spi: omap2-mcspi: remove private DMA API implementation
       [not found] <20120423160409.GE24299@n2100.arm.linux.org.uk>
  2012-04-23 16:07 ` [PATCH 10/12] spi: omap2-mcspi: add DMA engine support Russell King
@ 2012-04-23 16:07 ` Russell King
  1 sibling, 0 replies; 3+ messages in thread
From: Russell King @ 2012-04-23 16:07 UTC (permalink / raw)
  To: linux-arm-kernel, linux-omap, linux-mmc; +Cc: Grant Likely, spi-devel-general

Remove the private DMA API implementation from spi-omap2-mcspi.c,
making it use entirely the DMA engine API.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/spi/spi-omap2-mcspi.c |  104 ++---------------------------------------
 1 files changed, 5 insertions(+), 99 deletions(-)

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index b2461d7..e1a3432 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -20,8 +20,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#define USE_DMA_ENGINE_RX
-#define USE_DMA_ENGINE_TX
 
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -42,7 +40,6 @@
 
 #include <linux/spi/spi.h>
 
-#include <plat/dma.h>
 #include <plat/clock.h>
 #include <plat/mcspi.h>
 
@@ -100,8 +97,6 @@
 struct omap2_mcspi_dma {
 	struct dma_chan *dma_tx;
 	struct dma_chan *dma_rx;
-	int dma_tx_channel;
-	int dma_rx_channel;
 
 	int dma_tx_sync_dev;
 	int dma_rx_sync_dev;
@@ -325,9 +320,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 	struct omap2_mcspi	*mcspi;
 	struct omap2_mcspi_cs	*cs = spi->controller_state;
 	struct omap2_mcspi_dma  *mcspi_dma;
-	unsigned int		count, c;
-	unsigned long		base, tx_reg, rx_reg;
-	int			word_len, data_type, element_count;
+	unsigned int		count;
+	int			word_len, element_count;
 	int			elements = 0;
 	u32			l;
 	u8			* rx;
@@ -409,73 +403,26 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 	}
 
 	count = xfer->len;
-	c = count;
 	word_len = cs->word_len;
 
-	base = cs->phys;
-	tx_reg = base + OMAP2_MCSPI_TX0;
-	rx_reg = base + OMAP2_MCSPI_RX0;
 	rx = xfer->rx_buf;
 	tx = xfer->tx_buf;
 
 	if (word_len <= 8) {
-		data_type = OMAP_DMA_DATA_TYPE_S8;
 		element_count = count;
 	} else if (word_len <= 16) {
-		data_type = OMAP_DMA_DATA_TYPE_S16;
 		element_count = count >> 1;
 	} else /* word_len <= 32 */ {
-		data_type = OMAP_DMA_DATA_TYPE_S32;
 		element_count = count >> 2;
 	}
 
-	if (tx != NULL && mcspi_dma->dma_tx_channel != -1) {
-		omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
-				data_type, element_count, 1,
-				OMAP_DMA_SYNC_ELEMENT,
-				mcspi_dma->dma_tx_sync_dev, 0);
-
-		omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
-				OMAP_DMA_AMODE_CONSTANT,
-				tx_reg, 0, 0);
-
-		omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
-				OMAP_DMA_AMODE_POST_INC,
-				xfer->tx_dma, 0, 0);
-	}
-
-	if (rx != NULL && mcspi_dma->dma_rx_channel != -1) {
-		elements = element_count - 1;
-		if (l & OMAP2_MCSPI_CHCONF_TURBO)
-			elements--;
-
-		omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
-				data_type, elements, 1,
-				OMAP_DMA_SYNC_ELEMENT,
-				mcspi_dma->dma_rx_sync_dev, 1);
-
-		omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
-				OMAP_DMA_AMODE_CONSTANT,
-				rx_reg, 0, 0);
-
-		omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
-				OMAP_DMA_AMODE_POST_INC,
-				xfer->rx_dma, 0, 0);
-	}
-
 	if (tx != NULL) {
-		if (mcspi_dma->dma_tx)
-			dma_async_issue_pending(mcspi_dma->dma_tx);
-		else
-			omap_start_dma(mcspi_dma->dma_tx_channel);
+		dma_async_issue_pending(mcspi_dma->dma_tx);
 		omap2_mcspi_set_dma_req(spi, 0, 1);
 	}
 
 	if (rx != NULL) {
-		if (mcspi_dma->dma_rx)
-			dma_async_issue_pending(mcspi_dma->dma_rx);
-		else
-			omap_start_dma(mcspi_dma->dma_rx_channel);
+		dma_async_issue_pending(mcspi_dma->dma_rx);
 		omap2_mcspi_set_dma_req(spi, 1, 1);
 	}
 
@@ -819,16 +766,6 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
 	return 0;
 }
 
-static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
-{
-	omap2_mcspi_rx_callback(data);
-}
-
-static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
-{
-	omap2_mcspi_tx_callback(data);
-}
-
 extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param);
 
 static int omap2_mcspi_request_dma(struct spi_device *spi)
@@ -847,23 +784,13 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
 
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
-#ifdef USE_DMA_ENGINE_RX
 	sig = mcspi_dma->dma_rx_sync_dev;
 	mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
 	if (!mcspi_dma->dma_rx) {
 		dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n");
 		return -EAGAIN;
 	}
-#else
-	if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
-			omap2_mcspi_dma_rx_callback, spi,
-			&mcspi_dma->dma_rx_channel)) {
-		dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
-		return -EAGAIN;
-	}
-#endif
 
-#ifdef USE_DMA_ENGINE_TX
 	sig = mcspi_dma->dma_tx_sync_dev;
 	mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
 	if (!mcspi_dma->dma_tx) {
@@ -872,16 +799,6 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
 		mcspi_dma->dma_rx = NULL;
 		return -EAGAIN;
 	}
-#else
-	if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
-			omap2_mcspi_dma_tx_callback, spi,
-			&mcspi_dma->dma_tx_channel)) {
-		omap_free_dma(mcspi_dma->dma_rx_channel);
-		mcspi_dma->dma_rx_channel = -1;
-		dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
-		return -EAGAIN;
-	}
-#endif
 
 	return 0;
 }
@@ -915,8 +832,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
 			&omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs);
 	}
 
-	if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel == -1) ||
-	    (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel == -1)) {
+	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
 		ret = omap2_mcspi_request_dma(spi);
 		if (ret < 0)
 			return ret;
@@ -959,14 +875,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
 			dma_release_channel(mcspi_dma->dma_tx);
 			mcspi_dma->dma_tx = NULL;
 		}
-		if (mcspi_dma->dma_rx_channel != -1) {
-			omap_free_dma(mcspi_dma->dma_rx_channel);
-			mcspi_dma->dma_rx_channel = -1;
-		}
-		if (mcspi_dma->dma_tx_channel != -1) {
-			omap_free_dma(mcspi_dma->dma_tx_channel);
-			mcspi_dma->dma_tx_channel = -1;
-		}
 	}
 }
 
@@ -1326,7 +1234,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
 			break;
 		}
 
-		mcspi->dma_channels[i].dma_rx_channel = -1;
 		mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
 		sprintf(dma_ch_name, "tx%d", i);
 		dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
@@ -1337,7 +1244,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
 			break;
 		}
 
-		mcspi->dma_channels[i].dma_tx_channel = -1;
 		mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
 	}
 
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 10/12] spi: omap2-mcspi: add DMA engine support
  2012-04-23 16:07 ` [PATCH 10/12] spi: omap2-mcspi: add DMA engine support Russell King
@ 2012-04-27 17:20   ` Grant Likely
  0 siblings, 0 replies; 3+ messages in thread
From: Grant Likely @ 2012-04-27 17:20 UTC (permalink / raw)
  To: Russell King, linux-arm-kernel, linux-omap, linux-mmc; +Cc: spi-devel-general

On Mon, 23 Apr 2012 17:07:32 +0100, Russell King <rmk+kernel@arm.linux.org.uk> wrote:
> Add DMA engine support to the OMAP SPI driver.  This supplements the
> private DMA API implementation contained within this driver, and the
> driver can be independently switched at build time between using DMA
> engine and the private DMA API for the transmit and receive sides.
> 
> Tested-by: Shubhrajyoti <shubhrajyoti@ti.com>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/spi/spi-omap2-mcspi.c |  184 ++++++++++++++++++++++++++++++++++-------
>  1 files changed, 152 insertions(+), 32 deletions(-)

This patch and the next one appear to be part of a larger series.
Feel free to take them through whatever tree you need to.

Acked-by: Grant Likely <grant.likely@secretlab.ca>  (for both)

g.

> 
> diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
> index bb9274c..b2461d7 100644
> --- a/drivers/spi/spi-omap2-mcspi.c
> +++ b/drivers/spi/spi-omap2-mcspi.c
> @@ -20,6 +20,8 @@
>   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>   *
>   */
> +#define USE_DMA_ENGINE_RX
> +#define USE_DMA_ENGINE_TX
>  
>  #include <linux/kernel.h>
>  #include <linux/init.h>
> @@ -28,6 +30,7 @@
>  #include <linux/device.h>
>  #include <linux/delay.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/dmaengine.h>
>  #include <linux/platform_device.h>
>  #include <linux/err.h>
>  #include <linux/clk.h>
> @@ -95,6 +98,8 @@
>  
>  /* We have 2 DMA channels per CS, one for RX and one for TX */
>  struct omap2_mcspi_dma {
> +	struct dma_chan *dma_tx;
> +	struct dma_chan *dma_rx;
>  	int dma_tx_channel;
>  	int dma_rx_channel;
>  
> @@ -290,6 +295,30 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
>  	return 0;
>  }
>  
> +static void omap2_mcspi_rx_callback(void *data)
> +{
> +	struct spi_device *spi = data;
> +	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
> +	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
> +
> +	complete(&mcspi_dma->dma_rx_completion);
> +
> +	/* We must disable the DMA RX request */
> +	omap2_mcspi_set_dma_req(spi, 1, 0);
> +}
> +
> +static void omap2_mcspi_tx_callback(void *data)
> +{
> +	struct spi_device *spi = data;
> +	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
> +	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
> +
> +	complete(&mcspi_dma->dma_tx_completion);
> +
> +	/* We must disable the DMA TX request */
> +	omap2_mcspi_set_dma_req(spi, 0, 0);
> +}
> +
>  static unsigned
>  omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  {
> @@ -304,6 +333,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  	u8			* rx;
>  	const u8		* tx;
>  	void __iomem		*chstat_reg;
> +	struct dma_slave_config	cfg;
> +	enum dma_slave_buswidth width;
> +	unsigned es;
>  
>  	mcspi = spi_master_get_devdata(spi->master);
>  	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
> @@ -311,6 +343,71 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  
>  	chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
>  
> +	if (cs->word_len <= 8) {
> +		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +		es = 1;
> +	} else if (cs->word_len <= 16) {
> +		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> +		es = 2;
> +	} else {
> +		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> +		es = 4;
> +	}
> +
> +	memset(&cfg, 0, sizeof(cfg));
> +	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
> +	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
> +	cfg.src_addr_width = width;
> +	cfg.dst_addr_width = width;
> +	cfg.src_maxburst = 1;
> +	cfg.dst_maxburst = 1;
> +
> +	if (xfer->tx_buf && mcspi_dma->dma_tx) {
> +		struct dma_async_tx_descriptor *tx;
> +		struct scatterlist sg;
> +
> +		dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
> +
> +		sg_init_table(&sg, 1);
> +		sg_dma_address(&sg) = xfer->tx_dma;
> +		sg_dma_len(&sg) = xfer->len;
> +
> +		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
> +			DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> +		if (tx) {
> +			tx->callback = omap2_mcspi_tx_callback;
> +			tx->callback_param = spi;
> +			dmaengine_submit(tx);
> +		} else {
> +			/* FIXME: fall back to PIO? */
> +		}
> +	}
> +
> +	if (xfer->rx_buf && mcspi_dma->dma_rx) {
> +		struct dma_async_tx_descriptor *tx;
> +		struct scatterlist sg;
> +		size_t len = xfer->len - es;
> +
> +		dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
> +
> +		if (l & OMAP2_MCSPI_CHCONF_TURBO)
> +			len -= es;
> +
> +		sg_init_table(&sg, 1);
> +		sg_dma_address(&sg) = xfer->rx_dma;
> +		sg_dma_len(&sg) = len;
> +
> +		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
> +			DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> +		if (tx) {
> +			tx->callback = omap2_mcspi_rx_callback;
> +			tx->callback_param = spi;
> +			dmaengine_submit(tx);
> +		} else {
> +			/* FIXME: fall back to PIO? */
> +		}
> +	}
> +
>  	count = xfer->len;
>  	c = count;
>  	word_len = cs->word_len;
> @@ -332,7 +429,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  		element_count = count >> 2;
>  	}
>  
> -	if (tx != NULL) {
> +	if (tx != NULL && mcspi_dma->dma_tx_channel != -1) {
>  		omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
>  				data_type, element_count, 1,
>  				OMAP_DMA_SYNC_ELEMENT,
> @@ -347,7 +444,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  				xfer->tx_dma, 0, 0);
>  	}
>  
> -	if (rx != NULL) {
> +	if (rx != NULL && mcspi_dma->dma_rx_channel != -1) {
>  		elements = element_count - 1;
>  		if (l & OMAP2_MCSPI_CHCONF_TURBO)
>  			elements--;
> @@ -367,12 +464,18 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  	}
>  
>  	if (tx != NULL) {
> -		omap_start_dma(mcspi_dma->dma_tx_channel);
> +		if (mcspi_dma->dma_tx)
> +			dma_async_issue_pending(mcspi_dma->dma_tx);
> +		else
> +			omap_start_dma(mcspi_dma->dma_tx_channel);
>  		omap2_mcspi_set_dma_req(spi, 0, 1);
>  	}
>  
>  	if (rx != NULL) {
> -		omap_start_dma(mcspi_dma->dma_rx_channel);
> +		if (mcspi_dma->dma_rx)
> +			dma_async_issue_pending(mcspi_dma->dma_rx);
> +		else
> +			omap_start_dma(mcspi_dma->dma_rx_channel);
>  		omap2_mcspi_set_dma_req(spi, 1, 1);
>  	}
>  
> @@ -396,7 +499,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
>  		dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
>  		omap2_mcspi_set_enable(spi, 0);
>  
> +		elements = element_count - 1;
> +
>  		if (l & OMAP2_MCSPI_CHCONF_TURBO) {
> +			elements--;
>  
>  			if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
>  				   & OMAP2_MCSPI_CHSTAT_RXS)) {
> @@ -715,50 +821,58 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
>  
>  static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
>  {
> -	struct spi_device	*spi = data;
> -	struct omap2_mcspi	*mcspi;
> -	struct omap2_mcspi_dma	*mcspi_dma;
> -
> -	mcspi = spi_master_get_devdata(spi->master);
> -	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
> -
> -	complete(&mcspi_dma->dma_rx_completion);
> -
> -	/* We must disable the DMA RX request */
> -	omap2_mcspi_set_dma_req(spi, 1, 0);
> +	omap2_mcspi_rx_callback(data);
>  }
>  
>  static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
>  {
> -	struct spi_device	*spi = data;
> -	struct omap2_mcspi	*mcspi;
> -	struct omap2_mcspi_dma	*mcspi_dma;
> -
> -	mcspi = spi_master_get_devdata(spi->master);
> -	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
> -
> -	complete(&mcspi_dma->dma_tx_completion);
> -
> -	/* We must disable the DMA TX request */
> -	omap2_mcspi_set_dma_req(spi, 0, 0);
> +	omap2_mcspi_tx_callback(data);
>  }
>  
> +extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param);
> +
>  static int omap2_mcspi_request_dma(struct spi_device *spi)
>  {
>  	struct spi_master	*master = spi->master;
>  	struct omap2_mcspi	*mcspi;
>  	struct omap2_mcspi_dma	*mcspi_dma;
> +	dma_cap_mask_t mask;
> +	unsigned sig;
>  
>  	mcspi = spi_master_get_devdata(master);
>  	mcspi_dma = mcspi->dma_channels + spi->chip_select;
>  
> +	init_completion(&mcspi_dma->dma_rx_completion);
> +	init_completion(&mcspi_dma->dma_tx_completion);
> +
> +	dma_cap_zero(mask);
> +	dma_cap_set(DMA_SLAVE, mask);
> +#ifdef USE_DMA_ENGINE_RX
> +	sig = mcspi_dma->dma_rx_sync_dev;
> +	mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
> +	if (!mcspi_dma->dma_rx) {
> +		dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n");
> +		return -EAGAIN;
> +	}
> +#else
>  	if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
>  			omap2_mcspi_dma_rx_callback, spi,
>  			&mcspi_dma->dma_rx_channel)) {
>  		dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
>  		return -EAGAIN;
>  	}
> +#endif
>  
> +#ifdef USE_DMA_ENGINE_TX
> +	sig = mcspi_dma->dma_tx_sync_dev;
> +	mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
> +	if (!mcspi_dma->dma_tx) {
> +		dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n");
> +		dma_release_channel(mcspi_dma->dma_rx);
> +		mcspi_dma->dma_rx = NULL;
> +		return -EAGAIN;
> +	}
> +#else
>  	if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
>  			omap2_mcspi_dma_tx_callback, spi,
>  			&mcspi_dma->dma_tx_channel)) {
> @@ -767,9 +881,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
>  		dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
>  		return -EAGAIN;
>  	}
> -
> -	init_completion(&mcspi_dma->dma_rx_completion);
> -	init_completion(&mcspi_dma->dma_tx_completion);
> +#endif
>  
>  	return 0;
>  }
> @@ -803,8 +915,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
>  			&omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs);
>  	}
>  
> -	if (mcspi_dma->dma_rx_channel == -1
> -			|| mcspi_dma->dma_tx_channel == -1) {
> +	if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel == -1) ||
> +	    (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel == -1)) {
>  		ret = omap2_mcspi_request_dma(spi);
>  		if (ret < 0)
>  			return ret;
> @@ -839,6 +951,14 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
>  	if (spi->chip_select < spi->master->num_chipselect) {
>  		mcspi_dma = &mcspi->dma_channels[spi->chip_select];
>  
> +		if (mcspi_dma->dma_rx) {
> +			dma_release_channel(mcspi_dma->dma_rx);
> +			mcspi_dma->dma_rx = NULL;
> +		}
> +		if (mcspi_dma->dma_tx) {
> +			dma_release_channel(mcspi_dma->dma_tx);
> +			mcspi_dma->dma_tx = NULL;
> +		}
>  		if (mcspi_dma->dma_rx_channel != -1) {
>  			omap_free_dma(mcspi_dma->dma_rx_channel);
>  			mcspi_dma->dma_rx_channel = -1;
> -- 
> 1.7.4.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-04-27 17:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20120423160409.GE24299@n2100.arm.linux.org.uk>
2012-04-23 16:07 ` [PATCH 10/12] spi: omap2-mcspi: add DMA engine support Russell King
2012-04-27 17:20   ` Grant Likely
2012-04-23 16:07 ` [PATCH 11/12] spi: omap2-mcspi: remove private DMA API implementation Russell King

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).