Skip to content
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

driver: flash: npcx: introduce npcx flash driver #60024

Merged
merged 2 commits into from Jul 20, 2023

Conversation

MulinChao
Copy link
Collaborator

This PR attempts to implement npcx's flash driver instead of the original one (npcx spi driver plus spi_nor flash driver). There are two reasons to do this refactor. First, we'd like to support two or more spi nor flashes via a single Flash Interface Unit (FIU) module. Although the Zephyr spi driver uses different GPIOs to achieve this feature generically, npcx ec switches different interfaces and chip-select pins via several modules as ECTS in FIU and DEVCNT/DEV_CTLx in SCFG (System Configuration) instead.

Case 1: GPIOs for different CS pins

spi@f0006000 {
	cs-gpios = <&creg_gpio 0 GPIO_ACTIVE_HIGH>,
		   <&creg_gpio 1 GPIO_ACTIVE_HIGH>;
			   
	w25q128bv: w25q128bv@0 {
		compatible ="jedec,spi-nor";
		size = <0x8000000>;
		reg = <0>;
		...
	};
	
	w25q80:w25q80@1 {
		compatible ="nuvoton,npcx-fiu-nor";
		size = <0x800000>;
		reg = <1>;
		...
	}
};

Second, npcx FIU supports Direct Read Access (DRA) mode for faster flash reading and User Mode Access (UMA) mode for customized spi transactions. In the previous implementation, we only adopt the UMA mode. In this PR, the flash driver uses DRA mode directly to implement flash_read() API for better performance, especially when Quad/4-byte address mode enables. After applying this PR, the nor flash dt nodes looks like

Case 2: NPCX qspi-flash dt nodes

&qspi_fiu0 {
	status = "okay";
	
	int_flash: w25q40@0 {
		compatible ="nuvoton,npcx-fiu-nor";	
		size = <0x400000>; /* 4194304 bits = 512K Bytes */
		reg = <0>;
		status = "okay";

		/* quad spi bus configuration of nor flash device */
		qspi-flags = <NPCX_QSPI_SW_CS1>;
		mapped-addr = <0x64000000>;
		pinctrl-0 = <&int_flash_sl>;
		pinctrl-names = "default";
	};

	ext_flash: w25q256f@1 {
		compatible ="nuvoton,npcx-fiu-nor";
		quad-enable-requirements = "S2B1v1"; /* QE enabled */
		enter-4byte-addr = <0x85>; /* 4-byte addr support */
		size = <0x10000000>; /* 268435456 bits = 32M Bytes */
		max-timeout = <86784>;
		reg = <1>;
		status = "okay";

		/* quad spi bus configuration of nor flash device */
		qspi-flags = <NPCX_QSPI_SW_CS1>;
		mapped-addr = <0x64000000>;
		pinctrl-0 = <&fiu_ext_io0_io1_clk_cs_gpa4_96_a2_a0
			     &fiu_ext_quad_io2_io3_gp93_a7
			     &ext_flash_tris_off>;
		pinctrl-names = "default";
	};
};

The users can access the different nor flashes on qspi bus module by Zephyr flash APIs. We needn't care about pin-muxing, chip selection, and additional QE/4-byte settings between accessing the different flash interfaces. It looks like this:

rc = flash_read(DEVICE_DT_GET(DT_NODELABEL(int_flash)), ...);
/* do something after getting data from internal flash */
rc = flash_read(DEVICE_DT_GET(DT_NODELABEL(ext_flash)), ...);
/* do something after getting data from external flash */

In order to support cros_ec flash driver, this PR also supports extended flash operations APIs (CONFIG_FLASH_EX_OP_ENABLED) which includes UMA operation for status register read/write and specific operations for write protection. With CL4663912, it passed the following tests.

  1. zmake build --all --clobber
  2. Over 300 times reboot on ADL Chromebook with software sync flag enabled.
    (We upload the image with this PR before testing it every time by the script.)

@MulinChao MulinChao changed the title Npcx qspi fiu driver: flash: npcx: introduce npcx flash driver Jul 5, 2023
drivers/pinctrl/pinctrl_npcx.c Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
drivers/flash/Kconfig.npcx_fiu Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
dts/arm/nuvoton/npcx7m6fc.dtsi Outdated Show resolved Hide resolved
dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml Outdated Show resolved Hide resolved
drivers/flash/Kconfig.npcx_fiu Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Show resolved Hide resolved
@MulinChao MulinChao force-pushed the npcx_qspi_fiu branch 4 times, most recently from eb524bd to d944b96 Compare July 10, 2023 02:14
fabiobaltieri
fabiobaltieri previously approved these changes Jul 10, 2023
drivers/flash/flash_npcx_fiu_qspi.h Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
include/zephyr/drivers/flash/npcx_flash_api_ex.h Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_qspi.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
Comment on lines 313 to 330
/* Don't write more than a page. */
if (sz_write >= SPI_NOR_PAGE_SIZE) {
sz_write = SPI_NOR_PAGE_SIZE;
}

