cancel
Showing results for 
Search instead for 
Did you mean: 

Linux 6.10 STM32MP157 QSPI driver: device_initcall vs late_initcall causes NAND/NOR issues on custom board

MarkoPetrov
Associate

Hello everbody!

I came across this issue while making a custom Yocto Scarthgap BSP image working with kernel version 6.10 for a custom STM32MP157 board, although I have come across the same issue on all 6.x versions between 6.0 and 6.10 and in even more severe format on kernel 6.12 (where SPI NAND and SPi NOR flash read ID bytes all 0's and don't work at all). Here are the major points while updating the Yocto BSP from Kirkstone to Scarthgap:

  • Kernel version jumped from 5.10 to 6.10 (this fork), and device trees were updated per available device trees in the fork, as well as mainline, and per STM32Wiki guidelines for device tree board files.
  •  TF-A jumped from 2.4 to 2.12 (this fork) and U-Boot jumped from 2020.10 to 2024.01 (this fork), also device trees and board files for U-Boot updated per available files.
  • BSP still uses the old trusted boot flow (TF-A BL2 -> TF-A minimal secure payload (SP_MIN) as BL32-> U-Boot proper), as there was no adequate support for OP-TEE to include it in the boot flow and it didn't fit in the time frame of the project (also because of client requests).
  • Major issues only came up with QSPI and the on-board SPI NAND and SPI NOR flash memories (only in Linux userspace, not in U-Boot)

Kernel has been built with multi_v7_defconfig with added support for the following:

# KED STM32MP157 support
CONFIG_INPUT_PWM_BEEPER=y
CONFIG_STM32_RPROC=y
CONFIG_PINCTRL_STM32MP157=y
CONFIG_STM32_IPCC=y
CONFIG_PWM_STM32=y
CONFIG_RPMSG_VIRTIO=y
CONFIG_RPMSG_TTY=y
CONFIG_RPMSG_CHAR=y
CONFIG_CAN_M_CAN=y
CONFIG_CAN_M_CAN_PLATFORM=y
CONFIG_MTD_SPI_NAND=y

Here is a snippet of the device tree files for the QSPI and SPI NAND/NOR nodes:

/* QSPI interface */
&qspi {
    status = "okay";
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&qspi_pins_som>;
    pinctrl-1 = <&qspi_sleep_pins_som>;
    reg = <0x58003000 0x1000>, <0x70000000 0x200000>;
	#address-cells = <1>;
	#size-cells = <0>;

	/* QSPI NOR for boot */
	flash0: flash@0 {
		status = "okay";
		compatible = "jedec,spi-nor";
		reg = <0>;

		spi-rx-bus-width = <4>;
		spi-tx-bus-width = <4>;
		spi-max-frequency = <8000000>; /* MX25R1635F is slow */

		/* Required for partitions when mtdparts in u-boot are used */
		#address-cells = <1>;
		#size-cells = <1>;

		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;

			partition@fsbl1 {
				reg = <0x0 0x40000>;
				label = "fsbl1";
			};

			partition@fsbl2 {
				reg = <0x40000 0x40000>;
				label = "fsbl2";
			};

			partition@fip {
				reg = <0x80000 0x140000>;
				label = "fip";
			};

			partition@env {
				reg = <0x1C0000 0x10000>;
				label = "env";
			};

			partition@env-redundant {
				reg = <0x1D0000 0x10000>;
				label = "env-redundant";
			};
			
			partition@user {
				reg = <0x1F0000 0x10000>;
				label = "user";
			};
		};
	};	
	/* QSPI NAND for rootfs and data */
	flash1: flash@1 {
		status = "okay";
		compatible = "spi-nand";
		reg = <1>;
		spi-rx-bus-width = <4>;
		spi-tx-bus-width = <4>;
		spi-max-frequency = <104000000>;

		/* Required for partitions when mtdparts in u-boot are used */
		#address-cells = <1>;
		#size-cells = <1>;

		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;

			partition@ubifs {
				reg = <0x0 0x20000000>;
				label = "ubifs";
				compatible = "linux,ubi";
			};
		};
	};
};

Here is a snippet of the device tree files for the QSPI pin configuraitons:

