Linux SPI subsystem development
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver
@ 2017-09-13 16:21 Miquel Raynal
       [not found] ` <20170913162139.17598-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Miquel Raynal @ 2017-09-13 16:21 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Thomas Petazzoni, Gregory Clement, Antoine Tenart, Nadav Haklai,
	Miquel Raynal

Hello,

This short serie addresses two issues in Armada-3700 SPI controller driver.

Second patch from Zachary Zhang fixes the way padding is introduced in not
4-byte aligned SPI transfers (that fails some NAND flash devices). It also
revealed the issue fixed by the first commit when using quad-SPI. Thus, it
would be preferable to apply them in that order.

Differences with the first version:
- Added this cover letter.
- Fixed the commit titles by using "spi: armada-3700:" prefix.

And sorry for the noise.

Thanks,
Miquel

Miquel Raynal (1):
  spi: armada-3700: Fix failing commands with quad-SPI

Zachary Zhang (1):
  spi: armada-3700: Fix padding when sending not 4-byte aligned data

 drivers/spi/spi-armada-3700.c | 142 ++++++++++++++----------------------------
 1 file changed, 46 insertions(+), 96 deletions(-)

-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v2 1/2] spi: armada-3700: Fix failing commands with quad-SPI
       [not found] ` <20170913162139.17598-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-09-13 16:21   ` Miquel Raynal
  2017-09-13 16:21   ` [PATCH v2 2/2] spi: armada-3700: Fix padding when sending not 4-byte aligned data Miquel Raynal
  2017-09-13 17:20   ` [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver Gregory CLEMENT
  2 siblings, 0 replies; 5+ messages in thread
From: Miquel Raynal @ 2017-09-13 16:21 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Thomas Petazzoni, Gregory Clement, Antoine Tenart, Nadav Haklai,
	Miquel Raynal

A3700 SPI controller datasheet states that only the first line (IO0) is
used to receive and send instructions, addresses and dummy bytes,
unless for addresses during an RX operation in a quad SPI configuration
(see p.821 of the Armada-3720-DB datasheet). Otherwise, some commands
such as SPI NOR commands like READ_FROM_CACHE_DUAL_IO(0xeb) and
READ_FROM_CACHE_DUAL_IO(0xbb) will fail because these commands must send
address bytes through the four pins. Data transfer always use the four
bytes with this setup.

Thus, in quad SPI configuration, the A3700_SPI_ADDR_PIN bit must be set
only in this case to inform the controller that it must use the number
of pins indicated in the {A3700_SPI_DATA_PIN1,A3700_SPI_DATA_PIN0} field
during the address cycles of an RX operation.

Suggested-by: Ken Ma <make-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 drivers/spi/spi-armada-3700.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
index 6c7d7a460689..a28702b1fa05 100644
--- a/drivers/spi/spi-armada-3700.c
+++ b/drivers/spi/spi-armada-3700.c
@@ -161,7 +161,7 @@ static void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi,
 }
 
 static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
-				  unsigned int pin_mode)
+				  unsigned int pin_mode, bool receiving)
 {
 	u32 val;
 
@@ -177,6 +177,9 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
 		break;
 	case SPI_NBITS_QUAD:
 		val |= A3700_SPI_DATA_PIN1;
+		/* RX during address reception uses 4-pin */
+		if (receiving)
+			val |= A3700_SPI_ADDR_PIN;
 		break;
 	default:
 		dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode);
@@ -653,7 +656,7 @@ static int a3700_spi_transfer_one(struct spi_master *master,
 	else if (xfer->rx_buf)
 		nbits = xfer->rx_nbits;
 
-	a3700_spi_pin_mode_set(a3700_spi, nbits);
+	a3700_spi_pin_mode_set(a3700_spi, nbits, xfer->rx_buf ? true : false);
 
 	if (xfer->rx_buf) {
 		/* Set read data length */
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v2 2/2] spi: armada-3700: Fix padding when sending not 4-byte aligned data
       [not found] ` <20170913162139.17598-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-09-13 16:21   ` [PATCH v2 1/2] spi: armada-3700: Fix failing commands with quad-SPI Miquel Raynal
@ 2017-09-13 16:21   ` Miquel Raynal
  2017-09-13 17:20   ` [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver Gregory CLEMENT
  2 siblings, 0 replies; 5+ messages in thread
From: Miquel Raynal @ 2017-09-13 16:21 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Thomas Petazzoni, Gregory Clement, Antoine Tenart, Nadav Haklai,
	Miquel Raynal, Zachary Zhang

From: Zachary Zhang <zhangzg-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>

In 4-byte transfer mode, extra padding/dummy bytes '0xff' would be
sent in write operation if TX data is not 4-byte aligned since the
SPI data register is always shifted out as whole 4 bytes.

Fix this by using the header count feature that allows to transfer 0 to
4 bytes. Use it to actually send the first 1 to 3 bytes of data before
the rest of the buffer that will hence be 4-byte aligned.

Signed-off-by: Zachary Zhang <zhangzg-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 drivers/spi/spi-armada-3700.c | 135 +++++++++++++-----------------------------
 1 file changed, 41 insertions(+), 94 deletions(-)

diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
index a28702b1fa05..9172cb2d2e7a 100644
--- a/drivers/spi/spi-armada-3700.c
+++ b/drivers/spi/spi-armada-3700.c
@@ -99,11 +99,6 @@
 /* A3700_SPI_IF_TIME_REG */
 #define A3700_SPI_CLK_CAPT_EDGE		BIT(7)
 
-/* Flags and macros for struct a3700_spi */
-#define A3700_INSTR_CNT			1
-#define A3700_ADDR_CNT			3
-#define A3700_DUMMY_CNT			1
-
 struct a3700_spi {
 	struct spi_master *master;
 	void __iomem *base;
@@ -117,9 +112,6 @@ struct a3700_spi {
 	u8 byte_len;
 	u32 wait_mask;
 	struct completion done;
-	u32 addr_cnt;
-	u32 instr_cnt;
-	size_t hdr_cnt;
 };
 
 static u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset)
@@ -449,59 +441,43 @@ static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
 
 static void a3700_spi_header_set(struct a3700_spi *a3700_spi)
 {
-	u32 instr_cnt = 0, addr_cnt = 0, dummy_cnt = 0;
+	unsigned int addr_cnt;
 	u32 val = 0;
 
 	/* Clear the header registers */
 	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0);
 	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0);
 	spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
 
 	/* Set header counters */
 	if (a3700_spi->tx_buf) {
-		if (a3700_spi->buf_len <= a3700_spi->instr_cnt) {
-			instr_cnt = a3700_spi->buf_len;
-		} else if (a3700_spi->buf_len <= (a3700_spi->instr_cnt +
-						  a3700_spi->addr_cnt)) {
-			instr_cnt = a3700_spi->instr_cnt;
-			addr_cnt = a3700_spi->buf_len - instr_cnt;
-		} else if (a3700_spi->buf_len <= a3700_spi->hdr_cnt) {
-			instr_cnt = a3700_spi->instr_cnt;
-			addr_cnt = a3700_spi->addr_cnt;
-			/* Need to handle the normal write case with 1 byte
-			 * data
-			 */
-			if (!a3700_spi->tx_buf[instr_cnt + addr_cnt])
-				dummy_cnt = a3700_spi->buf_len - instr_cnt -
-					    addr_cnt;
+		/*
+		 * when tx data is not 4 bytes aligned, there will be unexpected
+		 * bytes out of SPI output register, since it always shifts out
+		 * as whole 4 bytes. This might cause incorrect transaction with
+		 * some devices. To avoid that, use SPI header count feature to
+		 * transfer up to 3 bytes of data first, and then make the rest
+		 * of data 4-byte aligned.
+		 */
+		addr_cnt = a3700_spi->buf_len % 4;
+		if (addr_cnt) {
+			val = (addr_cnt & A3700_SPI_ADDR_CNT_MASK)
+				<< A3700_SPI_ADDR_CNT_BIT;
+			spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
+
+			/* Update the buffer length to be transferred */
+			a3700_spi->buf_len -= addr_cnt;
+
+			/* transfer 1~3 bytes through address count */
+			val = 0;
+			while (addr_cnt--) {
+				val = (val << 8) | a3700_spi->tx_buf[0];
+				a3700_spi->tx_buf++;
+			}
+			spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
 		}
-		val |= ((instr_cnt & A3700_SPI_INSTR_CNT_MASK)
-			<< A3700_SPI_INSTR_CNT_BIT);
-		val |= ((addr_cnt & A3700_SPI_ADDR_CNT_MASK)
-			<< A3700_SPI_ADDR_CNT_BIT);
-		val |= ((dummy_cnt & A3700_SPI_DUMMY_CNT_MASK)
-			<< A3700_SPI_DUMMY_CNT_BIT);
 	}
-	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
-
-	/* Update the buffer length to be transferred */
-	a3700_spi->buf_len -= (instr_cnt + addr_cnt + dummy_cnt);
-
-	/* Set Instruction */
-	val = 0;
-	while (instr_cnt--) {
-		val = (val << 8) | a3700_spi->tx_buf[0];
-		a3700_spi->tx_buf++;
-	}
-	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, val);
-
-	/* Set Address */
-	val = 0;
-	while (addr_cnt--) {
-		val = (val << 8) | a3700_spi->tx_buf[0];
-		a3700_spi->tx_buf++;
-	}
-	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
 }
 
 static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)
@@ -515,35 +491,12 @@ static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)
 static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
 {
 	u32 val;
-	int i = 0;
 
 	while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
-		val = 0;
-		if (a3700_spi->buf_len >= 4) {
-			val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
-			spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
-
-			a3700_spi->buf_len -= 4;
-			a3700_spi->tx_buf += 4;
-		} else {
-			/*
-			 * If the remained buffer length is less than 4-bytes,
-			 * we should pad the write buffer with all ones. So that
-			 * it avoids overwrite the unexpected bytes following
-			 * the last one.
-			 */
-			val = GENMASK(31, 0);
-			while (a3700_spi->buf_len) {
-				val &= ~(0xff << (8 * i));
-				val |= *a3700_spi->tx_buf++ << (8 * i);
-				i++;
-				a3700_spi->buf_len--;
-
-				spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG,
-					     val);
-			}
-			break;
-		}
+		val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
+		spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
+		a3700_spi->buf_len -= 4;
+		a3700_spi->tx_buf += 4;
 	}
 
 	return 0;
@@ -648,9 +601,6 @@ static int a3700_spi_transfer_one(struct spi_master *master,
 	a3700_spi->rx_buf  = xfer->rx_buf;
 	a3700_spi->buf_len = xfer->len;
 
-	/* SPI transfer headers */
-	a3700_spi_header_set(a3700_spi);
-
 	if (xfer->tx_buf)
 		nbits = xfer->tx_nbits;
 	else if (xfer->rx_buf)
@@ -658,6 +608,12 @@ static int a3700_spi_transfer_one(struct spi_master *master,
 
 	a3700_spi_pin_mode_set(a3700_spi, nbits, xfer->rx_buf ? true : false);
 
+	/* Flush the FIFOs */
+	a3700_spi_fifo_flush(a3700_spi);
+
+	/* Transfer first bytes of data when buffer is not 4-byte aligned */
+	a3700_spi_header_set(a3700_spi);
+
 	if (xfer->rx_buf) {
 		/* Set read data length */
 		spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG,
@@ -736,16 +692,11 @@ static int a3700_spi_transfer_one(struct spi_master *master,
 				dev_err(&spi->dev, "wait wfifo empty timed out\n");
 				return -ETIMEDOUT;
 			}
-		} else {
-			/*
-			 * If the instruction in SPI_INSTR does not require data
-			 * to be written to the SPI device, wait until SPI_RDY
-			 * is 1 for the SPI interface to be in idle.
-			 */
-			if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) {
-				dev_err(&spi->dev, "wait xfer ready timed out\n");
-				return -ETIMEDOUT;
-			}
+		}
+
+		if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) {
+			dev_err(&spi->dev, "wait xfer ready timed out\n");
+			return -ETIMEDOUT;
 		}
 
 		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
@@ -837,10 +788,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
 	memset(spi, 0, sizeof(struct a3700_spi));
 
 	spi->master = master;
-	spi->instr_cnt = A3700_INSTR_CNT;
-	spi->addr_cnt = A3700_ADDR_CNT;
-	spi->hdr_cnt = A3700_INSTR_CNT + A3700_ADDR_CNT +
-		       A3700_DUMMY_CNT;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	spi->base = devm_ioremap_resource(dev, res);
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver
       [not found] ` <20170913162139.17598-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2017-09-13 16:21   ` [PATCH v2 1/2] spi: armada-3700: Fix failing commands with quad-SPI Miquel Raynal
  2017-09-13 16:21   ` [PATCH v2 2/2] spi: armada-3700: Fix padding when sending not 4-byte aligned data Miquel Raynal
@ 2017-09-13 17:20   ` Gregory CLEMENT
       [not found]     ` <87o9qeh5w9.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
  2 siblings, 1 reply; 5+ messages in thread
From: Gregory CLEMENT @ 2017-09-13 17:20 UTC (permalink / raw)
  To: Mark Brown, Miquel Raynal
  Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, Thomas Petazzoni,
	Antoine Tenart, Nadav Haklai

Hi Miquel and Mark,
 
 On mer., sept. 13 2017, Miquel Raynal <miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hello,
>
> This short serie addresses two issues in Armada-3700 SPI controller driver.
>
> Second patch from Zachary Zhang fixes the way padding is introduced in not
> 4-byte aligned SPI transfers (that fails some NAND flash devices). It also
> revealed the issue fixed by the first commit when using quad-SPI. Thus, it
> would be preferable to apply them in that order.
>
> Differences with the first version:
> - Added this cover letter.
> - Fixed the commit titles by using "spi: armada-3700:" prefix.
>
> And sorry for the noise.

These two patches being fixes it would be nice to add the Fixes and
Cc: <stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org> flags. Indeed the older version on Linux
should be fixed too.

Miquel could you provide the accurate Fixes: flag ?
(By the way there is also a way to indicate dependency between patches
for stable, see Documentation/process/stable-kernel-rules.rst.)

