mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	This flag was added to 4.9 with upstream commit 76a4707de5e18dc32d9cb4e990686140c5664a15. Signed-off-by: Victor Shyba <victor1984@riseup.net> [refresh and adjust platform patches, fix commit message] Signed-off-by: Mathias Kresin <dev@kresin.me>
		
			
				
	
	
		
			182 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 924f021c0344554a4b61746e5c4dcfc91d618ce2 Mon Sep 17 00:00:00 2001
 | |
| From: Yunhui Cui <yunhui.cui@nxp.com>
 | |
| Date: Thu, 18 Feb 2016 16:41:53 +0800
 | |
| Subject: [PATCH 105/113] mtd: spi-nor: add DDR quad read support
 | |
| 
 | |
| 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.
 | |
| 
 | |
|   [4] set dummy with 6 for Spansion family
 | |
| Test this patch for Spansion s25fl128s NOR flash.
 | |
| 
 | |
| Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
 | |
| ---
 | |
|  drivers/mtd/spi-nor/spi-nor.c |   53 ++++++++++++++++++++++++++++++++++++-----
 | |
|  include/linux/mtd/spi-nor.h   |    8 +++++--
 | |
|  2 files changed, 53 insertions(+), 8 deletions(-)
 | |
| 
 | |
| --- a/drivers/mtd/spi-nor/spi-nor.c
 | |
| +++ b/drivers/mtd/spi-nor/spi-nor.c
 | |
| @@ -73,7 +73,8 @@ 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	USE_FSR			0x80	/* use flag status register */
 | |
| +#define SPI_NOR_DDR_QUAD_READ	0x80	/* Flash supports DDR Quad Read */
 | |
| +#define	USE_FSR			0x100	/* use flag status register */
 | |
|  #define	SPI_NOR_HAS_LOCK	0x100	/* Flash supports lock/unlock via SR */
 | |
|  };
 | |
|  
 | |
| @@ -145,13 +146,17 @@ static int read_cr(struct spi_nor *nor)
 | |
|   * 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)
 | |
| +static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor,
 | |
| +			const struct flash_info *info)
 | |
|  {
 | |
|  	switch (nor->flash_read) {
 | |
|  	case SPI_NOR_FAST:
 | |
|  	case SPI_NOR_DUAL:
 | |
|  	case SPI_NOR_QUAD:
 | |
|  		return 8;
 | |
| +	case SPI_NOR_DDR_QUAD:
 | |
| +		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION)
 | |
| +			return 6;
 | |
|  	case SPI_NOR_NORMAL:
 | |
|  		return 0;
 | |
|  	}
 | |
| @@ -799,7 +804,8 @@ static const struct flash_info spi_nor_i
 | |
|  	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
 | |
|  	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
 | |
|  	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
 | |
| -	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
 | |
| +	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ
 | |
| +			| SPI_NOR_DDR_QUAD_READ) },
 | |
|  	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
|  	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
|  	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
 | |
| @@ -1188,6 +1194,23 @@ static int spansion_quad_enable(struct s
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| +static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 | |
| +{
 | |
| +	int status;
 | |
| +
 | |
| +	switch (JEDEC_MFR(info)) {
 | |
| +	case SNOR_MFR_SPANSION:
 | |
| +		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, const struct flash_info *info)
 | |
|  {
 | |
|  	int status;
 | |
| @@ -1378,8 +1401,15 @@ int spi_nor_scan(struct spi_nor *nor, co
 | |
|  	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);
 | |
| +		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);
 | |
|  		if (ret) {
 | |
|  			dev_err(dev, "quad mode not supported\n");
 | |
| @@ -1392,6 +1422,14 @@ int spi_nor_scan(struct spi_nor *nor, co
 | |
|  
 | |
|  	/* Default commands */
 | |
|  	switch (nor->flash_read) {
 | |
| +	case SPI_NOR_DDR_QUAD:
 | |
| +		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { /* 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;
 | |
| @@ -1419,6 +1457,9 @@ int spi_nor_scan(struct spi_nor *nor, co
 | |
|  		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
 | |
|  			/* 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;
 | |
| @@ -1448,7 +1489,7 @@ int spi_nor_scan(struct spi_nor *nor, co
 | |
|  		return -EINVAL;
 | |
|  	}
 | |
|  
 | |
| -	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
 | |
| +	nor->read_dummy = spi_nor_read_dummy_cycles(nor, info);
 | |
|  
 | |
|  	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 | |
|  			(long long)mtd->size >> 10);
 | |
| --- a/include/linux/mtd/spi-nor.h
 | |
| +++ b/include/linux/mtd/spi-nor.h
 | |
| @@ -30,10 +30,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. */
 | |
| @@ -44,6 +45,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 */
 | |
| @@ -59,6 +61,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) */
 | |
|  
 | |
| @@ -107,6 +110,7 @@ enum read_mode {
 | |
|  	SPI_NOR_FAST,
 | |
|  	SPI_NOR_DUAL,
 | |
|  	SPI_NOR_QUAD,
 | |
| +	SPI_NOR_DDR_QUAD,
 | |
|  };
 | |
|  
 | |
|  #define SPI_NOR_MAX_CMD_SIZE	8
 |