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> --- 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, ®s->lut[lut_base + 1], OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); + /* Read SFDP information */ + lut_base = SEQID_RDSFDP * 4; + qspi_write32(priv->flags, ®s->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, ®s->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, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); + /* Lock the LUT */ qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); qspi_write32(priv->flags, ®s->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, ®s->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, ®s->mcr); + qspi_write32(priv->flags, ®s->mcr, + QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + to_or_from = priv->sf_addr + priv->cur_amba_base; + + while (len > 0) { + WATCHDOG_RESET(); + + qspi_write32(priv->flags, ®s->sfar, to_or_from); + + size = (len > RX_BUFFER_SIZE) ? + RX_BUFFER_SIZE : len; + + qspi_write32(priv->flags, ®s->ipcr, + (seqid << QSPI_IPCR_SEQID_SHIFT) | + size); + while (qspi_read32(priv->flags, ®s->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, ®s->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, ®s->mcr, + qspi_read32(priv->flags, ®s->mcr) | + QSPI_MCR_CLR_RXF_MASK); + } + + qspi_write32(priv->flags, ®s->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