Mark, could you amend the patches with the flags that will be provided
my Miquel? Thanks, to this the patches will be backported to te stables
branches.

Thanks!

Gregory

>
> Thanks,
> Miquel
>
> Miquel Raynal (1):
>   spi: armada-3700: Fix failing commands with quad-SPI
>
> Zachary Zhang (1):
>   spi: armada-3700: Fix padding when sending not 4-byte aligned data
>
>  drivers/spi/spi-armada-3700.c | 142 ++++++++++++++----------------------------
>  1 file changed, 46 insertions(+), 96 deletions(-)
>
> -- 
> 2.11.0
>

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver
       [not found]     ` <87o9qeh5w9.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2017-09-13 18:12       ` Mark Brown
  0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2017-09-13 18:12 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Miquel Raynal, linux-spi-u79uwXL29TY76Z2rM5mHXA, Thomas Petazzoni,
	Antoine Tenart, Nadav Haklai

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

On Wed, Sep 13, 2017 at 10:20:38AM -0700, Gregory CLEMENT wrote:

> Mark, could you amend the patches with the flags that will be provided
> my Miquel? Thanks, to this the patches will be backported to te stables
> branches.

No, I've applied them already.  The second patch looked too big to be
stable material.

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

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

end of thread, other threads:[~2017-09-13 18:12 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-13 16:21 [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver Miquel Raynal
     [not found] ` <20170913162139.17598-1-miquel.raynal-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-09-13 16:21   ` [PATCH v2 1/2] spi: armada-3700: Fix failing commands with quad-SPI Miquel Raynal
2017-09-13 16:21   ` [PATCH v2 2/2] spi: armada-3700: Fix padding when sending not 4-byte aligned data Miquel Raynal
2017-09-13 17:20   ` [PATCH v2 0/2] Fix issues in Armada-3700 SPI controller driver Gregory CLEMENT
     [not found]     ` <87o9qeh5w9.fsf-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2017-09-13 18:12       ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox