[U-Boot] [PATCH 2/3] QSPI: Enable write device registers

Peng Fan Peng.Fan at freescale.com
Wed Sep 10 08:16:56 CEST 2014


From: Peng Fan <van.freenix at gmail.com>

Add qspi_op_wrr to support status and configuration register write in
flash devices.

Signed-off-by: Peng Fan <van.freenix at gmail.com>
---
 drivers/spi/fsl_qspi.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 74 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 7e8d07e..b1d75e7 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -32,12 +32,16 @@
 #define SEQID_CHIP_ERASE	5
 #define SEQID_PP		6
 #define SEQID_RDID		7
+#define SEQID_WRR		8
+#define SEQID_RDCR		9
 
 /* Flash opcodes */
+#define OPCODE_WRR		0x01	/* Write status/config register */
 #define OPCODE_PP		0x02	/* Page program (up to 256 bytes) */
 #define OPCODE_RDSR		0x05	/* Read status register */
 #define OPCODE_WREN		0x06	/* Write enable */
 #define OPCODE_FAST_READ	0x0b	/* Read data bytes (high frequency) */
+#define OPCODE_RDCR		0x35	/* Read configuration register */
 #define OPCODE_CHIP_ERASE	0xc7	/* Erase whole flash chip */
 #define OPCODE_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define OPCODE_RDID		0x9f	/* Read JEDEC ID */
@@ -189,6 +193,18 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
 	qspi_write32(&regs->lut[lut_base + 2], 0);
 	qspi_write32(&regs->lut[lut_base + 3], 0);
 
+	/* Write Register */
+	lut_base = SEQID_WRR * 4;
+	qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_WRR) |
+		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(LUT_WRITE) |
+		     PAD1(LUT_PAD1) | INSTR1(0x2));
+
+	/* Read Configuration Register */
+	lut_base = SEQID_RDCR * 4;
+	qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_RDCR) |
+		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(LUT_READ) |
+		     PAD1(LUT_PAD1) | INSTR1(0x1));
+
 	/* Lock the LUT */
 	qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
 	qspi_write32(&regs->lckcr, QSPI_LCKCR_LOCK);
@@ -352,6 +368,55 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
 	qspi_write32(&regs->mcr, mcr_reg);
 }
 
+static void qspi_op_wrr(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
+{
+	struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+	u32 mcr_reg, data, reg, status_reg;
+	u32 to_or_from;
+
+	mcr_reg = qspi_read32(&regs->mcr);
+	qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+	qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+	status_reg = 0;
+	while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
+		qspi_write32(&regs->ipcr,
+			     (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+		while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+			;
+
+		qspi_write32(&regs->ipcr,
+			     (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
+		while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+			;
+
+		reg = qspi_read32(&regs->rbsr);
+		if (reg & QSPI_RBSR_RDBFL_MASK) {
+			status_reg = qspi_read32(&regs->rbdr[0]);
+			status_reg = qspi_endian_xchg(status_reg);
+		}
+		qspi_write32(&regs->mcr,
+			     qspi_read32(&regs->mcr) | QSPI_MCR_CLR_RXF_MASK);
+	}
+
+	to_or_from = qspi->amba_base;
+	qspi_write32(&regs->sfar, to_or_from);
+
+	/* The max len is 2 for OPCODE_WRR */
+	data = 0;
+	memcpy(&data, txbuf, len);
+	data = qspi_endian_xchg(data);
+	qspi_write32(&regs->tbdr, data);
+
+	qspi_write32(&regs->ipcr,
+		     (SEQID_WRR << QSPI_IPCR_SEQID_SHIFT) | len);
+	while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+		;
+
+	qspi_write32(&regs->mcr, mcr_reg);
+}
+
 static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len)
 {
 	struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
@@ -476,11 +541,17 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 	if (dout) {
 		memcpy(&txbuf, dout, 4);
-		qspi->cur_seqid = *(u8 *)dout;
+		/* extract cmd when SPI_XFER_BEGIN is set */
+		if (flags & SPI_XFER_BEGIN)
+			qspi->cur_seqid = *(u8 *)dout;
 
 		if (flags == SPI_XFER_END) {
-			qspi->sf_addr = pp_sfaddr;
-			qspi_op_pp(qspi, (u32 *)dout, bytes);
+			if (qspi->cur_seqid == OPCODE_WRR) {
+				qspi_op_wrr(qspi, (u8 *)dout, bytes);
+			} else if (qspi->cur_seqid == OPCODE_PP) {
+				qspi->sf_addr = pp_sfaddr;
+				qspi_op_pp(qspi, (u32 *)dout, bytes);
+			}
 			return 0;
 		}
 
-- 
1.8.4




More information about the U-Boot mailing list