Enhanced the generic firmware loader to support QSPI RAW partition
loading. This would enable FPGA configuration bitstream loading
from QSPI RAW partition to program FPGA.

Signed-off-by: Tien Fong Chee <tien.fong.c...@altera.com>
Signed-off-by: Naresh Kumar Ravulapalli <nareshkumar.ravulapa...@altera.com>
---
 drivers/misc/fs_loader.c | 86 +++++++++++++++++++++++++++++++++-------
 include/fs_loader.h      | 36 ++++++++++++++++-
 2 files changed, 106 insertions(+), 16 deletions(-)

diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
index 66803f4b997..931443048e5 100644
--- a/drivers/misc/fs_loader.c
+++ b/drivers/misc/fs_loader.c
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0+
  /*
  * Copyright (C) 2018-2019 Intel Corporation <www.intel.com>
- *
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
  */
 
 #define LOG_CATEGORY UCLASS_FS_FIRMWARE_LOADER
@@ -20,6 +20,7 @@
 #include <mapmem.h>
 #include <malloc.h>
 #include <spl.h>
+#include <spi_flash.h>
 
 #ifdef CONFIG_CMD_UBIFS
 #include <ubi_uboot.h>
@@ -70,6 +71,11 @@ static int mount_ubifs(char *mtdpart, char *ubivol)
 }
 #endif
 
