[PATCH] Add support for flag status register on Micron chips.

Insop Song Insop.Song at gainspeed.com
Tue Apr 8 09:52:19 PDT 2014


On Tuesday, April 08, 2014 9:13 AM, Graham Moore <grmoore at altera.com>
> 
> From: Graham Moore <grmoore at altera.com>
> 
> Some new Micron flash chips require reading the flag status register to
> determine when operations have completed.
> 
> Furthermore, chips with multi-die stacks of the 65nm 256Mb QSPI also
> require reading the status register before reading the flag status register.
> 
> This patch adds support for the flag status register in the n25q512a1 and
> n25q00 Micron QSPI flash chips.
> 

Reviewed his change, and it is more generic then my previous patch.

Reviewed-by: Insop Song <insop.song at gainspeed.com>

> Signed-off-by: Graham Moore <grmoore at altera.com>
> ---
>  drivers/mtd/devices/m25p80.c |   94
> +++++++++++++++++++++++++++++++++++-------
>  1 file changed, 80 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index ad19139..38306aa 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -39,6 +39,7 @@
>  #define	OPCODE_WREN		0x06	/* Write enable */
>  #define	OPCODE_RDSR		0x05	/* Read status register */
>  #define	OPCODE_WRSR		0x01	/* Write status
> register 1 byte */
> +#define	OPCODE_RDFSR		0x70  /* read flag status
> register */
>  #define	OPCODE_NORM_READ	0x03	/* Read data bytes (low
> frequency) */
>  #define	OPCODE_FAST_READ	0x0b	/* Read data bytes (high
> frequency) */
>  #define	OPCODE_QUAD_READ        0x6b    /* Read data bytes */
> @@ -81,6 +82,9 @@
> 
>  #define SR_QUAD_EN_MX           0x40    /* Macronix Quad I/O */
> 
> +/* Flag Status Register bits */
> +#define FSR_READY               0x80    /* FSR ready */
> +
>  /* Configuration Register bits. */
>  #define CR_QUAD_EN_SPAN		0x2     /* Spansion Quad I/O */
> 
> @@ -108,6 +112,7 @@ struct m25p {
>  	u8			read_opcode;
>  	u8			program_opcode;
>  	u8			*command;
> +	int (*wait_till_ready)(struct m25p *flash);
>  	enum read_type		flash_read;
>  };
> 
> @@ -145,6 +150,27 @@ static int read_sr(struct m25p *flash)  }
> 
>  /*
> + * Read the flag status register, returning its value in the location
> + * Return the status register value.
> + * Returns negative if error occurred.
> + */
> +static int read_fsr(struct m25p *flash) {
> +	ssize_t retval;
> +	u8 code = OPCODE_RDFSR;
> +	u8 val;
> +
> +	retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
> +
> +	if (retval < 0) {
> +		dev_err(&flash->spi->dev, "error %d reading FSR\n",
> +				(int) retval);
> +		return retval;
> +	}
> +
> +	return val;
> +}
> +/*
>   * Read configuration register, returning its value in the
>   * location. Return the configuration register value.
>   * Returns negative if error occured.
> @@ -233,7 +259,7 @@ static inline int set_4byte(struct m25p *flash, u32
> jedec_id, int enable)
>   * Service routine to read status register until ready, or timeout occurs.
>   * Returns non-zero if error.
>   */
> -static int wait_till_ready(struct m25p *flash)
> +static int _wait_till_ready(struct m25p *flash)
>  {
>  	unsigned long deadline;
>  	int sr;
> @@ -254,6 +280,37 @@ static int wait_till_ready(struct m25p *flash)  }
> 
>  /*
> + * Service routine to read flag status register until ready, or timeout occurs.
> + * Returns non-zero if error.
> + */
> +static int _wait_till_fsr_ready(struct m25p *flash) {
> +	unsigned long deadline;
> +	int fsr;
> +	int sr;
> +
> +	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
> +
> +	do {
> +		sr = read_sr(flash);
> +		if (sr < 0)
> +			break;
> +		/* only check fsr if sr not busy */
> +		if (!(sr & SR_WIP)) {
> +			fsr = read_fsr(flash);
> +			if (fsr < 0)
> +				break;
> +			if (fsr & FSR_READY)
> +				return 0;
> +		}
> +
> +		cond_resched();
> +
> +	} while (!time_after_eq(jiffies, deadline));
> +
> +	return 1;
> +}
> +/*
>   * Write status Register and configuration register with 2 bytes
>   * The first byte will be written to the status register, while the
>   * second byte will be written to the configuration register.
> @@ -280,7 +337,7 @@ static int macronix_quad_enable(struct m25p *flash)
> 
>  	spi_write(flash->spi, &cmd, 2);
> 
> -	if (wait_till_ready(flash))
> +	if (flash->wait_till_ready(flash))
>  		return 1;
> 
>  	ret = read_sr(flash);
> @@ -351,7 +408,7 @@ static int erase_chip(struct m25p *flash)
>  			(long long)(flash->mtd.size >> 10));
> 
>  	/* Wait until finished previous write command. */
> -	if (wait_till_ready(flash))
> +	if (flash->wait_till_ready(flash))
>  		return 1;
> 
>  	/* Send write enable, then erase commands. */ @@ -391,7 +448,7
> @@ static int erase_sector(struct m25p *flash, u32 offset)
>  			__func__, flash->mtd.erasesize / 1024, offset);
> 
>  	/* Wait until finished previous write command. */
> -	if (wait_till_ready(flash))
> +	if (flash->wait_till_ready(flash))
>  		return 1;
> 
>  	/* Send write enable, then erase commands. */ @@ -536,7 +593,7
> @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
>  	mutex_lock(&flash->lock);
> 
>  	/* Wait till previous write/erase is done. */
> -	if (wait_till_ready(flash)) {
> +	if (flash->wait_till_ready(flash)) {
>  		/* REVISIT status return?? */
>  		mutex_unlock(&flash->lock);
>  		return 1;
> @@ -585,7 +642,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t
> to, size_t len,
>  	mutex_lock(&flash->lock);
> 
>  	/* Wait until finished previous write command. */
> -	if (wait_till_ready(flash)) {
> +	if (flash->wait_till_ready(flash)) {
>  		mutex_unlock(&flash->lock);
>  		return 1;
>  	}
> @@ -628,7 +685,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t
> to, size_t len,
>  			t[1].tx_buf = buf + i;
>  			t[1].len = page_size;
> 
> -			wait_till_ready(flash);
> +			flash->wait_till_ready(flash);
> 
>  			write_enable(flash);
> 
> @@ -668,7 +725,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to,
> size_t len,
>  	mutex_lock(&flash->lock);
> 
>  	/* Wait until finished previous write command. */
> -	ret = wait_till_ready(flash);
> +	ret = flash->wait_till_ready(flash);
>  	if (ret)
>  		goto time_out;
> 
> @@ -683,7 +740,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to,
> size_t len,
>  		/* write one byte. */
>  		t[1].len = 1;
>  		spi_sync(flash->spi, &m);
> -		ret = wait_till_ready(flash);
> +		ret = flash->wait_till_ready(flash);
>  		if (ret)
>  			goto time_out;
>  		*retlen += m.actual_length - m25p_cmdsz(flash); @@ -702,7
> +759,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
>  		t[1].tx_buf = buf + actual;
> 
>  		spi_sync(flash->spi, &m);
> -		ret = wait_till_ready(flash);
> +		ret = flash->wait_till_ready(flash);
>  		if (ret)
>  			goto time_out;
>  		*retlen += m.actual_length - cmd_sz;
> @@ -710,7 +767,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to,
> size_t len,
>  		to += 2;
>  	}
>  	write_disable(flash);
> -	ret = wait_till_ready(flash);
> +	ret = flash->wait_till_ready(flash);
>  	if (ret)
>  		goto time_out;
> 
> @@ -724,7 +781,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to,
> size_t len,
>  		t[1].tx_buf = buf + actual;
> 
>  		spi_sync(flash->spi, &m);
> -		ret = wait_till_ready(flash);
> +		ret = flash->wait_till_ready(flash);
>  		if (ret)
>  			goto time_out;
>  		*retlen += m.actual_length - m25p_cmdsz(flash); @@ -745,7
> +802,7 @@ static int m25p80_lock(struct mtd_info *mtd, loff_t ofs, uint64_t
> len)
> 
>  	mutex_lock(&flash->lock);
>  	/* Wait until finished previous command */
> -	if (wait_till_ready(flash)) {
> +	if (flash->wait_till_ready(flash)) {
>  		res = 1;
>  		goto err;
>  	}
> @@ -790,7 +847,7 @@ static int m25p80_unlock(struct mtd_info *mtd, loff_t
> ofs, uint64_t len)
> 
>  	mutex_lock(&flash->lock);
>  	/* Wait until finished previous command */
> -	if (wait_till_ready(flash)) {
> +	if (flash->wait_till_ready(flash)) {
>  		res = 1;
>  		goto err;
>  	}
> @@ -856,6 +913,7 @@ struct flash_info {
>  #define	M25P_NO_FR	0x08		/* Can't do fastread */
>  #define	SECT_4K_PMC	0x10		/* OPCODE_BE_4K_PMC
> works uniformly */
>  #define	M25P80_QUAD_READ	0x20    /* Flash supports Quad Read
> */
> +#define	USE_FSR		0x40		/* use flag status
> register */
>  };
> 
>  #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
> @@ -941,6 +999,8 @@ static const struct spi_device_id m25p_ids[] = {
>  	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 0) },
>  	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K) },
>  	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
> +	{ "n25q512a1",   INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) },
> +	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) },
> 
>  	/* PMC */
>  	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
> @@ -1206,6 +1266,12 @@ static int m25p_probe(struct spi_device *spi)
>  	if (info->flags & M25P_NO_ERASE)
>  		flash->mtd.flags |= MTD_NO_ERASE;
> 
> +	if (info->flags & USE_FSR)
> +		flash->wait_till_ready = &_wait_till_fsr_ready;
> +	else
> +		flash->wait_till_ready = &_wait_till_ready;
> +
> +
>  	ppdata.of_node = spi->dev.of_node;
>  	flash->mtd.dev.parent = &spi->dev;
>  	flash->page_size = info->page_size;
> --
> 1.7.10.4




More information about the linux-mtd mailing list