/* Don't write across a page boundary */
if (((addr + sz_write - 1U) / SPI_NOR_PAGE_SIZE)
!= (addr / SPI_NOR_PAGE_SIZE)) {
sz_write = SPI_NOR_PAGE_SIZE - (addr % SPI_NOR_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.

All this code is only meaningful for the first loop iteration, which basically means that it can be executed prior to entering the loop.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is based on the requirement of Page Program command. First, the write size cannot exceed the page size. Second, if the start address is not aligned with the page size, the write range cannot be across a page boundary. In the other flash drivers, such as spi_nor.c, flas_stm32_qspi.c, also have the same checks.

drivers/flash/flash_npcx_fiu_nor.c Show resolved Hide resolved
fabiobaltieri
fabiobaltieri previously approved these changes Jul 13, 2023
keith-zephyr
keith-zephyr previously approved these changes Jul 14, 2023
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
@MulinChao
Copy link
Collaborator Author

Hi @de-nordic, any further comment?

fabiobaltieri
fabiobaltieri previously approved these changes Jul 18, 2023
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
Comment on lines 318 to 330
while (size > 0) {
size_t sz_write = size;

/* Don't write more than a page. */
if (sz_write >= SPI_NOR_PAGE_SIZE) {
sz_write = SPI_NOR_PAGE_SIZE;
}

/* Don't write across a page boundary */
if (((addr + sz_write - 1U) / SPI_NOR_PAGE_SIZE)
!= (addr / SPI_NOR_PAGE_SIZE)) {
sz_write = SPI_NOR_PAGE_SIZE - (addr % SPI_NOR_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.

Because your MCU does not have source alignment you can just make this:

size_t sz_write;

/* This is max that the first, or any, write can take, which is SP_NOR_PAGE_SIZE */
if (size >= SPI_NOR_PAGE_SIZE) {
		sz_write = SPI_NOR_PAGE_SIZE;
}

/* Correct the first write to not go through page boundary */
size_t overflow = (addr + sz_write) & (SPI_NOR_PAGE_SIZE - 1);
sz_write -= overflow;
/* Now sz_write is reminder needed for addr to align to page boundary */

/* This is still valid test, as nothing has been written yet */
while (size > 0) {
    /* Write something */
    flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN);
    ret = flash_npcx_uma_write_by_addr(dev, SPI_NOR_CMD_PP,  tx_buf, sz_write, addr);
    if (ret != 0) {
	break;
    }
    ret = flash_npcx_nor_wait_until_ready(dev);
    if (ret != 0) {
        break;
    }
    size -= sz_write;
    addr += sz_write;
    tx_buf += sz_write;
    /* On the first run the sz_write was set to max bytes that would not cross the page boundary,
        but not more than page size and no more than size; for each next run the addr is now aligned to page boundary,
        so try to either write full page or what has left of size */
    if (size > SPI_NOR_PAGE_SIZE) {
        sz_write = SPI_NOR_PAGE_SIZE;
    } else {
         sz_write = size;
    }
}

Correct me if I have missed something, and the change is up to you, but I think that this significantly simplifies the loop and reduces branching within it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the detailed description. I got your point and will update a new version for it. Regarding overflow variable, we might need to check whether the addr plus sz_write cross the page boundary. Or the size of the first write might be zero.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

Add a new pinctrl type to control peripheral modules' specific IO
characteristics such as tri-state, the power supply type selection (3.3V
or 1.8V), and so on. In NPCX series, the corresponding registers/fields
are irregular. This CL wraps these definitions to dt nodes and put them
in pinctrl property if needed.

Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
@MulinChao
Copy link
Collaborator Author

Seems all #define XXXXXXX in this PR have compliance failures, API_DEFINE: do not specify a non-Zephyr API for libc. I have rebased to ToT but this symptom still occurred. Have no idea how to fix it.

@fabiobaltieri
Copy link
Member

fabiobaltieri commented Jul 19, 2023

That

Seems all #define XXXXXXX in this PR have compliance failures, API_DEFINE: do not specify a non-Zephyr API for libc. I have rebased to ToT but this symptom still occurred. Have no idea how to fix it.

That's fixed, sorry about it, retried the check, it should pass now.

keith-zephyr
keith-zephyr previously approved these changes Jul 19, 2023
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
drivers/flash/flash_npcx_fiu_nor.c Outdated Show resolved Hide resolved
This CL attempts to implement npcx's flash driver instead of the
original one (npcx spi driver plus spi_nor flash driver).

Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
@de-nordic
Copy link
Collaborator

@MulinChao Can you make another PR with release notes update documenting the addition of the driver? Thanks.

@carlescufi carlescufi merged commit f34fff9 into zephyrproject-rtos:main Jul 20, 2023
17 checks passed
@MulinChao
Copy link
Collaborator Author

@MulinChao Can you make another PR with release notes update documenting the addition of the driver? Thanks.

Sure. Please refer to PR 60660

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.

None yet

7 participants