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