From: Peng Fan <van.free...@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.free...@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(&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_64);
+
+       /* Read out the data directly from the AHB buffer.*/
+       memcpy(rxbuf, (u8 *)to_or_from, len);
+
+       qspi_write32(&regs->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(&regs->mcr);
+       mcr_reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
+       qspi_write32(&regs->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(&regs->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(&regs->smpr);
        smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
        qspi_write32(&regs->smpr, smpr_val);
+
+#ifdef CONFIG_MX6SX
+       qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK |
+                    QSPI_MCR_END_CFD_LE << QSPI_MCR_END_CFD_SHIFT);
+#else
        qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
+#endif
 
+#ifdef CONFIG_MX6SX
+       /* AHB configuration for access buffer 0/1/2 */
+       qspi_write32(&regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
+       qspi_write32(&regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
+       qspi_write32(&regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
+       qspi_write32(&regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
+                    (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
+
+       qspi_write32(&regs->buf0ind, 0);
+       qspi_write32(&regs->buf1ind, 0);
+       qspi_write32(&regs->buf2ind, 0);
+
+       seq_id = SEQID_FAST_READ;
+#else
        seq_id = 0;
+#endif
        reg_val = qspi_read32(&regs->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(&regs->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(&regs->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(&regs->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(&regs->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


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

Reply via email to