linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] [PATCH v3 0/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping
@ 2016-07-07 17:17 Franklin S Cooper Jr
  2016-07-07 17:17 ` [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround Franklin S Cooper Jr
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Franklin S Cooper Jr @ 2016-07-07 17:17 UTC (permalink / raw)
  To: tony, robh+dt, broonie, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik,
	nsekhar
  Cc: Franklin S Cooper Jr

This patchset switches omap2-mcspi from handling DMA mapping internally to
using the mechanism built into the SPI framework.

However, this is slightly complex since some OMAP SoCs have a quirk that
needs to be handled. In the driver on certain OMAP SOCs if certain
conditions are met the DMA should transfer one or two less elements
when reading from the SPI. The remaining bytes are read in CPU mode.
Sg_split is used to implement this quirk without altering the original
sgl.

Note: The first patch looks to already have been accepted.

V2 changes:
Save page_link value if page_link doesn't point to chained sg_list

v3 changes:
Switch from using custom sg_table clone function to sg_split that already
exist within the kernel.

Franklin S Cooper Jr (4):
  spi: omap2-mcspi: Add comments for RX only DMA buffer workaround
  spi: spi-omap2-mcspi: Select SPI_SPLIT
  spi: omap2-mcspi: Use the SPI framework to handle DMA mapping
  ARM: dts: am335x-icev2: Add SPI based NOR

 arch/arm/boot/dts/am335x-icev2.dts |  39 ++++++++++
 drivers/spi/Kconfig                |   1 +
 drivers/spi/spi-omap2-mcspi.c      | 145 ++++++++++++++++++-------------------
 3 files changed, 109 insertions(+), 76 deletions(-)

-- 
2.7.0

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

* [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround
  2016-07-07 17:17 [RFC] [PATCH v3 0/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
@ 2016-07-07 17:17 ` Franklin S Cooper Jr
  2016-07-08  8:46   ` Mark Brown
  2016-07-07 17:17 ` [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT Franklin S Cooper Jr
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Franklin S Cooper Jr @ 2016-07-07 17:17 UTC (permalink / raw)
  To: tony, robh+dt, broonie, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik,
	nsekhar
  Cc: Franklin S Cooper Jr

OMAP35x and OMAP37x mentions in the McSPI End-of-Transfer Sequences section
that if the McSPI is configured as a Master and only DMA RX is being
performed then the DMA transfer size needs to be reduced by 1 or 2.

This was originally implemented by:
commit 57c5c28dbc83 ("spi: omap2_mcspi rxdma bugfix")

This patch adds comments to clarify what is going on in the code since its
not obvious what problem its addressing.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
---
 drivers/spi/spi-omap2-mcspi.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 1d237e9..c47f958 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -459,6 +459,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	count = xfer->len;
 	dma_count = xfer->len;
 
+	/*
+	 *  In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
+	 *  it mentions reducing DMA transfer length by one element in master
+	 *  normal mode.
+	 */
 	if (mcspi->fifo_depth == 0)
 		dma_count -= es;
 
@@ -478,6 +483,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 
 		dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
 
+		/*
+		 *  Reduce DMA transfer length by one more if McSPI is
+		 *  configured in turbo mode.
+		 */
 		if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
 			dma_count -= es;
 
@@ -507,6 +516,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	if (mcspi->fifo_depth > 0)
 		return count;
 
+	/*
+	 *  Due to the DMA transfer length reduction the missing bytes must
+	 *  be read manually to receive all of the expected data.
+	 */
 	omap2_mcspi_set_enable(spi, 0);
 
 	elements = element_count - 1;
-- 
2.7.0

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

* [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT
  2016-07-07 17:17 [RFC] [PATCH v3 0/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
  2016-07-07 17:17 ` [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround Franklin S Cooper Jr
@ 2016-07-07 17:17 ` Franklin S Cooper Jr
  2016-07-07 17:33   ` Randy Dunlap
  2016-07-08  8:49   ` Applied "spi: omap2-mcspi: Select SPI_SPLIT" to the spi tree Mark Brown
  2016-07-07 17:17 ` [RFC] [PATCH v3 3/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
  2016-07-07 17:17 ` [RFC] [PATCH v3 4/4] ARM: dts: am335x-icev2: Add SPI based NOR Franklin S Cooper Jr
  3 siblings, 2 replies; 10+ messages in thread
From: Franklin S Cooper Jr @ 2016-07-07 17:17 UTC (permalink / raw)
  To: tony, robh+dt, broonie, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik,
	nsekhar
  Cc: Franklin S Cooper Jr

The function spi_split will be used by spi-omap2-mcspi to handle a SoC
workaround in the SPI driver. Therefore, select SPI_SPLIT so this function
is available to the driver.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
---
 drivers/spi/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec..d6fb8d4 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -411,6 +411,7 @@ config SPI_OMAP24XX
 	tristate "McSPI driver for OMAP"
 	depends on HAS_DMA
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
+	select SG_SPLIT
 	help
 	  SPI master controller for OMAP24XX and later Multichannel SPI
 	  (McSPI) modules.
-- 
2.7.0

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

* [RFC] [PATCH v3 3/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping
  2016-07-07 17:17 [RFC] [PATCH v3 0/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
  2016-07-07 17:17 ` [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround Franklin S Cooper Jr
  2016-07-07 17:17 ` [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT Franklin S Cooper Jr
@ 2016-07-07 17:17 ` Franklin S Cooper Jr
  2016-07-08  8:49   ` Applied "spi: omap2-mcspi: Use the SPI framework to handle DMA mapping" to the spi tree Mark Brown
  2016-07-07 17:17 ` [RFC] [PATCH v3 4/4] ARM: dts: am335x-icev2: Add SPI based NOR Franklin S Cooper Jr
  3 siblings, 1 reply; 10+ messages in thread
From: Franklin S Cooper Jr @ 2016-07-07 17:17 UTC (permalink / raw)
  To: tony, robh+dt, broonie, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik,
	nsekhar
  Cc: Franklin S Cooper Jr

Currently, the driver handles mapping buffers to be used by the DMA.
However, there are times that the current mapping implementation will
fail for certain buffers. Fortunately, the SPI framework can detect
and map buffers so its usable by the DMA.

Update the driver to utilize the SPI framework for buffer
mapping instead. Also incorporate hooks that the framework uses to
determine if the DMA can or can not be used.

This will result in the original omap2_mcspi_transfer_one function being
deleted and omap2_mcspi_work_one being renamed to
omap2_mcspi_transfer_one. Previously transfer_one was only responsible
for mapping and work_one handled the transfer. But now only transferring
needs to be handled by the driver.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
---
v3 changes:
Use sg_split rather than custom sg table clone function.

 drivers/spi/spi-omap2-mcspi.c | 132 ++++++++++++++++++------------------------
 1 file changed, 56 insertions(+), 76 deletions(-)

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index c47f958..d5157b2 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -419,16 +419,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
 
 	if (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);
+		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
+					     xfer->tx_sg.nents,
+					     DMA_MEM_TO_DEV,
+					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 		if (tx) {
 			tx->callback = omap2_mcspi_tx_callback;
 			tx->callback_param = spi;
@@ -449,7 +446,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 {
 	struct omap2_mcspi	*mcspi;
 	struct omap2_mcspi_dma  *mcspi_dma;
-	unsigned int		count, dma_count;
+	unsigned int		count, transfer_reduction = 0;
+	struct scatterlist	*sg_out[2];
+	int			nb_sizes = 0, out_mapped_nents[2], ret, x;
+	size_t			sizes[2];
 	u32			l;
 	int			elements = 0;
 	int			word_len, element_count;
@@ -457,7 +457,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	mcspi = spi_master_get_devdata(spi->master);
 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 	count = xfer->len;
-	dma_count = xfer->len;
 
 	/*
 	 *  In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
@@ -465,7 +464,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	 *  normal mode.
 	 */
 	if (mcspi->fifo_depth == 0)
-		dma_count -= es;
+		transfer_reduction = es;
 
 	word_len = cs->word_len;
 	l = mcspi_cached_chconf0(spi);
@@ -479,7 +478,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 
 	if (mcspi_dma->dma_rx) {
 		struct dma_async_tx_descriptor *tx;
-		struct scatterlist sg;
 
 		dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
 
@@ -488,15 +486,38 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 		 *  configured in turbo mode.
 		 */
 		if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
-			dma_count -= es;
+			transfer_reduction += es;
 
-		sg_init_table(&sg, 1);
-		sg_dma_address(&sg) = xfer->rx_dma;
-		sg_dma_len(&sg) = dma_count;
+		if (transfer_reduction) {
+			/* Split sgl into two. The second sgl won't be used. */
+			sizes[0] = count - transfer_reduction;
+			sizes[1] = transfer_reduction;
+			nb_sizes = 2;
+		} else {
+			/*
+			 * Don't bother splitting the sgl. This essentially
+			 * clones the original sgl.
+			 */
+			sizes[0] = count;
+			nb_sizes = 1;
+		}
+
+		ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
+			       0, nb_sizes,
+			       sizes,
+			       sg_out, out_mapped_nents,
+			       GFP_KERNEL);
 
-		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
-				DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
-				DMA_CTRL_ACK);
+		if (ret < 0) {
+			dev_err(&spi->dev, "sg_split failed\n");
+			return 0;
+		}
+
+		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
+					     sg_out[0],
+					     out_mapped_nents[0],
+					     DMA_DEV_TO_MEM,
+					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 		if (tx) {
 			tx->callback = omap2_mcspi_rx_callback;
 			tx->callback_param = spi;
@@ -510,8 +531,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	omap2_mcspi_set_dma_req(spi, 1, 1);
 
 	wait_for_completion(&mcspi_dma->dma_rx_completion);
-	dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
-			 DMA_FROM_DEVICE);
+
+	for (x = 0; x < nb_sizes; x++)
+		kfree(sg_out[x]);
 
 	if (mcspi->fifo_depth > 0)
 		return count;
@@ -628,8 +650,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
 	if (tx != NULL) {
 		wait_for_completion(&mcspi_dma->dma_tx_completion);
-		dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
-				 DMA_TO_DEVICE);
 
 		if (mcspi->fifo_depth > 0) {
 			irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
@@ -1087,8 +1107,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
 		gpio_free(spi->cs_gpio);
 }
 
-static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
-		struct spi_device *spi, struct spi_transfer *t)
+static int omap2_mcspi_transfer_one(struct spi_master *master,
+				    struct spi_device *spi,
+				    struct spi_transfer *t)
 {
 
 	/* We only enable one channel at a time -- the one whose message is
@@ -1098,7 +1119,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 	 * chipselect with the FORCE bit ... CS != channel enable.
 	 */
 
-	struct spi_master		*master;
+	struct omap2_mcspi		*mcspi;
 	struct omap2_mcspi_dma		*mcspi_dma;
 	struct omap2_mcspi_cs		*cs;
 	struct omap2_mcspi_device_config *cd;
@@ -1106,7 +1127,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 	int				status = 0;
 	u32				chconf;
 
-	master = spi->master;
+	mcspi = spi_master_get_devdata(master);
 	mcspi_dma = mcspi->dma_channels + spi->chip_select;
 	cs = spi->controller_state;
 	cd = spi->controller_data;
@@ -1166,7 +1187,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 		unsigned	count;
 
 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-		    (t->len >= DMA_MIN_BYTES))
+		    master->cur_msg_mapped &&
+		    master->can_dma(master, spi, t))
 			omap2_mcspi_set_fifo(spi, t, 1);
 
 		omap2_mcspi_set_enable(spi, 1);
@@ -1177,7 +1199,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 					+ OMAP2_MCSPI_TX0);
 
 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-		    (t->len >= DMA_MIN_BYTES))
+		    master->cur_msg_mapped &&
+		    master->can_dma(master, spi, t))
 			count = omap2_mcspi_txrx_dma(spi, t);
 		else
 			count = omap2_mcspi_txrx_pio(spi, t);
@@ -1246,55 +1269,11 @@ static int omap2_mcspi_prepare_message(struct spi_master *master,
 	return 0;
 }
 
-static int omap2_mcspi_transfer_one(struct spi_master *master,
-		struct spi_device *spi, struct spi_transfer *t)
+static bool omap2_mcspi_can_dma(struct spi_master *master,
+				struct spi_device *spi,
+				struct spi_transfer *xfer)
 {
-	struct omap2_mcspi	*mcspi;
-	struct omap2_mcspi_dma	*mcspi_dma;
-	const void	*tx_buf = t->tx_buf;
-	void		*rx_buf = t->rx_buf;
-	unsigned	len = t->len;
-
-	mcspi = spi_master_get_devdata(master);
-	mcspi_dma = mcspi->dma_channels + spi->chip_select;
-
-	if ((len && !(rx_buf || tx_buf))) {
-		dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
-				t->speed_hz,
-				len,
-				tx_buf ? "tx" : "",
-				rx_buf ? "rx" : "",
-				t->bits_per_word);
-		return -EINVAL;
-	}
-
-	if (len < DMA_MIN_BYTES)
-		goto skip_dma_map;
-
-	if (mcspi_dma->dma_tx && tx_buf != NULL) {
-		t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
-				len, DMA_TO_DEVICE);
-		if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
-			dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
-					'T', len);
-			return -EINVAL;
-		}
-	}
-	if (mcspi_dma->dma_rx && rx_buf != NULL) {
-		t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
-				DMA_FROM_DEVICE);
-		if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
-			dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
-					'R', len);
-			if (tx_buf != NULL)
-				dma_unmap_single(mcspi->dev, t->tx_dma,
-						len, DMA_TO_DEVICE);
-			return -EINVAL;
-		}
-	}
-
-skip_dma_map:
-	return omap2_mcspi_work_one(mcspi, spi, t);
+	return (xfer->len >= DMA_MIN_BYTES);
 }
 
 static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
@@ -1374,6 +1353,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
 	master->setup = omap2_mcspi_setup;
 	master->auto_runtime_pm = true;
 	master->prepare_message = omap2_mcspi_prepare_message;
+	master->can_dma = omap2_mcspi_can_dma;
 	master->transfer_one = omap2_mcspi_transfer_one;
 	master->set_cs = omap2_mcspi_set_cs;
 	master->cleanup = omap2_mcspi_cleanup;
-- 
2.7.0

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

* [RFC] [PATCH v3 4/4] ARM: dts: am335x-icev2: Add SPI based NOR
  2016-07-07 17:17 [RFC] [PATCH v3 0/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
                   ` (2 preceding siblings ...)
  2016-07-07 17:17 ` [RFC] [PATCH v3 3/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
@ 2016-07-07 17:17 ` Franklin S Cooper Jr
  3 siblings, 0 replies; 10+ messages in thread
From: Franklin S Cooper Jr @ 2016-07-07 17:17 UTC (permalink / raw)
  To: tony, robh+dt, broonie, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik,
	nsekhar
  Cc: Franklin S Cooper Jr

Enable support for W25Q64CVSSIG which is a Winbond 64 Mbit SPI NOR.

At boot you will see the following message:
m25p80 spi1.0: found s25fl064k, expected w25q64

This is because the JEDEC ID for this chip is the same as s25fl064k.
However, this should be harmless since both chips are essentially the
same.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
---
 arch/arm/boot/dts/am335x-icev2.dts | 39 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/am335x-icev2.dts b/arch/arm/boot/dts/am335x-icev2.dts
index e271013..e4d2d13 100644
--- a/arch/arm/boot/dts/am335x-icev2.dts
+++ b/arch/arm/boot/dts/am335x-icev2.dts
@@ -208,6 +208,45 @@
 	};
 };
 
+&spi0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_default>;
+
+	spi_nor: flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "winbond,w25q64", "jedec,spi-nor";
+		spi-max-frequency = <80000000>;
+		m25p,fast-read;
+		reg = <0>;
+
+		partition@0 {
+			label = "u-boot-spl";
+			reg = <0x0 0x80000>;
+			read-only;
+		};
+
+		partition@1 {
+			label = "u-boot";
+			reg = <0x80000 0x100000>;
+			read-only;
+		};
+
+		partition@2 {
+			label = "u-boot-env";
+			reg = <0x180000 0x20000>;
+			read-only;
+		};
+
+		partition@3 {
+			label = "misc";
+			reg = <0x1A0000 0x660000>;
+		};
+	};
+
+};
+
 #include "tps65910.dtsi"
 
 &tps {
-- 
2.7.0

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

* Re: [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT
  2016-07-07 17:17 ` [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT Franklin S Cooper Jr
@ 2016-07-07 17:33   ` Randy Dunlap
  2016-07-08  8:49   ` Applied "spi: omap2-mcspi: Select SPI_SPLIT" to the spi tree Mark Brown
  1 sibling, 0 replies; 10+ messages in thread
From: Randy Dunlap @ 2016-07-07 17:33 UTC (permalink / raw)
  To: Franklin S Cooper Jr, tony, robh+dt, broonie, linux-omap,
	devicetree, linux-arm-kernel, linux-kernel, linux-spi,
	andy.shevchenko, robert.jarzmik, nsekhar

On 07/07/16 10:17, Franklin S Cooper Jr wrote:
> The function spi_split will be used by spi-omap2-mcspi to handle a SoC

s/spi_split/sg_split/

> workaround in the SPI driver. Therefore, select SPI_SPLIT so this function

s/SPI_SPLIT/SG_SPLIT/ on line above and in $Subject.

> is available to the driver.
> 
> Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
> ---
>  drivers/spi/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 4b931ec..d6fb8d4 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -411,6 +411,7 @@ config SPI_OMAP24XX
>  	tristate "McSPI driver for OMAP"
>  	depends on HAS_DMA
>  	depends on ARCH_OMAP2PLUS || COMPILE_TEST
> +	select SG_SPLIT
>  	help
>  	  SPI master controller for OMAP24XX and later Multichannel SPI
>  	  (McSPI) modules.
> 


-- 
~Randy

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

* Re: [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround
  2016-07-07 17:17 ` [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround Franklin S Cooper Jr
@ 2016-07-08  8:46   ` Mark Brown
  0 siblings, 0 replies; 10+ messages in thread
From: Mark Brown @ 2016-07-08  8:46 UTC (permalink / raw)
  To: Franklin S Cooper Jr
  Cc: tony, robh+dt, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik,
	nsekhar

[-- Attachment #1: Type: text/plain, Size: 585 bytes --]

On Thu, Jul 07, 2016 at 12:17:48PM -0500, Franklin S Cooper Jr wrote:
> OMAP35x and OMAP37x mentions in the McSPI End-of-Transfer Sequences section
> that if the McSPI is configured as a Master and only DMA RX is being
> performed then the DMA transfer size needs to be reduced by 1 or 2.

Please do not submit new versions of already applied patches, please
submit incremental updates to the existing code.  Modifying existing
commits creates problems for other users building on top of those
commits so it's best practice to only change pubished git commits if
absolutely essential.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Applied "spi: omap2-mcspi: Use the SPI framework to handle DMA mapping" to the spi tree
  2016-07-07 17:17 ` [RFC] [PATCH v3 3/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
@ 2016-07-08  8:49   ` Mark Brown
  0 siblings, 0 replies; 10+ messages in thread
From: Mark Brown @ 2016-07-08  8:49 UTC (permalink / raw)
  To: Franklin S Cooper Jr
  Cc: Mark Brown, tony, robh+dt, broonie, linux-omap, devicetree,
	linux-arm-kernel, linux-kernel, linux-spi, andy.shevchenko,
	robert.jarzmik, nsekhar, linux-spi

The patch

   spi: omap2-mcspi: Use the SPI framework to handle DMA mapping

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 0ba1870f886501beca0e2c19ec367a85ae201ea8 Mon Sep 17 00:00:00 2001
From: Franklin S Cooper Jr <fcooper@ti.com>
Date: Thu, 7 Jul 2016 12:17:50 -0500
Subject: [PATCH] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping

Currently, the driver handles mapping buffers to be used by the DMA.
However, there are times that the current mapping implementation will
fail for certain buffers. Fortunately, the SPI framework can detect
and map buffers so its usable by the DMA.

Update the driver to utilize the SPI framework for buffer
mapping instead. Also incorporate hooks that the framework uses to
determine if the DMA can or can not be used.

This will result in the original omap2_mcspi_transfer_one function being
deleted and omap2_mcspi_work_one being renamed to
omap2_mcspi_transfer_one. Previously transfer_one was only responsible
for mapping and work_one handled the transfer. But now only transferring
needs to be handled by the driver.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-omap2-mcspi.c | 132 ++++++++++++++++++------------------------
 1 file changed, 56 insertions(+), 76 deletions(-)

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index c47f95879833..d5157b2222ce 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -419,16 +419,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
 
 	if (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);
+		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
+					     xfer->tx_sg.nents,
+					     DMA_MEM_TO_DEV,
+					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 		if (tx) {
 			tx->callback = omap2_mcspi_tx_callback;
 			tx->callback_param = spi;
@@ -449,7 +446,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 {
 	struct omap2_mcspi	*mcspi;
 	struct omap2_mcspi_dma  *mcspi_dma;
-	unsigned int		count, dma_count;
+	unsigned int		count, transfer_reduction = 0;
+	struct scatterlist	*sg_out[2];
+	int			nb_sizes = 0, out_mapped_nents[2], ret, x;
+	size_t			sizes[2];
 	u32			l;
 	int			elements = 0;
 	int			word_len, element_count;
@@ -457,7 +457,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	mcspi = spi_master_get_devdata(spi->master);
 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 	count = xfer->len;
-	dma_count = xfer->len;
 
 	/*
 	 *  In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
@@ -465,7 +464,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	 *  normal mode.
 	 */
 	if (mcspi->fifo_depth == 0)
-		dma_count -= es;
+		transfer_reduction = es;
 
 	word_len = cs->word_len;
 	l = mcspi_cached_chconf0(spi);
@@ -479,7 +478,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 
 	if (mcspi_dma->dma_rx) {
 		struct dma_async_tx_descriptor *tx;
-		struct scatterlist sg;
 
 		dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
 
@@ -488,15 +486,38 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 		 *  configured in turbo mode.
 		 */
 		if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
-			dma_count -= es;
+			transfer_reduction += es;
 
-		sg_init_table(&sg, 1);
-		sg_dma_address(&sg) = xfer->rx_dma;
-		sg_dma_len(&sg) = dma_count;
+		if (transfer_reduction) {
+			/* Split sgl into two. The second sgl won't be used. */
+			sizes[0] = count - transfer_reduction;
+			sizes[1] = transfer_reduction;
+			nb_sizes = 2;
+		} else {
+			/*
+			 * Don't bother splitting the sgl. This essentially
+			 * clones the original sgl.
+			 */
+			sizes[0] = count;
+			nb_sizes = 1;
+		}
+
+		ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
+			       0, nb_sizes,
+			       sizes,
+			       sg_out, out_mapped_nents,
+			       GFP_KERNEL);
 
-		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
-				DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
-				DMA_CTRL_ACK);
+		if (ret < 0) {
+			dev_err(&spi->dev, "sg_split failed\n");
+			return 0;
+		}
+
+		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
+					     sg_out[0],
+					     out_mapped_nents[0],
+					     DMA_DEV_TO_MEM,
+					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 		if (tx) {
 			tx->callback = omap2_mcspi_rx_callback;
 			tx->callback_param = spi;
@@ -510,8 +531,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	omap2_mcspi_set_dma_req(spi, 1, 1);
 
 	wait_for_completion(&mcspi_dma->dma_rx_completion);
-	dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
-			 DMA_FROM_DEVICE);
+
+	for (x = 0; x < nb_sizes; x++)
+		kfree(sg_out[x]);
 
 	if (mcspi->fifo_depth > 0)
 		return count;
@@ -628,8 +650,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
 	if (tx != NULL) {
 		wait_for_completion(&mcspi_dma->dma_tx_completion);
-		dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
-				 DMA_TO_DEVICE);
 
 		if (mcspi->fifo_depth > 0) {
 			irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
@@ -1087,8 +1107,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
 		gpio_free(spi->cs_gpio);
 }
 
-static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
-		struct spi_device *spi, struct spi_transfer *t)
+static int omap2_mcspi_transfer_one(struct spi_master *master,
+				    struct spi_device *spi,
+				    struct spi_transfer *t)
 {
 
 	/* We only enable one channel at a time -- the one whose message is
@@ -1098,7 +1119,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 	 * chipselect with the FORCE bit ... CS != channel enable.
 	 */
 
-	struct spi_master		*master;
+	struct omap2_mcspi		*mcspi;
 	struct omap2_mcspi_dma		*mcspi_dma;
 	struct omap2_mcspi_cs		*cs;
 	struct omap2_mcspi_device_config *cd;
@@ -1106,7 +1127,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 	int				status = 0;
 	u32				chconf;
 
-	master = spi->master;
+	mcspi = spi_master_get_devdata(master);
 	mcspi_dma = mcspi->dma_channels + spi->chip_select;
 	cs = spi->controller_state;
 	cd = spi->controller_data;
@@ -1166,7 +1187,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 		unsigned	count;
 
 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-		    (t->len >= DMA_MIN_BYTES))
+		    master->cur_msg_mapped &&
+		    master->can_dma(master, spi, t))
 			omap2_mcspi_set_fifo(spi, t, 1);
 
 		omap2_mcspi_set_enable(spi, 1);
@@ -1177,7 +1199,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
 					+ OMAP2_MCSPI_TX0);
 
 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-		    (t->len >= DMA_MIN_BYTES))
+		    master->cur_msg_mapped &&
+		    master->can_dma(master, spi, t))
 			count = omap2_mcspi_txrx_dma(spi, t);
 		else
 			count = omap2_mcspi_txrx_pio(spi, t);
@@ -1246,55 +1269,11 @@ static int omap2_mcspi_prepare_message(struct spi_master *master,
 	return 0;
 }
 
-static int omap2_mcspi_transfer_one(struct spi_master *master,
-		struct spi_device *spi, struct spi_transfer *t)
+static bool omap2_mcspi_can_dma(struct spi_master *master,
+				struct spi_device *spi,
+				struct spi_transfer *xfer)
 {
-	struct omap2_mcspi	*mcspi;
-	struct omap2_mcspi_dma	*mcspi_dma;
-	const void	*tx_buf = t->tx_buf;
-	void		*rx_buf = t->rx_buf;
-	unsigned	len = t->len;
-
-	mcspi = spi_master_get_devdata(master);
-	mcspi_dma = mcspi->dma_channels + spi->chip_select;
-
-	if ((len && !(rx_buf || tx_buf))) {
-		dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
-				t->speed_hz,
-				len,
-				tx_buf ? "tx" : "",
-				rx_buf ? "rx" : "",
-				t->bits_per_word);
-		return -EINVAL;
-	}
-
-	if (len < DMA_MIN_BYTES)
-		goto skip_dma_map;
-
-	if (mcspi_dma->dma_tx && tx_buf != NULL) {
-		t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
-				len, DMA_TO_DEVICE);
-		if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
-			dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
-					'T', len);
-			return -EINVAL;
-		}
-	}
-	if (mcspi_dma->dma_rx && rx_buf != NULL) {
-		t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
-				DMA_FROM_DEVICE);
-		if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
-			dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
-					'R', len);
-			if (tx_buf != NULL)
-				dma_unmap_single(mcspi->dev, t->tx_dma,
-						len, DMA_TO_DEVICE);
-			return -EINVAL;
-		}
-	}
-
-skip_dma_map:
-	return omap2_mcspi_work_one(mcspi, spi, t);
+	return (xfer->len >= DMA_MIN_BYTES);
 }
 
 static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
@@ -1374,6 +1353,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
 	master->setup = omap2_mcspi_setup;
 	master->auto_runtime_pm = true;
 	master->prepare_message = omap2_mcspi_prepare_message;
+	master->can_dma = omap2_mcspi_can_dma;
 	master->transfer_one = omap2_mcspi_transfer_one;
 	master->set_cs = omap2_mcspi_set_cs;
 	master->cleanup = omap2_mcspi_cleanup;
-- 
2.8.1

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

* Applied "spi: omap2-mcspi: Select SPI_SPLIT" to the spi tree
  2016-07-07 17:17 ` [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT Franklin S Cooper Jr
  2016-07-07 17:33   ` Randy Dunlap
@ 2016-07-08  8:49   ` Mark Brown
  2016-07-08  8:54     ` Sekhar Nori
  1 sibling, 1 reply; 10+ messages in thread
From: Mark Brown @ 2016-07-08  8:49 UTC (permalink / raw)
  To: Franklin S Cooper Jr
  Cc: Mark Brown, tony, robh+dt, broonie, linux-omap, devicetree,
	linux-arm-kernel, linux-kernel, linux-spi, andy.shevchenko,
	robert.jarzmik, nsekhar, linux-spi

The patch

   spi: omap2-mcspi: Select SPI_SPLIT

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 2b32e987c48c65a1a40b3b4294435f761e063b6b Mon Sep 17 00:00:00 2001
From: Franklin S Cooper Jr <fcooper@ti.com>
Date: Thu, 7 Jul 2016 12:17:49 -0500
Subject: [PATCH] spi: omap2-mcspi: Select SPI_SPLIT

The function sg_split will be used by spi-omap2-mcspi to handle a SoC
workaround in the SPI driver. Therefore, select SG_SPLIT so this function
is available to the driver.

Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec8d90b..d6fb8d4b7786 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -411,6 +411,7 @@ config SPI_OMAP24XX
 	tristate "McSPI driver for OMAP"
 	depends on HAS_DMA
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
+	select SG_SPLIT
 	help
 	  SPI master controller for OMAP24XX and later Multichannel SPI
 	  (McSPI) modules.
-- 
2.8.1

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

* Re: Applied "spi: omap2-mcspi: Select SPI_SPLIT" to the spi tree
  2016-07-08  8:49   ` Applied "spi: omap2-mcspi: Select SPI_SPLIT" to the spi tree Mark Brown
@ 2016-07-08  8:54     ` Sekhar Nori
  0 siblings, 0 replies; 10+ messages in thread
From: Sekhar Nori @ 2016-07-08  8:54 UTC (permalink / raw)
  To: Mark Brown, Franklin S Cooper Jr
  Cc: tony, robh+dt, linux-omap, devicetree, linux-arm-kernel,
	linux-kernel, linux-spi, andy.shevchenko, robert.jarzmik

Mark,

On Friday 08 July 2016 02:19 PM, Mark Brown wrote:
> From 2b32e987c48c65a1a40b3b4294435f761e063b6b Mon Sep 17 00:00:00 2001
> From: Franklin S Cooper Jr <fcooper@ti.com>
> Date: Thu, 7 Jul 2016 12:17:49 -0500
> Subject: [PATCH] spi: omap2-mcspi: Select SPI_SPLIT

Looks like you fixed up the description locally but forgot to fix the
subject line. It still shows SPI_SPLIT.

> 
> The function sg_split will be used by spi-omap2-mcspi to handle a SoC
> workaround in the SPI driver. Therefore, select SG_SPLIT so this function
> is available to the driver.
> 
> Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
> Signed-off-by: Mark Brown <broonie@kernel.org>

Thanks,
Sekhar

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

end of thread, other threads:[~2016-07-08  8:55 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-07 17:17 [RFC] [PATCH v3 0/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
2016-07-07 17:17 ` [RFC] [PATCH v3 1/4] spi: omap2-mcspi: Add comments for RX only DMA buffer workaround Franklin S Cooper Jr
2016-07-08  8:46   ` Mark Brown
2016-07-07 17:17 ` [RFC] [PATCH v3 2/4] spi: spi-omap2-mcspi: Select SPI_SPLIT Franklin S Cooper Jr
2016-07-07 17:33   ` Randy Dunlap
2016-07-08  8:49   ` Applied "spi: omap2-mcspi: Select SPI_SPLIT" to the spi tree Mark Brown
2016-07-08  8:54     ` Sekhar Nori
2016-07-07 17:17 ` [RFC] [PATCH v3 3/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Franklin S Cooper Jr
2016-07-08  8:49   ` Applied "spi: omap2-mcspi: Use the SPI framework to handle DMA mapping" to the spi tree Mark Brown
2016-07-07 17:17 ` [RFC] [PATCH v3 4/4] ARM: dts: am335x-icev2: Add SPI based NOR Franklin S Cooper Jr

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).