diff mbox

[v2,03/10] mtd: spi-nor: add DDR quad read support

Message ID 1398657227-20721-4-git-send-email-b32955@freescale.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Huang Shijie April 28, 2014, 3:53 a.m. UTC
This patch adds the DDR quad read support by the following:

  [1] add SPI_NOR_DDR_QUAD read mode.

  [2] add DDR Quad read opcodes:
       SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D

  [3] add set_ddr_quad_mode() to initialize for the DDR quad read.
      Currently it only works for Spansion NOR.

  [3] about the dummy cycles.
      We set the dummy with 8 for DDR quad read by default.
      The m25p80.c can not support the DDR quad read, but the SPI NOR controller
      can set the dummy value in its child DT node, and the SPI NOR framework
      can parse it out.

Test this patch for Spansion s25fl128s NOR flash.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/mtd/spi-nor/spi-nor.c |   54 +++++++++++++++++++++++++++++++++++++++-
 include/linux/mtd/spi-nor.h   |    8 ++++-
 2 files changed, 58 insertions(+), 4 deletions(-)

Comments

Marek Vasut April 28, 2014, 8:23 p.m. UTC | #1
On Monday, April 28, 2014 at 05:53:40 AM, Huang Shijie wrote:
> This patch adds the DDR quad read support by the following:
> 
>   [1] add SPI_NOR_DDR_QUAD read mode.
> 
>   [2] add DDR Quad read opcodes:
>        SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D
> 
>   [3] add set_ddr_quad_mode() to initialize for the DDR quad read.
>       Currently it only works for Spansion NOR.
> 
>   [3] about the dummy cycles.
>       We set the dummy with 8 for DDR quad read by default.
>       The m25p80.c can not support the DDR quad read, but the SPI NOR
> controller can set the dummy value in its child DT node, and the SPI NOR
> framework can parse it out.
> 
> Test this patch for Spansion s25fl128s NOR flash.
> 
> Signed-off-by: Huang Shijie <b32955@freescale.com>

Acked-by: Marek Vasut <marex@denx.de>

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Brian Norris July 30, 2014, 5:08 a.m. UTC | #2
Hi Huang,

Sorry to address this series so late.

I have a few questions about how you determine support for these DDR
modes.

On Mon, Apr 28, 2014 at 11:53:40AM +0800, Huang Shijie wrote:
> This patch adds the DDR quad read support by the following:

To Mark / linux-spi:

Are DDR modes in the scope of drivers/spi/ at all, so that we could
someday wire it up through m25p80.c? Or is 'DDR' such a distortion of
the meaning of 'SPI' such that it will be restricted only to SPI NOR
dedicated controllers?

>   [1] add SPI_NOR_DDR_QUAD read mode.
> 
>   [2] add DDR Quad read opcodes:
>        SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D
> 
>   [3] add set_ddr_quad_mode() to initialize for the DDR quad read.
>       Currently it only works for Spansion NOR.
> 
>   [3] about the dummy cycles.
>       We set the dummy with 8 for DDR quad read by default.

Why? That seems wrong. You need to know for sure how many cycles should
be used, not just guess a default.

>       The m25p80.c can not support the DDR quad read, but the SPI NOR controller
>       can set the dummy value in its child DT node, and the SPI NOR framework
>       can parse it out.

Why does the dummy value belong in device tree? I think this can be
handled in software. You might, however, want a few other hardware
description parameters in device tree to help you.

So I think spi-nor.c needs to know a few things:

 1. Does the hardware/driver support DDR clocking?
 2. What granularity of dummy cycles are supported? So m25p80.c needs to
    communicate that it only supports dummy cycles of multiples of 8,
    and fsl-quadspi supports single clock cycles.

And spi-nor.c should be able to do the following:

 3. Set how many dummy cycles should be used.
 4. Write to the configuration register, to choose a Latency Code
    according to what the flash supports. I see modes that support 3, 6,
    7, or 8. We'd probably just go for the fastest mode, which requires
    8, right?

So far, none of this seems to require a DT binding, unless there's
something I'm missing about your fsl-quadspi controller.

