mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			2136 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			2136 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			Diff
		
	
	
| --- linux-4.9.37/drivers/mtd/spi-nor/spi-nor.c	2017-07-12 16:42:41.000000000 +0300
 | |
| +++ linux-4.9.y/drivers/mtd/spi-nor/spi-nor.c	2021-06-07 13:01:33.000000000 +0300
 | |
| @@ -75,6 +75,13 @@
 | |
|  					 * bit. Must be used with
 | |
|  					 * SPI_NOR_HAS_LOCK.
 | |
|  					 */
 | |
| +#define SPI_NOR_4B_OPCODES	BIT(10)	/*
 | |
| +					 * Use dedicated 4byte address op codes
 | |
| +					 * to support memory size above 128Mib.
 | |
| +					 */
 | |
| +
 | |
| +	const struct spi_nor_basic_flash_parameter *params;
 | |
| +	u32 clkrate;
 | |
|  };
 | |
|  
 | |
|  #define JEDEC_MFR(info)	((info)->id[0])
 | |
| @@ -139,31 +146,24 @@
 | |
|  }
 | |
|  
 | |
|  /*
 | |
| - * Dummy Cycle calculation for different type of read.
 | |
| - * It can be used to support more commands with
 | |
| - * different dummy cycle requirements.
 | |
| + * Write status register 1 byte
 | |
| + * Returns negative if error occurred.
 | |
|   */
 | |
| -static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
 | |
| +static inline int write_sr(struct spi_nor *nor, u8 val)
 | |
|  {
 | |
| -	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;
 | |
| +	nor->cmd_buf[0] = val;
 | |
| +	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
 | |
|  }
 | |
|  
 | |
| +
 | |
|  /*
 | |
| - * Write status register 1 byte
 | |
| + * Write status register-2 1 byte
 | |
|   * Returns negative if error occurred.
 | |
|   */
 | |
| -static inline int write_sr(struct spi_nor *nor, u8 val)
 | |
| +static inline int write_sr2(struct spi_nor *nor, u8 val)
 | |
|  {
 | |
|  	nor->cmd_buf[0] = val;
 | |
| -	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
 | |
| +	return nor->write_reg(nor, SPINOR_OP_WRSR2, nor->cmd_buf, 1);
 | |
|  }
 | |
|  
 | |
|  /*
 | |
| @@ -188,9 +188,83 @@
 | |
|  	return mtd->priv;
 | |
|  }
 | |
|  
 | |
| +struct spi_nor_address_entry {
 | |
| +	u8	src_opcode;
 | |
| +	u8	dst_opcode;
 | |
| +};
 | |
| +
 | |
| +static u8 spi_nor_convert_opcode(u8 opcode,
 | |
| +				 const struct spi_nor_address_entry *entries,
 | |
| +				 size_t num_entries)
 | |
| +{
 | |
| +	unsigned int min, max;
 | |
| +
 | |
| +	min = 0;
 | |
| +	max = num_entries - 1;
 | |
| +	while (min <= max) {
 | |
| +		int mid = (min + max) >> 1;
 | |
| +		const struct spi_nor_address_entry *entry = &entries[mid];
 | |
| +
 | |
| +		if (opcode == entry->src_opcode)
 | |
| +			return entry->dst_opcode;
 | |
| +
 | |
| +		if (opcode < entry->src_opcode)
 | |
| +			max = mid - 1;
 | |
| +		else
 | |
| +			min = mid + 1;
 | |
| +	}
 | |
| +
 | |
| +	/* No conversion found */
 | |
| +	return opcode;
 | |
| +}
 | |
| +
 | |
| +static u8 spi_nor_3to4_opcode(u8 opcode)
 | |
| +{
 | |
| +	/* MUST be sorted by 3byte opcode */
 | |
| +#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
 | |
| +	static const struct spi_nor_address_entry spi_nor_3to4_table[] = {
 | |
| +		ENTRY_3TO4(SPINOR_OP_PP),		/* 0x02 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_READ),		/* 0x03 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_READ_FAST),	/* 0x0b */
 | |
| +		ENTRY_3TO4(SPINOR_OP_BE_4K),		/* 0x20 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_PP_1_1_4),		/* 0x32 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_PP_1_4_4),		/* 0x38 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_READ_1_1_2),	/* 0x3b */
 | |
| +		ENTRY_3TO4(SPINOR_OP_BE_32K),		/* 0x52 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_READ_1_1_4),	/* 0x6b */
 | |
| +		ENTRY_3TO4(SPINOR_OP_READ_1_2_2),	/* 0xbb */
 | |
| +		ENTRY_3TO4(SPINOR_OP_SE),		/* 0xd8 */
 | |
| +		ENTRY_3TO4(SPINOR_OP_READ_1_4_4),	/* 0xeb */
 | |
| +	};
 | |
| +#undef ENTRY_3TO4
 | |
| +
 | |
| +	return spi_nor_convert_opcode(opcode, spi_nor_3to4_table,
 | |
| +				      ARRAY_SIZE(spi_nor_3to4_table));
 | |
| +}
 | |
| +
 | |
| +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
 | |
| +				      const struct flash_info *info)
 | |
| +{
 | |
| +	/* Do some manufacturer fixups first */
 | |
| +	switch (JEDEC_MFR(info)) {
 | |
| +	case SNOR_MFR_SPANSION:
 | |
| +		/* No small sector erase for 4-byte command set */
 | |
| +		nor->erase_opcode = SPINOR_OP_SE;
 | |
| +		nor->mtd.erasesize = info->sector_size;
 | |
| +		break;
 | |
| +
 | |
| +	default:
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +	nor->read_opcode	= spi_nor_3to4_opcode(nor->read_opcode);
 | |
| +	nor->program_opcode	= spi_nor_3to4_opcode(nor->program_opcode);
 | |
| +	nor->erase_opcode	= spi_nor_3to4_opcode(nor->erase_opcode);
 | |
| +}
 | |
| +
 | |
|  /* Enable/disable 4-byte addressing mode. */
 | |
|  static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
 | |
| -			    int enable)
 | |
| +			    u32 enable)
 | |
|  {
 | |
|  	int status;
 | |
|  	bool need_wren = false;
 | |
| @@ -201,16 +275,26 @@
 | |
|  		/* Some Micron need WREN command; all will accept it */
 | |
|  		need_wren = true;
 | |
|  	case SNOR_MFR_MACRONIX:
 | |
| -	case SNOR_MFR_WINBOND:
 | |
|  		if (need_wren)
 | |
|  			write_enable(nor);
 | |
|  
 | |
|  		cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
 | |
|  		status = nor->write_reg(nor, cmd, NULL, 0);
 | |
| +
 | |
|  		if (need_wren)
 | |
|  			write_disable(nor);
 | |
|  
 | |
|  		return status;
 | |
| +	case SNOR_MFR_WINBOND:
 | |
| +		if (enable)
 | |
| +			return nor->write_reg(nor, SPINOR_OP_EN4B, NULL, 0);
 | |
| +		else {
 | |
| +			/* w25q256fvfg must send reset to disable 4 byte mode */
 | |
| +			nor->write_reg(nor, SPINOR_ENABLE_RESET, NULL, 0);
 | |
| +			nor->write_reg(nor, SPINOR_OP_RESET, NULL, 0);
 | |
| +			udelay(30);
 | |
| +		}
 | |
| +		return 0;
 | |
|  	default:
 | |
|  		/* Spansion style */
 | |
|  		nor->cmd_buf[0] = enable << 7;
 | |
| @@ -220,24 +304,28 @@
 | |
|  static inline int spi_nor_sr_ready(struct spi_nor *nor)
 | |
|  {
 | |
|  	int sr = read_sr(nor);
 | |
| +
 | |
|  	if (sr < 0)
 | |
|  		return sr;
 | |
|  	else
 | |
| -		return !(sr & SR_WIP);
 | |
| +		return !((unsigned int)sr & SR_WIP);
 | |
|  }
 | |
|  
 | |
| -static inline int spi_nor_fsr_ready(struct spi_nor *nor)
 | |
| +static inline unsigned int spi_nor_fsr_ready(struct spi_nor *nor)
 | |
|  {
 | |
|  	int fsr = read_fsr(nor);
 | |
| +	unsigned int ufsr = (unsigned int)fsr;
 | |
| +
 | |
|  	if (fsr < 0)
 | |
|  		return fsr;
 | |
|  	else
 | |
| -		return fsr & FSR_READY;
 | |
| +		return ufsr & FSR_READY;
 | |
|  }
 | |
|  
 | |
|  static int spi_nor_ready(struct spi_nor *nor)
 | |
|  {
 | |
|  	int sr, fsr;
 | |
| +
 | |
|  	sr = spi_nor_sr_ready(nor);
 | |
|  	if (sr < 0)
 | |
|  		return sr;
 | |
| @@ -282,7 +370,31 @@
 | |
|  	return spi_nor_wait_till_ready_with_timeout(nor,
 | |
|  						    DEFAULT_READY_WAIT_JIFFIES);
 | |
|  }
 | |
| +static int issi_spi_nor_wait_till_ready(struct spi_nor *nor)
 | |
| +{
 | |
| +	unsigned long deadline;
 | |
| +	int timeout = 0;
 | |
| +	int ret;
 | |
| +
 | |
| +	deadline = jiffies + DEFAULT_READY_WAIT_JIFFIES;
 | |
| +
 | |
| +	while (!timeout) {
 | |
| +		if (time_after_eq(jiffies, deadline))
 | |
| +			timeout = 1;
 | |
|  
 | |
| +		ret = spi_nor_sr_ready(nor);
 | |
| +		if (ret < 0)
 | |
| +			return ret;
 | |
| +		if (ret)
 | |
| +			return 0;
 | |
| +
 | |
| +		cond_resched();
 | |
| +	}
 | |
| +
 | |
| +	dev_err(nor->dev, "flash operation timed out\n");
 | |
| +
 | |
| +	return -ETIMEDOUT;
 | |
| +}
 | |
|  /*
 | |
|   * Erase the whole flash memory
 | |
|   *
 | |
| @@ -367,6 +479,12 @@
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT
 | |
| +	if ((nor->level) && (addr < nor->end_addr)) {
 | |
| +		dev_err(nor->dev, "Error: The erase area was locked\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +#endif
 | |
|  	/* whole-chip erase? */
 | |
|  	if (len == mtd->size) {
 | |
|  		unsigned long timeout;
 | |
| @@ -745,6 +863,280 @@
 | |
|  	return ret;
 | |
|  }
 | |
|  
 | |
| +#define SNOR_RD_MODES			\
 | |
| +	(SNOR_MODE_SLOW |			\
 | |
| +	 SNOR_MODE_1_1_1 |			\
 | |
| +	 SNOR_MODE_1_1_2 |			\
 | |
| +	 SNOR_MODE_1_2_2 |			\
 | |
| +	 SNOR_MODE_1_1_4 |			\
 | |
| +	 SNOR_MODE_1_4_4)
 | |
| +
 | |
| +#define SNOR_WR_MODES			\
 | |
| +	(SNOR_MODE_1_1_1 |			\
 | |
| +	 SNOR_MODE_1_1_4)
 | |
| +
 | |
| +static int spansion_quad_enable(struct spi_nor *nor);
 | |
| +static int macronix_quad_enable(struct spi_nor *nor);
 | |
| +static int gd_quad_enable(struct spi_nor *nor);
 | |
| +static int xtx_quad_enable(struct spi_nor *nor);
 | |
| +static int issi_quad_enable(struct spi_nor *nor);
 | |
| +static int puya_quad_enable(struct spi_nor *nor);
 | |
| +static int puya_quad_enable(struct spi_nor *nor);
 | |
| +
 | |
| +#define SNOR_EON_RD_MODES			\
 | |
| +	(SNOR_MODE_SLOW |			\
 | |
| +	 SNOR_MODE_1_1_1 |			\
 | |
| +	 SNOR_MODE_1_1_2 |			\
 | |
| +	 SNOR_MODE_1_2_2)
 | |
| +
 | |
| +#define SNOR_EON_WR_MODES			\
 | |
| +	(SNOR_MODE_1_1_1)
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter eon_params = {
 | |
| +	.rd_modes		= SNOR_EON_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_EON_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter esmt_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = macronix_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +#define SNOR_PARAGON_WR_MODES			\
 | |
| +	(SNOR_MODE_1_1_1)
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter paragon_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_PARAGON_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = spansion_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter gd_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = gd_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter winbond_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = spansion_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter spansion_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = spansion_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter issi_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = issi_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +#define SNOR_MXIC_WR_MODES			\
 | |
| +	(SNOR_MODE_1_1_1 |			\
 | |
| +	 SNOR_MODE_1_4_4)
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter mxic_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_MXIC_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_4_4]	= SPINOR_OP_PP_1_4_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = macronix_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter xmc_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(0, 24, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter micron_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(8, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(0, 40, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter micron_4k_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(1, 9, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +	.erase_types[1]		= SNOR_OP_ERASE_4K(SPINOR_OP_BE_4K),
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter xtx_params = {
 | |
| +	.rd_modes		= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]	= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]	= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]	= SNOR_OP_READ(0, 24, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes		= SNOR_MODE_1_1_1,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]	= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]	= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]		= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = xtx_quad_enable,
 | |
| +
 | |
| +};
 | |
