Skip to contentSkip to conversation

spi/sunxi patches

PATCH In review Michal Suchanek 4 participants 28 messages Aug 20, 2015 – May 17, 2016

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover spi/sunxi patches

Hello,

Since the sun4i dmaengine and DT label conversion patches are in this should be now workable.

- fix some minor issues with the spi driver
- add spi dt nodes on some boards
- include the DMA patch which depends on the dmaengine

Thanks

Michal

Emilio L?pez (1):
spi: sun4i: add DMA support

Michal Suchanek (8):
spi: sunxi: fix transfer timeout
spi: sun4i: fix FIFO limit
spi: sunxi: check that transfer speed is non-zero
ARM: dts: sun7i: cubieboard2: Enable SPI0
ARM: dts: sunxi: add spi aliases on cubieboards
ARM: dts: sun5i: add SPI pins on A13 and A10s
ARM: dts: sunxi: A10s Olinuxino Micro: add spi2.
ARM: dts: sunxi: Add SPI aliases on A10s Olinuxino.

 arch/arm/boot/dts/sun4i-a10-cubieboard.dts       |   1 +
 arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts |  10 ++
 arch/arm/boot/dts/sun5i-a10s.dtsi                |  21 +++
 arch/arm/boot/dts/sun5i.dtsi                     |  49 +++++++
 arch/arm/boot/dts/sun7i-a20-cubieboard2.dts      |   8 ++
 drivers/spi/spi-sun4i.c                          | 166 ++++++++++++++++++++---
 drivers/spi/spi-sun6i.c                          |  25 +++-
 7 files changed, 257 insertions(+), 23 deletions(-)
Signature · 1 line
2.1.4
#1 lore raw

PATCH 1/9 spi: sunxi: fix transfer timeout

The trasfer timeout is fixed at 1000 ms. Reading a 4Mbyte flash over 1MHz SPI bus takes way longer than that. Calculate the timeout from the actual time the transfer is supposed to take and multiply by 2 for good measure.

---
 drivers/spi/spi-sun4i.c | 10 +++++++++-
 drivers/spi/spi-sun6i.c | 10 +++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)
drivers/spi/spi-sun4i.c +9 -1
index fbb0a4d..48532ec 100644
@@ -170,6 +170,7 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(master);
 	unsigned int mclk_rate, div, timeout;
+	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
 	int ret = 0;
 	u32 reg;
@@ -279,9 +280,16 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
 
+	tx_time = max_t(int, tfr->len * 8 * 2 / (speed / 1000), 100);
+	start = jiffies;
 	timeout = wait_for_completion_timeout(&sspi->done,
-					      msecs_to_jiffies(1000));
+					      msecs_to_jiffies(tx_time));
+	end = jiffies;
 	if (!timeout) {
+		dev_warn(&master->dev,
+			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+			 dev_name(&spi->dev), tfr->len, speed,
+			 jiffies_to_msecs(end - start), tx_time);
 		ret = -ETIMEDOUT;
 		goto out;
 	}
drivers/spi/spi-sun6i.c +9 -1
index ac48f59..3d0f66c 100644
@@ -162,6 +162,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 	unsigned int mclk_rate, div, timeout;
 	unsigned int tx_len = 0;
 	int ret = 0;
+	unsigned int start, end, tx_time;
 	u32 reg;
 
 	/* We don't support transfer larger than the FIFO */
@@ -269,9 +270,16 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 	reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
 	sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
 
+	tx_time = max_t(int, tfr->len * 8 * 2 / (speed / 1000), 100);
+	start = jiffies;
 	timeout = wait_for_completion_timeout(&sspi->done,
-					      msecs_to_jiffies(1000));
+					      msecs_to_jiffies(tx_time));
+	end = jiffies;
 	if (!timeout) {
+		dev_warn(&master->dev,
+			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+			 dev_name(&spi->dev), tfr->len, speed,
+			 jiffies_to_msecs(end - start), tx_time);
 		ret = -ETIMEDOUT;
 		goto out;
 	}
Signature · 1 line
2.1.4
#8 lore raw

PATCH 2/9 spi: sun4i: fix FIFO limit

In reply to Michal Suchanek

When testing SPI without DMA I noticed that filling the FIFO on the spi controller causes timeout.

Always leave room for one byte in the FIFO.

---
 drivers/spi/spi-sun4i.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/spi/spi-sun4i.c +5 -1
index 48532ec..707f61b 100644
@@ -178,6 +178,8 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	/* We don't support transfer larger than the FIFO */
 	if (tfr->len > SUN4I_FIFO_DEPTH)
 		return -EINVAL;
+	if (tfr->tx_buf && tfr->len => SUN4I_FIFO_DEPTH)
+		return -EINVAL;
 
 	reinit_completion(&sspi->done);
 	sspi->tx_buf = tfr->tx_buf;
@@ -271,7 +273,9 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
 
 	/* Fill the TX FIFO */
-	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+	/* Filling the fifo fully causes timeout for some reason
+	 * at least on spi2 on a10s */
+	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
 
 	/* Enable the interrupts */
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
Signature · 1 line
2.1.4
#10 lore raw

PATCH 3/9 spi: sunxi: check that transfer speed is non-zero

In reply to Michal Suchanek

When the maximum transfer speed is not set for a SPI slave the value remains 0 and the code in sunxi SPI divides by it. Use an arbitrary speed instead in that case.

---
 drivers/spi/spi-sun4i.c | 15 ++++++++++-----
 drivers/spi/spi-sun6i.c | 15 ++++++++++-----
 2 files changed, 20 insertions(+), 10 deletions(-)
drivers/spi/spi-sun4i.c +10 -5
index 707f61b..4dda366 100644
@@ -169,7 +169,7 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 				  struct spi_transfer *tfr)
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(master);
-	unsigned int mclk_rate, div, timeout;
+	unsigned int speed, mclk_rate, div, timeout;
 	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
 	int ret = 0;
@@ -230,10 +230,15 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 
 	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
 