> Test this patch for Spansion s25fl128s NOR flash.
> 
> Signed-off-by: Huang Shijie <b32955@freescale.com>
> ---
>  drivers/mtd/spi-nor/spi-nor.c |   54 +++++++++++++++++++++++++++++++++++++++-
>  include/linux/mtd/spi-nor.h   |    8 ++++-
>  2 files changed, 58 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index f374e44..e0bc11a 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -73,7 +73,20 @@ static int read_cr(struct spi_nor *nor)
>   */
>  static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
>  {
> +	u32 dummy;
> +
>  	switch (nor->flash_read) {
> +	case SPI_NOR_DDR_QUAD:
> +		/*
> +		 * The m25p80.c can not support the DDR quad read.
> +		 * We set the dummy cycles to 8 by default. The SPI NOR
> +		 * controller driver can set it in its child DT node.
> +		 * We parse it out here.
> +		 */
> +		if (nor->np && !of_property_read_u32(nor->np,
> +				"spi-nor,ddr-quad-read-dummy", &dummy)) {
> +			return dummy;
> +		}
>  	case SPI_NOR_FAST:
>  	case SPI_NOR_DUAL:
>  	case SPI_NOR_QUAD:
> @@ -402,6 +415,7 @@ struct flash_info {
>  #define	SECT_4K_PMC		0x10	/* SPINOR_OP_BE_4K_PMC works uniformly */
>  #define	SPI_NOR_DUAL_READ	0x20    /* Flash supports Dual Read */
>  #define	SPI_NOR_QUAD_READ	0x40    /* Flash supports Quad Read */
> +#define	SPI_NOR_DDR_QUAD_READ	0x80    /* Flash supports DDR Quad Read */
>  };
>  
>  #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
> @@ -846,6 +860,24 @@ static int spansion_quad_enable(struct spi_nor *nor)
>  	return 0;
>  }
>  
> +static int set_ddr_quad_mode(struct spi_nor *nor, u32 jedec_id)
> +{
> +	int status;
> +
> +	switch (JEDEC_MFR(jedec_id)) {
> +	case CFI_MFR_AMD: /* Spansion, actually */
> +		status = spansion_quad_enable(nor);
> +		if (status) {
> +			dev_err(nor->dev,
> +				"Spansion DDR quad-read not enabled\n");
> +			return status;
> +		}
> +		return status;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
>  {
>  	int status;
> @@ -1016,8 +1048,15 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
>  	if (info->flags & SPI_NOR_NO_FR)
>  		nor->flash_read = SPI_NOR_NORMAL;
>  
> -	/* Quad/Dual-read mode takes precedence over fast/normal */
> -	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
> +	/* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
> +	if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {

Hmm, I think I should probably take another look at the design of
spi-nor.c... Why does spi_nor_scan() take a single 'mode' argument? The
driver should be communicating which (multiple) modes it supports, not
selecting a single mode. spi-nor.c is the only one which knows what the
*flash* supports, so it should be combining knowledge from the
controller driver with its own knowledge of the flash.

> +		ret = set_ddr_quad_mode(nor, info->jedec_id);
> +		if (ret) {
> +			dev_err(dev, "DDR quad mode not supported\n");
> +			return ret;

A ramification of my comment above is that we should not be returning an
error in a situation like this; we should be able to fall back to
another known-supported mode, like SDR QUAD, SDR DUAL, or just plain
SPI -- if they're supported by the driver -- and spi-nor.c doesn't
currently have enough information to do this.

> +		}
> +		nor->flash_read = SPI_NOR_DDR_QUAD;
> +	} else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
>  		ret = set_quad_mode(nor, info->jedec_id);
>  		if (ret) {
>  			dev_err(dev, "quad mode not supported\n");
> @@ -1030,6 +1069,14 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
>  
>  	/* Default commands */
>  	switch (nor->flash_read) {
> +	case SPI_NOR_DDR_QUAD:
> +		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Spansion */
> +			nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
> +		} else {
> +			dev_err(dev, "DDR Quad Read is not supported.\n");
> +			return -EINVAL;
> +		}
> +		break;
>  	case SPI_NOR_QUAD:
>  		nor->read_opcode = SPINOR_OP_READ_1_1_4;
>  		break;
> @@ -1057,6 +1104,9 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
>  		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
>  			/* Dedicated 4-byte command set */
>  			switch (nor->flash_read) {
> +			case SPI_NOR_DDR_QUAD:
> +				nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
> +				break;
>  			case SPI_NOR_QUAD:
>  				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
>  				break;
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index 48fe9fc..d191a6b 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -12,10 +12,11 @@
>  
>  /*
>   * Note on opcode nomenclature: some opcodes have a format like
> - * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
> + * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y, and z stand for the number
>   * of I/O lines used for the opcode, address, and data (respectively). The
>   * FUNCTION has an optional suffix of '4', to represent an opcode which
> - * requires a 4-byte (32-bit) address.
> + * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the
> + * DDR mode.
>   */
>  
>  /* Flash opcodes. */
> @@ -26,6 +27,7 @@
>  #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_4_4_D	0xed	/* Read data bytes (DDR Quad 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 */
> @@ -40,6 +42,7 @@
>  #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_4_4_D	0xee	/* Read data bytes (DDR Quad SPI) */
>  #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
>  #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
>  
> @@ -74,6 +77,7 @@ enum read_mode {
>  	SPI_NOR_FAST,
>  	SPI_NOR_DUAL,
>  	SPI_NOR_QUAD,
> +	SPI_NOR_DDR_QUAD,
>  };
>  
>  /**

So, I'll have to take another hard look at spi-nor.c soon. I think we
may need to work on the abstractions here a bit more before I merge any
new features like this.

Regards,
Brian

P.S. Is there a good reason we've defined a whole read_xfer/write_xfer
API that is completely unused?
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Huang Shijie July 30, 2014, 6:44 a.m. UTC | #3
On Tue, Jul 29, 2014 at 10:08:43PM -0700, Brian Norris wrote:
> 
> On Mon, Apr 28, 2014 at 11:53:40AM +0800, Huang Shijie wrote:
> > This patch adds the DDR quad read support by the following:
> 
> To Mark / linux-spi:
> 
> Are DDR modes in the scope of drivers/spi/ at all, so that we could
> someday wire it up through m25p80.c? Or is 'DDR' such a distortion of
> the meaning of 'SPI' such that it will be restricted only to SPI NOR
> dedicated controllers?

IMHO, the DDR modes can _NOT_ be handled by the driver/spi/*.
The SPI can only handles the byte streams. But the DDR mode may need to
handle the cycles(such as the dummy cycles could be 7 cycles) which is not byte.

So the DDR mode is handled by the SPI NOR controller now.

Please correct me if I am wrong. :)

> 
> >   [1] add SPI_NOR_DDR_QUAD read mode.
> > 
> >   [2] add DDR Quad read opcodes:
> >        SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D
> > 
> >   [3] add set_ddr_quad_mode() to initialize for the DDR quad read.
> >       Currently it only works for Spansion NOR.
> > 
> >   [3] about the dummy cycles.
> >       We set the dummy with 8 for DDR quad read by default.
> 
> Why? That seems wrong. You need to know for sure how many cycles should
> be used, not just guess a default.

Do you mean that if people do not set the DT node for dummy, we should
return an -EINVAL immediately?


> 
> >       The m25p80.c can not support the DDR quad read, but the SPI NOR controller
> >       can set the dummy value in its child DT node, and the SPI NOR framework
> >       can parse it out.
> 
> Why does the dummy value belong in device tree? I think this can be
> handled in software. You might, however, want a few other hardware
> description parameters in device tree to help you.
> 
> So I think spi-nor.c needs to know a few things:
> 
>  1. Does the hardware/driver support DDR clocking?
>  2. What granularity of dummy cycles are supported? So m25p80.c needs to
>     communicate that it only supports dummy cycles of multiples of 8,
>     and fsl-quadspi supports single clock cycles.

I think you can send patches for these features. I does not clear about:
  for what does the spi-nor needs to know the above things.

> And spi-nor.c should be able to do the following:
> 
>  3. Set how many dummy cycles should be used.
where can we get the number of the cycles? 


>  4. Write to the configuration register, to choose a Latency Code
>     according to what the flash supports. I see modes that support 3, 6,
>     7, or 8. We'd probably just go for the fastest mode, which requires
>     8, right?
not right.

The DDR mode can not work if we set a wrong dummy cycles for the flash.

for some chips, the fastest mode may need 6 cycles, not 8. 

> 
> So far, none of this seems to require a DT binding, unless there's
> something I'm missing about your fsl-quadspi controller.
> 
> > Test this patch for Spansion s25fl128s NOR flash.
> > 
> > Signed-off-by: Huang Shijie <b32955@freescale.com>
> > ---
> > +	/* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
> > +	if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
> 
> Hmm, I think I should probably take another look at the design of
> spi-nor.c... Why does spi_nor_scan() take a single 'mode' argument? The
> driver should be communicating which (multiple) modes it supports, not
> selecting a single mode. spi-nor.c is the only one which knows what the
> *flash* supports, so it should be combining knowledge from the
> controller driver with its own knowledge of the flash.

It is okay for me to add multiples modes for the spi_nor_scan().
I added the single mode for spi_nor_scan is because that the fsl-quadspi
does not want to support the low speed modes. (Of course, the fsl-quadspi
controller does support the low speed modes.)

> 
> > +		ret = set_ddr_quad_mode(nor, info->jedec_id);
> > +		if (ret) {
> > +			dev_err(dev, "DDR quad mode not supported\n");
> > +			return ret;
> 
> A ramification of my comment above is that we should not be returning an
> error in a situation like this; we should be able to fall back to
> another known-supported mode, like SDR QUAD, SDR DUAL, or just plain
> SPI -- if they're supported by the driver -- and spi-nor.c doesn't
> currently have enough information to do this.
ok.
> 
> > +		}
> > +		nor->flash_read = SPI_NOR_DDR_QUAD;
> >  
> >  /**
> 
> So, I'll have to take another hard look at spi-nor.c soon. I think we
> may need to work on the abstractions here a bit more before I merge any
> new features like this.

okay.  no problem.

> 
> Regards,
> Brian
> 
> P.S. Is there a good reason we've defined a whole read_xfer/write_xfer
> API that is completely unused?
These hooks are designed for other SPI NOR drivers, the fsl-quadspi does
not use them.

thanks
Huang Shijie


--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Brian Norris July 30, 2014, 7:45 a.m. UTC | #4
+ Mark

On Wed, Jul 30, 2014 at 02:44:13PM +0800, Huang Shijie wrote:
> On Tue, Jul 29, 2014 at 10:08:43PM -0700, Brian Norris wrote:
> > On Mon, Apr 28, 2014 at 11:53:40AM +0800, Huang Shijie wrote:
> > > This patch adds the DDR quad read support by the following:
> > 
> > To Mark / linux-spi:
> > 
> > Are DDR modes in the scope of drivers/spi/ at all, so that we could
> > someday wire it up through m25p80.c? Or is 'DDR' such a distortion of
> > the meaning of 'SPI' such that it will be restricted only to SPI NOR
> > dedicated controllers?
> 
> IMHO, the DDR modes can _NOT_ be handled by the driver/spi/*.

I agree to some extent, but I wanted to confirm with the SPI guys that
DDR is truly unique to SPI NOR. (I know it doesn't currently support
it.)

> The SPI can only handles the byte streams.

Sure.

> But the DDR mode may need to
> handle the cycles(such as the dummy cycles could be 7 cycles) which is not byte.

But that's the same story for some (but not all) of the dual and quad
modes now; some have dummy cycles that are not multiples of 8 bits.

Because there are some DDR modes which have 8 dummy cycles, it is
theoretically possible for the SPI subsystem to handle them.

> So the DDR mode is handled by the SPI NOR controller now.

Right.

BTW, does your quadspi controller unconditionally support DDR, or is
there any dependency on board/clock configuration? I'm just curious
whether you need a DT binding to describe DDR support, or if (as long as
the flash supports it, and we get the dummy cycles right) you can always
use DDR QUAD.

> Please correct me if I am wrong. :)
> 
> > >   [1] add SPI_NOR_DDR_QUAD read mode.
> > > 
> > >   [2] add DDR Quad read opcodes:
> > >        SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D
> > > 
> > >   [3] add set_ddr_quad_mode() to initialize for the DDR quad read.
> > >       Currently it only works for Spansion NOR.
> > > 
> > >   [3] about the dummy cycles.
> > >       We set the dummy with 8 for DDR quad read by default.
> > 
> > Why? That seems wrong. You need to know for sure how many cycles should
> > be used, not just guess a default.
> 
> Do you mean that if people do not set the DT node for dummy, we should
> return an -EINVAL immediately?

Possibly. But I actually don't think this belongs in DT at all. See
below.

> > >       The m25p80.c can not support the DDR quad read, but the SPI NOR controller
> > >       can set the dummy value in its child DT node, and the SPI NOR framework
> > >       can parse it out.
> > 
> > Why does the dummy value belong in device tree? I think this can be
> > handled in software.

Can you answer me this question?

> > You might, however, want a few other hardware
> > description parameters in device tree to help you.
> > 
> > So I think spi-nor.c needs to know a few things:
> > 
> >  1. Does the hardware/driver support DDR clocking?
> >  2. What granularity of dummy cycles are supported? So m25p80.c needs to
> >     communicate that it only supports dummy cycles of multiples of 8,
> >     and fsl-quadspi supports single clock cycles.
> 
> I think you can send patches for these features. I does not clear about:
>   for what does the spi-nor needs to know the above things.

To properly abstract features between a driver and the spi-nor
"library." For example, we need to make sure we don't try to use a
command mode with 7 dummy cycles on m25p80.c; right now, each driver has
to (implicitly) know the details of dummy cycles when selecting a 'mode'
parameter for spi_nor_scan(). spi-nor.c should be selecting this for us,
not forcing the driver to make the selection.

> > And spi-nor.c should be able to do the following:
> > 
> >  3. Set how many dummy cycles should be used.
> where can we get the number of the cycles? 

This should be a property of the flash device, just like everything else
we detect in spi-nor.c.

> >  4. Write to the configuration register, to choose a Latency Code
> >     according to what the flash supports. I see modes that support 3, 6,
> >     7, or 8. We'd probably just go for the fastest mode, which requires
> >     8, right?
> not right.
> 
> The DDR mode can not work if we set a wrong dummy cycles for the flash.
> 
> for some chips, the fastest mode may need 6 cycles, not 8. 

OK, but can spi-nor.c detect this instead of putting this in DT? e.g.,
associate this with the device ID?

Or even better, we can support CFI detection for SPI NOR flash. I notice
the datasheet for your Spansion flash [1] has an extensive set of CFI
parameters defined, including the dummy cycle information. I think it
might be more sustainable to try to support CFI [2] and SFDP [3] for
detecting new flash, rather than adding new table entries ad-hoc.

> > So far, none of this seems to require a DT binding, unless there's
> > something I'm missing about your fsl-quadspi controller.
> > 
> > > Test this patch for Spansion s25fl128s NOR flash.
> > > 
> > > Signed-off-by: Huang Shijie <b32955@freescale.com>
> > > ---
> > > +	/* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
> > > +	if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
> > 
> > Hmm, I think I should probably take another look at the design of
> > spi-nor.c... Why does spi_nor_scan() take a single 'mode' argument? The
> > driver should be communicating which (multiple) modes it supports, not
> > selecting a single mode. spi-nor.c is the only one which knows what the
> > *flash* supports, so it should be combining knowledge from the
> > controller driver with its own knowledge of the flash.
> 
> It is okay for me to add multiples modes for the spi_nor_scan().
> I added the single mode for spi_nor_scan is because that the fsl-quadspi
> does not want to support the low speed modes. (Of course, the fsl-quadspi
> controller does support the low speed modes.)

Right, fsl-quadspi only supports one mode. But m25p80.c is more
flexible, and I think we might have broken some of it in the process
(e.g., if the SPI controller supports single/dual/quad but the flash
only supports single, then we might fail to probe).

I can take a look at this problem if you don't. I'd just recommend that
we might take a step back on a few of these issues before blazing ahead
with something irrevocable, like a DT binding.

> > > +		ret = set_ddr_quad_mode(nor, info->jedec_id);
> > > +		if (ret) {
> > > +			dev_err(dev, "DDR quad mode not supported\n");
> > > +			return ret;
> > 
> > A ramification of my comment above is that we should not be returning an
> > error in a situation like this; we should be able to fall back to
> > another known-supported mode, like SDR QUAD, SDR DUAL, or just plain
> > SPI -- if they're supported by the driver -- and spi-nor.c doesn't
> > currently have enough information to do this.
> ok.
> > 
> > > +		}
> > > +		nor->flash_read = SPI_NOR_DDR_QUAD;
> > >  
> > >  /**
> > 
> > So, I'll have to take another hard look at spi-nor.c soon. I think we
> > may need to work on the abstractions here a bit more before I merge any
> > new features like this.
> 
> okay.  no problem.
> 
> > 
> > Regards,
> > Brian
> > 
> > P.S. Is there a good reason we've defined a whole read_xfer/write_xfer
> > API that is completely unused?
> These hooks are designed for other SPI NOR drivers, the fsl-quadspi does
> not use them.

Brian

[1] http://www.spansion.com/Support/Datasheets/S25FL128S_256S_00.pdf

[2] http://www.jedec.org/sites/default/files/docs/jesd68-01.pdf

    plus some of the vendor extensions which are documented in their
    datasheets

[3] http://www.macronix.com/Lists/ApplicationNote/Attachments/667/AN114v1-SFDP%20Introduction.pdf

    http://www.jedec.org/sites/default/files/docs/JESD216.pdf
    (login wall)
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown July 30, 2014, 10:46 a.m. UTC | #5
On Wed, Jul 30, 2014 at 12:45:00AM -0700, Brian Norris wrote:
> On Wed, Jul 30, 2014 at 02:44:13PM +0800, Huang Shijie wrote:
> > On Tue, Jul 29, 2014 at 10:08:43PM -0700, Brian Norris wrote:
> > > On Mon, Apr 28, 2014 at 11:53:40AM +0800, Huang Shijie wrote:
> > > > This patch adds the DDR quad read support by the following:

> > > Are DDR modes in the scope of drivers/spi/ at all, so that we could
> > > someday wire it up through m25p80.c? Or is 'DDR' such a distortion of
> > > the meaning of 'SPI' such that it will be restricted only to SPI NOR
> > > dedicated controllers?

> > IMHO, the DDR modes can _NOT_ be handled by the driver/spi/*.

> I agree to some extent, but I wanted to confirm with the SPI guys that
> DDR is truly unique to SPI NOR. (I know it doesn't currently support
> it.)

I don't know what DDR is in this context, sorry.  I'm guessing you're
right since it sounds like something to do with extra clocks and this is
probably not something used by generic SPI devices at present (if it
ends up being widely implemented by sufficiently generic controllers
that might change but the trend seems to be to flash specific
controllers).
Huang Shijie July 30, 2014, 3:23 p.m. UTC | #6
On Wed, Jul 30, 2014 at 12:45:00AM -0700, Brian Norris wrote:
> 
> BTW, does your quadspi controller unconditionally support DDR, or is
> there any dependency on board/clock configuration? I'm just curious
> whether you need a DT binding to describe DDR support, or if (as long as
> the flash supports it, and we get the dummy cycles right) you can always
> use DDR QUAD.
The fsl-quadspi controller can support the DDR quad mode unconditionally.
In the other word, this controller is _designed_ for the DDR quad mode.

the driver does not needs a DT binding for the DDR. thanks.


> 
> > Please correct me if I am wrong. :)
> > 
> > > >   [1] add SPI_NOR_DDR_QUAD read mode.
> > > > 
> > > >   [2] add DDR Quad read opcodes:
> > > >        SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D
> > > > 
> > > >   [3] add set_ddr_quad_mode() to initialize for the DDR quad read.
> > > >       Currently it only works for Spansion NOR.
> > > > 
> > > >   [3] about the dummy cycles.
> > > >       We set the dummy with 8 for DDR quad read by default.
> > > 
> > > Why? That seems wrong. You need to know for sure how many cycles should
> > > be used, not just guess a default.
> > 
> > Do you mean that if people do not set the DT node for dummy, we should
> > return an -EINVAL immediately?
> 
> Possibly. But I actually don't think this belongs in DT at all. See
> below.
> 
> > > >       The m25p80.c can not support the DDR quad read, but the SPI NOR controller
> > > >       can set the dummy value in its child DT node, and the SPI NOR framework
> > > >       can parse it out.
> > > 
> > > Why does the dummy value belong in device tree? I think this can be
> > > handled in software.

We can not handle it in the software way.
Why? since there are too many modes,and each mode needs different dummy
cycles. Even the same chips, different versions may uses different dummy
cycles in the same mode. ..

You can refer to the Spansion's  S25fs128s.

If you want to put these dummy cycles in the device ID, it will make you
crazy in the end. :)
> 
> Can you answer me this question?
> 
> > > You might, however, want a few other hardware
> > > description parameters in device tree to help you.
> > > 
> > > So I think spi-nor.c needs to know a few things:
> > > 
> > >  1. Does the hardware/driver support DDR clocking?
> > >  2. What granularity of dummy cycles are supported? So m25p80.c needs to
> > >     communicate that it only supports dummy cycles of multiples of 8,
> > >     and fsl-quadspi supports single clock cycles.
> > 
> > I think you can send patches for these features. I does not clear about:
> >   for what does the spi-nor needs to know the above things.
> 
> To properly abstract features between a driver and the spi-nor
> "library." For example, we need to make sure we don't try to use a
> command mode with 7 dummy cycles on m25p80.c; right now, each driver has
> to (implicitly) know the details of dummy cycles when selecting a 'mode'
> parameter for spi_nor_scan(). spi-nor.c should be selecting this for us,
> not forcing the driver to make the selection.
> 
> > > And spi-nor.c should be able to do the following:
> > > 
> > >  3. Set how many dummy cycles should be used.
> > where can we get the number of the cycles? 
> 
> This should be a property of the flash device, just like everything else
> we detect in spi-nor.c.
This is indeed a probably of the flash device.
and this is why I add a new DT binding file for the flash.

> 
> > >  4. Write to the configuration register, to choose a Latency Code
> > >     according to what the flash supports. I see modes that support 3, 6,
> > >     7, or 8. We'd probably just go for the fastest mode, which requires
> > >     8, right?
> > not right.
> > 
> > The DDR mode can not work if we set a wrong dummy cycles for the flash.
> > 
> > for some chips, the fastest mode may need 6 cycles, not 8. 
> 
> OK, but can spi-nor.c detect this instead of putting this in DT? e.g.,
> associate this with the device ID?

see the my comment above.
> 
> Or even better, we can support CFI detection for SPI NOR flash. I notice
> the datasheet for your Spansion flash [1] has an extensive set of CFI
> parameters defined, including the dummy cycle information. I think it
> might be more sustainable to try to support CFI [2] and SFDP [3] for
> detecting new flash, rather than adding new table entries ad-hoc.
I think different chip vendors may have different format to store the
info, just like the read-retry for nand chips.

do you want to add the code only available for Spansion?
What's more the code will be very long, i think.

Add a new DT binding file for the flash maybe is the simplest way.


> 
> > > So far, none of this seems to require a DT binding, unless there's
> > > something I'm missing about your fsl-quadspi controller.
> > > 
> > > > Test this patch for Spansion s25fl128s NOR flash.
> > > > 
> > > > Signed-off-by: Huang Shijie <b32955@freescale.com>
> > > > ---
> > > > +	/* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
> > > > +	if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
> > > 
> > > Hmm, I think I should probably take another look at the design of
> > > spi-nor.c... Why does spi_nor_scan() take a single 'mode' argument? The
> > > driver should be communicating which (multiple) modes it supports, not
> > > selecting a single mode. spi-nor.c is the only one which knows what the
> > > *flash* supports, so it should be combining knowledge from the
> > > controller driver with its own knowledge of the flash.
> > 
> > It is okay for me to add multiples modes for the spi_nor_scan().
> > I added the single mode for spi_nor_scan is because that the fsl-quadspi
> > does not want to support the low speed modes. (Of course, the fsl-quadspi
> > controller does support the low speed modes.)
> 
> Right, fsl-quadspi only supports one mode. But m25p80.c is more
> flexible, and I think we might have broken some of it in the process
> (e.g., if the SPI controller supports single/dual/quad but the flash
> only supports single, then we might fail to probe).
> 
> I can take a look at this problem if you don't. I'd just recommend that
> we might take a step back on a few of these issues before blazing ahead
> with something irrevocable, like a DT binding.

I am glad you can spend some time on this issue. 


Could you please also read this patch ?:

http://lists.infradead.org/pipermail/linux-mtd/2014-May/054108.html

thanks
Huang Shijie
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Brian Norris Aug. 2, 2014, 2:06 a.m. UTC | #7
On Wed, Jul 30, 2014 at 11:46:07AM +0100, Mark Brown wrote:
> On Wed, Jul 30, 2014 at 12:45:00AM -0700, Brian Norris wrote:
> > On Wed, Jul 30, 2014 at 02:44:13PM +0800, Huang Shijie wrote:
> > > IMHO, the DDR modes can _NOT_ be handled by the driver/spi/*.
> 
> > I agree to some extent, but I wanted to confirm with the SPI guys that
> > DDR is truly unique to SPI NOR. (I know it doesn't currently support
> > it.)
> 
> I don't know what DDR is in this context, sorry.

I think it's just the ability to latch data on both the rising and
falling edges of the SPI clock. For SPI flash, it seems to be used for
the data portion of the opcode/address/data sequence.

> I'm guessing you're
> right since it sounds like something to do with extra clocks and this is
> probably not something used by generic SPI devices at present (if it
> ends up being widely implemented by sufficiently generic controllers
> that might change but the trend seems to be to flash specific
> controllers).

OK, thanks for chiming in.

Yeah, I suppose it could be wedged in later if drivers/spi/ ever adopts
a solution.

Brian
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven Aug. 2, 2014, 9:09 a.m. UTC | #8
On Sat, Aug 2, 2014 at 4:06 AM, Brian Norris
<computersforpeace@gmail.com> wrote:
> On Wed, Jul 30, 2014 at 11:46:07AM +0100, Mark Brown wrote:
>> On Wed, Jul 30, 2014 at 12:45:00AM -0700, Brian Norris wrote:
>> > On Wed, Jul 30, 2014 at 02:44:13PM +0800, Huang Shijie wrote:
>> > > IMHO, the DDR modes can _NOT_ be handled by the driver/spi/*.
>>
>> > I agree to some extent, but I wanted to confirm with the SPI guys that
>> > DDR is truly unique to SPI NOR. (I know it doesn't currently support
>> > it.)
>>
>> I don't know what DDR is in this context, sorry.
>
> I think it's just the ability to latch data on both the rising and
> falling edges of the SPI clock. For SPI flash, it seems to be used for
> the data portion of the opcode/address/data sequence.
>
>> I'm guessing you're
>> right since it sounds like something to do with extra clocks and this is
>> probably not something used by generic SPI devices at present (if it
>> ends up being widely implemented by sufficiently generic controllers
>> that might change but the trend seems to be to flash specific
>> controllers).
>
> OK, thanks for chiming in.
>
> Yeah, I suppose it could be wedged in later if drivers/spi/ ever adopts
> a solution.

I think this can just be another SPI_* spi_device.mode flag.

Do we need bindings for this in
Documentation/devicetree/bindings/spi/spi-bus.txt?
Unlike Quad SPI transfer support, this doesn't need special wiring, so DDR
capability is an intrinsic property of the SPI slave, and the mode bit can just
be set in the SPI slave driver, without any DT magic?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Aug. 4, 2014, 2:25 p.m. UTC | #9
On Sat, Aug 02, 2014 at 11:09:09AM +0200, Geert Uytterhoeven wrote:
> On Sat, Aug 2, 2014 at 4:06 AM, Brian Norris
> > On Wed, Jul 30, 2014 at 11:46:07AM +0100, Mark Brown wrote:

> >> I don't know what DDR is in this context, sorry.

> > I think it's just the ability to latch data on both the rising and
> > falling edges of the SPI clock. For SPI flash, it seems to be used for
> > the data portion of the opcode/address/data sequence.

> > Yeah, I suppose it could be wedged in later if drivers/spi/ ever adopts
> > a solution.

> I think this can just be another SPI_* spi_device.mode flag.

Sounds like it yes - I was wondering if this might be one of the modes
with extra clock cycles that I've heard mentioned before which might be
a little more fun.

> Do we need bindings for this in
> Documentation/devicetree/bindings/spi/spi-bus.txt?
> Unlike Quad SPI transfer support, this doesn't need special wiring, so DDR
> capability is an intrinsic property of the SPI slave, and the mode bit can just
> be set in the SPI slave driver, without any DT magic?

Right, unless we run into things like board design issues causing
constraints this is something that can be enabled by the two drivers
without needing DT configuration.
Zhi Li July 22, 2015, 6:15 p.m. UTC | #10
On Mon, Aug 4, 2014 at 9:25 AM, Mark Brown <broonie@kernel.org> wrote:
> On Sat, Aug 02, 2014 at 11:09:09AM +0200, Geert Uytterhoeven wrote:
>> On Sat, Aug 2, 2014 at 4:06 AM, Brian Norris
>> > On Wed, Jul 30, 2014 at 11:46:07AM +0100, Mark Brown wrote:
>
>> >> I don't know what DDR is in this context, sorry.
>
>> > I think it's just the ability to latch data on both the rising and
>> > falling edges of the SPI clock. For SPI flash, it seems to be used for
>> > the data portion of the opcode/address/data sequence.
>
>> > Yeah, I suppose it could be wedged in later if drivers/spi/ ever adopts
>> > a solution.
>
>> I think this can just be another SPI_* spi_device.mode flag.
>
> Sounds like it yes - I was wondering if this might be one of the modes
> with extra clock cycles that I've heard mentioned before which might be
> a little more fun.
>
>> Do we need bindings for this in
>> Documentation/devicetree/bindings/spi/spi-bus.txt?
>> Unlike Quad SPI transfer support, this doesn't need special wiring, so DDR
>> capability is an intrinsic property of the SPI slave, and the mode bit can just
>> be set in the SPI slave driver, without any DT magic?
>
> Right, unless we run into things like board design issues causing
> constraints this is something that can be enabled by the two drivers
> without needing DT configuration.

All:

we plan resume this work.
I need direction how go ahead further.

I go through this email thread.

The discussion focus on how to get dummy cycle information.

Shijie get it from DT.

Brain suggest get from CFI or map id table if I understand correct.

Accodring to spec
http://www.spansion.com/Support/Datasheets/S25FL128S_256S_00.pdf

Table 8.10

Dummy cycle depend on frequency, read command.

if information saved in driver, it will be huge table.

>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zhi Li July 22, 2015, 6:18 p.m. UTC | #11
On Wed, Jul 22, 2015 at 1:15 PM, Zhi Li <lznuaa@gmail.com> wrote:
> On Mon, Aug 4, 2014 at 9:25 AM, Mark Brown <broonie@kernel.org> wrote:
>> On Sat, Aug 02, 2014 at 11:09:09AM +0200, Geert Uytterhoeven wrote:
>>> On Sat, Aug 2, 2014 at 4:06 AM, Brian Norris
>>> > On Wed, Jul 30, 2014 at 11:46:07AM +0100, Mark Brown wrote:
>>
>>> >> I don't know what DDR is in this context, sorry.
>>
>>> > I think it's just the ability to latch data on both the rising and
>>> > falling edges of the SPI clock. For SPI flash, it seems to be used for
>>> > the data portion of the opcode/address/data sequence.
>>
>>> > Yeah, I suppose it could be wedged in later if drivers/spi/ ever adopts
>>> > a solution.
>>
>>> I think this can just be another SPI_* spi_device.mode flag.
>>
>> Sounds like it yes - I was wondering if this might be one of the modes
>> with extra clock cycles that I've heard mentioned before which might be
>> a little more fun.
>>
>>> Do we need bindings for this in
>>> Documentation/devicetree/bindings/spi/spi-bus.txt?
>>> Unlike Quad SPI transfer support, this doesn't need special wiring, so DDR
>>> capability is an intrinsic property of the SPI slave, and the mode bit can just
>>> be set in the SPI slave driver, without any DT magic?
>>
>> Right, unless we run into things like board design issues causing
>> constraints this is something that can be enabled by the two drivers
>> without needing DT configuration.
>
> All:

Just update shijie's email address.

>
> we plan resume this work.
> I need direction how go ahead further.
>
> I go through this email thread.
>
> The discussion focus on how to get dummy cycle information.
>
> Shijie get it from DT.
>
> Brain suggest get from CFI or map id table if I understand correct.
>
> Accodring to spec
> http://www.spansion.com/Support/Datasheets/S25FL128S_256S_00.pdf
>
> Table 8.10
>
> Dummy cycle depend on frequency, read command.
>
> if information saved in driver, it will be huge table.
>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index f374e44..e0bc11a 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -73,7 +73,20 @@  static int read_cr(struct spi_nor *nor)
  */
 static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
 {
+	u32 dummy;
+
 	switch (nor->flash_read) {
+	case SPI_NOR_DDR_QUAD:
+		/*
+		 * The m25p80.c can not support the DDR quad read.
+		 * We set the dummy cycles to 8 by default. The SPI NOR
+		 * controller driver can set it in its child DT node.
+		 * We parse it out here.
+		 */
+		if (nor->np && !of_property_read_u32(nor->np,
+				"spi-nor,ddr-quad-read-dummy", &dummy)) {
+			return dummy;
+		}
 	case SPI_NOR_FAST:
 	case SPI_NOR_DUAL:
 	case SPI_NOR_QUAD:
@@ -402,6 +415,7 @@  struct flash_info {
 #define	SECT_4K_PMC		0x10	/* SPINOR_OP_BE_4K_PMC works uniformly */
 #define	SPI_NOR_DUAL_READ	0x20    /* Flash supports Dual Read */
 #define	SPI_NOR_QUAD_READ	0x40    /* Flash supports Quad Read */
+#define	SPI_NOR_DDR_QUAD_READ	0x80    /* Flash supports DDR Quad Read */
 };
 
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
@@ -846,6 +860,24 @@  static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
+static int set_ddr_quad_mode(struct spi_nor *nor, u32 jedec_id)
+{
+	int status;
+
+	switch (JEDEC_MFR(jedec_id)) {
+	case CFI_MFR_AMD: /* Spansion, actually */
+		status = spansion_quad_enable(nor);
+		if (status) {
+			dev_err(nor->dev,
+				"Spansion DDR quad-read not enabled\n");
+			return status;
+		}
+		return status;
+	default:
+		return -EINVAL;
+	}
+}
+
 static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
 {
 	int status;
@@ -1016,8 +1048,15 @@  int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
 	if (info->flags & SPI_NOR_NO_FR)
 		nor->flash_read = SPI_NOR_NORMAL;
 
-	/* Quad/Dual-read mode takes precedence over fast/normal */
-	if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+	/* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
+	if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
+		ret = set_ddr_quad_mode(nor, info->jedec_id);
+		if (ret) {
+			dev_err(dev, "DDR quad mode not supported\n");
+			return ret;
+		}
+		nor->flash_read = SPI_NOR_DDR_QUAD;
+	} else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
 		ret = set_quad_mode(nor, info->jedec_id);
 		if (ret) {
 			dev_err(dev, "quad mode not supported\n");
@@ -1030,6 +1069,14 @@  int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
 
 	/* Default commands */
 	switch (nor->flash_read) {
+	case SPI_NOR_DDR_QUAD:
+		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Spansion */
+			nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
+		} else {
+			dev_err(dev, "DDR Quad Read is not supported.\n");
+			return -EINVAL;
+		}
+		break;
 	case SPI_NOR_QUAD:
 		nor->read_opcode = SPINOR_OP_READ_1_1_4;
 		break;
@@ -1057,6 +1104,9 @@  int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
 		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
 			/* Dedicated 4-byte command set */
 			switch (nor->flash_read) {
+			case SPI_NOR_DDR_QUAD:
+				nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
+				break;
 			case SPI_NOR_QUAD:
 				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
 				break;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 48fe9fc..d191a6b 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -12,10 +12,11 @@ 
 
 /*
  * Note on opcode nomenclature: some opcodes have a format like
- * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
+ * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y, and z stand for the number
  * of I/O lines used for the opcode, address, and data (respectively). The
  * FUNCTION has an optional suffix of '4', to represent an opcode which
- * requires a 4-byte (32-bit) address.
+ * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the
+ * DDR mode.
  */
 
 /* Flash opcodes. */
@@ -26,6 +27,7 @@ 
 #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_4_4_D	0xed	/* Read data bytes (DDR Quad 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 */
@@ -40,6 +42,7 @@ 
 #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_4_4_D	0xee	/* Read data bytes (DDR Quad SPI) */
 #define SPINOR_OP_PP_4B		0x12	/* Page program (up to 256 bytes) */
 #define SPINOR_OP_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
 
@@ -74,6 +77,7 @@  enum read_mode {
 	SPI_NOR_FAST,
 	SPI_NOR_DUAL,
 	SPI_NOR_QUAD,
+	SPI_NOR_DDR_QUAD,
 };
 
 /**