Repository navigation
XM530/XM550 SPI NAND: driver and images - #16
Conversation
The XM530/XM550 flash controller also drives SPI NAND: OP1 runs page read, program execute and block erase with the row in ADDR, OP2 the reset, and OP3/OP4 move the ID, the features and a whole page through the controller's 4 KiB RAM at its column offsets. Ported from the vendor U-Boot 2014.04 xmsfc_v2_nand.c as a legacy raw NAND driver (NAND_XMSFC): - cmdfunc on whole commands instead of the vendor's byte-by-byte cmd_ctrl assembly; - the parts of the vendor table (W25N01GV, W25N02GV, GD5F1GQ4U) as full-ID nand_flash_dev entries for nand_scan_ident(), instead of the vendor's patch to nand_base.c; - the part's on-die ECC result (feature C0) reported through ecc.read_page as corrected bitflips or a failure, where the vendor ran NAND_ECC_NONE; - feature A0 cleared before each program and erase, as the vendor does. Under qemu-hisilicon's NAND model: the 128 MiB part is detected, the environment saves to NAND, UBI attaches and a UBIFS rootfs mounts.
openipc/nand_config, appended for NAND images, swaps the NOR driver for
NAND_XMSFC, puts the environment at 0xc0000 and enables MTD partitions,
UBI and UBIFS -- the layout and recovery of openipc-hisilicon's NAND
targets: 768k(boot), 256k(env), the rest one UBI device with the kernel
at /boot/uImage inside the UBIFS rootfs. build.sh builds xm530 and xm550
twice, into output/u-boot-<soc>-{nor,nand}.bin.
How the XM530 boots from SPI NAND is not documented, and Xiongmai never
built a NAND U-Boot from this SDK. The image follows the only evidence,
the vendor xm530.h's unused SPI NAND block: U-Boot is linked at
0x60001000, the controller window, behind a 4 KiB header, which here
starts with an absolute jump to it, so the image reaches U-Boot whether
the ROM enters at the window or at its 0x08000000 alias. Unverified on
silicon; CLAUDE.md says so.
The images are 372 KiB of the 768 KiB boot partition. Under
qemu-hisilicon's NAND model, which implements the same guess: xm530 and
xm550 boot to the prompt, load /boot/uImage from a UBIFS rootfs and
start the kernel with mem= first; from an erased NAND, TFTP recovery
(ur) creates the UBI volumes, writes the rootfs and boots it after the
reset. The OpenIPC XM530 kernel itself has no SPI NAND driver, so it
cannot mount that root yet.
PR Summary by QodoAdd XM530/XM550 SPI NAND driver and boot images
AI Description
Diagram
High-Level Assessment
Files changed (7)
|
Code Review by Qodo
1. NAND images enter code in the wrong state
|
| hdr = bytearray(b'\xff' * 0x1000) | ||
| hdr[0:8] = struct.pack('<II', 0xe51ff004, text) | ||
| open(dst, 'wb').write(bytes(hdr) + open(src, 'rb').read()) |
There was a problem hiding this comment.
1. Nand images enter code in the wrong state 🐞 Bug ≡ Correctness
build.sh prepends an ARM-state ldr pc instruction that jumps to the even CONFIG_SYS_TEXT_BASE, while the linked entry code is built in Thumb state. When the ROM executes that header, the jump reaches the image entry without switching instruction state, before U-Boot can initialize or relocate.
Agent Prompt
## Issue description
The NAND header jumps in ARM state to a Thumb-built U-Boot entry, so the image cannot execute its entry code correctly.
## Fix Focus Areas
- build.sh[44-55]
- openipc/openipc_config[6-6]
## Recommended Fix
Make the header explicitly transfer into the instruction state used by the linked entry, and verify the resulting entry sequence for both proposed ROM addresses.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| writel(cfg1, V2_CFG1); | ||
| writel(CFG2_POLL, V2_CFG2); | ||
| writel(cmd, V2_CMD); | ||
| writel(row, V2_ADDR); | ||
| xmsfc_run(1); |
There was a problem hiding this comment.
2. Nand commands can poll the wrong status 🐞 Bug ≡ Correctness
xmsfc_row_cmd() enables controller status polling without setting its poll-command register for SPI NAND. The v2 NOR driver programs that register before polled operations, so a NAND boot following a NOR-configured controller can poll a stale NOR opcode during page reads, programming, or erases.
Agent Prompt
## Issue description
Polled NAND row operations leave the controller's status-poll command at its previous value, which may be a NOR opcode.
## Fix Focus Areas
- drivers/mtd/nand/raw/xmsfc_nand.c[143-152]
- drivers/mtd/spi/xmsfc.c[143-169]
## Recommended Fix
Configure the controller's poll command and required SPI NAND status address before enabling hardware polling, or disable hardware polling and rely on correctly checked software status reads.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| CONFIG_NAND_XMSFC=y | ||
| CONFIG_CMD_NAND=y | ||
| CONFIG_CMD_NAND_TRIMFFS=y | ||
| CONFIG_ENV_IS_IN_NAND=y |
There was a problem hiding this comment.
5. Nand users cannot update the kernel alone 🐞 Bug ≡ Correctness
Enabling CONFIG_ENV_IS_IN_NAND selects a medium environment with no ukwrite, although the shared uk command always runs ukwrite after downloading a kernel. On a NAND image, invoking run uk downloads the file but cannot write it; NAND recovery instead replaces the rootfs volume containing the kernel.
Agent Prompt
## Issue description
The shared kernel-update command invokes an undefined writer when the new NAND configuration selects the NAND environment.
## Fix Focus Areas
- openipc/nand_config[14-14]
- include/configs/openipc-common.h[77-90]
- include/configs/openipc-common.h[147-155]
## Recommended Fix
Provide an appropriate NAND-specific `uk` path for a kernel embedded in the rootfs, or remove and clearly replace the unsupported kernel-only command for NAND images.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Review follow-ups: - every controller operation gets a 100 ms deadline: a stuck controller is reported instead of hanging boot, and a failed ID read leaves no ID, so nand_scan_ident() finds no chip; - the busy poll (feature C0 OIP) also stops at 100 ms and returns an error; a program or erase that times out reports NAND_STATUS_FAIL, and a page read that times out comes back as uncorrectable instead of stale data. Rechecked under qemu-hisilicon's NAND model: xm530/xm550 smoke (two boots, env in NAND) and the erased-NAND TFTP recovery to kernel start.
SPI NAND for the XM530/XM550, on the same xmsfc v2 controller as NOR.
xmsfc: SPI NAND (
drivers/mtd/nand/raw/xmsfc_nand.c,NAND_XMSFC): legacy raw NAND ported from the vendorxmsfc_v2_nand.c. Against the vendor driver:cmdfuncon whole commands instead of byte-by-bytecmd_ctrl;nand_base.c;ecc.read_page, where the vendor ranNAND_ECC_NONE;openipc: NAND images.
openipc/nand_configgivesopenipc-hisilicon's NAND layout and recovery:768k(boot),256k(env),-(ubi), with the env at 0xc0000;/boot/uImageinside the UBIFS rootfs;urrecovery that creates the UBI volumes.build.shbuilds xm530/xm550 as-nor.binand-nand.bin.BOARD_SIZE_LIMITis 768 KiB less the header.Unverified on silicon
Nothing documents how the XM530 boots from SPI NAND, and Xiongmai never built a NAND U-Boot from this SDK. The image follows the only evidence, the vendor
xm530.h's unused NAND block: U-Boot is linked at 0x60001000 (the controller window), behind a 4 KiB header. That header starts with an absolute jump to U-Boot, so the image reaches it whether the ROM enters at the window or at its 0x08000000 alias.CLAUDE.mdsays so. The OpenIPC XM530 kernel also has no SPI NAND driver yet.Checked
Under qemu-hisilicon's NAND model (u-boot#152), which implements the same guess:
/boot/uImageloads from UBIFS, and the kernel starts withmem=first;urcreates the UBI volumes, writes the rootfs and boots it after the reset.NOR images are unchanged. Sizes: NOR about 194 KiB, NAND about 372 KiB.