Add functionality to read SFDP parameters in fsl_qspi driver.
Also, use the address width information from SFDP to enable
flash access above 16 MB.

Introduce a way to access parent structure by adding pointer
to struct spi_slave in struct fsl_qspi_priv.

Signed-off-by: Rajat Srivastava <rajat.srivast...@nxp.com>
---
Changes in v2:
- none
---
 drivers/spi/fsl_qspi.c | 103 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 96 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 1598c4f698..615f36e351 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -26,7 +26,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define TX_BUFFER_SIZE         0x40
 #endif
 
-#define OFFSET_BITS_MASK       GENMASK(23, 0)
+#define SET_BITS_MASK(X)       GENMASK(X, 0)
 
 #define FLASH_STATUS_WEL       0x02
 
@@ -47,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #endif
 #define SEQID_WRAR             13
 #define SEQID_RDAR             14
+#define SEQID_RDSFDP           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_RDSFDP                0x5a    /* Read SFDP parameters from 
flash */
 
 /* Used for Micron, winbond and Macronix flashes */
 #define        QSPI_CMD_WREAR          0xc5    /* EAR register write */
@@ -132,6 +134,7 @@ struct fsl_qspi_priv {
        u32 flash_num;
        u32 num_chipselect;
        struct fsl_qspi_regs *regs;
+       void *spi_slave;
 };
 
 
@@ -363,6 +366,19 @@ static void qspi_set_lut(struct fsl_qspi_priv *priv)
        qspi_write32(priv->flags, &regs->lut[lut_base + 1],
                     OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
 
+       /* Read SFDP information */
+       lut_base = SEQID_RDSFDP * 4;
+       qspi_write32(priv->flags, &regs->lut[lut_base],
+                    OPRND0(QSPI_CMD_RDSFDP) | PAD0(LUT_PAD1) |
+                    INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+                    PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+       qspi_write32(priv->flags, &regs->lut[lut_base + 1],
+                    OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
+                    OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
+                    INSTR1(LUT_READ));
+       qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+       qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+
        /* Lock the LUT */
        qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
        qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_LOCK);
@@ -562,6 +578,61 @@ static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 
*rxbuf, u32 len)
        qspi_write32(priv->flags, &regs->mcr, mcr_reg);
 }
 
+static void qspi_op_rdsfdp(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
+{
+       struct fsl_qspi_regs *regs = priv->regs;
+       u32 mcr_reg, data;
+       int i, size;
+       u32 to_or_from;
+       u32 seqid;
+
+       seqid = SEQID_RDSFDP;
+
+       mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+       qspi_write32(priv->flags, &regs->mcr,
+                    QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+                    QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+       qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+       to_or_from = priv->sf_addr + priv->cur_amba_base;
+
+       while (len > 0) {
+               WATCHDOG_RESET();
+
+               qspi_write32(priv->flags, &regs->sfar, to_or_from);
+
+               size = (len > RX_BUFFER_SIZE) ?
+                       RX_BUFFER_SIZE : len;
+
+               qspi_write32(priv->flags, &regs->ipcr,
+                            (seqid << QSPI_IPCR_SEQID_SHIFT) |
+                            size);
+               while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
+                       ;
+
+               to_or_from += size;
+               len -= size;
+
+               i = 0;
+               while ((size < RX_BUFFER_SIZE) && (size > 0)) {
+                       data = qspi_read32(priv->flags, &regs->rbdr[i]);
+                       data = qspi_endian_xchg(data);
+                       if (size < 4)
+                               memcpy(rxbuf, &data, size);
+                       else
+                               memcpy(rxbuf, &data, 4);
+                       rxbuf++;
+                       size -= 4;
+                       i++;
+               }
+               qspi_write32(priv->flags, &regs->mcr,
+                            qspi_read32(priv->flags, &regs->mcr) |
+                            QSPI_MCR_CLR_RXF_MASK);
+       }
+
+       qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+}
+
 /* If not use AHB read, read data from ip interface */
 static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
 {
@@ -772,14 +843,25 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int 
bitlen,
 {
        u32 bytes = DIV_ROUND_UP(bitlen, 8);
        static u32 wr_sfaddr;
-       u32 txbuf;
+       u32 txbuf, bits_mask;
+       struct spi_flash *flash;
+
+       flash = ((struct spi_slave *)(priv->spi_slave))->flash;
 
        WATCHDOG_RESET();
 
+       if (flash->cmd_len == 5 && flash->size > SZ_16M)
+               bits_mask = SET_BITS_MASK(27);
+       else
+               bits_mask = SET_BITS_MASK(23);
+
        if (dout) {
                if (flags & SPI_XFER_BEGIN) {
                        priv->cur_seqid = *(u8 *)dout;
-                       memcpy(&txbuf, dout, 4);
+                       if (flash->size > SZ_16M && bytes > 4)
+                               memcpy(&txbuf, dout + 1, 4);
+                       else
+                               memcpy(&txbuf, dout, 4);
                }
 
                if (flags == SPI_XFER_END) {
@@ -790,20 +872,21 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int 
bitlen,
 
                if (priv->cur_seqid == QSPI_CMD_FAST_READ ||
                    priv->cur_seqid == QSPI_CMD_RDAR) {
-                       priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+                       priv->sf_addr = swab32(txbuf) & 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;
+                       priv->sf_addr = swab32(txbuf) & bits_mask;
                        qspi_op_erase(priv);
                } else if (priv->cur_seqid == QSPI_CMD_PP ||
                           priv->cur_seqid == QSPI_CMD_WRAR) {
-                       wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+                       wr_sfaddr = swab32(txbuf) & bits_mask;
                } else if ((priv->cur_seqid == QSPI_CMD_BRWR) ||
                         (priv->cur_seqid == QSPI_CMD_WREAR)) {
 #ifdef CONFIG_SPI_FLASH_BAR
                        wr_sfaddr = 0;
 #endif
-               }
+               } else if (priv->cur_seqid == QSPI_CMD_RDSFDP)
+                       priv->sf_addr = swab32(txbuf) & bits_mask;
        }
 
        if (din) {
@@ -819,6 +902,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_RDSFDP)
+                       qspi_op_rdsfdp(priv, din, bytes);
 #ifdef CONFIG_SPI_FLASH_BAR
                else if ((priv->cur_seqid == QSPI_CMD_BRRD) ||
                         (priv->cur_seqid == QSPI_CMD_RDEAR)) {
@@ -1044,9 +1129,13 @@ static int fsl_qspi_xfer(struct udevice *dev, unsigned 
int bitlen,
 {
        struct fsl_qspi_priv *priv;
        struct udevice *bus;
+       struct spi_slave *slave;
 
        bus = dev->parent;
        priv = dev_get_priv(bus);
+       slave = dev_get_parent_priv(dev);
+
+       priv->spi_slave = slave;
 
        return qspi_xfer(priv, bitlen, dout, din, flags);
 }
-- 
2.14.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to