diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 5ca0a712d8..c11e83263b 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -34,14 +34,27 @@ config SPI_FLASH
 
 	  If unsure, say N
 
+choice
+	prompt "Support SPI flash above 16MiB"
+	depends on SPI_FLASH
+	optional
+
 config SPI_FLASH_BAR
 	bool "SPI flash Bank/Extended address register support"
-	depends on SPI_FLASH
 	help
 	  Enable the SPI flash Bank/Extended address register support.
 	  Bank/Extended address registers are used to access the flash
 	  which has size > 16MiB in 3-byte addressing.
 
+config SPI_FLASH_4BAIS
+	bool "SPI flash 4-byte address instruction set support"
+	help
+	  Convert the selected 3-byte address op codes into their associated
+	  4-byte address op codes. Using this instruction set does not change
+	  the internal state of the SPI flash device.
+
+endchoice
+
 if SPI_FLASH
 
 config SPI_FLASH_ATMEL
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 8b8c951bcc..30994f9f46 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -27,6 +27,7 @@ enum spi_nor_option_flags {
 };
 
 #define SPI_FLASH_3B_ADDR_LEN		3
+#define SPI_FLASH_4B_ADDR_LEN		4
 #define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN + 16)
 #define SPI_FLASH_16MB_BOUN		0x1000000
 