+	speed = spi->max_speed_hz;
+	if (!speed) {
+		speed = 100000;
+		dev_warn(&spi->dev, "SPI speed not set. Using %uHz.", speed);
+	}
 	/* Ensure that we have a parent clock fast enough */
 	mclk_rate = clk_get_rate(sspi->mclk);
-	if (mclk_rate < (2 * spi->max_speed_hz)) {
-		clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+	if (mclk_rate < (2 * speed)) {
+		clk_set_rate(sspi->mclk, 2 * speed);
 		mclk_rate = clk_get_rate(sspi->mclk);
 	}
 
@@ -251,14 +256,14 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	 * First try CDR2, and if we can't reach the expected
 	 * frequency, fall back to CDR1.
 	 */
-	div = mclk_rate / (2 * spi->max_speed_hz);
+	div = mclk_rate / (2 * speed);
 	if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
 		if (div > 0)
 			div--;
 
 		reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
 	} else {
-		div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+		div = ilog2(mclk_rate) - ilog2(speed);
 		reg = SUN4I_CLK_CTL_CDR1(div);
 	}
 
drivers/spi/spi-sun6i.c +10 -5
index 3d0f66c..cf6a33e 100644
@@ -159,7 +159,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 				  struct spi_transfer *tfr)
 {
 	struct sun6i_spi *sspi = spi_master_get_devdata(master);
-	unsigned int mclk_rate, div, timeout;
+	unsigned int speed, mclk_rate, div, timeout;
 	unsigned int tx_len = 0;
 	int ret = 0;
 	unsigned int start, end, tx_time;
@@ -216,10 +216,15 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 
 	sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 
+	speed = spi->max_speed_hz;
+	if(!speed) {
+		speed = 100000;
+		dev_warn(&spi->dev, "SPI speed not set. Using %uHz.", speed);
+	}
 	/* Ensure that we have a parent clock fast enough */
 	mclk_rate = clk_get_rate(sspi->mclk);
-	if (mclk_rate < (2 * spi->max_speed_hz)) {
-		clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+	if (mclk_rate < (2 * speed)) {
+		clk_set_rate(sspi->mclk, 2 * speed);
 		mclk_rate = clk_get_rate(sspi->mclk);
 	}
 
@@ -237,14 +242,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 	 * First try CDR2, and if we can't reach the expected
 	 * frequency, fall back to CDR1.
 	 */
-	div = mclk_rate / (2 * spi->max_speed_hz);
+	div = mclk_rate / (2 * speed);
 	if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
 		if (div > 0)
 			div--;
 
 		reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
 	} else {
-		div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+		div = ilog2(mclk_rate) - ilog2(speed);
 		reg = SUN6I_CLK_CTL_CDR1(div);
 	}
 
Signature · 1 line
2.1.4
#15 lore raw

PATCH 5/9 ARM: dts: sun7i: cubieboard2: Enable SPI0

In reply to Michal Suchanek

Only SPI0 is enabled. The schematic denotes it as the only SPI bus. Other SPI pins are reserved for different peripherals.

---
 arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 7 +++++++
 1 file changed, 7 insertions(+)
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +7 -0
index 39a51d5..9861304 100644
@@ -198,6 +198,13 @@
 	status = "okay";
 };
 
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_a>,
+		    <&spi0_cs0_pins_a>;
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
Signature · 1 line
2.1.4
#17 lore raw

PATCH 4/9 spi: sun4i: add DMA support

In reply to Michal Suchanek

From: Emilio L?pez <[email protected]>

This patch adds support for 64 byte or bigger transfers on the sun4i SPI controller. Said transfers will be performed via DMA.

---
 drivers/spi/spi-sun4i.c | 145 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 130 insertions(+), 15 deletions(-)
drivers/spi/spi-sun4i.c +130 -15
index 4dda366..63242a7 100644
@@ -14,6 +14,8 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -34,6 +36,7 @@
 #define SUN4I_CTL_CPHA				BIT(2)
 #define SUN4I_CTL_CPOL				BIT(3)
 #define SUN4I_CTL_CS_ACTIVE_LOW			BIT(4)
+#define SUN4I_CTL_DMAMC_DEDICATED		BIT(5)
 #define SUN4I_CTL_LMTF				BIT(6)
 #define SUN4I_CTL_TF_RST			BIT(8)
 #define SUN4I_CTL_RF_RST			BIT(9)
@@ -51,6 +54,8 @@
 #define SUN4I_INT_STA_REG		0x10
 
 #define SUN4I_DMA_CTL_REG		0x14
+#define SUN4I_DMA_CTL_RF_READY			BIT(0)
+#define SUN4I_DMA_CTL_TF_NOT_FULL		BIT(10)
 
 #define SUN4I_WAIT_REG			0x18
 
@@ -130,6 +135,13 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
 	}
 }
 
+static bool sun4i_spi_can_dma(struct spi_master *master,
+			      struct spi_device *spi,
+			      struct spi_transfer *tfr)
+{
+	return tfr->len >= SUN4I_FIFO_DEPTH;
+}
+
 static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -169,17 +181,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 				  struct spi_transfer *tfr)
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(master);
+	struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
 	unsigned int speed, mclk_rate, div, timeout;
 	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
+	u32 reg, trigger = 0;
 	int ret = 0;
-	u32 reg;
-
-	/* We don't support transfer larger than the FIFO */
-	if (tfr->len > SUN4I_FIFO_DEPTH)
-		return -EINVAL;
-	if (tfr->tx_buf && tfr->len => SUN4I_FIFO_DEPTH)
-		return -EINVAL;
 
 	reinit_completion(&sspi->done);
 	sspi->tx_buf = tfr->tx_buf;
@@ -277,14 +284,67 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
 	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
 
-	/* Fill the TX FIFO */
-	/* Filling the fifo fully causes timeout for some reason
-	 * at least on spi2 on a10s */
-	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
-
 	/* Enable the interrupts */
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
 
