From: Tien Fong Chee <[email protected]>
Add support for loading data from a QSPI RAW flash offset through the
generic firmware loader. Consumers include the DDR calibration backup
restore path, and optionally FPGA bitstream loading from QSPI.
Signed-off-by: Tien Fong Chee <[email protected]>
Signed-off-by: Chen Huei Lok <[email protected]>
---
doc/device-tree-bindings/misc/fs_loader.txt | 8 ++
drivers/misc/fs_loader.c | 99 +++++++++++++++++----
include/fs_loader.h | 33 ++++++-
3 files changed, 120 insertions(+), 20 deletions(-)
diff --git a/doc/device-tree-bindings/misc/fs_loader.txt
b/doc/device-tree-bindings/misc/fs_loader.txt
index 542be4b25a0..8ee59db24d5 100644
--- a/doc/device-tree-bindings/misc/fs_loader.txt
+++ b/doc/device-tree-bindings/misc/fs_loader.txt
@@ -12,6 +12,7 @@ Required properties:
required for ubi and mounting.
- ubivol: which volume of ubi the image loading from, this property is
required
for ubi and mounting.
+- sfconfig: should only contain "bus number" and "chip selection".
Example of storage device and partition search set for mmc, usb, sata and
ubi in device tree source as shown in below:
@@ -46,3 +47,10 @@ ubi in device tree source as shown in below:
mtdpart = "UBI",
ubivol = "ubi0";
};
+
+ Example for qspi:
+ fs_loader4: fs-loader@4 {
+ bootph-all;
+ compatible = "u-boot,fs-loader";
+ sfconfig = <0 0>;
+ };
diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
index 6af4c7f15e7..293db94dd29 100644
--- a/drivers/misc/fs_loader.c
+++ b/drivers/misc/fs_loader.c
@@ -19,6 +19,7 @@
#include <mapmem.h>
#include <malloc.h>
#include <spl.h>
+#include <spi_flash.h>
#ifdef CONFIG_CMD_UBIFS
#include <ubi_uboot.h>
@@ -121,16 +122,31 @@ 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;
+ if (plat->data_type == DATA_RAW) {
+ if (!name)
+ return -EINVAL;
+
+ fw_offset = simple_strtoul(name, &endptr, 16);
+ if (name == endptr || *endptr != '\0')
+ return -EINVAL;
+
+ firmwarep->offset = fw_offset + offset;
+ } else {
+ if (!name || name[0] == '\0')
+ return -EINVAL;
+
+ firmwarep->offset = offset;
+ }
+
firmwarep->name = name;
- firmwarep->offset = offset;
firmwarep->data = dbuf;
firmwarep->size = size;
@@ -146,13 +162,17 @@ static int _request_firmware_prepare(struct udevice *dev,
static int fw_get_filesystem_firmware(struct udevice *dev)
{
loff_t actread = 0;
- char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
- int ret;
+ char *storage_interface = NULL, *dev_part = NULL;
+ char *ubi_mtdpart = NULL, *ubi_volume = NULL;
+ int ret = 0;
+ struct device_plat *plat = dev_get_plat(dev);
- storage_interface = env_get("storage_interface");
- dev_part = env_get("fw_dev_part");
- ubi_mtdpart = env_get("fw_ubi_mtdpart");
- ubi_volume = env_get("fw_ubi_volume");
+ if (CONFIG_IS_ENABLED(ENV_SUPPORT)) {
+ storage_interface = env_get("storage_interface");
+ dev_part = env_get("fw_dev_part");
+ ubi_mtdpart = env_get("fw_ubi_mtdpart");
+ ubi_volume = env_get("fw_ubi_volume");
+ }
if (storage_interface && dev_part) {
ret = fs_set_blk_dev(storage_interface, dev_part, FS_TYPE_ANY);
@@ -167,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)
@@ -178,8 +199,20 @@ 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) {
+ if (IS_ENABLED(CONFIG_SPI_FLASH)) {
+ ret = spi_flash_read_dm(plat->flash, firmwarep->offset,
+ firmwarep->size,
+ (void *)firmwarep->data);
+ actread = firmwarep->size;
+ } else {
+ ret = -ENOSYS;
+ }
+ }
if (ret) {
debug("Error: %d Failed to read %s from flash %lld != %zu.\n",
@@ -228,6 +261,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);
@@ -247,6 +281,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;
@@ -254,11 +297,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);
- if (plat->phandlepart.phandle) {
+ if (IS_ENABLED(CONFIG_SPI_FLASH) &&
+ plat->data_type == DATA_RAW && !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,
+ plat->sfconfig.cs, ret);
+ return -ENODEV;
+ }
+
+ if (!plat->flash)
+ return -EINVAL;
+ }
+
+ if (CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(BLK) &&
+ plat->phandlepart.phandle) {
ofnode node = ofnode_get_by_phandle(plat->phandlepart.phandle);
struct udevice *parent_dev = NULL;
@@ -269,15 +331,14 @@ static int fs_loader_probe(struct udevice *dev)
ret = blk_get_from_parent(parent_dev, &dev);
if (ret) {
debug("fs_loader: No block device: %d\n",
- ret);
+ ret);
return ret;
}
}
}
-#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 7e16e0f7030..f9c073fee6e 100644
--- a/include/fs_loader.h
+++ b/include/fs_loader.h
@@ -23,18 +23,49 @@ struct phandle_part {
};
/**
- * struct phandle_part - A place for storing all supported storage devices
+ * struct sf_config - A place for storing serial flash configuration
+ *
+ * This holds information about bus and chip-select 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 device_plat - A place for storing all supported storage devices
*
* This holds information about all supported storage devices for driver use.
*
* @phandlepart: Attribute data for block device.
* @mtdpart: MTD partition for ubi partition.
* @ubivol: UBI volume-name for ubifsmount.
+ * @data_type: Data type (RAW or filesystem).
+ * @sfconfig: Serial flash configuration.
+ * @flash: SPI flash device used for RAW offset reads.
*/
struct device_plat {
struct phandle_part phandlepart;
char *mtdpart;
char *ubivol;
+ enum data_flags data_type;
+ struct sf_config sfconfig;
+ struct udevice *flash;
};
/**