drivers: spi: consider command bytes when sending transfers
[oweals/u-boot.git] / drivers / mtd / spi / spi_flash.c
index 34f68881ed78231decd515a3bb3a5ae463fd0159..294d9f9d79c6eb123dec396bd56fac801d8da860 100644 (file)
@@ -113,6 +113,27 @@ static int write_cr(struct spi_flash *flash, u8 wc)
 #endif
 
 #ifdef CONFIG_SPI_FLASH_BAR
+/*
+ * This "clean_bar" is necessary in a situation when one was accessing
+ * spi flash memory > 16 MiB by using Bank Address Register's BA24 bit.
+ *
+ * After it the BA24 bit shall be cleared to allow access to correct
+ * memory region after SW reset (by calling "reset" command).
+ *
+ * Otherwise, the BA24 bit may be left set and then after reset, the
+ * ROM would read/write/erase SPL from 16 MiB * bank_sel address.
+ */
+static int clean_bar(struct spi_flash *flash)
+{
+       u8 cmd, bank_sel = 0;
+
+       if (flash->bank_curr == 0)
+               return 0;
+       cmd = flash->bank_write_cmd;
+
+       return spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
+}
+
 static int write_bar(struct spi_flash *flash, u32 offset)
 {
        u8 cmd, bank_sel;
@@ -339,6 +360,10 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
                len -= erase_size;
        }
 
+#ifdef CONFIG_SPI_FLASH_BAR
+       ret = clean_bar(flash);
+#endif
+
        return ret;
 }
 
@@ -380,7 +405,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 
                if (spi->max_write_size)
                        chunk_len = min(chunk_len,
-                                       (size_t)spi->max_write_size);
+                                       spi->max_write_size - sizeof(cmd));
 
                spi_flash_addr(write_addr, cmd);
 
@@ -397,6 +422,10 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
                offset += chunk_len;
        }
 
+#ifdef CONFIG_SPI_FLASH_BAR
+       ret = clean_bar(flash);
+#endif
+
        return ret;
 }
 
@@ -487,6 +516,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
                else
                        read_len = remain_len;
 
+               if (spi->max_read_size)
+                       read_len = min(read_len, spi->max_read_size);
+
                spi_flash_addr(read_addr, cmd);
 
                ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
@@ -500,6 +532,10 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
                data += read_len;
        }
 
+#ifdef CONFIG_SPI_FLASH_BAR
+       ret = clean_bar(flash);
+#endif
+
        free(cmd);
        return ret;
 }