Skip to content

add spi nand driver #50690

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

rogeryou
Copy link

This PR is updated for #43915.

Add SPI NAND block device driver for using SPI NAND Flash like Macronix Flash MX31LF4GE4BC.
This driver is tested on STM32L562E-DK.

The license of BCH code is updated.

Copy link
Member

@erwango erwango left a comment

Choose a reason for hiding this comment

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

Thanks for this contribution.
Some clean up required.
My main request would be to remove STM32 mentions, since there is nothing STM32 specific here aside from the board used for test.

@erwango erwango removed the platform: STM32 ST Micro STM32 label Sep 27, 2022
@carlescufi
Copy link
Member

@rogeryou can you please format your commits as described here:
https://docs.zephyrproject.org/latest/contribute/guidelines.html#commit-guidelines

@rogeryou rogeryou force-pushed the macronix_spi_nand_v1 branch from 9755c14 to 901b863 Compare September 28, 2022 03:16
@rogeryou
Copy link
Author

@rogeryou can you please format your commits as described here: https://docs.zephyrproject.org/latest/contribute/guidelines.html#commit-guidelines

I have formated my commits.

@Laczen
Copy link
Collaborator

Laczen commented Sep 29, 2022

@rogeryou, thank you for this contribution. It would be very nice to have nand flash support in zephyr.

Regarding the PR, I have seen that the ecc is hidden for the user as to be able to use the standard flash interface. This is a good thing, but doesn't this also make any other part of the oob data unavailable ? IMHO it would be good to extend the flash driver for nand flashes with read/write possibilities of the oob data. This would allow adding bad block info to the oob area.

@RyKolb
Copy link

RyKolb commented Nov 1, 2022

@rogeryou
It seems as though part of this driver is written for either a 2048 or 4096 page size NAND flash, and yet other parts use the defined page/block offset/mask. Is there reasoning behind this?

@carlescufi carlescufi requested review from Laczen and removed request for GeorgeCGV, gmarull and mbolivar-nordic November 2, 2022 14:12
erwango
erwango previously requested changes Nov 8, 2022
@rogeryou
Copy link
Author

@rogeryou, thank you for this contribution. It would be very nice to have nand flash support in zephyr.

Regarding the PR, I have seen that the ecc is hidden for the user as to be able to use the standard flash interface. This is a good thing, but doesn't this also make any other part of the oob data unavailable ? IMHO it would be good to extend the flash driver for nand flashes with read/write possibilities of the oob data. This would allow adding bad block info to the oob area.

Thank you for your suggestion. We will add APIs that operate OOB later.

@rogeryou rogeryou closed this Nov 23, 2022
@rogeryou
Copy link
Author

@rogeryou It seems as though part of this driver is written for either a 2048 or 4096 page size NAND flash, and yet other parts use the defined page/block offset/mask. Is there reasoning behind this?

Could you tell me which part of the program you mentioned?

@rogeryou rogeryou reopened this Nov 23, 2022
@zephyrbot zephyrbot added the area: Devicetree Binding PR modifies or adds a Device Tree binding label Nov 23, 2022
@daniel-0723 daniel-0723 force-pushed the macronix_spi_nand_v1 branch 6 times, most recently from 66a06e6 to 9d94e4c Compare January 28, 2025 01:25
@daniel-0723
Copy link

Hi @de-nordic , we have fixed the compliance and documentation, please review again.

Copy link
Collaborator

@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.

There should be configuration for existing flash tests added, as the driver implements the Flash API and should work with these tests and samples we already have.

Some comments left, still reviewing.

@@ -63,6 +63,8 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SMARTBOND flash_smartbond.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_TELINK_B91 soc_flash_b91.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c)
zephyr_library_sources_ifdef(CONFIG_SPI_FLASH_AT45 spi_flash_at45.c)
zephyr_library_sources_ifdef(CONFIG_SPI_NAND bch.c)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not to be fixed with this PR, but just want to mention that I will propose enhancement where bch implementation gets moved to CRC subsystem.

@@ -0,0 +1,38 @@
# Copyright (c) 2022 Macronix International Co., Ltd.
Copy link
Collaborator

Choose a reason for hiding this comment

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

You probably want to update date in copyrights.

Device is connected to SPI bus, it has to
be initialized after SPI driver.

config SPI_NAND_CS_WAIT_DELAY
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be defined in DTS for a device?

help
This is the wait delay (in us) to allow for CS switching to take effect

config SPI_NAND_IDLE_IN_DPD
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be defined in dts?

LOG_ERR("Enable continuous read failed: %d\n", secur_reg);
}

out: release_device(dev);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Labels alone in the line, drop the function call to the next line.

return ret;
}

static int spi_nand_conti_read_enable(const struct device *dev)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we merge the spi_nand_conti_read_enable and spi_nand_conti_read_disable. They are looking very similar.

size -= chunk;
}

out: release_device(dev);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Labels get own lines.

offset = addr % data->page_size;
chunk = (offset + size < data->page_size) ?
size : (data->page_size - offset);
read_bytes = chunk;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need read_bytes; it seem that is equivalent of chunk, through the loop, and not used outside.

:name: JEDEC SPI-NAND flash
:relevant-api: flash_interface

Use the flash API to interact with an SPI NOR serial flash memory device.
Copy link

Choose a reason for hiding this comment

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

Suggested change
Use the flash API to interact with an SPI NOR serial flash memory device.
Use the flash API to interact with an SPI NAND serial flash memory device.

@de-nordic de-nordic assigned de-nordic and unassigned nvlsianpu Feb 27, 2025
@de-nordic de-nordic added this to the v4.2.0 milestone Feb 27, 2025
@daniel-0723
Copy link

Hi @de-nordic @embed , since Zephyr has supported Multi-bit SPI bus last year, do we need to rework this PR based on MSPI (drivers/mspi.h) instead of SPI (drivers/spi.h)? Many controller IP core such as FlexSPI, stm32-ospi, cadence-xSPI or Renesas-xSPI support QSPI NAND Flash.

@embed
Copy link

embed commented Mar 19, 2025

@daniel-0723 I follow the philosophy of first make it work. How much effort is it to finish this as a proper SPI driver and then have another PR for adding MSPI support? I would vote for meeting the original PR goal, that is a working generic SPI-NAND driver. CC: @de-nordic

On another note, I can't reply to your comment for some reason so I made a new comment.

#define SPI_NAND_CMD_ECC_STAT_READ 0x7C

/* Page, sector, and block size are standard, not configurable. */
#define SPI_NAND_PAGE_SIZE 2048
Copy link

Choose a reason for hiding this comment

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

Page and block sizes should either come from device tree, or better from ONFI table.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 for leveraging the ONFI table.

Choose a reason for hiding this comment

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

Hi @embed @bbooher , I have updated the PR, now page sizes and sub page size come from ONFI table.

@daniel-0723 daniel-0723 force-pushed the macronix_spi_nand_v1 branch from 04e8854 to 0c4ca12 Compare March 26, 2025 10:34
@daniel-0723 daniel-0723 force-pushed the macronix_spi_nand_v1 branch 4 times, most recently from bce4642 to 6077f25 Compare April 25, 2025 09:44

/* Status register bits */
#define SPI_NAND_WIP_BIT BIT(0) /* Write in progress */
#define SPI_NAND_WEL_BIT BIT(1) /* Write enable latch */
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unused, remove.

Choose a reason for hiding this comment

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

sloved

Comment on lines 25 to 33
/* Status Register Bits 0xC0 */
#define SPINAND_STATUS_BIT_WIP 0x1 /* Write In Progress */
#define SPINAND_STATUS_BIT_WEL 0x2 /* Write Enable Latch */
#define SPINAND_STATUS_BIT_ERASE_FAIL 0x4 /* Erase failed */
#define SPINAND_STATUS_BIT_PROGRAM_FAIL 0x8 /* Program failed */
#define SPINAND_STATUS_BIT_ECC_STATUS_MASK 0x30 /* ECC status */
#define SPINAND_STATUS_ECC_STATUS_NO_ERR 0x00
#define SPINAND_STATUS_ECC_STATUS_ERR_COR 0x10
#define SPINAND_STATUS_ECC_STATUS_ERR_NO_COR 0x20
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unused, remove.

Choose a reason for hiding this comment

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

sloved

#define SPINAND_SECURE_BIT_CONT 0x04 /* continuous read enable */
#define SPINAND_SECURE_BIT_ECC_EN 0x10 /* On-die ECC enable */
#define SPINAND_SECURE_BIT_OTP_EN 0x40
#define SPINAND_SECURE_BIT_OTP_PROT 0x80
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unused, remove.

Choose a reason for hiding this comment

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

sloved

#define SPINAND_STATUS_ECC_STATUS_ERR_NO_COR 0x20

/* Secure OTP Register Bits 0xB0 */
#define SPINAND_SECURE_BIT_QE 0x01 /* Quad enable */
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unused, remove.

Choose a reason for hiding this comment

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

sloved

Comment on lines 43 to 49
#define SPINAND_BLOCK_PROT_BIT_SP 0x01
#define SPINAND_BLOCK_PROT_BIT_COMPLE 0x02
#define SPINAND_BLOCK_PROT_BIT_INVERT 0x04
#define SPINAND_BLOCK_PROT_BIT_BP0 0x08
#define SPINAND_BLOCK_PROT_BIT_BP1 0x10
#define SPINAND_BLOCK_PROT_BIT_BP2 0x20
#define SPINAND_BLOCK_PROT_BIT_BPRWD 0x80
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unused, remove.

Choose a reason for hiding this comment

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

sloved

}

/* size must be a multiple of sub-page */
if ((size % driver_cfg->sub_page_size) != 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

size can still be bigger then the device.

Choose a reason for hiding this comment

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

sloved

while (size > 0) {

/* Don't write more than a page. */
offset = addr % data->page_size;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I assume that page_size may be bigger than sub_page_size, in which case this alignment in this line may lead to offset pointing to whole page before offset of sub_page_size, that has been accepted by line 534.

Choose a reason for hiding this comment

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

sloved

Comment on lines +636 to +749
if ((size % data->block_size) != 0) {
return -EINVAL;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

No check for addr being positive and size + addr to fit into real device size.

Choose a reason for hiding this comment

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

sloved


/* verify that eccbytes has the expected value */
if (data->nbc.bch->ecc_words * 4 != eccbytes) {
LOG_ERR("invalid eccbytes %u, should be %u\n",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this print hex rather than decimal?

Choose a reason for hiding this comment

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

sloved


data->page_buf = (uint8_t *)k_malloc(data->page_size + data->oob_size);
if (data->page_buf == NULL) {
LOG_ERR("Not enougn heap\n");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why pass-through? Shouldn't that just fail the entire operation already?

Choose a reason for hiding this comment

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

sloved

@daniel-0723 daniel-0723 force-pushed the macronix_spi_nand_v1 branch 3 times, most recently from 1ef8ab7 to 7ae596a Compare May 27, 2025 10:21
Add SPI NAND Flash driver support

Signed-off-by: Daniel Zhang <danielzhang@mxic.com.cn>
@daniel-0723 daniel-0723 force-pushed the macronix_spi_nand_v1 branch from 555fd5d to eaf79f9 Compare May 28, 2025 01:57
Copy link

return &flash_nand_parameters;
}

static const struct flash_driver_api spi_nand_api = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Driver API needs to be wrapped in macro.

Suggested change
static const struct flash_driver_api spi_nand_api = {
static DEVICE_API(flash, spi_nand_api) = {

Comment on lines +1041 to +1044
DEVICE_DT_INST_DEFINE(0, &spi_nand_init, NULL,
&spi_nand_data_0, &spi_nand_config_0,
POST_KERNEL, CONFIG_SPI_NAND_INIT_PRIORITY,
&spi_nand_api);
Copy link
Collaborator

Choose a reason for hiding this comment

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

If it would be possible to have multiple instances use, DT_INST_FOREACH_STATUS_OKAY

required: true
type: int
description: |
Size (in bytes) of the Flash memory.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a trailing newline to the file.

@@ -0,0 +1,3 @@
CONFIG_STDOUT_CONSOLE=y
CONFIG_FLASH=y
CONFIG_HEAP_MEM_POOL_SIZE=100000
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing trailing newline.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we want driver specific samples? Can't you re-use the existing flash driver sample?

LOG_ERR("get feature failed: %d", ret);
goto out;
}
if (!(secur_reg & SPINAND_SECURE_BIT_CONT)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (!(secur_reg & SPINAND_SECURE_BIT_CONT)) {
if ((secur_reg & SPINAND_SECURE_BIT_CONT) == 0U) {

LOG_ERR("get feature failed: %d", ret);
goto out0;
}
if (!(secur_reg & SPINAND_SECURE_BIT_OTP_EN)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (!(secur_reg & SPINAND_SECURE_BIT_OTP_EN)) {
if ((secur_reg & SPINAND_SECURE_BIT_OTP_EN) == 0U) {

release_device(dev);
}

if (onfi_table[ONFI_CONT_READ_168] & 0x02) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a define for the 0x02 constant?

Suggested change
if (onfi_table[ONFI_CONT_READ_168] & 0x02) {
if ((onfi_table[ONFI_CONT_READ_168] & 0x02) != 0U) {

goto out1;
}

if (secur_reg & SPINAND_SECURE_BIT_OTP_EN) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (secur_reg & SPINAND_SECURE_BIT_OTP_EN) {
if ((secur_reg & SPINAND_SECURE_BIT_OTP_EN) != 0U) {

goto out;
}
/* Only clear if GET_FEATURE worked and something's set. */
if (reg & SPINAND_BLOCK_PROT_BIT_BP_MASK) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (reg & SPINAND_BLOCK_PROT_BIT_BP_MASK) {
if ((reg & SPINAND_BLOCK_PROT_BIT_BP_MASK) != 0U) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.