@@ -268,4 +268,15 @@ config GDSYS_RXAUI_CTRL
depends on MISC
help
Support gdsys FPGA's RXAUI control.
+
+config FS_LOADER
+ bool "Enable loader driver for file system"
+ depends on DM
+ help
+ This is file system generic loader which can be used to load
+ the file image from the storage into target such as memory.
+
+ The consumer driver would then use this loader to program whatever,
+ ie. the FPGA device.
+
endmenu
@@ -53,3 +53,4 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o
obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
+obj-$(CONFIG_FS_LOADER) += fs_loader.o
new file mode 100644
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <fs.h>
+#include <fs_loader.h>
+#include <linux/string.h>
+#include <malloc.h>
+#include <spl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct firmware_priv {
+ const char *name; /* Filename */
+ u32 offset; /* Offset of reading a file */
+};
+
+static int select_fs_dev(struct udevice *dev)
+{
+ int ret;
+ struct device_platdata *plat;
+
+ plat = dev->platdata;
+ if (!strcmp("mmc", plat->name)) {
+ ret = fs_set_blk_dev("mmc", plat->devpart, FS_TYPE_ANY);
+ } else if (!strcmp("usb", plat->name)) {
+ ret = fs_set_blk_dev("usb", plat->devpart, FS_TYPE_ANY);
+ } else if (!strcmp("sata", plat->name)) {
+ ret = fs_set_blk_dev("sata", plat->devpart, FS_TYPE_ANY);
+ } else if (!strcmp("ubi", plat->name)) {
+ if (plat->ubivol)
+ ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
+ else
+ ret = -ENODEV;
+ } else {
+ debug("Error: unsupported storage device.\n");
+ return -ENODEV;
+ }
+
+ if (ret)
+ debug("Error: could not access storage.\n");
+
+ return ret;
+}
+
+static void set_storage_devpart(struct udevice *dev, char *devpart)
+{
+ struct device_platdata *plat;
+
+ plat = dev->platdata;
+ plat->devpart = devpart;
+}
+
+static void set_storage_mtdpart(struct udevice *dev, char *mtdpart)
+{
+ struct device_platdata *plat;
+
+ plat = dev->platdata;
+ plat->mtdpart = mtdpart;
+}
+
+static void set_storage_ubivol(struct udevice *dev, char *ubivol)
+{
+ struct device_platdata *plat;
+
+ plat = dev->platdata;
+ plat->ubivol = ubivol;
+}
+
+/**
+ * _request_firmware_prepare - Prepare firmware struct.
+ *
+ * @firmware_p: Pointer to pointer to firmware image.
+ * @name: Name of firmware file.
+ * @dbuf: Address of buffer to load firmware into.
+ * @size: Size of buffer.
+ * @offset: Offset of a file for start reading into buffer.
+ *
+ * Return: Negative value if fail, 0 for successful.
+ */
+static int _request_firmware_prepare(struct firmware **firmware_p,
+ const char *name, void *dbuf,
+ size_t size, u32 offset)
+{
+ struct firmware *firmware;
+ struct firmware_priv *fw_priv;
+
+ *firmware_p = NULL;
+
+ if (!name || name[0] == '\0')
+ return -EINVAL;
+
+ firmware = calloc(1, sizeof(*firmware));
+ if (!firmware)
+ return -ENOMEM;
+
+ fw_priv = calloc(1, sizeof(*fw_priv));
+ if (!fw_priv) {
+ free(firmware);
+ return -ENOMEM;
+ }
+
+ fw_priv->name = name;
+ fw_priv->offset = offset;
+ firmware->data = dbuf;
+ firmware->size = size;
+ firmware->priv = fw_priv;
+ *firmware_p = firmware;
+
+ return 0;
+}
+
+/**
+ * fw_get_filesystem_firmware - load firmware into an allocated buffer.
+ * @dev: An instance of a driver.
+ * @firmware_p: pointer to firmware image.
+ *
+ * Return: Size of total read, negative value when error.
+ */
+static int fw_get_filesystem_firmware(struct udevice *dev,
+ struct firmware *firmware_p)
+{
+ struct firmware_priv *fw_priv = NULL;
+ loff_t actread;
+ char *dev_part, *ubi_mtdpart, *ubi_volume;
+ int ret;
+
+ dev_part = env_get("fw_dev_part");
+ if (dev_part)
+ set_storage_devpart(dev, dev_part);
+
+ ubi_mtdpart = env_get("fw_ubi_mtdpart");
+ if (ubi_mtdpart)
+ set_storage_mtdpart(dev, ubi_mtdpart);
+
+ ubi_volume = env_get("fw_ubi_volume");
+ if (ubi_volume)
+ set_storage_ubivol(dev, ubi_volume);
+
+ ret = select_fs_dev(dev);
+ if (ret)
+ goto out;
+
+ fw_priv = firmware_p->priv;
+
+ ret = fs_read(fw_priv->name, (ulong)firmware_p->data, fw_priv->offset,
+ firmware_p->size, &actread);
+ if (ret) {
+ debug("Error: %d Failed to read %s from flash %lld != %d.\n",
+ ret, fw_priv->name, actread, firmware_p->size);
+ } else {
+ ret = actread;
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * request_firmware_into_buf - Load firmware into a previously allocated buffer.
+ * @dev: An instance of a driver.
+ * @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 into buffer.
+ *
+ * The 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, negative value when error.
+ */
+int request_firmware_into_buf(struct udevice *dev,
+ struct firmware **firmware_p,
+ const char *name,
+ 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(dev, *firmware_p);
+
+ return ret;
+}
+
+static int fs_loader_ofdata_to_platdata(struct udevice *dev)
+{
+ struct device_platdata *plat;
+ const void *blob;
+ int node;
+
+ plat = dev->platdata;
+ blob = gd->fdt_blob;
+ node = dev_of_offset(dev);
+ plat->name = (char *)fdt_getprop(blob, node,
+ "storage_device", NULL);
+
+ plat->devpart = (char *)fdt_getprop(blob, node,
+ "devpart", NULL);
+
+ plat->mtdpart = (char *)fdt_getprop(blob, node,
+ "mtdpart", NULL);
+
+ plat->ubivol = (char *)fdt_getprop(blob, node,
+ "ubivol", NULL);
+
+ return 0;
+}
+
+static int fs_loader_probe(struct udevice *dev)
+{
+ return 0;
+};
+
+static const struct udevice_id fs_loader_ids[] = {
+ { .compatible = "fs_loader"},
+ { }
+};
+
+U_BOOT_DRIVER(fs_loader) = {
+ .name = "fs_loader",
+ .id = UCLASS_FS_FIRMWARE_LOADER,
+ .of_match = fs_loader_ids,
+ .probe = fs_loader_probe,
+ .ofdata_to_platdata = fs_loader_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct device_platdata),
+};
+
+UCLASS_DRIVER(fs_loader) = {
+ .id = UCLASS_FS_FIRMWARE_LOADER,
+ .name = "fs_loader",
+};
@@ -36,6 +36,7 @@ enum uclass_id {
UCLASS_DMA, /* Direct Memory Access */
UCLASS_EFI, /* EFI managed devices */
UCLASS_ETH, /* Ethernet device */
+ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_GPIO, /* Bank of general-purpose I/O pins */
UCLASS_FIRMWARE, /* Firmware */
UCLASS_I2C, /* I2C bus */
new file mode 100644
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+#ifndef _FS_LOADER_H_
+#define _FS_LOADER_H_
+
+#include <dm.h>
+
+struct firmware {
+ size_t size; /* Size of a file */
+ const u8 *data; /* Buffer for file */
+ void *priv; /* Firmware loader private fields */
+};
+
+struct device_platdata {
+ 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 udevice *dev,
+ struct firmware **firmware_p,
+ const char *name,
+ void *buf, size_t size, u32 offset);
+#endif