[U-Boot] [PATCH v2] spi: omap3: Fix timeout handling

The timeout value is never reset during the transfer. This means that when transferring more data we eventually trigger the timeout.
This was reported on the mailing list: "Spansion SPI flash read timeout with AM335x"
Signed-off-by: David Dueck davidcdueck@googlemail.com CC: Tom Rini trini@konsulko.com CC: Jagannadh Teki jagannadh.teki@gmail.com CC: Stefan Roese sr@denx.de CC: Andy Pont andy.pont@sdcsystems.com --- Changes since v1: - fix style issue - fix CC line
drivers/spi/omap3_spi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 651e46e..85f9e85 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include "omap3_spi.h"
-#define SPI_WAIT_TIMEOUT 3000000 +#define SPI_WAIT_TIMEOUT 10
static void spi_reset(struct omap3_spi_slave *ds) { @@ -227,7 +227,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, { struct omap3_spi_slave *ds = to_omap3_spi(slave); int i; - int timeout = SPI_WAIT_TIMEOUT; + ulong start; int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
/* Enable the channel */ @@ -241,9 +241,10 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
for (i = 0; i < len; i++) { /* wait till TX register is empty (TXS == 1) */ + start = get_timer(0); while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_TXS)) { - if (--timeout <= 0) { + if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI TXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1; @@ -280,7 +281,7 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, { struct omap3_spi_slave *ds = to_omap3_spi(slave); int i; - int timeout = SPI_WAIT_TIMEOUT; + ulong start; int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
/* Enable the channel */ @@ -295,10 +296,11 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, writel(0, &ds->regs->channel[ds->slave.cs].tx);
for (i = 0; i < len; i++) { + start = get_timer(0); /* Wait till RX register contains data (RXS == 1) */ while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_RXS)) { - if (--timeout <= 0) { + if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI RXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1; @@ -332,7 +334,7 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); - int timeout = SPI_WAIT_TIMEOUT; + ulong start; int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); int irqstatus = readl(&ds->regs->irqstatus); int i=0; @@ -350,9 +352,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, for (i=0; i < len; i++){ /* Write: wait for TX empty (TXS == 1)*/ irqstatus |= (1<< (4*(ds->slave.bus))); + start = get_timer(0); while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_TXS)) { - if (--timeout <= 0) { + if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI TXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1; @@ -368,9 +371,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, writel(((u8 *)txp)[i], tx);
/*Read: wait for RX containing data (RXS == 1)*/ + start = get_timer(0); while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_RXS)) { - if (--timeout <= 0) { + if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI RXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1;

On 1 April 2015 at 17:50, David Dueck davidcdueck@googlemail.com wrote:
The timeout value is never reset during the transfer. This means that when transferring more data we eventually trigger the timeout.
This was reported on the mailing list: "Spansion SPI flash read timeout with AM335x"
Signed-off-by: David Dueck davidcdueck@googlemail.com CC: Tom Rini trini@konsulko.com CC: Jagannadh Teki jagannadh.teki@gmail.com CC: Stefan Roese sr@denx.de CC: Andy Pont andy.pont@sdcsystems.com
Changes since v1:
- fix style issue
- fix CC line
drivers/spi/omap3_spi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
Any Tested-by?
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 651e46e..85f9e85 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include "omap3_spi.h"
-#define SPI_WAIT_TIMEOUT 3000000 +#define SPI_WAIT_TIMEOUT 10
static void spi_reset(struct omap3_spi_slave *ds) { @@ -227,7 +227,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, { struct omap3_spi_slave *ds = to_omap3_spi(slave); int i;
int timeout = SPI_WAIT_TIMEOUT;
ulong start; int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); /* Enable the channel */
@@ -241,9 +241,10 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
for (i = 0; i < len; i++) { /* wait till TX register is empty (TXS == 1) */
start = get_timer(0); while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_TXS)) {
if (--timeout <= 0) {
if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI TXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1;
@@ -280,7 +281,7 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, { struct omap3_spi_slave *ds = to_omap3_spi(slave); int i;
int timeout = SPI_WAIT_TIMEOUT;
ulong start; int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); /* Enable the channel */
@@ -295,10 +296,11 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, writel(0, &ds->regs->channel[ds->slave.cs].tx);
for (i = 0; i < len; i++) {
start = get_timer(0); /* Wait till RX register contains data (RXS == 1) */ while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_RXS)) {
if (--timeout <= 0) {
if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI RXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1;
@@ -332,7 +334,7 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave);
int timeout = SPI_WAIT_TIMEOUT;
ulong start; int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); int irqstatus = readl(&ds->regs->irqstatus); int i=0;
@@ -350,9 +352,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, for (i=0; i < len; i++){ /* Write: wait for TX empty (TXS == 1)*/ irqstatus |= (1<< (4*(ds->slave.bus)));
start = get_timer(0); while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_TXS)) {
if (--timeout <= 0) {
if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI TXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1;
@@ -368,9 +371,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, writel(((u8 *)txp)[i], tx);
/*Read: wait for RX containing data (RXS == 1)*/
start = get_timer(0); while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_RXS)) {
if (--timeout <= 0) {
if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI RXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds->slave.cs].chstat)); return -1;
-- 2.3.4

Hi David,
<snipped for brevity>
for (i = 0; i < len; i++) { /* wait till TX register is empty (TXS == 1) */
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & OMAP3_MCSPI_CHSTAT_TXS)) {start = get_timer(0);
if (--timeout <= 0) {
if (get_timer(start) > SPI_WAIT_TIMEOUT) { printf("SPI TXS timed out, status=0x%08x\n", readl(&ds->regs->channel[ds-
slave.cs].chstat));
return -1;
I have a couple of questions...
Firstly, when in SPL is there access to the get_timer() function?
Secondly, when using Falcon mode to load Linux directly from SPI (Falcon mode) then we want to maximise the throughput and save every CPU cycle we possibly can. Adding yet another function call into the for loop and hence calling it a couple of million times seems, on the face of it, like it is going to slow things down.
Regards,
Andy.
participants (3)
-
Andy Pont
-
David Dueck
-
Jagan Teki