diff mbox

[linux-next,2/5] mtd: spi-nor: fix Quad SPI mode support for Spansion, Micron and Macronix

Message ID 7f2a084da433f1936a1305dfa30327bc5abc802c.1449494420.git.cyrille.pitchen@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Cyrille Pitchen Dec. 7, 2015, 2:09 p.m. UTC
This patch reworks the support of Quad and Dual SPI protocols for Micron,
Spansion and Macronix Quad/Dual capable memories. Indeed, in the best
case, only Spansion memories are correctly supported by the current
spi-nor framework.

1 - Micron:
When their Quad SPI mode is enabled, Micron spi-nor memories expect all
commands to use the SPI 4-4-4 protocol. Also when the Dual SPI mode is
enabled, all commands must use the SPI 2-2-2 protocol.

Before this patch, the spi-nor framework used to always enable the Quad
mode when the mode argument of spi_nor_scan() took the value SPI_NOR_QUAD.
That was not suited with drivers only supporting SPI 1-x-4 protocols but
not the 4-4-4 (e.g. the m25p80 driver). Also the SPI controller was not
notified about which SPI protocol to use to transfert command. We cannot
rely only on the op code: in Extended SPI mode the 0x6b command must use
the SPI 1-1-4 protocol whereas in Quad SPi mode the SPI 4-4-4 protocol
must be use instead.

After this patch, the spi-nor framework uses the result of the
spi_nor_read_id() function to choose the right SPI protocol to be used.
If the reg_proto was set to SPI_PROTO_4_4_4, we already know that the Quad
SPI mode is already enabled and that the SPI controller supports the SPI
4-4-4 protocol (otherwise it would have fail to read the JEDEC ID with the
0xaf op code). For the very same reason, if the reg_proto was set to
SPI_PROTO_2_2_2, we already know that the Dual mode is already enabled and
that the SPI controller supports the SPI 2-2-2 protocol.
Otherwise we switch back to the Extended SPI protocol, which supports at
least the Fast Read commands:
- 1-1-1 (0x0b)
- Dual Output 1-1-2 (0x3b)
- Quad Output 1-1-4 (0x6b)

We also safely set the number of dummy cycles to 8 for Fast Read commands
through the Volatile Configuration Register (VCR): some drivers (m25p80)
or SPI controllers only support a number of dummy cycles multiple of 8.
This number may have previouly been set to an unsupported value by an
early bootloader or at reset thanks to the Non-Volatile Configuration
Register.

Finally the XIP bit is always set in the VCR to disable the Continuous
Read mode as we don't want to care about mode cycles.

2 - Macronix:
When the QPI mode is enabled, all commands must use the SPI 4-4-4 protocol
and only the 0xeb op code is supported for Fast Read commands.
Before this patch, the spi-nor framework used to force the QPI mode but
used the 0x6b op code for Fast Read commands when the SPI controller
claims to support Quad SPI mode.
This patch uses the result of spi_nor_read_id() to guess whether the QPI
mode is both enable and supported by the SPI controller (otherwise it
would have failed to read the JEDEC ID with the 0xaf op code).
When the QPI mode is disabled, Macronix memories still support the
following Fast Read commands:
- 1-1-1 (0x0b)
- Dual Output 1-1-2 (0x3b)
- Quad Output 1-1-4 (0x6b)
So if the QPI mode has not already been enabled, there is not need to
enable it. We also avoid the 0xbb (Dual I/O 1-2-2) and 0xeb (Quad I/O
1-4-4) op codes on purpose as we don't want to care about the value to set
in mode cycles not to enter the Continuous Read (Performance Enhance)
mode.

As for Micron memories, the spi-nor framework now safely sets the number
of dummy cycles to 8 thanks to 2 volatile bits inside the Configuration
Register.

3 - Spansion:
As for Macronix, we avoid the 0xbb (Dual I/O 1-2-2) and 0xeb (Quad I/O
1-4-4) op codes on purpose as we don't want to care about the value to set
in mode cycles not to enter in the Continuous Read mode.

Besides, we only care about the Quad Enable bit inside the Configuration
Register (CR) when using Quad operations. In such a case, we first check
its state before trying to set it. Now we also notify the user about the
update of this non-volatile bit.

We also check the Latency Code (LC) in CR to know the exact number of
dummy cycles to use when performing a Fast Read operation. Currently only
the 0x0b, 0x3b and 0x6b op codes are used to perform Fast Read operation
so the number of dummy cycles is always either 0 or 8. Hence no regression
should be introduced.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 783 +++++++++++++++++++++++++++++++++++++-----
 include/linux/mtd/spi-nor.h   |  15 +-
 2 files changed, 699 insertions(+), 99 deletions(-)

Comments

Brian Norris Dec. 18, 2015, 2:18 a.m. UTC | #1
On Mon, Dec 07, 2015 at 03:09:11PM +0100, Cyrille Pitchen wrote:
> This patch reworks the support of Quad and Dual SPI protocols for Micron,
> Spansion and Macronix Quad/Dual capable memories. Indeed, in the best
> case, only Spansion memories are correctly supported by the current
> spi-nor framework.

^^ Ah, so this is what I was struggling with at first. I agree that
Micron looks broken. Quite possibly Macronix too. Unfortunately, I
haven't had great test hardware for some of the quad modes. Especially
not anything that supports generic SPI, and not completely on mainline.