+	if (sun4i_spi_can_dma(master, spi, tfr)) {
+		dev_dbg(&sspi->master->dev, "Using DMA mode for transfer\n");
+
+		if (sspi->tx_buf) {
+			desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
+					tfr->tx_sg.sgl, tfr->tx_sg.nents,
+					DMA_TO_DEVICE,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+			if (!desc_tx) {
+				dev_err(&sspi->master->dev,
+					"Couldn't prepare dma slave\n");
+				return -EIO;
+			}
+
+			trigger |= SUN4I_DMA_CTL_TF_NOT_FULL;
+
+			dmaengine_submit(desc_tx);
+			dma_async_issue_pending(master->dma_tx);
+
+		}
+
+		if (sspi->rx_buf) {
+			desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
+					tfr->rx_sg.sgl, tfr->rx_sg.nents,
+					DMA_FROM_DEVICE,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+			if (!desc_rx) {
+				dev_err(&sspi->master->dev,
+					"Couldn't prepare dma slave\n");
+				return -EIO;
+			}
+
+			trigger |= SUN4I_DMA_CTL_RF_READY;
+
+			dmaengine_submit(desc_rx);
+			dma_async_issue_pending(master->dma_rx);
+		}
+
+		/* Enable Dedicated DMA requests */
+		reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+		reg |= SUN4I_CTL_DMAMC_DEDICATED;
+		sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+		sun4i_spi_write(sspi, SUN4I_DMA_CTL_REG, trigger);
+	} else {
+		dev_dbg(&sspi->master->dev, "Using PIO mode for transfer\n");
+
+		/* Disable DMA requests */
+		reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+		sun4i_spi_write(sspi, SUN4I_CTL_REG,
+				reg & ~SUN4I_CTL_DMAMC_DEDICATED);
+		sun4i_spi_write(sspi, SUN4I_DMA_CTL_REG, 0);
+
+		/* Fill the TX FIFO */
+		/* Filling the fifo fully causes timeout for some reason
+		 * at least on spi2 on a10s */
+		sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
+	}
+
 	/* Start the transfer */
 	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
@@ -303,7 +363,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 		goto out;
 	}
 
-	sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+	if (sun4i_spi_can_dma(master, spi, tfr) && desc_rx) {
+		/* The receive transfer should be the last one to finish */
+		dma_wait_for_async_tx(desc_rx);
+	} else {
+		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+	}
 
 out:
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
@@ -368,6 +433,7 @@ static int sun4i_spi_runtime_suspend(struct device *dev)
 
 static int sun4i_spi_probe(struct platform_device *pdev)
 {
+	struct dma_slave_config dma_sconfig;
 	struct spi_master *master;
 	struct sun4i_spi *sspi;
 	struct resource	*res;
@@ -403,7 +469,9 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 		goto err_free_master;
 	}
 
+	init_completion(&sspi->done);
 	sspi->master = master;
+	master->can_dma = sun4i_spi_can_dma;
 	master->set_cs = sun4i_spi_set_cs;
 	master->transfer_one = sun4i_spi_transfer_one;
 	master->num_chipselect = 4;
@@ -426,7 +494,45 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 		goto err_free_master;
 	}
 
