Integrate the Cadence QSPI driver with read-only support into the PBL
with a pbl_bio abstraction. This allows to load additional binaries and
firmware from the flash while still in the PBL without requiring a full
barebox proper.

Signed-off-by: Michael Tretter <[email protected]>
---
 drivers/mtd/spi-nor/Kconfig               |   3 +
 drivers/mtd/spi-nor/Makefile              |   1 +
 drivers/mtd/spi-nor/cadence-quadspi-pbl.c | 104 ++++++++++++++++++++++++++++++
 include/pbl/mtd.h                         |  26 ++++++++
 4 files changed, 134 insertions(+)

diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index b34c69203ec2..e703ce707c5b 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -26,6 +26,9 @@ config SPI_CADENCE_QUADSPI
        help
          This enables support for the Cadence Quad SPI controller and NOR 
flash.
 
+config SPI_CADENCE_QUADSPI_PBL
+       bool
+
 config SPI_SYNOPSYS_OCTALSPI_NOR
        tristate "Synopsys DesignWare Octal SPI controller"
        help
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index ed73a95ec6b9..9e229a37ddfb 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-pbl-$(CONFIG_MTD_SPI_NOR)          += spi-nor.o
 obj-$(CONFIG_SPI_CADENCE_QUADSPI)      += cadence-quadspi.o 
cadence-quadspi-common.o
+pbl-$(CONFIG_SPI_CADENCE_QUADSPI_PBL)  += cadence-quadspi-pbl.o 
cadence-quadspi-common.o
 obj-$(CONFIG_SPI_SYNOPSYS_OCTALSPI_NOR) += dw-ospi-nor.o
diff --git a/drivers/mtd/spi-nor/cadence-quadspi-pbl.c 
b/drivers/mtd/spi-nor/cadence-quadspi-pbl.c
new file mode 100644
index 000000000000..b2bb00d15dc7
--- /dev/null
+++ b/drivers/mtd/spi-nor/cadence-quadspi-pbl.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <io.h>
+#include <linux/array_size.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/printk.h>
+#include <linux/time.h>
+#include <pbl/bio.h>
+#include <pbl/mtd.h>
+
+#include "cadence-quadspi.h"
+
+static void cqspi_write(struct spi_nor *nor, loff_t to,
+                       size_t len, size_t *retlen, const u_char *buf)
+{
+}
+
+static int cqspi_get_flash_pdata(struct cqspi_st *cqspi,
+                                struct cqspi_flash_pdata *f_pdata)
+{
+       void __iomem *reg_base = cqspi->iobase;
+
+       f_pdata->block_size = (readl(reg_base + CQSPI_REG_SIZE) >>
+               CQSPI_REG_SIZE_BLOCK_LSB) &
+               CQSPI_REG_SIZE_BLOCK_MASK;
+       cqspi->no_reconfig = true;
+
+       return 0;
+}
+
+static int cqspi_setup_flash(struct cqspi_st *cqspi,
+                            struct cqspi_flash_pdata *f_pdata)
+{
+       const struct spi_nor_hwcaps hwcaps = {
+               .mask = SNOR_HWCAPS_READ |
+                       SNOR_HWCAPS_READ_FAST |
+                       SNOR_HWCAPS_READ_1_1_2 |
+                       SNOR_HWCAPS_READ_1_1_4 |
+                       SNOR_HWCAPS_PP,
+       };
+       struct spi_nor *nor;
+       struct mtd_info *mtd;
+       int ret;
+
+       ret = cqspi_get_flash_pdata(cqspi, f_pdata);
+       if (ret)
+               return ret;
+
+       nor = &f_pdata->nor;
+       mtd = &f_pdata->mtd;
+
+       nor->mtd = mtd;
+
+       nor->priv = cqspi;
+       nor->read_reg = cqspi_read_reg;
+       nor->write_reg = cqspi_write_reg;
+       nor->read = cqspi_read;
+       nor->write = cqspi_write;
+
+       return spi_nor_scan(nor, NULL, &hwcaps, false);
+}
+
+static int cqspi_bio_read(struct pbl_bio *bio, off_t start,
+                         void *buf, unsigned int nblocks)
+{
+       struct cqspi_st *cqspi = bio->priv;
+       struct spi_nor *nor = &cqspi->f_pdata[0].nor;
+       int ret;
+       size_t count = 0;
+
+       ret = nor->read(nor, start, nblocks, &count, buf);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static struct cqspi_st cqspi;
+
+int cqspi_bio_init(struct pbl_bio *bio,
+                  void __iomem *iobase, void __iomem *ahb_base,
+                  unsigned int master_ref_clk,
+                  struct cadence_qspi_platform_data *qspi_pdata)
+{
+       cqspi.master_ref_clk_hz = master_ref_clk;
+       cqspi.iobase = iobase;
+       cqspi.ahb_base = ahb_base;
+
+       cqspi_wait_idle(&cqspi);
+       cqspi_controller_init(&cqspi);
+
+       cqspi.current_cs = -1;
+       cqspi.sclk = 0;
+
+       cqspi.is_decoded_cs = qspi_pdata->is_decoded_cs;
+       cqspi.fifo_depth = qspi_pdata->fifo_depth;
+
+       cqspi_setup_flash(&cqspi, &cqspi.f_pdata[0]);
+
+       bio->priv = &cqspi;
+       bio->read = cqspi_bio_read;
+
+       return 0;
+}
diff --git a/include/pbl/mtd.h b/include/pbl/mtd.h
new file mode 100644
index 000000000000..f58b61d29997
--- /dev/null
+++ b/include/pbl/mtd.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __PBL_MTD_H__
+#define __PBL_MTD_H__
+
+#include <linux/types.h>
+
+struct pbl_bio;
+
+#include <platform_data/cadence_qspi.h>
+
+#ifdef CONFIG_SPI_CADENCE_QUADSPI_PBL
+int cqspi_bio_init(struct pbl_bio *bio,
+                  void __iomem *iobase, void __iomem *ahb_base,
+                  unsigned int master_ref_clk,
+                  struct cadence_qspi_platform_data *qspi_pdata);
+#else
+static inline int cqspi_bio_init(struct pbl_bio *bio,
+                                void __iomem *iobase, void __iomem *ahb_base,
+                                unsigned int master_ref_clk,
+                                struct cadence_qspi_platform_data *qspi_pdata)
+{
+       return -ENOSYS;
+}
+#endif
+
+#endif /* __PBL_MTD_H__ */

-- 
2.47.3


Reply via email to