> 1 - Micron:
> When their Quad SPI mode is enabled, Micron spi-nor memories expect all
> commands to use the SPI 4-4-4 protocol. Also when the Dual SPI mode is
> enabled, all commands must use the SPI 2-2-2 protocol.
> 
> Before this patch, the spi-nor framework used to always enable the Quad
> mode when the mode argument of spi_nor_scan() took the value SPI_NOR_QUAD.
> That was not suited with drivers only supporting SPI 1-x-4 protocols but
> not the 4-4-4 (e.g. the m25p80 driver). Also the SPI controller was not
> notified about which SPI protocol to use to transfert command. We cannot
> rely only on the op code: in Extended SPI mode the 0x6b command must use
> the SPI 1-1-4 protocol whereas in Quad SPi mode the SPI 4-4-4 protocol
> must be use instead.
> 
> After this patch, the spi-nor framework uses the result of the
> spi_nor_read_id() function to choose the right SPI protocol to be used.
> If the reg_proto was set to SPI_PROTO_4_4_4, we already know that the Quad
> SPI mode is already enabled and that the SPI controller supports the SPI
> 4-4-4 protocol (otherwise it would have fail to read the JEDEC ID with the
> 0xaf op code). For the very same reason, if the reg_proto was set to
> SPI_PROTO_2_2_2, we already know that the Dual mode is already enabled and
> that the SPI controller supports the SPI 2-2-2 protocol.
> Otherwise we switch back to the Extended SPI protocol, which supports at
> least the Fast Read commands:
> - 1-1-1 (0x0b)
> - Dual Output 1-1-2 (0x3b)
> - Quad Output 1-1-4 (0x6b)
> 
> We also safely set the number of dummy cycles to 8 for Fast Read commands
> through the Volatile Configuration Register (VCR): some drivers (m25p80)
> or SPI controllers only support a number of dummy cycles multiple of 8.
> This number may have previouly been set to an unsupported value by an
> early bootloader or at reset thanks to the Non-Volatile Configuration
> Register.

It's not clear to me how you're being safe with the dummy cycles at all.
It seems like you're introducing new values that may be incompatible
with drivers. That can be OK, but you have to give drivers a chance to
opt-out... Maybe some kind of "host capability" flags?

> Finally the XIP bit is always set in the VCR to disable the Continuous
> Read mode as we don't want to care about mode cycles.
> 
> 2 - Macronix:
> When the QPI mode is enabled, all commands must use the SPI 4-4-4 protocol
> and only the 0xeb op code is supported for Fast Read commands.
> Before this patch, the spi-nor framework used to force the QPI mode but
> used the 0x6b op code for Fast Read commands when the SPI controller
> claims to support Quad SPI mode.
> This patch uses the result of spi_nor_read_id() to guess whether the QPI
> mode is both enable and supported by the SPI controller (otherwise it
> would have failed to read the JEDEC ID with the 0xaf op code).
> When the QPI mode is disabled, Macronix memories still support the
> following Fast Read commands:
> - 1-1-1 (0x0b)
> - Dual Output 1-1-2 (0x3b)
> - Quad Output 1-1-4 (0x6b)
> So if the QPI mode has not already been enabled, there is not need to
> enable it. We also avoid the 0xbb (Dual I/O 1-2-2) and 0xeb (Quad I/O
> 1-4-4) op codes on purpose as we don't want to care about the value to set
> in mode cycles not to enter the Continuous Read (Performance Enhance)
> mode.
> 
> As for Micron memories, the spi-nor framework now safely sets the number
> of dummy cycles to 8 thanks to 2 volatile bits inside the Configuration
> Register.
> 
> 3 - Spansion:
> As for Macronix, we avoid the 0xbb (Dual I/O 1-2-2) and 0xeb (Quad I/O
> 1-4-4) op codes on purpose as we don't want to care about the value to set
> in mode cycles not to enter in the Continuous Read mode.
> 
> Besides, we only care about the Quad Enable bit inside the Configuration
> Register (CR) when using Quad operations. In such a case, we first check
> its state before trying to set it. Now we also notify the user about the
> update of this non-volatile bit.
> 
> We also check the Latency Code (LC) in CR to know the exact number of
> dummy cycles to use when performing a Fast Read operation. Currently only
> the 0x0b, 0x3b and 0x6b op codes are used to perform Fast Read operation
> so the number of dummy cycles is always either 0 or 8. Hence no regression
> should be introduced.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 783 +++++++++++++++++++++++++++++++++++++-----
>  include/linux/mtd/spi-nor.h   |  15 +-
>  2 files changed, 699 insertions(+), 99 deletions(-)

That's quite a lot to do in one patch, both in number of lines of code,
and in number of tasks outlined in the commit description. Can this be
broken down at all to be more modular and incremental?

Snipped the rest of the patch for now.

Brian
Cyrille Pitchen Jan. 4, 2016, 4:12 p.m. UTC | #2
Hi Brian,

Le 18/12/2015 03:18, Brian Norris a écrit :
> On Mon, Dec 07, 2015 at 03:09:11PM +0100, Cyrille Pitchen wrote:
>> This patch reworks the support of Quad and Dual SPI protocols for Micron,
>> Spansion and Macronix Quad/Dual capable memories. Indeed, in the best
>> case, only Spansion memories are correctly supported by the current
>> spi-nor framework.
> 
> ^^ Ah, so this is what I was struggling with at first. I agree that
> Micron looks broken. Quite possibly Macronix too. Unfortunately, I
> haven't had great test hardware for some of the quad modes. Especially
> not anything that supports generic SPI, and not completely on mainline.
> 

To explain the origin of this series of patches I would say that at first
I was only supposed to write a driver for the Atmel QSPI controller. I was
using (ans still use) a sama5d2 xplained board with a Micron n25q128a13
memory. Hence, testing the driver, I found that the probe failed inside the
old micron_quad_enable() function.
Indeed nor->write_reg() was successfully called to clear the Quad Enable bit
in the Enhanced Volatile Configuration Register but immediately after
spi_nor_wait_till_ready() failed.
The reason was that the Micron memory was switched to its Quad Mode and then
expected all the following commands to use the SPI 4-4-4 protocol. However
the Atmel QSPI controller driver was not aware of this protocol change and
kept on using the SPI 1-1-1 protocol.

So in the very first version of this series of patches, I inserted a call of
spi_nor_set_protocol(), a new function simply calling an optional hook,
between the nor->write_reg() and spi_nor_wait_till_ready() calls. This way
the (Q)SPI controller driver was now notified about the protocol switch and
can eventually adapt to this change.

After some discussions on the mailing list, it appeared that using such a
hook to handle protocol changes would required to insert calls of the new
spi_nor_set_protocol() function before all the calls of nor->read_reg(),
nor->write_reg(), nor->read(), nor->write() and nor->erase().
Indeed some manufacturers like Spansion use different numbers of I/O lines
depending on the type of operation:
- Fast Read: 1-1-4
- register read/write: 1-1-1

