[PATCH 04/11] mtd: spi-nor: cadence: add a PBL driver

Michael Tretter m.tretter at pengutronix.de
Wed Oct 7 03:55:49 PDT 2026


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 <m.tretter at pengutronix.de>
---
 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




More information about the barebox mailing list