+__weak struct blk_desc *blk_get_by_device(struct udevice *dev)
+{
+       return NULL;
+}
+
 static int select_fs_dev(struct device_plat *plat)
 {
        int ret;
@@ -124,16 +130,26 @@ static int _request_firmware_prepare(struct udevice *dev,
                                    const char *name, void *dbuf,
                                    size_t size, u32 offset)
 {
-       if (!name || name[0] == '\0')
-               return -EINVAL;
-
        struct firmware *firmwarep = dev_get_priv(dev);
+       struct device_plat *plat = dev_get_plat(dev);
+       char *endptr;
+       u32 fw_offset;
 
        if (!firmwarep)
                return -ENOMEM;
 
        firmwarep->name = name;
-       firmwarep->offset = offset;
+
+       if (plat->data_type == DATA_RAW) {
+               fw_offset = simple_strtoul(firmwarep->name, &endptr, 16);
+               if (firmwarep->name == endptr || *endptr != '\0')
+                       return -EINVAL;
+
+               firmwarep->offset = fw_offset + offset;
+       } else {
+               firmwarep->offset = offset;
+       }
+
        firmwarep->data = dbuf;
        firmwarep->size = size;
 
@@ -148,9 +164,10 @@ static int _request_firmware_prepare(struct udevice *dev,
  */
 static int fw_get_filesystem_firmware(struct udevice *dev)
 {
-       loff_t actread;
+       loff_t actread = 0;
        char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
-       int ret;
+       int ret = 0;
+       struct device_plat *plat = dev_get_plat(dev);
 
        storage_interface = env_get("storage_interface");
        dev_part = env_get("fw_dev_part");
@@ -170,7 +187,8 @@ static int fw_get_filesystem_firmware(struct udevice *dev)
                else
                        ret = -ENODEV;
        } else {
-               ret = select_fs_dev(dev_get_plat(dev));
+               if (plat->data_type == DATA_FS)
+                       ret = select_fs_dev(dev_get_plat(dev));
        }
 
        if (ret)
@@ -181,8 +199,18 @@ static int fw_get_filesystem_firmware(struct udevice *dev)
        if (!firmwarep)
                return -ENOMEM;
 
-       ret = fs_read(firmwarep->name, (ulong)map_to_sysmem(firmwarep->data),
-                       firmwarep->offset, firmwarep->size, &actread);
+       if (plat->data_type == DATA_FS)
+               ret = fs_read(firmwarep->name,
+                             (ulong)map_to_sysmem(firmwarep->data),
+                             firmwarep->offset, firmwarep->size, &actread);
+       else if (plat->data_type == DATA_RAW) {
+#ifdef CONFIG_SPI_FLASH
+               ret = spi_flash_read_dm(plat->flash, firmwarep->offset,
+                                       firmwarep->size,
+                                       (void *)map_to_sysmem(firmwarep->data));
+               actread = firmwarep->size;
+#endif
+       }
 
        if (ret) {
                debug("Error: %d Failed to read %s from flash %lld != %zu.\n",
@@ -231,6 +259,7 @@ int request_firmware_into_buf(struct udevice *dev,
 static int fs_loader_of_to_plat(struct udevice *dev)
 {
        u32 phandlepart[2];
+       u32 sfconfig[2];
 
        ofnode fs_loader_node = dev_ofnode(dev);
 
@@ -250,6 +279,15 @@ static int fs_loader_of_to_plat(struct udevice *dev)
 
                plat->ubivol = (char *)ofnode_read_string(
                                 fs_loader_node, "ubivol");
+
+               if (!ofnode_read_u32_array(fs_loader_node, "sfconfig", sfconfig,
+                                          2)) {
+                       plat->data_type = DATA_RAW;
+                       plat->sfconfig.bus = sfconfig[0];
+                       plat->sfconfig.cs = sfconfig[1];
+               } else {
+                       plat->data_type = DATA_FS;
+               }
        }
 
        return 0;
@@ -257,10 +295,30 @@ static int fs_loader_of_to_plat(struct udevice *dev)
 
 static int fs_loader_probe(struct udevice *dev)
 {
-#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(BLK)
-       int ret;
+       int ret = 0;
        struct device_plat *plat = dev_get_plat(dev);
 
+#ifdef CONFIG_SPI_FLASH
+       if (!plat->flash) {
+               debug("bus = %d\ncs = %d\n",
+                     plat->sfconfig.bus, plat->sfconfig.cs);
+
+               ret = spi_flash_probe_bus_cs(plat->sfconfig.bus,
+                                            plat->sfconfig.cs,
+                                            &plat->flash);
+               if (ret) {
+                       debug("fs_loader: Failed to initialize SPI flash at ");
+                       debug("%u:%u (error %d)\n", plat->sfconfig.bus,
+                             sfconfig.cs, ret);
+                       return -ENODEV;
+               }
+
+               if (!plat->flash)
+                       return -EINVAL;
+       }
+#endif
+
+#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(BLK)
        if (plat->phandlepart.phandle) {
                ofnode node = ofnode_get_by_phandle(plat->phandlepart.phandle);
                struct udevice *parent_dev = NULL;
@@ -280,7 +338,7 @@ static int fs_loader_probe(struct udevice *dev)
        }
 #endif
 
-       return 0;
+       return ret;
 };
 
 static const struct udevice_id fs_loader_ids[] = {
diff --git a/include/fs_loader.h b/include/fs_loader.h
index 5eb5b7ab4a1..1b36f05415a 100644
--- a/include/fs_loader.h
+++ b/include/fs_loader.h
@@ -1,8 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2018 Intel Corporation <www.intel.com>
- *
- * SPDX-License-Identifier:    GPL-2.0
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
  */
+
 #ifndef _FS_LOADER_H_
 #define _FS_LOADER_H_
 
@@ -22,6 +23,31 @@ struct phandle_part {
        u32 partition;
 };
 
+/**
+ * struct sf_config - A place for storing serial flash configuration
+ *
+ * This holds information about bus, chip-select, and speed and mode of a 
serial
+ * flash configuration.
+ *
+ * @bus: SPI bus number.
+ * @cs: SPI chip selection.
+ */
+struct sf_config {
+       u32 bus;
+       u32 cs;
+};
+
+/**
+ * enum data_flags - Flag to indicate data as RAW or as filesystem
+ *
+ * DATA_RAW: Data stored as RAW.
+ * DATA_FS: DATA stored as filesystem.
+ */
+enum data_flags {
+       DATA_RAW, /* Stored in raw */
+       DATA_FS,  /* Stored within a file system */
+};
+
 /**
  * struct phandle_part - A place for storing all supported storage devices
  *
@@ -30,11 +56,17 @@ struct phandle_part {
  * @phandlepart: Attribute data for block device.
  * @mtdpart: MTD partition for ubi partition.
  * @ubivol: UBI volume-name for ubifsmount.
+ * @enum data_flags: Data type (RAW or filesystem).
+ * @struct sf_config: Serial flash configuration.
+ * @struct spi_flash: Information about a SPI flash.
  */
 struct device_plat {
        struct phandle_part phandlepart;
        char *mtdpart;
        char *ubivol;
+       enum data_flags data_type;
+       struct sf_config sfconfig;
+       struct udevice *flash;
 };
 
 /**
-- 
2.35.3

Reply via email to