diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index c061c05443..b8092538e9 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -92,6 +92,30 @@ int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
 	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
+bool dm_spi_is_flash_command_supported(struct udevice *dev,
+				       const struct spi_flash_command *cmd)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->is_flash_command_supported)
+		return ops->is_flash_command_supported(dev, cmd);
+
+	return false;
+}
+
+int dm_spi_exec_flash_command(struct udevice *dev,
+			      const struct spi_flash_command *cmd)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->exec_flash_command)
+		return ops->exec_flash_command(dev, cmd);
+
+	return -EINVAL;
+}
+
 int spi_claim_bus(struct spi_slave *slave)
 {
 	return dm_spi_claim_bus(slave->dev);
@@ -108,6 +132,18 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
 }
 
+bool spi_is_flash_command_supported(struct spi_slave *slave,
+				    const struct spi_flash_command *cmd)
+{
+	return dm_spi_is_flash_command_supported(slave->dev, cmd);
+}
+
+int spi_exec_flash_command(struct spi_slave *slave,
+			   const struct spi_flash_command *cmd)
+{
+	return dm_spi_exec_flash_command(slave->dev, cmd);
+}
+
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 static int spi_child_post_bind(struct udevice *dev)
 {
@@ -147,6 +183,10 @@ static int spi_post_probe(struct udevice *bus)
 		ops->set_mode += gd->reloc_off;
 	if (ops->cs_info)
 		ops->cs_info += gd->reloc_off;
+	if (ops->is_flash_command_supported)
+		ops->is_flash_command_supported += gd->reloc_off;
+	if (ops->exec_flash_command)
+		ops->exec_flash_command += gd->reloc_off;
 #endif
 
 	return 0;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 7d81fbd7f8..e47acdc9e4 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
@@ -58,3 +59,15 @@ struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
 	return spi_setup_slave(busnum, cs, max_hz, mode);
 }
 #endif
+
+__weak bool spi_is_flash_command_supported(struct spi_slave *slave,
+					   const struct spi_flash_command *cmd)
+{
+	return false;
+}
+
+__weak int spi_exec_flash_command(struct spi_slave *slave,
+				  const struct spi_flash_command *cmd)
+{
+	return -EINVAL;
+}
diff --git a/include/spi.h b/include/spi.h
index deb65efdfb..eec36b4689 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -10,6 +10,8 @@
 #ifndef _SPI_H_
 #define _SPI_H_
 
+#include <linux/string.h> /* memset() */
+
 /* SPI mode flags */
 #define SPI_CPHA	BIT(0)			/* clock phase */
 #define SPI_CPOL	BIT(1)			/* clock polarity */
