Hi all,
I want to know how to add flag status check during SPI Flash write/erase for Micron 512Mb Serial Flash.
We have to change the QSPI-NOR density from 256Mb to 512Mb, because our RootFS is larger than QSPI-NOR density(256Mb).
Our development environment is like as below,
- AP/Board : i.MX6SX-SabreSDB
- OS : Linux 3.10.53
- Device : Micron 512Mb QSPI-NOR N25Q512A
Firstly I confirmed the 512Mb QSPI-NOR probing.
For this I modified the below files,
drivers/mtd/spi-nor/spi-nor.c
const struct spi_device_id spi_nor_ids[] = {
...
{ "n25q512a", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K) },
...
};
arch/arm/boot/dts/imx6sx-sdb.dts
&qspi2 {
...
flash0: n25q512a@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "micron,n25q512a";
spi-max-frequency = <29000000>;
reg = <0>;
};
...
};
I couldn't confirm the flash erase operation.
And I couldn't find the flag status check routine and the SECT_4K control routine in Freescale BSP.
In the Web-Site, I could find the relative code like as below,
- Check flag status register for Micron n25q512a
. http://lists.infradead.org/pipermail/linux-mtd/2014-January/051382.html?
- mtd: st_spi_fsm: Add support for Micron N25Q512A (for STMicro)
. http://www.gossamer-threads.com/lists/linux/kernel/2090517
But I couldn't find the relative code for i.MX6SX.
Could you give any guidance to apply Micron N25Q512A?
Best Regards,
Eric.
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
*/
Hi,
The board I can test with has a different SPI NOR memory.
If you try with the flash_erase command the amount of erased data is 64K?
How are you testing the memory erase?
I am checking the code in 3.14.28 and it seems that the memory has the 4K sector flag as expected.
Nor even one sector is erased?
Best Regards,
Alejandro
Hi Alejandro,
Thanks for your response.
These days I couldn't confirm your response, because I couldn't access the Freescale Community.
Today I'm confirming your response.
I performed the flash_erase for 64K sector size.
For this, I configured the the "const struct spi_device_id spi_nor_ids" value like as below,
drivers/mtd/spi-nor/spi-nor.c
const struct spi_device_id spi_nor_ids[] = {
...
{ "n25q512a", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K) }, // original : 4KB sector erase
{ "n25q512a", INFO(0x20ba20, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, // original : 64KB sector erase
...
};
The 64KB erasing operation seems well, but the erasing speed was so fast.
And I could confirm the flash was not erased through other Flash programmer.
I heard you are checking the 4KB erasing code in 3.14.28.
Could you inform me if you have any update?
Best Regards,
Eric.