2025-02-14 8:13 AM
I am working on getting a new board design with a STM32MP153F to boot from parallel SLC NAND flash. The flash chip is 1 GB, using the FMC interface with 16-bit I/O. What happens when writing flash via STMCubeProgrammer is the first 2160 bytes of each page are written correctly, but after that byte 2160 is repeated until the end of the page, including through the OOB part of the page. The page size is 4096 + 256 bytes.
As an example, I tried programming ARM Trusted Firmware at the beginning of flash. If I read back a page from u-boot using the nand dump command, the first 2160 bytes match exactly what is in the file. The remaining 2192 bytes will contain the same byte, whatever byte #2160 was. This happens for every page written. I get the same result if I write a page from the u-boot prompt using the nand write command.
For the device tree setup, I am following the STM32MP157A-EV1 as an example.
from the output from "nand info", the u-boot flash driver appears to be reading out the ONFI table correctly.
Device 0: nand0, sector size 256 KiB
Page size 4096 b
OOB size 256 b
Erase size 262144 b
ecc strength 8 bits
ecc step size 512 b
subpagesize 4096 b
options 0x00184202
bbt options 0x00060000
Any help is much appreciated. Thanks!
Solved! Go to Solution.
2025-02-19 7:54 AM - edited 2025-02-19 7:56 AM
I was able to fix this by adding nand-bus-width = <16> to the device tree (excerpt below).
&fmc {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&fmc_pins_d16>;
pinctrl-1 = <&fmc_sleep_pins_d16>;
status = "okay";
nand-controller@4,0 {
status = "okay";
nand@0 {
reg = <0>;
nand-on-flash-bbt;
nand-bus-width = <16>;
#address-cells = <1>;
#size-cells = <1>;
};
};
};
I'm not sure why this is necessary. u-boot does detect the 16-bit capability of the flash chip via ONFI. However, in when calling nand_set_defaults() to set up the function pointers for reading/writing flash, it is passing 0 for the value of busw (0 means 8-bit width), and so causing the 8-bit functions to be used. This value of busw was saved prior to the auto-detect logic. From the comments in the code , this is intentional. Maybe the intent is to make sure the flash controller supports 16 bits.
In any case, it is working now with nand-bus-width = <16> in the device tree.
/*
* Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
* override it.
* This is required to make sure initial NAND bus width set by the
* NAND controller driver is coherent with the real NAND bus width
* (extracted by auto-detection code).
*/
busw = chip->options & NAND_BUSWIDTH_16;
....
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(chip->options & NAND_BUSWIDTH_16);
chip->options |= busw;
nand_set_defaults(chip, busw);
2025-02-19 7:54 AM - edited 2025-02-19 7:56 AM
I was able to fix this by adding nand-bus-width = <16> to the device tree (excerpt below).
&fmc {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&fmc_pins_d16>;
pinctrl-1 = <&fmc_sleep_pins_d16>;
status = "okay";
nand-controller@4,0 {
status = "okay";
nand@0 {
reg = <0>;
nand-on-flash-bbt;
nand-bus-width = <16>;
#address-cells = <1>;
#size-cells = <1>;
};
};
};
I'm not sure why this is necessary. u-boot does detect the 16-bit capability of the flash chip via ONFI. However, in when calling nand_set_defaults() to set up the function pointers for reading/writing flash, it is passing 0 for the value of busw (0 means 8-bit width), and so causing the 8-bit functions to be used. This value of busw was saved prior to the auto-detect logic. From the comments in the code , this is intentional. Maybe the intent is to make sure the flash controller supports 16 bits.
In any case, it is working now with nand-bus-width = <16> in the device tree.
/*
* Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
* override it.
* This is required to make sure initial NAND bus width set by the
* NAND controller driver is coherent with the real NAND bus width
* (extracted by auto-detection code).
*/
busw = chip->options & NAND_BUSWIDTH_16;
....
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(chip->options & NAND_BUSWIDTH_16);
chip->options |= busw;
nand_set_defaults(chip, busw);