MLK-17656: mtd: qspi: support read the flag status in fspi driver
authorHan Xu <han.xu@nxp.com>
Thu, 14 Dec 2017 22:33:51 +0000 (16:33 -0600)
committerHan Xu <han.xu@nxp.com>
Fri, 2 Mar 2018 21:20:04 +0000 (15:20 -0600)
support to read the flag status in driver to avoid the spi-nor framework
wait_for_ready hang issue.

Signed-off-by: Han Xu <han.xu@nxp.com>
drivers/spi/fsl_qspi.c

index 6e511bc..7dad4ec 100644 (file)
@@ -47,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #endif
 #define SEQID_WRAR             13
 #define SEQID_RDAR             14
+#define SEQID_RDFSR            15
 
 /* QSPI CMD */
 #define QSPI_CMD_PP            0x02    /* Page program (up to 256 bytes) */
@@ -57,6 +58,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define QSPI_CMD_CHIP_ERASE    0xc7    /* Erase whole flash chip */
 #define QSPI_CMD_SE            0xd8    /* Sector erase (usually 64KiB) */
 #define QSPI_CMD_RDID          0x9f    /* Read JEDEC ID */
+#define QSPI_CMD_FLAG_SR       0x70    /* Read FLAG STATUS*/
 
 /* Used for Micron, winbond and Macronix flashes */
 #define        QSPI_CMD_WREAR          0xc5    /* EAR register write */
@@ -219,6 +221,15 @@ static void qspi_set_lut(struct fsl_qspi_priv *priv)
        qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
        qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
 
+       /* Read Flag Status */
+       lut_base = SEQID_RDFSR * 4;
+       qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_FLAG_SR) |
+               PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
+               PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+       qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+       qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+       qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+
        /* Erase a sector */
        lut_base = SEQID_SE * 4;
 #ifdef CONFIG_SPI_FLASH_BAR
@@ -742,6 +753,40 @@ static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len)
        qspi_write32(priv->flags, &regs->mcr, mcr_reg);
 }
 
+static void qspi_op_rdfsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len)
+{
+       struct fsl_qspi_regs *regs = priv->regs;
+       u32 mcr_reg, reg, data;
+
+       mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+       qspi_write32(priv->flags, &regs->mcr,
+                    QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+                    mcr_reg);
+       qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+       qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
+
+       qspi_write32(priv->flags, &regs->ipcr,
+                    (SEQID_RDFSR << QSPI_IPCR_SEQID_SHIFT) | 0);
+       while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
+               ;
+
+       while (1) {
+               reg = qspi_read32(priv->flags, &regs->rbsr);
+               if (reg & QSPI_RBSR_RDBFL_MASK) {
+                       data = qspi_read32(priv->flags, &regs->rbdr[0]);
+                       data = qspi_endian_xchg(data);
+                       memcpy(rxbuf, &data, len);
+                       qspi_write32(priv->flags, &regs->mcr,
+                                    qspi_read32(priv->flags, &regs->mcr) |
+                                    QSPI_MCR_CLR_RXF_MASK);
+                       break;
+               }
+       }
+
+       qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+}
+
 static void qspi_op_erase(struct fsl_qspi_priv *priv)
 {
        struct fsl_qspi_regs *regs = priv->regs;
@@ -825,6 +870,8 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
                        qspi_op_rdid(priv, din, bytes);
                else if (priv->cur_seqid == QSPI_CMD_RDSR)
                        qspi_op_rdsr(priv, din, bytes);
+               else if (priv->cur_seqid == QSPI_CMD_FLAG_SR)
+                       qspi_op_rdfsr(priv, din, bytes);
 #ifdef CONFIG_SPI_FLASH_BAR
                else if ((priv->cur_seqid == QSPI_CMD_BRRD) ||
                         (priv->cur_seqid == QSPI_CMD_RDEAR)) {