spi, mpc8xx: Add support for chipselect via GPIO and fixups
[platform/kernel/u-boot.git] / drivers / spi / nxp_fspi.c
index 012f304..579d6ba 100644 (file)
 #include <spi.h>
 #include <spi-mem.h>
 #include <asm/io.h>
+#ifdef CONFIG_FSL_LAYERSCAPE
+#include <asm/arch/clock.h>
+#include <asm/arch/soc.h>
+#include <asm/arch/speed.h>
+#endif
 #include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/sizes.h>
 #define POLL_TOUT              5000
 #define NXP_FSPI_MAX_CHIPSELECT                4
 
+/* Access flash memory using IP bus only */
+#define FSPI_QUIRK_USE_IP_ONLY         BIT(0)
+
 struct nxp_fspi_devtype_data {
        unsigned int rxfifo;
        unsigned int txfifo;
@@ -312,7 +320,7 @@ struct nxp_fspi_devtype_data {
        bool little_endian;
 };
 
-static const struct nxp_fspi_devtype_data lx2160a_data = {
+static struct nxp_fspi_devtype_data lx2160a_data = {
        .rxfifo = SZ_512,       /* (64  * 64 bits)  */
        .txfifo = SZ_1K,        /* (128 * 64 bits)  */
        .ahb_buf_size = SZ_2K,  /* (256 * 64 bits)  */
@@ -320,7 +328,7 @@ static const struct nxp_fspi_devtype_data lx2160a_data = {
        .little_endian = true,  /* little-endian    */
 };
 
-static const struct nxp_fspi_devtype_data imx8mm_data = {
+static struct nxp_fspi_devtype_data imx8mm_data = {
        .rxfifo = SZ_512,       /* (64  * 64 bits)  */
        .txfifo = SZ_1K,        /* (128 * 64 bits)  */
        .ahb_buf_size = SZ_2K,  /* (256 * 64 bits)  */
@@ -335,9 +343,14 @@ struct nxp_fspi {
        u32 memmap_phy;
        u32 memmap_phy_size;
        struct clk clk, clk_en;
-       const struct nxp_fspi_devtype_data *devtype_data;
+       struct nxp_fspi_devtype_data *devtype_data;
 };
 
+static inline int needs_ip_only(struct nxp_fspi *f)
+{
+       return f->devtype_data->quirks & FSPI_QUIRK_USE_IP_ONLY;
+}
+
 /*
  * R/W functions for big- or little-endian registers:
  * The FSPI controller's endianness is independent of
@@ -428,7 +441,7 @@ static bool nxp_fspi_supports_op(struct spi_slave *slave,
            op->data.nbytes > f->devtype_data->txfifo)
                return false;
 
-       return true;
+       return spi_mem_default_supports_op(slave, op);
 }
 
 /* Instead of busy looping invoke readl_poll_sleep_timeout functionality. */
@@ -521,8 +534,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
        for (i = 0; i < ARRAY_SIZE(lutval); i++)
                fspi_writel(f, lutval[i], base + FSPI_LUT_REG(i));
 
-       dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x]\n",
-               op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3]);
+       dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n",
+               op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes);
 
        /* lock LUT */
        fspi_writel(f, FSPI_LUTKEY_VALUE, f->iobase + FSPI_LUTKEY);
@@ -769,12 +782,14 @@ static int nxp_fspi_exec_op(struct spi_slave *slave,
 
        nxp_fspi_prepare_lut(f, op);
        /*
-        * If we have large chunks of data, we read them through the AHB bus
-        * by accessing the mapped memory. In all other cases we use
-        * IP commands to access the flash.
+        * If we have large chunks of data, we read them through the AHB bus by
+        * accessing the mapped memory. In all other cases we use IP commands
+        * to access the flash. Read via AHB bus may be corrupted due to
+        * existence of an errata and therefore discard AHB read in such cases.
         */
        if (op->data.nbytes > (f->devtype_data->rxfifo - 4) &&
-           op->data.dir == SPI_MEM_DATA_IN) {
+           op->data.dir == SPI_MEM_DATA_IN &&
+           !needs_ip_only(f)) {
                nxp_fspi_read_ahb(f, op);
        } else {
                if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
@@ -808,9 +823,42 @@ static int nxp_fspi_adjust_op_size(struct spi_slave *slave,
                        op->data.nbytes = ALIGN_DOWN(op->data.nbytes, 8);
        }
 
+       /* Limit data bytes to RX FIFO in case of IP read only */
+       if (needs_ip_only(f) &&
+           op->data.dir == SPI_MEM_DATA_IN &&
+           op->data.nbytes > f->devtype_data->rxfifo)
+               op->data.nbytes = f->devtype_data->rxfifo;
+
        return 0;
 }
 
+#ifdef CONFIG_FSL_LAYERSCAPE
+static void erratum_err050568(struct nxp_fspi *f)
+{
+       struct sys_info sysinfo;
+       u32 svr = 0, freq = 0;
+
+       /* Check for LS1028A variants */
+       svr = SVR_SOC_VER(get_svr());
+       if (svr != SVR_LS1017A ||
+           svr != SVR_LS1018A ||
+           svr != SVR_LS1027A ||
+           svr != SVR_LS1028A) {
+               dev_dbg(f->dev, "Errata applicable only for LS1028A variants\n");
+               return;
+       }
+
+       /* Read PLL frequency */
+       get_sys_info(&sysinfo);
+       freq = sysinfo.freq_systembus / 1000000; /* Convert to MHz */
+       dev_dbg(f->dev, "svr: %08x, Frequency: %dMhz\n", svr, freq);
+
+       /* Use IP bus only if PLL is 300MHz */
+       if (freq == 300)
+               f->devtype_data->quirks |= FSPI_QUIRK_USE_IP_ONLY;
+}
+#endif
+
 static int nxp_fspi_default_setup(struct nxp_fspi *f)
 {
        void __iomem *base = f->iobase;
@@ -818,12 +866,9 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
        u32 reg;
 
 #if CONFIG_IS_ENABLED(CLK)
-       /* disable and unprepare clock to avoid glitch pass to controller */
-       nxp_fspi_clk_disable_unprep(f);
-
        /* the default frequency, we will change it later if necessary. */
        ret = clk_set_rate(&f->clk, 20000000);
-       if (ret)
+       if (ret < 0)
                return ret;
 
        ret = nxp_fspi_clk_prep_enable(f);
@@ -831,6 +876,17 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
                return ret;
 #endif
 
+#ifdef CONFIG_FSL_LAYERSCAPE
+       /*
+        * ERR050568: Flash access by FlexSPI AHB command may not work with
+        * platform frequency equal to 300 MHz on LS1028A.
+        * LS1028A reuses LX2160A compatible entry. Make errata applicable for
+        * Layerscape LS1028A platform family.
+        */
+       if (device_is_compatible(f->dev, "nxp,lx2160a-fspi"))
+               erratum_err050568(f);
+#endif
+
        /* Reset the module */
        /* w1c register, wait unit clear */
        ret = fspi_readl_poll_tout(f, f->iobase + FSPI_MCR0,
@@ -914,7 +970,7 @@ static int nxp_fspi_set_speed(struct udevice *bus, uint speed)
        nxp_fspi_clk_disable_unprep(f);
 
        ret = clk_set_rate(&f->clk, speed);
-       if (ret)
+       if (ret < 0)
                return ret;
 
        ret = nxp_fspi_clk_prep_enable(f);
@@ -994,6 +1050,7 @@ static const struct dm_spi_ops nxp_fspi_ops = {
 static const struct udevice_id nxp_fspi_ids[] = {
        { .compatible = "nxp,lx2160a-fspi", .data = (ulong)&lx2160a_data, },
        { .compatible = "nxp,imx8mm-fspi", .data = (ulong)&imx8mm_data, },
+       { .compatible = "nxp,imx8mp-fspi", .data = (ulong)&imx8mm_data, },
        { }
 };