[U-Boot] [PATCH v2 2/2] fsl_qspi: Access flash above 16MB using SFDP
Rajat Srivastava
rajat.srivastava at nxp.com
Tue Nov 13 12:00:44 UTC 2018
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.srivastava at 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, ®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
More information about the U-Boot
mailing list