From ff0fa68b8141fa7c83b3b42e7d6cf5a6bc27c980 Mon Sep 17 00:00:00 2001
From: Tien Fong Chee <tien.fong.chee@intel.com>
Date: Mon, 15 Apr 2019 14:02:44 +0800
Subject: [PATCH 01/10] misc: fs_loader: Add QSPI RAW partition loading support

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.chee@intel.com>
---
 drivers/misc/fs_loader.c | 85 +++++++++++++++++++++++++++++++++++++++++-------
 include/fs_loader.h      | 35 ++++++++++++++++++++
 2 files changed, 109 insertions(+), 11 deletions(-)

diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
index f42eeff8f6..638eb1e0d2 100644
--- a/drivers/misc/fs_loader.c
+++ b/drivers/misc/fs_loader.c
@@ -13,6 +13,7 @@
 #include <mapmem.h>
 #include <malloc.h>
 #include <spl.h>
+#include <spi_flash.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -59,6 +60,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_platdata *plat)
 {
 	int ret;
@@ -113,16 +119,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_platdata *plat = dev->platdata;
+	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;
 
@@ -139,7 +155,8 @@ static int fw_get_filesystem_firmware(struct udevice *dev)
 {
 	loff_t actread;
 	char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
-	int ret;
+	int ret = 0;
+	struct device_platdata *plat = dev->platdata;
 
 	storage_interface = env_get("storage_interface");
 	dev_part = env_get("fw_dev_part");
@@ -159,7 +176,8 @@ static int fw_get_filesystem_firmware(struct udevice *dev)
 		else
 			ret = -ENODEV;
 	} else {
-		ret = select_fs_dev(dev->platdata);
+		if (plat->data_type == DATA_FS)
+			ret = select_fs_dev(dev->platdata);
 	}
 
 	if (ret)
@@ -170,8 +188,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",
@@ -220,6 +248,7 @@ int request_firmware_into_buf(struct udevice *dev,
 static int fs_loader_ofdata_to_platdata(struct udevice *dev)
 {
 	u32 phandlepart[2];
+	u32 sfconfig[4];
 
 	ofnode fs_loader_node = dev_ofnode(dev);
 
@@ -239,6 +268,17 @@ static int fs_loader_ofdata_to_platdata(struct udevice *dev)
 
 		plat->ubivol = (char *)ofnode_read_string(
 				 fs_loader_node, "ubivol");
+
+		if (!ofnode_read_u32_array(fs_loader_node, "sfconfig", sfconfig,
+					   4)) {
+			plat->data_type = DATA_RAW;
+			plat->sfconfig.bus = sfconfig[0];
+			plat->sfconfig.cs = sfconfig[1];
+			plat->sfconfig.speed = sfconfig[2];
+			plat->sfconfig.mode = sfconfig[3];
+		} else {
+			plat->data_type = DATA_FS;
+		}
 	}
 
 	return 0;
@@ -246,10 +286,33 @@ static int fs_loader_ofdata_to_platdata(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_platdata *plat = dev->platdata;
 
+#ifdef CONFIG_SPI_FLASH
+	if (!plat->flash) {
+		debug("bus = %d\ncs = %d\nspeed= %d\nmode = %d\n",
+			 plat->sfconfig.bus, plat->sfconfig.cs,
+			 plat->sfconfig.speed, plat->sfconfig.mode);
+
+		ret = spi_flash_probe_bus_cs(plat->sfconfig.bus,
+					    plat->sfconfig.cs,
+					    plat->sfconfig.speed,
+					    plat->sfconfig.mode,
+					    &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;
+	}
+#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;
@@ -269,7 +332,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 b728c06fcf..fc371272fa 100644
--- a/include/fs_loader.h
+++ b/include/fs_loader.h
@@ -23,6 +23,35 @@ struct phandle_part {
 };
 
 /**
+ * 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.
+ * @speed: Speed selection.
+ * @mode: SPI mode.
+ */
+struct sf_config {
+	u32 bus;
+	u32 cs;
+	u32 speed;
+	u32 mode;
+};
+
+/**
+ * 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
  *
  * This holds information about all supported storage devices for driver use.
@@ -30,11 +59,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_platdata {
 	struct phandle_part phandlepart;
 	char *mtdpart;
 	char *ubivol;
+	enum data_flags data_type;
+	struct sf_config sfconfig;
+	struct udevice *flash;
 };
 
 /**
-- 
2.13.0