-	init_completion(&sspi->done);
+	master->dma_tx = dma_request_slave_channel_reason(&pdev->dev, "tx");
+	if (IS_ERR(master->dma_tx)) {
+		dev_err(&pdev->dev, "Unable to acquire DMA channel TX\n");
+		ret = PTR_ERR(master->dma_tx);
+		goto err_free_master;
+	}
+
+	dma_sconfig.direction = DMA_MEM_TO_DEV;
+	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.dst_addr = res->start + SUN4I_TXDATA_REG;
+	dma_sconfig.src_maxburst = 1;
+	dma_sconfig.dst_maxburst = 1;
+
+	ret = dmaengine_slave_config(master->dma_tx, &dma_sconfig);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to configure TX DMA slave\n");
+		goto err_tx_dma_release;
+	}
+
+	master->dma_rx = dma_request_slave_channel_reason(&pdev->dev, "rx");
+	if (IS_ERR(master->dma_rx)) {
+		dev_err(&pdev->dev, "Unable to acquire DMA channel RX\n");
+		ret = PTR_ERR(master->dma_rx);
+		goto err_tx_dma_release;
+	}
+
+	dma_sconfig.direction = DMA_DEV_TO_MEM;
+	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.src_addr = res->start + SUN4I_RXDATA_REG;
+	dma_sconfig.src_maxburst = 1;
+	dma_sconfig.dst_maxburst = 1;
+
+	ret = dmaengine_slave_config(master->dma_rx, &dma_sconfig);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to configure RX DMA slave\n");
+		goto err_rx_dma_release;
+	}
 
 	/*
 	 * This wake-up/shutdown pattern is to be able to have the
@@ -435,7 +541,7 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 	ret = sun4i_spi_runtime_resume(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Couldn't resume the device\n");
-		goto err_free_master;
+		goto err_rx_dma_release;
 	}
 
 	pm_runtime_set_active(&pdev->dev);
@@ -453,6 +559,10 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 	sun4i_spi_runtime_suspend(&pdev->dev);
+err_rx_dma_release:
+	dma_release_channel(master->dma_rx);
+err_tx_dma_release:
+	dma_release_channel(master->dma_tx);
 err_free_master:
 	spi_master_put(master);
 	return ret;
@@ -460,8 +570,13 @@ err_free_master:
 
 static int sun4i_spi_remove(struct platform_device *pdev)
 {
+	struct spi_master *master = platform_get_drvdata(pdev);
+
 	pm_runtime_disable(&pdev->dev);
 
+	dma_release_channel(master->dma_rx);
+	dma_release_channel(master->dma_tx);
+
 	return 0;
 }
 
Signature · 1 line
2.1.4
#23 lore raw

PATCH 6/9 ARM: dts: sunxi: add spi aliases on cubieboards

In reply to Michal Suchanek

Aliases give nicer device node names.

---
 arch/arm/boot/dts/sun4i-a10-cubieboard.dts  | 1 +
 arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 1 +
 2 files changed, 2 insertions(+)
arch/arm/boot/dts/sun4i-a10-cubieboard.dts +1 -0
index 9afb4e0..ba02f3b 100644
@@ -54,6 +54,7 @@
 
 	aliases {
 		serial0 = &uart0;
+		spi0 = &spi0;
 	};
 
 	chosen {
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +1 -0
index 9861304..4c952a2 100644
@@ -56,6 +56,7 @@
 
 	aliases {
 		serial0 = &uart0;
+		spi0 = &spi0;
 	};
 
 	chosen {
Signature · 1 line
2.1.4
#24 lore raw

PATCH 7/9 ARM: dts: sun5i: add SPI pins on A13 and A10s

In reply to Michal Suchanek

According to datasheet some pins are available on A10s only while others are shared with A13.

---
This time add all spi pins and make the CS pins separate as is seen with current sun4i DTs

---
 arch/arm/boot/dts/sun5i-a10s.dtsi | 21 +++++++++++++++++
 arch/arm/boot/dts/sun5i.dtsi      | 49 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)
arch/arm/boot/dts/sun5i-a10s.dtsi +21 -0
index f11efb7..d9610fa 100644
@@ -201,6 +201,27 @@
 		allwinner,drive = <SUN4I_PINCTRL_30_MA>;
 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 	};
+
+	spi1_cs1_pins_a: spi1_cs1 at 0 {
+		allwinner,pins = "PG13";
+		allwinner,function = "spi1";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	spi2_pins_a: spi2 at 0 {
+		allwinner,pins = "PB12", "PB13", "PB14";
+		allwinner,function = "spi1";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	spi2_cs0_pins_a: spi2_cs0 at 0 {
+		allwinner,pins = "PB11";
+		allwinner,function = "spi1";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
 };
 
 &sram_a {
arch/arm/boot/dts/sun5i.dtsi +49 -0

55 lines not on this page · raw message

Signature · 1 line
2.1.4
#26 lore raw

PATCH 8/9 ARM: dts: sunxi: A10s Olinuxino Micro: add spi2.

In reply to Michal Suchanek

spi2 is exposed on the UEXT connector.

---
 arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 7 +++++++
 1 file changed, 7 insertions(+)
arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +7 -0
index a7e19e4..b546fc2 100644
@@ -185,6 +185,13 @@
 	status = "okay";
 };
 
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_pins_a>,
+		    <&spi2_cs0_pins_a>;
+	status = "okay";
+};
+
 &ohci0 {
 	status = "okay";
 };
Signature · 1 line
2.1.4
#27 lore raw

PATCH 9/9 ARM: dts: sunxi: Add SPI aliases on A10s Olinuxino.

In reply to Michal Suchanek

SPI aliases give nicer spidev device node names.

---
 arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 3 +++
 1 file changed, 3 insertions(+)
arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +3 -0
index b546fc2..1a0e0c0 100644
@@ -58,6 +58,9 @@
 		serial0 = &uart0;
 		serial1 = &uart2;
 		serial2 = &uart3;
+		spi0 = &spi0;
+		spi1 = &spi1;
+		spi2 = &spi2;
 	};
 
 	chosen {
Signature · 1 line
2.1.4
#2 lore raw

Re: [PATCH 1/9] spi: sunxi: fix transfer timeout

In reply to Michal Suchanek
Quoted 28 lines · Michal Suchanek

The trasfer timeout is fixed at 1000 ms. Reading a 4Mbyte flash over 1MHz SPI bus takes way longer than that. Calculate the timeout from the actual time the transfer is supposed to take and multiply by 2 for good measure.

---
 drivers/spi/spi-sun4i.c | 10 +++++++++-
 drivers/spi/spi-sun6i.c | 10 +++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)
drivers/spi/spi-sun4i.c +2 -0
index fbb0a4d..48532ec 100644
@@ -170,6 +170,7 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(master);
 	unsigned int mclk_rate, div, timeout;
+	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
 	int ret = 0;
 	u32 reg;
@@ -279,9 +280,16 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
 
+	tx_time = max_t(int, tfr->len * 8 * 2 / (speed / 1000), 100);

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 292

Quoted 10 lines
drivers/spi/spi-sun4i.c +7 -1
+	start = jiffies;
 	timeout = wait_for_completion_timeout(&sspi->done,
-					      msecs_to_jiffies(1000));
+					      msecs_to_jiffies(tx_time));
+	end = jiffies;
 	if (!timeout) {
+		dev_warn(&master->dev,
+			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+			 dev_name(&spi->dev), tfr->len, speed,
+			 jiffies_to_msecs(end - start), tx_time);

Timeout already contains the number of jiffies elapsed (and I'm not sure anyone reading that message would get that the last number is actually the maximum timeout).

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/ca920d73/attachment.sig>
#9 lore raw

Re: [PATCH 2/9] spi: sun4i: fix FIFO limit

In reply to Michal Suchanek
Quoted 15 lines · Michal Suchanek

When testing SPI without DMA I noticed that filling the FIFO on the spi controller causes timeout.

Always leave room for one byte in the FIFO.

---
 drivers/spi/spi-sun4i.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/spi/spi-sun4i.c +0 -0
index 48532ec..707f61b 100644

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 182

Quoted 5 lines
drivers/spi/spi-sun4i.c +2 -0
@@ -178,6 +178,8 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	/* We don't support transfer larger than the FIFO */
 	if (tfr->len > SUN4I_FIFO_DEPTH)
 		return -EINVAL;
+	if (tfr->tx_buf && tfr->len => SUN4I_FIFO_DEPTH)
+		return -EINVAL;

Shouldn't you fix the condition just above instead?

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 277

Quoted 10 lines
drivers/spi/spi-sun4i.c +2 -1
 	reinit_completion(&sspi->done);
 	sspi->tx_buf = tfr->tx_buf;
@@ -271,7 +273,9 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
 
 	/* Fill the TX FIFO */
