* [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL
@ 2026-10-07 10:55 Michael Tretter
2026-10-07 10:55 ` [PATCH 01/11] mtd: spi-nor: drop requirement for device field Michael Tretter
` (10 more replies)
0 siblings, 11 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
The image of the first stage boot loader on the Agilex 5 is limited to
approximately 256k. The SRAM is actually 512k, but there is some handoff
data at the send of the SRAM, which must not be overridden. There are
some size checks, but due to compression of the FSBL image, it's the
possible image size cannot be determined reliably.
The barebox PBL and a full featured barebox proper are easily larger
than the allowed size. Compression of the piggy data may even be counter
productive, since the entire FSBL image is compressed again when
creating the boot image.
Add support to remove the piggy data from the FSBL image, and load the
second stage (consisting of a barebox PBL and barebox proper) from flash
in the PBL.
Patches 1-4 rework the Cadence QSPI NOR flash driver to be available in
the PBL via the pbl_bio abstraction.
Patches 5-9 extend the Agilex 5 support to initialize the flash driver
in the PBL and chain load an SSBL as bl33 instead of copying the
currently running barebox. The patches also add the infrastructure to
build the PBL without piggy data and device tree.
Patches 10-11 enable the xload support in the Arrow AXE5 Eagle board.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
Michael Tretter (11):
mtd: spi-nor: drop requirement for device field
mtd: spi-nor: enable module in PBL
mtd: spi-nor: cadence: extract common part for use in PBL
mtd: spi-nor: cadence: add a PBL driver
arm: socfpga: agilex5: add bl33 xload support
arm: socfpga: agilex5: separate load and start of bl33
arm: socfpga: agilex5: enable xload for bl33
arm: socfpga: agilex5: initialize QSPI flash in PBL
arm: socfpga: agilex5: add agilex5_barebox_entry_xload
arm: socfpga: axe5-eagle: move lowlevel init to separate function
arm: socfpga: axe5-eagle: build FSBL without piggy data
arch/arm/boards/arrow-axe5-eagle/lowlevel.c | 31 +-
arch/arm/mach-socfpga/Kconfig | 43 +-
arch/arm/mach-socfpga/Makefile | 3 +
arch/arm/mach-socfpga/agilex5-xload.c | 74 +++
arch/arm/mach-socfpga/atf.c | 83 ++-
drivers/mtd/spi-nor/Kconfig | 3 +
drivers/mtd/spi-nor/Makefile | 5 +-
drivers/mtd/spi-nor/cadence-quadspi-common.c | 615 +++++++++++++++++++++
drivers/mtd/spi-nor/cadence-quadspi-pbl.c | 104 ++++
drivers/mtd/spi-nor/cadence-quadspi.c | 794 +--------------------------
drivers/mtd/spi-nor/cadence-quadspi.h | 216 ++++++++
drivers/mtd/spi-nor/spi-nor.c | 3 +-
images/Makefile.socfpga | 5 +
include/mach/socfpga/generic.h | 16 +
include/pbl/mtd.h | 26 +
15 files changed, 1210 insertions(+), 811 deletions(-)
---
base-commit: 70421fc4591e6b4b9c7172ca72b60ef1868ecc5c
change-id: 20261007-socfpga-agilex5-xload-f3f89721453b
Best regards,
--
Michael Tretter <m.tretter@pengutronix.de>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 01/11] mtd: spi-nor: drop requirement for device field
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 02/11] mtd: spi-nor: enable module in PBL Michael Tretter
` (9 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
The device field is not actually necessary. If the device is NULL,
the logging won't print the device name, but the driver is actually
fine.
Since the are no devices in the PBL, drop the check for the device field
to be able to use the functions in spi-nor.c in the PBL.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
drivers/mtd/spi-nor/spi-nor.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 73c27df51dea..1acf124cd0cf 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1086,8 +1086,7 @@ static int spansion_quad_enable(struct spi_nor *nor)
static int spi_nor_check(struct spi_nor *nor)
{
- if (!nor->dev || !nor->read || !nor->write ||
- !nor->read_reg || !nor->write_reg) {
+ if (!nor->read || !nor->write || !nor->read_reg || !nor->write_reg) {
pr_err("spi-nor: please fill all the necessary fields!\n");
return -EINVAL;
}
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 02/11] mtd: spi-nor: enable module in PBL
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
2026-10-07 10:55 ` [PATCH 01/11] mtd: spi-nor: drop requirement for device field Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 03/11] mtd: spi-nor: cadence: extract common part for use " Michael Tretter
` (8 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
Enable the spi-nor module in the PBL to be able to use the helper
functions in the PBL. This allows to have SPI NOR flash drivers in the
PBL and load barebox proper from flash.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
drivers/mtd/spi-nor/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 61cf789182fd..54d870a6f45c 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
+obj-pbl-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
obj-$(CONFIG_SPI_SYNOPSYS_OCTALSPI_NOR) += dw-ospi-nor.o
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 03/11] mtd: spi-nor: cadence: extract common part for use in PBL
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
2026-10-07 10:55 ` [PATCH 01/11] mtd: spi-nor: drop requirement for device field Michael Tretter
2026-10-07 10:55 ` [PATCH 02/11] mtd: spi-nor: enable module in PBL Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 04/11] mtd: spi-nor: cadence: add a PBL driver Michael Tretter
` (7 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
Split the driver into separate files for common functions and an
integration into barebox. This allows to use the common part in the
upcoming PBL driver.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
drivers/mtd/spi-nor/Makefile | 2 +-
drivers/mtd/spi-nor/cadence-quadspi-common.c | 615 +++++++++++++++++++++
drivers/mtd/spi-nor/cadence-quadspi.c | 794 +--------------------------
drivers/mtd/spi-nor/cadence-quadspi.h | 216 ++++++++
4 files changed, 833 insertions(+), 794 deletions(-)
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 54d870a6f45c..ed73a95ec6b9 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-pbl-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
-obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
+obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o cadence-quadspi-common.o
obj-$(CONFIG_SPI_SYNOPSYS_OCTALSPI_NOR) += dw-ospi-nor.o
diff --git a/drivers/mtd/spi-nor/cadence-quadspi-common.c b/drivers/mtd/spi-nor/cadence-quadspi-common.c
new file mode 100644
index 000000000000..401992401fa2
--- /dev/null
+++ b/drivers/mtd/spi-nor/cadence-quadspi-common.c
@@ -0,0 +1,615 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2015 Pengutronix, Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * derived from Linux kernel driver by
+ *
+ * Driver for Cadence QSPI Controller
+ *
+ * Copyright Altera Corporation (C) 2012-2014. All rights reserved.
+ */
+
+#include <common.h>
+#include <io.h>
+#include <errno.h>
+#include <linux/time.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+#include "cadence-quadspi.h"
+
+static void cqspi_fifo_read(void *dest, const void *src_ahb_addr,
+ unsigned int bytes)
+{
+ unsigned int temp;
+ int remaining = bytes;
+ unsigned int *dest_ptr = (unsigned int *)dest;
+ unsigned int *src_ptr = (unsigned int *)src_ahb_addr;
+
+ while (remaining > CQSPI_FIFO_WIDTH) {
+ *dest_ptr = readl(src_ptr);
+ dest_ptr++;
+ remaining -= CQSPI_FIFO_WIDTH;
+ }
+ if (remaining > 0) {
+ /* dangling bytes */
+ temp = readl(src_ptr);
+ memcpy(dest_ptr, &temp, remaining);
+ }
+}
+
+static int cqspi_find_chipselect(struct spi_nor *nor)
+{
+ int cs = -1;
+ struct cqspi_st *cqspi = nor->priv;
+
+ for (cs = 0; cs < CQSPI_MAX_CHIPSELECT; cs++)
+ if (nor == &cqspi->f_pdata[cs].nor)
+ break;
+ return cs;
+}
+
+unsigned int cqspi_calc_rdreg(struct spi_nor *nor, u8 opcode)
+{
+ unsigned int rdreg = 0;
+ struct cqspi_st *cqspi = nor->priv;
+ struct cqspi_flash_pdata *f_pdata;
+
+ f_pdata = &cqspi->f_pdata[cqspi->current_cs];
+
+ rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
+ rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
+ rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
+
+ return rdreg;
+}
+
+unsigned int cqspi_wait_idle(struct cqspi_st *cqspi)
+{
+ void __iomem *reg_base = cqspi->iobase;
+
+ if (wait_on_timeout(CQSPI_TIMEOUT_MS,
+ CQSPI_REG_IS_IDLE(reg_base))) {
+ /* Timeout, in busy mode. */
+ dev_err(cqspi->dev, "QSPI is still busy after %llums timeout.\n",
+ CQSPI_TIMEOUT_MS);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
+{
+ void __iomem *reg_base = cqspi->iobase;
+
+ /* Write the CMDCTRL without start execution. */
+ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
+ /* Start execute */
+ reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
+ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
+
+ if (wait_on_timeout(CQSPI_TIMEOUT_MS,
+ (readl(reg_base + CQSPI_REG_CMDCTRL) &
+ CQSPI_REG_CMDCTRL_INPROGRESS_MASK) == 0)) {
+ dev_err(cqspi->dev, "flash cmd execute time out (0x%08x)\n",
+ readl(reg_base + CQSPI_REG_CMDCTRL));
+ return -EIO;
+ }
+
+ /* Polling QSPI idle status. */
+ return cqspi_wait_idle(cqspi);
+}
+
+static int cqspi_command_read(struct spi_nor *nor,
+ const u8 *txbuf, unsigned n_tx,
+ u8 *rxbuf, unsigned n_rx)
+{
+ unsigned int reg;
+ unsigned int read_len;
+ int status;
+ struct cqspi_st *cqspi = nor->priv;
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int rdreg;
+
+ if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) {
+ dev_err(nor->dev,
+ "Invalid input argument, len %d rxbuf 0x%p\n", n_rx, rxbuf);
+ return -EINVAL;
+ }
+
+ reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+
+ rdreg = cqspi_calc_rdreg(nor, txbuf[0]);
+ writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
+
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
+
+ /* 0 means 1 byte. */
+ reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
+ << CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
+ status = cqspi_exec_flash_cmd(cqspi, reg);
+ if (status != 0)
+ return status;
+
+ reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
+
+ /* Put the read value into rx_buf */
+ read_len = (n_rx > 4) ? 4 : n_rx;
+ memcpy(rxbuf, ®, read_len);
+ rxbuf += read_len;
+
+ if (n_rx > 4) {
+ reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
+
+ read_len = n_rx - read_len;
+ memcpy(rxbuf, ®, read_len);
+ }
+
+ return 0;
+}
+
+static int cqspi_command_write(struct spi_nor *nor,
+ u8 opcode, const u8 *txbuf, unsigned n_tx)
+{
+ unsigned int reg;
+ struct cqspi_st *cqspi = nor->priv;
+ unsigned int data;
+ void __iomem *reg_base = cqspi->iobase;
+
+ if (n_tx > 4 || (n_tx && txbuf == NULL)) {
+ dev_err(nor->dev,
+ "Invalid input argument, cmdlen %d txbuf 0x%p\n", n_tx, txbuf);
+ return -EINVAL;
+ }
+
+ reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+ if (n_tx) {
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
+ reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
+ << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
+ data = 0;
+ memcpy(&data, txbuf, n_tx);
+ writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
+ }
+
+ return cqspi_exec_flash_cmd(cqspi, reg);
+}
+
+static int cqspi_indirect_read_setup(struct spi_nor *nor,
+ unsigned int from_addr)
+{
+ struct cqspi_flash_pdata *f_pdata;
+ struct cqspi_st *cqspi = nor->priv;
+ phys_addr_t ahb_base = virt_to_phys(cqspi->ahb_base);
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int dummy_clk = 0;
+ unsigned int dummy_bytes;
+ unsigned int reg = 0;
+
+ writel(ahb_base & CQSPI_INDIRECTTRIGGER_ADDR_MASK,
+ reg_base + CQSPI_REG_INDIRECTTRIGGER);
+ writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
+ f_pdata = &cqspi->f_pdata[cqspi->current_cs];
+
+ reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+ reg |= cqspi_calc_rdreg(nor, nor->read_opcode);
+
+ /* Setup dummy clock cycles */
+ dummy_bytes = nor->read_dummy / 8;
+
+ if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
+ dummy_bytes = CQSPI_DUMMY_BYTES_MAX;
+
+ if (dummy_bytes) {
+ reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
+ /* Set mode bits high to ensure chip doesn't enter XIP */
+ writel(0xFF, reg_base + CQSPI_REG_MODE_BIT);
+
+ /* Convert to clock cycles. */
+ dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
+ /* Need to subtract the mode byte (8 clocks). */
+ if (f_pdata->inst_width != CQSPI_INST_TYPE_QUAD)
+ dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;
+
+ if (dummy_clk)
+ reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
+ << CQSPI_REG_RD_INSTR_DUMMY_LSB;
+ }
+
+ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
+
+ /* Set address width */
+ reg = readl(reg_base + CQSPI_REG_SIZE);
+ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+ reg |= (nor->addr_width) - 1;
+ writel(reg, reg_base + CQSPI_REG_SIZE);
+ return 0;
+}
+
+static int cqspi_indirect_read_execute(struct spi_nor *nor,
+ u8 *rxbuf, unsigned n_rx)
+{
+ int ret = 0;
+ unsigned int reg = 0;
+ unsigned int bytes_to_read = 0;
+ unsigned int watermark;
+ struct cqspi_st *cqspi = nor->priv;
+ void __iomem *reg_base = cqspi->iobase;
+ void __iomem *ahb_base = cqspi->ahb_base;
+ int remaining = (int)n_rx;
+
+ watermark = cqspi->fifo_depth * CQSPI_FIFO_WIDTH / 2;
+ writel(watermark, reg_base + CQSPI_REG_INDIRECTRDWATERMARK);
+ writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
+
+ /* Clear all interrupts. */
+ writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
+
+ cqspi->irq_mask = CQSPI_IRQ_MASK_RD;
+ writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK);
+
+ writel(CQSPI_REG_INDIRECTRD_START_MASK,
+ reg_base + CQSPI_REG_INDIRECTRD);
+
+ while (remaining > 0) {
+ unsigned int irq_status;
+
+ ret = wait_on_timeout(CQSPI_READ_TIMEOUT_MS,
+ readl(reg_base + CQSPI_REG_IRQSTATUS) & cqspi->irq_mask);
+
+ irq_status = readl(reg_base + CQSPI_REG_IRQSTATUS);
+ bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
+
+ /* Clear all interrupts. */
+ writel(irq_status, reg_base + CQSPI_REG_IRQSTATUS);
+
+ if (!ret && bytes_to_read == 0) {
+ dev_err(nor->dev, "Indirect read timeout, no bytes\n");
+ ret = -ETIMEDOUT;
+ goto failrd;
+ }
+
+ while (bytes_to_read != 0) {
+ bytes_to_read *= CQSPI_FIFO_WIDTH;
+ bytes_to_read = bytes_to_read > remaining
+ ? remaining : bytes_to_read;
+ cqspi_fifo_read(rxbuf, ahb_base, bytes_to_read);
+ rxbuf += bytes_to_read;
+ remaining -= bytes_to_read;
+ bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
+ }
+ }
+
+ /* Check indirect done status */
+ if (wait_on_timeout(CQSPI_TIMEOUT_MS,
+ readl(reg_base + CQSPI_REG_INDIRECTRD) &
+ CQSPI_REG_INDIRECTRD_DONE_MASK)) {
+ dev_err(nor->dev,
+ "Indirect read completion error 0x%08x\n", reg);
+ ret = -ETIMEDOUT;
+ goto failrd;
+ }
+
+ /* Disable interrupt */
+ writel(0, reg_base + CQSPI_REG_IRQMASK);
+
+ /* Clear indirect completion status */
+ writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);
+
+ return 0;
+
+ failrd:
+ /* Disable interrupt */
+ writel(0, reg_base + CQSPI_REG_IRQMASK);
+
+ /* Cancel the indirect read */
+ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
+ reg_base + CQSPI_REG_INDIRECTRD);
+ return ret;
+}
+
+static void cqspi_controller_enable(struct cqspi_st *cqspi)
+{
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static void cqspi_controller_disable(struct cqspi_st *cqspi)
+{
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static void cqspi_chipselect(struct cqspi_st *cqspi,
+ unsigned int chip_select,
+ unsigned int decoder_enable)
+{
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ if (decoder_enable) {
+ reg |= CQSPI_REG_CONFIG_DECODE_MASK;
+ } else {
+ reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
+
+ /* Convert CS if without decoder.
+ * CS0 to 4b'1110
+ * CS1 to 4b'1101
+ * CS2 to 4b'1011
+ * CS3 to 4b'0111
+ */
+ chip_select = 0xF & ~(1 << chip_select);
+ }
+
+ reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
+ << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
+ reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
+ << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static unsigned int calculate_ticks_for_ns(unsigned int ref_clk_hz,
+ unsigned int ns_val)
+{
+ unsigned int ticks;
+
+ ticks = ref_clk_hz;
+ ticks /= 1000;
+ ticks *= ns_val;
+ ticks += 999999;
+ ticks /= 1000000;
+ return ticks;
+}
+
+static void cqspi_delay(struct cqspi_st *cqspi,
+ unsigned int ref_clk_hz, unsigned int sclk_hz)
+{
+ void __iomem *reg_base = cqspi->iobase;
+ struct cqspi_flash_pdata *f_pdata;
+ unsigned int ref_clk_ns;
+ unsigned int sclk_ns;
+ unsigned int tshsl, tchsh, tslch, tsd2d;
+ unsigned int reg;
+ unsigned int tsclk;
+
+ if (cqspi->no_reconfig)
+ return;
+
+ f_pdata = &cqspi->f_pdata[cqspi->current_cs];
+
+ /* Convert to ns. */
+ ref_clk_ns = NSEC_PER_SEC / ref_clk_hz;
+
+ /* Convert to ns. */
+ sclk_ns = NSEC_PER_SEC / sclk_hz;
+
+ /* calculate the number of ref ticks for one sclk tick */
+ tsclk = (ref_clk_hz + sclk_hz - 1) / sclk_hz;
+
+ tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns);
+ /* this particular value must be at least one sclk */
+ if (tshsl < tsclk)
+ tshsl = tsclk;
+
+ tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns);
+ tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns);
+ tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns);
+
+ reg = ((tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
+ << CQSPI_REG_DELAY_TSHSL_LSB);
+ reg |= ((tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
+ << CQSPI_REG_DELAY_TCHSH_LSB);
+ reg |= ((tslch & CQSPI_REG_DELAY_TSLCH_MASK)
+ << CQSPI_REG_DELAY_TSLCH_LSB);
+ reg |= ((tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
+ << CQSPI_REG_DELAY_TSD2D_LSB);
+ writel(reg, reg_base + CQSPI_REG_DELAY);
+}
+
+static void cqspi_config_baudrate_div(struct cqspi_st *cqspi,
+ unsigned int ref_clk_hz,
+ unsigned int sclk_hz)
+{
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+ unsigned int div;
+
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
+
+ div = ref_clk_hz / sclk_hz;
+
+ /* Recalculate the baudrate divisor based on QSPI specification. */
+ if (div > 32)
+ div = 32;
+
+ /* Check if even number. */
+ if (div & 1)
+ div = (div / 2);
+ else
+ div = (div / 2) - 1;
+
+ div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
+ reg |= div;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static void cqspi_readdata_capture(struct cqspi_st *cqspi,
+ unsigned int bypass, unsigned int delay)
+{
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+
+ if (cqspi->no_reconfig)
+ return;
+
+ reg = readl(reg_base + CQSPI_REG_READCAPTURE);
+
+ if (bypass)
+ reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
+ else
+ reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
+
+ reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
+ << CQSPI_REG_READCAPTURE_DELAY_LSB);
+
+ reg |= ((delay & CQSPI_REG_READCAPTURE_DELAY_MASK)
+ << CQSPI_REG_READCAPTURE_DELAY_LSB);
+
+ writel(reg, reg_base + CQSPI_REG_READCAPTURE);
+}
+
+static void cqspi_switch_cs(struct cqspi_st *cqspi, unsigned int cs)
+{
+ unsigned int reg;
+ struct cqspi_flash_pdata *f_pdata = &cqspi->f_pdata[cs];
+ void __iomem *reg_base = cqspi->iobase;
+ struct spi_nor *nor = &f_pdata->nor;
+
+ cqspi_controller_disable(cqspi);
+
+ /* configure page size and block size. */
+ reg = readl(reg_base + CQSPI_REG_SIZE);
+ reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
+ reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
+ reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB);
+ reg |= (f_pdata->block_size << CQSPI_REG_SIZE_BLOCK_LSB);
+ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+ reg |= (nor->addr_width - 1);
+ writel(reg, reg_base + CQSPI_REG_SIZE);
+
+ /* configure the chip select */
+ cqspi_chipselect(cqspi, cs, cqspi->is_decoded_cs);
+
+ cqspi_controller_enable(cqspi);
+}
+
+static int cqspi_configure(struct spi_nor *nor)
+{
+ struct cqspi_st *cqspi = nor->priv;
+ int cs = cqspi_find_chipselect(nor);
+ struct cqspi_flash_pdata *f_pdata;
+ unsigned int sclk;
+
+ /* Switch chip select. */
+ if (cqspi->current_cs != cs) {
+ cqspi->current_cs = cs;
+ cqspi_switch_cs(cqspi, cs);
+ }
+
+ /* Setup baudrate divisor and delays */
+ f_pdata = &cqspi->f_pdata[cqspi->current_cs];
+ sclk = f_pdata->clk_rate;
+ if (cqspi->sclk != sclk) {
+ cqspi->sclk = sclk;
+ cqspi_controller_disable(cqspi);
+ cqspi_config_baudrate_div(cqspi,
+ cqspi->master_ref_clk_hz, sclk);
+ cqspi_delay(cqspi, cqspi->master_ref_clk_hz, sclk);
+ cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay);
+ cqspi_controller_enable(cqspi);
+ }
+ return 0;
+}
+
+int cqspi_set_protocol(struct spi_nor *nor, const int read)
+{
+ struct cqspi_st *cqspi = nor->priv;
+ struct cqspi_flash_pdata *f_pdata;
+ int cs = cqspi_find_chipselect(nor);
+
+ if (cs < 0)
+ return -EINVAL;
+
+ f_pdata = &cqspi->f_pdata[cs];
+
+ f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
+ f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
+ f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
+
+ if (read) {
+ switch (nor->read_proto) {
+ case SNOR_PROTO_1_1_1:
+ f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
+ break;
+ case SNOR_PROTO_1_1_2:
+ f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
+ break;
+ case SNOR_PROTO_1_1_4:
+ f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ cqspi_configure(nor);
+
+ return 0;
+}
+
+int cqspi_read(struct spi_nor *nor, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+{
+ int ret;
+
+ ret = cqspi_set_protocol(nor, 1);
+ if (ret)
+ return ret;
+
+ ret = cqspi_indirect_read_setup(nor, from);
+ if (ret == 0) {
+ ret = cqspi_indirect_read_execute(nor, buf, len);
+ if (ret == 0)
+ *retlen += len;
+ }
+ return ret;
+}
+
+int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+ int ret;
+
+ ret = cqspi_set_protocol(nor, 0);
+ if (!ret)
+ ret = cqspi_command_read(nor, &opcode, 1, buf, len);
+
+ return ret;
+}
+
+int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+ int ret = 0;
+
+ if (!IS_ENABLED(CONFIG_MTD_WRITE))
+ return -ENOTSUPP;
+
+ ret = cqspi_set_protocol(nor, 0);
+ if (!ret)
+ ret = cqspi_command_write(nor, opcode, buf, len);
+
+ return ret;
+}
+
+void cqspi_controller_init(struct cqspi_st *cqspi)
+{
+ cqspi_controller_disable(cqspi);
+
+ /* Configure the remap address register, no remap */
+ writel(0, cqspi->iobase + CQSPI_REG_REMAP);
+
+ /* Disable all interrupts */
+ writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
+
+ cqspi_controller_enable(cqspi);
+}
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 56af62dd1733..7c160fa2e0d7 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -22,223 +22,7 @@
#include <platform_data/cadence_qspi.h>
#include <spi/spi.h>
-#define CQSPI_MAX_CHIPSELECT 16
-
-struct cqspi_flash_pdata {
- struct mtd_info mtd;
- struct spi_nor nor;
- u32 clk_rate;
- unsigned int block_size;
- unsigned int read_delay;
- unsigned int tshsl_ns;
- unsigned int tsd2d_ns;
- unsigned int tchsh_ns;
- unsigned int tslch_ns;
- u8 inst_width;
- u8 addr_width;
- u8 data_width;
-};
-
-struct cqspi_st {
- struct device *dev;
- struct clk *l4_mp_clk;
- struct clk *qspi_clk;
- unsigned int sclk;
-
- void __iomem *iobase;
- void __iomem *ahb_base;
- unsigned int irq_mask;
- int current_cs;
- unsigned int master_ref_clk_hz;
- unsigned int is_decoded_cs;
- unsigned int fifo_depth;
- struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
- bool no_reconfig;
-};
-
-/* Operation timeout value */
-#define CQSPI_TIMEOUT_MS 800 * MSECOND
-#define CQSPI_READ_TIMEOUT_MS 100 * MSECOND
-#define CQSPI_POLL_IDLE_RETRY 3
-
-#define CQSPI_FIFO_WIDTH 4
-
-#define CQSPI_REG_SRAM_THRESHOLD_BYTES 50
-
-/* Instruction type */
-#define CQSPI_INST_TYPE_SINGLE 0
-#define CQSPI_INST_TYPE_DUAL 1
-#define CQSPI_INST_TYPE_QUAD 2
-
-#define CQSPI_DUMMY_CLKS_PER_BYTE 8
-#define CQSPI_DUMMY_BYTES_MAX 4
-
-#define CQSPI_STIG_DATA_LEN_MAX 8
-
-#define CQSPI_INDIRECTTRIGGER_ADDR_MASK 0xFFFFF
-
-/* Register map */
-#define CQSPI_REG_CONFIG 0x00
-#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
-#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
-#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
-#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
-#define CQSPI_REG_CONFIG_BAUD_LSB 19
-#define CQSPI_REG_CONFIG_IDLE_LSB 31
-#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
-#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
-
-#define CQSPI_REG_RD_INSTR 0x04
-#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
-#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
-#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
-#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
-#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
-#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
-#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
-#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
-#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
-#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
-
-#define CQSPI_REG_WR_INSTR 0x08
-#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
-#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
-#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
-
-#define CQSPI_REG_DELAY 0x0C
-#define CQSPI_REG_DELAY_TSLCH_LSB 0
-#define CQSPI_REG_DELAY_TCHSH_LSB 8
-#define CQSPI_REG_DELAY_TSD2D_LSB 16
-#define CQSPI_REG_DELAY_TSHSL_LSB 24
-#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
-#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
-#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
-#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
-
-#define CQSPI_REG_READCAPTURE 0x10
-#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0
-#define CQSPI_REG_READCAPTURE_DELAY_LSB 1
-#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF
-
-#define CQSPI_REG_SIZE 0x14
-#define CQSPI_REG_SIZE_ADDRESS_LSB 0
-#define CQSPI_REG_SIZE_PAGE_LSB 4
-#define CQSPI_REG_SIZE_BLOCK_LSB 16
-#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
-#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
-#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
-
-#define CQSPI_REG_SRAMPARTITION 0x18
-#define CQSPI_REG_INDIRECTTRIGGER 0x1C
-
-#define CQSPI_REG_DMA 0x20
-#define CQSPI_REG_DMA_SINGLE_LSB 0
-#define CQSPI_REG_DMA_BURST_LSB 8
-#define CQSPI_REG_DMA_SINGLE_MASK 0xFF
-#define CQSPI_REG_DMA_BURST_MASK 0xFF
-
-#define CQSPI_REG_REMAP 0x24
-#define CQSPI_REG_MODE_BIT 0x28
-
-#define CQSPI_REG_SRAMLEVEL 0x2C
-#define CQSPI_REG_SRAMLEVEL_RD_LSB 0
-#define CQSPI_REG_SRAMLEVEL_WR_LSB 16
-#define CQSPI_REG_SRAMLEVEL_RD_MASK 0xFFFF
-#define CQSPI_REG_SRAMLEVEL_WR_MASK 0xFFFF
-
-#define CQSPI_REG_IRQSTATUS 0x40
-#define CQSPI_REG_IRQMASK 0x44
-
-#define CQSPI_REG_INDIRECTRD 0x60
-#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0)
-#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1)
-#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5)
-
-#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
-#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
-#define CQSPI_REG_INDIRECTRDBYTES 0x6C
-
-#define CQSPI_REG_CMDCTRL 0x90
-#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0)
-#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1)
-#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
-#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
-#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
-#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
-#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
-#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
-#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
-#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
-#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
-#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
-
-#define CQSPI_REG_INDIRECTWR 0x70
-#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0)
-#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1)
-#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5)
-
-#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
-#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
-#define CQSPI_REG_INDIRECTWRBYTES 0x7C
-
-#define CQSPI_REG_CMDADDRESS 0x94
-#define CQSPI_REG_CMDREADDATALOWER 0xA0
-#define CQSPI_REG_CMDREADDATAUPPER 0xA4
-#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
-#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
-
-/* Interrupt status bits */
-#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
-#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
-#define CQSPI_REG_IRQ_IND_COMP BIT(2)
-#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3)
-#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4)
-#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5)
-#define CQSPI_REG_IRQ_WATERMARK BIT(6)
-#define CQSPI_REG_IRQ_IND_RD_OVERFLOW BIT(12)
-
-#define CQSPI_IRQ_STATUS_ERR (CQSPI_REG_IRQ_MODE_ERR | \
- CQSPI_REG_IRQ_IND_RD_REJECT | \
- CQSPI_REG_IRQ_WR_PROTECTED_ERR | \
- CQSPI_REG_IRQ_ILLEGAL_AHB_ERR)
-
-#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \
- CQSPI_REG_IRQ_IND_RD_OVERFLOW | \
- CQSPI_REG_IRQ_IND_COMP)
-
-#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \
- CQSPI_REG_IRQ_WATERMARK | \
- CQSPI_REG_IRQ_UNDERFLOW)
-
-#define CQSPI_IRQ_STATUS_MASK 0x1FFFE
-
-#define CQSPI_REG_IS_IDLE(base) \
- ((readl(base + CQSPI_REG_CONFIG) >> \
- CQSPI_REG_CONFIG_IDLE_LSB) & 0x1)
-
-#define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \
- (((readl(reg_base + CQSPI_REG_SRAMLEVEL)) >> \
- CQSPI_REG_SRAMLEVEL_RD_LSB) & CQSPI_REG_SRAMLEVEL_RD_MASK)
-
-static void cqspi_fifo_read(void *dest, const void *src_ahb_addr,
- unsigned int bytes)
-{
- unsigned int temp;
- int remaining = bytes;
- unsigned int *dest_ptr = (unsigned int *)dest;
- unsigned int *src_ptr = (unsigned int *)src_ahb_addr;
-
- while (remaining > CQSPI_FIFO_WIDTH) {
- *dest_ptr = readl(src_ptr);
- dest_ptr++;
- remaining -= CQSPI_FIFO_WIDTH;
- }
- if (remaining > 0) {
- /* dangling bytes */
- temp = readl(src_ptr);
- memcpy(dest_ptr, &temp, remaining);
- }
-}
+#include "cadence-quadspi.h"
static void cqspi_fifo_write(void *dest_ahb_addr,
const void *src, unsigned int bytes)
@@ -260,144 +44,6 @@ static void cqspi_fifo_write(void *dest_ahb_addr,
}
}
-static int cqspi_find_chipselect(struct spi_nor *nor)
-{
- int cs = -1;
- struct cqspi_st *cqspi = nor->priv;
-
- for (cs = 0; cs < CQSPI_MAX_CHIPSELECT; cs++)
- if (nor == &cqspi->f_pdata[cs].nor)
- break;
- return cs;
-}
-
-static unsigned int cqspi_calc_rdreg(struct spi_nor *nor, u8 opcode)
-{
- unsigned int rdreg = 0;
- struct cqspi_st *cqspi = nor->priv;
- struct cqspi_flash_pdata *f_pdata;
-
- f_pdata = &cqspi->f_pdata[cqspi->current_cs];
-
- rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
- rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
- rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
-
- return rdreg;
-}
-
-static unsigned int cqspi_wait_idle(struct cqspi_st *cqspi)
-{
- void __iomem *reg_base = cqspi->iobase;
-
- if (wait_on_timeout(CQSPI_TIMEOUT_MS,
- CQSPI_REG_IS_IDLE(reg_base))) {
- /* Timeout, in busy mode. */
- dev_err(cqspi->dev, "QSPI is still busy after %llums timeout.\n",
- CQSPI_TIMEOUT_MS);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
-{
- void __iomem *reg_base = cqspi->iobase;
-
- /* Write the CMDCTRL without start execution. */
- writel(reg, reg_base + CQSPI_REG_CMDCTRL);
- /* Start execute */
- reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
- writel(reg, reg_base + CQSPI_REG_CMDCTRL);
-
- if (wait_on_timeout(CQSPI_TIMEOUT_MS,
- (readl(reg_base + CQSPI_REG_CMDCTRL) &
- CQSPI_REG_CMDCTRL_INPROGRESS_MASK) == 0)) {
- dev_err(cqspi->dev, "flash cmd execute time out (0x%08x)\n",
- readl(reg_base + CQSPI_REG_CMDCTRL));
- return -EIO;
- }
-
- /* Polling QSPI idle status. */
- return cqspi_wait_idle(cqspi);
-}
-
-static int cqspi_command_read(struct spi_nor *nor,
- const u8 *txbuf, unsigned n_tx,
- u8 *rxbuf, unsigned n_rx)
-{
- unsigned int reg;
- unsigned int read_len;
- int status;
- struct cqspi_st *cqspi = nor->priv;
- void __iomem *reg_base = cqspi->iobase;
- unsigned int rdreg;
-
- if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) {
- dev_err(nor->dev,
- "Invalid input argument, len %d rxbuf 0x%p\n", n_rx, rxbuf);
- return -EINVAL;
- }
-
- reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
-
- rdreg = cqspi_calc_rdreg(nor, txbuf[0]);
- writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
-
- reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
-
- /* 0 means 1 byte. */
- reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
- << CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
- status = cqspi_exec_flash_cmd(cqspi, reg);
- if (status != 0)
- return status;
-
- reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
-
- /* Put the read value into rx_buf */
- read_len = (n_rx > 4) ? 4 : n_rx;
- memcpy(rxbuf, ®, read_len);
- rxbuf += read_len;
-
- if (n_rx > 4) {
- reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
-
- read_len = n_rx - read_len;
- memcpy(rxbuf, ®, read_len);
- }
-
- return 0;
-}
-
-static __maybe_unused int cqspi_command_write(struct spi_nor *nor,
- u8 opcode, const u8 *txbuf, unsigned n_tx)
-{
- unsigned int reg;
- unsigned int data;
- struct cqspi_st *cqspi = nor->priv;
- void __iomem *reg_base = cqspi->iobase;
-
- if (n_tx > 4 || (n_tx && txbuf == NULL)) {
- dev_err(nor->dev,
- "Invalid input argument, cmdlen %d txbuf 0x%p\n", n_tx, txbuf);
- return -EINVAL;
- }
-
- reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
- if (n_tx) {
- reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
- reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
- << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
- data = 0;
- memcpy(&data, txbuf, n_tx);
- writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
- }
-
- return cqspi_exec_flash_cmd(cqspi, reg);
-}
-
static int cqspi_command_write_addr(struct spi_nor *nor,
u8 opcode, unsigned int addr)
{
@@ -415,139 +61,6 @@ static int cqspi_command_write_addr(struct spi_nor *nor,
return cqspi_exec_flash_cmd(cqspi, reg);
}
-static int cqspi_indirect_read_setup(struct spi_nor *nor,
- unsigned int from_addr)
-{
- struct cqspi_flash_pdata *f_pdata;
- struct cqspi_st *cqspi = nor->priv;
- phys_addr_t ahb_base = virt_to_phys(cqspi->ahb_base);
- void __iomem *reg_base = cqspi->iobase;
- unsigned int dummy_clk = 0;
- unsigned int dummy_bytes;
- unsigned int reg = 0;
-
- writel(ahb_base & CQSPI_INDIRECTTRIGGER_ADDR_MASK,
- reg_base + CQSPI_REG_INDIRECTTRIGGER);
- writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
- f_pdata = &cqspi->f_pdata[cqspi->current_cs];
-
- reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
- reg |= cqspi_calc_rdreg(nor, nor->read_opcode);
-
- /* Setup dummy clock cycles */
- dummy_bytes = nor->read_dummy / 8;
-
- if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
- dummy_bytes = CQSPI_DUMMY_BYTES_MAX;
-
- if (dummy_bytes) {
- reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
- /* Set mode bits high to ensure chip doesn't enter XIP */
- writel(0xFF, reg_base + CQSPI_REG_MODE_BIT);
-
- /* Convert to clock cycles. */
- dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
- /* Need to subtract the mode byte (8 clocks). */
- if (f_pdata->inst_width != CQSPI_INST_TYPE_QUAD)
- dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;
-
- if (dummy_clk)
- reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
- << CQSPI_REG_RD_INSTR_DUMMY_LSB;
- }
-
- writel(reg, reg_base + CQSPI_REG_RD_INSTR);
-
- /* Set address width */
- reg = readl(reg_base + CQSPI_REG_SIZE);
- reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
- reg |= (nor->addr_width) - 1;
- writel(reg, reg_base + CQSPI_REG_SIZE);
- return 0;
-}
-
-static int cqspi_indirect_read_execute(struct spi_nor *nor,
- u8 *rxbuf, unsigned n_rx)
-{
- int ret = 0;
- unsigned int reg = 0;
- unsigned int bytes_to_read = 0;
- unsigned int watermark;
- struct cqspi_st *cqspi = nor->priv;
- void __iomem *reg_base = cqspi->iobase;
- void __iomem *ahb_base = cqspi->ahb_base;
- int remaining = (int)n_rx;
-
- watermark = cqspi->fifo_depth * CQSPI_FIFO_WIDTH / 2;
- writel(watermark, reg_base + CQSPI_REG_INDIRECTRDWATERMARK);
- writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
-
- /* Clear all interrupts. */
- writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
-
- cqspi->irq_mask = CQSPI_IRQ_MASK_RD;
- writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK);
-
- writel(CQSPI_REG_INDIRECTRD_START_MASK,
- reg_base + CQSPI_REG_INDIRECTRD);
-
- while (remaining > 0) {
- unsigned int irq_status;
-
- ret = wait_on_timeout(CQSPI_READ_TIMEOUT_MS,
- readl(reg_base + CQSPI_REG_IRQSTATUS) & cqspi->irq_mask);
-
- irq_status = readl(reg_base + CQSPI_REG_IRQSTATUS);
- bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
-
- /* Clear all interrupts. */
- writel(irq_status, reg_base + CQSPI_REG_IRQSTATUS);
-
- if (!ret && bytes_to_read == 0) {
- dev_err(nor->dev, "Indirect read timeout, no bytes\n");
- ret = -ETIMEDOUT;
- goto failrd;
- }
-
- while (bytes_to_read != 0) {
- bytes_to_read *= CQSPI_FIFO_WIDTH;
- bytes_to_read = bytes_to_read > remaining
- ? remaining : bytes_to_read;
- cqspi_fifo_read(rxbuf, ahb_base, bytes_to_read);
- rxbuf += bytes_to_read;
- remaining -= bytes_to_read;
- bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
- }
- }
-
- /* Check indirect done status */
- if (wait_on_timeout(CQSPI_TIMEOUT_MS,
- readl(reg_base + CQSPI_REG_INDIRECTRD) &
- CQSPI_REG_INDIRECTRD_DONE_MASK)) {
- dev_err(nor->dev,
- "Indirect read completion error 0x%08x\n", reg);
- ret = -ETIMEDOUT;
- goto failrd;
- }
-
- /* Disable interrupt */
- writel(0, reg_base + CQSPI_REG_IRQMASK);
-
- /* Clear indirect completion status */
- writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);
-
- return 0;
-
- failrd:
- /* Disable interrupt */
- writel(0, reg_base + CQSPI_REG_IRQMASK);
-
- /* Cancel the indirect read */
- writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
- reg_base + CQSPI_REG_INDIRECTRD);
- return ret;
-}
-
static __maybe_unused int cqspi_indirect_write_setup(struct spi_nor *nor,
unsigned int to_addr)
{
@@ -666,255 +179,6 @@ static __maybe_unused int cqspi_indirect_write_execute(struct spi_nor *nor,
return ret;
}
-static void cqspi_controller_enable(struct cqspi_st *cqspi)
-{
- void __iomem *reg_base = cqspi->iobase;
- unsigned int reg;
-
- reg = readl(reg_base + CQSPI_REG_CONFIG);
- reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
- writel(reg, reg_base + CQSPI_REG_CONFIG);
-}
-
-static void cqspi_controller_disable(struct cqspi_st *cqspi)
-{
- void __iomem *reg_base = cqspi->iobase;
- unsigned int reg;
-
- reg = readl(reg_base + CQSPI_REG_CONFIG);
- reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
- writel(reg, reg_base + CQSPI_REG_CONFIG);
-}
-
-static void cqspi_chipselect(struct cqspi_st *cqspi,
- unsigned int chip_select,
- unsigned int decoder_enable)
-{
- void __iomem *reg_base = cqspi->iobase;
- unsigned int reg;
-
- reg = readl(reg_base + CQSPI_REG_CONFIG);
- if (decoder_enable) {
- reg |= CQSPI_REG_CONFIG_DECODE_MASK;
- } else {
- reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
-
- /* Convert CS if without decoder.
- * CS0 to 4b'1110
- * CS1 to 4b'1101
- * CS2 to 4b'1011
- * CS3 to 4b'0111
- */
- chip_select = 0xF & ~(1 << chip_select);
- }
-
- reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
- << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
- reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
- << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
- writel(reg, reg_base + CQSPI_REG_CONFIG);
-}
-
-static unsigned int calculate_ticks_for_ns(unsigned int ref_clk_hz,
- unsigned int ns_val)
-{
- unsigned int ticks;
-
- ticks = ref_clk_hz;
- ticks /= 1000;
- ticks *= ns_val;
- ticks += 999999;
- ticks /= 1000000;
- return ticks;
-}
-
-static void cqspi_delay(struct cqspi_st *cqspi,
- unsigned int ref_clk_hz, unsigned int sclk_hz)
-{
- void __iomem *reg_base = cqspi->iobase;
- struct cqspi_flash_pdata *f_pdata;
- unsigned int ref_clk_ns;
- unsigned int sclk_ns;
- unsigned int tshsl, tchsh, tslch, tsd2d;
- unsigned int reg;
- unsigned int tsclk;
-
- if (cqspi->no_reconfig)
- return;
-
- f_pdata = &cqspi->f_pdata[cqspi->current_cs];
-
- /* Convert to ns. */
- ref_clk_ns = NSEC_PER_SEC / ref_clk_hz;
-
- /* Convert to ns. */
- sclk_ns = NSEC_PER_SEC / sclk_hz;
-
- /* calculate the number of ref ticks for one sclk tick */
- tsclk = (ref_clk_hz + sclk_hz - 1) / sclk_hz;
-
- tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns);
- /* this particular value must be at least one sclk */
- if (tshsl < tsclk)
- tshsl = tsclk;
-
- tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns);
- tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns);
- tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns);
-
- reg = ((tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
- << CQSPI_REG_DELAY_TSHSL_LSB);
- reg |= ((tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
- << CQSPI_REG_DELAY_TCHSH_LSB);
- reg |= ((tslch & CQSPI_REG_DELAY_TSLCH_MASK)
- << CQSPI_REG_DELAY_TSLCH_LSB);
- reg |= ((tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
- << CQSPI_REG_DELAY_TSD2D_LSB);
- writel(reg, reg_base + CQSPI_REG_DELAY);
-}
-
-static void cqspi_config_baudrate_div(struct cqspi_st *cqspi,
- unsigned int ref_clk_hz,
- unsigned int sclk_hz)
-{
- void __iomem *reg_base = cqspi->iobase;
- unsigned int reg;
- unsigned int div;
-
- reg = readl(reg_base + CQSPI_REG_CONFIG);
- reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
-
- div = ref_clk_hz / sclk_hz;
-
- /* Recalculate the baudrate divisor based on QSPI specification. */
- if (div > 32)
- div = 32;
-
- /* Check if even number. */
- if (div & 1)
- div = (div / 2);
- else
- div = (div / 2) - 1;
-
- div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
- reg |= div;
- writel(reg, reg_base + CQSPI_REG_CONFIG);
-}
-
-static void cqspi_readdata_capture(struct cqspi_st *cqspi,
- unsigned int bypass, unsigned int delay)
-{
- void __iomem *reg_base = cqspi->iobase;
- unsigned int reg;
-
- if (cqspi->no_reconfig)
- return;
-
- reg = readl(reg_base + CQSPI_REG_READCAPTURE);
-
- if (bypass)
- reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
- else
- reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
-
- reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
- << CQSPI_REG_READCAPTURE_DELAY_LSB);
-
- reg |= ((delay & CQSPI_REG_READCAPTURE_DELAY_MASK)
- << CQSPI_REG_READCAPTURE_DELAY_LSB);
-
- writel(reg, reg_base + CQSPI_REG_READCAPTURE);
-}
-
-static void cqspi_switch_cs(struct cqspi_st *cqspi, unsigned int cs)
-{
- unsigned int reg;
- struct cqspi_flash_pdata *f_pdata = &cqspi->f_pdata[cs];
- void __iomem *reg_base = cqspi->iobase;
- struct spi_nor *nor = &f_pdata->nor;
-
- cqspi_controller_disable(cqspi);
-
- /* configure page size and block size. */
- reg = readl(reg_base + CQSPI_REG_SIZE);
- reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
- reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
- reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB);
- reg |= (f_pdata->block_size << CQSPI_REG_SIZE_BLOCK_LSB);
- reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
- reg |= (nor->addr_width - 1);
- writel(reg, reg_base + CQSPI_REG_SIZE);
-
- /* configure the chip select */
- cqspi_chipselect(cqspi, cs, cqspi->is_decoded_cs);
-
- cqspi_controller_enable(cqspi);
-}
-
-static int cqspi_configure(struct spi_nor *nor)
-{
- struct cqspi_st *cqspi = nor->priv;
- int cs = cqspi_find_chipselect(nor);
- struct cqspi_flash_pdata *f_pdata;
- unsigned int sclk;
-
- /* Switch chip select. */
- if (cqspi->current_cs != cs) {
- cqspi->current_cs = cs;
- cqspi_switch_cs(cqspi, cs);
- }
-
- /* Setup baudrate divisor and delays */
- f_pdata = &cqspi->f_pdata[cqspi->current_cs];
- sclk = f_pdata->clk_rate;
- if (cqspi->sclk != sclk) {
- cqspi->sclk = sclk;
- cqspi_controller_disable(cqspi);
- cqspi_config_baudrate_div(cqspi,
- cqspi->master_ref_clk_hz, sclk);
- cqspi_delay(cqspi, cqspi->master_ref_clk_hz, sclk);
- cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay);
- cqspi_controller_enable(cqspi);
- }
- return 0;
-}
-
-static int cqspi_set_protocol(struct spi_nor *nor, const int read)
-{
- struct cqspi_st *cqspi = nor->priv;
- struct cqspi_flash_pdata *f_pdata;
- int cs = cqspi_find_chipselect(nor);
-
- if (cs < 0)
- return -EINVAL;
-
- f_pdata = &cqspi->f_pdata[cs];
-
- f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
- f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
- f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
-
- if (read) {
- switch (nor->read_proto) {
- case SNOR_PROTO_1_1_1:
- f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
- break;
- case SNOR_PROTO_1_1_2:
- f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
- break;
- case SNOR_PROTO_1_1_4:
- f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
- break;
- default:
- return -EINVAL;
- }
- }
-
- cqspi_configure(nor);
-
- return 0;
-}
-
static void cqspi_write(struct spi_nor *nor, loff_t to,
size_t len, size_t *retlen, const u_char *buf)
{
@@ -935,24 +199,6 @@ static void cqspi_write(struct spi_nor *nor, loff_t to,
}
}
-static int cqspi_read(struct spi_nor *nor, loff_t from,
- size_t len, size_t *retlen, u_char *buf)
-{
- int ret;
-
- ret = cqspi_set_protocol(nor, 1);
- if (ret)
- return ret;
-
- ret = cqspi_indirect_read_setup(nor, from);
- if (ret == 0) {
- ret = cqspi_indirect_read_execute(nor, buf, len);
- if (ret == 0)
- *retlen += len;
- }
- return ret;
-}
-
static int cqspi_erase(struct spi_nor *nor, loff_t offs)
{
int ret;
@@ -974,31 +220,6 @@ static int cqspi_erase(struct spi_nor *nor, loff_t offs)
return 0;
}
-static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
-{
- int ret;
-
- ret = cqspi_set_protocol(nor, 0);
- if (!ret)
- ret = cqspi_command_read(nor, &opcode, 1, buf, len);
-
- return ret;
-}
-
-static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
-{
- int ret = 0;
-
- if (!IS_ENABLED(CONFIG_MTD_WRITE))
- return -ENOTSUPP;
-
- ret = cqspi_set_protocol(nor, 0);
- if (!ret)
- ret = cqspi_command_write(nor, opcode, buf, len);
-
- return ret;
-}
-
static int cqspi_of_get_flash_pdata(struct device *dev,
struct cqspi_flash_pdata *f_pdata,
struct device_node *np)
@@ -1137,19 +358,6 @@ static int cqspi_setup_flash(struct device *dev,
}
-static void cqspi_controller_init(struct cqspi_st *cqspi)
-{
- cqspi_controller_disable(cqspi);
-
- /* Configure the remap address register, no remap */
- writel(0, cqspi->iobase + CQSPI_REG_REMAP);
-
- /* Disable all interrupts */
- writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
-
- cqspi_controller_enable(cqspi);
-}
-
static int cqspi_probe(struct device *dev)
{
struct resource *iores;
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.h b/drivers/mtd/spi-nor/cadence-quadspi.h
new file mode 100644
index 000000000000..82e2a45efdef
--- /dev/null
+++ b/drivers/mtd/spi-nor/cadence-quadspi.h
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+#include <clock.h>
+
+#define CQSPI_FIFO_WIDTH 4
+
+#define CQSPI_REG_SRAM_THRESHOLD_BYTES 50
+
+/* Instruction type */
+#define CQSPI_INST_TYPE_SINGLE 0
+#define CQSPI_INST_TYPE_DUAL 1
+#define CQSPI_INST_TYPE_QUAD 2
+
+#define CQSPI_DUMMY_CLKS_PER_BYTE 8
+#define CQSPI_DUMMY_BYTES_MAX 4
+
+#define CQSPI_STIG_DATA_LEN_MAX 8
+
+#define CQSPI_INDIRECTTRIGGER_ADDR_MASK 0xFFFFF
+
+/* Register map */
+#define CQSPI_REG_CONFIG 0x00
+#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
+#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
+#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
+#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
+#define CQSPI_REG_CONFIG_BAUD_LSB 19
+#define CQSPI_REG_CONFIG_IDLE_LSB 31
+#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
+#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
+
+#define CQSPI_REG_RD_INSTR 0x04
+#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
+#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
+#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
+#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
+
+#define CQSPI_REG_WR_INSTR 0x08
+#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
+#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
+#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
+
+#define CQSPI_REG_DELAY 0x0C
+#define CQSPI_REG_DELAY_TSLCH_LSB 0
+#define CQSPI_REG_DELAY_TCHSH_LSB 8
+#define CQSPI_REG_DELAY_TSD2D_LSB 16
+#define CQSPI_REG_DELAY_TSHSL_LSB 24
+#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
+#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
+#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
+#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
+
+#define CQSPI_REG_READCAPTURE 0x10
+#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0
+#define CQSPI_REG_READCAPTURE_DELAY_LSB 1
+#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF
+
+#define CQSPI_REG_SIZE 0x14
+#define CQSPI_REG_SIZE_ADDRESS_LSB 0
+#define CQSPI_REG_SIZE_PAGE_LSB 4
+#define CQSPI_REG_SIZE_BLOCK_LSB 16
+#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
+#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
+#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
+
+#define CQSPI_REG_SRAMPARTITION 0x18
+#define CQSPI_REG_INDIRECTTRIGGER 0x1C
+
+#define CQSPI_REG_DMA 0x20
+#define CQSPI_REG_DMA_SINGLE_LSB 0
+#define CQSPI_REG_DMA_BURST_LSB 8
+#define CQSPI_REG_DMA_SINGLE_MASK 0xFF
+#define CQSPI_REG_DMA_BURST_MASK 0xFF
+
+#define CQSPI_REG_REMAP 0x24
+#define CQSPI_REG_MODE_BIT 0x28
+
+#define CQSPI_REG_SRAMLEVEL 0x2C
+#define CQSPI_REG_SRAMLEVEL_RD_LSB 0
+#define CQSPI_REG_SRAMLEVEL_WR_LSB 16
+#define CQSPI_REG_SRAMLEVEL_RD_MASK 0xFFFF
+#define CQSPI_REG_SRAMLEVEL_WR_MASK 0xFFFF
+
+#define CQSPI_REG_IRQSTATUS 0x40
+#define CQSPI_REG_IRQMASK 0x44
+
+#define CQSPI_REG_INDIRECTRD 0x60
+#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0)
+#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1)
+#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5)
+
+#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
+#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
+#define CQSPI_REG_INDIRECTRDBYTES 0x6C
+
+#define CQSPI_REG_CMDCTRL 0x90
+#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0)
+#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1)
+#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
+#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
+#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
+#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
+#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
+#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
+#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
+#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
+
+#define CQSPI_REG_INDIRECTWR 0x70
+#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0)
+#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1)
+#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5)
+
+#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
+#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
+#define CQSPI_REG_INDIRECTWRBYTES 0x7C
+
+#define CQSPI_REG_CMDADDRESS 0x94
+#define CQSPI_REG_CMDREADDATALOWER 0xA0
+#define CQSPI_REG_CMDREADDATAUPPER 0xA4
+#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
+#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
+
+/* Interrupt status bits */
+#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
+#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
+#define CQSPI_REG_IRQ_IND_COMP BIT(2)
+#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3)
+#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4)
+#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5)
+#define CQSPI_REG_IRQ_WATERMARK BIT(6)
+#define CQSPI_REG_IRQ_IND_RD_OVERFLOW BIT(12)
+
+#define CQSPI_IRQ_STATUS_ERR (CQSPI_REG_IRQ_MODE_ERR | \
+ CQSPI_REG_IRQ_IND_RD_REJECT | \
+ CQSPI_REG_IRQ_WR_PROTECTED_ERR | \
+ CQSPI_REG_IRQ_ILLEGAL_AHB_ERR)
+
+#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \
+ CQSPI_REG_IRQ_IND_RD_OVERFLOW | \
+ CQSPI_REG_IRQ_IND_COMP)
+
+#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \
+ CQSPI_REG_IRQ_WATERMARK | \
+ CQSPI_REG_IRQ_UNDERFLOW)
+
+#define CQSPI_IRQ_STATUS_MASK 0x1FFFE
+
+#define CQSPI_MAX_CHIPSELECT 16
+
+struct cqspi_flash_pdata {
+ struct mtd_info mtd;
+ struct spi_nor nor;
+ u32 clk_rate;
+ unsigned int block_size;
+ unsigned int read_delay;
+ unsigned int tshsl_ns;
+ unsigned int tsd2d_ns;
+ unsigned int tchsh_ns;
+ unsigned int tslch_ns;
+ u8 inst_width;
+ u8 addr_width;
+ u8 data_width;
+};
+
+struct cqspi_st {
+ struct device *dev;
+ struct clk *l4_mp_clk;
+ struct clk *qspi_clk;
+ unsigned int sclk;
+
+ void __iomem *iobase;
+ void __iomem *ahb_base;
+ unsigned int irq_mask;
+ int current_cs;
+ unsigned int master_ref_clk_hz;
+ unsigned int is_decoded_cs;
+ unsigned int fifo_depth;
+ struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
+ bool no_reconfig;
+};
+
+#define CQSPI_REG_IS_IDLE(base) \
+ ((readl(base + CQSPI_REG_CONFIG) >> \
+ CQSPI_REG_CONFIG_IDLE_LSB) & 0x1)
+
+#define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \
+ (((readl(reg_base + CQSPI_REG_SRAMLEVEL)) >> \
+ CQSPI_REG_SRAMLEVEL_RD_LSB) & CQSPI_REG_SRAMLEVEL_RD_MASK)
+
+#define CQSPI_TIMEOUT_MS (800 * MSECOND)
+#define CQSPI_READ_TIMEOUT_MS (100 * MSECOND)
+
+void cqspi_controller_init(struct cqspi_st *cqspi);
+
+int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg);
+
+unsigned int cqspi_calc_rdreg(struct spi_nor *nor, u8 opcode);
+
+unsigned int cqspi_wait_idle(struct cqspi_st *cqspi);
+
+int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+int cqspi_read(struct spi_nor *nor, loff_t from, size_t len,
+ size_t *retlen, u_char *buf);
+
+int cqspi_set_protocol(struct spi_nor *nor, const int read);
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 04/11] mtd: spi-nor: cadence: add a PBL driver
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (2 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 03/11] mtd: spi-nor: cadence: extract common part for use " Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 05/11] arm: socfpga: agilex5: add bl33 xload support Michael Tretter
` (6 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
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@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
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 05/11] arm: socfpga: agilex5: add bl33 xload support
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (3 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 04/11] mtd: spi-nor: cadence: add a PBL driver Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 06/11] arm: socfpga: agilex5: separate load and start of bl33 Michael Tretter
` (5 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
The size of the FSBL on Agilex 5 is limited by the size of the available
SRAM (512k), but there are additional limits imposed by the tooling
which limit the possible size of the FSBL to about 256k.
Add xload support to the Agilex 5 PBL to optionally xload a barebox
image as bl33 from another boot medium.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/mach-socfpga/Kconfig | 11 ++++++
arch/arm/mach-socfpga/Makefile | 3 ++
arch/arm/mach-socfpga/agilex5-xload.c | 74 +++++++++++++++++++++++++++++++++++
include/mach/socfpga/generic.h | 15 +++++++
4 files changed, 103 insertions(+)
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index a836711e6c40..55d7b12200c9 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -92,4 +92,15 @@ config ARCH_SOCFPGA_XLOAD
depends on ARCH_SOCFPGA_CYCLONE5
prompt "Build SoCFPGA preloader image"
+config SOCFPGA_AGILEX5_XLOAD
+ bool
+ depends on ARCH_SOCFPGA_AGILEX5
+ prompt "Support SSBL xloading on Agilex 5"
+ help
+ On Agilex 5, the FSBL binary is limited to a size of ~256k. Enable
+ XLOAD support to load the SSBL from a separate medium and allow
+ larger bootloader images.
+
+ Note that the SSBL loading has to be configured in the board code.
+
endmenu
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 6a8117874136..f061d82f01dd 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -22,6 +22,9 @@ pbl-$(CONFIG_ARCH_SOCFPGA_AGILEX5) += soc64-system-manager.o \
agilex5-secreg.o \
agilex5-clock-manager.o \
atf.o
+ifdef CONFIG_SOCFPGA_AGILEX5_XLOAD
+pbl-$(CONFIG_ARCH_SOCFPGA_AGILEX5) += agilex5-xload.o
+endif
obj-$(CONFIG_ARCH_SOCFPGA_AGILEX5) += secure_reg_helper.o \
smc_api.o
diff --git a/arch/arm/mach-socfpga/agilex5-xload.c b/arch/arm/mach-socfpga/agilex5-xload.c
new file mode 100644
index 000000000000..9e55252c04cc
--- /dev/null
+++ b/arch/arm/mach-socfpga/agilex5-xload.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <asm/barebox-arm.h>
+#include <filetype.h>
+#include <linux/sizes.h>
+#include <mach/socfpga/generic.h>
+#include <pbl/bio.h>
+
+static inline u32 barebox_arm_size(const char *head)
+{
+ return *(u32 *)(head + ARM_HEAD_SIZE_OFFSET);
+}
+
+const struct socfpga_barebox_part *barebox_part;
+
+void agilex5_set_barebox_part(struct socfpga_barebox_part *part)
+{
+ barebox_part = part;
+}
+
+static ssize_t agilex5_bl33_read(struct pbl_bio *bio, void *bl33,
+ off_t offs, size_t max)
+{
+ const off_t step = ARM_HEAD_SIZE;
+ u32 size = 0;
+ int ret;
+
+ ret = pbl_bio_read(bio, offs, bl33, step);
+ if (ret < 0)
+ return ret;
+ if (is_barebox_arm_head(bl33))
+ size = barebox_arm_size(bl33);
+ if (size == 0) {
+ pr_err("cannot find bl33 at offset 0x%08lx)\n", offs);
+ return -EIO;
+ }
+ if (size > max) {
+ pr_err("bl33 size (%u) larger than partition\n", size);
+ return -EINVAL;
+ }
+
+ pr_info("bl33 found at 0x%08lx, size %u\n", offs, size);
+
+ ret = pbl_bio_read(bio, offs + step, bl33 + step, size - step);
+ if (ret < size - step) {
+ pr_warn("failed to read bl33 from flash: %d\n", ret);
+ return ret;
+ }
+
+ pr_debug("read bl33 to %p from %lx (%u bytes)\n", bl33, offs, size);
+
+ return size;
+}
+
+int agilex5_xload_bl33(struct pbl_bio *bio, void *bl33)
+{
+ ssize_t size;
+
+ if (!bio) {
+ pr_warn("source device for SSBL is not configured\n");
+ return -ENODEV;
+ }
+ if (!barebox_part) {
+ pr_warn("source partition for SSBL is not configured\n");
+ return -ENODEV;
+ }
+ size = agilex5_bl33_read(bio, bl33,
+ barebox_part->nor_offset,
+ barebox_part->nor_size);
+ if (size < 0)
+ return size;
+
+ return 0;
+}
diff --git a/include/mach/socfpga/generic.h b/include/mach/socfpga/generic.h
index 6c99a17e81f1..16e117f4206c 100644
--- a/include/mach/socfpga/generic.h
+++ b/include/mach/socfpga/generic.h
@@ -134,4 +134,19 @@ struct socfpga_barebox_part {
/* Partition/device for xloader to load main bootloader from */
extern const struct socfpga_barebox_part *barebox_part;
+struct pbl_bio;
+#ifdef CONFIG_SOCFPGA_AGILEX5_XLOAD
+void agilex5_set_barebox_part(struct socfpga_barebox_part *part);
+int agilex5_xload_bl33(struct pbl_bio *bio, void *bl33);
+#else
+static inline void agilex5_set_barebox_part(struct socfpga_barebox_part *part)
+{
+}
+
+static inline int agilex5_xload_bl33(struct pbl_bio *bio, void *bl33)
+{
+ return -ENODEV;
+}
+#endif
+
#endif /* __MACH_SOCFPGA_GENERIC_H */
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 06/11] arm: socfpga: agilex5: separate load and start of bl33
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (4 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 05/11] arm: socfpga: agilex5: add bl33 xload support Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 07/11] arm: socfpga: agilex5: enable xload for bl33 Michael Tretter
` (4 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
Extract loading of the bl33 to a separate function. This allows a
cleaner separation for adding the bl33 xload from another medium.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/mach-socfpga/atf.c | 37 ++++++++++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-socfpga/atf.c b/arch/arm/mach-socfpga/atf.c
index ac69fb7776ca..4bf13a464657 100644
--- a/arch/arm/mach-socfpga/atf.c
+++ b/arch/arm/mach-socfpga/atf.c
@@ -12,6 +12,8 @@
#include <mach/socfpga/soc64-sdram.h>
#include <mach/socfpga/soc64-system-manager.h>
+#include <pbl/bio.h>
+
static void socfpga_agilex5_qspi_init(void)
{
unsigned long master_ref_clk = 0;
@@ -36,16 +38,38 @@ static void socfpga_agilex5_qspi_init(void)
}
}
-static void __noreturn agilex5_load_and_start_image_via_tfa(void)
+static int agilex5_load_bl33_piggy(void *bl33)
{
- void *bl31 = (void *)AGILEX5_ATF_BL31_BASE_ADDR;
- void *bl33 = (void *)AGILEX5_ATF_BL33_BASE_ADDR;
- struct fwobj tfa;
+ /*
+ * Do not use input_data and input_data_end, to ensure that the
+ * piggydata can be stripped in the FSBL.
+ */
+ if (barebox_image_size <= barebox_pbl_size)
+ return -EINVAL;
pr_debug("copy bl33 to %p from %p (%zu bytes)\n",
bl33, __image_start, barebox_image_size);
memcpy(bl33, __image_start, barebox_image_size);
+ return 0;
+}
+
+static void agilex5_load_bl33(struct pbl_bio *bio, void *bl33)
+{
+ int ret;
+
+ ret = agilex5_load_bl33_piggy(bl33);
+ if (ret == 0)
+ return;
+
+ panic("No barebox image found!\n");
+}
+
+static void __noreturn agilex5_start_image_via_tfa(void *bl33)
+{
+ void *bl31 = (void *)AGILEX5_ATF_BL31_BASE_ADDR;
+ struct fwobj tfa;
+
get_builtin_firmware(agilex5_bl31_bin, &tfa);
pr_debug("copy bl31 to %p from %p (%zu bytes)\n",
@@ -63,6 +87,7 @@ static void __noreturn agilex5_load_and_start_image_via_tfa(void)
static void agilex5_el3_init(void)
{
+ void *bl33 = (void *)AGILEX5_ATF_BL33_BASE_ADDR;
int ret;
agilex5_initialize_security_policies();
@@ -74,7 +99,9 @@ static void agilex5_el3_init(void)
socfpga_agilex5_qspi_init();
- agilex5_load_and_start_image_via_tfa();
+ agilex5_load_bl33(NULL, bl33);
+
+ agilex5_start_image_via_tfa(bl33);
}
void __noreturn agilex5_barebox_entry(void *fdt)
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 07/11] arm: socfpga: agilex5: enable xload for bl33
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (5 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 06/11] arm: socfpga: agilex5: separate load and start of bl33 Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 08/11] arm: socfpga: agilex5: initialize QSPI flash in PBL Michael Tretter
` (3 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
If SSBL loading is configured, barebox shall prefer the SSBL over the
running FSBL.
This may be surprising, if the FSBL is updated, but since the SSBL is
probably easier to update, preferring the SSBL is probably the more
useful behavior.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/mach-socfpga/atf.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-socfpga/atf.c b/arch/arm/mach-socfpga/atf.c
index 4bf13a464657..6d036d20d4b6 100644
--- a/arch/arm/mach-socfpga/atf.c
+++ b/arch/arm/mach-socfpga/atf.c
@@ -58,6 +58,10 @@ static void agilex5_load_bl33(struct pbl_bio *bio, void *bl33)
{
int ret;
+ ret = agilex5_xload_bl33(bio, bl33);
+ if (ret == 0)
+ return;
+
ret = agilex5_load_bl33_piggy(bl33);
if (ret == 0)
return;
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 08/11] arm: socfpga: agilex5: initialize QSPI flash in PBL
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (6 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 07/11] arm: socfpga: agilex5: enable xload for bl33 Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 12:11 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 09/11] arm: socfpga: agilex5: add agilex5_barebox_entry_xload Michael Tretter
` (2 subsequent siblings)
10 siblings, 1 reply; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
Make the QSPI flash available in the PBL to be able to read a second
stage boot loader from flash.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/mach-socfpga/atf.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-socfpga/atf.c b/arch/arm/mach-socfpga/atf.c
index 6d036d20d4b6..a59a73d1c31f 100644
--- a/arch/arm/mach-socfpga/atf.c
+++ b/arch/arm/mach-socfpga/atf.c
@@ -13,29 +13,46 @@
#include <mach/socfpga/soc64-system-manager.h>
#include <pbl/bio.h>
+#include <pbl/mtd.h>
-static void socfpga_agilex5_qspi_init(void)
+static struct pbl_bio *socfpga_agilex5_qspi_init(struct pbl_bio *bio)
{
+ void __iomem *iobase = IOMEM(SOCFPGA_HPS2SDM_QSPI_REGS);
+ void __iomem *ahb_base = IOMEM(SOCFPGA_HPS2SDM_QSPI_DATA);
+ struct cadence_qspi_platform_data pdata = {
+ .is_decoded_cs = 0,
+ .fifo_depth = 128,
+ };
unsigned long master_ref_clk = 0;
int ret;
ret = socfpga_mailbox_s10_init();
if (ret) {
pr_warn("Failed to init s10 mailbox: %d\n", ret);
- return;
+ return PTR_ERR(-ENODEV);
}
ret = socfpga_mailbox_s10_qspi_open(&master_ref_clk);
if (ret) {
pr_warn("Failed to request QSPI access: %d\n", ret);
- return;
+ return ERR_PTR(-ENODEV);
}
+ /*
+ * Failing to store the reference clock may result in an unavailable
+ * QSPI flash later, but is not fatal.
+ */
ret = socfpga_agilex5_write_qspi_refclk(master_ref_clk);
- if (ret) {
+ if (ret)
pr_warn("Failed to store reference clock: %d\n", ret);
- return;
+
+ ret = cqspi_bio_init(bio, iobase, ahb_base, master_ref_clk, &pdata);
+ if (ret) {
+ pr_warn("failed to initialize bio for qspi\n");
+ return ERR_PTR(-ENODEV);
}
+
+ return bio;
}
static int agilex5_load_bl33_piggy(void *bl33)
@@ -92,6 +109,7 @@ static void __noreturn agilex5_start_image_via_tfa(void *bl33)
static void agilex5_el3_init(void)
{
void *bl33 = (void *)AGILEX5_ATF_BL33_BASE_ADDR;
+ struct pbl_bio tmp, *bio;
int ret;
agilex5_initialize_security_policies();
@@ -101,9 +119,11 @@ static void agilex5_el3_init(void)
if (ret)
panic("DDR initialization failed\n");
- socfpga_agilex5_qspi_init();
+ bio = socfpga_agilex5_qspi_init(&tmp);
+ if (IS_ERR_OR_NULL(bio))
+ bio = NULL;
- agilex5_load_bl33(NULL, bl33);
+ agilex5_load_bl33(bio, bl33);
agilex5_start_image_via_tfa(bl33);
}
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 09/11] arm: socfpga: agilex5: add agilex5_barebox_entry_xload
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (7 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 08/11] arm: socfpga: agilex5: initialize QSPI flash in PBL Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 10/11] arm: socfpga: axe5-eagle: move lowlevel init to separate function Michael Tretter
2026-10-07 10:55 ` [PATCH 11/11] arm: socfpga: axe5-eagle: build FSBL without piggy data Michael Tretter
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
The xload function allows to build the FSBL without piggy data and load
the SSBL from QSPI.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/mach-socfpga/atf.c | 10 ++++++++++
include/mach/socfpga/generic.h | 1 +
2 files changed, 11 insertions(+)
diff --git a/arch/arm/mach-socfpga/atf.c b/arch/arm/mach-socfpga/atf.c
index a59a73d1c31f..7583a20b16f5 100644
--- a/arch/arm/mach-socfpga/atf.c
+++ b/arch/arm/mach-socfpga/atf.c
@@ -128,6 +128,16 @@ static void agilex5_el3_init(void)
agilex5_start_image_via_tfa(bl33);
}
+void __noreturn agilex5_barebox_entry_xload(void)
+{
+ /* Using xload in EL1 is not supported */
+ if (current_el() != 3)
+ hang();
+
+ agilex5_el3_init();
+ __builtin_unreachable();
+}
+
void __noreturn agilex5_barebox_entry(void *fdt)
{
phys_addr_t membase;
diff --git a/include/mach/socfpga/generic.h b/include/mach/socfpga/generic.h
index 16e117f4206c..a2a3fad58b18 100644
--- a/include/mach/socfpga/generic.h
+++ b/include/mach/socfpga/generic.h
@@ -101,6 +101,7 @@ static inline void arria10_watchdog_disable(void) {}
int agilex5_clk_init(void);
void __noreturn agilex5_barebox_entry(void *fdt);
+void __noreturn agilex5_barebox_entry_xload(void);
static inline void __udelay(unsigned us)
{
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 10/11] arm: socfpga: axe5-eagle: move lowlevel init to separate function
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (8 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 09/11] arm: socfpga: agilex5: add agilex5_barebox_entry_xload Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 11/11] arm: socfpga: axe5-eagle: build FSBL without piggy data Michael Tretter
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
Move the lowlevel initialization to a separate function to be able to
reuse it in the xload entry point.
Drop the debug message that lowlevel init is finished, because the
message isn't really useful.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/boards/arrow-axe5-eagle/lowlevel.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boards/arrow-axe5-eagle/lowlevel.c b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
index b0a2d6673e0f..bf98515f28d8 100644
--- a/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
+++ b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
@@ -13,7 +13,7 @@
extern char __dtb_z_socfpga_agilex5_axe5_eagle_start[];
-static noinline void axe5_eagle_continue(void)
+static void axe5_eagle_lowlevel_init(void)
{
void __iomem *uart = IOMEM(SOCFPGA_UART_BASE(0));
@@ -21,8 +21,11 @@ static noinline void axe5_eagle_continue(void)
socfpga_uart_setup(uart);
pbl_set_putc(socfpga_uart_putc, uart);
+}
- pr_debug("Lowlevel init done\n");
+static noinline void axe5_eagle_continue(void)
+{
+ axe5_eagle_lowlevel_init();
agilex5_barebox_entry(__dtb_z_socfpga_agilex5_axe5_eagle_start);
}
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 11/11] arm: socfpga: axe5-eagle: build FSBL without piggy data
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
` (9 preceding siblings ...)
2026-10-07 10:55 ` [PATCH 10/11] arm: socfpga: axe5-eagle: move lowlevel init to separate function Michael Tretter
@ 2026-10-07 10:55 ` Michael Tretter
10 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 10:55 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Michael Tretter
Add xload support to the Arrow AXE5 Eagle board and remove the piggy
data from the FSBL.
The load address and size are set via the barebox configuration, because
they depend on the partition layout in flash, which is configured when
configuring the flash image in Quartus.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
arch/arm/boards/arrow-axe5-eagle/lowlevel.c | 24 ++++++++++++++++++++++
arch/arm/mach-socfpga/Kconfig | 32 ++++++++++++++++++++++++++++-
images/Makefile.socfpga | 5 +++++
3 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boards/arrow-axe5-eagle/lowlevel.c b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
index bf98515f28d8..7b7f699655a1 100644
--- a/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
+++ b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
@@ -13,6 +13,11 @@
extern char __dtb_z_socfpga_agilex5_axe5_eagle_start[];
+static struct socfpga_barebox_part axe5_eagle_barebox_part = {
+ .nor_offset = CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD_ADDR,
+ .nor_size = CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD_SIZE,
+};
+
static void axe5_eagle_lowlevel_init(void)
{
void __iomem *uart = IOMEM(SOCFPGA_UART_BASE(0));
@@ -30,6 +35,14 @@ static noinline void axe5_eagle_continue(void)
agilex5_barebox_entry(__dtb_z_socfpga_agilex5_axe5_eagle_start);
}
+static noinline void axe5_eagle_continue_xload(void)
+{
+ axe5_eagle_lowlevel_init();
+
+ agilex5_set_barebox_part(&axe5_eagle_barebox_part);
+ agilex5_barebox_entry_xload();
+}
+
ENTRY_FUNCTION_AGILEX5(start_socfpga_agilex5_axe5_eagle)
{
if (current_el() == 3)
@@ -40,3 +53,14 @@ ENTRY_FUNCTION_AGILEX5(start_socfpga_agilex5_axe5_eagle)
axe5_eagle_continue();
}
+
+ENTRY_FUNCTION_AGILEX5(start_socfpga_agilex5_axe5_eagle_xload)
+{
+ if (current_el() == 3)
+ socfpga_agilex5_cpu_lowlevel_init();
+
+ relocate_to_current_adr();
+ setup_c();
+
+ axe5_eagle_continue_xload();
+}
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 55d7b12200c9..915bae352b0e 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -79,10 +79,40 @@ if 64BIT
comment "Agilex 5 boards"
-config MACH_SOCFPGA_ARROW_AXE5_EAGLE
+menuconfig MACH_SOCFPGA_ARROW_AXE5_EAGLE
bool "Arrow AXE5 Eagle"
select ARCH_SOCFPGA_AGILEX5
+config MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD
+ bool "Build Arrow AXE5 Eagle FSBL without piggy data"
+ depends on MACH_SOCFPGA_ARROW_AXE5_EAGLE
+ select SOCFPGA_AGILEX5_XLOAD
+ select SPI_CADENCE_QUADSPI_PBL
+ help
+ This option reduces the binary size of the FSBL and makes it
+ independent of the enabled features of the SSBL, but requires SSBL
+ xload support.
+
+config MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD_ADDR
+ depends on MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD
+ prompt "Start address of the Arrow AXE5 SSBL on flash"
+ hex
+ default 0x01000000
+ help
+ barebox tries to load an SSBL from this address in the QSPI flash.
+
+ Keep this address in sync with your QSPI image configuration.
+
+config MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD_SIZE
+ depends on MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD
+ prompt "Maximum size of the Arrow AXE5 SSBL on flash"
+ hex
+ default 0x00400000
+ help
+ The maximum size of the SSBL in the QSPI flash.
+
+ Keep this size in sync with your QSPI image configuration.
+
endif
comment "board features"
diff --git a/images/Makefile.socfpga b/images/Makefile.socfpga
index ec1bce5079c9..38bb27ac0e58 100644
--- a/images/Makefile.socfpga
+++ b/images/Makefile.socfpga
@@ -96,8 +96,13 @@ FILE_barebox-socfpga-socrates.img = start_socfpga_socrates.pblb
socfpga-barebox-$(CONFIG_MACH_SOCFPGA_EBV_SOCRATES) += barebox-socfpga-socrates.img
# ----------------------- Agilex5 based boards ---------------------------
+#ifdef MACH_SOCFPGA_ARROW_AXE5_EAGLE_XLOAD
+pblb-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += start_socfpga_agilex5_axe5_eagle_xload
+FILE_barebox-socfpga-agilex5-axe5-eagle.img = start_socfpga_agilex5_axe5_eagle_xload.pblb.hex
+#else
pblb-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += start_socfpga_agilex5_axe5_eagle
FILE_barebox-socfpga-agilex5-axe5-eagle.img = start_socfpga_agilex5_axe5_eagle.pblb.hex
+#endif
socfpga-barebox-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += barebox-socfpga-agilex5-axe5-eagle.img
pblb-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += start_socfpga_agilex5_axe5_eagle
--
2.47.3
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 08/11] arm: socfpga: agilex5: initialize QSPI flash in PBL
2026-10-07 10:55 ` [PATCH 08/11] arm: socfpga: agilex5: initialize QSPI flash in PBL Michael Tretter
@ 2026-10-07 12:11 ` Michael Tretter
0 siblings, 0 replies; 13+ messages in thread
From: Michael Tretter @ 2026-10-07 12:11 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX
On Wed, 07 Oct 2026 12:55:53 +0200, Michael Tretter wrote:
> Make the QSPI flash available in the PBL to be able to read a second
> stage boot loader from flash.
>
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> ---
> arch/arm/mach-socfpga/atf.c | 34 +++++++++++++++++++++++++++-------
> 1 file changed, 27 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm/mach-socfpga/atf.c b/arch/arm/mach-socfpga/atf.c
> index 6d036d20d4b6..a59a73d1c31f 100644
> --- a/arch/arm/mach-socfpga/atf.c
> +++ b/arch/arm/mach-socfpga/atf.c
> @@ -13,29 +13,46 @@
> #include <mach/socfpga/soc64-system-manager.h>
>
> #include <pbl/bio.h>
> +#include <pbl/mtd.h>
>
> -static void socfpga_agilex5_qspi_init(void)
> +static struct pbl_bio *socfpga_agilex5_qspi_init(struct pbl_bio *bio)
> {
> + void __iomem *iobase = IOMEM(SOCFPGA_HPS2SDM_QSPI_REGS);
> + void __iomem *ahb_base = IOMEM(SOCFPGA_HPS2SDM_QSPI_DATA);
> + struct cadence_qspi_platform_data pdata = {
> + .is_decoded_cs = 0,
> + .fifo_depth = 128,
> + };
> unsigned long master_ref_clk = 0;
> int ret;
>
> ret = socfpga_mailbox_s10_init();
> if (ret) {
> pr_warn("Failed to init s10 mailbox: %d\n", ret);
> - return;
> + return PTR_ERR(-ENODEV);
This should have been
return ERR_PTR(-ENODEV);
Michael
> }
>
> ret = socfpga_mailbox_s10_qspi_open(&master_ref_clk);
> if (ret) {
> pr_warn("Failed to request QSPI access: %d\n", ret);
> - return;
> + return ERR_PTR(-ENODEV);
> }
>
> + /*
> + * Failing to store the reference clock may result in an unavailable
> + * QSPI flash later, but is not fatal.
> + */
> ret = socfpga_agilex5_write_qspi_refclk(master_ref_clk);
> - if (ret) {
> + if (ret)
> pr_warn("Failed to store reference clock: %d\n", ret);
> - return;
> +
> + ret = cqspi_bio_init(bio, iobase, ahb_base, master_ref_clk, &pdata);
> + if (ret) {
> + pr_warn("failed to initialize bio for qspi\n");
> + return ERR_PTR(-ENODEV);
> }
> +
> + return bio;
> }
>
> static int agilex5_load_bl33_piggy(void *bl33)
> @@ -92,6 +109,7 @@ static void __noreturn agilex5_start_image_via_tfa(void *bl33)
> static void agilex5_el3_init(void)
> {
> void *bl33 = (void *)AGILEX5_ATF_BL33_BASE_ADDR;
> + struct pbl_bio tmp, *bio;
> int ret;
>
> agilex5_initialize_security_policies();
> @@ -101,9 +119,11 @@ static void agilex5_el3_init(void)
> if (ret)
> panic("DDR initialization failed\n");
>
> - socfpga_agilex5_qspi_init();
> + bio = socfpga_agilex5_qspi_init(&tmp);
> + if (IS_ERR_OR_NULL(bio))
> + bio = NULL;
>
> - agilex5_load_bl33(NULL, bl33);
> + agilex5_load_bl33(bio, bl33);
>
> agilex5_start_image_via_tfa(bl33);
> }
>
> --
> 2.47.3
>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-10-07 12:13 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-07 10:55 [PATCH 00/11] arm: socfpga: agilex5: add xload support for bl33 to FSBL Michael Tretter
2026-10-07 10:55 ` [PATCH 01/11] mtd: spi-nor: drop requirement for device field Michael Tretter
2026-10-07 10:55 ` [PATCH 02/11] mtd: spi-nor: enable module in PBL Michael Tretter
2026-10-07 10:55 ` [PATCH 03/11] mtd: spi-nor: cadence: extract common part for use " Michael Tretter
2026-10-07 10:55 ` [PATCH 04/11] mtd: spi-nor: cadence: add a PBL driver Michael Tretter
2026-10-07 10:55 ` [PATCH 05/11] arm: socfpga: agilex5: add bl33 xload support Michael Tretter
2026-10-07 10:55 ` [PATCH 06/11] arm: socfpga: agilex5: separate load and start of bl33 Michael Tretter
2026-10-07 10:55 ` [PATCH 07/11] arm: socfpga: agilex5: enable xload for bl33 Michael Tretter
2026-10-07 10:55 ` [PATCH 08/11] arm: socfpga: agilex5: initialize QSPI flash in PBL Michael Tretter
2026-10-07 12:11 ` Michael Tretter
2026-10-07 10:55 ` [PATCH 09/11] arm: socfpga: agilex5: add agilex5_barebox_entry_xload Michael Tretter
2026-10-07 10:55 ` [PATCH 10/11] arm: socfpga: axe5-eagle: move lowlevel init to separate function Michael Tretter
2026-10-07 10:55 ` [PATCH 11/11] arm: socfpga: axe5-eagle: build FSBL without piggy data Michael Tretter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox