Dear All,
I applied the patch I mentioned in the upper statement.
- Check flag status register for Micron n25q512a
. http://lists.infradead.org/pipermail/linux-mtd/2014-January/051382.html?
For the patched files, I'll mention the end of this statement.
But I couldn't find Sector Erase code for SECT_4K,
drivers/mtd/spi-nor/spi-nor.c
const struct spi_device_id spi_nor_ids[] = {
...
{ "n25q512a", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K) },
...
};
So I modified the Sector Erase Size, from 4KB to 64KB. (SECT_4K -> SPI_NOR_QUAD_READ)
But the Flash seems not to be erased.
Could you tell me how to erase flash by using 4KB sector unit?
Best Regards,
Eric.
==================== Patch Files
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 7eda71d..e53e522 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
#01 : add Read.Flag.Status.Register opcode, 0x70
- include/linux/mtd/spi-nor.h
@@ -38,6 +38,7 @@
/* Flash opcodes. */
#define OPCODE_WREN 0x06 /* Write enable */
#define OPCODE_RDSR 0x05 /* Read status register */
+#define OPCODE_RDFSR 0x70 /* Read flag status register */
#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) */
#02 : FSR Register Bit.Field, as Ready : bit.7
- include/linux/mtd/spi-nor.h
@@ -70,6 +71,8 @@
/* Status Register bits. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
+/* Flag Status Register bits. */
+#define FSR_RDY 0x80 /* FSR ready */
/* meaning of other SR_* bits may differ between vendors */
#define SR_BP0 4 /* Block protect 0 */
#define SR_BP1 8 /* Block protect 1 */
#03 : add flag_status valiable
- drivers/mtd/devices/m25p80.c
@@ -95,6 +98,7 @@ struct m25p {
u8 program_opcode;
u8 *command;
bool fast_read;
+ bool flag_status;
};
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
#04 : add FSR read function
- drivers/mtd/devices/m25p80.c
@@ -131,6 +135,28 @@ 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) {
+ printk(&flash->spi->dev, "error %d reading FSR\n",
+ (int) retval);
+ return retval;
+ }
+
+ return val;
+}
+
+/*
* Write status register 1 byte
* Returns negative if error occurred.
*/
#05 : add wait_till_fsr_ready function
- drivers/mtd/devices/m25p80.c
@@ -220,6 +246,30 @@ 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 sr;
+
+ deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+
+ do {
+ if ((sr = read_fsr(flash)) < 0)
+ break;
+ else if ((sr & FSR_RDY))
+ return 0;
+
+ cond_resched();
+
+ } while (!time_after_eq(jiffies, deadline));
+
+ return 1;
+}
+
+/*
* Erase the whole flash memory
*
* Returns 0 if successful, non-zero otherwise.
#06 : wait until previous erase command operation complete
- drivers/mtd/devices/m25p80.c
@@ -273,6 +323,14 @@ static int erase_sector(struct m25p *flash, u32 offset)
if (wait_till_ready(flash))
return 1;
+ /* Flag status, Wait until finished previous write command. */
+ if (flash->flag_status == true) {
+ if (wait_till_fsr_ready(flash)) {
+ mutex_unlock(&flash->lock);
+ return 1;
+ }
+ }
+
/* Send write enable, then erase commands. */
write_enable(flash);
#07 : wait until previous write command operation complete
- drivers/mtd/devices/m25p80.c
@@ -427,6 +485,14 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
mutex_lock(&flash->lock);
+ /* Flag status, Wait until finished previous write command. */
+ if (flash->flag_status == true) {
+ if (wait_till_fsr_ready(flash)) {
+ mutex_unlock(&flash->lock);
+ return 1;
+ }
+ }
+
/* Wait until finished previous write command. */
if (wait_till_ready(flash)) {
mutex_unlock(&flash->lock);
#08 : wait until previous write command operation complete : after sync
- drivers/mtd/devices/m25p80.c
@@ -457,6 +523,14 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
t[1].len = page_size;
spi_sync(flash->spi, &m);
+ /* Flag status, Wait until finished previous write command. */
+ if (flash->flag_status == true) {
+ if (wait_till_fsr_ready(flash)) {
+ mutex_unlock(&flash->lock);
+ return 1;
+ }
+ }
+
*retlen = m.actual_length - m25p_cmdsz(flash);
/* write everything in flash->page_size chunks */
#09 : wait until previous write command operation complete : after sync
- drivers/mtd/devices/m25p80.c
@@ -477,6 +551,14 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
spi_sync(flash->spi, &m);
+ /* Flag status, Wait until finished previous write command. */
+ if (flash->flag_status == true) {
+ if (wait_till_fsr_ready(flash)) {
+ mutex_unlock(&flash->lock);
+ return 1;
+ }
+ }
+
*retlen += m.actual_length - m25p_cmdsz(flash);
}
}
#10 : change Manufacture.ID of Micron.512Mb.Flash
- drivers/mtd/spi-nor/spi-nor.c
@@ -782,7 +864,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
{ "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) },
+ { "n25q512a", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
#11 : set flag_status if Flash is Micron.512Mb
@@ -996,6 +1078,13 @@ static int m25p_probe(struct spi_device *spi)
spi_set_drvdata(spi, flash);
/*
+ * Micron n25q512a requires to check flag status register
+ */
+ flash->flag_status = false;
+ if (strcmp(id->name, "n25q512a") == 0)
+ flash->flag_status = true;;
+
+ /*
* Atmel, SST and Intel/Numonyx serial flash tend to power
* up with the software protection bits set
*/