| +
 | |
| +static const struct spi_nor_basic_flash_parameter puya_params = {
 | |
| +	.rd_modes= SNOR_RD_MODES,
 | |
| +	.reads[SNOR_MIDX_SLOW]= SNOR_OP_READ(0, 0, SPINOR_OP_READ),
 | |
| +	.reads[SNOR_MIDX_1_1_1]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST),
 | |
| +	.reads[SNOR_MIDX_1_1_2]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2),
 | |
| +	.reads[SNOR_MIDX_1_2_2]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2),
 | |
| +	.reads[SNOR_MIDX_1_1_4]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4),
 | |
| +	.reads[SNOR_MIDX_1_4_4]= SNOR_OP_READ(0, 24, SPINOR_OP_READ_1_4_4),
 | |
| +
 | |
| +	.wr_modes= SNOR_WR_MODES,
 | |
| +	.page_programs[SNOR_MIDX_1_1_1]= SPINOR_OP_PP,
 | |
| +	.page_programs[SNOR_MIDX_1_1_4]= SPINOR_OP_PP_1_1_4,
 | |
| +
 | |
| +	.erase_types[0]= SNOR_OP_ERASE_64K(SPINOR_OP_SE),
 | |
| +
 | |
| +	.enable_quad_io         = puya_quad_enable,
 | |
| +};
 | |
| +
 | |
| +#define PARAMS(_name) .params = &_name##_params
 | |
| +
 | |
|  /* Used when the "_ext_id" is two bytes at most */
 | |
|  #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
 | |
