ar71xx: allow to specify max read size for m25p80
authorGabor Juhos <juhosg@openwrt.org>
Sat, 7 Jan 2012 19:36:33 +0000 (19:36 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Sat, 7 Jan 2012 19:36:33 +0000 (19:36 +0000)
Reading from the flash chip on the TL-WR2543ND seems buggy.
If the SPI flash driver tries to read too much data in one
SPI transfer, the flash chip returns bogus values. This can
be caused by a buggy flash chip on my board, or it can
be a bug in our SPI driver.

Add a workaround to the m25p80 driver until I find out the
root cause of the problem. The patch allows to specify the
maximum numner of bytes which can be read safely withint
one SPI transfer.

SVN-Revision: 29679

target/linux/ar71xx/patches-2.6.39/113-mtd-m25p80-allow-to-specify-max-read-size.patch [new file with mode: 0644]

diff --git a/target/linux/ar71xx/patches-2.6.39/113-mtd-m25p80-allow-to-specify-max-read-size.patch b/target/linux/ar71xx/patches-2.6.39/113-mtd-m25p80-allow-to-specify-max-read-size.patch
new file mode 100644 (file)
index 0000000..8bb69df
--- /dev/null
@@ -0,0 +1,112 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -94,6 +94,7 @@ struct m25p {
+       u16                     addr_width;
+       u8                      erase_opcode;
+       u8                      *command;
++      size_t                  max_read_len;
+ };
+ static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
+@@ -341,6 +342,7 @@ static int m25p80_read(struct mtd_info *
+       struct m25p *flash = mtd_to_m25p(mtd);
+       struct spi_transfer t[2];
+       struct spi_message m;
++      loff_t ofs;
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+                       dev_name(&flash->spi->dev), __func__, "from",
+@@ -364,8 +366,6 @@ static int m25p80_read(struct mtd_info *
+       t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
+       spi_message_add_tail(&t[0], &m);
+-      t[1].rx_buf = buf;
+-      t[1].len = len;
+       spi_message_add_tail(&t[1], &m);
+       /* Byte count starts at zero. */
+@@ -373,13 +373,6 @@ static int m25p80_read(struct mtd_info *
+       mutex_lock(&flash->lock);
+-      /* Wait till previous write/erase is done. */
+-      if (wait_till_ready(flash)) {
+-              /* REVISIT status return?? */
+-              mutex_unlock(&flash->lock);
+-              return 1;
+-      }
+-
+       /* FIXME switch to OPCODE_FAST_READ.  It's required for higher
+        * clocks; and at this writing, every chip this driver handles
+        * supports that opcode.
+@@ -387,11 +380,44 @@ static int m25p80_read(struct mtd_info *
+       /* Set up the write data buffer. */
+       flash->command[0] = OPCODE_READ;
+-      m25p_addr2cmd(flash, from, flash->command);
+-      spi_sync(flash->spi, &m);
++      ofs = 0;
++      while (len) {
++              size_t readlen;
++              size_t done;
++              int ret;
++
++              ret = wait_till_ready(flash);
++              if (ret) {
++                      mutex_unlock(&flash->lock);
++                      return 1;
++              }
++
++              if (flash->max_read_len > 0 &&
++                  flash->max_read_len < len)
++                      readlen = flash->max_read_len;
++              else
++                      readlen = len;
++
++              t[1].rx_buf = buf + ofs;
++              t[1].len = readlen;
++
++              m25p_addr2cmd(flash, from + ofs, flash->command);
++
++              spi_sync(flash->spi, &m);
+-      *retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
++              done = m.actual_length - m25p_cmdsz(flash) -
++                     FAST_READ_DUMMY_BYTE;
++              if (done != readlen) {
++                      mutex_unlock(&flash->lock);
++                      return 1;
++              }
++
++              ofs += done;
++              len -= done;
++      }
++
++      *retlen = ofs;
+       mutex_unlock(&flash->lock);
+@@ -901,6 +927,12 @@ static int __devinit m25p_probe(struct s
+       flash->mtd.erase = m25p80_erase;
+       flash->mtd.read = m25p80_read;
++      if (data && data->max_read_len) {
++              flash->max_read_len = data->max_read_len;
++              dev_warn(&spi->dev, "max_read_len set to %d bytes\n",
++                      flash->max_read_len);
++      }
++
+       /* sst flash chips use AAI word program */
+       if (info->jedec_id >> 16 == 0xbf)
+               flash->mtd.write = sst_write;
+--- a/include/linux/spi/flash.h
++++ b/include/linux/spi/flash.h
+@@ -26,6 +26,7 @@ struct flash_platform_data {
+       char            *type;
+       const char      **part_probes;
++      size_t          max_read_len;
+       /* we'll likely add more ... use JEDEC IDs, etc */
+ };