Skip to content

Commit ecacf3d

Browse files
robhancocksedkartben
authored andcommitted
drivers: flash: spi_nor: Added flag status register support
Some Micron (and possibly other) SPI NOR devices implement a flag status register which provides more information on the success/failure of erase and program operations. In addition to better error checking, some of these devices actually don't function properly if the flag status register is not read after a program operation (subsequent reads will only return 0xFF bytes). Add a device tree parameter to indicate that the flag status register is supported. When specified, the flag status register will be used for ready/error checks rather than the standard status register. Signed-off-by: Robert Hancock <robert.hancock@calian.com>
1 parent 1fdb43c commit ecacf3d

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

drivers/flash/spi_nor.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ LOG_MODULE_REGISTER(spi_nor, CONFIG_FLASH_LOG_LEVEL);
5353
#define ANY_INST_HAS_WP_GPIOS DT_ANY_INST_HAS_PROP_STATUS_OKAY(wp_gpios)
5454
#define ANY_INST_HAS_HOLD_GPIOS DT_ANY_INST_HAS_PROP_STATUS_OKAY(hold_gpios)
5555
#define ANY_INST_USE_4B_ADDR_OPCODES DT_ANY_INST_HAS_BOOL_STATUS_OKAY(use_4b_addr_opcodes)
56+
#define ANY_INST_HAS_FLSR \
57+
DT_ANY_INST_HAS_BOOL_STATUS_OKAY(use_flag_status_register)
5658

5759
#ifdef CONFIG_SPI_NOR_ACTIVE_DWELL_MS
5860
#define ACTIVE_DWELL_MS CONFIG_SPI_NOR_ACTIVE_DWELL_MS
@@ -150,6 +152,7 @@ struct spi_nor_config {
150152
bool requires_ulbpr_exist:1;
151153
bool wp_gpios_exist:1;
152154
bool hold_gpios_exist:1;
155+
bool has_flsr: 1;
153156
};
154157

