diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index f19cc26..098de0c 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -268,6 +268,14 @@ static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page)
 	return fpga_reload(fme, type, page);
 }
 
+static int ifpga_mgr_read_flash(struct opae_manager *mgr, u32 address,
+		u32 size, void *buf)
+{
+	struct ifpga_fme_hw *fme = mgr->data;
+
+	return fme_mgr_read_flash(fme, address, size, buf);
+}
+
 struct opae_manager_ops ifpga_mgr_ops = {
 	.flash = ifpga_mgr_flash,
 	.get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info,
@@ -277,6 +285,7 @@ struct opae_manager_ops ifpga_mgr_ops = {
 	.update_flash = ifpga_mgr_update_flash,
 	.stop_flash_update = ifpga_mgr_stop_flash_update,
 	.reload = ifpga_mgr_reload,
+	.read_flash = ifpga_mgr_read_flash
 };
 
 static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset,
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.h b/drivers/raw/ifpga/base/ifpga_feature_dev.h
index a637eb5..7a2f2e5 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.h
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.h
@@ -223,4 +223,6 @@ int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme,
 int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme,
 		struct opae_sensor_info *sensor,
 		unsigned int *value);
+int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,
+		u32 size, void *buf);
 #endif /* _IFPGA_FEATURE_DEV_H_ */
diff --git a/drivers/raw/ifpga/base/ifpga_fme.c b/drivers/raw/ifpga/base/ifpga_fme.c
index 608a352..25ff819 100644
--- a/drivers/raw/ifpga/base/ifpga_fme.c
+++ b/drivers/raw/ifpga/base/ifpga_fme.c
@@ -1658,3 +1658,11 @@ struct ifpga_feature_ops fme_pmci_ops = {
 	.init = fme_pmci_init,
 	.uinit = fme_pmci_uinit,
 };
+
+int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,
+		u32 size, void *buf)
+{
+	struct intel_max10_device *max10 = fme->max10_dev;
+
+	return opae_read_flash(max10, address, size, buf);
+}
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 87256fc..fd08326 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -1041,3 +1041,23 @@ int opae_mgr_reload(struct opae_manager *mgr, int type, int page)
 
 	return -ENOENT;
 }
+/**
+ * opae_mgr_read_flash -  read flash content
+ * @mgr: targeted manager
+ * @address: the start address of flash
+ * @size: the size of flash
+ * @buf: the read buffer
+ *
+ * Return: 0 on success, otherwise error code.
+ */
+int opae_mgr_read_flash(struct opae_manager *mgr, u32 address,
+		u32 size, void *buf)
+{
+	if (!mgr)
+		return -EINVAL;
+
+	if (mgr->ops && mgr->ops->read_flash)
+		return mgr->ops->read_flash(mgr, address, size, buf);
+
+	return -ENOENT;
+}
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index fd40e09..de1e984 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -60,6 +60,7 @@ struct opae_manager_ops {
 			u64 *status);
 	int (*stop_flash_update)(struct opae_manager *mgr, int force);
 	int (*reload)(struct opae_manager *mgr, int type, int page);
+	int (*read_flash)(struct opae_manager *mgr, u32 address, u32 size, void *buf);
 };
 
 /* networking management ops in FME */
@@ -368,4 +369,5 @@ int opae_mgr_update_flash(struct opae_manager *mgr, const char *image,
 		uint64_t *status);
 int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force);
 int opae_mgr_reload(struct opae_manager *mgr, int type, int page);
+int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, u32 size, void *buf);
 #endif /* _OPAE_HW_API_H_*/
diff --git a/drivers/raw/ifpga/base/opae_intel_max10.c b/drivers/raw/ifpga/base/opae_intel_max10.c
index 26f323c..9c01729 100644
--- a/drivers/raw/ifpga/base/opae_intel_max10.c
+++ b/drivers/raw/ifpga/base/opae_intel_max10.c
@@ -58,6 +58,279 @@ int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset,
 	return max10_sys_write(dev, offset, temp);
 }
 
