spi: spi-fsl-qspi: Clear TDH bits in FLSHCR register
authorFrieder Schrempf <frieder.schrempf@kontron.de>
Mon, 7 Oct 2019 07:23:02 +0000 (07:23 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Dec 2019 07:43:12 +0000 (08:43 +0100)
commit f6910679e17ad4915f008bd2c614d38052426f7c upstream.

Later versions of the QSPI controller (e.g. in i.MX6UL/ULL and i.MX7)
seem to have an additional TDH setting in the FLSHCR register, that
needs to be set in accordance with the access mode that is used (DDR
or SDR).

Previous bootstages such as BootROM or bootloader might have used the
DDR mode to access the flash. As we currently only use SDR mode, we
need to make sure the TDH bits are cleared upon initialization.

Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller")
Cc: <stable@vger.kernel.org>
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Acked-by: Han Xu <han.xu@nxp.com>
Link: https://lore.kernel.org/r/20191007071933.26786-1-frieder.schrempf@kontron.de
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/spi/spi-fsl-qspi.c

index c02e24c..63c9f7e 100644 (file)
 #define QUADSPI_IPCR                   0x08
 #define QUADSPI_IPCR_SEQID(x)          ((x) << 24)
 
+#define QUADSPI_FLSHCR                 0x0c
+#define QUADSPI_FLSHCR_TCSS_MASK       GENMASK(3, 0)
+#define QUADSPI_FLSHCR_TCSH_MASK       GENMASK(11, 8)
+#define QUADSPI_FLSHCR_TDH_MASK                GENMASK(17, 16)
+
 #define QUADSPI_BUF3CR                 0x1c
 #define QUADSPI_BUF3CR_ALLMST_MASK     BIT(31)
 #define QUADSPI_BUF3CR_ADATSZ(x)       ((x) << 8)
 #define QUADSPI_FR                     0x160
 #define QUADSPI_FR_TFF_MASK            BIT(0)
 
+#define QUADSPI_RSER                   0x164
+#define QUADSPI_RSER_TFIE              BIT(0)
+
 #define QUADSPI_SPTRCLR                        0x16c
 #define QUADSPI_SPTRCLR_IPPTRC         BIT(8)
 #define QUADSPI_SPTRCLR_BFPTRC         BIT(0)
 #define QUADSPI_LCKER_LOCK             BIT(0)
 #define QUADSPI_LCKER_UNLOCK           BIT(1)
 
-#define QUADSPI_RSER                   0x164
-#define QUADSPI_RSER_TFIE              BIT(0)
-
 #define QUADSPI_LUT_BASE               0x310
 #define QUADSPI_LUT_OFFSET             (SEQID_LUT * 4 * 4)
 #define QUADSPI_LUT_REG(idx) \
  */
 #define QUADSPI_QUIRK_BASE_INTERNAL    BIT(4)
 
+/*
+ * Controller uses TDH bits in register QUADSPI_FLSHCR.
+ * They need to be set in accordance with the DDR/SDR mode.
+ */
+#define QUADSPI_QUIRK_USE_TDH_SETTING  BIT(5)
+
 struct fsl_qspi_devtype_data {
        unsigned int rxfifo;
        unsigned int txfifo;
@@ -209,7 +220,8 @@ static const struct fsl_qspi_devtype_data imx7d_data = {
        .rxfifo = SZ_128,
        .txfifo = SZ_512,
        .ahb_buf_size = SZ_1K,
-       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+                 QUADSPI_QUIRK_USE_TDH_SETTING,
        .little_endian = true,
 };
 
@@ -217,7 +229,8 @@ static const struct fsl_qspi_devtype_data imx6ul_data = {
        .rxfifo = SZ_128,
        .txfifo = SZ_512,
        .ahb_buf_size = SZ_1K,
-       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK,
+       .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+                 QUADSPI_QUIRK_USE_TDH_SETTING,
        .little_endian = true,
 };
 
@@ -275,6 +288,11 @@ static inline int needs_amba_base_offset(struct fsl_qspi *q)
        return !(q->devtype_data->quirks & QUADSPI_QUIRK_BASE_INTERNAL);
 }
 
+static inline int needs_tdh_setting(struct fsl_qspi *q)
+{
+       return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
+}
+
 /*
  * An IC bug makes it necessary to rearrange the 32-bit data.
  * Later chips, such as IMX6SLX, have fixed this bug.
@@ -710,6 +728,16 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
        qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
                    base + QUADSPI_MCR);
 
+       /*
+        * Previous boot stages (BootROM, bootloader) might have used DDR
+        * mode and did not clear the TDH bits. As we currently use SDR mode
+        * only, clear the TDH bits if necessary.
+        */
+       if (needs_tdh_setting(q))
+               qspi_writel(q, qspi_readl(q, base + QUADSPI_FLSHCR) &
+                           ~QUADSPI_FLSHCR_TDH_MASK,
+                           base + QUADSPI_FLSHCR);
+
        reg = qspi_readl(q, base + QUADSPI_SMPR);
        qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK
                        | QUADSPI_SMPR_FSPHS_MASK