diff mbox

[U-Boot,2/2,v2] powerpc: make espi can read more than 0xFFFA bytes

Message ID 1303365951-27301-1-git-send-email-b21989@freescale.com
State Superseded
Headers show

Commit Message

shaohui xie April 21, 2011, 6:05 a.m. UTC
espi flash read returns invalid data if the read length is more than 0xFFFA
bytes, it supports maximum transaction of 2^16 bytes at a time, resister
spcom[TRANLEN] is 16 bits. If the transaction length is greater than  0xFFFF,
it need to be split into multiple transactions.

Signed-off-by: Shaohui Xie <b21989@freescale.com>
Cc: Mike Frysinger <vapier@gentoo.org>
---
changes for v2:
fix some compile warnings.
remove ifdef and use if else instead.

 drivers/mtd/spi/spi_flash.c |   39 +++++++++++++++++++++++++++++++++++----
 drivers/spi/fsl_espi.c      |    6 ++++++
 include/spi.h               |    2 ++
 3 files changed, 43 insertions(+), 4 deletions(-)

Comments

Mike Frysinger April 21, 2011, 5:16 p.m. UTC | #1
On Thu, Apr 21, 2011 at 2:05 AM, Shaohui Xie wrote:
> espi flash read returns invalid data if the read length is more than 0xFFFA
> bytes, it supports maximum transaction of 2^16 bytes at a time, resister
> spcom[TRANLEN] is 16 bits. If the transaction length is greater than  0xFFFF,
> it need to be split into multiple transactions.

hrm, so how does this work under Linux ?  or does it just not ?
-mike
shaohui xie April 22, 2011, 9:23 a.m. UTC | #2
>From: vapierfilter@gmail.com [mailto:vapierfilter@gmail.com] On Behalf Of
>Mike Frysinger
>Sent: Friday, April 22, 2011 1:17 AM
>To: Xie Shaohui-B21989
>Cc: u-boot@lists.denx.de; Gala Kumar-B11780; Zang Roy-R61911
>Subject: Re: [PATCH 2/2][v2] powerpc: make espi can read more than 0xFFFA
>bytes
>
>On Thu, Apr 21, 2011 at 2:05 AM, Shaohui Xie wrote:
>> espi flash read returns invalid data if the read length is more than
>> 0xFFFA bytes, it supports maximum transaction of 2^16 bytes at a time,
>> resister spcom[TRANLEN] is 16 bits. If the transaction length is
>> greater than  0xFFFF, it need to be split into multiple transactions.
>
>hrm, so how does this work under Linux ?  or does it just not ?

[Xie Shaohui] This does work under Linux, being solved in similar way.

 
Best Regards, 
Shaohui Xie
Mike Frysinger April 30, 2011, 4:38 a.m. UTC | #3
On Friday, April 22, 2011 05:23:59 Xie Shaohui-B21989 wrote:
> From: Mike Frysinger
> >On Thu, Apr 21, 2011 at 2:05 AM, Shaohui Xie wrote:
> >> espi flash read returns invalid data if the read length is more than
> >> 0xFFFA bytes, it supports maximum transaction of 2^16 bytes at a time,
> >> resister spcom[TRANLEN] is 16 bits. If the transaction length is
> >> greater than  0xFFFF, it need to be split into multiple transactions.
> >
> >hrm, so how does this work under Linux ?  or does it just not ?
> 
> [Xie Shaohui] This does work under Linux, being solved in similar way.

so it doesnt work under Linux atm, but you're trying to get similar changes 
made to the Linux code upstream ?
-mike
diff mbox

Patch

diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index c75b716..f90ef25 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -1,6 +1,7 @@ 
 /*
  * SPI flash interface
  *
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Atmel Corporation
  * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
  *
@@ -82,11 +83,41 @@  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
 {
 	u8 cmd[5];
 
-	cmd[0] = CMD_READ_ARRAY_FAST;
-	spi_flash_addr(offset, cmd);
-	cmd[4] = 0x00;
+	if (len <= flash->spi->max_transfer_length) {
+		cmd[0] = CMD_READ_ARRAY_FAST;
+		spi_flash_addr(offset, cmd);
+		cmd[4] = 0x00;
+
+		return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
+	} else {
+		int max_tran_len, num_chunks, tran_len, ret = 0;
+
+		max_tran_len = flash->spi->max_transfer_length;
+		num_chunks = len / max_tran_len + (len % max_tran_len ? 1 : 0);
+
+		while (num_chunks--) {
+			tran_len = min(len , max_tran_len);
+
+			cmd[0] = CMD_READ_ARRAY_FAST;
+			spi_flash_addr(offset, cmd);
+			cmd[4] = 0x00;
+
+			debug("READ: 0x%x => cmd = "
+			"{ 0x%02x 0x%02x%02x%02x%02x } tran_len = 0x%x\n",
+			offset, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], tran_len);
 
-	return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
+			ret = spi_flash_read_common(
+				flash, cmd, sizeof(cmd), data, tran_len);
+			if (ret < 0)
+				return ret;
+
+			offset += max_tran_len;
+			data += max_tran_len;
+			len -= max_tran_len;
+		}
+
+		return ret;
+	}
 }
 
 int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c
index 9b8ae9a..7630fb3 100644
--- a/drivers/spi/fsl_espi.c
+++ b/drivers/spi/fsl_espi.c
@@ -53,6 +53,8 @@ 
 		ESPI_CSMODE_CSBEF(0) | ESPI_CSMODE_CSAFT(0) | \
 		ESPI_CSMODE_CSCG(1))
 
+#define ESPI_MAX_DATA_TRANSFER_LEN 0xFFF0
+
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 		unsigned int max_hz, unsigned int mode)
 {
@@ -72,6 +74,7 @@  struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 
 	slave->bus = bus;
 	slave->cs = cs;
+	slave->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN;
 
 	/* Enable eSPI interface */
 	out_be32(&espi->mode, ESPI_MODE_RXTHR(3)
@@ -165,6 +168,9 @@  int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
 	unsigned char *buffer;
 	size_t buf_len;
 
+	if (slave->max_transfer_length > ESPI_MAX_DATA_TRANSFER_LEN)
+		return -1;
+
 	switch (flags) {
 	case SPI_XFER_BEGIN:
 		cmd_len = bitlen / 8;
diff --git a/include/spi.h b/include/spi.h
index c5da3ca..866b920 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -58,10 +58,12 @@ 
  *
  *   bus:	ID of the bus that the slave is attached to.
  *   cs:	ID of the chip select connected to the slave.
+ *   max_transfer_length: maximum data transfer length supported by the slave.
  */
 struct spi_slave {
 	unsigned int	bus;
 	unsigned int	cs;
+	unsigned int    max_transfer_length;
 };
 
 /*-----------------------------------------------------------------------