+static int n3000_bulk_raw_write(struct intel_max10_device *dev, uint32_t addr,
+	void *buf, uint32_t len)
+{
+	uint32_t v = 0;
+	uint32_t i = 0;
+	char *p = buf;
+	int ret = 0;
+
+	len = IFPGA_ALIGN(len, 4);
+
+	for (i = 0; i < len; i += 4) {
+		v = *(uint32_t *)(p + i);
+		ret = max10_reg_write(dev, addr + i, v);
+		if (ret < 0) {
+			dev_err(dev,
+				"Failed to write to staging area 0x%08x [e:%d]\n",
+				addr + i, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int n3000_bulk_raw_read(struct intel_max10_device *dev,
+		uint32_t addr, void *buf, uint32_t len)
+{
+	u32 v, i;
+	char *p = buf;
+	int ret;
+
+	len = IFPGA_ALIGN(len, 4);
+
+	for (i = 0; i < len; i += 4) {
+		ret = max10_reg_read(dev, addr + i, &v);
+		if (ret < 0) {
+			dev_err(dev,
+				"Failed to write to staging area 0x%08x [e:%d]\n",
+				addr + i, ret);
+			return ret;
+		}
+		*(u32 *)(p + i) = v;
+	}
+
+	return 0;
+}
+
+static int n3000_flash_read(struct intel_max10_device *dev,
+		u32 addr, void *buf, u32 size)
+{
+	if (!dev->raw_blk_ops.read_blk)
+		return -ENODEV;
+
+	return dev->raw_blk_ops.read_blk(dev, addr, buf, size);
+}
+
+static int n3000_flash_write(struct intel_max10_device *dev,
+		u32 addr, void *buf, u32 size)
+{
+	if (!dev->raw_blk_ops.write_blk)
+		return -ENODEV;
+
+	return dev->raw_blk_ops.write_blk(dev, addr, buf, size);
+}
+
+static u32
+pmci_get_write_space(struct intel_max10_device *dev, u32 size)
+{
+	u32 count, val;
+	int ret;
+
+	ret = opae_readl_poll_timeout(dev->mmio + PMCI_FLASH_CTRL, val,
+				GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) ==
+				PMCI_FIFO_MAX_WORDS,
+				PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US);
+	if (ret == -ETIMEDOUT)
+		return 0;
+
+	count = GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) * 4;
+
+	return (size > count) ? count : size;
+}
+
+static void pmci_write_fifo(void __iomem *base, char *buf, size_t count)
+{
+	size_t i;
+	u32 val;
+
+	for (i = 0; i < count/4 ; i++) {
+		val = *(u32 *)(buf + i * 4);
+		writel(val, base);
+	}
+}
+
+static void pmci_read_fifo(void __iomem *base, char *buf, size_t count)
+{
+	size_t i;
+	u32 val;
+
+	for (i = 0; i < count/4; i++) {
+		val = readl(base);
+		*(u32 *)(buf + i * 4) = val;
+	}
+}
+
+static int
+__pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr,
+		void *buf, u32 size)
+{
+	UNUSED(addr);
+	u32 blk_size, n_offset = 0;
+
+	while (size) {
+		blk_size = pmci_get_write_space(dev, size);
+		if (blk_size == 0) {
+			dev_err(pmci->dev, "get FIFO available size fail\n");
+			return -EIO;
+		}
+		size -= blk_size;
+		pmci_write_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + n_offset,
+				blk_size);
+		n_offset += blk_size;
+	}
+
+	return 0;
+}
+
+static int
+pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr,
+		void *buf, u32 size)
+{
+	int ret;
+
+	pthread_mutex_lock(dev->bmc_ops.mutex);
+
+	ret = __pmci_flash_bulk_write(dev, addr, buf, size);
+
+	pthread_mutex_unlock(dev->bmc_ops.mutex);
+	return ret;
+}
+
+static int
+pmci_set_flash_host_mux(struct intel_max10_device *dev, bool request)
+{
+	u32 ctrl;
+	int ret;
+
+	ret = max10_sys_update_bits(dev,
+			m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL,
+			FLASH_HOST_REQUEST,
+			SET_FIELD(FLASH_HOST_REQUEST, request));
+	if (ret)
+		return ret;
+
+	return opae_max10_read_poll_timeout(dev, m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL,
+			ctrl, request ? (get_flash_mux(ctrl) == FLASH_MUX_HOST) :
+			(get_flash_mux(ctrl) != FLASH_MUX_HOST),
+			PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US);
+}
+
+static int
+pmci_get_mux(struct intel_max10_device *dev)
+{
+	pthread_mutex_lock(dev->bmc_ops.mutex);
+	return pmci_set_flash_host_mux(dev, true);
+}
+
+static int
+pmci_put_mux(struct intel_max10_device *dev)
+{
+	int ret;
+
+	ret = pmci_set_flash_host_mux(dev, false);
+	pthread_mutex_unlock(dev->bmc_ops.mutex);
+	return ret;
+}
+
+static int
+__pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr,
+		     void *buf, u32 size)
+{
+	u32 blk_size, offset = 0, val;
+	int ret;
+
+	while (size) {
+		blk_size = min_t(u32, size, PMCI_READ_BLOCK_SIZE);
+
+		opae_writel(addr + offset, dev->mmio + PMCI_FLASH_ADDR);
+
+		opae_writel(SET_FIELD(PMCI_FLASH_READ_COUNT, blk_size / 4)
+				| PMCI_FLASH_RD_MODE,
+			dev->mmio + PMCI_FLASH_CTRL);
+
+		ret = opae_readl_poll_timeout((dev->mmio + PMCI_FLASH_CTRL),
+				val, !(val & PMCI_FLASH_BUSY),
+				PMCI_FLASH_INT_US,
+				PMCI_FLASH_TIMEOUT_US);
+		if (ret) {
+			dev_err(dev, "%s timed out on reading flash 0x%xn",
+				__func__, val);
+			return ret;
+		}
+
+		pmci_read_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + offset,
+				blk_size);
+
+		size -= blk_size;
+		offset += blk_size;
+
+		opae_writel(0, dev->mmio + PMCI_FLASH_CTRL);
+	}
+
+	return 0;
+}
+
+static int
+pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr,
+		     void *buf, u32 size)
+{
+	int ret;
+
+	ret = pmci_get_mux(dev);
+	if (ret)
+		goto fail;
+
+	ret = __pmci_flash_bulk_read(dev, addr, buf, size);
+	if (ret)
+		goto fail;
+
+	return pmci_put_mux(dev);
+
+fail:
+	pmci_put_mux(dev);
+	return ret;
+}
+
+static int pmci_check_flash_address(u32 start, u32 end)
+{
+	if (start < PMCI_FLASH_START || end > PMCI_FLASH_END)
+		return -EINVAL;
+
+	return 0;
+}
+
+int opae_read_flash(struct intel_max10_device *dev, u32 addr,
+		u32 size, void *buf)
+{
+	int ret;
+
+	if (!dev->bmc_ops.flash_read)
+		return -ENODEV;
+
+	if (!buf)
+		return -EINVAL;
+
+	if (dev->bmc_ops.check_flash_range) {
+		ret = dev->bmc_ops.check_flash_range(addr, addr + size);
+		if (ret)
+			return ret;
+	} else {
+		u32 top_addr = dev->staging_area_base + dev->staging_area_size;
+		if ((addr < dev->staging_area_base) ||
+			((addr + size) >= top_addr))
+			return -EINVAL;
+	}
+
+	ret = dev->bmc_ops.flash_read(dev, addr, buf, size);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int max10_spi_read(struct intel_max10_device *dev,
 	unsigned int addr, unsigned int *val)
 {
@@ -841,6 +1114,11 @@ int max10_get_bmcfw_version(struct intel_max10_device *dev, unsigned int *val)
 		dev->ops = &m10bmc_n3000_regmap;
 		dev->csr = &m10bmc_spi_csr;
 
+		dev->raw_blk_ops.write_blk = n3000_bulk_raw_write;
+		dev->raw_blk_ops.read_blk = n3000_bulk_raw_read;
+		dev->bmc_ops.flash_read = n3000_flash_read;
+		dev->bmc_ops.flash_write = n3000_flash_write;
+
 		/* check the max10 version */
 		ret = check_max10_version(dev);
 		if (ret) {
@@ -871,6 +1149,10 @@ int max10_get_bmcfw_version(struct intel_max10_device *dev, unsigned int *val)
 		dev->staging_area_size = MAX_STAGING_AREA_SIZE;
 		dev->flags |= MAX10_FLAGS_SECURE;
 
+		dev->bmc_ops.flash_read = pmci_flash_bulk_read;
+		dev->bmc_ops.flash_write = pmci_flash_bulk_write;
+		dev->bmc_ops.check_flash_range = pmci_check_flash_address;
+
 		ret = pthread_mutex_init(&dev->bmc_ops.lock, NULL);
 		if (ret)
 			return ret;
diff --git a/drivers/raw/ifpga/base/opae_intel_max10.h b/drivers/raw/ifpga/base/opae_intel_max10.h
index 6a1b122..0f3360e 100644
--- a/drivers/raw/ifpga/base/opae_intel_max10.h
+++ b/drivers/raw/ifpga/base/opae_intel_max10.h
@@ -62,9 +62,22 @@ struct m10bmc_csr {
 };
 
 /**
+ * struct flash_raw_blk_ops - device specific operations for flash R/W
+ * @write_blk: write a block of data to flash
+ * @read_blk: read a block of data from flash
+ */
+struct flash_raw_blk_ops {
+	int (*write_blk)(struct intel_max10_device *dev, uint32_t addr,
+			void *buf, uint32_t size);
+	int (*read_blk)(struct intel_max10_device *dev, uint32_t addr,
+			void *buf, uint32_t size);
+};
+
+/**
  * struct m10bmc_ops - device specific operations
  * @lock: prevent concurrent flash read/write
  * @mutex: prevent concurrent bmc read/write
+ * @check_flash_range: validate flash address
  * @flash_read: read a block of data from flash
  * @flash_write: write a block of data to flash
  */
@@ -92,6 +105,7 @@ struct intel_max10_device {
 	enum m10bmc_type type;
 	const struct m10bmc_regmap *ops;
 	const struct m10bmc_csr *csr;
+	struct flash_raw_blk_ops raw_blk_ops;
 	struct m10bmc_ops bmc_ops;
 	u8 *mmio; /* mmio address for PMCI */
 };
@@ -431,6 +445,22 @@ struct opae_sensor_info {
 #define PMCI_FPGA_RECONF_PAGE  GENMASK(22, 20)
 #define PMCI_FPGA_RP_LOAD      BIT(23)
 
+#define PMCI_FLASH_CTRL 0x40
+#define PMCI_FLASH_WR_MODE BIT(0)
+#define PMCI_FLASH_RD_MODE BIT(1)
+#define PMCI_FLASH_BUSY    BIT(2)
+#define PMCI_FLASH_FIFO_SPACE GENMASK(13, 4)
+#define PMCI_FLASH_READ_COUNT GENMASK(25, 16)
+
+#define PMCI_FLASH_INT_US       1
+#define PMCI_FLASH_TIMEOUT_US   10000
+
+#define PMCI_FLASH_ADDR 0x44
+#define PMCI_FLASH_FIFO 0x800
+#define PMCI_READ_BLOCK_SIZE 0x800
+#define PMCI_FIFO_MAX_BYTES 0x800
+#define PMCI_FIFO_MAX_WORDS (PMCI_FIFO_MAX_BYTES / 4)
+
 #define M10BMC_PMCI_FPGA_POC	0xb0
 #define PMCI_FPGA_POC		BIT(0)
 #define PMCI_NIOS_REQ_CLEAR	BIT(1)
@@ -447,6 +477,16 @@ struct opae_sensor_info {
 #define PMCI_FPGA_BOOT_PAGE  GENMASK(2, 0)
 #define PMCI_FPGA_CONFIGURED  BIT(3)
 
+#define M10BMC_PMCI_FLASH_CTRL 0x1d0
+#define FLASH_MUX_SELECTION GENMASK(2, 0)
+#define FLASH_MUX_IDLE 0
+#define FLASH_MUX_NIOS 1
+#define FLASH_MUX_HOST 2
+#define FLASH_MUX_PFL  4
+#define get_flash_mux(mux)  GET_FIELD(FLASH_MUX_SELECTION, mux)
+#define FLASH_NIOS_REQUEST BIT(4)
+#define FLASH_HOST_REQUEST BIT(5)
+
 #define M10BMC_PMCI_SDM_CTRL_STS 0x230
 #define PMCI_SDM_IMG_REQ	BIT(0)
 #define PMCI_SDM_STAT GENMASK(23, 16)
@@ -472,4 +512,10 @@ struct opae_sensor_info {
 #define SDM_STAT_CS_MIS   0x12
 #define SDM_STAT_PR_MIS   0x13
 #define SDM_STAT_MAX SDM_STAT_PR_MIS
+
+#define PMCI_FLASH_START 0x10000
+#define PMCI_FLASH_END 0xC7FFFFF
+
+int opae_read_flash(struct intel_max10_device *dev, u32 addr,
+		u32 size, void *buf);
 #endif
diff --git a/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h b/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h
index 3ff49a8..68499e6 100644
--- a/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h
+++ b/drivers/raw/ifpga/base/osdep_rte/osdep_generic.h
@@ -39,6 +39,16 @@
 #define min(a, b) RTE_MIN(a, b)
 #define max(a, b) RTE_MAX(a, b)
 
+#define min_t(type, x, y) ({                    \
+	type __min1 = (x);                      \
+	type __min2 = (y);                      \
+	__min1 < __min2 ? __min1 : __min2; })
+
+#define max_t(type, x, y) ({                    \
+	type __max1 = (x);                      \
+	type __max2 = (y);                      \
+	__max1 > __max2 ? __max1 : __max2; })
+
 #define spinlock_t rte_spinlock_t
 #define spinlock_init(x) rte_spinlock_init(x)
 #define spinlock_lock(x) rte_spinlock_lock(x)