/* Pin configuration */
&pinctrl {
    ....
    qspi_pins_som: qspi_som@0 {
        pins1 {
            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QSPI_BK1_NCS */
                     <STM32_PINMUX('C', 0, AF10)>; /* QSPI_BK2_NCS */
            bias-pull-up;
            drive-push-pull;
            slew-rate = <3>;
        };
        pins2 {
            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QSPI_BK2_IO0 */
                     <STM32_PINMUX('E', 8, AF10)>, /* QSPI_BK2_IO1 */
                     <STM32_PINMUX('E', 9, AF10)>, /* QSPI_BK2_IO2 */
                     <STM32_PINMUX('E', 10, AF10)>, /* QSPI_BK2_IO3 */
                     <STM32_PINMUX('F', 6, AF9)>, /* QSPI_BK1_IO3 */
                     <STM32_PINMUX('F', 7, AF9)>, /* QSPI_BK1_IO2 */
                     <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
                     <STM32_PINMUX('F', 9, AF10)>, /* QSPI_BK1_IO1 */
                     <STM32_PINMUX('F', 10, AF9)>; /* QSPI_CLK */
            bias-disable;
            drive-push-pull;
            slew-rate = <3>;
        };
    };

    qspi_sleep_pins_som: qspi_sleep_som@0 {
        pins {
            pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QSPI_BK1_NCS */
                     <STM32_PINMUX('C', 0, ANALOG)>, /* QSPI_BK2_NCS */
                     <STM32_PINMUX('E', 7, ANALOG)>, /* QSPI_BK2_IO0 */
                     <STM32_PINMUX('E', 8, ANALOG)>, /* QSPI_BK2_IO1 */
                     <STM32_PINMUX('E', 9, ANALOG)>, /* QSPI_BK2_IO2 */
                     <STM32_PINMUX('E', 10, ANALOG)>, /* QSPI_BK2_IO3 */
                     <STM32_PINMUX('F', 6, ANALOG)>, /* QSPI_BK1_IO3 */
                     <STM32_PINMUX('F', 7, ANALOG)>, /* QSPI_BK1_IO2 */
                     <STM32_PINMUX('F', 8, ANALOG)>, /* QSPI_BK1_IO0 */
                     <STM32_PINMUX('F', 9, ANALOG)>, /* QSPI_BK1_IO1 */
                     <STM32_PINMUX('F', 10, ANALOG)>; /* QSPI_CLK */
        };
    };
    ....
};

After boot up, kernel logs show no initialization errors with neither QSPI, SPI NAND nor SPI NOR drivers. I have attached two kernel log files from boot up to shell, for both initcall levels, so you can look at it for more details. 

SPI NAND gets attached as UBI during boot up due to the fixed partition containing the compatible = "linux,ubi" filed. This is needed when using the SPI NAND as a rootfs (client request also, so a must). Mounting a UBI volume gets the following error message (full log attached as file):

root@stm32mp-t1000-multi:~# mount -t ubifs ubi0_0 /mnt/
[  133.520607] UBIFS (ubi0:0): Mounting in unauthenticated mode
[  133.525336] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 1012
[  133.550353] ubi0 error: ubi_io_write: error -5 while writing 4096 bytes to PEB 338:98304, written 0 bytes
[  133.558596] CPU: 0 PID: 1009 Comm: mount Not tainted 6.10.6-ked #1
[  133.564751] Hardware name: STM32 (Device Tree Support)
[  133.569893] Call trace: 
[  133.569909]  unwind_backtrace from show_stack+0x10/0x14
[  133.577602]  show_stack from dump_stack_lvl+0x54/0x68
[  133.582566]  dump_stack_lvl from ubi_io_write+0x4ec/0x620
[  133.588032]  ubi_io_write from ubi_eba_write_leb+0x9c/0x83c
[  133.593596]  ubi_eba_write_leb from ubi_leb_write+0xcc/0xe4
[  133.599058]  ubi_leb_write from ubifs_leb_write+0xa0/0x104
[  133.604620]  ubifs_leb_write from ubifs_write_node_hmac+0xcc/0x1a4
[  133.610783]  ubifs_write_node_hmac from ubifs_write_master+0x70/0x13c
[  133.617150]  ubifs_write_master from ubifs_mount+0x1368/0x15b8
[  133.623012]  ubifs_mount from legacy_get_tree+0x24/0x48
[  133.628179]  legacy_get_tree from vfs_get_tree+0x24/0xe4
[  133.633446]  vfs_get_tree from path_mount+0x2e8/0xa20
[  133.638512]  path_mount from sys_mount+0x1dc/0x230
[  133.643281]  sys_mount from ret_fast_syscall+0x0/0x54
[  133.648344] Exception stack(0xe0f39fa8 to 0xe0f39ff0)
[  133.653394] 9fa0:                   00000000 00000000 004f33a8 004f3a40 004f3398 00000000
[  133.661557] 9fc0: 00000000 00000000 004f33a8 00000015 b6f1b144 00000001 b6f10e3c 00000005
[  133.669716] 9fe0: b6f1afc4 beec7ac0 b6ef81af b6e79fca
[  133.675079] ubi0: dumping 4096 bytes of data from PEB 338, offset 98304
[  133.683517] ubi0 warning: ubi_eba_write_leb: failed to write data to PEB 338
[  133.689219] ubi0: recover PEB 338, move data to PEB 356
[  133.698577] ubi0 error: ubi_io_write: error -5 while writing 4096 bytes to PEB 356:4096, written 0 bytes
......
mount: /mnt: can't read superblock on ubi0_0.
       dmesg(1) may have more information after failed mount system call.
root@stm32mp-t1000-multi:~# mount -t ubifs ubi0_0 /mnt/
[  136.809080] UBIFS (ubi0:0): read-only UBI device
[  136.812565] UBIFS error (ubi0:0 pid 1013): ubifs_mount: cannot mount read-write - read-only media
[  136.824382] UBIFS (ubi0:0): read-only UBI device
[  136.828848] UBIFS (ubi0:0): Mounting in unauthenticated mode
[  136.877273] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "boroot", R/O mode
[  136.884219] UBIFS (ubi0:0): LEB size: 253952 bytes (248 KiB), min./max. I/O unit sizes: 4096 bytes/4096 bytes
[  136.894158] UBIFS (ubi0:0): FS size: 438067200 bytes (417 MiB, 1725 LEBs), max 1735 LEBs, journal size 9404416 bytes (8 MiB, 38 LEBs)
[  136.906098] UBIFS (ubi0:0): reserved for root: 0 bytes (0 KiB)
[  136.911886] UBIFS (ubi0:0): media format: w4/r0 (latest is w5/r0), UUID FB96E6EA-6E29-44C1-9292-3669CA2853BD, small LPT model
mount: /mnt: WARNING: source write-protected, mounted read-only.
root@stm32mp-t1000-multi:~# 

SPI NOR has no obvious errors, as raw read/write/erase works in linux userspace as well as U-Boot. The only problem with the SPI NOR that I have found is that after putting the board to sleep and setting the RTC as a wake-up source, the board wakes up with the following prompt that SPI NOR resume has failed:

root@stm32mp-t1000-multi:~# echo +20 > /sys/class/rtc/rtc0/wakealarm 
root@stm32mp-t1000-multi:~# echo mem > /sys/power/state 
[  187.930435] PM: suspend entry (s2idle)
[  187.934373] Filesystems sync: 0.001 seconds
[  187.942172] Freezing user space processes
[  187.946195] Freezing user space processes completed (elapsed 0.001 seconds)
[  187.951851] OOM killer disabled.
[  187.954991] Freezing remaining freezable tasks
[  187.960681] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[  187.966779] printk: Suspending console(s) (use no_console_suspend to debug)
[  187.980319] smsc95xx 1-1.1:1.0 eth1: entering SUSPEND2 mode
[  201.376811] stm32-dwmac 5800a000.ethernet eth0: configuring for phy/rmii link mode
[  201.389698] dwmac4: Master AXI performs any burst length
[  201.389753] stm32-dwmac 5800a000.ethernet eth0: No Safety Features support found
[  201.389791] stm32-dwmac 5800a000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
[  201.391293] spi-nor spi0.0: resume() failed
[  201.800213] usb 1-1: reset high-speed USB device number 2 using ehci-platform
[  202.370166] usb 1-1.1: reset high-speed USB device number 3 using ehci-platform
[  202.735708] OOM killer enabled.
[  202.738780] Restarting tasks ... done.
[  202.747514] random: crng reseeded on system resumption
[  202.755193] PM: suspend exit
[  202.758380] smsc95xx 1-1.1:1.0 eth1: Link is Down
root@stm32mp-t1000-multi:~# 

 

This all gets fixed the either:

  • Patching the QSPI driver to be initialized in the late_initcall phase of the kernel, which also forces the SPI NAND and SPI NOR drivers to be pushed to late_initcall due to the dependency of the QSPI driver, or
  • Patching the SPI NAND and SPI NOR drivers separately to late_initcall instead of device_initcall

The patch for the QSPI driver would be the following modification on drivers/spi/spi-stm32-qspi.c :