So the addition inside struct spi_nor of the new reg_proto, read_proto,
write_proto and erase_proto fields was prefered to the first
spi_nor_set_protocol() proposal. This fields are set once for all by
spi_nor_scan(). SPI controller drivers have to worry about their values only
if they claim to support Dual or Quad protocols through the 'mode' argument
of spi_nor_scan().

Then about the Micron case, I did test it and it didn't work without patching.
To be cautious, I wondered whether it might have work with a
different configuration/SPI controller because I don't want to break
something working. I wondered about a mean for the SPI controller driver to
detect the protocol change. Maybe parsing the SPI message and checking the
command op code. However it looked a highly inefficient method and also it
simply can not work since the very same op code, for instance 0x6B, is used
by both the 1-1-4 and 4-4-4 protocols.
So my conclusion was it could not have worked before: I don't have to worry
about breaking the support of Quad protocols for Micron memories.

I don't think there is a real need to revert Bean's commit since this series
fixes the issue anyway. However if you feel it would be better to revert it to
start from a cleaner base, I'm fine with it. Just let me know your choice so
I can adapt my series before sending the next version.


About the Macronix case, I still don't have any memory sample to test.
However, reading some memory datasheet (again and again), my understanding
has changed a little bit: setting the Quad Enable (QE) non-volatile bit in
the Status Register doesn't mean enabling the Quad Peripheral Interface (QPI)
as I thought.
Two dedicated op codes are used when sending the required commands to
enable/disable the QPI. Once the QPI enabled, the memory expects ALL commands
to use the SPI 4-4-4 protocol. Enabling the QPI requires the QE bit to bit set
first in the Status Register.
However the QE bit is also required to use the SPI 1-1-4 protocol: QPI must be
disabled in that case.
Setting the QE bit only disables the Write Protect and Hold features: the two
associated pins then become the IO2 and IO3 lines, needed by Quad SPI
protocols.

Finally for the Winbond case, I don't have memory from this manufacturer
yet so once again I refer only to some datasheets: it looks like Winbond
memories use a pattern of behaviour very closed to Macronix' one.
Indeed, some Quad Enable non volatile bit must be set inside the Status
Register. Also two dedicated op codes are used to enable/disable the QPI mode.
The QPI mode requires the QE bit to be set and, once enabled, all commands
must use the SPI 4-4-4 protocol.
However the two op codes to enter/leave the QPI mode are not the same as
those of Macronix and both manufacturers use different offsets for their
QE bits.

What I've planned to do to support Macronix and Winbond memory is to sill
use the spi_nor_read_id() function to guess the current protocol. If the
caller of spi_nor_scan() asks for Quad SPI support through the 'mode'
argument, I will use the SPI 4-4-4 protocol if the QPI mode is already
enabled, the SPI 1-1-4 protocol otherwise: I won't change the state of the
QPI mode. Indeed, if spi_nor_read_id() has succeeded in reading the JEDEC
ID, the current state of QPI mode is supported whatever it is.


>> 1 - Micron:
>> When their Quad SPI mode is enabled, Micron spi-nor memories expect all
>> commands to use the SPI 4-4-4 protocol. Also when the Dual SPI mode is
>> enabled, all commands must use the SPI 2-2-2 protocol.
>>
>> Before this patch, the spi-nor framework used to always enable the Quad
>> mode when the mode argument of spi_nor_scan() took the value SPI_NOR_QUAD.
>> That was not suited with drivers only supporting SPI 1-x-4 protocols but
>> not the 4-4-4 (e.g. the m25p80 driver). Also the SPI controller was not
>> notified about which SPI protocol to use to transfert command. We cannot
>> rely only on the op code: in Extended SPI mode the 0x6b command must use
>> the SPI 1-1-4 protocol whereas in Quad SPi mode the SPI 4-4-4 protocol
>> must be use instead.
>>
>> After this patch, the spi-nor framework uses the result of the
>> spi_nor_read_id() function to choose the right SPI protocol to be used.
>> If the reg_proto was set to SPI_PROTO_4_4_4, we already know that the Quad
>> SPI mode is already enabled and that the SPI controller supports the SPI
>> 4-4-4 protocol (otherwise it would have fail to read the JEDEC ID with the
>> 0xaf op code). For the very same reason, if the reg_proto was set to
>> SPI_PROTO_2_2_2, we already know that the Dual mode is already enabled and
>> that the SPI controller supports the SPI 2-2-2 protocol.
>> Otherwise we switch back to the Extended SPI protocol, which supports at
>> least the Fast Read commands:
>> - 1-1-1 (0x0b)
>> - Dual Output 1-1-2 (0x3b)
>> - Quad Output 1-1-4 (0x6b)
>>
>> We also safely set the number of dummy cycles to 8 for Fast Read commands
>> through the Volatile Configuration Register (VCR): some drivers (m25p80)
>> or SPI controllers only support a number of dummy cycles multiple of 8.
>> This number may have previouly been set to an unsupported value by an
>> early bootloader or at reset thanks to the Non-Volatile Configuration
>> Register.
> 
> It's not clear to me how you're being safe with the dummy cycles at all.
> It seems like you're introducing new values that may be incompatible
> with drivers. That can be OK, but you have to give drivers a chance to
> opt-out... Maybe some kind of "host capability" flags?
> 

Currently not all drivers support numbers of dummy cycles which are not
multiple of 8 bits. Especially this is the case of the m25p80 driver.
Other drivers, those supporting more numbers of dummy cycles still support
multiple of 8 bits. So now the spi-nor framework always  sets to 8 the number
of dummy cycles to be used by updating some Micron *volatile* register.
All drivers can deal with a value of 8. This value is almost always the
value used before. It is large enough to fit the highest SPI bus clock
frequencies but still provides good performances.
Actually, I'm pretty sure it was the only used value before.
And since the driver updates a volatile register, the configuration will
still be the same after reset for bootloaders.
In fact it should not change what worked before, it only gives a chance to
recover from bootloaders which would have used "strange" values of dummy
cycle number.
For instance, the romcode of the sama5d2 sets this number of dummy cycles to
10 for all Micron memories to limit the risk of incompatibility with memory
timing requirements. This romcode cannot be updated and tries to
support as many QSPI memories as possible within a limited code size: we
cannot afford using tables indexed by JEDEC ID but only by manufacturer ID.
However a value of 10 is not such a kind of value as expected by Linux
drivers. A value of 8 gives a chance to use the m25p80 driver to manufacturers
who don't want/can't develop a driver dedicated to their QSPI controller.