-	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+	/* Filling the fifo fully causes timeout for some reason
+	 * at least on spi2 on a10s */

Please use the proper comment style. And it only happens on that particular SPI controller and SoC combination?

Quoted 7 lines
drivers/spi/spi-sun4i.c +1 -0
+	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
 
 	/* Enable the interrupts */
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
Signature · 1 line
2.1.4
Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/b3e270e9/attachment.sig>
#11 lore raw

Re: [PATCH 3/9] spi: sunxi: check that transfer speed is non-zero

In reply to Michal Suchanek
Quoted 5 lines · Michal Suchanek

When the maximum transfer speed is not set for a SPI slave the value remains 0 and the code in sunxi SPI divides by it. Use an arbitrary speed instead in that case.

spi->max_speed_hz is set using the spi-max-frequency property, and spi->will error out if that property isn't set. What am I missing?

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/45a045ea/attachment-0001.sig>
#19 lore raw

Re: [PATCH 4/9] spi: sun4i: add DMA support

In reply to Emilio López
Quoted 7 lines · Emilio L?pez

From: Emilio L?pez <[email protected]>

This patch adds support for 64 byte or bigger transfers on the sun4i SPI controller. Said transfers will be performed via DMA.

This should have your SoB.

Quoted 107 lines
---
 drivers/spi/spi-sun4i.c | 145 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 130 insertions(+), 15 deletions(-)
drivers/spi/spi-sun4i.c +41 -12
index 4dda366..63242a7 100644
@@ -14,6 +14,8 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -34,6 +36,7 @@
 #define SUN4I_CTL_CPHA				BIT(2)
 #define SUN4I_CTL_CPOL				BIT(3)
 #define SUN4I_CTL_CS_ACTIVE_LOW			BIT(4)
+#define SUN4I_CTL_DMAMC_DEDICATED		BIT(5)
 #define SUN4I_CTL_LMTF				BIT(6)
 #define SUN4I_CTL_TF_RST			BIT(8)
 #define SUN4I_CTL_RF_RST			BIT(9)
@@ -51,6 +54,8 @@
 #define SUN4I_INT_STA_REG		0x10
 
 #define SUN4I_DMA_CTL_REG		0x14
+#define SUN4I_DMA_CTL_RF_READY			BIT(0)
+#define SUN4I_DMA_CTL_TF_NOT_FULL		BIT(10)
 
 #define SUN4I_WAIT_REG			0x18
 
@@ -130,6 +135,13 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
 	}
 }
 
+static bool sun4i_spi_can_dma(struct spi_master *master,
+			      struct spi_device *spi,
+			      struct spi_transfer *tfr)
+{
+	return tfr->len >= SUN4I_FIFO_DEPTH;
+}
+
 static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -169,17 +181,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 				  struct spi_transfer *tfr)
 {
 	struct sun4i_spi *sspi = spi_master_get_devdata(master);
+	struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
 	unsigned int speed, mclk_rate, div, timeout;
 	unsigned int start, end, tx_time;
 	unsigned int tx_len = 0;
+	u32 reg, trigger = 0;
 	int ret = 0;
-	u32 reg;
-
-	/* We don't support transfer larger than the FIFO */
-	if (tfr->len > SUN4I_FIFO_DEPTH)
-		return -EINVAL;
-	if (tfr->tx_buf && tfr->len => SUN4I_FIFO_DEPTH)
-		return -EINVAL;
 
 	reinit_completion(&sspi->done);
 	sspi->tx_buf = tfr->tx_buf;
@@ -277,14 +284,67 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 	sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
 	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
 
-	/* Fill the TX FIFO */
-	/* Filling the fifo fully causes timeout for some reason
-	 * at least on spi2 on a10s */
-	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
-
 	/* Enable the interrupts */
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
 
+	if (sun4i_spi_can_dma(master, spi, tfr)) {
+		dev_dbg(&sspi->master->dev, "Using DMA mode for transfer\n");
+
+		if (sspi->tx_buf) {
+			desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
+					tfr->tx_sg.sgl, tfr->tx_sg.nents,
+					DMA_TO_DEVICE,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+			if (!desc_tx) {
+				dev_err(&sspi->master->dev,
+					"Couldn't prepare dma slave\n");
+				return -EIO;
+			}
+
+			trigger |= SUN4I_DMA_CTL_TF_NOT_FULL;
+
+			dmaengine_submit(desc_tx);
+			dma_async_issue_pending(master->dma_tx);
+
+		}
+
+		if (sspi->rx_buf) {
+			desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
+					tfr->rx_sg.sgl, tfr->rx_sg.nents,
+					DMA_FROM_DEVICE,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+			if (!desc_rx) {

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 326

Quoted 10 lines
drivers/spi/spi-sun4i.c +10 -0
+				dev_err(&sspi->master->dev,
+					"Couldn't prepare dma slave\n");
+				return -EIO;
+			}
+
+			trigger |= SUN4I_DMA_CTL_RF_READY;
+
+			dmaengine_submit(desc_rx);
+			dma_async_issue_pending(master->dma_rx);
+		}

What happens if the dma driver controller isn't present in your system? Or that it doesn't have any channels available anymore?

Quoted 24 lines
drivers/spi/spi-sun4i.c +20 -0
+		/* Enable Dedicated DMA requests */
+		reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+		reg |= SUN4I_CTL_DMAMC_DEDICATED;
+		sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+		sun4i_spi_write(sspi, SUN4I_DMA_CTL_REG, trigger);
+	} else {
+		dev_dbg(&sspi->master->dev, "Using PIO mode for transfer\n");
+
+		/* Disable DMA requests */
+		reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+		sun4i_spi_write(sspi, SUN4I_CTL_REG,
+				reg & ~SUN4I_CTL_DMAMC_DEDICATED);
+		sun4i_spi_write(sspi, SUN4I_DMA_CTL_REG, 0);
+
+		/* Fill the TX FIFO */
+		/* Filling the fifo fully causes timeout for some reason
+		 * at least on spi2 on a10s */
+		sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
+	}
+
 	/* Start the transfer */
 	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 368

Quoted 7 lines
drivers/spi/spi-sun4i.c +3 -1
@@ -303,7 +363,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 		goto out;
 	}
 