static struct platform_driver stm32_qspi_driver = {
	.probe	= stm32_qspi_probe,
	.remove_new = stm32_qspi_remove,
	.driver	= {
		.name = "stm32-qspi",
		.of_match_table = stm32_qspi_match,
		.pm = &stm32_qspi_pm_ops,
	},
};
// module_platform_driver(stm32_qspi_driver);

// patch: substitute module_platform_driver for init function with late_initcall
static int __init qspi_driver_init(void)
{
    return platform_driver_register(&stm32_qspi_driver);
}

late_initcall(qspi_driver_init);

Very similarly would be done for SPI NAND/NOR, only using the spi_mem_driver_register function.

Here is the SPI NAND UBI mount after patching the drivers:

root@stm32mp-t1000-multi:~# mount -t ubifs ubi0_0 /mnt/
[ 1448.490250] UBIFS (ubi0:0): Mounting in unauthenticated mode
[ 1448.495216] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 1008
[ 1448.545125] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "boroot"
[ 1448.551187] UBIFS (ubi0:0): LEB size: 253952 bytes (248 KiB), min./max. I/O unit sizes: 4096 bytes/4096 bytes
[ 1448.561137] UBIFS (ubi0:0): FS size: 438067200 bytes (417 MiB, 1725 LEBs), max 1735 LEBs, journal size 9404416 bytes (8 MiB, 38 LEBs)
[ 1448.573080] UBIFS (ubi0:0): reserved for root: 0 bytes (0 KiB)
[ 1448.578839] UBIFS (ubi0:0): media format: w4/r0 (latest is w5/r0), UUID FB96E6EA-6E29-44C1-9292-3669CA2853BD, small LPT model
root@stm32mp-t1000-multi:~# cd /mnt/
root@stm32mp-t1000-multi:/mnt# ls
abc     bin     boot    dev     etc     home    lib     media   mnt     opt     proc    run     sbin    sys     tmp     usr     var     vendor
root@stm32mp-t1000-multi:/mnt# touch test22
root@stm32mp-t1000-multi:/mnt# ls
abc     bin     boot    dev     etc     home    lib     media   mnt     opt     proc    run     sbin    sys     test22  tmp     usr     var     vendor
root@stm32mp-t1000-multi:/mnt# rm test22
root@stm32mp-t1000-multi:/mnt# ls
abc     bin     boot    dev     etc     home    lib     media   mnt     opt     proc    run     sbin    sys     tmp     usr     var     vendor
root@stm32mp-t1000-multi:/mnt# cd
root@stm32mp-t1000-multi:~# umount /mnt/
[ 1468.033498] UBIFS (ubi0:0): un-mount UBI device 0
[ 1468.036870] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" stops
root@stm32mp-t1000-multi:~# 

And here is the SPI NOR resume after wake up from sleep with RTC:

root@stm32mp-t1000-multi:~# echo +20 > /sys/class/rtc/rtc0/wakealarm 
root@stm32mp-t1000-multi:~# echo mem > /sys/power/state 
[   48.610049] PM: suspend entry (s2idle)
[   48.623006] Filesystems sync: 0.010 seconds
[   48.631778] Freezing user space processes
[   48.635704] Freezing user space processes completed (elapsed 0.001 seconds)
[   48.641454] OOM killer disabled.
[   48.644591] Freezing remaining freezable tasks
[   48.650286] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[   48.656358] printk: Suspending console(s) (use no_console_suspend to debug)
[   48.670117] smsc95xx 1-1.1:1.0 eth1: entering SUSPEND2 mode
[   63.285915] stm32-dwmac 5800a000.ethernet eth0: configuring for phy/rmii link mode
[   63.298707] dwmac4: Master AXI performs any burst length
[   63.298762] stm32-dwmac 5800a000.ethernet eth0: No Safety Features support found
[   63.298798] stm32-dwmac 5800a000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
[   63.709821] usb 1-1: reset high-speed USB device number 2 using ehci-platform
[   64.279776] usb 1-1.1: reset high-speed USB device number 3 using ehci-platform
[   64.661180] OOM killer enabled.
[   64.664246] Restarting tasks ... done.
[   64.671800] random: crng reseeded on system resumption
[   64.677043] PM: suspend exit
root@stm32mp-t1000-multi:~# [   64.682682] smsc95xx 1-1.1:1.0 eth1: Link is Down

I will try to get in contact with the linux kernel maintainers likely through their mailing lists and see If I can get a reply from them. Will be posting updates too.

0 REPLIES 0