From: Vincent Wiemann <me@bibbl.com>
Date: Sat, 6 Jan 2018 04:33:09 +0100
Subject: ramips: mtd: spi-nor: add support for switching between 3-byte and 4-byte addressing on w25q256 flash

CAUTION! NEEDS TESTING!
Tries to backport switching between 3-byte and 4-byte addressing on w25q256 flash from Lede master (62ede4f78389c313a8004e79330a7d055eda2f7d) by Felix Fietkau.

Applied patches:
mtd: spi-nor: rename SPINOR_OP_* macros of the 4-byte address op codes
mtd: spi-nor: add a stateless method to support memory size above 128Mib
mtd: spi-nor: add w25q256 3b-mode-switch
mtd: add chunked read-io to m25p80

On some devices the flash chip needs to be in 3-byte addressing mode during
reboot, otherwise the boot loader will fail to start.
This mode however does not allow regular reads/writes onto the upper 16M
half. W25Q256 has separate read commands for reading from >16M, however
it does not have any separate write commands.
This patch changes the code to leave the chip in 3-byte mode most of the
time and only switch during erase/write cycles that go to >16M
addresses.

Signed-off-by: Vincent Wiemann (me@bibbl.com)

diff --git a/target/linux/ramips/patches-4.4/400-mtd-spi-nor-add-w25q256-3b-mode-switch.patch b/target/linux/ramips/patches-4.4/400-mtd-spi-nor-add-w25q256-3b-mode-switch.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5399f547e4edd0eb1cfee8c1ec5b35e69c692ee9
--- /dev/null
+++ b/target/linux/ramips/patches-4.4/400-mtd-spi-nor-add-w25q256-3b-mode-switch.patch
@@ -0,0 +1,399 @@
+--- a/drivers/mtd/devices/serial_flash_cmds.h
++++ b/drivers/mtd/devices/serial_flash_cmds.h
+@@ -18,19 +18,12 @@
+ #define SPINOR_OP_RDVCR		0x85
+ 
+ /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
+-#define SPINOR_OP_READ_1_2_2	0xbb	/* DUAL I/O READ */
+-#define SPINOR_OP_READ_1_4_4	0xeb	/* QUAD I/O READ */
+-
+ #define SPINOR_OP_WRITE		0x02	/* PAGE PROGRAM */
+ #define SPINOR_OP_WRITE_1_1_2	0xa2	/* DUAL INPUT PROGRAM */
+ #define SPINOR_OP_WRITE_1_2_2	0xd2	/* DUAL INPUT EXT PROGRAM */
+ #define SPINOR_OP_WRITE_1_1_4	0x32	/* QUAD INPUT PROGRAM */
+ #define SPINOR_OP_WRITE_1_4_4	0x12	/* QUAD INPUT EXT PROGRAM */
+ 
+-/* READ commands with 32-bit addressing */
+-#define SPINOR_OP_READ4_1_2_2	0xbc
+-#define SPINOR_OP_READ4_1_4_4	0xec
+-
+ /* Configuration flags */
+ #define FLASH_FLAG_SINGLE	0x000000ff
+ #define FLASH_FLAG_READ_WRITE	0x00000001
+--- a/drivers/mtd/devices/st_spi_fsm.c
++++ b/drivers/mtd/devices/st_spi_fsm.c
+@@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_c
+  *	- 'FAST' variants configured for 8 dummy cycles (see note above.)
+  */
+ static struct seq_rw_config n25q_read4_configs[] = {
+-	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4,	0, 4, 4, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4,	0, 1, 4, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2,	0, 2, 2, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2,	0, 1, 2, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ4_FAST,	0, 1, 1, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4,	0, 1, 1, 0x00, 0, 0},
+-	{0x00,			0,			0, 0, 0, 0x00, 0, 0},
++	{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
++	{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
++	{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
++	{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
++	{FLASH_FLAG_READ_FAST,	SPINOR_OP_READ_FAST_4B,  0, 1, 1, 0x00, 0, 8},
++	{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B,       0, 1, 1, 0x00, 0, 0},
++	{0x00,			0,                       0, 0, 0, 0x00, 0, 0},
+ };
+ 
+ /*
+@@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(
+  * entering a state that is incompatible with the SPIBoot Controller.
+  */
+ static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
+-	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
+-	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
+-	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
+-	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ4,        0, 1, 1, 0x00, 0, 0},
+-	{0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
++	{FLASH_FLAG_READ_1_4_4,  SPINOR_OP_READ_1_4_4_4B,  0, 4, 4, 0x00, 2, 4},
++	{FLASH_FLAG_READ_1_1_4,  SPINOR_OP_READ_1_1_4_4B,  0, 1, 4, 0x00, 0, 8},
++	{FLASH_FLAG_READ_1_2_2,  SPINOR_OP_READ_1_2_2_4B,  0, 2, 2, 0x00, 4, 0},
++	{FLASH_FLAG_READ_1_1_2,  SPINOR_OP_READ_1_1_2_4B,  0, 1, 2, 0x00, 0, 8},
++	{FLASH_FLAG_READ_FAST,   SPINOR_OP_READ_FAST_4B,   0, 1, 1, 0x00, 0, 8},
++	{FLASH_FLAG_READ_WRITE,  SPINOR_OP_READ_4B,        0, 1, 1, 0x00, 0, 0},
++	{0x00,                   0,                        0, 0, 0, 0x00, 0, 0},
+ };
+ 
+ static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -69,6 +69,14 @@ struct flash_info {
+ #define	SPI_NOR_QUAD_READ	0x40    /* Flash supports Quad Read */
+ #define	USE_FSR			0x80	/* use flag status register */
+ #define	SPI_NOR_HAS_LOCK	0x100	/* Flash supports lock/unlock via SR */
++#define SPI_NOR_4B_OPCODES	0x200	/*
++					 * Use dedicated 4byte address op codes
++					 * to support memory size above 128Mib.
++					 */
++#define SPI_NOR_4B_READ_OP	0x400	/*
++					 * Like SPI_NOR_4B_OPCODES, but for read
++					 * op code only.
++					 */
+ };
+ 
+ #define JEDEC_MFR(info)	((info)->id[0])
+@@ -182,6 +190,89 @@ static inline struct spi_nor *mtd_to_spi
+ 	return mtd->priv;
+ }
+ 
++
++static u8 spi_nor_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 inline u8 spi_nor_convert_3to4_read(u8 opcode)
++{
++	static const u8 spi_nor_3to4_read[][2] = {
++		{ SPINOR_OP_READ,	SPINOR_OP_READ_4B },
++		{ SPINOR_OP_READ_FAST,	SPINOR_OP_READ_FAST_4B },
++		{ SPINOR_OP_READ_1_1_2,	SPINOR_OP_READ_1_1_2_4B },
++		{ SPINOR_OP_READ_1_2_2,	SPINOR_OP_READ_1_2_2_4B },
++		{ SPINOR_OP_READ_1_1_4,	SPINOR_OP_READ_1_1_4_4B },
++		{ SPINOR_OP_READ_1_4_4,	SPINOR_OP_READ_1_4_4_4B },
++	};
++
++	return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
++				      ARRAY_SIZE(spi_nor_3to4_read));
++}
++
++static inline u8 spi_nor_convert_3to4_program(u8 opcode)
++{
++	static const u8 spi_nor_3to4_program[][2] = {
++		{ SPINOR_OP_PP,		SPINOR_OP_PP_4B },
++		{ SPINOR_OP_PP_1_1_4,	SPINOR_OP_PP_1_1_4_4B },
++		{ SPINOR_OP_PP_1_4_4,	SPINOR_OP_PP_1_4_4_4B },
++	};
++
++	return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
++				      ARRAY_SIZE(spi_nor_3to4_program));
++}
++
++static inline u8 spi_nor_convert_3to4_erase(u8 opcode)
++{
++	static const u8 spi_nor_3to4_erase[][2] = {
++		{ SPINOR_OP_BE_4K,	SPINOR_OP_BE_4K_4B },
++		{ SPINOR_OP_BE_32K,	SPINOR_OP_BE_32K_4B },
++		{ SPINOR_OP_SE,		SPINOR_OP_SE_4B },
++	};
++
++	return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
++				      ARRAY_SIZE(spi_nor_3to4_erase));
++}
++
++static void spi_nor_set_4byte_read(struct spi_nor *nor,
++				   const struct flash_info *info)
++{
++	nor->addr_width = 3;
++	nor->ext_addr = 0;
++	nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
++	nor->flags |= SNOR_F_4B_EXT_ADDR;
++}
++
++
++
++static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
++				      const struct flash_info *info)
++{
++	/* Do some manufacturer fixups first */
++	switch (JEDEC_MFR(info)) {
++	case SNOR_MFR_SPANSION:
++		/* No small sector erase for 4-byte command set */
++		nor->erase_opcode = SPINOR_OP_SE;
++		nor->mtd.erasesize = info->sector_size;
++		break;
++
++	default:
++		break;
++	}
++
++	nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
++	nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
++	nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
++}
++
+ /* Enable/disable 4-byte addressing mode. */
+ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
+ 			    int enable)
+@@ -313,6 +404,36 @@ static void spi_nor_unlock_and_unprep(st
+ 	mutex_unlock(&nor->lock);
+ }
+ 
++static int spi_nor_check_ext_addr(struct spi_nor *nor, u32 addr)
++{
++	bool ext_addr;
++	int ret;
++	u8 cmd;
++
++	if (!(nor->flags & SNOR_F_4B_EXT_ADDR))
++		return 0;
++
++	ext_addr = !!(addr & 0xff000000);
++	if (nor->ext_addr == ext_addr)
++		return 0;
++
++	cmd = ext_addr ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
++	write_enable(nor);
++	ret = nor->write_reg(nor, cmd, NULL, 0);
++	if (ret)
++		return ret;
++
++	cmd = 0;
++	ret = nor->write_reg(nor, SPINOR_OP_WREAR, &cmd, 1);
++	if (ret)
++		return ret;
++
++	nor->addr_width = 3 + ext_addr;
++	nor->ext_addr = ext_addr;
++	write_disable(nor);
++	return 0;
++}
++
+ /*
+  * Erase an address range on the nor chip.  The address range may extend
+  * one or more erase sectors.  Return an error is there is a problem erasing.
+@@ -338,6 +459,10 @@ static int spi_nor_erase(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	ret = spi_nor_check_ext_addr(nor, addr + len);
++	if (ret)
++		return ret;
++
+ 	/* whole-chip erase? */
+ 	if (len == mtd->size) {
+ 		unsigned long timeout;
+@@ -396,6 +521,7 @@ static int spi_nor_erase(struct mtd_info
+ 	return ret;
+ 
+ erase_err:
++	spi_nor_check_ext_addr(nor, 0);
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+ 	instr->state = MTD_ERASE_FAILED;
+ 	return ret;
+@@ -585,7 +711,9 @@ static int spi_nor_lock(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	spi_nor_check_ext_addr(nor, ofs + len);
+ 	ret = nor->flash_lock(nor, ofs, len);
++	spi_nor_check_ext_addr(nor, 0);
+ 
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
+ 	return ret;
+@@ -600,7 +728,9 @@ static int spi_nor_unlock(struct mtd_inf
+ 	if (ret)
+ 		return ret;
+ 
++	spi_nor_check_ext_addr(nor, ofs + len);
+ 	ret = nor->flash_unlock(nor, ofs, len);
++	spi_nor_check_ext_addr(nor, 0);
+ 
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+ 	return ret;
+@@ -851,7 +981,7 @@ static const struct flash_info spi_nor_i
+ 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+-	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
++	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_READ_OP) },
+ 
+ 	/* Catalyst / On Semiconductor -- non-JEDEC */
+ 	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+@@ -898,8 +1028,23 @@ static int spi_nor_read(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	if (nor->flags & SNOR_F_4B_EXT_ADDR)
++		nor->addr_width = 4;
++
+ 	ret = nor->read(nor, from, len, retlen, buf);
+ 
++	if (nor->flags & SNOR_F_4B_EXT_ADDR) {
++		u8 val = 0;
++
++		if ((from + len) & 0xff000000) {
++			write_enable(nor);
++			nor->write_reg(nor, SPINOR_OP_WREAR, &val, 1);
++			write_disable(nor);
++		}
++
++		nor->addr_width = 3;
++	}
++
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+ 	return ret;
+ }
+@@ -988,6 +1133,10 @@ static int spi_nor_write(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	ret = spi_nor_check_ext_addr(nor, to + len);
++	if (ret < 0)
++		return ret;
++
+ 	write_enable(nor);
+ 
+ 	page_offset = to & (nor->page_size - 1);
+@@ -1018,6 +1167,7 @@ static int spi_nor_write(struct mtd_info
+ 
+ 	ret = spi_nor_wait_till_ready(nor);
+ write_err:
++	spi_nor_check_ext_addr(nor, 0);
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+ 	return ret;
+ }
+@@ -1366,27 +1516,12 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	else if (mtd->size > 0x1000000) {
+ 		/* enable 4-byte addressing if the device exceeds 16MiB */
+ 		nor->addr_width = 4;
+-		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
+-			/* Dedicated 4-byte command set */
+-			switch (nor->flash_read) {
+-			case SPI_NOR_QUAD:
+-				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
+-				break;
+-			case SPI_NOR_DUAL:
+-				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
+-				break;
+-			case SPI_NOR_FAST:
+-				nor->read_opcode = SPINOR_OP_READ4_FAST;
+-				break;
+-			case SPI_NOR_NORMAL:
+-				nor->read_opcode = SPINOR_OP_READ4;
+-				break;
+-			}
+-			nor->program_opcode = SPINOR_OP_PP_4B;
+-			/* No small sector erase for 4-byte command set */
+-			nor->erase_opcode = SPINOR_OP_SE_4B;
+-			mtd->erasesize = info->sector_size;
+-		} else
++		if (info->flags & SPI_NOR_4B_READ_OP)
++			spi_nor_set_4byte_read(nor, info);
++		else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
++			 info->flags & SPI_NOR_4B_OPCODES)
++			spi_nor_set_4byte_opcodes(nor, info);
++		else
+ 			set_4byte(nor, info, 1);
+ 	} else {
+ 		nor->addr_width = 3;
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -42,9 +42,13 @@
+ #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
+ #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
+ #define SPINOR_OP_READ_FAST	0x0b	/* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ_1_1_2	0x3b	/* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ_1_2_2	0xbb	/* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ_1_1_4	0x6b	/* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ_1_4_4	0xeb	/* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP		0x02	/* Page program (up to 256 bytes) */
++#define SPINOR_OP_PP_1_1_4	0x32	/* Quad page program */
++#define SPINOR_OP_PP_1_4_4	0x38	/* Quad page program */
+ #define SPINOR_OP_BE_4K		0x20	/* Erase 4KiB block */
+ #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
+ #define SPINOR_OP_BE_32K	0x52	/* Erase 32KiB block */
+@@ -55,11 +59,17 @@
+ #define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
+ 
+ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+-#define SPINOR_OP_READ4		0x13	/* Read data bytes (low frequency) */
+-#define SPINOR_OP_READ4_FAST	0x0c	/* Read data bytes (high frequency) */
+-#define SPINOR_OP_READ4_1_1_2	0x3c	/* Read data bytes (Dual SPI) */
+-#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
++#define SPINOR_OP_READ_FAST_4B	0x0c	/* Read data bytes (high frequency) */
++#define SPINOR_OP_READ_1_1_2_4B	0x3c	/* Read data bytes (Dual Output SPI) */
++#define SPINOR_OP_READ_1_2_2_4B	0xbc	/* Read data bytes (Dual I/O SPI) */
++#define SPINOR_OP_READ_1_1_4_4B	0x6c	/* Read data bytes (Quad Output SPI) */
++#define SPINOR_OP_READ_1_4_4_4B	0xec	/* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
++#define SPINOR_OP_PP_1_1_4_4B	0x34	/* Quad page program */
++#define SPINOR_OP_PP_1_4_4_4B	0x3e	/* Quad page program */
++#define SPINOR_OP_BE_4K_4B	0x21	/* Erase 4KiB block */
++#define SPINOR_OP_BE_32K_4B	0x5c	/* Erase 32KiB block */
+ #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
+ 
+ /* Used for SST flashes only. */
+@@ -70,6 +80,7 @@
+ /* Used for Macronix and Winbond flashes. */
+ #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
+ #define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */
++#define SPINOR_OP_WREAR		0xc5	/* Write extended address register */
+ 
+ /* Used for Spansion flashes only. */
+ #define SPINOR_OP_BRWR		0x17	/* Bank register write */
+@@ -117,6 +128,7 @@ enum spi_nor_ops {
+ enum spi_nor_option_flags {
+ 	SNOR_F_USE_FSR		= BIT(0),
+ 	SNOR_F_SST		= BIT(1),
++	SNOR_F_4B_EXT_ADDR	= BIT(5),
+ };
+ 
+ /**
+@@ -166,6 +178,7 @@ struct spi_nor {
+ 	enum read_mode		flash_read;
+ 	bool			sst_write_second;
+ 	u32			flags;
++	u8			ext_addr;
+ 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+ 
+ 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
diff --git a/target/linux/ramips/patches-4.4/401-mtd-add-chunked-read-io-to-m25p80.patch b/target/linux/ramips/patches-4.4/401-mtd-add-chunked-read-io-to-m25p80.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b6111abad7063951c07688c66854fa743daeb6c6
--- /dev/null
+++ b/target/linux/ramips/patches-4.4/401-mtd-add-chunked-read-io-to-m25p80.patch
@@ -0,0 +1,21 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1176,6 +1176,7 @@ static int spi_nor_chunked_write(struct
+ 				 size_t *_retlen, const u_char *_buf)
+ {
+ 	struct spi_nor *nor = mtd_to_spi_nor(mtd);
++	u32 addr_width = nor->addr_width + !!(nor->flags & SNOR_F_4B_EXT_ADDR);
+ 	int chunk_size;
+ 	int retlen = 0;
+ 	int ret;
+@@ -1184,8 +1185,8 @@ static int spi_nor_chunked_write(struct
+ 	if (!chunk_size)
+ 		chunk_size = _len;
+ 
+-	if (nor->addr_width > 3)
+-		chunk_size -= nor->addr_width - 3;
++	if (addr_width > 3)
++		chunk_size -= addr_width - 3;
+ 
+ 	while (retlen < _len) {
+ 		size_t len = min_t(int, chunk_size, _len - retlen);