-	sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+	if (sun4i_spi_can_dma(master, spi, tfr) && desc_rx) {
+		/* The receive transfer should be the last one to finish */
+		dma_wait_for_async_tx(desc_rx);

Nope, this is only meant for async_tx. You should register a callback in your transfer that will mark the completion structure as completed, and then drain the FIFO only if not using DMA.

Quoted 52 lines
drivers/spi/spi-sun4i.c +29 -1
+	} else {
+		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+	}
 
 out:
 	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
@@ -368,6 +433,7 @@ static int sun4i_spi_runtime_suspend(struct device *dev)
 
 static int sun4i_spi_probe(struct platform_device *pdev)
 {
+	struct dma_slave_config dma_sconfig;
 	struct spi_master *master;
 	struct sun4i_spi *sspi;
 	struct resource	*res;
@@ -403,7 +469,9 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 		goto err_free_master;
 	}
 
+	init_completion(&sspi->done);
 	sspi->master = master;
+	master->can_dma = sun4i_spi_can_dma;
 	master->set_cs = sun4i_spi_set_cs;
 	master->transfer_one = sun4i_spi_transfer_one;
 	master->num_chipselect = 4;
@@ -426,7 +494,45 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 		goto err_free_master;
 	}
 
-	init_completion(&sspi->done);
+	master->dma_tx = dma_request_slave_channel_reason(&pdev->dev, "tx");
+	if (IS_ERR(master->dma_tx)) {
+		dev_err(&pdev->dev, "Unable to acquire DMA channel TX\n");
+		ret = PTR_ERR(master->dma_tx);
+		goto err_free_master;
+	}
+
+	dma_sconfig.direction = DMA_MEM_TO_DEV;
+	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.dst_addr = res->start + SUN4I_TXDATA_REG;
+	dma_sconfig.src_maxburst = 1;
+	dma_sconfig.dst_maxburst = 1;
+
+	ret = dmaengine_slave_config(master->dma_tx, &dma_sconfig);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to configure TX DMA slave\n");
+		goto err_tx_dma_release;
+	}
+
+	master->dma_rx = dma_request_slave_channel_reason(&pdev->dev, "rx");
+	if (IS_ERR(master->dma_rx)) {
+		dev_err(&pdev->dev, "Unable to acquire DMA channel RX\n");

drivers/spi/spi-sun4i.c static int sun4i_spi_probe(struct platform_device *pdev) · line 529

Quoted 10 lines
drivers/spi/spi-sun4i.c +10 -0
+		ret = PTR_ERR(master->dma_rx);
+		goto err_tx_dma_release;
+	}
+
+	dma_sconfig.direction = DMA_DEV_TO_MEM;
+	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_sconfig.src_addr = res->start + SUN4I_RXDATA_REG;
+	dma_sconfig.src_maxburst = 1;
+	dma_sconfig.dst_maxburst = 1;

We can't use a higher bust size?

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/707bfe7e/attachment.sig>
#16 lore raw

Re: [PATCH 5/9] ARM: dts: sun7i: cubieboard2: Enable SPI0

In reply to Michal Suchanek
Quoted 4 lines · Michal Suchanek

Only SPI0 is enabled. The schematic denotes it as the only SPI bus. Other SPI pins are reserved for different peripherals.

What device is connected to the other end?

Quoted 9 lines
---
 arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 7 +++++++
 1 file changed, 7 insertions(+)
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +0 -0
index 39a51d5..9861304 100644

arch/arm/boot/dts/sun7i-a20-cubieboard2.dts line 207

Quoted 10 lines
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +7 -0
@@ -198,6 +198,13 @@
 	status = "okay";
 };
 
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_a>,
+		    <&spi0_cs0_pins_a>;
+	status = "okay";
+};
+

You should probably add an alias to that bus too.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/5f89b1a8/attachment-0001.sig>
#25 lore raw

Re: [PATCH 7/9] ARM: dts: sun5i: add SPI pins on A13 and A10s

In reply to Michal Suchanek
Quoted 31 lines · Michal Suchanek

According to datasheet some pins are available on A10s only while others are shared with A13.

---
This time add all spi pins and make the CS pins separate as is seen with current sun4i DTs

---
 arch/arm/boot/dts/sun5i-a10s.dtsi | 21 +++++++++++++++++
 arch/arm/boot/dts/sun5i.dtsi      | 49 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)
arch/arm/boot/dts/sun5i-a10s.dtsi +11 -0
index f11efb7..d9610fa 100644
@@ -201,6 +201,27 @@
 		allwinner,drive = <SUN4I_PINCTRL_30_MA>;
 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 	};
