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 <b21...@freescale.com>
Cc: Mike Frysinger <vap...@gentoo.org>
---
changes for v2:
fix some compile warnings.
remove ifdef and use if else instead.

changes for v3:
rebased on first patch.

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

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 55b29cc..5ed6a59 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)
 {
@@ -71,6 +73,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned 
int cs,
        slave->bus = bus;
        slave->cs = cs;
        slave->slave_data.mode = mode;
+       slave->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN;
 
        /* Set eSPI BRG clock source */
        get_sys_info(&sysinfo);
@@ -174,6 +177,9 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, 
const void *data_out,
        u8 *cmd_buf = slave->slave_data.cmd_buf;
        size_t cmd_len = slave->slave_data.cmd_len;
 
+       if (slave->max_transfer_length > ESPI_MAX_DATA_TRANSFER_LEN)
+               return -1;
+
        switch (flags) {
        case SPI_XFER_BEGIN:
                cmd_len = slave->slave_data.cmd_len = bitlen / 8;
diff --git a/include/spi.h b/include/spi.h
index 213f6e6..c2c0d36 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -70,11 +70,13 @@ struct spi_slave_data {
  *   bus:      ID of the bus that the slave is attached to.
  *   cs:       ID of the chip select connected to the slave.
  *   slave_data: slave data for hardware and transfer.
+ *   max_transfer_length: maximum data transfer length supported by the slave.
  */
 struct spi_slave {
        unsigned int    bus;
        unsigned int    cs;
        struct spi_slave_data slave_data;
+       unsigned int    max_transfer_length;
 };
 
 /*-----------------------------------------------------------------------
-- 
1.6.4


_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to