@@ -130,3 +130,4 @@ obj-$(CONFIG_CMD_DFU) += dfu.o
obj-y += command.o
obj-y += s_record.o
obj-y += xyzModem.o
+obj-y += fs_loader.o
new file mode 100644
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2017 Intel Corporation <www.intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fs.h>
+#include <fs_loader.h>
+#include <nand.h>
+#include <sata.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <spl.h>
+#include <linux/string.h>
+#include <usb.h>
+
+static struct device_location default_locations[] = {
+ {
+ .name = "mmc",
+ .devpart = "0:1",
+ },
+ {
+ .name = "usb",
+ .devpart = "0:1",
+ },
+ {
+ .name = "sata",
+ .devpart = "0:1",
+ },
+};
+
+/* USB build is not supported yet in SPL */
+#ifndef CONFIG_SPL_BUILD
+#ifdef CONFIG_USB_STORAGE
+static int init_usb(void)
+{
+ int err;
+
+ err = usb_init();
+ if (err)
+ return err;
+
+#ifndef CONFIG_DM_USB
+ err = usb_stor_scan(1) < 0 ? -ENODEV : 0;
+#endif
+
+ return err;
+}
+#else
+static int init_usb(void)
+{
+ printf("Error: Cannot load flash image: no USB support\n");
+ return -ENOSYS;
+}
+#endif
+#endif
+
+#ifdef CONFIG_SATA
+static int init_storage_sata(void)
+{
+ return sata_probe(0);
+}
+#else
+static int init_storage_sata(void)
+{
+ printf("Error: Cannot load image: no SATA support\n");
+ return -ENOSYS;
+}
+#endif
+
+#ifdef CONFIG_CMD_UBIFS
+static int mount_ubifs(struct device_location *location)
+{
+ int ret;
+ char cmd[32];
+
+ sprintf(cmd, "ubi part %s", location->mtdpart);
+
+ ret = run_command(cmd, 0);
+ if (ret)
+ return ret;
+
+ sprintf(cmd, "ubifsmount %s", location->ubivol);
+
+ ret = run_command(cmd, 0);
+
+ return ret;
+}
+
+static int umount_ubifs(void)
+{
+ return run_command("ubifsumount", 0);
+}
+#else
+static int mount_ubifs(struct device_location *location)
+{
+ printf("Error: Cannot load image: no UBIFS support\n");
+ return -ENOSYS;
+}
+#endif
+
+#if defined(CONFIG_SPL_MMC_SUPPORT) && defined(CONFIG_SPL_BUILD)
+static int init_mmc(void)
+{
+ /* Just for the case MMC is not yet initialized */
+ struct mmc *mmc = NULL;
+ int err;
+
+ spl_mmc_find_device(&mmc, spl_boot_device());
+
+ err = mmc_init(mmc);
+ if (err) {
+ printf("spl: mmc init failed with error: %d\n", err);
+ return err;
+ }
+
+ return err;
+}
+#else
+static int init_mmc(void)
+{
+ /* Expect somewhere already initialize MMC */
+ return 0;
+}
+#endif
+
+static int select_fs_dev(struct device_location *location)
+{
+ int ret = 0;
+
+ if (!strcmp("mmc", location->name)) {
+ ret = fs_set_blk_dev("mmc", location->devpart, FS_TYPE_ANY);
+ }
+ else if (!strcmp("usb", location->name)) {
+ ret = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY);
+ }
+ else if (!strcmp("sata", location->name)) {
+ ret = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
+ }
+ else if (!strcmp("ubi", location->name)) {
+ if (location->ubivol != NULL)
+ ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
+ else
+ ret = -ENODEV;
+ }
+ else {
+ printf("Error: unsupported location storage.\n");
+ return -ENODEV;
+ }
+
+ if (ret)
+ printf("Error: could not access storage.\n");
+
+ return ret;
+}
+
+static int init_storage_device(struct device_location *location)
+{
+ int ret = 0;
+#ifndef CONFIG_SPL_BUILD
+ /* USB build is not supported yet in SPL */
+ if (!strcmp("usb", location->name))
+ ret = init_usb();
+#endif
+
+ if (!strcmp("mmc", location->name))
+ ret = init_mmc();
+
+ if (!strcmp("sata", location->name))
+ ret = init_storage_sata();
+
+ if (location->ubivol != NULL)
+ ret = mount_ubifs(location);
+
+ return ret;
+}
+
+static void set_storage_devpart(char *name, char *devpart)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(default_locations); i++) {
+ if (!strcmp(default_locations[i].name, name))
+ default_locations[i].devpart = devpart;
+ }
+
+ return;
+}
+
+/*
+ * Prepare firmware struct;
+ * return -ve if fail.
+ */
+static int _request_firmware_prepare(struct firmware **firmware_p,
+ const char *name, void *dbuf,
+ size_t size, u32 offset)
+{
+ struct firmware *firmware = NULL;
+ int ret = 0;
+
+ *firmware_p = NULL;
+
+ if (!name || name[0] == '\0')
+ ret = -EINVAL;
+
+ *firmware_p = firmware = calloc(1, sizeof(*firmware));
+
+ if (!firmware) {
+ printf("%s: calloc(struct firmware) failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ firmware->name = name;
+ firmware->data = dbuf;
+ firmware->size = size;
+ firmware->offset = offset;
+
+ return ret;
+}
+
+/*
+ * fw_get_filesystem_firmware - load firmware into a allocated buffer
+ * @firmware_p: pointer to firmware image
+ * @location: An array of supported firmware location
+ *
+ * @return: size of total read
+ * -ve when error
+ */
+static int fw_get_filesystem_firmware(struct device_location *location,
+ struct firmware *firmware_p)
+{
+ loff_t actread;
+ char *dev_part;
+ int ret;
+
+ dev_part = env_get("FW_DEV_PART");
+ if (dev_part)
+ set_storage_devpart(location->name, dev_part);
+
+ ret = init_storage_device(location);
+ if (ret)
+ goto out;
+
+ select_fs_dev(location);
+
+ ret = fs_read(firmware_p->name, (ulong)firmware_p->data,
+ firmware_p->offset, firmware_p->size, &actread);
+
+ if (ret || (actread != firmware_p->size)) {
+ printf("Error: %d Failed to read %s from flash %lld ",
+ ret,
+ firmware_p->name,
+ actread);
+ printf("!= %d.\n", firmware_p->size);
+ return -EPERM;
+ } else {
+ ret = actread;
+ }
+
+out:
+#ifdef CONFIG_CMD_UBIFS
+ if (location->ubivol != NULL)
+ umount_ubifs();
+#endif
+
+ return ret;
+}
+
+/*
+ * request_firmware_into_buf - load firmware into a previously allocated buffer
+ * @firmware_p: pointer to firmware image
+ * @name: name of firmware file
+ * @buf: address of buffer to load firmware into
+ * @size: size of buffer
+ * @offset: offset of a file for start reading
+ *
+ * This firmware is loaded directly into the buffer pointed to by @buf and
+ * the @firmware_p data member is pointed at @buf.
+ *
+ * @return: size of total read
+ * -ve when error
+ */
+int request_firmware_into_buf(struct firmware **firmware_p,
+ const char *name,
+ struct device_location *location,
+ void *buf, size_t size, u32 offset)
+{
+ int ret;
+
+ ret = _request_firmware_prepare(firmware_p, name, buf, size, offset);
+ if (ret < 0) /* error */
+ return ret;
+
+ ret = fw_get_filesystem_firmware(location, *firmware_p);
+
+ return ret;
+}
new file mode 100644
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Intel Corporation <www.intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+#ifndef _FS_LOADER_H_
+#define _FS_LOADER_H_
+
+#include <linux/types.h>
+
+struct firmware {
+ size_t size; /* Size of a file */
+ const u8 *data; /* Buffer for file */
+ const char *name; /* Filename */
+ u32 offset; /* Offset of reading a file */
+ void *priv; /* Firmware loader private fields */
+};
+
+struct device_location {
+ char *name; /* Such as mmc, usb,and sata. */
+ char *devpart; /* Use the load command dev:part conventions */
+ char *mtdpart; /* MTD partition for ubi part */
+ char *ubivol; /* UBI volume-name for ubifsmount */
+};
+
+int request_firmware_into_buf(struct firmware **firmware_p,
+ const char *name,
+ struct device_location *location,
+ void *buf, size_t size, u32 offset);
+#endif