S32G399A octal DTR reads fail with Macronix MX66UM2G45G QSPI flash Hi Community, We have a custom board based on the S32G399A-RDB3 reference design. The main change to the boot flash is that we replaced the MX25UW51245G (64 MB) with a Macronix MX66UM2G45G (256 MB, 1.8 V octal, JEDEC ID C2 80 3C). Everything works in 1-1-1 SPI. We cannot get 8D-8D-8D (octal DTR) reads to return correct data, and we would like help from NXP. We also could not find this part in any S32 BSP release up to bsp48.0, although AMD's U-Boot has supported it since 2024.1. Software TF-A bsp43.0-2.10.7, U-Boot bsp43.0-2022.04, Linux bsp43.0 (6.6.52) BootROM QSPI parameters: mx66_sim133sdr.bin (512 bytes, "OPI SDR 133 MHz"), taken unchanged from S32 Design Studio 3.6.1, Platform SDK S32XX 4.0.0, processors/S32G399A/.../quadspi/default_boot_images/. We did not generate it with U-Boot's s32cc_qspiparams tool. U-Boot changes: the flash ID entry for 0xC2803C, plus the octal-SDR soft reset. The BootROM leaves the flash in OPI SDR, and without the reset RDID returns 00 00 00. What works: - Boot from QSPI at 1-1-1, 133 MHz (~16 MB/s), in BootROM, TF-A, U-Boot and Linux. - Linux reads and writes, after we forced the IP-command path. With the flash in 1-bit mode, the AHB direct-map read path in spi-fsl-qspi.c causes a synchronous external abort or a hang. What we did to enable octal DTR in U-Boot 1. Set spi-tx-bus-width / spi-rx-bus-width to 8. The flash then negotiates and enables 8D-8D-8D: opcode 0xEE, octal_dtr_enable() returns 0, and probe reports 256 MiB. 2. Found a dummy-cycle mismatch. SFDP gave 14 dummy cycles, but the flash defaults to 20 (CR2 at 0x300). We now program CR2[0x300] = 0 (20 cycles) and set read_dummy = 20. Before this fix, reads returned random data that changed on every read of the same address: *** Warning - bad CRC, using default environment
Too large ELF file, size: 3568570404 <- PFE firmware header, read 1
Too large ELF file, size: 1226703397 <- same header, read 2
Bad Linux ARM64 Image magic! 3. Read the ID back in DTR mode: 3c 3c 3c 3c c2 c2. Both correct values come back, so we believe the flash really is in octal DTR. The problem Expected first bytes at the kernel offset: 1f 20 03 d5 19 80 31 14. The controller registers (read individually) are: MCR 030f00cc SMPR 33000000 DLLCRA c280000d
DLCR 40ff40ff DLLSR 8000c078 (both DLLs locked)
FR 09000001 (no DLPFF flag) - MCR DQS source = external (driver default for DDR): we get only 2 DTR clocks of data, then zeros: 1f 20 1f d5 00 00 00 00. The result is deterministic, and the controller reports a successful transfer. - MCR DQS source = internal (MCR[25:24] = 1): all the data arrives, but one DDR edge lags the other by exactly one clock: expected: 1f 20 | 03 d5 | 19 80 | 31 14
read: 1f 20 | 1f d5 | 03 80 | 19 14 | 31 .. The second byte of every pair is correct. The first byte of every pair is the correct sequence, delayed by one clock. DQS source sweep (MCR[25:24], BSWAP on/off), first 12 bytes read: bswap src MCR data result
on 2 020f00cc 19 80 19 19 14 14 31 14 00 00 00 00 bad
on 3 030f00cc 1f 20 1f d5 00 00 00 00 00 00 00 00 bad
off 0 000f00cc 31 0c 00 1d 55 02 19 18 31 20 00 00 bad
off 1 010f00cc 1f 20 1f d5 03 80 19 14 31 00 00 00 bad
off 2 020f00cc 80 19 19 19 14 14 14 31 00 00 00 00 bad
off 3 030f00cc 20 1f d5 1f 00 00 00 00 00 00 00 00 bad What we swept, with a full disable -> configure -> enable -> DLL-lock cycle each time (none fixed it): - SMPR DLLFSMPFA/FB_NTH 0-7, with DLP on and off - MCR END_CFG 0-3, with SFACR BSWAP on and off: this only reorders the same wrong bytes - MCR DQS source 0-3 - SMPR DDRSMP 0-7, with FSPHS on and off: no effect at all on the data Code changes (test builds only, on top of the bsp43.0 sources) TF-A fdts/s32cc-nxp-flash-macronix.dtsi (the DTB that U-Boot uses): mx66um2g45g@0 {
compatible = "jedec,spi-nor";
spi-tx-bus-width = <8>; /* was 1 */
spi-rx-bus-width = <8>; /* was 1 */
}; U-Boot drivers/mtd/spi/spi-nor-core.c, spi_nor_macronix_octal_dtr_enable(), before CR2[0x0] is switched to DTR OPI: u8 dc = 0x00; /* CR2[0x300] = 0 -> 20 dummy */
write_enable(nor);
op = (struct spi_mem_op)
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRCR2, 1),
SPI_MEM_OP_ADDR(4, 0x300, 1),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(1, &dc, 1));
spi_mem_exec_op(nor->spi, &op);
spi_nor_wait_till_ready(nor);
nor->read_dummy = 20; /* SFDP gave 14 */ U-Boot drivers/spi/fsl_qspi.c, enable_octal_ddr(), DQS source test (internal DQS instead of the octal_ddr_conf default DQS_EXTERNAL): mcr |= octal_ddr_conf.mcr;
mcr &= ~QUADSPI_MCR_DQS_EXTERNAL; /* clear MCR[25:24] */
mcr |= QUADSPI_MCR_DQS_INT_PAD; /* MCR[25:24] = 1 */
qspi_writel(q, mcr, base + QUADSPI_MCR); The register sweeps used a test U-Boot command that repeats the full enable_octal_ddr() sequence (MDIS=1, program MCR/SMPR/DLCR/SFACR, MDIS=0, wait for DLL lock) for each setting, then reads 512 bytes 3 times. Board side: DQS is pinmuxed (pads 85-93, IMCR 540-548). Questions 1. Is external DQS required for 8D-8D-8D at 133 MHz on the S32G3 QuadSPI? Is "2 clocks then zeros" a known symptom of a missing or bad DQS return? 2. Is internal DQS (loopback) supported in DDR mode? If so, which register settings fix the one-clock skew between edges? DLLCRA slave-delay settings, perhaps? 3. Do you have validated QuadSPI settings (MCR/SMPR/DLLCRA/FLSHCR), or a BootROM parameter set, for the MX66UM2G45G or another 1.8 V Macronix octal part on S32G3? The same S32DS folder also has mx66_sim133ddr.bin. Has that octal DTR boot image been validated on S32G3, and on which board? 4. Is the AHB read path in the Linux spi-fsl-qspi driver validated only for octal DTR? Is it expected to fault when the flash runs in 1-1-1? 5. Is NXP planning to add the MX66UM2G45G (JEDEC ID C2 80 3C) to the S32 BSP? We checked the U-Boot, Linux and TF-A releases up to bsp48.0 and found no entry for it. AMD's U-Boot fork (u-boot-xlnx) has supported this part with octal-DTR read and program since its 2024.1 release, and mainline U-Boot supports its 1 Gbit sibling, the MX66UM1G45G (C2 80 3B). If support is planned, which BSP release is it targeted for? Would it include validated QuadSPI and BootROM parameters for octal DTR? We can share full logs and the register sweep tables. Thank you.
View full article