As a second thought, another solution is to only read the current value of dummy
cycle number and simply set use this value to initialize nor->read_dummy.
The assumption is now that is the value was fine for the QSPI controller during
the bootloader phase it's still fine under Linux as long as a driver can handle
this QSPI controller.

Please let me know which strategy you prefer for my next series.


>> Finally the XIP bit is always set in the VCR to disable the Continuous
>> Read mode as we don't want to care about mode cycles.
>>
>> 2 - Macronix:
>> When the QPI mode is enabled, all commands must use the SPI 4-4-4 protocol
>> and only the 0xeb op code is supported for Fast Read commands.
>> Before this patch, the spi-nor framework used to force the QPI mode but
>> used the 0x6b op code for Fast Read commands when the SPI controller
>> claims to support Quad SPI mode.
>> This patch uses the result of spi_nor_read_id() to guess whether the QPI
>> mode is both enable and supported by the SPI controller (otherwise it
>> would have failed to read the JEDEC ID with the 0xaf op code).
>> When the QPI mode is disabled, Macronix memories still support the
>> following Fast Read commands:
>> - 1-1-1 (0x0b)
>> - Dual Output 1-1-2 (0x3b)
>> - Quad Output 1-1-4 (0x6b)
>> So if the QPI mode has not already been enabled, there is not need to
>> enable it. We also avoid the 0xbb (Dual I/O 1-2-2) and 0xeb (Quad I/O
>> 1-4-4) op codes on purpose as we don't want to care about the value to set
>> in mode cycles not to enter the Continuous Read (Performance Enhance)
>> mode.
>>
>> As for Micron memories, the spi-nor framework now safely sets the number
>> of dummy cycles to 8 thanks to 2 volatile bits inside the Configuration
>> Register.
>>
>> 3 - Spansion:
>> As for Macronix, we avoid the 0xbb (Dual I/O 1-2-2) and 0xeb (Quad I/O
>> 1-4-4) op codes on purpose as we don't want to care about the value to set
>> in mode cycles not to enter in the Continuous Read mode.
>>
>> Besides, we only care about the Quad Enable bit inside the Configuration
>> Register (CR) when using Quad operations. In such a case, we first check
>> its state before trying to set it. Now we also notify the user about the
>> update of this non-volatile bit.
>>
>> We also check the Latency Code (LC) in CR to know the exact number of
>> dummy cycles to use when performing a Fast Read operation. Currently only
>> the 0x0b, 0x3b and 0x6b op codes are used to perform Fast Read operation
>> so the number of dummy cycles is always either 0 or 8. Hence no regression
>> should be introduced.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
>> ---
>>  drivers/mtd/spi-nor/spi-nor.c | 783 +++++++++++++++++++++++++++++++++++++-----
>>  include/linux/mtd/spi-nor.h   |  15 +-
>>  2 files changed, 699 insertions(+), 99 deletions(-)
> 
> That's quite a lot to do in one patch, both in number of lines of code,
> and in number of tasks outlined in the commit description. Can this be
> broken down at all to be more modular and incremental?

I've already tried to split the series a bit more. I had troubles making
patches smaller without breaking functionnal dependencies but I'll try
to split it again before sending the next series.

> 
> Snipped the rest of the patch for now.
> 
> Brian
> 

Happy new year, all! :)

Best regards,

Cyrille
diff mbox

Patch

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index bf17736750c1..30b63ab96410 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -138,24 +138,6 @@  static int read_cr(struct spi_nor *nor)
 }
 
 /*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
-{
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
-		return 8;
-	case SPI_NOR_NORMAL:
-		return 0;
-	}
-	return 0;
-}
-
-/*
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
@@ -1065,39 +1047,238 @@  write_err:
 	return ret;
 }
 
-static int macronix_quad_enable(struct spi_nor *nor)
+/*
+ * Write status Register and configuration register with 2 bytes
+ * The first byte will be written to the status register, while the
+ * second byte will be written to the configuration register.
+ * Return negative if error occured.
+ */
+static int write_sr_cr(struct spi_nor *nor, u16 val)
 {
-	int ret, val;
+	nor->cmd_buf[0] = val & 0xff;
+	nor->cmd_buf[1] = (val >> 8);
 
-	val = read_sr(nor);
-	write_enable(nor);
+	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
+}
 
