diff mbox

[RFC] mtd: spi-nor: add DDR quad read support

Message ID 1397641641-11430-1-git-send-email-b32955@freescale.com
State Superseded
Headers show

Commit Message

Huang Shijie April 16, 2014, 9:47 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 opcode: SPINOR_OP_READ_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] set the dummy with 8 for DDR quad read.
      _
Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/mtd/spi-nor/spi-nor.c |   36 ++++++++++++++++++++++++++++++++++--
 include/linux/mtd/spi-nor.h   |    7 +++++--
 2 files changed, 39 insertions(+), 4 deletions(-)

Comments

Marek Vasut April 17, 2014, 2:24 p.m. UTC | #1
On Wednesday, April 16, 2014 at 11:47:21 AM, Huang Shijie wrote:
[...]

> @@ -74,6 +74,11 @@ static int read_cr(struct spi_nor *nor)
>  static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
>  {
>  	switch (nor->flash_read) {
> +	case SPI_NOR_DDR_QUAD:
> +		/*
> +		 * We set 8 for the DDR Quad read, the SPI NOR controller
> +		 * can change it to 6 or 4 with DeviceTree property.
> +		 */

Isn't the number of dummy cycles a property of the chip ?
[...]

> +static int set_ddr_quad_mode(struct spi_nor *nor, u32 jedec_id)
> +{
> +	int status;
> +
> +	switch (JEDEC_MFR(jedec_id)) {
> +	default: /* Spansion */

This should really _check_ the jedec ID here and only enable the quad mode for 
spansion on spansion flashes. The default case should just return -ENOTSUP or 
something.
[...]

> @@ -1016,8 +1038,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;

Is it really necessary to fail here? Can we not fall back to some "lower" mode ?
[...]

Best regards,
Marek Vasut
Huang Shijie April 17, 2014, 4:05 p.m. UTC | #2
On Thu, Apr 17, 2014 at 04:24:36PM +0200, Marek Vasut wrote:
> On Wednesday, April 16, 2014 at 11:47:21 AM, Huang Shijie wrote:
> [...]
> 
> > @@ -74,6 +74,11 @@ static int read_cr(struct spi_nor *nor)
> >  static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
> >  {
> >  	switch (nor->flash_read) {
> > +	case SPI_NOR_DDR_QUAD:
> > +		/*
> > +		 * We set 8 for the DDR Quad read, the SPI NOR controller
> > +		 * can change it to 6 or 4 with DeviceTree property.
> > +		 */
> 
> Isn't the number of dummy cycles a property of the chip ?
I want to add DT node, such as "ddr_quad_read_dummy".
But I do not know which Document file to put the DT node to. 

the spi-bus.txt ? or the spi-nor.txt? 


> [...]
> 
> > +static int set_ddr_quad_mode(struct spi_nor *nor, u32 jedec_id)
> > +{
> > +	int status;
> > +
> > +	switch (JEDEC_MFR(jedec_id)) {
> > +	default: /* Spansion */
> 
> This should really _check_ the jedec ID here and only enable the quad mode for 
> spansion on spansion flashes. The default case should just return -ENOTSUP or 
> something.
> [...]
ok. change it in next version.


> 
> > @@ -1016,8 +1038,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;
> 
> Is it really necessary to fail here? Can we not fall back to some "lower" mode ?
I perfer to fail here.
If we fail to enable the quad read, we also do not fall back to fast
read mode.

thanks
Huang Shijie
Geert Uytterhoeven April 17, 2014, 6:41 p.m. UTC | #3
On Thu, Apr 17, 2014 at 4:24 PM, Marek Vasut <marex@denx.de> wrote:
>> @@ -1016,8 +1038,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;
>
> Is it really necessary to fail here? Can we not fall back to some "lower" mode ?

IIRC, the original m25p80 also fails, FWIW...

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
Marek Vasut April 21, 2014, 3:25 p.m. UTC | #4
On Thursday, April 17, 2014 at 08:41:50 PM, Geert Uytterhoeven wrote:
> On Thu, Apr 17, 2014 at 4:24 PM, Marek Vasut <marex@denx.de> wrote:
> >> @@ -1016,8 +1038,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;
> > 
> > Is it really necessary to fail here? Can we not fall back to some "lower"
> > mode ?
> 
> IIRC, the original m25p80 also fails, FWIW...

OK, so let's keep consistent. But maybe we should add a note for future 
generations that this can be improved.

Best regards,
Marek Vasut
Marek Vasut April 21, 2014, 3:26 p.m. UTC | #5
On Thursday, April 17, 2014 at 06:05:17 PM, Huang Shijie wrote:
> On Thu, Apr 17, 2014 at 04:24:36PM +0200, Marek Vasut wrote:
> > On Wednesday, April 16, 2014 at 11:47:21 AM, Huang Shijie wrote:
> > [...]
> > 
> > > @@ -74,6 +74,11 @@ static int read_cr(struct spi_nor *nor)
> > > 
> > >  static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
> > >  {
> > >  
> > >  	switch (nor->flash_read) {
> > > 
> > > +	case SPI_NOR_DDR_QUAD:
> > > +		/*
> > > +		 * We set 8 for the DDR Quad read, the SPI NOR controller
> > > +		 * can change it to 6 or 4 with DeviceTree property.
> > > +		 */
> > 
> > Isn't the number of dummy cycles a property of the chip ?
> 
> I want to add DT node, such as "ddr_quad_read_dummy".
> But I do not know which Document file to put the DT node to.
> 
> the spi-bus.txt ? or the spi-nor.txt?

It's a property of the chip, therefore spi-nor.txt , no ?
[...]

I replied about the failing-to-lower-mode in the other email.

Best regards,
Marek Vasut
Huang Shijie April 22, 2014, 7:33 a.m. UTC | #6
On Mon, Apr 21, 2014 at 05:26:07PM +0200, Marek Vasut wrote:
> On Thursday, April 17, 2014 at 06:05:17 PM, Huang Shijie wrote:
> > On Thu, Apr 17, 2014 at 04:24:36PM +0200, Marek Vasut wrote:
> > > On Wednesday, April 16, 2014 at 11:47:21 AM, Huang Shijie wrote:
> > > [...]
> > > 
> > > > @@ -74,6 +74,11 @@ static int read_cr(struct spi_nor *nor)
> > > > 
> > > >  static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
> > > >  {
> > > >  
> > > >  	switch (nor->flash_read) {
> > > > 
> > > > +	case SPI_NOR_DDR_QUAD:
> > > > +		/*
> > > > +		 * We set 8 for the DDR Quad read, the SPI NOR controller
> > > > +		 * can change it to 6 or 4 with DeviceTree property.
> > > > +		 */
> > > 
> > > Isn't the number of dummy cycles a property of the chip ?
> > 
> > I want to add DT node, such as "ddr_quad_read_dummy".
> > But I do not know which Document file to put the DT node to.
> > 
> > the spi-bus.txt ? or the spi-nor.txt?
> 
> It's a property of the chip, therefore spi-nor.txt , no ?

[1] For the m25p80.c, the @nor->dev points to a spi_device{}.

   If the spi core can support the DDR QUAD read, we can add the DT node to
  the spi-bus.txt. Please see the spi-bus.txt:
  
  ----------------------------------------------------------------------
  SPI slave nodes must be children of the SPI master node and can
  contain the following properties.
  - reg             - (required) chip select address of device.
  - compatible      - (required) name of SPI device following generic names
      		recommended practice
  - spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
  - spi-cpol        - (optional) Empty property indicating device requires
      		inverse clock polarity (CPOL) mode
  - spi-cpha        - (optional) Empty property indicating device requires
      		shifted clock phase (CPHA) mode
  - spi-cs-high     - (optional) Empty property indicating device requires
      		chip select active high
  - spi-3wire       - (optional) Empty property indicating device requires
  ----------------------------------------------------------------------
  
  As a SPI slave DT node, we can put the "ddr_quad_read_dummy" to the spi-bus.txt.
  
  But unfortunately, I am not sure if the SPI core can support the DDR quad read
  or not. :( IMHO, it can _NOT_ support. 

[2] For the SPI NOR controller(such as fsl-quadspi.c), the @nor->dev points
   to a platform_device{}.  I did not allocate a device{} for the NOR flash.
   so i could add the "ddr_quad_read_dummy" to the fsl-quadspi.txt.

   what's your opinion?

thanks   
Huang Shijie
diff mbox

Patch

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index b88cc7e..6858e36 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -74,6 +74,11 @@  static int read_cr(struct spi_nor *nor)
 static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
 {
 	switch (nor->flash_read) {
+	case SPI_NOR_DDR_QUAD:
+		/*
+		 * We set 8 for the DDR Quad read, the SPI NOR controller
+		 * can change it to 6 or 4 with DeviceTree property.
+		 */
 	case SPI_NOR_FAST:
 	case SPI_NOR_DUAL:
 	case SPI_NOR_QUAD:
@@ -402,6 +407,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 +852,22 @@  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)) {
+	default: /* Spansion */
+		status = spansion_quad_enable(nor);
+		if (status) {
+			dev_err(nor->dev,
+				"Spansion DDR quad-read not enabled\n");
+			return -EINVAL;
+		}
+		return status;
+	}
+}
+
 static int set_quad_mode(struct spi_nor *nor, u32 jedec_id)
 {
 	int status;
@@ -1016,8 +1038,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 +1059,9 @@  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:
+		nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
+		break;
 	case SPI_NOR_QUAD:
 		nor->read_opcode = SPINOR_OP_READ_1_1_4;
 		break;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 5324184..b3ada3e 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 */
@@ -74,6 +76,7 @@  enum read_mode {
 	SPI_NOR_FAST,
 	SPI_NOR_DUAL,
 	SPI_NOR_QUAD,
+	SPI_NOR_DDR_QUAD,
 };
 
 /**