[U-Boot] [PATCH] spi: qspi: Fix issue when booting with DDR mode

When booting from QSPI NOR with DDR mode enabled on i.MX7D/6UL, the FLSHCR TDH bit is set to 1 by ROM along with MCR DDR_EN bit set. But the read/write/readid/erase operations in the driver will overwrite the MCR register, and cause the bits like DDR_EN are cleared. If the DDR_EN is cleared but TDH is set, there is no clk2x output for TX data shift. So these operations above will fail.
Fix the issue in two aspects: 1. In read/write/readid/erase operations, only set useful bit to MCR, not overwrite the whole register. 2. Set the TDH to 1 in qspi_enable_ddr_mode, so that DDR_EN and TDH will be correctly set by this function.
Signed-off-by: Ye Li ye.li@nxp.com --- drivers/spi/fsl_qspi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 1598c4f..1987a72 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -405,7 +405,7 @@ static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
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); + mcr_reg);
rx_addr = (void *)(uintptr_t)(priv->cur_amba_base + priv->sf_addr); /* Read out the data directly from the AHB buffer. */ @@ -435,6 +435,12 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv) reg |= BIT(29);
qspi_write32(priv->flags, ®s->mcr, reg); + + /* Enable the TDH to 1 for i.mx6ul and mx7d, it is reserved on other platforms */ + reg = qspi_read32(priv->flags, ®s->flshcr); + reg &= ~(BIT(17)); + reg |= BIT(16); + qspi_write32(priv->flags, ®s->flshcr, reg); }
/* @@ -488,7 +494,7 @@ static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len) 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); + mcr_reg); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS);
qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); @@ -533,7 +539,7 @@ static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) 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); + mcr_reg); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS);
qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); @@ -579,7 +585,7 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) 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); + mcr_reg); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS);
to_or_from = priv->sf_addr + priv->cur_amba_base; @@ -631,7 +637,7 @@ static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) 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); + mcr_reg); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS);
status_reg = 0; @@ -706,7 +712,7 @@ static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len) 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); + mcr_reg); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS);
qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); @@ -743,7 +749,7 @@ static void qspi_op_erase(struct fsl_qspi_priv *priv) 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); + mcr_reg); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS);
to_or_from = priv->sf_addr + priv->cur_amba_base;

On Mon, Jan 7, 2019 at 2:15 PM Ye Li ye.li@nxp.com wrote:
When booting from QSPI NOR with DDR mode enabled on i.MX7D/6UL, the FLSHCR TDH bit is set to 1 by ROM along with MCR DDR_EN bit set. But the read/write/readid/erase operations in the driver will overwrite the MCR register, and cause the bits like DDR_EN are cleared. If the DDR_EN is cleared but TDH is set, there is no clk2x output for TX data shift. So these operations above will fail.
Fix the issue in two aspects:
- In read/write/readid/erase operations, only set useful bit to MCR, not overwrite the whole register.
- Set the TDH to 1 in qspi_enable_ddr_mode, so that DDR_EN and TDH will be correctly set by this function.
Signed-off-by: Ye Li ye.li@nxp.com
drivers/spi/fsl_qspi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 1598c4f..1987a72 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -405,7 +405,7 @@ static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
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);
mcr_reg); rx_addr = (void *)(uintptr_t)(priv->cur_amba_base + priv->sf_addr); /* Read out the data directly from the AHB buffer. */
@@ -435,6 +435,12 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv) reg |= BIT(29);
qspi_write32(priv->flags, ®s->mcr, reg);
/* Enable the TDH to 1 for i.mx6ul and mx7d, it is reserved on other platforms */
reg = qspi_read32(priv->flags, ®s->flshcr);
reg &= ~(BIT(17));
reg |= BIT(16);
Add proper macros for these bits.
participants (2)
-
Jagan Teki
-
Ye Li