diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index be900cf..59f716b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -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
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e362609..74364a0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -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
diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
new file mode 100644
index 0000000..127f7f1
--- /dev/null
+++ b/drivers/misc/fs_loader.c
@@ -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",
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index d7f9df3..39e88ac 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -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 */
diff --git a/include/fs_loader.h b/include/fs_loader.h
new file mode 100644
index 0000000..0f0ea00
--- /dev/null
+++ b/include/fs_loader.h
@@ -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
