From febffe8dd1c7ba841890eec578b050bb6faa3273 Mon Sep 17 00:00:00 2001 From: Yuan Yao Date: Tue, 15 Mar 2016 14:36:42 +0800 Subject: [PATCH] spi: fsl_qspi: Enable Spansion S25FS-S family flashes The flash type of LS2085AQDS QSPI is S25FS256S. It has special write any device register command and read any device register command. This patch enable support for those commands. Signed-off-by: Yuan Yao Signed-off-by: Prabhakar Kushwaha Reviewed-by: York Sun --- drivers/mtd/spi/sf_internal.h | 5 +++ drivers/spi/fsl_qspi.c | 58 +++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 007a5a085c..da2bb7b5d2 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -127,6 +127,11 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len, const void *buf); #endif +#ifdef CONFIG_SPI_FLASH_SPANSION +/* Used for Spansion S25FS-S family flash only. */ +#define CMD_SPANSION_RDAR 0x65 /* Read any device register */ +#define CMD_SPANSION_WRAR 0x71 /* Write any device register */ +#endif /** * struct spi_flash_params - SPI/QSPI flash device params structure * diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index db7ebee972..75cbab2676 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -44,6 +44,8 @@ DECLARE_GLOBAL_DATA_PTR; #define SEQID_RDEAR 11 #define SEQID_WREAR 12 #endif +#define SEQID_WRAR 13 +#define SEQID_RDAR 14 /* QSPI CMD */ #define QSPI_CMD_PP 0x02 /* Page program (up to 256 bytes) */ @@ -63,6 +65,10 @@ DECLARE_GLOBAL_DATA_PTR; #define QSPI_CMD_BRRD 0x16 /* Bank register read */ #define QSPI_CMD_BRWR 0x17 /* Bank register write */ +/* Used for Spansion S25FS-S family flash only. */ +#define QSPI_CMD_RDAR 0x65 /* Read any device register */ +#define QSPI_CMD_WRAR 0x71 /* Write any device register */ + /* 4-byte address QSPI CMD - used on Spansion and some Macronix flashes */ #define QSPI_CMD_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ #define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */ @@ -317,6 +323,33 @@ static void qspi_set_lut(struct fsl_qspi_priv *priv) PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | PAD1(LUT_PAD1) | INSTR1(LUT_WRITE)); #endif + + /* + * Read any device register. + * Used for Spansion S25FS-S family flash only. + */ + lut_base = SEQID_RDAR * 4; + qspi_write32(priv->flags, ®s->lut[lut_base], + OPRND0(QSPI_CMD_RDAR) | PAD0(LUT_PAD1) | + INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], + OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | + OPRND1(1) | PAD1(LUT_PAD1) | + INSTR1(LUT_READ)); + + /* + * Write any device register. + * Used for Spansion S25FS-S family flash only. + */ + lut_base = SEQID_WRAR * 4; + qspi_write32(priv->flags, ®s->lut[lut_base], + OPRND0(QSPI_CMD_WRAR) | PAD0(LUT_PAD1) | + INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], + OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); + /* Lock the LUT */ qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_LOCK); @@ -510,7 +543,6 @@ static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -#ifndef CONFIG_SYS_FSL_QSPI_AHB /* If not use AHB read, read data from ip interface */ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) { @@ -518,6 +550,12 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) u32 mcr_reg, data; int i, size; u32 to_or_from; + u32 seqid; + + if (priv->cur_seqid == QSPI_CMD_RDAR) + seqid = SEQID_RDAR; + else + seqid = SEQID_FAST_READ; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, @@ -536,7 +574,7 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) RX_BUFFER_SIZE : len; qspi_write32(priv->flags, ®s->ipcr, - (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | + (seqid << QSPI_IPCR_SEQID_SHIFT) | size); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; @@ -548,7 +586,10 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) while ((RX_BUFFER_SIZE >= size) && (size > 0)) { data = qspi_read32(priv->flags, ®s->rbdr[i]); data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, 4); + if (size < 4) + memcpy(rxbuf, &data, size); + else + memcpy(rxbuf, &data, 4); rxbuf++; size -= 4; i++; @@ -560,7 +601,6 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -#endif static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) { @@ -601,6 +641,8 @@ static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) /* Default is page programming */ seqid = SEQID_PP; + if (priv->cur_seqid == QSPI_CMD_WRAR) + seqid = SEQID_WRAR; #ifdef CONFIG_SPI_FLASH_BAR if (priv->cur_seqid == QSPI_CMD_BRWR) seqid = SEQID_BRWR; @@ -725,13 +767,15 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, return 0; } - if (priv->cur_seqid == QSPI_CMD_FAST_READ) { + if (priv->cur_seqid == QSPI_CMD_FAST_READ || + priv->cur_seqid == QSPI_CMD_RDAR) { priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; } else if ((priv->cur_seqid == QSPI_CMD_SE) || (priv->cur_seqid == QSPI_CMD_BE_4K)) { priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; qspi_op_erase(priv); - } else if (priv->cur_seqid == QSPI_CMD_PP) { + } else if (priv->cur_seqid == QSPI_CMD_PP || + priv->cur_seqid == QSPI_CMD_WRAR) { wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; } else if ((priv->cur_seqid == QSPI_CMD_BRWR) || (priv->cur_seqid == QSPI_CMD_WREAR)) { @@ -748,6 +792,8 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, #else qspi_op_read(priv, din, bytes); #endif + } else if (priv->cur_seqid == QSPI_CMD_RDAR) { + qspi_op_read(priv, din, bytes); } else if (priv->cur_seqid == QSPI_CMD_RDID) qspi_op_rdid(priv, din, bytes); else if (priv->cur_seqid == QSPI_CMD_RDSR) -- 2.39.5