diff options
Diffstat (limited to 'drivers/spi/fsl_qspi.c')
-rw-r--r-- | drivers/spi/fsl_qspi.c | 137 |
1 files changed, 127 insertions, 10 deletions
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index ad4f4ce..5e0b069 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -263,6 +263,110 @@ static void qspi_set_lut(struct fsl_qspi *qspi) qspi_write32(®s->lckcr, QSPI_LCKCR_LOCK); } +#if defined(CONFIG_SYS_FSL_QSPI_AHB) +/* + * 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_ahb_invalid(struct fsl_qspi *q) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base; + u32 reg; + + reg = qspi_read32(®s->mcr); + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; + qspi_write32(®s->mcr, reg); + + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + udelay(1); + + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); + qspi_write32(®s->mcr, reg); +} + +/* Read out the data from the AHB buffer. */ +static inline void qspi_ahb_read(struct fsl_qspi *q, u8 *rxbuf, int len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base; + u32 mcr_reg; + + 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); + + /* Read out the data directly from the AHB buffer. */ + memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len); + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs) +{ + u32 reg, reg2; + + reg = qspi_read32(®s->mcr); + /* Disable the module */ + qspi_write32(®s->mcr, reg | QSPI_MCR_MDIS_MASK); + + /* Set the Sampling Register for DDR */ + reg2 = qspi_read32(®s->smpr); + reg2 &= ~QSPI_SMPR_DDRSMP_MASK; + reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT); + qspi_write32(®s->smpr, reg2); + + /* Enable the module again (enable the DDR too) */ + reg |= QSPI_MCR_DDR_EN_MASK; + /* Enable bit 29 for imx6sx */ + reg |= (1 << 29); + + qspi_write32(®s->mcr, reg); +} + +/* + * 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. + */ +static void qspi_init_ahb_read(struct fsl_qspi_regs *regs) +{ + /* 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)); + + /* We only use the buffer3 */ + qspi_write32(®s->buf0ind, 0); + qspi_write32(®s->buf1ind, 0); + qspi_write32(®s->buf2ind, 0); + + /* + * Set the default lut sequence for AHB Read. + * Parallel mode is disabled. + */ + qspi_write32(®s->bfgencr, + SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT); + + /*Enable DDR Mode*/ + qspi_enable_ddr_mode(regs); +} +#endif + void spi_init() { /* do nothing */ @@ -273,8 +377,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, { struct fsl_qspi *qspi; struct fsl_qspi_regs *regs; - u32 reg_val, smpr_val; - u32 total_size, seq_id; + u32 smpr_val; + u32 total_size; if (bus >= ARRAY_SIZE(spi_bases)) return NULL; @@ -329,13 +433,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, qspi_write32(®s->smpr, smpr_val); qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); - seq_id = 0; - reg_val = qspi_read32(®s->bfgencr); - reg_val &= ~QSPI_BFGENCR_SEQID_MASK; - reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT); - reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK; - qspi_write32(®s->bfgencr, reg_val); - +#ifdef CONFIG_SYS_FSL_QSPI_AHB + qspi_init_ahb_read(regs); +#endif return &qspi->slave; } @@ -426,6 +526,8 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) qspi_write32(®s->mcr, mcr_reg); } +#ifndef CONFIG_SYS_FSL_QSPI_AHB +/* If not use AHB read, read data from ip interface */ 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; @@ -469,6 +571,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_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len) { @@ -643,8 +746,13 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, } if (din) { - if (qspi->cur_seqid == QSPI_CMD_FAST_READ) + if (qspi->cur_seqid == QSPI_CMD_FAST_READ) { +#ifdef CONFIG_SYS_FSL_QSPI_AHB + qspi_ahb_read(qspi, din, bytes); +#else qspi_op_read(qspi, din, bytes); +#endif + } else if (qspi->cur_seqid == QSPI_CMD_RDID) qspi_op_rdid(qspi, din, bytes); else if (qspi->cur_seqid == QSPI_CMD_RDSR) @@ -658,6 +766,15 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, #endif } +#ifdef CONFIG_SYS_FSL_QSPI_AHB + if ((qspi->cur_seqid == QSPI_CMD_SE) || + (qspi->cur_seqid == QSPI_CMD_PP) || + (qspi->cur_seqid == QSPI_CMD_BE_4K) || + (qspi->cur_seqid == QSPI_CMD_WREAR) || + (qspi->cur_seqid == QSPI_CMD_BRWR)) + qspi_ahb_invalid(qspi); +#endif + return 0; } |