@@ -64,6 +66,116 @@ struct dm_spi_slave_platdata {
 #endif /* CONFIG_DM_SPI */
 
 /**
+ * enum spi_flash_protocol - SPI flash command protocol
+ */
+#define SPI_FPROTO_INST_SHIFT	16
+#define SPI_FPROTO_INST_MASK	GENMASK(23, 16)
+#define SPI_FPROTO_INST(nbits)					\
+	((((unsigned long)(nbits)) << SPI_FPROTO_INST_SHIFT) &	\
+	 SPI_FPROTO_INST_MASK)
+
+#define SPI_FPROTO_ADDR_SHIFT	8
+#define SPI_FPROTO_ADDR_MASK	GENMASK(15, 8)
+#define SPI_FPROTO_ADDR(nbits)					\
+	((((unsigned long)(nbits)) << SPI_FPROTO_ADDR_SHIFT) &	\
+	 SPI_FPROTO_ADDR_MASK)
+
+#define SPI_FPROTO_DATA_SHIFT	0
+#define SPI_FPROTO_DATA_MASK	GENMASK(7, 0)
+#define SPI_FPROTO_DATA(nbits)					\
+	((((unsigned long)(nbits)) << SPI_FPROTO_DATA_SHIFT) &	\
+	 SPI_FPROTO_DATA_MASK)
+
+#define SPI_FPROTO(inst_nbits, addr_nbits, data_nbits)	\
+	(SPI_FPROTO_INST(inst_nbits) |			\
+	 SPI_FPROTO_ADDR(addr_nbits) |			\
+	 SPI_FPROTO_DATA(data_nbits))
+
+enum spi_flash_protocol {
+	SPI_FPROTO_1_1_1 = SPI_FPROTO(1, 1, 1),
+	SPI_FPROTO_1_1_2 = SPI_FPROTO(1, 1, 2),
+	SPI_FPROTO_1_1_4 = SPI_FPROTO(1, 1, 4),
+	SPI_FPROTO_1_2_2 = SPI_FPROTO(1, 2, 2),
+	SPI_FPROTO_1_4_4 = SPI_FPROTO(1, 4, 4),
+	SPI_FPROTO_2_2_2 = SPI_FPROTO(2, 2, 2),
+	SPI_FPROTO_4_4_4 = SPI_FPROTO(4, 4, 4),
+};
+
+static inline
+u8 spi_flash_protocol_get_inst_nbits(enum spi_flash_protocol proto)
+{
+	return ((unsigned long)(proto & SPI_FPROTO_INST_MASK)) >>
+		SPI_FPROTO_INST_SHIFT;
+}
+
+static inline
+u8 spi_flash_protocol_get_addr_nbits(enum spi_flash_protocol proto)
+{
+	return ((unsigned long)(proto & SPI_FPROTO_ADDR_MASK)) >>
+		SPI_FPROTO_ADDR_SHIFT;
+}
+
+static inline
+u8 spi_flash_protocol_get_data_nbits(enum spi_flash_protocol proto)
+{
+	return ((unsigned long)(proto & SPI_FPROTO_DATA_MASK)) >>
+		SPI_FPROTO_DATA_SHIFT;
+}
+
+/**
+ * struct spi_flash_command - SPI flash command structure
+ *
+ * @instr:		Opcode sent to the SPI slave during instr clock cycles.
+ * @mode:		Value sent to the SPI slave during mode clock cycles.
+ * @num_mode_cycles:	Number of mode clock cycles.
+ * @num_wait_states:	Number of wait-state clock cycles.
+ * @addr_len:		Number of bytes sent during address clock cycles:
+ *			should be 0, 3, or 4.
+ * @addr:		Value sent to the SPI slave during address clock cycles.
+ * @data_len:		Number of bytes to be sent during data clock cycles.
+ * @tx_data:		Data sent to the SPI slave during data clock cycles.
+ * @rx_data:		Data read from the SPI slave during data clock cycles.
+ */
+struct spi_flash_command {
+	enum spi_flash_protocol proto;
+	u8 flags;
+#define SPI_FCMD_TYPE		GENMASK(2, 0)
+#define SPI_FCMD_READ		(0x0U << 0)
+#define SPI_FCMD_WRITE		(0x1U << 0)
+#define SPI_FCMD_ERASE		(0x2U << 0)
+#define SPI_FCMD_READ_REG	(0x3U << 0)
+#define SPI_FCMD_WRITE_REG	(0x4U << 0)
+
+	u8 inst;
+	u8 mode;
+	u8 num_mode_cycles;
+	u8 num_wait_states;
+	u8 addr_len;
+	u32 addr;
+	size_t data_len;
+	const void *tx_data;
+	void *rx_data;
+};
+
+/**
+ * Initialize a 'struct spi_flash_command'.
+ *
+ * @cmd:		Pointer to the 'struct spi_flash_command' to initialize.
+ * @instr:		Instruction opcode.
+ * @addr_len:		Number of address bytes.
+ */
+static inline void
+spi_flash_command_init(struct spi_flash_command *cmd,
+		       u8 inst, u8 addr_len, u8 flags)
+{
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->proto = SPI_FPROTO_1_1_1;
+	cmd->inst = inst;
+	cmd->addr_len = addr_len;
+	cmd->flags = flags;
+}
+
+/**
  * struct spi_slave - Representation of a SPI slave
  *
  * For driver model this is the per-child data used by the SPI bus. It can
@@ -252,6 +364,24 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
 int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 		void *din, unsigned long flags);
 
+/**
+ * Check whether the given SPI flash command is supported
+ *
+ * @slave:	The SPI slave
+ * @cmd:	The SPI flash command to check.
+ */
+bool spi_is_flash_command_supported(struct spi_slave *slave,
+				    const struct spi_flash_command *cmd);
+
+/**
+ * Execute SPI flash command
+ *
+ * @slave:	The SPI slave which will execute the give SPI flash command.
+ * @cmd:	The SPI flash command to execute.
+ */
+int spi_exec_flash_command(struct spi_slave *slave,
+			   const struct spi_flash_command *cmd);
+
 /* Copy memory mapped data */
 void spi_flash_copy_mmap(void *data, void *offset, size_t len);
 
@@ -464,6 +594,26 @@ struct dm_spi_ops {
 	 *	   is invalid, other -ve value on error
 	 */
 	int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
+
+	/**
+	 * Check whether the given SPI flash command is supported.
+	 *
+	 * @bus:	The SPI bus
+	 * @cmd:	The SPI flash command to check.
+	 * @return:	true if supported, false otherwise
+	 */
+	bool (*is_flash_command_supported)(struct udevice *bus,
+					   const struct spi_flash_command *cmd);
+
+	/**
+	 * Execute a SPI flash command
+	 *
+	 * @bus:	The SPI bus
+	 * @cmd:	The SPI flash command to execute.
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*exec_flash_command)(struct udevice *bus,
+				  const struct spi_flash_command *cmd);
 };
 
 struct dm_spi_emul_ops {
@@ -651,6 +801,24 @@ void dm_spi_release_bus(struct udevice *dev);
 int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		const void *dout, void *din, unsigned long flags);
 
+/**
+ * Check whether the given SPI flash command is supported.
+ *
+ * @dev:	The SPI slave device
+ * @cmd:	The SPI flash command
+ */
+bool dm_spi_is_flash_command_supported(struct udevice *dev,
+				       const struct spi_flash_command *cmd);
+
+/**
+ * Execute the given SPI flash command.
+ *
+ * @dev:	The SPI slave device
+ * @cmd:	The SPI flash command
+ */
+int dm_spi_exec_flash_command(struct udevice *dev,
+			      const struct spi_flash_command *cmd);
+
 /* Access the operations for a SPI device */
 #define spi_get_ops(dev)	((struct dm_spi_ops *)(dev)->driver->ops)
 #define spi_emul_get_ops(dev)	((struct dm_spi_emul_ops *)(dev)->driver->ops)
