Message ID | 1380024647-18955-1-git-send-email-sourav.poddar@ti.com |
---|---|
State | New, archived |
Headers | show |
于 2013年09月24日 20:10, Sourav Poddar 写道: > Some flash like spansion flash also support quad read mode. > This patch add support for enabling quad mode in m25p80. > > Patch enables quad mode bit on the flash device, add an api > for quad read defines a communuication > parameter(t[1].rx_nbits = SPI_NBITS_QUAD) to let know the > spi controller that quad read should be used. > > Tested on DRA7 board with S25fl256s spansion device by doing a > flash erase, write and read. > > Signed-off-by: Sourav Poddar<sourav.poddar@ti.com> > --- > drivers/mtd/devices/m25p80.c | 102 +++++++++++++++++++++++++++++++++++++----- > 1 files changed, 91 insertions(+), 11 deletions(-) > > diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c > index 26b14f9..2b6ee4b 100644 > --- a/drivers/mtd/devices/m25p80.c > +++ b/drivers/mtd/devices/m25p80.c > @@ -41,6 +41,7 @@ > #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ > #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 /* QUAD READ */ > #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ > #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ > #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ > @@ -52,6 +53,7 @@ > /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ > #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ > #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ > +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ > #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ > #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ > > @@ -95,6 +97,7 @@ struct m25p { > u8 program_opcode; > u8 *command; > bool fast_read; > + bool quad_read; > }; > > static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) > @@ -336,6 +339,75 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) > return 0; > } > > +static int quad_enable(struct m25p *flash) > +{ > + u8 cmd[3]; > + cmd[0] = OPCODE_WRSR; > + cmd[1] = 0x00; > + cmd[2] = 0x02; > + > + write_enable(flash); > + > + spi_write(flash->spi,&cmd, 3); > + > + if (wait_till_ready(flash)) > + return 1; > + > + return 0; > +} > + why not add a more common function, such as write_sr_cr()? see the my patch :http://lists.infradead.org/pipermail/linux-mtd/2013-August/048438.html > +static int m25p80_quad_read(struct mtd_info *mtd, loff_t from, size_t len, I think we can reuse the m25p80_read(), and there is no need to add a new function. > + size_t *retlen, u_char *buf) > +{ > + struct m25p *flash = mtd_to_m25p(mtd); > + struct spi_transfer t[2]; > + struct spi_message m; > + uint8_t opcode; > + > + pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), > + __func__, (u32)from, len); > + > + spi_message_init(&m); > + memset(t, 0, (sizeof(t))); > + > + t[0].tx_buf = flash->command; > + t[0].len = m25p_cmdsz(flash) + (flash->quad_read ? 1 : 0); > + spi_message_add_tail(&t[0],&m); > + > + t[1].rx_buf = buf; > + t[1].len = len; > + t[1].rx_nbits = SPI_NBITS_QUAD; > + spi_message_add_tail(&t[1],&m); > + > + mutex_lock(&flash->lock); > + > + /* Wait till previous write/erase is done. */ > + if (wait_till_ready(flash)) { > + /* REVISIT status return?? */ > + mutex_unlock(&flash->lock); > + return 1; > + } > + > + /* FIXME switch to OPCODE_QUAD_READ. It's required for higher > + * clocks; and at this writing, every chip this driver handles > + * supports that opcode. > + */ > + > + /* Set up the write data buffer. */ > + opcode = flash->read_opcode; > + flash->command[0] = opcode; > + m25p_addr2cmd(flash, from, flash->command); > + > + spi_sync(flash->spi,&m); > + > + *retlen = m.actual_length - m25p_cmdsz(flash) - > + (flash->quad_read ? 1 : 0); > + > + mutex_unlock(&flash->lock); > + > + return 0; > +} > + > /* > * Read an address range from the flash chip. The address range > * may be any size provided it is within the physical boundaries. > @@ -979,15 +1051,9 @@ static int m25p_probe(struct spi_device *spi) > } > } > > - flash = kzalloc(sizeof *flash, GFP_KERNEL); > + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); > if (!flash) > return -ENOMEM; > - flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0), > - GFP_KERNEL); > - if (!flash->command) { > - kfree(flash); > - return -ENOMEM; > - } > > flash->spi = spi; > mutex_init(&flash->lock); > @@ -1015,7 +1081,14 @@ static int m25p_probe(struct spi_device *spi) > flash->mtd.flags = MTD_CAP_NORFLASH; > flash->mtd.size = info->sector_size * info->n_sectors; > flash->mtd._erase = m25p80_erase; > - flash->mtd._read = m25p80_read; > + > + flash->quad_read = false; > + if (spi->mode&& SPI_RX_QUAD) { > + quad_enable(flash); what about the quad_enable() failed, you should read back the Quad bit and check it. thanks Huang Shijie
On Wednesday 25 September 2013 08:36 AM, Huang Shijie wrote: > 于 2013年09月24日 20:10, Sourav Poddar 写道: >> Some flash like spansion flash also support quad read mode. >> This patch add support for enabling quad mode in m25p80. >> >> Patch enables quad mode bit on the flash device, add an api >> for quad read defines a communuication >> parameter(t[1].rx_nbits = SPI_NBITS_QUAD) to let know the >> spi controller that quad read should be used. >> >> Tested on DRA7 board with S25fl256s spansion device by doing a >> flash erase, write and read. >> >> Signed-off-by: Sourav Poddar<sourav.poddar@ti.com> >> --- >> drivers/mtd/devices/m25p80.c | 102 >> +++++++++++++++++++++++++++++++++++++----- >> 1 files changed, 91 insertions(+), 11 deletions(-) >> >> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c >> index 26b14f9..2b6ee4b 100644 >> --- a/drivers/mtd/devices/m25p80.c >> +++ b/drivers/mtd/devices/m25p80.c >> @@ -41,6 +41,7 @@ >> #define OPCODE_WRSR 0x01 /* Write status register 1 >> byte */ >> #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 /* QUAD READ */ >> #define OPCODE_PP 0x02 /* Page program (up to 256 >> bytes) */ >> #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ >> #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC >> chips */ >> @@ -52,6 +53,7 @@ >> /* 4-byte address opcodes - used on Spansion and some Macronix >> flashes. */ >> #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low >> frequency) */ >> #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high >> frequency) */ >> +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ >> #define OPCODE_PP_4B 0x12 /* Page program (up to 256 >> bytes) */ >> #define OPCODE_SE_4B 0xdc /* Sector erase (usually >> 64KiB) */ >> >> @@ -95,6 +97,7 @@ struct m25p { >> u8 program_opcode; >> u8 *command; >> bool fast_read; >> + bool quad_read; >> }; >> >> static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) >> @@ -336,6 +339,75 @@ static int m25p80_erase(struct mtd_info *mtd, >> struct erase_info *instr) >> return 0; >> } >> >> +static int quad_enable(struct m25p *flash) >> +{ >> + u8 cmd[3]; >> + cmd[0] = OPCODE_WRSR; >> + cmd[1] = 0x00; >> + cmd[2] = 0x02; >> + >> + write_enable(flash); >> + >> + spi_write(flash->spi,&cmd, 3); >> + >> + if (wait_till_ready(flash)) >> + return 1; >> + >> + return 0; >> +} >> + > why not add a more common function, such as write_sr_cr()? sounds neat, will add in my next version. > > see the my patch > :http://lists.infradead.org/pipermail/linux-mtd/2013-August/048438.html >> +static int m25p80_quad_read(struct mtd_info *mtd, loff_t from, >> size_t len, > > I think we can reuse the m25p80_read(), and there is no need to add a > new function. I thought so initially, but if we see the list of quad read commands for a typical flash like spansion, there are other quad commands with different dummy cycles requirement. Later, they might also get added to this quad list. Handling them in a single read api might be a bit clumsy, so i thought of keeping the fast and normal read in a single api, while creating a new one for quad. >> + size_t *retlen, u_char *buf) >> +{ >> + struct m25p *flash = mtd_to_m25p(mtd); >> + struct spi_transfer t[2]; >> + struct spi_message m; >> + uint8_t opcode; >> + >> + pr_debug("%s: %s from 0x%08x, len %zd\n", >> dev_name(&flash->spi->dev), >> + __func__, (u32)from, len); >> + >> + spi_message_init(&m); >> + memset(t, 0, (sizeof(t))); >> + >> + t[0].tx_buf = flash->command; >> + t[0].len = m25p_cmdsz(flash) + (flash->quad_read ? 1 : 0); >> + spi_message_add_tail(&t[0],&m); >> + >> + t[1].rx_buf = buf; >> + t[1].len = len; >> + t[1].rx_nbits = SPI_NBITS_QUAD; >> + spi_message_add_tail(&t[1],&m); >> + >> + mutex_lock(&flash->lock); >> + >> + /* Wait till previous write/erase is done. */ >> + if (wait_till_ready(flash)) { >> + /* REVISIT status return?? */ >> + mutex_unlock(&flash->lock); >> + return 1; >> + } >> + >> + /* FIXME switch to OPCODE_QUAD_READ. It's required for higher >> + * clocks; and at this writing, every chip this driver handles >> + * supports that opcode. >> + */ >> + >> + /* Set up the write data buffer. */ >> + opcode = flash->read_opcode; >> + flash->command[0] = opcode; >> + m25p_addr2cmd(flash, from, flash->command); >> + >> + spi_sync(flash->spi,&m); >> + >> + *retlen = m.actual_length - m25p_cmdsz(flash) - >> + (flash->quad_read ? 1 : 0); >> + >> + mutex_unlock(&flash->lock); >> + >> + return 0; >> +} >> + >> /* >> * Read an address range from the flash chip. The address range >> * may be any size provided it is within the physical boundaries. >> @@ -979,15 +1051,9 @@ static int m25p_probe(struct spi_device *spi) >> } >> } >> >> - flash = kzalloc(sizeof *flash, GFP_KERNEL); >> + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); >> if (!flash) >> return -ENOMEM; >> - flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0), >> - GFP_KERNEL); >> - if (!flash->command) { >> - kfree(flash); >> - return -ENOMEM; >> - } >> >> flash->spi = spi; >> mutex_init(&flash->lock); >> @@ -1015,7 +1081,14 @@ static int m25p_probe(struct spi_device *spi) >> flash->mtd.flags = MTD_CAP_NORFLASH; >> flash->mtd.size = info->sector_size * info->n_sectors; >> flash->mtd._erase = m25p80_erase; >> - flash->mtd._read = m25p80_read; >> + >> + flash->quad_read = false; >> + if (spi->mode&& SPI_RX_QUAD) { >> + quad_enable(flash); > what about the quad_enable() failed, you should read back the Quad bit > and check it. > hmm..yes, I will add it. > thanks > Huang Shijie >
于 2013年09月24日 20:10, Sourav Poddar 写道: > + flash->quad_read = false; > + if (spi->mode&& SPI_RX_QUAD) { > + quad_enable(flash); > + flash->mtd._read = m25p80_quad_read; > + flash->quad_read = true; > + } else > + flash->mtd._read = m25p80_read; How do you know the NOR support the QUAD read? by the spi->mode? i think you'd better add a DT node such as "m25p, quad-read". thanks Huang Shijie
On Wednesday 25 September 2013 11:18 AM, Huang Shijie wrote: > 于 2013年09月24日 20:10, Sourav Poddar 写道: >> + flash->quad_read = false; >> + if (spi->mode&& SPI_RX_QUAD) { >> + quad_enable(flash); >> + flash->mtd._read = m25p80_quad_read; >> + flash->quad_read = true; >> + } else >> + flash->mtd._read = m25p80_read; > How do you know the NOR support the QUAD read? by the spi->mode? > > i think you'd better add a DT node such as "m25p, quad-read". no need to add a new property, support is already there. If you see spi.c, "spi-rx-bus-width" property is already added. We will set this property in dts to 4 in case of quad read. Once this is set, spi->mode will be set to SPI_RX_QUAD in spi.c. which can be used by mtd layer to device whether flash supports quad read or not. > > thanks > Huang Shijie >
On Wednesday 25 September 2013 11:21 AM, Sourav Poddar wrote: > On Wednesday 25 September 2013 11:18 AM, Huang Shijie wrote: >> 于 2013年09月24日 20:10, Sourav Poddar 写道: >>> + flash->quad_read = false; >>> + if (spi->mode&& SPI_RX_QUAD) { >>> + quad_enable(flash); >>> + flash->mtd._read = m25p80_quad_read; >>> + flash->quad_read = true; >>> + } else >>> + flash->mtd._read = m25p80_read; >> How do you know the NOR support the QUAD read? by the spi->mode? >> >> i think you'd better add a DT node such as "m25p, quad-read". > no need to add a new property, support is already there. > > If you see spi.c, "spi-rx-bus-width" property is already added. We > will set this > property in dts to 4 in case of quad read. Once this is set, spi->mode > will > be set to SPI_RX_QUAD in spi.c. which can be used by mtd layer to > device whether Sorry for the typo.. ^^^^ decide > flash supports quad read or not. >> >> thanks >> Huang Shijie >> > > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/
于 2013年09月25日 13:51, Sourav Poddar 写道: > be set to SPI_RX_QUAD in spi.c. which can be used by mtd layer to > device whether > flash supports quad read or not. yes. it's ok. thanks Huang Shijie
于 2013年09月24日 20:10, Sourav Poddar 写道: > +static int quad_enable(struct m25p *flash) > +{ > + u8 cmd[3]; > + cmd[0] = OPCODE_WRSR; > + cmd[1] = 0x00; > + cmd[2] = 0x02; > + Please use a macro here, do not use a hardcode. thanks Huang Shijie
On Wednesday 25 September 2013 11:46 AM, Huang Shijie wrote: > 于 2013年09月24日 20:10, Sourav Poddar 写道: >> +static int quad_enable(struct m25p *flash) >> +{ >> + u8 cmd[3]; >> + cmd[0] = OPCODE_WRSR; >> + cmd[1] = 0x00; >> + cmd[2] = 0x02; >> + > Please use a macro here, do not use a hardcode. OK. > > thanks > Huang Shijie >
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 26b14f9..2b6ee4b 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -41,6 +41,7 @@ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #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 /* QUAD READ */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ @@ -52,6 +53,7 @@ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ @@ -95,6 +97,7 @@ struct m25p { u8 program_opcode; u8 *command; bool fast_read; + bool quad_read; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @@ -336,6 +339,75 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) return 0; } +static int quad_enable(struct m25p *flash) +{ + u8 cmd[3]; + cmd[0] = OPCODE_WRSR; + cmd[1] = 0x00; + cmd[2] = 0x02; + + write_enable(flash); + + spi_write(flash->spi, &cmd, 3); + + if (wait_till_ready(flash)) + return 1; + + return 0; +} + +static int m25p80_quad_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct m25p *flash = mtd_to_m25p(mtd); + struct spi_transfer t[2]; + struct spi_message m; + uint8_t opcode; + + pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)from, len); + + spi_message_init(&m); + memset(t, 0, (sizeof(t))); + + t[0].tx_buf = flash->command; + t[0].len = m25p_cmdsz(flash) + (flash->quad_read ? 1 : 0); + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = len; + t[1].rx_nbits = SPI_NBITS_QUAD; + spi_message_add_tail(&t[1], &m); + + mutex_lock(&flash->lock); + + /* Wait till previous write/erase is done. */ + if (wait_till_ready(flash)) { + /* REVISIT status return?? */ + mutex_unlock(&flash->lock); + return 1; + } + + /* FIXME switch to OPCODE_QUAD_READ. It's required for higher + * clocks; and at this writing, every chip this driver handles + * supports that opcode. + */ + + /* Set up the write data buffer. */ + opcode = flash->read_opcode; + flash->command[0] = opcode; + m25p_addr2cmd(flash, from, flash->command); + + spi_sync(flash->spi, &m); + + *retlen = m.actual_length - m25p_cmdsz(flash) - + (flash->quad_read ? 1 : 0); + + mutex_unlock(&flash->lock); + + return 0; +} + /* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. @@ -979,15 +1051,9 @@ static int m25p_probe(struct spi_device *spi) } } - flash = kzalloc(sizeof *flash, GFP_KERNEL); + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); if (!flash) return -ENOMEM; - flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0), - GFP_KERNEL); - if (!flash->command) { - kfree(flash); - return -ENOMEM; - } flash->spi = spi; mutex_init(&flash->lock); @@ -1015,7 +1081,14 @@ static int m25p_probe(struct spi_device *spi) flash->mtd.flags = MTD_CAP_NORFLASH; flash->mtd.size = info->sector_size * info->n_sectors; flash->mtd._erase = m25p80_erase; - flash->mtd._read = m25p80_read; + + flash->quad_read = false; + if (spi->mode && SPI_RX_QUAD) { + quad_enable(flash); + flash->mtd._read = m25p80_quad_read; + flash->quad_read = true; + } else + flash->mtd._read = m25p80_read; /* flash protection support for STmicro chips */ if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) { @@ -1067,6 +1140,13 @@ static int m25p_probe(struct spi_device *spi) flash->program_opcode = OPCODE_PP; + flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : + (flash->quad_read ? 1 : 0)), GFP_KERNEL); + if (!flash->command) { + kfree(flash); + return -ENOMEM; + } + if (info->addr_width) flash->addr_width = info->addr_width; else if (flash->mtd.size > 0x1000000) { @@ -1074,9 +1154,9 @@ static int m25p_probe(struct spi_device *spi) flash->addr_width = 4; if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Dedicated 4-byte command set */ - flash->read_opcode = flash->fast_read ? - OPCODE_FAST_READ_4B : - OPCODE_NORM_READ_4B; + flash->read_opcode = (flash->fast_read ? + OPCODE_FAST_READ_4B : (flash->quad_read ? + OPCODE_QUAD_READ_4B : OPCODE_NORM_READ_4B)); flash->program_opcode = OPCODE_PP_4B; /* No small sector erase for 4-byte command set */ flash->erase_opcode = OPCODE_SE_4B;
Some flash like spansion flash also support quad read mode. This patch add support for enabling quad mode in m25p80. Patch enables quad mode bit on the flash device, add an api for quad read defines a communuication parameter(t[1].rx_nbits = SPI_NBITS_QUAD) to let know the spi controller that quad read should be used. Tested on DRA7 board with S25fl256s spansion device by doing a flash erase, write and read. Signed-off-by: Sourav Poddar <sourav.poddar@ti.com> --- drivers/mtd/devices/m25p80.c | 102 +++++++++++++++++++++++++++++++++++++----- 1 files changed, 91 insertions(+), 11 deletions(-)