@@ -64,6 +65,19 @@ enum spi_nor_option_flags {
 #define CMD_READ_CONFIG			0x35
 #define CMD_FLAG_STATUS			0x70
 
+/* 4-byte address instruction set */
+#define CMD_READ_ARRAY_SLOW_4B		0x13
+#define CMD_READ_ARRAY_FAST_4B		0x0c
+#define CMD_READ_DUAL_OUTPUT_FAST_4B	0x3c
+#define CMD_READ_DUAL_IO_FAST_4B	0xbc
+#define CMD_READ_QUAD_OUTPUT_FAST_4B	0x6c
+#define CMD_READ_QUAD_IO_FAST_4B	0xec
+#define CMD_PAGE_PROGRAM_4B		0x12
+#define CMD_PAGE_PROGRAM_1_1_4_4B	0x34
+#define CMD_PAGE_PROGRAM_1_4_4_4B	0x3e
+#define CMD_ERASE_4K_4B			0x21
+#define CMD_ERASE_64K_4B		0xdc
+
 /* Bank addr access commands */
 #ifdef CONFIG_SPI_FLASH_BAR
 # define CMD_BANKADDR_BRWR		0x17
@@ -133,6 +147,10 @@ struct spi_flash_info {
 #define RD_QUADIO		BIT(6)	/* use Quad IO Read */
 #define RD_DUALIO		BIT(7)	/* use Dual IO Read */
 #define RD_FULL			(RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
+#define NO_4BAIS		BIT(8)	/*
+					 * 4-byte address instruction set
+					 * NOT supported
+					 */
 };
 
 extern const struct spi_flash_info spi_flash_ids[];
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index c5e00772f2..695c8555db 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -176,6 +176,67 @@ bar_end:
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_4BAIS
+static u8 spi_flash_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
+{
+	size_t i;
+
+	for (i = 0; i < size; i++)
+		if (table[i][0] == opcode)
+			return table[i][1];
+
+	/* No conversion found, keep input op code. */
+	return opcode;
+}
+
+static u8 spi_flash_convert_3to4_read(u8 opcode)
+{
+	static const u8 spi_flash_3to4_read[][2] = {
+		{CMD_READ_ARRAY_SLOW,		CMD_READ_ARRAY_SLOW_4B},
+		{CMD_READ_ARRAY_FAST,		CMD_READ_ARRAY_FAST_4B},
+		{CMD_READ_DUAL_OUTPUT_FAST,	CMD_READ_DUAL_OUTPUT_FAST_4B},
+		{CMD_READ_DUAL_IO_FAST,		CMD_READ_DUAL_IO_FAST_4B},
+		{CMD_READ_QUAD_OUTPUT_FAST,	CMD_READ_QUAD_OUTPUT_FAST_4B},
+		{CMD_READ_QUAD_IO_FAST,		CMD_READ_QUAD_IO_FAST_4B},
+	};
+
+	return spi_flash_convert_opcode(opcode, spi_flash_3to4_read,
+					ARRAY_SIZE(spi_flash_3to4_read));
+}
+
+static u8 spi_flash_convert_3to4_write(u8 opcode)
+{
+	static const u8 spi_flash_3to4_write[][2] = {
+		{CMD_PAGE_PROGRAM,		CMD_PAGE_PROGRAM_4B},
+		{CMD_PAGE_PROGRAM_1_1_4,	CMD_PAGE_PROGRAM_1_1_4_4B},
+		{CMD_PAGE_PROGRAM_1_4_4,	CMD_PAGE_PROGRAM_1_4_4_4B},
+	};
+
+	return spi_flash_convert_opcode(opcode, spi_flash_3to4_write,
+					ARRAY_SIZE(spi_flash_3to4_write));
+}
+
+static u8 spi_flash_convert_3to4_erase(u8 opcode)
+{
+	static const u8 spi_flash_3to4_erase[][2] = {
+		{CMD_ERASE_4K,	CMD_ERASE_4K_4B},
+		{CMD_ERASE_64K,	CMD_ERASE_64K_4B},
+	};
+
+	return spi_flash_convert_opcode(opcode, spi_flash_3to4_erase,
+					ARRAY_SIZE(spi_flash_3to4_erase));
+}
+
+static void spi_flash_set_4byte_addr_opcodes(struct spi_flash *flash,
+					     const struct spi_flash_info *info)
+{
+	flash->read_cmd = spi_flash_convert_3to4_read(flash->read_cmd);
+	flash->write_cmd = spi_flash_convert_3to4_write(flash->write_cmd);
+	flash->erase_cmd = spi_flash_convert_3to4_erase(flash->erase_cmd);
+	flash->addr_len = SPI_FLASH_4B_ADDR_LEN;
+}
+#endif
+
 #ifdef CONFIG_SF_DUAL_FLASH
 static void spi_flash_dual(struct spi_flash *flash, u32 *addr)
 {
@@ -966,6 +1027,7 @@ int spi_flash_scan(struct spi_flash *flash)
 {
 	struct spi_slave *spi = flash->spi;
 	const struct spi_flash_info *info = NULL;
+	bool above_16MB;
 	int ret;
 
 	info = spi_flash_read_id(flash);
@@ -1106,6 +1168,26 @@ int spi_flash_scan(struct spi_flash *flash)
 	/* Set the address length */
 	flash->addr_len = SPI_FLASH_3B_ADDR_LEN;
 
+	above_16MB = ((flash->dual_flash == SF_SINGLE_FLASH) &&
+		      (flash->size > SPI_FLASH_16MB_BOUN)) ||
+		     ((flash->dual_flash > SF_SINGLE_FLASH) &&
+		      (flash->size > SPI_FLASH_16MB_BOUN << 1));
+
+	/*
+	 * replace the selected 3-byte address op codes with the associated
+	 * 4-byte address op codes, if needed (flash->size > 16 MiB)
+	 */
+#ifdef CONFIG_SPI_FLASH_4BAIS
+	if (above_16MB) {
+		if (info->flags & NO_4BAIS) {
+			puts("SF: Warning - Only lower 16MiB accessible,");
+			puts(" 4-byte address instruction set not supported\n");
+		} else {
+			spi_flash_set_4byte_addr_opcodes(flash, info);
+		}
+	}
+#endif
+
 	/* Configure the BAR - discover bank cmds and read current bank */
 #ifdef CONFIG_SPI_FLASH_BAR
 	ret = read_bar(flash, info);
@@ -1131,13 +1213,11 @@ int spi_flash_scan(struct spi_flash *flash)
 	puts("\n");
 #endif
 
-#ifndef CONFIG_SPI_FLASH_BAR
-	if (((flash->dual_flash == SF_SINGLE_FLASH) &&
-	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
-	     ((flash->dual_flash > SF_SINGLE_FLASH) &&
-	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+#if !defined(CONFIG_SPI_FLASH_BAR) && !defined(CONFIG_SPI_FLASH_4BAIS)
+	if (above_16MB) {
 		puts("SF: Warning - Only lower 16MiB accessible,");
-		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+		puts(" Full access #define CONFIG_SPI_FLASH_BAR");
+		puts(" or CONFIG_SPI_FLASH_4BAIS\n");
 	}
 #endif
 