155158
/**
@@ -485,16 +488,53 @@ static int spi_nor_access(const struct device *const dev,
485488
*/
486489
static int spi_nor_wait_until_ready(const struct device *dev, k_timeout_t poll_delay)
487490
{
491+
const struct spi_nor_config *cfg = dev->config;
488492
int ret;
489493
uint8_t reg;
490494

491495
ARG_UNUSED(poll_delay);
492496

493497
while (true) {
494-
ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDSR, &reg, sizeof(reg));
495-
/* Exit on error or no longer WIP */
496-
if (ret || !(reg & SPI_NOR_WIP_BIT)) {
497-
break;
498+
/* If flag status register is present, check it rather than the standard
499+
* status register since it allows better error detection. Also, some devices
500+
* that have it require it to be read after a program operation.
501+
*/
502+
if (IS_ENABLED(ANY_INST_HAS_FLSR) && cfg->has_flsr) {
503+
ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDFLSR, &reg, sizeof(reg));
504+
if (ret) {
505+
break;
506+
}
507+
if (reg & SPI_NOR_FLSR_READY) {
508+
if (reg & SPI_NOR_FLSR_ERASE_FAIL) {
509+
LOG_ERR("Erase failure");
510+
ret = -EIO;
511+
}
512+
if (reg & SPI_NOR_FLSR_PROGRAM_FAIL) {
513+
LOG_ERR("Program failure");
514+
ret = -EIO;
515+
}
516+
if (reg & SPI_NOR_FLSR_PROT_ERROR) {
517+
LOG_ERR("Protection violation");
518+
ret = -EIO;
519+
}
520+
521+
if (ret) {
522+
/* Clear flag status register for next operation */
523+
int ret2 = spi_nor_cmd_write(dev, SPI_NOR_CMD_CLRFLSR);
524+
525+
if (ret2) {
526+
LOG_ERR("Failed to clear flag status register: %d",
527+
ret2);
528+
}
529+
}
530+
break;
531+
}
532+
} else {
533+
ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDSR, &reg, sizeof(reg));
534+
/* Exit on error or no longer WIP */
535+
if (ret || !(reg & SPI_NOR_WIP_BIT)) {
536+
break;
537+
}
498538
}
499539
#ifdef CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY
500540
/* Don't monopolise the CPU while waiting for ready */
@@ -1818,6 +1858,7 @@ static DEVICE_API(flash, spi_nor_api) = {
18181858
.wp_gpios_exist = DT_INST_NODE_HAS_PROP(idx, wp_gpios), \
18191859
.hold_gpios_exist = DT_INST_NODE_HAS_PROP(idx, hold_gpios), \
18201860
.use_4b_addr_opcodes = DT_INST_PROP(idx, use_4b_addr_opcodes), \
1861+
.has_flsr = DT_INST_PROP(idx, use_flag_status_register), \
18211862
IF_ENABLED(INST_HAS_LOCK(idx), (.has_lock = DT_INST_PROP(idx, has_lock),)) \
18221863
IF_ENABLED(ANY_INST_HAS_DPD, (INIT_T_ENTER_DPD(idx),)) \
18231864
IF_ENABLED(UTIL_AND(ANY_INST_HAS_DPD, ANY_INST_HAS_T_EXIT_DPD), \

drivers/flash/spi_nor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
#define SPI_NOR_WIP_BIT BIT(0) /* Write in progress */
1616
#define SPI_NOR_WEL_BIT BIT(1) /* Write enable latch */
1717

18+
/* Flag status register bits */
19+
#define SPI_NOR_FLSR_READY BIT(7) /* Ready (program/erase not in progress) */
20+
#define SPI_NOR_FLSR_ERASE_SUSPEND BIT(6) /* Erase suspend active */
21+
#define SPI_NOR_FLSR_ERASE_FAIL BIT(5) /* Last erase failed */
22+
#define SPI_NOR_FLSR_PROGRAM_FAIL BIT(4) /* Last program failed */
23+
#define SPI_NOR_FLSR_PROGRAM_SUSPEND BIT(2) /* Program suspend active */
24+
#define SPI_NOR_FLSR_PROT_ERROR BIT(1) /* Protection violation */
25+
#define SPI_NOR_FLSR_4BA BIT(0) /* 4-byte address mode active */
26+
1827
/* Flash opcodes */
1928
#define SPI_NOR_CMD_WRSR 0x01 /* Write status register */
2029
#define SPI_NOR_CMD_RDSR 0x05 /* Read status register */
@@ -60,6 +69,8 @@
6069
#define SPI_NOR_CMD_PP_4B 0x12 /* Page Program 4 Byte Address */
6170
#define SPI_NOR_CMD_PP_1_1_4_4B 0x34 /* Quad Page program (1-1-4) 4 Byte Address */
6271
#define SPI_NOR_CMD_PP_1_4_4_4B 0x3e /* Quad Page program (1-4-4) 4 Byte Address */
72+
#define SPI_NOR_CMD_RDFLSR 0x70 /* Read Flag Status Register */
73+
#define SPI_NOR_CMD_CLRFLSR 0x50 /* Clear Flag Status Register */
6374

6475
/* Flash octal opcodes */
6576
#define SPI_NOR_OCMD_SE 0x21DE /* Octal Sector erase */

dts/bindings/mtd/jedec,spi-nor-common.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,13 @@ properties:
113113
Some devices support 4-byte address opcodes for read/write/erase
114114
operations. Use this property to indicate that the device supports
115115
4-byte address opcodes.
116+
117+
use-flag-status-register:
118+
type: boolean
119+
description: |
120+
Indicates the device supports a flag status register.
121+
122+
Some devices (Micron and possibly others) support a flag status register
123+
which indicates more details on the status of program or erase operations.
124+
In some cases, program operations will not function properly if the flag
125+
status register is not read after the operation.

0 commit comments

Comments
 (0)