[U-Boot,6/6] spi: fsl_qspi: Fix flash write issue with small TX FIFO
diff mbox series

Message ID 1565777311-1752-6-git-send-email-ye.li@nxp.com
State New
Delegated to: Stefano Babic
Headers show
Series
  • [U-Boot,1/6] spi: fsl_qspi: Fix DDR mode setting for latest iMX platforms
Related show

Commit Message

Ye Li Aug. 14, 2019, 10:09 a.m. UTC
The page write sequence in spi-mem is changed with orignal spi-flash.
When the max_write_size is set by driver, the orignal sequence is
1. WREN
2. write max_write_size data to flash
3. wait for WIP clean
4. back to #1 if having data remained in a page.

The new sequence is:
1. WREN
2. write (max_write_size - command length) data to flash
3. back to #2 if having data remained in a page
4. wait for WIP clean

If TX FIFO (max_write_size) is small (for example iMX7ULP only has
64 bytes TX FIFO, while other iMX SOCs have 512 bytes),  the driver has
to check the WIP in step 3. Otherwise the WIP may set due to previous
write is not completed by flash device, then cause current write failed.

Signed-off-by: Ye Li <ye.li@nxp.com>
---
 drivers/spi/fsl_qspi.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Patch
diff mbox series

diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index f3cf8e6..450155e 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -22,6 +22,7 @@  DECLARE_GLOBAL_DATA_PTR;
 #define OFFSET_BITS_MASK	GENMASK(23, 0)
 
 #define FLASH_STATUS_WEL	0x02
+#define FLASH_STATUS_WIP	0x01
 
 /* SEQID */
 #define SEQID_WREN		1
@@ -666,6 +667,27 @@  static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len)
 		     mcr_reg);
 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
 
+	if (priv->devtype_data->txfifo <= 256) {
+		status_reg = 0;
+		do {
+			WATCHDOG_RESET();
+
+			qspi_write32(priv->flags, &regs->ipcr,
+				     (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
+			while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
+				;
+
+			reg = qspi_read32(priv->flags, &regs->rbsr);
+			if (reg & QSPI_RBSR_RDBFL_MASK) {
+				status_reg = qspi_read32(priv->flags, &regs->rbdr[0]);
+				status_reg = qspi_endian_xchg(priv, status_reg);
+			}
+			qspi_write32(priv->flags, &regs->mcr,
+				     qspi_read32(priv->flags, &regs->mcr) |
+				     QSPI_MCR_CLR_RXF_MASK);
+		} while ((status_reg & FLASH_STATUS_WIP) == FLASH_STATUS_WIP);
+	}
+
 	status_reg = 0;
 	while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
 		WATCHDOG_RESET();