+
+	spi1_cs1_pins_a: spi1_cs1 at 0 {
+		allwinner,pins = "PG13";
+		allwinner,function = "spi1";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	spi2_pins_a: spi2 at 0 {
+		allwinner,pins = "PB12", "PB13", "PB14";
+		allwinner,function = "spi1";

arch/arm/boot/dts/sun5i-a10s.dtsi line 224

Quoted 10 lines
arch/arm/boot/dts/sun5i-a10s.dtsi +10 -0
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	spi2_cs0_pins_a: spi2_cs0 at 0 {
+		allwinner,pins = "PB11";
+		allwinner,function = "spi1";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};

spi2 nodes with spi1 function ??? How can that even work?

Quoted 50 lines
arch/arm/boot/dts/sun5i-a10s.dtsi +0 -0
 };
 
 &sram_a {
arch/arm/boot/dts/sun5i.dtsi +39 -0
index 54b0978..7d32d49 100644
@@ -516,6 +516,55 @@
 				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
 				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
+
+			spi0_pins_a: spi0 at 0 {
+				allwinner,pins = "PC00", "PC01", "PC02";
+				allwinner,function = "spi0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi0_cs0_pins_a: spi0_cs0 at 0 {
+				allwinner,pins = "PC03";
+				allwinner,function = "spi0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi1_pins_a: spi1 at 0 {
+				allwinner,pins = "PG10", "PG11", "PG12";
+				allwinner,function = "spi1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi1_cs0_pins_a: spi1_cs0 at 0 {
+				allwinner,pins = "PG09";
+				allwinner,function = "spi1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi2_pins_b: spi2 at 1 {
+				allwinner,pins = "PE01", "PE02", "PE03";
+				allwinner,function = "spi2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi2_cs0_pins_b: spi2_cs1 at 1 {
+				allwinner,pins = "PE00";
+				allwinner,function = "spi2";

arch/arm/boot/dts/sun5i.dtsi line 567

Quoted 10 lines
arch/arm/boot/dts/sun5i.dtsi +10 -0
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi2_cs1_pins_a: spi2_cs1 at 0 {
+				allwinner,pins = "PB10";
+				allwinner,function = "spi2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};

Please only add the pins you intend to use.

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/04bcd02f/attachment.sig>
maintainer
#3 lore raw

Re: [PATCH 1/9] spi: sunxi: fix transfer timeout

In reply to Michal Suchanek
Quoted 2 lines · Michal Suchanek
 drivers/spi/spi-sun4i.c | 10 +++++++++-
 drivers/spi/spi-sun6i.c | 10 +++++++++-

Are we *sure* we can't work on merging these drivers :(
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/ffc08de4/attachment.sig>

maintainer
#14 lore raw

Re: [PATCH 3/9] spi: sunxi: check that transfer speed is non-zero

In reply to Michal Suchanek
Quoted 3 lines · Michal Suchanek

When the maximum transfer speed is not set for a SPI slave the value remains 0 and the code in sunxi SPI divides by it. Use an arbitrary speed instead in that case.

You should always be using the transfer speed that is defined per
transfer, the core will ensure that this is always set.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/db73391e/attachment.sig>

maintainer
#20 lore raw

Re: [PATCH 4/9] spi: sun4i: add DMA support

In reply to Emilio López

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 368

Quoted 4 lines · Emilio L?pez
drivers/spi/spi-sun4i.c +3 -1
-	sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+	if (sun4i_spi_can_dma(master, spi, tfr) && desc_rx) {
+		/* The receive transfer should be the last one to finish */
+		dma_wait_for_async_tx(desc_rx);

What if it's a transmit only transfer? We'll fall over to this...

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 371

Quoted 3 lines
drivers/spi/spi-sun4i.c +3 -0
+	} else {
+		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+	}

...which manually reads data from the FIFO which doesn't seem like what
we want, won't it conflict with the DMA?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/5d89ea8e/attachment.sig>

maintainer
#22 lore raw

Re: [PATCH 4/9] spi: sun4i: add DMA support

In reply to Emilio López
Quoted 2 lines · Emilio L?pez

Also, if you're sending on a patch from someone else you must add a
Signed-off-by, see SubmittingPatches.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/d0884ad1/attachment.sig>

#4 lore raw

Re: [PATCH 1/9] spi: sunxi: fix transfer timeout

In reply to Mark Brown
Quoted 6 lines · Mark Brown
Quoted 2 lines · Michal Suchanek
 drivers/spi/spi-sun4i.c | 10 +++++++++-
 drivers/spi/spi-sun6i.c | 10 +++++++++-

Are we *sure* we can't work on merging these drivers :(

Those are two different IPs, that don't really share anything but their author...

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/3fafe925/attachment.sig>
#12 lore raw

Re: [PATCH 3/9] spi: sunxi: check that transfer speed is non-zero

In reply to Maxime Ripard
Quoted 10 lines · Maxime Ripard
Quoted 5 lines · Michal Suchanek

When the maximum transfer speed is not set for a SPI slave the value remains 0 and the code in sunxi SPI divides by it. Use an arbitrary speed instead in that case.

spi->max_speed_hz is set using the spi-max-frequency property, and spi->will error out if that property isn't set. What am I missing?

Spidev I guess.

You can set the speed to arbitrary value from userspace at any time using the spidev ioctls.

Thanks

Michal

maintainer
#5 lore raw

Re: [PATCH 1/9] spi: sunxi: fix transfer timeout

In reply to Maxime Ripard
Quoted 10 lines · Maxime Ripard
Quoted 6 lines · Mark Brown
Quoted 2 lines · Michal Suchanek
 drivers/spi/spi-sun4i.c | 10 +++++++++-
 drivers/spi/spi-sun6i.c | 10 +++++++++-

Are we *sure* we can't work on merging these drivers :(

Those are two different IPs, that don't really share anything but their author...

I seem to be seeing a number of changes like this one which make
apparently very similar modifications to both. Perhaps there is more
core usage that should be happening instead?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/c5c0c589/attachment-0001.sig>

#6 lore raw

Re: [PATCH 1/9] spi: sunxi: fix transfer timeout

Quoted 7 lines · Mark Brown
Quoted 5 lines · Maxime Ripard
Quoted 4 lines · Mark Brown
Quoted 2 lines · Michal Suchanek
 drivers/spi/spi-sun4i.c | 10 +++++++++-
 drivers/spi/spi-sun6i.c | 10 +++++++++-
Quoted 8 lines
Quoted 4 lines
Quoted 1 line

Are we *sure* we can't work on merging these drivers :(

Those are two different IPs, that don't really share anything but their author...

I seem to be seeing a number of changes like this one which make apparently very similar modifications to both. Perhaps there is more core usage that should be happening instead?

Yeah, because I wrote the two at the same time, and they share the same flaws. But that doesn't really mean that you can share anything at the driver level. And I'm not really sure that we can do much more at the framework level either, except maybe handling the timeout directly (but then the drivers would have to handle the recovering after a timeout too).

Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/6f6ae098/attachment.sig>
#13 lore raw

Re: [PATCH 3/9] spi: sunxi: check that transfer speed is non-zero

In reply to Michal Suchanek
Quoted 9 lines · Michal Suchanek
Quoted 7 lines · Maxime Ripard
Quoted 5 lines · Michal Suchanek

When the maximum transfer speed is not set for a SPI slave the value remains 0 and the code in sunxi SPI divides by it. Use an arbitrary speed instead in that case.

Quoted 8 lines
Quoted 3 lines

spi->max_speed_hz is set using the spi-max-frequency property, and spi->will error out if that property isn't set. What am I missing?

Spidev I guess.

You can set the speed to arbitrary value from userspace at any time using the spidev ioctls.

Then why should it be fixed at the controller driver level? It looks more like an issue that impacts everyone and should be fixed either in spidev directly or in the framework.

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/579970a2/attachment.sig>
maintainer
#7 lore raw

Re: [PATCH 1/9] spi: sunxi: fix transfer timeout

In reply to Maxime Ripard
Quoted 4 lines · Maxime Ripard

at the driver level. And I'm not really sure that we can do much more at the framework level either, except maybe handling the timeout directly (but then the drivers would have to handle the recovering after a timeout too).

We have handle_err() for that sort of cleanup.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150820/aa6e52ea/attachment.sig>

#21 lore raw

Re: [linux-sunxi] Re: [PATCH 4/9] spi: sun4i: add DMA support

In reply to Mark Brown
Quoted 27 lines · Maxime Ripard
Quoted 27 lines
drivers/spi/spi-sun4i.c +20 -0
+             /* Enable Dedicated DMA requests */
+             reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+             reg |= SUN4I_CTL_DMAMC_DEDICATED;
+             sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+             sun4i_spi_write(sspi, SUN4I_DMA_CTL_REG, trigger);
+     } else {
+             dev_dbg(&sspi->master->dev, "Using PIO mode for transfer\n");
+
+             /* Disable DMA requests */
+             reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+             sun4i_spi_write(sspi, SUN4I_CTL_REG,
+                             reg & ~SUN4I_CTL_DMAMC_DEDICATED);
+             sun4i_spi_write(sspi, SUN4I_DMA_CTL_REG, 0);
+
+             /* Fill the TX FIFO */
+             /* Filling the fifo fully causes timeout for some reason
+              * at least on spi2 on a10s */
+             sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
+     }
+
      /* Start the transfer */
      reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
      sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
@@ -303,7 +363,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
              goto out;
      }
 
Quoted 8 lines

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 368

Quoted 4 lines
drivers/spi/spi-sun4i.c +3 -1
-     sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+     if (sun4i_spi_can_dma(master, spi, tfr) && desc_rx) {
+             /* The receive transfer should be the last one to finish */
+             dma_wait_for_async_tx(desc_rx);

Nope, this is only meant for async_tx. You should register a callback in your transfer that will mark the completion structure as completed, and then drain the FIFO only if not using DMA.

What exactly is wrong with this?

I did not observe data corruption. Passing desc_rx to dma_wait_for_async_tx looks odd on closer inspection, though. Will look through some other spi driver code.

Quoted 28 lines
Quoted 28 lines
drivers/spi/spi-sun4i.c +27 -1
-     init_completion(&sspi->done);
+     master->dma_tx = dma_request_slave_channel_reason(&pdev->dev, "tx");
+     if (IS_ERR(master->dma_tx)) {
+             dev_err(&pdev->dev, "Unable to acquire DMA channel TX\n");
+             ret = PTR_ERR(master->dma_tx);
+             goto err_free_master;
+     }
+
+     dma_sconfig.direction = DMA_MEM_TO_DEV;
+     dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+     dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+     dma_sconfig.dst_addr = res->start + SUN4I_TXDATA_REG;
+     dma_sconfig.src_maxburst = 1;
+     dma_sconfig.dst_maxburst = 1;
+
+     ret = dmaengine_slave_config(master->dma_tx, &dma_sconfig);
+     if (ret) {
+             dev_err(&pdev->dev, "Unable to configure TX DMA slave\n");
+             goto err_tx_dma_release;
+     }
+
+     master->dma_rx = dma_request_slave_channel_reason(&pdev->dev, "rx");
+     if (IS_ERR(master->dma_rx)) {
+             dev_err(&pdev->dev, "Unable to acquire DMA channel RX\n");
+             ret = PTR_ERR(master->dma_rx);
+             goto err_tx_dma_release;
+     }
+
Quoted 8 lines

drivers/spi/spi-sun4i.c static int sun4i_spi_probe(struct platform_device *pdev) · line 529

Quoted 6 lines
drivers/spi/spi-sun4i.c +6 -0
+     dma_sconfig.direction = DMA_DEV_TO_MEM;
+     dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+     dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+     dma_sconfig.src_addr = res->start + SUN4I_RXDATA_REG;
+     dma_sconfig.src_maxburst = 1;
+     dma_sconfig.dst_maxburst = 1;

We can't use a higher bust size?

Who actually does?

It accomplishes the transfer with burst size of 1 so that's good enough.

Researching alignment requirements and other oddities of Chinese controllers when larger burst size is used can be topic for another patch.

Quoted 7 lines · Mark Brown

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 368

Quoted 4 lines · Emilio L?pez
drivers/spi/spi-sun4i.c +3 -1
-     sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+     if (sun4i_spi_can_dma(master, spi, tfr) && desc_rx) {
+             /* The receive transfer should be the last one to finish */
+             dma_wait_for_async_tx(desc_rx);
Quoted 7 lines

What if it's a transmit only transfer? We'll fall over to this...

drivers/spi/spi-sun4i.c static int sun4i_spi_transfer_one(struct spi_master *master, · line 371

Quoted 3 lines
drivers/spi/spi-sun4i.c +3 -0
+     } else {
+             sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+     }

...which manually reads data from the FIFO which doesn't seem like what

... which should be empty since RX is not enabled.

Quoted 1 line

we want, won't it conflict with the DMA?

It does not seem to conflict in practice.

Thanks

Michal