[U-Boot] [PATCH 3/3] QSPI: Enable QSPI AHB read for MX6SX
Peng Fan
Peng.Fan at freescale.com
Wed Sep 10 08:16:57 CEST 2014
From: Peng Fan <van.freenix at gmail.com>
There are two different ways to read out the data from the flash:
the "IP Command Read" and the "AHB Command Read".
The IC guy suggests we use the "AHB Command Read" which is faster
then the "IP Command Read". (What's more is that there is a bug in
the "IP Command Read" in the Vybrid.)
After we set up the registers for the "AHB Command Read", we can use
the memcpy to read the data directly. A "missed" access to the buffer
causes the controller to clear the buffer, and use the sequence pointed
by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
Signed-off-by: Peng Fan <van.freenix at gmail.com>
---
drivers/spi/fsl_qspi.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/spi/fsl_qspi.h | 11 +++++++
2 files changed, 92 insertions(+)
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index b1d75e7..95b36f0 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -215,6 +215,52 @@ void spi_init()
/* do nothing */
}
+#ifdef CONFIG_MX6SX
+static void qspi_ahb_read(struct fsl_qspi *qspi, u8 *rxbuf, u32 len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg;
+ u32 to_or_from;
+
+ to_or_from = qspi->sf_addr + qspi->amba_base;
+
+ mcr_reg = qspi_read32(®s->mcr);
+ qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK |
+ QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK |
+ QSPI_MCR_END_CFD_LE_64);
+
+ /* Read out the data directly from the AHB buffer.*/
+ memcpy(rxbuf, (u8 *)to_or_from, len);
+
+ qspi_write32(®s->mcr, mcr_reg);
+}
+
+/*
+ * If we have changed the content of the flash by writing or erasing,
+ * we need to invalidate the AHB buffer. If we do not do so, we may read out
+ * the wrong data. The spec tells us reset the AHB domain and Serial Flash
+ * domain at the same time.
+ */
+static inline void qspi_invalid_buf(struct fsl_qspi *qspi)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg;
+
+ mcr_reg = qspi_read32(®s->mcr);
+ mcr_reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
+ qspi_write32(®s->mcr, mcr_reg);
+
+ /*
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
+ */
+ udelay(1);
+
+ mcr_reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
+ qspi_write32(®s->mcr, mcr_reg);
+}
+#endif
+
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
@@ -266,9 +312,30 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
smpr_val = qspi_read32(®s->smpr);
smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
qspi_write32(®s->smpr, smpr_val);
+
+#ifdef CONFIG_MX6SX
+ qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK |
+ QSPI_MCR_END_CFD_LE << QSPI_MCR_END_CFD_SHIFT);
+#else
qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK);
+#endif
+#ifdef CONFIG_MX6SX
+ /* AHB configuration for access buffer 0/1/2 */
+ qspi_write32(®s->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(®s->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(®s->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(®s->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
+ (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
+
+ qspi_write32(®s->buf0ind, 0);
+ qspi_write32(®s->buf1ind, 0);
+ qspi_write32(®s->buf2ind, 0);
+
+ seq_id = SEQID_FAST_READ;
+#else
seq_id = 0;
+#endif
reg_val = qspi_read32(®s->bfgencr);
reg_val &= ~QSPI_BFGENCR_SEQID_MASK;
reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT);
@@ -324,6 +391,7 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(®s->mcr, mcr_reg);
}
+#ifndef CONFIG_MX6SX
static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
{
struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
@@ -367,6 +435,7 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(®s->mcr, mcr_reg);
}
+#endif
static void qspi_op_wrr(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
{
@@ -470,6 +539,10 @@ static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len)
;
qspi_write32(®s->mcr, mcr_reg);
+
+#ifdef CONFIG_MX6SX
+ qspi_invalid_buf(qspi);
+#endif
}
static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf)
@@ -529,6 +602,10 @@ static void qspi_op_se(struct fsl_qspi *qspi)
;
qspi_write32(®s->mcr, mcr_reg);
+
+#ifdef CONFIG_MX6SX
+ qspi_invalid_buf(qspi);
+#endif
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
@@ -567,7 +644,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (din) {
if (qspi->cur_seqid == OPCODE_FAST_READ)
+#ifdef CONFIG_MX6SX
+ qspi_ahb_read(qspi, din, bytes);
+#else
qspi_op_read(qspi, din, bytes);
+#endif
else if (qspi->cur_seqid == OPCODE_RDID)
qspi_op_rdid(qspi, din, bytes);
else if (qspi->cur_seqid == OPCODE_RDSR)
diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
index db400e6..80c5ac9 100644
--- a/drivers/spi/fsl_qspi.h
+++ b/drivers/spi/fsl_qspi.h
@@ -56,9 +56,14 @@ struct fsl_qspi_regs {
#define QSPI_IPCR_SEQID_SHIFT 24
#define QSPI_IPCR_SEQID_MASK (0xf << QSPI_IPCR_SEQID_SHIFT)
+#define QSPI_MCR_SWRSTSD_SHIFT 0
+#define QSPI_MCR_SWRSTSD_MASK (1 << QSPI_MCR_SWRSTSD_SHIFT)
+#define QSPI_MCR_SWRSTHD_SHIFT 1
+#define QSPI_MCR_SWRSTHD_MASK (1 << QSPI_MCR_SWRSTHD_SHIFT)
#define QSPI_MCR_END_CFD_SHIFT 2
#define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT)
#define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT)
+#define QSPI_MCR_END_CFD_LE_64 (3 << QSPI_MCR_END_CFD_SHIFT)
#define QSPI_MCR_DDR_EN_SHIFT 7
#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT)
#define QSPI_MCR_CLR_RXF_SHIFT 10
@@ -79,6 +84,12 @@ struct fsl_qspi_regs {
#define QSPI_SMPR_DDRSMP_SHIFT 16
#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT)
+#define QSPI_BUFXCR_INVALID_MSTRID 0xe
+#define QSPI_BUF3CR_ALLMST_SHIFT 31
+#define QSPI_BUF3CR_ALLMST_MASK (1 << QSPI_BUF3CR_ALLMST_SHIFT)
+#define QSPI_BUF3CR_ADATSZ_SHIFT 8
+#define QSPI_BUF3CR_ADATSZ_MASK (0xff << QSPI_BUF3CR_ADATSZ_SHIFT)
+
#define QSPI_BFGENCR_SEQID_SHIFT 12
#define QSPI_BFGENCR_SEQID_MASK (0xf << QSPI_BFGENCR_SEQID_SHIFT)
#define QSPI_BFGENCR_PAR_EN_SHIFT 16
--
1.8.4
More information about the U-Boot
mailing list