summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorHan Xu <han.xu@nxp.com>2017-12-14 16:33:51 -0600
committerYe Li <ye.li@nxp.com>2018-04-27 02:21:27 -0700
commit55e83ccb588c3e953f55148161bc524b5dab7a25 (patch)
tree485de5e29f63135b553f502ebec751181c1eb011 /drivers/spi
parent1c84e2e3ceeb0c7dce3d5a8b139e7ef6d56725bf (diff)
MLK-17656: mtd: qspi: support read the flag status in fspi driver
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> (cherry picked from commit 767faa948d2d140b6d56ee505f81f8f57c045a3d)
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/fsl_qspi.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 12561f1409..662cd1ae05 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -48,6 +48,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) */
@@ -58,6 +59,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 */
@@ -220,6 +222,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
@@ -739,6 +750,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;
@@ -824,6 +869,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)) {