|  		.id = {							\
 | |
| @@ -758,7 +1150,7 @@
 | |
|  		.sector_size = (_sector_size),				\
 | |
|  		.n_sectors = (_n_sectors),				\
 | |
|  		.page_size = 256,					\
 | |
| -		.flags = (_flags),
 | |
| +		.flags = (_flags)
 | |
|  
 | |
|  #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
 | |
|  		.id = {							\
 | |
| @@ -782,6 +1174,10 @@
 | |
|  		.addr_width = (_addr_width),				\
 | |
|  		.flags = (_flags),
 | |
|  
 | |
| +/* Different from spi-max-frequency in DTS, the clk here stands for the clock
 | |
| + * rate on SPI interface, it is half of the FMC CRG configuration */
 | |
| +#define CLK_MHZ_2X(clk)  .clkrate = (clk * 2000000),
 | |
| +
 | |
|  /* NOTE: double check command sets and memory organization when you add
 | |
|   * more nor chips.  This current list focusses on newer chips, which
 | |
|   * have been converging on command sets which including JEDEC ID.
 | |
| @@ -793,6 +1189,63 @@
 | |
|   * For historical (and compatibility) reasons (before we got above config) some
 | |
|   * old entries may be missing 4K flag.
 | |
|   */
 | |
| +#define SPI_NOR_IDS_VER     "1.2"
 | |
| +
 | |
| +/******* SPI Nor ID Table ************************************************************************
 | |
| + * Version   Manufacturer    	Chip Name    		Chipsize	Block	Vol  	Operation
 | |
| + *		Macronix/MXIC	MX25V1635F              2M	        64K     3V3
 | |
| + * 1.0		Macronix/MXIC	MX25L1606E		2M		64K	3V3
 | |
| + *		Macronix/MXIC	MX25L6436F		8M		64K	3V3
 | |
| + *		Macronix/MXIC	MX25R6435F		8M		64K	1V8/3V3 Add 14chips
 | |
| + *		Macronix/MXIC	MX25U6435F		8M		64K	1V8
 | |
| + *		Macronix/MXIC	MX25U12835F		16M		64K     1V8
 | |
| + *		Macronix/MXIC	MX25F128XXX		16M		64K     3V3
 | |
| + *		Macronix/MXIC	MX25U25635F/45G		32M		64K	1V8 	25645G-DTR
 | |
| + *		Macronix/MXIC	MX25L(256/257)		32M     	64K     3V3	25645G-DTR
 | |
| + *		Macronix/MXIC	MX25U51245G		64M		64K	1V8 	51245G-DTR
 | |
| + *		Macronix/MXIC   MX25L51245G		64M		64K	3V3
 | |
| + *		Macronix/MXIC	MX66U1G45GM		128M		64K	1V8
 | |
| + *		Spansion	S25FL129P1		16M     	64K	3V3
 | |
| + *		Spansion	S25FL256S		32M     	64K	3V3
 | |
| + *		Micron		N25Q064A		8M      	64K     3V3
 | |
| + *		Micron		N25QL064A		8M      	64K     3V3
 | |
| + *		Micron		N25Q128A11/MT25QU128AB  16M     	64K     1V8
 | |
| + *		Micron		N25QL128A		16M     	64K     3V3
 | |
| + *		Micron		MT25QU256A		32M     	64K     1V8
 | |
| + *		Micron		MT25QL256A		32M     	64K     3V3
 | |
| + *		Winbond		W25Q16(B/C)V/S25FL016K	2M		64K     3V3
 | |
| + *		Winbond		W25Q32(B/F)V		4M		64K     3V3
 | |
| + *		Winbond		W25Q32FW		4M		64K     1V8
 | |
| + *		Winbond		W25Q64FW		8M		64K     1V8
 | |
| + *		Winbond		W25Q64FV(SPI)/W25Q64JV_IQ 8M		64K     3V3
 | |
| + *		Winbond		W25Q128FW		16M     	64K     1V8
 | |
| + *		Winbond		W25Q128(B/F)V		16M     	64K     3V3
 | |
| + *		Winbond		W25Q128JV_IM		16M     	64K     3V3  	DTR
 | |
| + *		Winbond     	W25Q256JWEIQ        	32M		64K     1V8
 | |
| + *		Winbond         W25Q256JWFIM        	32M		64K     1V8
 | |
| + *		ESMT/CFEON	EN25Q32B		4M      	64K     3V3
 | |
| + *		ESMT/CFEON	EN25Q64			8M      	64K     3V3
 | |
| + *		ESMT/CFEON	EN25Q128		16M     	64K     3V3
 | |
| + *		ESMT/CFEON	F25L64QA		8M      	64K     3V3
 | |
| + *		GD		GD25Q16C	        2M		64K     3V3
 | |
| + *		GD		GD25Q64			8M      	64K     3V3
 | |
| + *		GD		GD25LQ128		16M     	64K     1V8
 | |
| + *		GD		GD25Q128		16M     	64K     3V3
 | |
| + *		GD		GD25Q256		32M     	64K     3V3
 | |
| + *		GD		GD25LQ64C		8M      	64K     1V8
 | |
| + *		GD		GD25Q32			4M      	64K     3V3
 | |
| + *		Paragon		PN25F16S		2M		64K     3V3
 | |
| + *		Paragon		PN25F32S		4M      	64K     3V3
 | |
| + * 1.1		ESMT/CFEON	EN25QH64A		8M      	64K     3V3
 | |
| + * 1.2		XMC		XM25QH64AHIG		8M      	64K     3V3
 | |
| + * 		XMC		XM25QH128A		16M		64K	3V3
 | |
| + * 		XMC		XM25QH128B		16M		64K	3V3
 | |
| + *		Puya		P25Q128H-SUH-IT		16M		64K	3V3
 | |
| + *		FM		FM25Q64-SOB-T-G		8M		64K	3V3
 | |
| + *		FM		FM25Q128-SOB-T-G	16M		64K	3V3
 | |
| + *		HUAHONG		H25S64			8M		64K	3V3
 | |
| + *		HUAHONG		H25S128			16M		64K	3V3
 | |
| + ********************************************************************************************/
 | |
|  static const struct flash_info spi_nor_ids[] = {
 | |
|  	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
 | |
|  	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
 | |
| @@ -812,44 +1265,60 @@
 | |
|  	/* EON -- en25xxx */
 | |
|  	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
 | |
|  	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
 | |
| -	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
 | |
| +	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
|  	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
 | |
| -	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
 | |
| +	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
| +	{ "en25qh32b-104hip2b",    INFO(0x1c7016, 0, 64 * 1024,  64,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
| +	{ "en25qh64a",    INFO(0x1c7017, 0, 64 * 1024,  128,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
| +	{ "en25q128",   INFO(0x1c3018, 0, 64 * 1024,  256,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
|  	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 0) },
 | |
| +	{ "en25qh128a", INFO(0x1c7018, 0, 64 * 1024,  256,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
|  	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
 | |
|  	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, SECT_4K) },
 | |
|  
 | |
| +	/* GallopMemory */
 | |
| +	{ "gm25q128a", INFO(0x1c4018, 0, 64 * 1024,  256,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +
 | |
|  	/* ESMT */
 | |
|  	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
 | |
| +	{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128,
 | |
| +					SPI_NOR_DUAL_READ), PARAMS(esmt), CLK_MHZ_2X(84) },
 | |
|  
 | |
|  	/* Everspin */
 | |
| -	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| -	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| +	{ "mr25h256", CAT25_INFO(32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
| +	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
|  
 | |
|  	/* Fujitsu */
 | |
|  	{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
 | |
|  
 | |
| -	/* GigaDevice */
 | |
| -	{
 | |
| -		"gd25q32", INFO(0xc84016, 0, 64 * 1024,  64,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| -	{
 | |
| -		"gd25q64", INFO(0xc84017, 0, 64 * 1024, 128,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| -	{
 | |
| -		"gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| -	{
 | |
| -		"gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| +	/* GigaDevice 3.3V */
 | |
| +	{ "gd25q16c", INFO(0xc84015, 0, 64 * 1024, 32,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	{ "gd25q128/gd25q127", INFO(0xc84018, 0, 64 * 1024, 256,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	{ "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512,
 | |
| +			SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	/* GigaDevice 1.8V */
 | |
| +	{ "gd25lq16c", INFO(0xc86015, 0, 64 * 1024, 32,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	{ "gd25lq64", INFO(0xc86017, 0, 64 * 1024, 128,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
| +	{ "gd25lq128", INFO(0xc86018, 0, 64 * 1024, 256,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) },
 | |
|  
 | |
|  	/* Intel/Numonyx -- xxxs33b */
 | |
|  	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
 | |
| @@ -859,68 +1328,136 @@
 | |
|  	/* ISSI */
 | |
|  	{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024,   2, SECT_4K) },
 | |
|  
 | |
| -	/* Macronix */
 | |
| +	{ "IS25WP512M-RMLA3", INFO(0x9d701a, 0, 64 * 1024, 1024,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(issi), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	/* Macronix/MXIC 3.3V */
 | |
|  	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
 | |
|  	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
 | |
|  	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
 | |
|  	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
 | |
| -	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
 | |
| -	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
 | |
| +	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ), CLK_MHZ_2X(80) },
 | |
| +	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
 | |
|  	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
 | |
| -	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
 | |
| -	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
 | |
| -	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
 | |
| +	{ "mx25l6436f",  INFO(0xc22017, 0, 64 * 1024, 128,
 | |
| +			SPI_NOR_DUAL_READ), CLK_MHZ_2X(80) },
 | |
| +	{ "mx25l12835f", INFO(0xc22018, 0, 64 * 1024, 256,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
 | |
|  	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
 | |
| -	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
 | |
| +	{ "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512,
 | |
| +			SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(84) },
 | |
| +	{ "mx25l25673g", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_QUAD_READ
 | |
| +			| SPI_NOR_4B_OPCODES) },
 | |
|  	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 | |
| -	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
 | |
| -	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
 | |
| -
 | |
| -	/* Micron */
 | |
| -	{ "n25q032",	 INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q032a",	 INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | |
| -	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 | |
| +	{ "mx66l51235l/mx25l51245g", INFO(0xc2201a, 0, 64 * 1024, 1024,
 | |
| +					SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(80)},
 | |
| +	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ)},
 | |
| +	{ "mx25v1635f",  INFO(0xc22315, 0, 64 * 1024, 32 ,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(80) },
 | |
| +	/* Macronix/MXIC Wide Voltage Range 1.65~3.6V */
 | |
| +	{ "mx25r6435f",  INFO(0xc22817, 0, 64 * 1024, 128,
 | |
| +			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), CLK_MHZ_2X(80) },
 | |
| +	/* Macronix/MXIC 1.8V */
 | |
| +	{ "mx25u1633f",  INFO(0xc22535, 0, 64 * 1024, 32,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(80) },
 | |
| +	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
 | |
| +	{ "mx25u12835f/mx25u12832f", INFO(0xc22538, 0, 64 * 1024, 256,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(84) },
 | |
| +	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512,
 | |
| +			SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(84) },
 | |
| +	{ "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024,
 | |
| +			SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(166) },
 | |
| +	{ "mx66u1g45gm", INFO(0xc2253b, 0, 64 * 1024, 2048,
 | |
| +			SPI_NOR_DUAL_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	/* Micron 3.3V */
 | |
| +	{ "n25q032",     INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron), CLK_MHZ_2X(84) },
 | |
| +	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron_4k), CLK_MHZ_2X(108) },
 | |
| +	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron), CLK_MHZ_2X(108) },
 | |
| + 	{ "mt25ql256a",  INFO(0x20ba19, 0x1044, 64 * 1024,  512, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron), CLK_MHZ_2X(108) },
 | |
| +	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR),
 | |
| +			PARAMS(micron_4k) },
 | |
| +	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR | SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron_4k), CLK_MHZ_2X(80) },
 | |
| +	/* Micron 1.8V */
 | |
| +	{ "n25q032a",    INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron), CLK_MHZ_2X(108) },
 | |
| +	{ "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron), CLK_MHZ_2X(108) },
 | |
| +	{ "mt25qu128a/n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron), CLK_MHZ_2X(108) },
 | |
| +	{ "mt25qu256a",  INFO(0x20bb19, 0, 64 * 1024,  512,
 | |
| +			SPI_NOR_4B_OPCODES | SPI_NOR_DUAL_READ), PARAMS(micron), CLK_MHZ_2X(108) },
 | |
| +	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, USE_FSR | SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(micron_4k), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	/* XMC */
 | |
| +	{ "xm25qh64a",    INFO(0x207017, 0, 64 * 1024,   128, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(xmc), CLK_MHZ_2X(80) },
 | |
| +	{ "xm25qh64b",    INFO(0x206017, 0, 64 * 1024,   128, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(xmc), CLK_MHZ_2X(80) },
 | |
| +	{ "xm25qh128a",   INFO(0x207018, 0, 64 * 1024,   256, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(xmc), CLK_MHZ_2X(80) },
 | |
| +	{ "xm25qh128b",   INFO(0x206018, 0, 64 * 1024,   256, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(xmc), CLK_MHZ_2X(80) },
 | |
| +	{ "xm25qh64chiq",   INFO(0x204017, 0, 64 * 1024,   128, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(xmc), CLK_MHZ_2X(80) },
 | |
| +	{ "xm25qh128chiq",   INFO(0x204018, 0, 64 * 1024,   256, SPI_NOR_DUAL_READ),
 | |
| +			PARAMS(xmc), CLK_MHZ_2X(80) },
 | |
|  
 | |
|  	/* PMC */
 | |
| -	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
 | |
| -	{ "pm25lv010",   INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
 | |
| -	{ "pm25lq032",   INFO(0x7f9d46, 0, 64 * 1024,   64, SECT_4K) },
 | |
| +	{ "pm25lv512",	INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
 | |
| +	{ "pm25lv010",	INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
 | |
| +	{ "pm25lq032",	INFO(0x7f9d46, 0, 64 * 1024,   64, SECT_4K) },
 | |
|  
 | |
|  	/* Spansion -- single (large) sector size only, at least
 | |
|  	 * for the chips listed here (without boot sectors).
 | |
|  	 */
 | |
| -	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| +	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64,
 | |
| +			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| +	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128,
 | |
| +			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
|  	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
 | |
| -	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
 | |
| +	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512,
 | |
| +			 SPI_NOR_4B_OPCODES | SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +	{ "s25fl512s",	INFO(0x010220, 0x4d00, 256 * 1024, 256,
 | |
| +			SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| +	{ "s70fl01gs",	INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
 | |
| +	{ "s25fl127s/129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(108) },
 | |
|  	{ "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) },
 | |
| -	{ "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) },
 | |
| -	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
 | |
| -	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
 | |
| -	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
 | |
| -	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
 | |
| -	{ "s25fl004k",  INFO(0xef4013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
 | |
| -	{ "s25fl116k",  INFO(0x014015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| -	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
 | |
| -	{ "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
 | |
| -	{ "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ) },
 | |
| +	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| +	{ "s25fl128lagmfi010z",  INFO(0x016018, 0, 64 * 1024, 256,
 | |
| +			SPI_NOR_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) },
 | |
| +	{ "s25sl008a",	INFO(0x010213,      0,  64 * 1024,  16, 0) },
 | |
| +	{ "s25sl016a",	INFO(0x010214,      0,  64 * 1024,  32, 0) },
 | |
| +	{ "s25sl032a",	INFO(0x010215,      0,  64 * 1024,  64, 0) },
 | |
| +	{ "s25sl064a",	INFO(0x010216,      0,  64 * 1024, 128, 0) },
 | |
| +	{ "s25fl004k",	INFO(0xef4013,      0,  64 * 1024,   8, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| +	{ "s25fl008k",	INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
| +	{ "w25Q16jv-iq/s25fl016k",	INFO(0xef4015,      0,  64 * 1024,  32,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(84) },
 | |
| +	/* { "s25fl064k",	INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, */
 | |
| +	{ "s25fl132k",	INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
 | |
| +	{ "s25fl164k",	INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
 | |
| +	{ "s25fl204k",	INFO(0x014013,      0,  64 * 1024,   8, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ) },
 | |
|  
 | |
|  	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
 | |
|  	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
 | |
| @@ -947,6 +1484,9 @@
 | |
|  	{ "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
 | |
|  	{ "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
 | |
|  
 | |
| +	{ "GM25Q128ASIG", INFO(0x1C4018,  0, 64 * 1024,  256, 0) },
 | |
| +	{ "NM25Q128EVB", INFO(0x522118,  0, 64 * 1024,  256, 0) },
 | |
| +
 | |
|  	{ "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
 | |
|  	{ "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
 | |
|  	{ "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4, 0) },
 | |
| @@ -972,43 +1512,109 @@
 | |
|  	{ "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
 | |
|  	{ "m25px80",    INFO(0x207114,  0, 64 * 1024, 16, 0) },
 | |
|  
 | |
| -	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
 | |
| +	/* Winbond 3.3V-- w25x "blocks" are 64K, "sectors" are 4KiB */
 | |
|  	{ "w25x05", INFO(0xef3010, 0, 64 * 1024,  1,  SECT_4K) },
 | |
|  	{ "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
 | |
|  	{ "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
 | |
|  	{ "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
 | |
|  	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
 | |
| -	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
 | |
| +	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K
 | |
| +			| SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 | |
|  	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
 | |
| -	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
 | |
| -	{
 | |
| -		"w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| +	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
|  	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
 | |
| -	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
 | |
| -	{
 | |
| -		"w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| -	{
 | |
| -		"w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
 | |
| -			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| -			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 | |
| -	},
 | |
| +	{ "w25q64fv(spi)/w25q64jv_iq", INFO(0xef4017, 0, 64 * 1024, 128,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
|  	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
 | |
|  	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
 | |
| -	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
 | |
| -	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
 | |
| +	{ "w25q128(b/f)v", INFO(0xef4018, 0, 64 * 1024, 256,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +  	{ "w25q128jv_im", INFO(0xef7018, 0, 64 * 1024, 256,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +#ifdef CONFIG_AUTOMOTIVE_GRADE
 | |
| +	{ "w25q256(f/j)v", INFO(0xef4019, 0, 64 * 1024, 512,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +#else	
 | |
| +	{ "w25q256(f/j)v", INFO(0xef4019, 0, 64 * 1024, 512,
 | |
| +			SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +#endif
 | |
| +	/* Winbond 1.8V */
 | |
| +	{ "w25q32fw", INFO(0xef6016, 0, 64 * 1024,  64,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| +			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| +			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +	{ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| +			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +	{ "w25q256jw-im", INFO(0xef8019, 0, 64 * 1024, 512,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| +			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES),
 | |
| +			PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
| +	{ "w25q256jw-iq", INFO(0xef6019, 0, 64 * 1024, 512,
 | |
| +			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 | |
| +			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES),
 | |
| +			PARAMS(winbond), CLK_MHZ_2X(80) },
 | |
|  
 | |
|  	/* Catalyst / On Semiconductor -- non-JEDEC */
 | |
| -	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| -	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| -	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| -	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| -	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 | |
| +	{ "cat25c11", CAT25_INFO(16, 8, 16, 1, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
| +	{ "cat25c03", CAT25_INFO(32, 8, 16, 2, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
| +	{ "cat25c09", CAT25_INFO(28, 8, 32, 2, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
| +	{ "cat25c17", CAT25_INFO(256, 8, 32, 2, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
| +	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE
 | |
| +			| SPI_NOR_NO_FR) },
 | |
| +	/* Paragon 3.3V */
 | |
| +	{ "pn25f16s", INFO(0xe04015, 0, 64 * 1024,  32,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(paragon), CLK_MHZ_2X(80) },
 | |
| +	{ "pn25f32s", INFO(0xe04016, 0, 64 * 1024,  64,
 | |
| +			SPI_NOR_DUAL_READ), PARAMS(paragon), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	/* XTX */
 | |
| +	{ "xt25f16bssigu", INFO(0x0b4015, 0, 64 * 1024,  32,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	{ "xt25f32bssigu-s", INFO(0x0b4016, 0, 64 * 1024,  64,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	{ "xt25f128b", INFO(0x0b4018, 0, 64 * 1024,  256,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) },
 | |
| +
 | |
| +	{ "xt25f64b", INFO(0x0b4017, 0, 64 * 1024,  128,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) },
 | |
| +
 | |
| +	/*puya 3.3V */
 | |
| +	{"p25q128h", INFO(0x856018, 0, 64 * 1024, 256,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(puya), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	/* FM 3.3v */
 | |
| +	{ "FM25Q64-SOB-T-G",INFO(0xa14017, 0, 64 * 1024, 128,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +	{ "FM25Q128-SOB-T-G",INFO(0xa14018, 0, 64 * 1024, 256,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +		
 | |
| +	/* HUAHONG 3.3v */
 | |
| +	{ "H25S64",INFO(0x684017, 0, 64 * 1024, 128,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +		
 | |
| +	{ "H25S128",INFO(0x684018, 0, 64 * 1024, 256,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	{ "ZB25VQ64A",INFO(0x5e4017, 0, 64 * 1024, 128,
 | |
| +		SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +        { "ZB25VQ128ASIG",INFO(0x5e4018, 0, 64 * 1024, 256,
 | |
| +                SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) },
 | |
| +
 | |
| +	/* SiliconKaiser 3.3v */
 | |
| +	{ "sk25p128", INFO(0x256018, 0, 64 * 1024,  256, SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) },
 | |
| +
 | |
| +	{ "sk25p64", INFO(0x256017, 0, 64 * 1024,  128, SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) },
 | |
| +
 | |
|  	{ },
 | |
|  };
 | |
|  
 | |
| @@ -1024,6 +1630,11 @@
 | |
|  		return ERR_PTR(tmp);
 | |
|  	}
 | |
|  
 | |
| +	if ((id[0] == 0xff) || (id[0] == 0x00)) {
 | |
| +		dev_err(nor->dev, "unrecognized Manufacturer ID\n");
 | |
| +		return ERR_PTR(-ENODEV);
 | |
| +	}
 | |
| +
 | |
|  	for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
 | |
|  		info = &spi_nor_ids[tmp];
 | |
|  		if (info->id_len) {
 | |
| @@ -1036,6 +1647,36 @@
 | |
|  	return ERR_PTR(-ENODEV);
 | |
|  }
 | |
|  
 | |
| +static int puya_quad_enable(struct spi_nor *nor)
 | |
| +{
 | |
| +	int ret;
 | |
| +	u8 val;
 | |
| +
 | |
| +	ret = read_cr(nor);
 | |
| +	if ((unsigned int)ret & CR_QUAD_EN_SPAN)
 | |
| +		return 0;
 | |
| +
 | |
| +	val = (((unsigned int)ret & 0xff) | CR_QUAD_EN_SPAN);
 | |
| +	write_enable(nor);
 | |
| +
 | |
| +	ret = write_sr2(nor, val);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev,
 | |
| +			"error while writing status register-2\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if (spi_nor_wait_till_ready(nor))
 | |
| +		return 1;
 | |
| +
 | |
| +	/* read back and check it */
 | |
| +	ret = read_cr(nor);
 | |
| +	if ((unsigned int)ret & CR_QUAD_EN_SPAN)
 | |
| +		return 0;
 | |
| +	else
 | |
| +		return 1;
 | |
| +}
 | |
| +
 | |
|  static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
 | |
|  			size_t *retlen, u_char *buf)
 | |
|  {
 | |
| @@ -1167,14 +1808,22 @@
 | |
|  	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
| +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT
 | |
| +	if (nor->level && (to < nor->end_addr)) {
 | |
| +		dev_err(nor->dev, "Error: The DMA write area was locked\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +#endif
 | |
|  
 | |
|  	for (i = 0; i < len; ) {
 | |
|  		ssize_t written;
 | |
|  
 | |
|  		page_offset = (to + i) & (nor->page_size - 1);
 | |
| +#ifndef CONFIG_SPI_GOKE_SFC
 | |
|  		WARN_ONCE(page_offset,
 | |
|  			  "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
 | |
|  			  page_offset);
 | |
| +#endif
 | |
|  		/* the size of data remaining on the first page */
 | |
|  		page_remain = min_t(size_t,
 | |
|  				    nor->page_size - page_offset, len - i);
 | |
| @@ -1211,15 +1860,22 @@
 | |
|  	val = read_sr(nor);
 | |
|  	if (val < 0)
 | |
|  		return val;
 | |
| +
 | |
| +	if ((unsigned int)val & SR_QUAD_EN_MX)
 | |
| +		return 0;
 | |
| +
 | |
| +	/* Update the Quad Enable bit. */
 | |
| +	dev_dbg(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n");
 | |
| +
 | |
|  	write_enable(nor);
 | |
|  
 | |
| -	write_sr(nor, val | SR_QUAD_EN_MX);
 | |
| +	write_sr(nor, (u8)val | SR_QUAD_EN_MX);
 | |
|  
 | |
|  	if (spi_nor_wait_till_ready(nor))
 | |
|  		return 1;
 | |
|  
 | |
|  	ret = read_sr(nor);
 | |
| -	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
 | |
| +	if (!(ret > 0 && ((unsigned int)ret & SR_QUAD_EN_MX))) {
 | |
|  		dev_err(nor->dev, "Macronix Quad bit not set\n");
 | |
|  		return -EINVAL;
 | |
|  	}
 | |
| @@ -1227,6 +1883,41 @@
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| +static int xtx_quad_enable(struct spi_nor *nor)
 | |
| +{
 | |
| +	u8 ret, val_h,val_l;
 | |
| +	/* read SR high 8bit*/
 | |
| +	val_h = read_cr(nor);
 | |
| +	if (val_h < 0)
 | |
| +		return val_h;
 | |
| +
 | |
| +	if (val_h & SR_QUAD_EN_XTX)
 | |
| +		return 0;
 | |
| +
 | |
| +	/* Update the Quad Enable bit. */
 | |
| +	dev_dbg(nor->dev, "setting xtx Quad Enable (non-volatile) bit\n");
 | |
| +
 | |
| +	write_enable(nor);
 | |
| +
 | |
| +	/* read SR low 8bit*/
 | |
| +	val_l = read_sr(nor);
 | |
| +
 | |
| +	/* write SR */
 | |
| +	nor->cmd_buf[0] = val_l;
 | |
| +	nor->cmd_buf[1] = val_h;
 | |
| +	nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
 | |
| +
 | |
| +	if (spi_nor_wait_till_ready(nor))
 | |
| +		return 1;
 | |
| +
 | |
| +	ret = read_cr(nor);
 | |
| +	if (!(ret > 0 && (ret & SR_QUAD_EN_XTX))) {
 | |
| +		dev_err(nor->dev, "xtx Quad bit not set\n");
 | |
| +		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
 | |
| @@ -1243,29 +1934,168 @@
 | |
|  
 | |
|  static int spansion_quad_enable(struct spi_nor *nor)
 | |
|  {
 | |
| -	int ret;
 | |
| -	int quad_en = CR_QUAD_EN_SPAN << 8;
 | |
| +	unsigned int ret;
 | |
| +	u16 val;
 | |
| +
 | |
| +	ret = read_cr(nor);
 | |
| +	if (ret & CR_QUAD_EN_SPAN)
 | |
| +		return 0;
 | |
| +
 | |
| +	/* Update the Quad Enable bit. */
 | |
| +	dev_dbg(nor->dev, "setting Quad Enable (non-volatile) bit\n");
 | |
| +
 | |
| +	val = ((ret & 0xff) | CR_QUAD_EN_SPAN) << 8;
 | |
| +
 | |
| +	ret = read_sr(nor);
 | |
| +	val |= (ret & 0xff);
 | |
| +
 | |
| +	write_enable(nor);
 | |
| +
 | |
| +	ret = write_sr_cr(nor, val);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev,
 | |
| +			"error while writing configuration register\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if (spi_nor_wait_till_ready(nor))
 | |
| +		return 1;
 | |
| +
 | |
| +	/* read back and check it */
 | |
| +	ret = read_cr(nor);
 | |
| +	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
 | |
| +		dev_err(nor->dev, "Spansion Quad bit not set\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int issi_quad_enable(struct spi_nor *nor)
 | |
| +{
 | |
| +	unsigned int ret;
 | |
| +	u16 val;
 | |
| +
 | |
| +	ret = read_sr(nor);
 | |
| +	if (ret & QUAD_EN_ISSI)
 | |
| +		return 0;
 | |
| +
 | |
| +	/* Update the Quad Enable bit. */
 | |
| +	dev_dbg(nor->dev, "setting Quad Enable (non-volatile) bit\n");
 | |
| +
 | |
| +	val = ((ret & 0xff) | QUAD_EN_ISSI);
 | |
|  
 | |
|  	write_enable(nor);
 | |
|  
 | |
| -	ret = write_sr_cr(nor, quad_en);
 | |
| +	ret = write_sr(nor, val);
 | |
|  	if (ret < 0) {
 | |
|  		dev_err(nor->dev,
 | |
|  			"error while writing configuration register\n");
 | |
|  		return -EINVAL;
 | |
|  	}
 | |
|  
 | |
| +	if (issi_spi_nor_wait_till_ready(nor))
 | |
| +		return 1;
 | |
| +
 | |
| +	/* read back and check it */
 | |
| +	ret = read_sr(nor);
 | |
| +	if (!(ret > 0 && (ret & QUAD_EN_ISSI))) {
 | |
| +		dev_err(nor->dev, "ISSI Quad bit not set\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int micron_quad_enable(struct spi_nor *nor)
 | |
| +{
 | |
| +	int ret;
 | |
| +	u8 val;
 | |
| +
 | |
| +	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error %d reading EVCR\n", ret);
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	write_enable(nor);
 | |
| +
 | |
| +	/* 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);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error while writing EVCR register\n");
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
|  	ret = spi_nor_wait_till_ready(nor);
 | |
| -	if (ret) {
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	/* read EVCR and check it */
 | |
| +	ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error %d reading EVCR\n", ret);
 | |
| +		return ret;
 | |
| +	}
 | |
| +	if (val & EVCR_QUAD_EN_MICRON) {
 | |
| +		dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int gd_quad_enable(struct spi_nor *nor)
 | |
| +{
 | |
| +	int ret;
 | |
| +	u16 val;
 | |
| +
 | |
| +	/* First, Quad Enable for 16-Pin GD flash, use WRSR[01h] cmd */
 | |
| +	ret = read_cr(nor);
 | |
| +	val = (((unsigned int)ret & 0xff) | CR_QUAD_EN_SPAN) << 8;
 | |
| +
 | |
| +	ret = read_sr(nor);
 | |
| +	val |= ((unsigned int)ret & 0xff);
 | |
| +
 | |
| +	write_enable(nor);
 | |
| +
 | |
| +	ret = write_sr_cr(nor, val);
 | |
| +	if (ret < 0) {
 | |
|  		dev_err(nor->dev,
 | |
| -			"timeout while writing configuration register\n");
 | |
| +			"error while writing config and status register\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	if (spi_nor_wait_till_ready(nor))
 | |
| +		return 1;
 | |
| +
 | |
| +	/* read back and check it */
 | |
| +	ret = read_cr(nor);
 | |
| +	if ((unsigned int)ret & CR_QUAD_EN_SPAN)
 | |
| +		return 0;
 | |
| +
 | |
| +	/* Second, Quad Enable for 8-Pin GD flash, use WRCR[31h] cmd */
 | |
| +	ret = read_sr(nor);
 | |
| +	if (!((unsigned int)ret & SR_WEL))
 | |
| +		write_enable(nor);
 | |
| +
 | |
| +	ret = read_cr(nor);
 | |
| +	nor->cmd_buf[0] = ((unsigned int)ret & 0xff) | CR_QUAD_EN_SPAN;
 | |
| +
 | |
| +	ret = nor->write_reg(nor, SPINOR_OP_WRCR, nor->cmd_buf, 1);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error while writing config register\n");
 | |
|  		return ret;
 | |
|  	}
 | |
|  
 | |
| +	if (spi_nor_wait_till_ready(nor))
 | |
| +		return 1;
 | |
| +
 | |
|  	/* read back and check it */
 | |
|  	ret = read_cr(nor);
 | |
| -	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
 | |
| -		dev_err(nor->dev, "Spansion Quad bit not set\n");
 | |
| +	if (!(ret > 0 && ((unsigned int)ret & CR_QUAD_EN_SPAN))) {
 | |
| +		dev_err(nor->dev, "GigaDevice Quad bit not set\n");
 | |
|  		return -EINVAL;
 | |
|  	}
 | |
|  
 | |
| @@ -1277,6 +2107,7 @@
 | |
|  	int status;
 | |
|  
 | |
|  	switch (JEDEC_MFR(info)) {
 | |
| +	case SNOR_MFR_ESMT:
 | |
|  	case SNOR_MFR_MACRONIX:
 | |
|  		status = macronix_quad_enable(nor);
 | |
|  		if (status) {
 | |
| @@ -1285,7 +2116,40 @@
 | |
|  		}
 | |
|  		return status;
 | |
|  	case SNOR_MFR_MICRON:
 | |
| -		return 0;
 | |
| +		status = micron_quad_enable(nor);
 | |
| +		if (status) {
 | |
| +			dev_err(nor->dev, "Micron quad-read not enabled\n");
 | |
| +			return -EINVAL;
 | |
| +		}
 | |
| +		return status;
 | |
| +	case SNOR_MFR_GD:
 | |
| +		status = gd_quad_enable(nor);
 | |
| +		if (status) {
 | |
| +			dev_err(nor->dev, "GD quad-read not enabled\n");
 | |
| +			return -EINVAL;
 | |
| +		}
 | |
| +		return status;
 | |
| +	case SNOR_MFR_XTX:
 | |
| +		status = xtx_quad_enable(nor);
 | |
| +		if (status) {
 | |
| +			dev_err(nor->dev, "xtx quad-read not enabled\n");
 | |
| +			return -EINVAL;
 | |
| +		}
 | |
| +		return status;
 | |
| +	case SNOR_MFR_PUYA:
 | |
| +		status = puya_quad_enable(nor);
 | |
| +		if (status) {
 | |
| +			dev_err(nor->dev, "puya quad-read not enabled\n");
 | |
| +			return -EINVAL;
 | |
| +		}
 | |
| +		return status;
 | |
| +	case SNOR_MFR_ISSI:
 | |
| +		status = issi_quad_enable(nor);
 | |
| +		if (status) {
 | |
| +			dev_err(nor->dev, "puya quad-read not enabled\n");
 | |
| +			return -EINVAL;
 | |
| +		}
 | |
| +		return status;
 | |
|  	default:
 | |
|  		status = spansion_quad_enable(nor);
 | |
|  		if (status) {
 | |
| @@ -1307,8 +2171,497 @@
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 | |
| +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT
 | |
| +static void spi_lock_update_address(struct spi_nor *nor, const struct flash_info *info)
 | |
| +{
 | |
| +	unsigned int lock_level_max, sectorsize, chipsize;
 | |
| +
 | |
| +	if (!nor->level) {
 | |
| +		nor->end_addr = 0;
 | |
| +		dev_warn(nor->dev, "all blocks is unlocked.\n");
 | |
| +		return;
 | |
| +	}
 | |
| +
 | |
| +	sectorsize = info->sector_size;
 | |
| +	chipsize = sectorsize * info->n_sectors;
 | |
| +	lock_level_max = nor->lock_level_max;
 | |
| +
 | |
| +	switch (JEDEC_MFR(info)) {
 | |
| +	case SNOR_MFR_MACRONIX:
 | |
| +		if (chipsize == _2M) {
 | |
| +			if ((nor->level != lock_level_max)
 | |
| +					&& (nor->level != 1))
 | |
| +				nor->end_addr = chipsize - (sectorsize <<
 | |
| +					(lock_level_max - nor->level - 1));
 | |
| +			else
 | |
| +				nor->end_addr = chipsize;
 | |
| +			return;
 | |
| +		}
 | |
| +
 | |
| +		if (chipsize != _8M)
 | |
| +			break;
 | |
| +	case SNOR_MFR_ESMT:
 | |
| +		/* this case is for ESMT and MXIC 8M devices */
 | |
| +		if (nor->level != lock_level_max)
 | |
| +			nor->end_addr = chipsize - (sectorsize
 | |
| +					<< (lock_level_max - nor->level));
 | |
| +		else
 | |
| +			nor->end_addr = chipsize;
 | |
| +		return;
 | |
| +	case SNOR_MFR_EON:
 | |
| +		if (nor->level != lock_level_max)
 | |
| +			nor->end_addr = chipsize - (sectorsize
 | |
| +					<< (nor->level - 1));
 | |
| +		else
 | |
| +			nor->end_addr = chipsize;
 | |
| +		return;
 | |
| +	default:
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +	/* general case */
 | |
| +	nor->end_addr = chipsize >> (lock_level_max - nor->level);
 | |
| +}
 | |
| +
 | |
| +static unsigned char bsp_bp_to_level(struct spi_nor *nor,
 | |
| +		const struct flash_info *info, unsigned int bp_num)
 | |
| +{
 | |
| +	int ret;
 | |
| +	unsigned char val;
 | |
| +	unsigned char level;
 | |
| +	unsigned int chipsize;
 | |
| +
 | |
| +	ret = spi_nor_wait_till_ready(nor);
 | |
| +	BUG_ON(ret);
 | |
| +
 | |
| +	ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error %d reading SR\n", ret);
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	if (bp_num == BP_NUM_3)
 | |
| +		level = (val & SPI_NOR_SR_BP_MASK_3) >> SPI_NOR_SR_BP0_SHIFT;
 | |
| +	else
 | |
| +		level = (val & SPI_NOR_SR_BP_MASK_4) >> SPI_NOR_SR_BP0_SHIFT;
 | |
| +
 | |
| +	dev_dbg(nor->dev, "the current level[%d]\n", level);
 | |
| +
 | |
| +	if (bp_num == BP_NUM_4) {
 | |
| +		nor->lock_level_max = LOCK_LEVEL_MAX(bp_num) - 5;
 | |
| +		chipsize = info->sector_size * info->n_sectors;
 | |
| +		if ((JEDEC_MFR(info) == SNOR_MFR_MACRONIX)
 | |
| +				&& (chipsize == _16M))
 | |
| +			nor->lock_level_max--;
 | |
| +	} else
 | |
| +		nor->lock_level_max = LOCK_LEVEL_MAX(bp_num);
 | |
| +	dev_dbg(nor->dev, "Get the max bp level: [%d]\n",
 | |
| +	   nor->lock_level_max);
 | |
| +
 | |
| +	return level;
 | |
| +}
 | |
| +
 | |
| +static void bsp_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info)
 | |
| +{
 | |
| +	unsigned int chipsize;
 | |
| +	struct device *dev = nor->dev;
 | |
| +
 | |
| +	chipsize = info->sector_size * info->n_sectors;
 | |
| +
 | |
| +	/* read the BP bit in RDSR to check whether nor is lock or not */
 | |
| +	switch (JEDEC_MFR(info)) {
 | |
| +	case SNOR_MFR_GD:
 | |
| +	case SNOR_MFR_FM:
 | |
| +	case SNOR_MFR_ESMT:
 | |
| +	case SNOR_MFR_EON:
 | |
| +	case SNOR_MFR_SPANSION:
 | |
| +		/* BP bit convert to lock level */
 | |
| +		nor->level = bsp_bp_to_level(nor, info, BP_NUM_3);
 | |
| +		break;
 | |
| +	case SNOR_MFR_WINBOND:
 | |
| +		if (!strcmp("w25q128(b/f)v", info->name)) {
 | |
| +			dev_info(nor->dev, "Force global unlock\n");
 | |
| +			write_enable(nor);
 | |
| +			/* Global Block/Sector Unlock,
 | |
| +			 * see 8.2.42 Global Block/Sector Unlock (98h) */
 | |
| +			nor->write_reg(nor, 0x98, NULL, 0);
 | |
| +			write_disable(nor);
 | |
| +		}
 | |
| +		/* BP bit convert to lock level */
 | |
| +		if (chipsize <= _16M)
 | |
| +			nor->level = bsp_bp_to_level(nor, info, BP_NUM_3);
 | |
| +		else
 | |
| +			nor->level = bsp_bp_to_level(nor, info, BP_NUM_4);
 | |
| +		break;
 | |
| +	case SNOR_MFR_MACRONIX:
 | |
| +	
 | |
| +		/* BP bit convert to lock level */
 | |
| +		if (chipsize <= _8M)
 | |
| +			nor->level = bsp_bp_to_level(nor, info, BP_NUM_3);
 | |
| +		else
 | |
| +			nor->level = bsp_bp_to_level(nor, info, BP_NUM_4);
 | |
| +		break;
 | |
| +	case SNOR_MFR_XTX:
 | |
| +		/* BP bit convert to lock level */
 | |
| +		nor->level = bsp_bp_to_level(nor, info, BP_NUM_4);
 | |
| +		break;
 | |
| +	default:
 | |
| +		goto usage;
 | |
| +	}
 | |
| +
 | |
| +	spi_lock_update_address(nor, info);
 | |
| +	if (nor->end_addr)
 | |
| +		dev_info(dev, "Address range [0 => %#x] is locked.\n",
 | |
| +		nor->end_addr);
 | |
| +	return;
 | |
| +usage:
 | |
| +	dev_err(dev, "The ID: %#x isn't in the BP table,"
 | |
| +			" Current device can't not protect\n",
 | |
| +			JEDEC_MFR(info));
 | |
| +}
 | |
| +#endif/* CONFIG_GOKE_SPI_BLOCK_PROTECT */
 | |
| +
 | |
| +static int spi_nor_midx2proto(int midx, enum spi_nor_protocol *proto)
 | |
| +{
 | |
| +	switch (midx) {
 | |
| +	case SNOR_MIDX_SLOW:
 | |
| +	case SNOR_MIDX_1_1_1:
 | |
| +		*proto = SNOR_PROTO_1_1_1;
 | |
| +		break;
 | |
| +
 | |
| +	case SNOR_MIDX_1_1_2:
 | |
| +		*proto = SNOR_PROTO_1_1_2;
 | |
| +		break;
 | |
| +
 | |
| +	case SNOR_MIDX_1_2_2:
 | |
| +		*proto = SNOR_PROTO_1_2_2;
 | |
| +		break;
 | |
| +	case SNOR_MIDX_1_1_4:
 | |
| +		*proto = SNOR_PROTO_1_1_4;
 | |
| +		break;
 | |
| +
 | |
| +	case SNOR_MIDX_1_4_4:
 | |
| +		*proto = SNOR_PROTO_1_4_4;
 | |
| +		break;
 | |
| +	default:
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int spi_nor_sr3_to_reset(struct spi_nor *nor)
 | |
| +{
 | |
| +	int ret;
 | |
| +	unsigned char val;
 | |
| +
 | |
| +	ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error %d reading Status Reg 3.\n", ret);
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	if (SPI_NOR_GET_RST(val)) {
 | |
| +		dev_dbg(nor->dev, "Device has worked on RESET#.\n");
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	dev_dbg(nor->dev, "Start to enable RESET# function.\n");
 | |
| +	val = SPI_NOR_SET_RST(val);
 | |
| +
 | |
| +	nor->write_reg(nor, SPINOR_OP_WRSR3, &val, 1);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err(nor->dev, "error while writing Status Reg 3.\n");
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	dev_dbg(nor->dev, "Enable RESET# function success.\n");
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int spi_nor_reset_pin_enable(struct spi_nor *nor,
 | |
| +		const struct flash_info *info)
 | |
| +{
 | |
| +	switch (JEDEC_MFR(info)) {
 | |
| +	case SNOR_MFR_WINBOND:
 | |
| +	case SNOR_MFR_GD:
 | |
| +		return spi_nor_sr3_to_reset(nor);
 | |
| +	default:
 | |
| +		return 0;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
 | |
| +			 const struct spi_nor_basic_flash_parameter *params,
 | |
| +			 const struct spi_nor_modes *modes)
 | |
| +{
 | |
| +	bool enable_quad_io;
 | |
| +	u32 rd_modes, wr_modes;
 | |
| +	const struct spi_nor_erase_type *erase_type;
 | |
| +	const struct spi_nor_read_op *read;
 | |
| +	int rd_midx, wr_midx, err = 0;
 | |
| +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
 | |
| +	int i = 0;
 | |
| +#endif
 | |
| +	rd_modes = modes->rd_modes;
 | |
| +	wr_modes = modes->wr_modes;
 | |
| +
 | |
| +	/* Setup read operation. */
 | |
| +	rd_midx = fls(params->rd_modes & rd_modes) - 1;
 | |
| +	if (spi_nor_midx2proto(rd_midx, &nor->read_proto)) {
 | |
| +		dev_err(nor->dev, "invalid (fast) read\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	read = ¶ms->reads[rd_midx];
 | |
| +	nor->read_opcode = read->opcode;
 | |
| +	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
 | |
| +
 | |
| +	/* Set page program op code and protocol. */
 | |
| +	wr_midx = fls(params->wr_modes & wr_modes) - 1;
 | |
| +	if (spi_nor_midx2proto(wr_midx, &nor->write_proto)) {
 | |
| +		dev_err(nor->dev, "invalid page program\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +	nor->program_opcode = params->page_programs[wr_midx];
 | |
| +
 | |
| +	/* Set sector erase op code and size. */
 | |
| +	erase_type = ¶ms->erase_types[0];
 | |
| +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
 | |
| +	for (i = 1; i < SNOR_MAX_ERASE_TYPES; ++i)
 | |
| +		if (params->erase_types[i].size == 0x0c)
 | |
| +			erase_type = ¶ms->erase_types[i];
 | |
| +#endif
 | |
| +	nor->erase_opcode = erase_type->opcode;
 | |
| +	nor->mtd.erasesize = (1 << erase_type->size);
 | |
| +
 | |
| +	enable_quad_io = (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto) == 4 ||
 | |
| +			  SNOR_PROTO_DATA_FROM_PROTO(nor->write_proto) == 4);
 | |
| +
 | |
| +	/* Enable Quad I/O if needed. */
 | |
| +	if (enable_quad_io && params->enable_quad_io) {
 | |
| +		err = params->enable_quad_io(nor);
 | |
| +		if (err) {
 | |
| +			dev_err(nor->dev,
 | |
| +				"failed to enable the Quad I/O mode\n");
 | |
| +			return err;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	/*
 | |
| +	 * Fix erase protocol if needed, read and write protocols should
 | |
| +	 * already be valid.
 | |
| +	 */
 | |
| +	nor->erase_proto = SNOR_PROTO_1_1_1;
 | |
| +
 | |
| +	dev_dbg(nor->dev,
 | |
| +		"(Fast) Read:  opcode=%02Xh, protocol=%03x, mode=%u, wait=%u\n",
 | |
| +		nor->read_opcode, nor->read_proto,
 | |
| +		read->num_mode_clocks, read->num_wait_states);
 | |
| +	dev_dbg(nor->dev,
 | |
| +		"Page Program: opcode=%02Xh, protocol=%03x\n",
 | |
| +		nor->program_opcode, nor->write_proto);
 | |
| +	dev_dbg(nor->dev,
 | |
| +		"Sector Erase: opcode=%02Xh, protocol=%03x, sector size=%zu\n",
 | |
| +		nor->erase_opcode, nor->erase_proto, (size_t)nor->mtd.erasesize);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +#define SR_SEC BIT(6)
 | |
| +
 | |
| +static char* winbond_sr1txt(char buf[512], unsigned char val) {
 | |
| +	if (val & SR_WIP) {
 | |
| +		strcat(buf, ",BUSY");
 | |
| +	}
 | |
| +	if (val & SR_WEL) {
 | |
| +		strcat(buf, ",WEL");
 | |
| +	}
 | |
| +	if (val & SR_BP0) {
 | |
| +		strcat(buf, ",BP0");
 | |
| +	}
 | |
| +	if (val & SR_BP1) {
 | |
| +		strcat(buf, ",BP1");
 | |
| +	}
 | |
| +	if (val & SR_BP2) {
 | |
| +		strcat(buf, ",BP2");
 | |
| +	}
 | |
| +	if (val & SR_TB) {
 | |
| +		strcat(buf, ",TB");
 | |
| +	}
 | |
| +	if (val & SR_SEC) {
 | |
| +		strcat(buf, ",SEC");
 | |
| +	}
 | |
| +	if (val & SR_SRWD) {
 | |
| +		strcat(buf, ",SRP0");
 | |
| +	}
 | |
| +	if (strlen(buf)) buf += 1;
 | |
| +	return buf;
 | |
| +}
 | |
| +
 | |
| +#define SR2_SRP1 BIT(0)
 | |
| +#define SR2_QE BIT(1)
 | |
| +#define SR2_R BIT(2)
 | |
| +#define SR2_LB1 BIT(3)
 | |
| +#define SR2_LB2 BIT(4)
 | |
| +#define SR2_LB3 BIT(5)
 | |
| +#define SR2_CMP BIT(6)
 | |
| +#define SR2_SUS BIT(7)
 | |
| +
 | |
| +static char* winbond_sr2txt(char buf[512], unsigned char val) {
 | |
| +	if (val & SR2_SRP1) {
 | |
| +		strcat(buf, ",SRP1");
 | |
| +	}
 | |
| +	if (val & SR2_QE) {
 | |
| +		strcat(buf, ",QE");
 | |
| +	}
 | |
| +	if (val & SR2_LB1) {
 | |
| +		strcat(buf, ",LB1");
 | |
| +	}
 | |
| +	if (val & SR2_LB2) {
 | |
| +		strcat(buf, ",LB2");
 | |
| +	}
 | |
| +	if (val & SR2_LB3) {
 | |
| +		strcat(buf, ",LB3");
 | |
| +	}
 | |
| +	if (val & SR2_CMP) {
 | |
| +		strcat(buf, ",CMP");
 | |
| +	}
 | |
| +	if (val & SR2_SUS) {
 | |
| +		strcat(buf, ",SUS");
 | |
| +	}
 | |
| +	if (strlen(buf)) buf += 1;
 | |
| +	return buf;
 | |
| +}
 | |
| +
 | |
| +#define SR3_WPS BIT(2)
 | |
| +#define SR3_DRV0 BIT(5)
 | |
| +#define SR3_DRV1 BIT(6)
 | |
| +#define SR3_HOLD BIT(7)
 | |
| +
 | |
| +static char* winbond_sr3txt(char buf[512], unsigned char val) {
 | |
| +	if (val & SR3_WPS) {
 | |
| +		strcat(buf, ",WPS");
 | |
| +	}
 | |
| +	if (val & SR3_DRV0) {
 | |
| +		strcat(buf, ",DRV0");
 | |
| +	}
 | |
| +	if (val & SR3_DRV1) {
 | |
| +		strcat(buf, ",DRV1");
 | |
| +	}
 | |
| +	if (val & SR3_HOLD) {
 | |
| +		strcat(buf, ",HOLD");
 | |
| +	}
 | |
| +	if (strlen(buf)) buf += 1;
 | |
| +	return buf;
 | |
| +}
 | |
| +
 | |
| +static int spi_nor_config(struct spi_nor *nor, const struct flash_info *info,
 | |
| +			 const struct spi_nor_basic_flash_parameter *params,
 | |
| +			 struct spi_nor_modes *modes)
 | |
|  {
 | |
| +	int ret;
 | |
| +	unsigned char cval,val;
 | |
| +
 | |
| +	if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX){
 | |
| +		val = read_sr(nor);
 | |
| +		if (val < 0)
 | |
| +			return val;
 | |
| +
 | |
| +		/* read Configuration Register for macronix's spi nor flash */
 | |
| +		ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &cval, 1);
 | |
| +		if(ret < 0){
 | |
| +			dev_err(nor->dev, "error %d reading config Reg.\n", ret);
 | |
| +			return ret;
 | |
| +		}
 | |
| +
 | |
| +		/* check the bit[6:7] whether is set in uboot when use DTR mode;if it was set and clear it. */
 | |
| +		/* pay attention to sequence of issuing WRSR instruction */
 | |
| +		if (cval & CR_DUMMY_CYCLE){
 | |
| +			write_enable(nor);
 | |
| +			nor->cmd_buf[0]=val;
 | |
| +			nor->cmd_buf[1]=(cval & (~CR_DUMMY_CYCLE));
 | |
| +			ret = nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
 | |
| +		}
 | |
| +	} else if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
 | |
| +		unsigned char sr1, sr2, sr3;
 | |
| +		char sr1txt[256] = {0}, sr2txt[256] = {0}, sr3txt[256] = {0};
 | |
| +
 | |
| +		sr1 = read_sr(nor);
 | |
| +		if (sr1 < 0)
 | |
| +			return sr1;
 | |
| +		ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
 | |
| +		if(ret < 0){
 | |
| +			dev_err(nor->dev, "error %d reading config Reg.\n", ret);
 | |
| +			return ret;
 | |
| +		}
 | |
| +		ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &sr3, 1);
 | |
| +		if(ret < 0){
 | |
| +			dev_err(nor->dev, "error %d reading config Reg.\n", ret);
 | |
| +			return ret;
 | |
| +		}
 | |
| +		dev_info(nor->dev, "Winbond: SR1 [%s], SR2 [%s], SR3 [%s]\n",
 | |
| +				winbond_sr1txt(sr1txt, sr1), winbond_sr2txt(sr2txt, sr2),
 | |
| +				winbond_sr3txt(sr3txt, sr3));
 | |
| +	}
 | |
| +
 | |
| +	if (params) {
 | |
| +		ret = spi_nor_setup(nor, info, params, modes);
 | |
| +		if (ret)
 | |
| +			return ret;
 | |
| +	} else if (modes->rd_modes & SNOR_MODE_1_1_4 &&
 | |
| +			info->flags & SPI_NOR_QUAD_READ) {
 | |
| +		/*
 | |
| +		 * This branch is spcially for some devices which can
 | |
| +		 * not be stated by params, but only SPI_NOR_QUAD_READ,
 | |
| +		 * it just supports the protocol 1_1_4.
 | |
| +		 */
 | |
| +			if (spi_nor_wait_till_ready(nor))
 | |
| +				return 1;
 | |
| +
 | |
| +			ret = set_quad_mode(nor, info);
 | |
| +			if (ret) {
 | |
| +				dev_err(nor->dev, "quad mode not supported\n");
 | |
| +				return ret;
 | |
| +			}
 | |
| +			nor->read_proto = SNOR_PROTO_1_1_4;
 | |
| +			nor->read_opcode = SPINOR_OP_READ_1_1_4;
 | |
| +			nor->read_dummy = 8;
 | |
| +	} else if (modes->rd_modes & SNOR_MODE_1_1_2 &&
 | |
| +			info->flags & SPI_NOR_DUAL_READ) {
 | |
| +		/*
 | |
| +		 * This branch is spcially for some devices which can
 | |
| +		 * not be stated by params, but only SPI_NOR_DUAL_READ,
 | |
| +		 * it just supports the protocol 1_1_2.
 | |
| +		 */
 | |
| +			nor->read_proto = SNOR_PROTO_1_1_2;
 | |
| +			nor->read_opcode = SPINOR_OP_READ_1_1_2;
 | |
| +			nor->read_dummy = 8;
 | |
| +	} else {
 | |
| +		if (modes->rd_modes & SNOR_MODE_1_1_1) {
 | |
| +			nor->read_opcode = SPINOR_OP_READ_FAST;
 | |
| +			nor->read_dummy = 8;
 | |
| +		} else {
 | |
| +			nor->read_opcode = SPINOR_OP_READ;
 | |
| +			nor->read_dummy = 0;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	if (!(modes->rd_modes & (SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4))) {
 | |
| +		ret = spi_nor_reset_pin_enable(nor, info);
 | |
| +		if (ret < 0) {
 | |
| +			dev_err(nor->dev, "Enable RESET# fail.\n");
 | |
| +			return ret;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int spi_nor_scan(struct spi_nor *nor, const char *name,
 | |
| +		 struct spi_nor_modes *modes)
 | |
| +{
 | |
| +	const struct spi_nor_basic_flash_parameter *params = NULL;
 | |
|  	const struct flash_info *info = NULL;
 | |
|  	struct device *dev = nor->dev;
 | |
|  	struct mtd_info *mtd = &nor->mtd;
 | |
| @@ -1320,11 +2673,19 @@
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| +	/* Reset SPI protocol for all commands */
 | |
| +	nor->erase_proto = SNOR_PROTO_1_1_1;
 | |
| +	nor->read_proto = SNOR_PROTO_1_1_1;
 | |
| +	nor->write_proto = SNOR_PROTO_1_1_1;
 | |
| +
 | |
|  	if (name)
 | |
|  		info = spi_nor_match_id(name);
 | |
|  	/* Try to auto-detect if chip name wasn't specified or not found */
 | |
| -	if (!info)
 | |
| +	if (!info) {
 | |
| +		dev_info(dev, "SPI Nor ID Table Version %s\n", SPI_NOR_IDS_VER);
 | |
|  		info = spi_nor_read_id(nor);
 | |
| +	}
 | |
| +
 | |
|  	if (IS_ERR_OR_NULL(info))
 | |
|  		return -ENOENT;
 | |
|  
 | |
| @@ -1351,9 +2712,15 @@
 | |
|  			info = jinfo;
 | |
|  		}
 | |
|  	}
 | |
| +	if (info->params)
 | |
| +		params = info->params;
 | |
|  
 | |
|  	mutex_init(&nor->lock);
 | |
|  
 | |
| +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT
 | |
| +	/* NOR block protection support */
 | |
| +	bsp_get_spi_lock_info(nor, info);
 | |
| +#else
 | |
|  	/*
 | |
|  	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
 | |
|  	 * with the software protection bits set
 | |
| @@ -1367,6 +2734,7 @@
 | |
|  		write_sr(nor, 0);
 | |
|  		spi_nor_wait_till_ready(nor);
 | |
|  	}
 | |
| +#endif
 | |
|  
 | |
|  	if (!mtd->name)
 | |
|  		mtd->name = dev_name(dev);
 | |
| @@ -1380,7 +2748,10 @@
 | |
|  
 | |
|  	/* NOR protection support for STmicro/Micron chips and similar */
 | |
|  	if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
 | |
| -			info->flags & SPI_NOR_HAS_LOCK) {
 | |
| +	    JEDEC_MFR(info) == SNOR_MFR_WINBOND ||
 | |
| +	    JEDEC_MFR(info) == SNOR_MFR_XTX ||
 | |
| +	    JEDEC_MFR(info) == SNOR_MFR_FM ||
 | |
| +		info->flags & SPI_NOR_HAS_LOCK) {
 | |
|  		nor->flash_lock = stm_lock;
 | |
|  		nor->flash_unlock = stm_unlock;
 | |
|  		nor->flash_is_locked = stm_is_locked;
 | |
| @@ -1428,92 +2799,61 @@
 | |
|  	if (np) {
 | |
|  		/* If we were instantiated by DT, use it */
 | |
|  		if (of_property_read_bool(np, "m25p,fast-read"))
 | |
| -			nor->flash_read = SPI_NOR_FAST;
 | |
| +			modes->rd_modes |= SNOR_MODE_1_1_1;
 | |
|  		else
 | |
| -			nor->flash_read = SPI_NOR_NORMAL;
 | |
| +			modes->rd_modes &= ~SNOR_MODE_1_1_1;
 | |
|  	} else {
 | |
|  		/* If we weren't instantiated by DT, default to fast-read */
 | |
| -		nor->flash_read = SPI_NOR_FAST;
 | |
| +		modes->rd_modes |= SNOR_MODE_1_1_1;
 | |
|  	}
 | |
|  
 | |
|  	/* Some devices cannot do fast-read, no matter what DT tells us */
 | |
|  	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) {
 | |
| -		ret = set_quad_mode(nor, info);
 | |
| -		if (ret) {
 | |
| -			dev_err(dev, "quad mode not supported\n");
 | |
| -			return ret;
 | |
| -		}
 | |
| -		nor->flash_read = SPI_NOR_QUAD;
 | |
| -	} else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) {
 | |
| -		nor->flash_read = SPI_NOR_DUAL;
 | |
| -	}
 | |
| -
 | |
| -	/* 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;
 | |
| -	}
 | |
| +		modes->rd_modes &= ~SNOR_MODE_1_1_1;
 | |
|  
 | |
|  	nor->program_opcode = SPINOR_OP_PP;
 | |
|  
 | |
| +	/*
 | |
| +	 * Configure the SPI memory:
 | |
| +	 * - select op codes for (Fast) Read, Page Program and Sector Erase.
 | |
| +	 * - set the number of dummy cycles (mode cycles + wait states).
 | |
| +	 * - set the SPI protocols for register and memory accesses.
 | |
| +	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
 | |
| +	 */
 | |
| +	ret = spi_nor_config(nor, info, params, modes);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
|  	if (info->addr_width)
 | |
|  		nor->addr_width = info->addr_width;
 | |
|  	else if (mtd->size > 0x1000000) {
 | |
|  		/* enable 4-byte addressing if the device exceeds 16MiB */
 | |
|  		nor->addr_width = 4;
 | |
| -		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
 | |
| -			/* Dedicated 4-byte command set */
 | |
| -			switch (nor->flash_read) {
 | |
| -			case SPI_NOR_QUAD:
 | |
| -				nor->read_opcode = SPINOR_OP_READ4_1_1_4;
 | |
| -				break;
 | |
| -			case SPI_NOR_DUAL:
 | |
| -				nor->read_opcode = SPINOR_OP_READ4_1_1_2;
 | |
| -				break;
 | |
| -			case SPI_NOR_FAST:
 | |
| -				nor->read_opcode = SPINOR_OP_READ4_FAST;
 | |
| -				break;
 | |
| -			case SPI_NOR_NORMAL:
 | |
| -				nor->read_opcode = SPINOR_OP_READ4;
 | |
| -				break;
 | |
| -			}
 | |
| -			nor->program_opcode = SPINOR_OP_PP_4B;
 | |
| -			/* No small sector erase for 4-byte command set */
 | |
| -			nor->erase_opcode = SPINOR_OP_SE_4B;
 | |
| -			mtd->erasesize = info->sector_size;
 | |
| -		} else
 | |
| +		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
 | |
| +		    info->flags & SPI_NOR_4B_OPCODES)
 | |
| +			spi_nor_set_4byte_opcodes(nor, info);
 | |
| +		else
 | |
|  			set_4byte(nor, info, 1);
 | |
|  	} else {
 | |
|  		nor->addr_width = 3;
 | |
|  	}
 | |
|  
 | |
| +	/* choose the suitable clockrate */
 | |
| +	if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) /* device supports dual or quad */
 | |
| +		&& (modes->rd_modes & (~SNOR_MODE_SLOW)) /* controller supports fast mode */
 | |
| +		&& info->clkrate)
 | |
| +		nor->clkrate = info->clkrate;
 | |
| +	else
 | |
| +		nor->clkrate = 24000000;
 | |
| +
 | |
|  	if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
 | |
|  		dev_err(dev, "address width is too large: %u\n",
 | |
|  			nor->addr_width);
 | |
|  		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);
 | |
| +	dev_info(dev, "%s (Chipsize %lld Mbytes, Blocksize %uKiB)\n",
 | |
| +		info->name, (long long)mtd->size >> 20, mtd->erasesize / 1024);
 | |
|  
 | |
|  	dev_dbg(dev,
 | |
|  		"mtd .name = %s, .size = 0x%llx (%lldMiB), "
 | |
| @@ -1547,6 +2887,64 @@
 | |
|  	return NULL;
 | |
|  }
 | |
|  
 | |
| +/******************************************************************************/
 | |
| +void spi_nor_driver_shutdown(struct spi_nor *nor)
 | |
| +{
 | |
| +	/* disable 4-byte addressing if the device exceeds 16MiB */
 | |
| +	if (nor->addr_width == 4) {
 | |
| +		const struct flash_info *info = NULL;
 | |
| +
 | |
| +		info = spi_nor_read_id(nor);
 | |
| +		set_4byte(nor, info, 0);
 | |
| +	}
 | |
| +	return;
 | |
| +}
 | |
| +
 | |
| +#ifdef CONFIG_PM
 | |
| +/******************************************************************************/
 | |
| +int spi_nor_suspend(struct spi_nor *nor, pm_message_t state)
 | |
| +{
 | |
| +	return spi_nor_wait_till_ready(nor);
 | |
| +}
 | |
| +
 | |
| +/******************************************************************************/
 | |
| +int spi_nor_resume(struct spi_nor *nor)
 | |
| +{
 | |
| +	int ret;
 | |
| +	const struct flash_info *info = NULL;
 | |
| +	const struct spi_nor_basic_flash_parameter *params = NULL;
 | |
| +	struct spi_nor_modes modes = {
 | |
| +		.rd_modes = SNOR_MODE_SLOW,
 | |
| +		.wr_modes = SNOR_MODE_1_1_1,
 | |
| +	};
 | |
| +
 | |
| +	modes.rd_modes |= SNOR_MODE_1_1_1
 | |
| +			| SNOR_MODE_1_1_2
 | |
| +			| SNOR_MODE_1_2_2;
 | |
| +#ifndef CONFIG_CLOSE_SPI_8PIN_4IO
 | |
| +	modes.rd_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4;
 | |
| +	modes.wr_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4;
 | |
| +#endif
 | |
| +
 | |
| +	if (!info)
 | |
| +		info = spi_nor_read_id(nor);
 | |
| +
 | |
| +	/* Quad mode takes precedence over fast/normal */
 | |
| +	if (info->params)
 | |
| +		params = info->params;
 | |
| +
 | |
| +	ret = spi_nor_config(nor, info, params, &modes);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	/* enable 4-byte addressing if the device exceeds 16MiB */
 | |
| +	if (nor->addr_width == 4 && JEDEC_MFR(info) != SNOR_MFR_SPANSION)
 | |
| +		set_4byte(nor, info, 1);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +#endif /* End of CONFIG_PM */
 | |
| +
 | |
|  MODULE_LICENSE("GPL");
 | |
|  MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>");
 | |
|  MODULE_AUTHOR("Mike Lavender");
 |