Skip to content

flash: spi_nand: initial generic driver#100845

Merged
kartben merged 2 commits intozephyrproject-rtos:mainfrom
Embeint:251211_spi_nand
Feb 20, 2026
Merged

flash: spi_nand: initial generic driver#100845
kartben merged 2 commits intozephyrproject-rtos:mainfrom
Embeint:251211_spi_nand

Conversation

@JordanYates
Copy link
Copy Markdown
Contributor

Initial generic driver for SPI-NAND devices that expose the ONFI parameter page. Does not support advanced/optional features such as continuous reads, software ECC, or power down modes.

Configuration comes from devicetree in order to support other modules, but is validated against the loaded ONFI data at boot.

Can provide a base towards future work on #99908.

PR #50690 was used as inspiration and for some logic (copyrights preserved), but this PR attempts to sidestep the significant review challenges around the software ECC support by simply providing a baseline driver that uses hardware ECC.

Implementing the driver for the Micron flash devices also exposed non-generic register defines etc used in the previous PR. Everything in this PR should be generic across Micron (tested in hardware) and Macronix (datasheets and the other PR).

Tested on Micron MT29F4G01ABBFDWB. Example debug logs from a (erase-write-read-erase functionality test)

[00:00:00.008,480] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 32 us (Status 00)
[00:00:00.008,832] <dbg> spi_nand: onfi_parameters_load:      Manufacturer: MICRON
[00:00:00.008,832] <dbg> spi_nand: onfi_parameters_load:             Model: MT29F4G01ABBFDWB
[00:00:00.008,864] <dbg> spi_nand: onfi_parameters_load:  Page Size (data): 4096
[00:00:00.008,864] <dbg> spi_nand: onfi_parameters_load: Page Size (spare): 256
[00:00:00.008,864] <dbg> spi_nand: onfi_parameters_load:   Pages per Block: 64
[00:00:00.008,864] <dbg> spi_nand: onfi_parameters_load:   Blocks per Unit: 2048
[00:00:00.008,896] <dbg> spi_nand: onfi_parameters_load:             Units: 1
[00:00:00.049,056] <dbg> spi_nand: spi_nand_erase: Erasing block starting at 011380
[00:00:00.049,920] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 768 us (Status 00)
[00:00:00.051,840] <dbg> spi_nand: spi_nand_write: Write 4096 to 01139d:000
[00:00:00.052,160] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 256 us (Status 00)
[00:00:00.052,192] <dbg> spi_nand: spi_nand_read: Read 4096 from 01139d:000
[00:00:00.052,416] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 128 us (Status 00)
[00:00:00.053,952] <dbg> spi_nand: spi_nand_read: Read 51 from 01139d:031
[00:00:00.054,144] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 128 us (Status 00)
[00:00:00.054,336] <dbg> spi_nand: spi_nand_erase: Erasing block starting at 011380
[00:00:00.055,008] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 640 us (Status 00)
[00:00:00.055,072] <dbg> spi_nand: spi_nand_read: Read 4096 from 01139d:000
[00:00:00.055,232] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 128 us (Status 00)

@zephyrbot zephyrbot added area: Boards/SoCs area: Tests Issues related to a particular existing or missing test area: Devicetree Bindings area: Flash labels Dec 11, 2025
@JordanYates JordanYates force-pushed the 251211_spi_nand branch 2 times, most recently from 2dbcf36 to c8775c8 Compare December 11, 2025 01:30
@JordanYates
Copy link
Copy Markdown
Contributor Author

Ping @rogeryou and @daniel-0723, since I can't seem to add you as reviewers

@sonarqubecloud
Copy link
Copy Markdown

@LinderPi
Copy link
Copy Markdown
Contributor

You could already check if the implemented NFTL disk driver module works for you (#100858).

@tpambor
Copy link
Copy Markdown
Contributor

tpambor commented Jan 31, 2026

I also gave this a try with a Winbond W25N01GVZEIG

[00:00:00.000,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 0 us (Status 00)
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load:      Manufacturer: WINBOND
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load:             Model: W25N01GV
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load:  Page Size (data): 2048
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load: Page Size (spare): 64
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load:   Pages per Block: 64
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load:   Blocks per Unit: 1024
[00:00:00.001,000] <dbg> spi_nand: onfi_parameters_load:             Units: 1

@JordanYates
Copy link
Copy Markdown
Contributor Author

@de-nordic @rghaddab is there anything blocking this review? I appreciate you probably don't have any hardware to test it against.

@de-nordic
Copy link
Copy Markdown
Contributor

@de-nordic @rghaddab is there anything blocking this review? I appreciate you probably don't have any hardware to test it against.

Sorry, I will take a look this evening.

@carlescufi
Copy link
Copy Markdown
Member

@JordanYates how does this fit #100683? Are we just going to have the same as NOR, where we have an SPI NOR driver and then flash-specific ones?

@tpambor
Copy link
Copy Markdown
Contributor

tpambor commented Feb 5, 2026

@JordanYates how does this fit #100683? Are we just going to have the same as NOR, where we have an SPI NOR driver and then flash-specific ones?

This driver issues the SET_FEATURE/GET_FEATURE command to addresses 0xa0, 0xb0, 0xc0.
https://github.com/Embeint/zephyr/blob/97f4c915ad2da5ee63638a7fe377a8a7de185d06/drivers/flash/spi_nand.h#L46-L53

These are in the vendor specific range (0x80-0xff) according to ONFI spec. Most SPI NANDs have similar content there, e.g. ECC enable bit is the same on Micron MT29F4G01ABBFDWB and Winbond W25N01GVZEIG. But there are also differences, I haven't looked at everything but Micron MT29F4G01ABBFDWB has 3 bits of ECC status in the status register, but Winbond W25N01GVZEIG has only 2 bits of ECC status. Currently, the driver in this PR is not checking the ECC status bits.

@carlescufi
Copy link
Copy Markdown
Member

carlescufi commented Feb 6, 2026

@JordanYates how does this fit #100683? Are we just going to have the same as NOR, where we have an SPI NOR driver and then flash-specific ones?

This driver issues the SET_FEATURE/GET_FEATURE command to addresses 0xa0, 0xb0, 0xc0. https://github.com/Embeint/zephyr/blob/97f4c915ad2da5ee63638a7fe377a8a7de185d06/drivers/flash/spi_nand.h#L46-L53

These are in the vendor specific range (0x80-0xff) according to ONFI spec. Most SPI NANDs have similar content there, e.g. ECC enable bit is the same on Micron MT29F4G01ABBFDWB and Winbond W25N01GVZEIG. But there are also differences, I haven't looked at everything but Micron MT29F4G01ABBFDWB has 3 bits of ECC status in the status register, but Winbond W25N01GVZEIG has only 2 bits of ECC status. Currently, the driver in this PR is not checking the ECC status bits.

Thanks @tpambor for the feedback, but what I meant is how will we organize the code for NAND flashes in general. In the case of NOR, we have:

  • Individual drivers for different flashes
  • spi_nor.c which is a generic flash driver over the SPI API
  • flash_mspi_nor.c which is a generic flash driver over the MSPI API

My question was whether we will have something similar here, in the lines of:

  • NAND drivers that target "raw" NAND and require a translation layer (Dhara)
  • An spi_nand.c as in this PR that handles NAND flashes that do not require an FTL because they do bad block allocation and wear levelling internally, and that are accessible via the SPI API
  • A future flash_mspi_nand.c that does the same as spi_nand.c but over MSPI

CC @JordanYates @anangl @swift-tk

@JordanYates
Copy link
Copy Markdown
Contributor Author

These are in the vendor specific range (0x80-0xff) according to ONFI spec. Most SPI NANDs have similar content there, e.g. ECC enable bit is the same on Micron MT29F4G01ABBFDWB and Winbond W25N01GVZEIG.

I wasn't aware that these were defined as vendor specific commands, but as I mentioned in the PR description I did my best to ensure that only defines that were common across the two manufacturers were used. Maybe it won't end up being true for all NAND flashes, but I would want to see a counter-example before complicating the driver.

I haven't looked at everything but Micron MT29F4G01ABBFDWB has 3 bits of ECC status in the status register, but Winbond W25N01GVZEIG has only 2 bits of ECC status. Currently, the driver in this PR is not checking the ECC status bits.

Correct, the ECC bits are currently not checked since AFAIK its not required for this basic operation mode. Obviously when combined with something like Dhara they start to have meaning, but what is the flash API supposed to do when these bits start to be set?

Note that the program and erase fail bits are common, and are checked to confirm operation success/failure.

@JordanYates
Copy link
Copy Markdown
Contributor Author

  • NAND drivers that target "raw" NAND and require a translation layer (Dhara)
  • An spi_nand.c as in this PR that handles NAND flashes that do not require an FTL because they do bad block allocation and wear levelling internally, and that are accessible via the SPI API

The NAND flashes supported by this PR don't do bad block allocation or wear leveling internally AFAIK. This driver is more the first option. The longer term goal would be to extend this driver with support for the extension commands that Dhara needs, so that it can be either used "raw" for use-cases that don't care about the unreliability, or with Dhara to get the error handling.

My question was whether we will have something similar here, in the lines of:

  • NAND drivers that target "raw" NAND and require a translation layer (Dhara)
  • An spi_nand.c as in this PR that handles NAND flashes that do not require an FTL because they do bad block allocation and wear levelling internally, and that are accessible via the SPI API
  • A future flash_mspi_nand.c that does the same as spi_nand.c but over MSPI

Sounds reasonable to me

Comment thread drivers/flash/spi_nand.h
Comment thread drivers/flash/spi_nand.h
Comment thread drivers/flash/spi_nand.c Outdated
Comment thread drivers/flash/spi_nand.c Outdated
Comment thread drivers/flash/spi_nand.c Outdated
Comment thread drivers/flash/spi_nand.h Outdated
Comment thread drivers/flash/spi_nand.h Outdated
Comment thread dts/bindings/mtd/jedec,spi-nand.yaml Outdated
Comment thread drivers/flash/spi_nand.h Outdated
Comment thread drivers/flash/spi_nand.c
@tpambor
Copy link
Copy Markdown
Contributor

tpambor commented Feb 7, 2026

I wasn't aware that these were defined as vendor specific commands, but as I mentioned in the PR description I did my best to ensure that only defines that were common across the two manufacturers were used. Maybe it won't end up being true for all NAND flashes, but I would want to see a counter-example before complicating the driver.

I had a closer look across vendor datasheets and these registers are sufficiently similar to implement a generic solution for the basic functionality.

Correct, the ECC bits are currently not checked since AFAIK its not required for this basic operation mode. Obviously when combined with something like Dhara they start to have meaning, but what is the flash API supposed to do when these bits start to be set?

I would expect that if ECC detects unrecoverable errors, this is propagated as an error (like -EIO) to the upper layers (FTL, FS, application). Dhara currently doesn't do anything too special: if a page contains unrecoverable errors, it propagates that error for data pages and avoids utilizing them for metadata. While handling this isn't strictly required for basic operation, "bad things" may happen if unrecoverable errors are present but not reported, regardless of whether Dhara is used or not.

Note that the program and erase fail bits are common, and are checked to confirm operation success/failure.

This is fine and all that Dhara expects. Dhara would then mark the block as a bad but these extensions can be implemented in a follow-up PR.

@zephyrbot zephyrbot added the area: Devicetree Binding PR modifies or adds a Device Tree binding label Feb 9, 2026
@zephyrbot zephyrbot requested a review from JarmouniA February 9, 2026 11:45
@RichardSWheatley
Copy link
Copy Markdown
Contributor

Initial generic driver for SPI-NAND devices that expose the ONFI parameter page. Does not support advanced/optional features such as continuous reads, software ECC, or power down modes.

Is your proposal the these features be handled elsewhere?

@JordanYates
Copy link
Copy Markdown
Contributor Author

Is your proposal the these features be handled elsewhere?

My proposal is that advanced features can be debated in future PRs without bogging down the discussion for baseline support. That's what killed the other PR.

@RichardSWheatley
Copy link
Copy Markdown
Contributor

RichardSWheatley commented Feb 10, 2026

Is your proposal the these features be handled elsewhere?

My proposal is that advanced features can be debated in future PRs without bogging down the discussion for baseline support. That's what killed the other PR.

Agreed! This is a good idea to move forward.
I also see that @tpambor said "extensions can be implemented in a follow-up PR."

Comment thread drivers/flash/spi_nand.c Outdated
Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c Outdated
Comment thread dts/bindings/mtd/jedec,spi-nand.yaml Outdated
Comment thread tests/drivers/build_all/flash/spi.dtsi
Copy link
Copy Markdown
Contributor

@de-nordic de-nordic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it takes long, overworked and under the weather.

Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c Outdated
Comment thread drivers/flash/spi_nand.c Outdated
Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c Outdated
k_sleep(K_USEC(poll_us));
} while (!sys_timepoint_expired(timeout));

LOG_ERR("Timeout waiting for flash ready (Status %02X)", *status);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should be debug. Status does not matter that much in production code and you have to deal with timeout in calling code, so you will probably log the timeout info there too; probably with more accurate info like device you have been using.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I've found it useful even when not actively developing the driver. It is an error, and does provide context that isn't propagated further up, LOG_ERR seems appropriate to me.

Comment thread drivers/flash/spi_nand.c
Comment thread dts/bindings/mtd/jedec,spi-nand.yaml Outdated
Comment thread dts/bindings/mtd/jedec,spi-nand.yaml Outdated
Comment thread dts/bindings/mtd/jedec,spi-nand.yaml Outdated
@JordanYates JordanYates force-pushed the 251211_spi_nand branch 2 times, most recently from 132397d to d104e63 Compare February 13, 2026 00:55
Comment thread dts/bindings/mtd/jedec,spi-nand.yaml Outdated
@JordanYates JordanYates force-pushed the 251211_spi_nand branch 2 times, most recently from a73e4ca to 1431609 Compare February 13, 2026 04:38
Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c
Copy link
Copy Markdown
Contributor

@de-nordic de-nordic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks OK, the only controversial addition is the line that removes const, as it breaks one of our coding guidelines.

Comment thread drivers/flash/spi_nand.c
{
const struct spi_nand_config *config = dev->config;
uint32_t write_block = config->parameters->write_block_size;
uint8_t *src_u8 = (void *)src;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not supposed to do that according to https://docs.zephyrproject.org/latest/contribute/coding_guidelines/index.html, rule 70

Comment thread drivers/flash/spi_nand.c
Comment thread drivers/flash/spi_nand.c
Comment on lines +660 to +664
/* Validate JEDEC ID */
ret = spi_nand_cmd_read_dummy(dev, SPI_NAND_CMD_READ_ID, jedec_id, SPI_NAND_MAX_ID_LEN);
if (ret != 0) {
goto release;
}
Copy link
Copy Markdown
Contributor

@de-nordic de-nordic Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jesd 106 "Standard Manufacturer’s Identification Code" , the document only contains id codes.
Leave it as is. Till we figure common way to address it with NOR driver.

Initial generic driver for SPI-NAND devices that expose the ONFI
parameter page. Does not support advanced features such as continuous
reads, software ECC, or optional power down modes.

Configuration comes from devicetree in order to support other modules,
but is validated against the loaded ONFI data at boot.

Signed-off-by: Jordan Yates <jordan@embeint.com>
Add `jedec,spi-nand` node to the build all test.

Signed-off-by: Jordan Yates <jordan@embeint.com>
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@tpambor tpambor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Retested on hardware:

[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load: Valid CRC: 3D0F
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load:      Manufacturer: WINBOND
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load:             Model: W25N01GV
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load:  Page Size (data): 2048
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load: Page Size (spare): 64
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load:   Pages per Block: 64
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load:   Blocks per Unit: 1024
[00:00:00.002,000] <dbg> spi_nand: onfi_parameters_load:             Units: 1
uart:~$ flash test spi-nand@0 0 20000 1
Erase OK.
Write OK.
Verified OK.
Erase-Write-Verify test done.

@kartben kartben merged commit a5b080c into zephyrproject-rtos:main Feb 20, 2026
49 of 60 checks passed
@kartben kartben mentioned this pull request Feb 20, 2026
@JordanYates JordanYates deleted the 251211_spi_nand branch February 21, 2026 07:42
@prashant3285
Copy link
Copy Markdown

prashant3285 commented Feb 22, 2026

@JordanYates I was testing this driver, and got into an issue.

The driver operation are normal, but when I analysed the data, I found duplication and overwriting on previous pages
so I ran a test- indicative code

size_t len = SPI_NAND_PAGE_SIZE; (2048)
uint8_t *test_buf = k_malloc(len);
memset(test_buf, pattern_value, len); // pattern is like entries 1 , 2 , 3 incremented on each page write
ret = flash_write(flash_nand_dev, addr, test_buf, len); //address increments by one page each time

after writing 3 pages, expected output on read is page 1: full of 1, page 2: full of 2 and page 3: full of 3
but actual output is page 1, 2 and 3 are full of 3

Can you advise if I am doing anything wrong
[00:00:00.291,259] nand_test: Step 1: Erasing block 1 at offset 0x20000
[00:00:05.292,999] nand_test: Step 2.1: Writing pattern 0x01 to page 0 at offset 0x20000
[00:00:05.300,140] nand_test: Step 2.2: Writing pattern 0x02 to page 1 at offset 0x20800
[00:00:05.307,312] nand_test: Step 2.3: Writing pattern 0x03 to page 2 at offset 0x21000
[00:00:05.314,300] nand_test: Page writes completed
[00:00:10.315,032] nand_test: Step 3.1: Read first 4 bytes of page 0: 0x03 0x03 0x03 0x03
[00:00:10.315,673] nand_test: Step 3.2: Read first 4 bytes of page 1: 0x03 0x03 0x03 0x03
[00:00:10.316,314] nand_test: Step 3.3: Read first 4 bytes of page 2: 0x03 0x03 0x03 0x03

@tpambor
Copy link
Copy Markdown
Contributor

tpambor commented Feb 22, 2026

@prashant3285 I only have tested with the shell but I haven't seen any such behavior

uart:~$ flash erase spi-nand@0 0 20000
Erase success.
[09:35:26.859,000] <dbg> spi_nand: spi_nand_erase: Erasing block starting at 000000
[09:35:26.860,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 1000 us (Op erase, Status 00)
uart:~$ flash read spi-nand@0 0 16
00000000: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff |........ ........|

[09:35:31.361,000] <dbg> spi_nand: spi_nand_read: Read 16 from 000000:000
[09:35:31.362,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 200 us (Op read, Status 00)
uart:~$ flash read spi-nand@0 800 16
00000800: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff |........ ........|

[09:35:34.997,000] <dbg> spi_nand: spi_nand_read: Read 16 from 000001:000
[09:35:34.997,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 200 us (Op read, Status 00)
uart:~$ flash write_test spi-nand@0 800 2048 1
Loop #1 done in 2448986 ns.
Total: 2448986 ns, Per loop: 2448986 ns, Speed: ~816.7KiBps
[09:35:49.797,000] <dbg> spi_nand: spi_nand_write: Write 2048 to 000001:000
[09:35:49.800,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 600 us (Op write, Status 00)
uart:~$ flash read spi-nand@0 0 16
00000000: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff |........ ........|

[09:35:58.476,000] <dbg> spi_nand: spi_nand_read: Read 16 from 000000:000
[09:35:58.477,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 200 us (Op read, Status 00)
uart:~$ flash read spi-nand@0 800 16
00000800: 00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f |........ ........|

[09:36:03.867,000] <dbg> spi_nand: spi_nand_read: Read 16 from 000001:000
[09:36:03.868,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 200 us (Op read, Status 00)
uart:~$ flash read spi-nand@0 1000 16
00001000: ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff |........ ........|

[09:38:25.276,000] <dbg> spi_nand: spi_nand_read: Read 16 from 000002:000
[09:38:25.276,000] <dbg> spi_nand: spi_nand_wait_until_ready: Ready after 200 us (Op read, Status 00)

@prashant3285
Copy link
Copy Markdown

After further digging I see a pattern where odd number blocks are not working as desired but the even number blocks work fine

Works: Block 0 2 4
Not Working: Blocks 1 3 5

#define SPI_NAND_PAGE_SIZE    2048        /* 2KB physical page */
#define SPI_NAND_BLOCK_SIZE   131072      /* 128KB (64 pages * 2048) */
#define SPI_NAND_COMPAT       jedec_spi_nand

/* Test block index */
#define TEST_BLOCK_INDEX      4
#define TEST_BLOCK_OFFSET     (TEST_BLOCK_INDEX * SPI_NAND_BLOCK_SIZE)

#define TEST_BLOCK_INDEX1      5
#define TEST_BLOCK_OFFSET1     (TEST_BLOCK_INDEX1 * SPI_NAND_BLOCK_SIZE)

Logs

[00:00:00.264,892] <inf> spi_nand: Ready after 183 us (Op reset, Status 00)
[00:00:00.266,021] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:00.267,242] <inf> spi_nand: Valid CRC: FD9F
[00:00:00.267,272] <inf> spi_nand:      Manufacturer: MICRON      
[00:00:00.267,333] <inf> spi_nand:             Model: MT29F2G01ABAGDWB    
[00:00:00.267,333] <inf> spi_nand:  Page Size (data): 2048
[00:00:00.267,333] <inf> spi_nand: Page Size (spare): 128
[00:00:00.267,333] <inf> spi_nand:   Pages per Block: 64
[00:00:00.267,364] <inf> spi_nand:   Blocks per Unit: 2048
[00:00:00.267,364] <inf> spi_nand:             Units: 1
*** Booting nRF Connect SDK v3.2.1-d8887f6f32df ***
*** Using Zephyr OS v4.2.99-ec78104f1569 ***
[00:00:00.267,944] <inf> udc_nrf: Initialized
[00:00:00.268,096] <inf> nand_test: === Application Started ===
[00:00:00.268,127] <inf> nand_test: Device spi_nand@0 is ready
[00:00:00.268,127] <inf> nand_test: === SPI-NAND Flash Block Test ===
[00:00:05.268,218] <inf> nand_test: Step 1: Erasing block 4 at offset 0x80000
[00:00:05.268,432] <inf> spi_nand: Erasing block starting at 000100
[00:00:05.269,622] <inf> spi_nand: Ready after 977 us (Op erase, Status 00)
[00:00:05.269,653] <inf> nand_test: Block erase succeeded
[00:00:10.269,775] <inf> spi_nand: Read 4 from 000100:000
[00:00:10.270,172] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:10.270,416] <inf> nand_test: Verification - Page 0 (erased): 0xFF 0xFF 0xFF 0xFF
[00:00:15.270,751] <inf> nand_test: Step 2.0: Writing pattern 0x01 to page 0 at offset 0x80000
[00:00:15.270,935] <inf> spi_nand: Write 2048 to 000100:000
[00:00:15.277,709] <inf> spi_nand: Ready after 580 us (Op write, Status 00)
[00:00:15.277,954] <inf> nand_test: Step 2.1: Writing pattern 0x02 to page 1 at offset 0x80800
[00:00:15.278,167] <inf> spi_nand: Write 2048 to 000101:000
[00:00:15.284,942] <inf> spi_nand: Ready after 580 us (Op write, Status 00)
[00:00:15.285,186] <inf> nand_test: Step 2.2: Writing pattern 0x03 to page 2 at offset 0x81000
[00:00:15.285,400] <inf> spi_nand: Write 2048 to 000102:000
[00:00:15.292,175] <inf> spi_nand: Ready after 580 us (Op write, Status 00)
[00:00:15.292,419] <inf> nand_test: Step 2.3: Writing pattern 0x04 to page 3 at offset 0x81800
[00:00:15.292,663] <inf> spi_nand: Write 2048 to 000103:000
[00:00:15.299,407] <inf> spi_nand: Ready after 519 us (Op write, Status 00)
[00:00:15.299,438] <inf> nand_test: Page writes completed
[00:00:20.299,530] <inf> spi_nand: Read 4 from 000100:000
[00:00:20.299,926] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:20.300,170] <inf> nand_test: Step 3.0: Read first 4 bytes of page 0: 0x01 0x01 0x01 0x01
[00:00:20.300,201] <inf> spi_nand: Read 4 from 000101:000
[00:00:20.300,598] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:20.300,842] <inf> nand_test: Step 3.1: Read first 4 bytes of page 1: 0x02 0x02 0x02 0x02
[00:00:20.300,872] <inf> spi_nand: Read 4 from 000102:000
[00:00:20.301,269] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:20.301,513] <inf> nand_test: Step 3.2: Read first 4 bytes of page 2: 0x03 0x03 0x03 0x03
[00:00:20.301,544] <inf> spi_nand: Read 4 from 000103:000
[00:00:20.301,971] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:20.302,215] <inf> nand_test: Step 3.3: Read first 4 bytes of page 3: 0x04 0x04 0x04 0x04
[00:00:20.302,215] <inf> nand_test: === Test Completed ===
[00:00:25.302,307] <inf> nand_test: Step 1: Erasing block 5 at offset 0xA0000
[00:00:25.302,520] <inf> spi_nand: Erasing block starting at 000140
[00:00:25.303,710] <inf> spi_nand: Ready after 977 us (Op erase, Status 00)
[00:00:25.303,741] <inf> nand_test: Block erase succeeded
[00:00:30.303,863] <inf> spi_nand: Read 4 from 000140:000
[00:00:30.304,260] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:30.304,504] <inf> nand_test: Verification - Page 0 (erased): 0x04 0x04 0x04 0x04
[00:00:35.304,840] <inf> nand_test: Step 2.0: Writing pattern 0x01 to page 0 at offset 0xA0000
[00:00:35.305,023] <inf> spi_nand: Write 2048 to 000140:000
[00:00:35.311,401] <inf> spi_nand: Ready after 183 us (Op write, Status 00)
[00:00:35.311,645] <inf> nand_test: Step 2.1: Writing pattern 0x02 to page 1 at offset 0xA0800
[00:00:35.311,859] <inf> spi_nand: Write 2048 to 000141:000
[00:00:35.318,237] <inf> spi_nand: Ready after 183 us (Op write, Status 00)
[00:00:35.318,481] <inf> nand_test: Step 2.2: Writing pattern 0x03 to page 2 at offset 0xA1000
[00:00:35.318,695] <inf> spi_nand: Write 2048 to 000142:000
[00:00:35.325,073] <inf> spi_nand: Ready after 183 us (Op write, Status 00)
[00:00:35.325,317] <inf> nand_test: Step 2.3: Writing pattern 0x04 to page 3 at offset 0xA1800
[00:00:35.325,531] <inf> spi_nand: Write 2048 to 000143:000
[00:00:35.331,939] <inf> spi_nand: Ready after 183 us (Op write, Status 00)
[00:00:35.331,970] <inf> nand_test: Page writes completed
[00:00:40.332,061] <inf> spi_nand: Read 4 from 000140:000
[00:00:40.332,458] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:40.332,702] <inf> nand_test: Step 3.0: Read first 4 bytes of page 0: 0x04 0x04 0x04 0x04
[00:00:40.332,702] <wrn> nand_test: Data mismatch at page 0! Expected 0x01, got 0x04
[00:00:40.332,733] <inf> spi_nand: Read 4 from 000141:000
[00:00:40.333,160] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:40.333,404] <inf> nand_test: Step 3.1: Read first 4 bytes of page 1: 0x04 0x04 0x04 0x04
[00:00:40.333,404] <wrn> nand_test: Data mismatch at page 1! Expected 0x02, got 0x04
[00:00:40.333,435] <inf> spi_nand: Read 4 from 000142:000
[00:00:40.333,862] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:40.334,106] <inf> nand_test: Step 3.2: Read first 4 bytes of page 2: 0x04 0x04 0x04 0x04
[00:00:40.334,106] <wrn> nand_test: Data mismatch at page 2! Expected 0x03, got 0x04
[00:00:40.334,136] <inf> spi_nand: Read 4 from 000143:000
[00:00:40.334,564] <inf> spi_nand: Ready after 183 us (Op read, Status 00)
[00:00:40.334,808] <inf> nand_test: Step 3.3: Read first 4 bytes of page 3: 0x04 0x04 0x04 0x04

@prashant3285
Copy link
Copy Markdown

This issue is due to NAND with multiple planes.
Odd and even blocks are located in different planes and for Reading, Writing a block, its designated plane needs to be selected.

@tpambor
Copy link
Copy Markdown
Contributor

tpambor commented Mar 1, 2026

@prashant3285 Could you fill a issue so that we can track and fix this. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Boards/SoCs area: Devicetree Binding PR modifies or adds a Device Tree binding area: Devicetree Bindings area: Flash area: Tests Issues related to a particular existing or missing test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants