Message ID | 1396973570-13995-2-git-send-email-grmoore@altera.com |
---|---|
State | Superseded |
Headers | show |
On Tuesday, April 08, 2014 9:13 AM, Graham Moore <grmoore@altera.com> > > From: Graham Moore <grmoore@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@gainspeed.com> > Signed-off-by: Graham Moore <grmoore@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
On Tuesday, April 08, 2014 at 06:12:50 PM, grmoore@altera.com wrote: > From: Graham Moore <grmoore@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. [...] > +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); Is the type-cast really needed here? Why ? > + 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) Please avoid using function names that start with underscore . [...] Thanks! Best regards, Marek Vasut
On Wednesday, April 09, 2014 7:07 PM, Marek Vasut wrote: > On Tuesday, April 08, 2014 at 06:12:50 PM, grmoore@altera.com wrote: > > From: Graham Moore <grmoore@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. > > [...] > > > +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); > > Is the type-cast really needed here? Why ? The type-cast looks clumsy. The type of 'retval' is retval; thus, '%zd' can be used, instead of '%d', as below. + dev_err(&flash->spi->dev, "error %zd reading FSR\n", + 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) > > Please avoid using function names that start with underscore . +1 I agree with Marek Vasut's opinion. If there is no reason, please don't use it. Best regards, Jingoo Han > [...] > > Thanks! > > Best regards, > Marek Vasut
On Wednesday, April 09, 2014 7:16 PM, Jingoo Han wrote: > On Wednesday, April 09, 2014 7:07 PM, Marek Vasut wrote: > > On Tuesday, April 08, 2014 at 06:12:50 PM, grmoore@altera.com wrote: > > > From: Graham Moore <grmoore@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. > > > > [...] > > > > > +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); > > > > Is the type-cast really needed here? Why ? > > The type-cast looks clumsy. > The type of 'retval' is retval; thus, '%zd' can be used, Sorry, there is a typo! s/retval/ssize_t The type of 'retval' is "ssize_t"; thus, '%zd' can be used, instead of '%d', as below. + dev_err(&flash->spi->dev, "error %zd reading FSR\n", + retval); Best regards, Jingoo Han
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;