-	write_sr(nor, val | SR_QUAD_EN_MX);
+static int macronix_dummy2code(u8 read_opcode, u8 read_dummy, u8 *dc)
+{
+	switch (read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		*dc = 0;
+		break;
 
-	if (spi_nor_wait_till_ready(nor))
-		return 1;
+	case SPINOR_OP_READ_FAST:
+	case SPINOR_OP_READ_1_1_2:
+	case SPINOR_OP_READ_1_1_4:
+	case SPINOR_OP_READ4_FAST:
+	case SPINOR_OP_READ4_1_1_2:
+	case SPINOR_OP_READ4_1_1_4:
+		switch (read_dummy) {
+		case 6:
+			*dc = 1;
+			break;
+		case 8:
+			*dc = 0;
+			break;
+		case 10:
+			*dc = 3;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SPINOR_OP_READ_1_2_2:
+	case SPINOR_OP_READ4_1_2_2:
+		switch (read_dummy) {
+		case 4:
+			*dc = 0;
+			break;
+		case 6:
+			*dc = 1;
+			break;
+		case 8:
+			*dc = 2;
+			break;
+		case 10:
+			*dc = 3;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SPINOR_OP_READ_1_4_4:
+	case SPINOR_OP_READ4_1_4_4:
+		switch (read_dummy) {
+		case 4:
+			*dc = 1;
+			break;
+		case 6:
+			*dc = 0;
+			break;
+		case 8:
+			*dc = 2;
+			break;
+		case 10:
+			*dc = 3;
+		default:
+			return -EINVAL;
+		}
+		break;
 
-	ret = read_sr(nor);
-	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-		dev_err(nor->dev, "Macronix Quad bit not set\n");
+	default:
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-/*
- * Write status Register and configuration register with 2 bytes
- * The first byte will be written to the status register, while the
- * second byte will be written to the configuration register.
- * Return negative if error occured.
- */
-static int write_sr_cr(struct spi_nor *nor, u16 val)
+static int macronix_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
 {
-	nor->cmd_buf[0] = val & 0xff;
-	nor->cmd_buf[1] = (val >> 8);
+	int ret, sr, cr, mask, val;
+	u16 sr_cr;
+	u8 dc;
 
-	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
+	/* Convert the number of dummy cycles into Macronix DC volatile bits */
+	ret = macronix_dummy2code(nor->read_opcode, read_dummy, &dc);
+	if (ret)
+		return ret;
+
+	mask = GENMASK(7, 6);
+	val = (dc << 6) & mask;
+
+	cr = read_cr(nor);
+	if (cr < 0) {
+		dev_err(nor->dev, "error while reading the config register\n");
+		return cr;
+	}
+
+	if ((cr & mask) == val) {
+		nor->read_dummy = read_dummy;
+		return 0;
+	}
+
+	sr = read_sr(nor);
+	if (sr < 0) {
+		dev_err(nor->dev, "error while reading the status register\n");
+		return sr;
+	}
+
+	cr = (cr & ~mask) | val;
+	sr_cr = (sr & 0xff) | ((cr & 0xff) << 8);
+	write_enable(nor);
+	ret = write_sr_cr(nor, sr_cr);
+	if (ret) {
+		dev_err(nor->dev,
+			"error while writting the SR and CR registers\n");
+		return ret;
+	}
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	cr = read_cr(nor);
+	if (cr < 0 || (cr & mask) != val) {
+		dev_err(nor->dev, "Macronix Dummy Cycle bits not updated\n");
+		return -EINVAL;
+	}
+
+	/* Save the number of dummy cycles to use with Fast Read commands */
+	nor->read_dummy = read_dummy;
+	return 0;
+}
+
+static int macronix_set_quad_mode(struct spi_nor *nor)
+{
+	/* Check whether the QPI mode is enabled. */
+	if (nor->reg_proto == SPI_PROTO_4_4_4) {
+		/* 
+		 * In QPI mode, only the Fast Read Quad I/O (0xeb) command is
+		 * supported by the memory. Also the memory expects ALL commands
+		 * to use the SPI 4-4-4 protocol.
+		 * We already know that the SPI controller supports this
+		 * protocol as we succeeded in reading the JEDEC ID with the
+		 * 0xaf command and SPI-4-4-4 protocol.
+		 * However, using the 0xeb command we must take care about the
+		 * values sent during the dummy cycles as we don't want the
+		 * memory to enter its Continuous Read (Performance Enhance)
+		 * mode.
+		 */
+		nor->erase_proto = SPI_PROTO_4_4_4;
+		nor->write_proto = SPI_PROTO_4_4_4;
+		nor->read_proto = SPI_PROTO_4_4_4;
+		nor->read_opcode = SPINOR_OP_READ_1_4_4;
+		return macronix_set_dummy_cycles(nor, 8);
+	}
+
+	/*
+	 * Use the Fast Read Quad Output 1-1-4 (0x6b) command with 8 dummy
+	 * cycles (up to 133MHz for STR and 66MHz for DTR).
+	 */
+	nor->read_proto = SPI_PROTO_1_1_4;
+	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	return macronix_set_dummy_cycles(nor, 8);
+}
+
+static int macronix_set_dual_mode(struct spi_nor *nor)
+{
+	/*
+	 * Use the Fast Read Dual Output 1-1-2 (0x3b) command with 8 dummy
+	 * cycles (up to 133MHz for STR and 66MHz for DTR).
+	 */
+	nor->read_proto = SPI_PROTO_1_1_2;
+	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	return macronix_set_dummy_cycles(nor, 8);
+}
+
+static int macronix_set_single_mode(struct spi_nor *nor)
+{
+	u8 read_dummy;
+
+	/*
+	 * Configure 8 dummy cycles for Fast Read 1-1-1 (0x0b) command (up to
+	 * 133MHz for STR and 66MHz for DTR). The Read 1-1-1 (0x03) command
+	 * expects no dummy cycle.
+	 * read_opcode should not be overridden here!
+	 */
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		read_dummy = 0;
+		break;
+
+	default:
+		read_dummy = 8;
+		break;
+	}
+
+	nor->read_proto = SPI_PROTO_1_1_1;
+	return macronix_set_dummy_cycles(nor, read_dummy);
+}
+
+static inline int spansion_get_config(struct spi_nor *nor,
+				      bool *quad_enabled,
+				      u8 *latency_code)
+{
+	int cr;
+
+	cr = read_cr(nor);
+	if (cr < 0) {
+		dev_err(nor->dev,
+			"error while reading the configuration register\n");
+		return cr;
+	}
+
+	if (quad_enabled)
+		*quad_enabled = !!(cr & CR_QUAD_EN_SPAN);
+
+	if (latency_code)
+		*latency_code = (u8)((cr & GENMASK(7, 6)) >> 6);
+
+	return 0;
 }
 
 static int spansion_quad_enable(struct spi_nor *nor)
@@ -1124,24 +1305,170 @@  static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
-static int micron_quad_enable(struct spi_nor *nor)
+static int spansion_set_dummy_cycles(struct spi_nor *nor, u8 latency_code)
 {
+	/* SDR dummy cycles */
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		nor->read_dummy = 0;
+		break;
+
+	case SPINOR_OP_READ_FAST:
+	case SPINOR_OP_READ_1_1_2:
+	case SPINOR_OP_READ_1_1_4:
+	case SPINOR_OP_READ4_FAST:
+	case SPINOR_OP_READ4_1_1_2:
+	case SPINOR_OP_READ4_1_1_4:
+		nor->read_dummy = (latency_code == 3) ? 0 : 8;
+		break;
+
+	case SPINOR_OP_READ_1_2_2:
+	case SPINOR_OP_READ4_1_2_2:
+		switch (latency_code) {
+		default:
+		case 0:
+		case 3:
+			nor->read_dummy = 4;
+			break;
+		case 1:
+			nor->read_dummy = 5;
+			break;
+		case 2:
+			nor->read_dummy = 6;
+			break;
+		}
+		break;
+
+
+	case SPINOR_OP_READ_1_4_4:
+	case SPINOR_OP_READ4_1_4_4:
+		switch (latency_code) {
+		default:
+		case 0:
+		case 1:
+			nor->read_dummy = 4;
+			break;
+		case 2:
+			nor->read_dummy = 5;
+			break;
+		case 3:
+			nor->read_dummy = 1;
+			break;
+		}
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int spansion_set_quad_mode(struct spi_nor *nor)
+{
+	bool quad_enabled;
+	u8 latency_code;
 	int ret;
-	u8 val;
 
-	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+	/*
+	 * The QUAD bit of Configuration Register must be set (CR Bit1=1) for
+	 * using any Quad SPI command.
+	 */
+	ret = spansion_get_config(nor, &quad_enabled, &latency_code);
+	if (ret)
+		return ret;
+
+	/* The Quad mode should be enabled ... */
+	if (!quad_enabled) {
+		/* ... if not try to enable it. */
+		dev_warn(nor->dev, "Spansion Quad mode disabled, enable it\n");
+		ret = spansion_quad_enable(nor);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Don't use the Fast Read Quad I/O (0xeb / 0xec) commands as their
+	 * number of dummy cycles can not be set to a multiple of 8: some SPI
+	 * controllers, especially those relying on the m25p80 driver, expect
+	 * the number of dummy cycles to be a multiple of 8.
+	 * Also when using a Fast Read Quad I/O command, the memory checks the 
+	 * value of the first mode/dummy cycles to decice whether it enters or
+	 * leaves the Countinuous Read mode. We should never enter the
+	 * Countinuous Read mode as the spi-nor framework doesn't support it.
+	 * For all these reason, we'd rather use the Fast Read Quad Output
+	 * 1-1-4 (0x6b / 0x6c) commands instead.
+	 */
+	nor->read_proto = SPI_PROTO_1_1_4;
+	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	return spansion_set_dummy_cycles(nor, latency_code);
+}
+
+static int spansion_set_dual_mode(struct spi_nor *nor)
+{
+	u8 latency_code;
+	int ret;
+
+	/* We don't care about the quad mode status */
+	ret = spansion_get_config(nor, NULL, &latency_code);
+	if (ret)
+		return ret;
+
+	/*
+	 * Don't use the Fast Read Dual I/O (0xbb / 0xbc) commands as their
+	 * number of dummy cycles can not bet set to a multiple of 8: some SPI
+	 * controllers, especially those relying on the m25p80 driver, expect
+	 * the number of dummy cycles to be a multiple of 8.
+	 * For this reason, w'd rather use the Fast Read Dual Output 1-1-2
+	 * (0x3b / 0x3c) commands instead.
+	 */
+	nor->read_proto = SPI_PROTO_1_1_2;
+	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	return spansion_set_dummy_cycles(nor, latency_code);
+}
+
+static int spansion_set_single_mode(struct spi_nor *nor)
+{
+	u8 latency_code;
+	int ret;
+
+	/* We don't care about the quad mode status */
+	ret = spansion_get_config(nor, NULL, &latency_code);
+	if (ret)
+		return ret;
+
+	nor->read_proto = SPI_PROTO_1_1_1;
+	return spansion_set_dummy_cycles(nor, latency_code);
+}
+
+static int micron_set_dummy_cycles(struct spi_nor *nor, u8 read_dummy)
+{
+	u8 vcr, val, mask;
+	int ret;
+
+	/* Set bit3 (XIP) to disable the Continuous Read mode */
+	mask = GENMASK(7, 4) | BIT(3);
+	val = ((read_dummy << 4) | BIT(3)) & mask;
+
+	/* Read the Volatile Configuration Register (VCR). */
+	ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
 	if (ret < 0) {
-		dev_err(nor->dev, "error %d reading EVCR\n", ret);
+		dev_err(nor->dev, "error while reading VCR register\n");
 		return ret;
 	}
 
-	write_enable(nor);
+	/* Check whether we need to update the number of dummy cycles. */
+	if ((vcr & mask) == val) {
+		nor->read_dummy = read_dummy;
+		return 0;
+	}
 
-	/* set EVCR, enable quad I/O */
-	nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-	ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
+	/* Update the number of dummy into the VCR. */
+	write_enable(nor);
+	vcr = (vcr & ~mask) | val;
+	ret = nor->write_reg(nor, SPINOR_OP_WR_VCR, &vcr, 1);
 	if (ret < 0) {
-		dev_err(nor->dev, "error while writing EVCR register\n");
+		dev_err(nor->dev, "error while writing VCR register\n");
 		return ret;
 	}
 
@@ -1149,47 +1476,309 @@  static int micron_quad_enable(struct spi_nor *nor)
 	if (ret)
 		return ret;
 
-	/* read EVCR and check it */
-	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+	/* Read VCR and check it. */
+	ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
+	if (ret < 0 || (vcr & mask) != val) {
+		dev_err(nor->dev, "Micron VCR dummy cycles not updated\n");
+		return -EINVAL;
+	}
+
+	/* Save the number of dummy cycles to use with Fast Read commands */
+	nor->read_dummy = read_dummy;
+	return 0;
+}
+
+static int micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
+			       enum spi_protocol proto)
+{
+	u8 evcr;
+	int ret;
+
+	/* Read the Exhanced Volatile Configuration Register (EVCR). */
+	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
+	if (ret < 0) {
+		dev_err(nor->dev, "error while reading EVCR register\n");
+		return ret;
+	}
+
+	/* Check whether we need to update the protocol bits. */
+	if ((evcr & mask) == val)
+		return 0;
+
+	/* Set EVCR protocol bits. */
+	write_enable(nor);
+	evcr = (evcr & ~mask) | val;
+	ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, &evcr, 1);
 	if (ret < 0) {
-		dev_err(nor->dev, "error %d reading EVCR\n", ret);
+		dev_err(nor->dev, "error while writing EVCR register\n");
 		return ret;
 	}
-	if (val & EVCR_QUAD_EN_MICRON) {
-		dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
+
+	/* Switch reg protocol now before accessing any other registers. */
+	nor->reg_proto = proto;
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	/* Read EVCR and check it. */
+	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
+	if (ret < 0 || (evcr & mask) != val) {
+		dev_err(nor->dev, "Micron EVCR protocol bits not updated\n");
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
+static int micron_set_quad_protocol(struct spi_nor *nor)
+{
+	int ret;
+
+	/* Set Quad bit to 0 to select the Quad SPI mode. */
+	ret = micron_set_protocol(nor,
+				  EVCR_QUAD_EN_MICRON,
+				  0,
+				  SPI_PROTO_4_4_4);
+	if (ret) {
+		dev_err(nor->dev, "Failed to set Micron Quad SPI mode\n");
+		return ret;
+	}
+
+	nor->read_proto = SPI_PROTO_4_4_4;
+	nor->write_proto = SPI_PROTO_4_4_4;
+	nor->erase_proto = SPI_PROTO_4_4_4;
+	return 0;
+}
+
+static int micron_set_dual_protocol(struct spi_nor *nor)
+{
+	int ret;
+
+	/* Set Quad/Dual bits to 10 to select the Dual SPI mode. */
+	ret = micron_set_protocol(nor,
+				  EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
+				  EVCR_QUAD_EN_MICRON,
+				  SPI_PROTO_2_2_2);
+	if (ret) {
+		dev_err(nor->dev, "Failed to set Micron Dual SPI mode\n");
+		return ret;
+	}
+
+	nor->read_proto = SPI_PROTO_2_2_2;
+	nor->write_proto = SPI_PROTO_2_2_2;
+	nor->erase_proto = SPI_PROTO_2_2_2;
+	return 0;
+}
+
+static int micron_set_extended_spi_protocol(struct spi_nor *nor)
+{
+	int ret;
+
+	/* Set Quad/Dual bits to 11 to select the Extended SPI mode */
+	ret = micron_set_protocol(nor,
+				  EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
+				  EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
+				  SPI_PROTO_1_1_1);
+	if (ret) {
+		dev_err(nor->dev, "Failed to set Micron Extended SPI mode\n");
+		return ret;
+	}
+
+	nor->write_proto = SPI_PROTO_1_1_1;
+	nor->erase_proto = SPI_PROTO_1_1_1;
+	return 0;
+}
+
+static int micron_set_quad_mode(struct spi_nor *nor)
+{
+	int ret;
+
+	/* Check whether the Quad SPI mode is enabled. */
+	if (nor->reg_proto == SPI_PROTO_4_4_4) {
+		/*
+		 * If here, the Quad mode should have already been enabled and
+		 * is supported by the SPI controller since the memory replied
+		 * to the Read ID Multiple I/O (0xaf) command in SPI 4-4-4
+		 * protocol. So it might be enough to only set the read, write
+		 * and erase protocols to SPI 4-4-4 but just in case...
+		 */
+		ret = micron_set_quad_protocol(nor);
+		if (ret)
+			return ret;
+
+		/*
+		 * In Quad mode, the memory doesn't make any difference between
+		 * the Fast Read Quad Output 1-1-4 (0x6b) and Fast Read Quad I/O
+		 * 1-4-4 (0xeb) commands: they are both processed in SPI 4-4-4
+		 * protocol. The 1-4-4 command is chosen here only for debug
+		 * purpose to easily detect the chosen mode when logging
+		 * commands.
+		 */
+		nor->read_opcode = SPINOR_OP_READ_1_4_4;
+		return micron_set_dummy_cycles(nor, 8);
+	}
+
+	/*
+	 * Exit Dual or Quad mode if not done yet: the Fast Read Quad Output
+	 * 1-1-4 (0x6b) command is also supported by the Extended SPI Protocol.
+	 * We can change the mode safely as we write into a volatile register.
+	 */
+	ret = micron_set_extended_spi_protocol(nor);
+	if (ret)
+		return ret;
+
+	/*
+	 * Use the Fast Read Quad Output 1-1-4 command.
+	 * Force the number of dummy cycles to 8 and disable the Continuous Read
+	 * mode to prevent some drivers from using it by mistake (m25p80).
+	 * We can change these settings safely as we write into a volatile
+	 * register.
+	 */
+	nor->read_proto = SPI_PROTO_1_1_4;
+	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	return micron_set_dummy_cycles(nor, 8);
+}
+
+static int micron_set_dual_mode(struct spi_nor *nor)
+{
+	int ret;
+
+	/* Check whether the Dual SPI mode is enabled. */
+	if (nor->reg_proto == SPI_PROTO_2_2_2) {
+		/*
+		 * If here, the Dual mode should have already been enabled and
+		 * is supported by the SPI controller since the memory replied
+		 * to the Read ID Multiple I/O (0xaf) command in SPI 2-2-2
+		 * protocol. So it might be enough to only set the read, write
+		 * and erase protocols to SPI 2-2-2 but just in case...
+		 */
+		ret = micron_set_dual_protocol(nor);
+		if (ret)
+			return ret;
+
+		/*
+		 * In Dual mode, the memory doesn't make any difference between
+		 * the Fast Read Dual Output 1-1-2 (0x3b) and Fast Read Dual I/O
+		 * 1-2-2 (0xbb) commands: they are both processed in SPI 2-2-2
+		 * protocol. The 1-2-2 command is chosen here only for debug
+		 * purpose to easily detect the chosen mode when logging
+		 * commands.
+		 */
+		nor->read_opcode = SPINOR_OP_READ_1_2_2;
+		return micron_set_dummy_cycles(nor, 8);
+	}
+
+	/*
+	 * Exit Dual or Quad mode if not done yet: the Fast Read Dual Output
+	 * 1-1-2 (0x3b) command is also supported by the Extended SPI Protocol.
+	 * We can change the mode safely as we write into a volatile register.
+	 */
+	ret = micron_set_extended_spi_protocol(nor);
+	if (ret)
+		return ret;
+
+	/*
+	 * Use the Fast Read Dual Output 1-1-2 command.
+	 * Force the number of dummy cycles to 8 and disable the Continuous Read
+	 * mode to prevent some drivers from using it by mistake (m25p80).
+	 * We can change these settings safely as we write into a volatile
+	 * register.
+	 */
+	nor->read_proto = SPI_PROTO_1_1_2;
+	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	return micron_set_dummy_cycles(nor, 8);
+}
+
+static int micron_set_single_mode(struct spi_nor *nor)
+{
+	u8 read_dummy;
+	int ret;
+
+	/*
+	 * Exit Dual or Quad mode if not done yet.
+	 * We can change the mode safely as we write into a volatile register.
+	 */
+	ret = micron_set_extended_spi_protocol(nor);
+	if (ret)
+		return ret;
+
+	/*
+	 * Force the number of dummy cycles to 8 for Fast Read, 0 for Read,
+	 * and disable the Continuous Read mode to prevent some drivers
+	 * from using it by mistake (m25p80).
+	 * We can change these settings safely as we write into a volatile
+	 * register.
+	 */
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		read_dummy = 0;
+		break;
+
+	default:
+		read_dummy = 8;
+		break;
+	}
+	nor->read_proto = SPI_PROTO_1_1_1;
+	return micron_set_dummy_cycles(nor, read_dummy);
+}
+
 static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 {
-	int status;
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_MACRONIX:
+		return macronix_set_quad_mode(nor);
 
+	case SNOR_MFR_MICRON:
+		return micron_set_quad_mode(nor);
+
+	case SNOR_MFR_SPANSION:
+		return spansion_set_quad_mode(nor);
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+{
 	switch (JEDEC_MFR(info)) {
 	case SNOR_MFR_MACRONIX:
-		status = macronix_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Macronix quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
+		return macronix_set_dual_mode(nor);
+
 	case SNOR_MFR_MICRON:
-		status = micron_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Micron quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
+		return micron_set_dual_mode(nor);
+
+	case SNOR_MFR_SPANSION:
+		return spansion_set_dual_mode(nor);
+
 	default:
-		status = spansion_quad_enable(nor);
-		if (status) {
-			dev_err(nor->dev, "Spansion quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+{
+	switch (JEDEC_MFR(info)) {
+	case SNOR_MFR_MACRONIX:
+		return macronix_set_single_mode(nor);
+
+	case SNOR_MFR_MICRON:
+		return micron_set_single_mode(nor);
+
+	case SNOR_MFR_SPANSION:
+		return spansion_set_single_mode(nor);
+
+	default:
+		break;
 	}
+
+	return -EINVAL;
 }
 
 static int spi_nor_check(struct spi_nor *nor)
@@ -1339,7 +1928,22 @@  int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	if (info->flags & SPI_NOR_NO_FR)
 		nor->flash_read = SPI_NOR_NORMAL;
 
-	/* Quad/Dual-read mode takes precedence over fast/normal */
+	/* Default commands and number of dummy cycles */
+	nor->program_opcode = SPINOR_OP_PP;
+	if (nor->flash_read == SPI_NOR_NORMAL) {
+		nor->read_opcode = SPINOR_OP_READ;
+		nor->read_dummy = 0;
+	} else {
+		nor->read_opcode = SPINOR_OP_READ_FAST;
+		nor->read_dummy = 8;
+	}
+
+	/*
+	 * Quad/Dual-read mode takes precedence over fast/normal. The opcodes,
+	 * the protocols and the number of dummy cycles are updated depending
+	 * on the manufacturer. The read opcode and protocol should be updated
+	 * by the relevant function when entering Quad or Dual mode.
+	 */
 	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
 		ret = set_quad_mode(nor, info);
 		if (ret) {
@@ -1348,30 +1952,21 @@  int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		}
 		nor->flash_read = SPI_NOR_QUAD;
 	} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
+		ret = set_dual_mode(nor, info);
+		if (ret) {
+			dev_err(dev, "dual mode not supported\n");
+			return ret;
+		}
 		nor->flash_read = SPI_NOR_DUAL;
+	} else if (info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) {
+		/* We may need to leave a Quad or Dual mode */
+		ret = set_single_mode(nor, info);
+		if (ret) {
+			dev_err(dev, "failed to switch back to single mode\n");
+			return ret;
+		}
 	}
 
-	/* Default commands */
-	switch (nor->flash_read) {
-	case SPI_NOR_QUAD:
-		nor->read_opcode = SPINOR_OP_READ_1_1_4;
-		break;
-	case SPI_NOR_DUAL:
-		nor->read_opcode = SPINOR_OP_READ_1_1_2;
-		break;
-	case SPI_NOR_FAST:
-		nor->read_opcode = SPINOR_OP_READ_FAST;
-		break;
-	case SPI_NOR_NORMAL:
-		nor->read_opcode = SPINOR_OP_READ;
-		break;
-	default:
-		dev_err(dev, "No Read opcode defined\n");
-		return -EINVAL;
-	}
-
-	nor->program_opcode = SPINOR_OP_PP;
-
 	if (info->addr_width)
 		nor->addr_width = info->addr_width;
 	else if (mtd->size > 0x1000000) {
@@ -1409,8 +2004,6 @@  int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		return -EINVAL;
 	}
 
-	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
-
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c91986a99caf..9f54b01675fd 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -42,8 +42,10 @@ 
 #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_BE_4K		0x20	/* Erase 4KiB block */
 #define SPINOR_OP_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
@@ -57,8 +59,10 @@ 
 /* 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_READ4_1_1_2	0x3c	/* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ4_1_2_2	0xbc	/* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ4_1_1_4	0x6c	/* Read data bytes (Quad Output SPI) */
+#define SPINOR_OP_READ4_1_4_4	0xec	/* Read data bytes (Quad I/O SPI) */
 #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
 #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
 
@@ -76,6 +80,8 @@ 
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_MIO_RDID	0xaf	/* Multiple I/O Read JEDEC ID */
+#define SPINOR_OP_RD_VCR	0x85	/* Read VCR register */
+#define SPINOR_OP_WR_VCR	0x81	/* Write VCR register */
 #define SPINOR_OP_RD_EVCR	0x65    /* Read EVCR register */
 #define SPINOR_OP_WD_EVCR	0x61    /* Write EVCR register */
 
@@ -92,6 +98,7 @@ 
 
 /* Enhanced Volatile Configuration Register bits */
 #define EVCR_QUAD_EN_MICRON	BIT(7)	/* Micron Quad I/O */
+#define EVCR_DUAL_EN_MICRON	BIT(6)	/* Micron Dual I/O */
 
 /* Flag Status Register bits */
 #define FSR_READY		BIT(7)