Skip to content

novatek: 14 more SoCs (NT9852x, NT98532/533, NT9832x, NT98332/633) and the loader's MMU hand-off - #99

Merged
dimerr merged 41 commits into
openipc-novatekfrom
novatek/more-socs
Nov 4, 2026
Merged

dimerr merged 41 commits into
openipc-novatekfrom
novatek/more-socs

Conversation

@dimerr

@dimerr dimerr commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

Adds 14 Novatek SoCs to openipc-novatek, which now builds 16 (the NT98562 and NT98566 were already here).

Die SoCs Notes
NA51089 NT98560, NT98561, NT98562, NT98566 560/561 are new; NT98560 is built for the SDK board's external DDR
NA51055 NT98520, NT98522, NT98523, NT98525 loader imported from the NT9852x SDK, with an LZMA decoder added so U-Boot fits its slot
NA51084 NT98528, NT98529 NT98529 cleared for 1.2 GHz
NS02501 NT98532, NT98533 loader from the NT98532/533 SDK with an LZMA U-Boot and device tree
NA51068 (DVR/NVR) NT98321, NT98323 loader from the NT9832x SDK; SPI NOR only (new FTSPI020 driver)
NA51103 / NA51090 (NVR) NT98332, NT98633 AArch64; the image replaces only the board's U-Boot slot and keeps its own loader and BL31; new SPI NAND driver for NT98633

The image layout is unchanged: loader at 0, FDT at 0x10000, U-Boot at 0x20000, environment at 0x40000.

Fix for the existing NT98562/566 port (likely #95)

Novatek's loader starts U-Boot with the MMU and the D/I caches still on (SCTLR 0x00c5187d, page table at 0x1018000). The port skipped cpu_init_cp15 and does no cache maintenance, so Ethernet and flash DMA ran against a live data cache. Loading anything at OpenIPC's default baseaddr also overwrote the loader's page table and hung U-Boot. d96348d sets SKIP_LOWLEVEL_INIT_ONLY, so U-Boot turns the MMU and caches off at entry. That matches #95 (an NT98566 with no ping and TFTP timeouts). QEMU doesn't model caches, though, so only a board can confirm it.

Testing

Nothing has been tested on real hardware yet. Everything below was run in QEMU (OpenIPC/qemu-bench#222), which runs each image's own loader from a mask ROM model, DDR training included:

  • All 16 targets build with CI's toolchains (reproduced in Ubuntu 24.04) and pass a two-boot smoke test.
  • DHCP, ping, a 3 MB TFTP with matching crc32, an unaligned sf write/read and SD write/read pass on representative SoCs of every die.
  • NT98562 boots OpenIPC lite to the login prompt; the SDK kernels boot on NT98525, NT98323 and NT98533.

Known limits

  • External DDR: the external-DDR parts (NT98560, NT98520/525/528/529, NT98321/323) use the SDK boards' DDR settings. A board with different DDR needs its own loader build.
  • NT98528/529 toolchain: their loader stops after DDR training when built with arm-linux-gnueabi, cause unknown. arm-none-eabi (what CI uses) works, and build.sh refuses the Linux toolchain for those two.
  • CPU clock: NS02501 and NA51068 keep whatever CPU clock the loader set.
  • Not supported: NT98321 on SPI NAND. NS02201/02301/02302/02401 and NA51102 have no loader, board trees or QEMU machine to work from.

The CI and README changes are in a separate PR against openipc.

dimerr added 30 commits November 3, 2026 20:58
Both are the NA51089 die, chip ID 0x7021, as the NT98562 and NT98566;
the SDK (nt9856x v1.01.007) has a board and a prebuilt loader for each.

- NT98561: the NT98562's 64 MiB DDR2 package. The SDK's
  cfg_561_IPCAM1_EVB differs from cfg_562_IPCAM1_EVB in the firmware's
  name alone; its loader runs the DDR at 522 MHz.
- NT98560: external DDR3, 512 MiB on cfg_560_IPCAM1_EVB, at 933 MHz.
  The loader reads that DDR's profile, ConfigRam/560/51089A_DRAM1_933_
  4096.ini, so build.sh passes the loader its size too. Linux gets the
  first 256 MiB by default (osmem), as on the SDK's board, and the media
  pool the rest. U-Boot stays at 0x03900000, below 64 MiB, as on the
  other parts: the loader reads our device tree, not the SDK's, which
  puts it at 0x1E000000.

The DDR size is now NVT_DDR_SIZE in Kconfig.

Verified under qemu-hisilicon's nt98560 and nt98561 machines (OpenIPC/
qemu-hisilicon#222), which run the image's own loader: it reports
560_DRAM1_933_4096Mb / 561_DRAM1_522_512Mb as the SDK's prebuilt
loaders do, trains the DDR, unpacks U-Boot, and U-Boot reaches the
prompt twice, the second time with the environment the first saved.
The loader of Novatek's NT9852x Linux SDK, release
nt9852x_loader_release_v2.05.013 (the same sources as the SDK tree's
na51055_ldr), as the SDK ships it: the boot flow sources (LibExt/
LIBExt_src/Ctrl_Flow, Project/Model/Src), the headers, the make system,
the DRAM parameter tables of the NT985xx parts (Tools/ConfigRam: 520,
522, 523, 523_A, 525, 528, 529), and what Novatek ships as binaries: the
driver and DRAM libraries (ARC/Lib/Release) and the Linux host tools
(Tools/Bin: nvt-ld-op, bfc, Configram520, encrypt_boot,
encrypt_boot_dump).

One loader serves both dies of the SDK: NA51055 (chip ID 0x4821;
NT98520/522/523/525, ModelConfig_EMU_EVB.txt) and NA51084 (0x5021;
NT98528/529, ModelConfig_EMU_EVB_528.txt). The mask ROM loads it into
SRAM; it trains the DDR, reads the device tree at flash block 1, loads
U-Boot as the tree says and starts it, as NA51089's does.

Left out: the documentation, the Windows tools and scripts, the ICE and
debugger scripts, the sample AES/RSA keys (secure boot is off), the
tables of the NT96xxx parts (570, 575, 580, NC520), and the build output
the archive carries (Project/Model/Loader520_Data, Loader525_Data and
the Ctrl_Flow objects), which a build would otherwise pick up.

.gitattributes keeps the vendor bytes as they are; .gitignore lets the
libraries in.
The NA51089 loader's changes (cf32065, 784be2b, 1098fc3),
made again for the NT9852x one, so that a distribution's Arm toolchain
builds it (arm-none-eabi, or arm-linux-gnueabi as U-Boot's):

- target("thumb2") is not a GCC target attribute: target("thumb");
- bin_info.h's header guard defined a different name than it tested;
- -fshort-enums: the vendor libraries are built with short enums;
- the link asks for neither libstdc++ nor libm, which nothing uses
  and Ubuntu's arm-none-eabi does not have;
- a raise() for libgcc's division by zero handler;
- the OP-TEE decrypt option follows its own setting (the vendor typo
  NA51089's MakeConfig.txt had too; both are Normal here).

And for OpenIPC's images:

- both models boot from the SPI NOR (STORAGEINT SpiFlash);
- LOADER_TYPE follows CHIP: the NA51084 parts (528, 529) take
  bl_func.h's stand-alone 528 flow, the others the 52x one. The SDK's
  make_combo_loader.sh got there by editing bl_func.h with sed before
  building MODEL=EMU_EVB_528; build.sh passes MODEL instead.
U-Boot is ~235 KiB, ~94 KiB in an LZMA BCL1 container: its 128 KiB slot
in the 256 KiB boot partition holds nothing larger. Novatek's LZ
(algorithm 9), the only method the NT9852x loader unpacks, leaves it at
~176 KiB. NA51089's loader calls the LZMA decoder in its mask ROM;
NA51055's mask ROM has none (its table holds memcpy, Dec2HexStr and the
efuse reader only), so the loader carries one: Igor Pavlov's public
domain LzmaDec, as U-Boot has it in lib/lzma, with the loader's memcpy
and a 32 KiB static heap for the probabilities (lc=3, lp=0 needs 16 KiB).

bl_load_uboot_from_flash() takes BCL1 algorithm 11 to it, as NA51089's
loader takes it to the ROM, and anything else to LZ_Uncompress() as
before. openipc/nvt-image.py's image is then the same on both dies.

The loader's image is limited to 32 KiB (64 KiB for the 528 flow).
Built in Thumb, at -Os, with _LZMA_SIZE_OPT, the decoder adds 4.6 KiB;
the 52x loaders end at 32722-32741 bytes, the 528/529 ones at 65047.
The loader of Novatek's NT9832x DVR/NVR SDK v1.02.024, release
na51068_loader_v1.08.014 (software/board/loader/source_code), as the SDK
ships it: the boot flow sources (LibExt/LIBExt_src/Ctrl_Flow,
Project/Model/Src), the headers, the make system, the model files, the
DRAM parameter tables of the parts it builds for (Tools/ConfigRam: 321,
323, 621, 623, NC321, NC323), and what Novatek ships as binaries: the
driver and DRAM libraries (ARC/Lib/Release) and the Linux host tools
(Tools/Bin: nvt-ld-op, bfc, Configram321, encrypt_boot,
encrypt_boot_dump).

The die is NA51068 (NT98321, NT98323): two Cortex-A9s, SRAM at
0xFE080000. The mask ROM loads the loader into SRAM; it trains the DDR,
reads the device tree at flash block 1 (0x10000 on NOR), loads U-Boot
from the tree's /nor/partition_uboot to /nvt_memory_cfg/uboot (a BCL1
container through its LZ decoder, whatever the algorithm field says;
anything else copied by the HEADINFO's length at 0x300) and starts it,
as NA51089's does. Its mask ROM exports no routines.

Left out: the git metadata the archive carries, the Jenkins scripts
(admin/), History.txt, the Windows tools and the ICE / debugger scripts
(*.exe, *.bat, *.ttl, gdb*), the sample AES/RSA keys and their tools
(aes.txt, rsa_*, rsa_genkey; secure boot is off), packtool (the make
system does not call it), and the build output the archive carries
(Project/Model/loader.bin, ld_d.tmp, and ld.script, which nothing reads).

.gitattributes keeps the vendor bytes as they are; .gitignore lets the
libraries in.
The NA51089 and NA51055 loaders' changes (cf32065, 38ec5ad),
made again for the NT9832x one, so that a distribution's Arm toolchain
builds it (arm-none-eabi, or arm-linux-gnueabi as U-Boot's):

- target("thumb2") is not a GCC target attribute: target("thumb");
- two header guards defined a different name than they tested
  (bin_info.h, nvt_rdata_sys.h), which GCC 15 makes an error;
- -fshort-enums: the vendor libraries are built with short enums;
- the link asks for neither libstdc++ nor libm, which nothing uses
  and Ubuntu's arm-none-eabi does not have.

Unlike the other two, no raise() is added: the DRAM remap libraries
(Remap_*.a) define one already.

Built with Ubuntu's arm-linux-gnueabi-gcc 15.2 (CHIP 323, SpiFlash):
LD98323A.bin, 65536 bytes as always (the image is padded to its 64 KiB);
the compressed part is 64464 bytes, 64664 with the SDK's Linaro 6.4
arm-eabi.
U-Boot, ~94 KiB in an LZMA BCL1 container on NA51089, has a 128 KiB slot
in OpenIPC's 256 KiB boot partition. The NT9832x loader unpacks BCL1
with Novatek's LZ alone, whatever the algorithm field says, which leaves
it far larger. Its library Compress.a has an LZMA decoder as well,
lzma_inflate(), which only the bound-U-Boot flow (UBOOT_BIND_ON,
bl_boot_bind_uboot()) calls, with the 64 KiB .lzma scratch area the
linker script reserves after the heap for it. bl_load_uboot_from_flash()
now takes BCL1 algorithm 11 to it, and anything else to LZ_Uncompress()
as before; openipc/nvt-image.py's image is then the same as on NA51089
and NA51055. The decoder reads the stream's own header (properties,
dictionary, the unpacked size) and returns the unpacked length, or -1.

Two NOR models for OpenIPC, made from the SDK's NAND ones:

- 323_DDR4_4GX1_NOR_EVB (the default MODEL now): 321_DDR4_8GX1_NAND_SYS
  with CHIP 323, SDRAM_SIZE 4096, DRAM_MUX FB, the SDK's
  cfg_98323_DDR4_4GX1_NOR_EVB board, as qemu-hisilicon's
  build-novatek-loader.sh derives its nt98323 loader;
- 321_DDR3_4GX1_NOR_EVB: 321_DDR3_4Gx1_NAND_SYS.

Both boot from the SPI NOR (STORAGEINT SpiFlash) and have no SD card
update at boot (STORAGEEXT NONE): with the card code and the decoder
the image does not fit its 64 KiB (65968 bytes compressed), without the
card code it is 60816; U-Boot does OpenIPC's SD recovery instead.

Verified under qemu-hisilicon (PR u-boot#222, -M nt98323,flash-file=, the mask
ROM model running the loader): the 323 loader built with Ubuntu's
arm-linux-gnueabi-gcc trains the DDR, reads the tree at 0x10000, finds
partition_uboot through nvtpack/index, unpacks an 80 KiB LZMA BCL1 test
image to 0x03900000 and starts it ("Single core ... jump 0x03900000").
38ec5ad passed -DLOADER_TYPE from Project/Model/Makefile, whose
sources do not read it; bl_func.c, which does, is built by
LibExt/LIBExt_src/Ctrl_Flow/Makefile, with its own C_DEFINE_EXT. So the
528 and 529 loaders took the 52x flow and stopped after the DDR
training.

With the 528 flow in, the 528 model's loader is 65800 bytes with the
LZMA decoder, past its 64 KiB; build.sh builds it without the loader's
own SD card update (STORAGEEXT=NONE), 62833 bytes.

Verified under qemu-hisilicon's nt98528 (OpenIPC/qemu-bench#222),
whose mask ROM model runs the image's loader: DDR1 and DDR2 trained,
U-Boot unpacked from its LZMA BCL1 container, the prompt reached twice,
the second time with the environment the first saved. Built with
arm-none-eabi 13.2 (Ubuntu 24.04, as CI) and with the SDK's Linaro 6.4
arm-eabi; arm-linux-gnueabi's build stops after the training (open).
gd->ram_size is a phys_size_t, 64 bits on AArch64: "%ld" warned there.
Print it as an unsigned long. Built for nt98562 (arm) and nt98332
(aarch64), no warning.
NA51103 is Novatek's two Cortex-A53 NVR die. Its boards boot: mask ROM,
the board's loader (Xiongmai's FW98332A on the NBD80N36RA; no loader
source exists for this die), DDR training, a warm reset (RMR) of the
A53s into AArch64, the board's BL31 (TF-A v2.2), then U-Boot. BL31 enters
BL33 at the address in its own header (0x1E000000, the loader's
/nvt_memory_cfg/uboot) with a fixed SPSR 0x3C9: AArch64 EL2h, so U-Boot
is an AArch64 one. The vendor's _a32 configs for the die are template
copies of NA51000's and cannot be entered from this BL31.

- arch/arm/Kconfig: ARCH_NOVATEK selects CPU_V7A only without ARM64;
  NVT_NA511XX selects ARM64 (mach-novatek/Kconfig), TARGET_NT98332.
- mach/na511xx.h: the blocks at 0x2_F000_0000 (vendor
  arch-nvt-na51103_a64/IOAddress.h, the dump's tree), SHMINFO at
  0xA00000, BL31 at 0x1F00000, U-Boot's region 0x1E000000 + 32 MiB.
  mach/hardware.h picks a die's header for the drivers and the board.
- soc.c: HEADINFO "ub51103 ", BinFlag 2 as the vendor's SMP builds;
  the vendor's watchdog reset (CG 0x9C bit 12, 0x7C bit 4); the MMU map
  (DDR normal, 0x2_F000_0000 device: with the MMU off every access is
  a device one and U-Boot's unaligned ones fault); nvt_loader_fdt().
- board/novatek/na511xx: the loader's tree to ${fdtaddr}, relocation
  inside the U-Boot region, mem=/hdal-memory/media split at ${osmem}
  (the media node's 4-cell addresses), and the first MAC's pins, clocks
  and PHY reset as eth_na51103.c (RGMII, RMII, embedded PHY).
- novatek.h: UART at 48 MHz, the architected timer, osmem 0x15e00000
  and staging at 0x2000000 as the board's firmware; ubwrite writes only
  U-Boot's slot (0x20000) and openipc-common.h lets a SoC say so.
- MMC_NVT is NA51089's.

Verified under qemu-hisilicon nt98332 (-smp 3) from the Xiongmai dump
with U-Boot's slot replaced: ROM -> FW98332A -> BL31 -> U-Boot 2022.10
at EL2, "chip id 8b20", 1 GiB; and the dump's own kernel (4.19.148
arm64, repacked as an LZMA uImage) boots from it: PSCI CPU1, squashfs
root, Xiongmai's userland.
The NVR dies keep NA51089's flash controller at 0x2_F018_0000; what
differs is around it, as the vendor U-Boot's nvt_spinor_reset() and
nand_phy_config() do it per chip:

- clock CG 0x74 bit 10, reset CG 0x98 bit 1, divider CG 0x48 [21:16];
- pins TOP 0x04 [1:0] (bit 2 for the second chip select), TOP 0xA0;
- pad drive PAD 0x50, by clock; no clock auto-gate to hold off;
- TSLCH of 3 at least on NA51103, DLL input delay 0 (NA51090: 8);
- the clock is the tree's /nor clock-frequency (Xiongmai: 12 MHz);
- chip select 0 is SPI_CFG bit 3 clear.

Their FIFO is 128 bytes: a PIO read now waits for the bytes it takes or
a full FIFO, not for exactly 64 bytes, which a 128-byte FIFO holding the
tail of a longer read would never show (the count field also tops out at
31 words). Same waits as before on NA51089's 64-byte FIFO.

Verified under qemu-hisilicon nt98332, from the board's loader and BL31:
JEDEC ef4018 16 MiB; sf erase 256 KiB, sf write from 0x3000001 to
0x800003 0x2fffd bytes and sf read back to 0x4000002, crc32 equal
(c28efca1), the flash file holding the data and 0xff around it;
saveenv, reset, env loaded. nt98562 and nt98566 still pass the two-boot
smoke test.
The NA51103 / NA51090 MACs are the same Synopsys EQoS core with
Novatek's glue at +0x3000. Its CSR clock is the 150 MHz APB there, so
the MDC divider is fixed (CR 1, /62, as eth_na51103.c's mdc_div),
not read from NA51089's CG. Gigabit needs nothing more: the MAC
configuration already leaves PS/FES clear at 1000 Mb/s.

Verified under qemu-hisilicon nt98332, from the board's loader and BL31,
user networking: ping 192.168.1.107, dhcp (bound 192.168.1.15),
tftpboot of a 3 MB file with crc32 equal to the host's (e7287026), and
of a 2.8 MB kernel.
The board's loader (DDR training, BL31) and device tree are the
board's and stay: the image is U-Boot's slot alone,
output/u-boot-nt98332-nor.bin, 128 KiB for flash 0x20000..0x40000
(${ubwrite} writes it there). Xiongmai's FW98332A reads its tree's
partition_boot as a bare LZMA stream ("compress header 0x5D", 16 MiB
dictionary, end marker) and unpacks it to 0x1E000000; the HEADINFO is
filled in as for NA51089 (length, checksum). The OpenIPC NOR layout
follows unchanged: env 0x40000, kernel 0x50000, rootfs 0x250000.

- openipc/nvt-nvr-image.py: the slot (and, given a dump of the board's
  flash, a copy of it with the slot written, for a programmer).
- openipc/nt98332_config: text base 0x1E000000, caches on, load and
  staging address 0x2000000, the boot counter at 0x1E20000 (the other
  families' 0x1F20000 is BL31's secure megabyte here), no SD.
- openipc/nt98332.dts: what U-Boot reads of the board's tree, plain,
  for the emulator's stand-in loader; build.sh puts it with the slot
  into output/u-boot-nt98332-qemu.bin for CI's smoke test.
- build.sh: nt98332 with CROSS_COMPILE_A64 (aarch64-linux-gnu-).

U-Boot is 230 KiB, 90 KiB packed. Verified: the two-boot smoke test
passes on qemu-hisilicon nt98332 -smp 2 (stand-in loader) with
u-boot-nt98332-qemu.bin; the slot written into the Xiongmai dump boots
on nt98332 -smp 3 through the board's own FW98332A and BL31.
nt98562/nt98566/nt98560/nt98561 still build.
The NA51068 (NT98321, NT98323) has two of NA51089's Ethernet QoS MACs,
at 0xFCC00000 and 0xFCD00000, with the same glue and embedded PHY at
+0x3000 / +0x3800. The driver's state, rings and buffers move into a
per-MAC struct (two at most, in .bss as before), the registers are taken
from its base, and nvt_eqos_register() registers a MAC by name, base,
PHY interface and MDC divider. nvt_eqos_initialize() stays NA51089's
entry point, its one MAC "eqos" at NVT_ETH_BASE with the divider from
the CSR clock, so board/novatek/na51089 is unchanged.

Verified: nt98562 and nt98566 build; under qemu-hisilicon both MACs of
the nt98323 machine (-nic user twice) take a DHCP lease, answer ping
and pass a 3 MB tftpboot with the host's CRC32.
The NA51090 NVRs boot from SPI NAND (a W25N01GV on the N2032-8HDD) on
the flash controller nvt_sflash runs for NOR. This driver runs it the
same way, as a plain SPI master: a command and its address bytes, then
the data, the chip held selected by hand. PAGE DATA READ, GET FEATURE
polling, READ from the cache, PROGRAM LOAD/EXECUTE and BLOCK ERASE go
out byte for byte, a page and its spare area by DMA through one buffer.
The controller's own NAND mode, which the vendor U-Boot uses, is not
needed for that. The chip's on-die ECC is on, as the vendor runs it;
its status after a page read becomes the MTD layer's corrected/failed
counts. The raw NAND framework drives it through cmdfunc (non-DM,
SYS_NAND_SELF_INIT), with the parts' geometry from a table: W25N01GV,
W25N02KV, GD5F1GQ4UB, GD5F1GQ5UE, MX35LF1GE4AB, XT26G01C. Clock, pins
and PHY as the vendor's spinand.c does on NA51090, at the tree's /nand
clock (24 MHz on the NVR).

Verified under qemu-hisilicon nt98633, from the board's own FW98633A
and BL31 on its NAND dump: "NAND: 128 MiB"; nand erase 256 KiB, nand
write 192 KiB, nand read back, crc32 equal (23dc90b5) and the image
file holding the data; saveenv, reset, env loaded; nand erase.part ubi,
ubi part, ubi create/write/read of a 3 MB volume, crc32 equal to the
host's, and the volume intact after a reset. Only the on-die ECC's
"no error" path runs there: the model never reports ECC errors.
NA51090 is the four Cortex-A53 NVR die, 2 GiB on the N2032-8HDD. Its
boot chain is NA51103's: the board's loader (FW98633A), DDR training,
the RMR warm reset, the board's BL31 v2.2, which enters BL33 at its
header's address (0x3E000000 here) with SPSR 0x3C9, AArch64 EL2h.
U-Boot shares NA51103's code: the map differs in the watchdog
(0x110000), and the MAC is the one at 0x2_F021_0000, the boards'
tree's and Linux's eth0 (the vendor U-Boot's MAC1), set up as
eth_na51090.c's mac1_*: RGMII or RMII on either pad set, the PHY's
clock from the SoC, its reset on E_GPIO 17 or S_GPIO 19.

On SPI NAND the OpenIPC layer takes openipc-hisilicon's NAND medium:
the environment in the board's uenv partition (0x1A0000, two blocks),
UBI after it (0x1E0000), the kernel in the UBIFS rootfs;
mtdparts spi_nand.0:1664k(boot),256k(env),-(ubi), where boot is the
board's loader, tree, BL31 and U-Boot's slot (0xC0000, written alone
by ${ubwrite}). openipc-common.h gains that medium under
CONFIG_ENV_IS_IN_NAND; the NOR one is unchanged.

Verified under qemu-hisilicon nt98633 -smp 5, the board's loader and
BL31 from its NAND dump, U-Boot's slot and env replaced: U-Boot 2022.10
at EL2, "chip id bc21", 2 GiB; ping, dhcp, tftpboot of 3 MB with the
host's crc32 on the first -nic; and the dump's own kernel (4.19.148,
repacked as an LZMA uImage) with its initramfs: four CPUs through BL31's
PSCI, the SPI NAND and eth0 probed.
As for NT98332, the board's loader, tree and BL31 stay: the image is
U-Boot's slot, output/u-boot-nt98633-nand.bin, 896 KiB for NAND
0xC0000..0x1A0000, a BCL1 LZMA container (algorithm 11, its 64-bit size
field the 32-bit length twice, as the board's own U-Boot is packed).

- openipc/nt98633_config: text base 0x3E000000, caches on, the boot
  counter at 0x1E20000, no SPI NOR, the NAND driver, the environment in
  NAND, UBI and UBIFS.
- openipc/nt98633.dts: what U-Boot reads of the board's tree, for the
  emulator's stand-in loader; output/u-boot-nt98633-qemu.bin puts it at
  0x40000 and the slot at 0xC0000.
- build.sh: build_nvr takes the flash and the layout per SoC; nt98633.

U-Boot is 444 KiB, 169 KiB packed. Verified: the two-boot smoke test
passes on qemu-hisilicon nt98633 -smp 4 (stand-in) with a 128 MiB
image holding u-boot-nt98633-qemu.bin, and on nt98332 -smp 2; the slot
written into the NT98633 NAND dump boots on nt98633 -smp 5 through the
board's own loader and BL31.
What the board's loader and BL31 expect of U-Boot and why only its
slot is OpenIPC's, the two layouts, how to install, the peripherals,
and what was verified under qemu-hisilicon and what was not.
The loader starts U-Boot with its MMU, data and instruction caches on:
SCTLR 0x00c5187d, its translation table at 0x1018000 (in its DRAM area,
/nvt_memory_cfg/loader) mapping the DDR write-back write-allocate
(sections 0x...5de6) and the registers as device memory. This U-Boot is
built with SYS_DCACHE_OFF, so its cache maintenance is compiled out,
and with SKIP_LOWLEVEL_INIT, which also skipped cpu_init_cp15: it ran
with a live write-back cache and no flush or invalidate around the
DMA of the Ethernet MAC and the flash controller, on a table anything
loaded to 0x1000000-0x1100000 overwrites.

SKIP_LOWLEVEL_INIT_ONLY instead: no lowlevel_init (the loader has the
clocks and DDR up), but cpu_init_cp15 invalidates the TLBs and turns the
MMU and the data cache off, as the vendor U-Boot's start does (it then
builds its own tables; this one stays uncached). The loader cleans its
caches before it jumps.

Found under qemu-hisilicon's machines of OpenIPC/qemu-bench#222,
which run the image's own loader: a TFTP to 0x1000000, OpenIPC's
${baseaddr}, overwrote the table and the transfer died; on nt98562,
`mw.l 0x1018000 0 0x2000` hung U-Boot. Now SCTLR reads 0x00c5187a at
the prompt (M and C clear, A and I set), and the same TFTP and mw work
on nt98562 and nt98525. qemu does not model caches, so what this
changes on silicon it cannot show; a write-back cache with no
maintenance fits #95 (NT98566: no ping, TFTP timeouts,
the PHY up and configured).
NA51055 (chip ID 0x4821) and NA51084 (0x5021), the two dies of the
NT9852x SDK, have NA51089's blocks at NA51089's addresses; their vendor
U-Boot 2019.04 tells them apart at run time by the chip ID, as this
does now (nvt_chip_id()). What differs, from that U-Boot's
nvt_na51055_a32/clock.c, eth_na51055.c and nvt_ivot_mmc.c:

- CPU clock: PLL8's ratio is at CG+0x1188 on NA51055 and CG+0x47E0 on
  NA51084 (CG+0x4420 on NA51089). NA51084 runs 1000 MHz unless the
  tree asks for 1200 or 1350, which only the NT98529 is cleared for:
  the vendor reads that from the eFuse, here the target says it. The
  NT9852x trees spell apb-frequency right; both spellings are read.
- Ethernet: their own pinmux and LED bits (one-LED flags in [9:8]),
  the external PHY selected by bit 8 of 0x3004 (bit 4 on NA51089),
  NA51084's RMII_2 and RGMII, PLL16 for its external PHYs, and no PHY
  PLL reset before the embedded PHY's power-on.
- The MAC's DMA: the descriptor skip (DSL) counts in bus-width units,
  4 bytes on NA51055, so no skip reaches a 64-byte line there. The
  NT9852x targets pack the descriptors (16 bytes, no skip), which the
  data cache being off allows (a build-time check says so). Their
  vendor driver also sets DMA_SYSBUS_MODE AALE.
- SD: NA51055 samples on the internal clock after the pad
  (SRC_CLK_SEL), NA51089 and NA51084 on the pad's before it.
- ft_board_setup(): a second DDR die's range in /hdal-memory/media
  (<0x40000000 0x20000000> on the SDK's boards) stays the pool's.
- HEADINFO: the vendor's tag, "ub51055 ".

Verified under qemu-hisilicon (OpenIPC/qemu-bench#222) with the
targets of the next commit: on nt98525 (0x4821) and nt98528 (0x5021)
PLL8 reads 0xA00000 and 0x14D555 (0x190000 on nt98529); dhcp, ping, a
3 MB tftpboot with the host's crc32, an unaligned sf erase/write/read,
mmc info, fatls and a 64 KiB mmc write/read compare; bootm prep of the
SDK's 4.19.91 kernel leaves /memory <0 0x10000000> and media
<0x10000000 0x10000000 0x40000000 0x20000000>, and that kernel boots
with the tree. nt98562 and nt98566 still pass their smoke test.
The NT9852x SDK's parts: NA51055 (NT98520/522/523/525) and NA51084
(NT98528/529), two Cortex-A9s each, booted by the NT9852x loader
(board/novatek/na51055/loader) into the same image layout as NA51089's.

- Kconfig: TARGET_NT985xx, NVT_NA51055 for both dies, NVT_DDR_SIZE as
  each loader is built, and NVT_OSMEM, what Linux gets by default: 32M
  as before, 64M on the NT98523 (its SDK board's; its CMA is at 48 MiB),
  256M on the 512 MiB parts.
- Device trees: openipc/na51055.dtsi and na51084.dtsi are the SDK's
  NT98525 and NT98528 NOR boards (cfg_IPCAM1_NOR_EVB,
  cfg_528_IPCAM1_NOR_EVB) flattened, with the OpenIPC chain in /nor,
  U-Boot at 0x03900000 and the loader's scratch below it. The parts'
  trees carry what their SDK boards change: the NT98523's DDR and split
  (cfg_IPCAM1_523_NOR_EVB), the NT98529's 1.2 GHz CPUs and PLL15
  (cfg_529_IPCAM1_RAMDISK_EVB). The NT98520 and NT98522 have no SDK
  board: the NT98525's tree with one DDR die, the NT98523's with 64 MiB.
  The SDK's NA51055 boards describe one CPU, its NA51084 ones two.
- build.sh: build_loader takes the die and the loader's make variables.
  DDR: the in-package 512 Mbit / 1 Gbit of the NT98522/523 with no
  DDR2; the SDK boards' external 4 Gbit dies otherwise (DDR3, 933 MHz;
  1066 MHz on the NT98528/529). The 528 model's loader is built
  without its own SD card update to fit its 64 KiB, and needs a
  bare-metal toolchain (see a051a70).

Verified under qemu-hisilicon's nt98523, nt98525, nt98528 and nt98529
(OpenIPC/qemu-bench#222), which run the image's loader; the NT98520
and NT98522 images on nt98525 and nt98523, the same dies. Built as CI
builds them (Ubuntu 24.04, arm-none-eabi 13.2, gcc-arm-linux-gnueabi),
every image reaches the prompt twice, the second time with the
environment the first saved; the loaders report 520_DRAM1_933_4096Mb,
522_DRAM1_933_512Mb, 523_DRAM1_933_1024Mb, 525_..._4096Mb and
528_DRAM1_1066_4096Mb_DRAM2_1066_4096Mb. Not on silicon: the external
DDR's settings are the SDK boards', and must match a board's.
AArch64 U-Boots for NA51103 (NT98332) and NA51090 (NT98633), started by
the board's own loader and BL31; the image is U-Boot's slot alone.

Resolved against this branch's NT9852x work: both sets of targets and
die symbols in Kconfig; the NVRs' osmem defaults moved into NVT_OSMEM
(ahead of the 512 MiB rule, which their 1 and 2 GiB would hit);
per-die HEADINFO tags; build.sh's cases and ALL_SOCS from both. Two
fixes the merge needed: nvt_eqos sets AALE by the NVT_NA51055 die
symbol, not nvt_chip_id() (NA51089's header, which the NVR builds do
not include), and MMC_NVT depends on NVT_NA51089 || NVT_NA51055 (the
NVR branch had narrowed it to NA51089, which dropped SD on NT9852x).

Verified: all twelve targets build as CI would (Ubuntu 24.04,
arm-none-eabi, gcc-arm-linux-gnueabi, gcc-aarch64-linux-gnu); every
image passes the two-boot smoke test under qemu-hisilicon
(OpenIPC/qemu-bench#222): the ten camera images through their own
loaders, the NVR stand-in images on nt98332 (-smp 2) and nt98633
(-smp 4).
… qemu

CLAUDE.md: the SoCs this branch now builds, a section on the NT9852x
dies (their loader and its LZMA decoder, DDR, trees, what differs from
NA51089), the loader's hand-off with its MMU and caches on and why
cpu_init_cp15 runs, and qemu-hisilicon#222's machines running the
image's own loader.
The loader of Novatek's NS02501 Linux SDK, release
ns02501_loader_v3.07.101 (the same sources as the SDK tree's
ns02501_ldr), as the SDK ships it: the boot flow sources (LibExt/
LIBExt_src/Ctrl_Flow, LibExt/LIBExt_src/compress, Project/Model/Src),
the headers, the make system, and what Novatek ships as binaries: the
driver and DRAM libraries (ARC/Lib/Release) and the Linux host tools the
build runs (Tools/Bin: nvt-ld-op, bfc, Configram533, encrypt_boot,
encrypt_boot_dump). The SDK has no Tools/ConfigRam: the DDR of every
package is in Configram533's own tables.

One loader serves every package of the die, NS02501 (chip ID 0x5521):
NT98532 and NT98533 with 512 Mbit (QB), 1 or 2 Gbit (QC/QD) of DDR in
the package, or 1, 2 or 4 Gbit (BC/BD/BE), picked by CHIP in
ModelConfig_EMU_EVB.txt. The mask ROM loads it into SRAM; it trains the
DDR, reads the device tree at flash block 1, loads U-Boot as the tree
says and starts it, as NA51089's does.

Left out: the documentation, the Windows tools and scripts, the ICE and
debugger scripts, the sample AES/RSA/ECDSA keys and the key tools
(gen_key, key_app_writer, rsa_genkey, ecdsa_genkey.sh; secure boot is
off), and the host tools no build step runs (bch_8bit, bin2byte_linux).
The archive carries no build output. 162 files in the SDK, 28 left out,
.gitattributes and .gitignore added: 136; the other 134 match the SDK's
byte for byte.

.gitattributes keeps the vendor bytes as they are; .gitignore lets the
libraries in.
The NA51068 is Novatek's DVR/NVR die, sold as NT98321 (DDR3) and NT98323
(DDR4): two Cortex-A9s with the A9 MPCore at 0xF9C00000 and Faraday-
heritage peripherals, external DDR (512 MiB or more on every SDK board).
Its boot chain is NA51089's: the mask ROM starts the SDK's loader
(board/novatek/na51068/loader), which trains the DDR, reads the device
tree at flash 0x10000, unpacks U-Boot from /nor/partition_uboot to
/nvt_memory_cfg/uboot and checks the HEADINFO at 0x300.

- Kconfig: NVT_NA51068 and TARGET_NT98321 / TARGET_NT98323; SYS_BOARD
  "na51068"; NVT_SFLASH and MMC_NVT, NA51089's own blocks, depend on
  NVT_NA51089 now.
- arch/arm/mach-novatek/na51068.c: the HEADINFO ("ub51068", BinCtrl
  SMP as the vendor U-Boot sets it, so that the loader parks the second
  core at /nvt_memory_cfg/core2entry2 for Linux); the A9 global timer,
  64 bits at PLL16's rate (an eighth of the CPU's, CG+0x107C0); reset
  through the watchdog, as the vendor kernel does; the DRAM size from
  the loader's tree (/nvt_memory_cfg/dram), NVT_DDR_SIZE (512 MiB) as
  the fallback.
- include/configs/novatek.h: the UART at 0xFE200000 runs at 48 MHz;
  Linux gets the SDK boards' share, 192 MiB (NT98323) or 160 MiB
  (NT98321), the media pool the rest; the device tree and an initrd
  stay in the first 128 MiB (CONFIG_SYS_BOOTMAPSZ): just below 192 MiB,
  where bootm would put them, the SDK's kernel 4.9 hangs before its
  first message.
- board/novatek/na51068: the loader's tree copied to ${fdtaddr} for
  bootm, the /memory and /hdal-memory/media split at ${osmem}, U-Boot
  kept in the loader's region for it (0x1E000000, the SDK's: past Linux
  and its CMA pools at 0x02000000-0x04800000, below the second core's
  pen at 0x1FF80000); the Ethernet glue of both MACs (RGMII, RMII or
  the embedded PHY, per /top@fe030000/eth pinmux, as the vendor's
  eth_na51068.c, each registered with nvt_eqos); the SD host, a standard
  SDHCI at 0xFA600000, pins and clock as the vendor's nvt_ivot_sdc021.c,
  through mainline's non-DM sdhci.c.

Not ported: the vendor U-Boot raises the CPU to the tree's 1400 MHz
after setting the core and DDR voltages by PWM from the eFuse trim; here
the CPU stays at the loader's clock, and the timer follows PLL16 either
way.

Verified under qemu-hisilicon (PR u-boot#222), -M nt98323 and nt98321 with
the real loader: the CPU shows 800 MHz (the machine's PLL16), DRAM
512 MiB from the tree, reset restarts through the loader; the SDK's
kernel 4.9.118 boots with ${fdtaddr} and an initrd to a shell on both
CPUs (the loader's pen), mem=192M, its spi020_nor taking OpenIPC's
mtdparts, eth0 linked.
The NA51068 (NT98321, NT98323) boots from a SPI NOR on a Faraday
FTSPI020 at 0xFA900000. Each command is the address (CMD0), its length
with the dummy cycles (CMD1), the data length (CMD2) and the instruction
(CMD3, which starts it); data through the 32-byte FIFO at 0x100, a word
at a time; INT_STS bit 0 when done. A status read returns SR1 in
READ_STS, or, polled by the controller, completes only once WIP is
clear, which is how programs and erases are waited for.

After the vendor U-Boot 2016.07 of the NT9832x SDK (nvt_flash_spi020*.c,
spi020_nor.c), PIO and single lane as it runs, but:

- programs are split at page boundaries and padded to whole words with
  0xff (the vendor's write a page from any offset, and pad with whatever
  follows the buffer);
- block protection a vendor firmware left set is cleared, and if it
  stays, writes and erases fail (-EROFS), as nvt_sflash does;
- the size is 2^(the last JEDEC byte), as the vendor driver takes it
  (trace-stdtable in the SDK's trees); past 16 MiB the 4-byte opcodes
  (0x13, 0x12, 0xDC), as the vendor's;
- the clock divider follows the loader's tree (/nor@fa900000
  clock-frequency), the pins are the loader's.

As nvt_sflash, it provides spi_flash_probe() itself; CMD_SF and
ENV_IS_IN_SPI_FLASH accept it.

Verified under qemu-hisilicon (PR u-boot#222), -M nt98323, real loader:
- 16 MiB (W25Q128): sf read of 0x12345 bytes at 0x400005 into 0x2000003
  matches the host's CRC32; erase of 0x600000+128K, write at 0x600007,
  read back to 0x3000001: same CRC; the bytes either side stay 0xff, in
  U-Boot and in the flash file qemu writes back;
- 32 MiB (W25Q256): a 0x80001-byte read at 0x1800001, and a 0x1001-byte
  write at 0x1f00003, against the host's data;
- saveenv, reset, the variable is there.
- openipc/na51068.dtsi: the device tree of the NT9832x SDK's NT98323 NOR
  EVB (cfg_98323_DDR4_4GX1_NOR_EVB, preprocessed and decompiled), with
  the OpenIPC boot chain in /nor (loader 0, fdt 0x10000, uboot 0x20000,
  and the nvtpack index the loader looks a partition up in) and its
  /nvt_memory_cfg but for linuxtmp (the SDK's: U-Boot at 0x1E000000,
  the pen at 0x1FF80000); nt98323.dts is it, nt98321.dts changes what
  the SDK's NT98321 EVB does (Linux 160 MiB, the audio SSP).
- openipc/nt98321_config, nt98323_config: the SoC, NVT_SPI020 and
  MMC_SDHCI; SYS_TEXT_BASE 0x1E000000; SKIP_LOWLEVEL_INIT_ONLY instead
  of SKIP_LOWLEVEL_INIT: the loader jumps to U-Boot with its MMU on and
  its page tables in DDR (its region, 0x100000-0xA00000), so U-Boot's
  cpu_init_cp15 must turn the MMU off, else a write there hangs (a
  kernel load to 0x8000 did).
- build.sh: build_loader() takes the die's loader directory and an
  optional MODEL; build_nvt() a die (default na51089) and a model; the
  NA51089 SoCs build as before. nt98321 and nt98323 take the loader's
  321_DDR3_4GX1_NOR_EVB / 323_DDR4_4GX1_NOR_EVB models, and are in
  ALL_SOCS.
- nvt-image.py: the same 256 KiB image; its comment says so.

U-Boot is 242 KiB, 98 KiB in its LZMA BCL1 container (the slot is
128 KiB); the device tree 14 KiB.

Verified: bash build.sh nt98562 nt98566 nt98560 nt98561 nt98321 nt98323
with Ubuntu's arm-linux-gnueabi-gcc 15.2; under qemu-hisilicon (PR u-boot#222)
the two-boot smoke of an 8 MiB image passes on nt98321 and nt98323 (and
still on nt98562, nt98566); see the driver commits for flash, network,
SD and kernel checks.
What a teammate needs for the NT98321 / NT98323: the boot chain and
where things land in DDR, the loader's MMU (SKIP_LOWLEVEL_INIT_ONLY),
the timer and clock, the drivers, the kernel hand-off limit
(CONFIG_SYS_BOOTMAPSZ), what is not done (SPI NAND, the CPU's 1400 MHz)
and what was verified.

SD, verified under qemu-hisilicon -M nt98323 with -drive if=sd: mmc info
(4-bit, SD 3.0), mmc read of 1 MiB at block 0x186a0 and mmc write/read
at 0x1c000 against the host's CRC32 and the image file, mmc part,
fatls / fatinfo of a FAT16 partition, and OpenIPC's recovery writing
uImage.nt98323.img to flash 0x50000 (byte-exact), then skipping it at
the next boot ("already in flash").
NA51068, the NT9832x SDK's DVR/NVR die, on SPI NOR: its loader
(unpacking an LZMA U-Boot with its own Compress.a), the FTSPI020 NOR
driver, two MACs, SDHCI, the A9 global timer, U-Boot at 0x1E000000.

Resolved against this branch:
- arch/arm/mach-novatek/Makefile: soc.c for every die but NA51068 (the
  branch built it for NA51089 alone, which dropped it from the NT9852x
  and NVR targets); hardware.h picks na51068.h.
- NVT_SFLASH and MMC_NVT stay on every die that has those blocks
  (NA51089, NT9852x; NVT_SFLASH also the NVRs): !NVT_NA51068, not
  NVT_NA51089 alone.
- NA51068's osmem defaults (160M, 192M) moved into NVT_OSMEM.
- nvt_eqos: the branch's one instance per MAC (nvt_eqos_register()),
  with this branch's packed descriptors and AALE on the NT9852x dies and
  the NVRs' fixed MDIO divider (NVT_ETH_MDIO_CR); nvt_eqos_initialize()
  for every die with one MAC.
- build.sh: build_loader keeps taking the loader's make variables; the
  NA51068 cases pass MODEL= that way.

Verified: all fourteen targets build as CI would (Ubuntu 24.04,
arm-none-eabi 13.2, gcc-arm-linux-gnueabi, gcc-aarch64-linux-gnu), and
every image passes the two-boot smoke test under qemu-hisilicon
(OpenIPC/qemu-bench#222): the twelve camera and NA51068 images
through their own loaders, the NVR stand-in images on nt98332 and
nt98633. Three back-to-back 3 MB TFTPs on nt98525 (packed descriptors),
nt98562 and nt98323 (two MACs).
The NA51089 and NA51055 loaders' changes (cf32065, 784be2b,
1098fc3, 38ec5ad), made again for the NS02501 one, so that a
distribution's Arm toolchain builds it (arm-none-eabi, or
arm-linux-gnueabi as U-Boot's):

- target("thumb2") is not a GCC target attribute: target("thumb");
- bin_info.h's header guard defined a different name than it tested;
- -fshort-enums: the vendor libraries are built with short enums;
- the link asks for neither libstdc++ nor libm, which nothing uses
  and Ubuntu's arm-none-eabi does not have;
- a raise() for libgcc's division by zero handler;
- the OP-TEE decrypt option follows its own setting (the same vendor
  typo as the other loaders'; both are Normal here).

And for OpenIPC's images: the model boots from the SPI NOR (STORAGEINT
SpiFlash) and defaults to the 533QD, the SDK's NT98533 package, whose
loader runs under qemu-hisilicon (its 533QC one checks for a DDR die
the board does not have); build.sh passes CHIP for each part.

The loader is 45056 bytes (0xB000, what encrypt_boot_dump pads it to;
its main part deflated by bfc, 32712 bytes before padding), built with
Ubuntu's arm-linux-gnueabi 15 and, in Ubuntu 24.04 as CI, with
arm-none-eabi 13.2 and arm-linux-gnueabi 13.3.
U-Boot is ~240 KiB, ~97 KiB in an LZMA BCL1 container, for its 128 KiB
slot. The NS02501 loader's LZMA branch is NA51089's call into the mask
ROM (ROM_LZMA_POSITION 0xbfd0), but its make system builds it with
ROM_PUBLIC_API OFF: as shipped it takes algorithm 11 to "Can not
support LZMA" and starts nothing, and what the ROM has at 0xbfd0 is
not documented anywhere in the SDK (qemu-hisilicon's model has no ROM
calls for this die). So it carries its own decoder, as the NA51055
loader does (22afed1): LzmaDec from U-Boot's lib/lzma and
bl_lzma.c, copied from there, in the #else of that branch.

The device tree too: the SDK's NS02501 trees are ~95 KiB, the clocks
the vendor kernels' clock framework takes from them (nvt-clk) most of
it, and the loader reads the tree plainly from flash block 1 for
fdt_totalsize() bytes. Plain, it would leave U-Boot 64 KiB before the
environment at 0x40000. bl_load_fdt_from_flash() now unpacks a tree in
an LZMA BCL1 container (the U-Boot one's format) into its scratch
buffer past the packed data, then goes on as for a plain one (the
checks, the copy to /nvt_memory_cfg/fdt). openipc/nvt-image.py packs
the tree with --fdt-lzma: ~8.5 KiB.

The loader stays 45056 bytes (its deflated main part 36088 bytes with
arm-none-eabi 13.2, 36124 with arm-linux-gnueabi 13.3, of the 44 KiB
encrypt_boot_dump pads it to). Verified under qemu-hisilicon's
nt98532 and nt98533 (OpenIPC/qemu-bench#222), whose mask ROM model
runs the image's loader: DDR trained, the tree and U-Boot unpacked
("lzma uboot_size 0x0003A818"), U-Boot started at 0x03900000 with the
tree at 0x100000 and SHMINFO at 0xA00000. Loaders built with
arm-none-eabi 13.2, arm-linux-gnueabi 13.3 (both Ubuntu 24.04, as CI)
and the host's arm-linux-gnueabi 15 all boot so; unlike the NT98528
one, no toolchain needs refusing.
NS02501 (chip ID 0x5521), the NT98532/NT98533 die: two Cortex-A32s run
in AArch32, NA51089's blocks at NA51089's addresses. It gets its own
targets (next commit), so what differs is compiled in under
NVT_NS02501. From the NS02501 SDK's U-Boot 2021.10 (nvt_ns02501_a32,
nvt-ns02501/ns02501_hw_init.c, eth_ns02501.c, nvt_ivot_mmc_a64.c with
nvt_ivot_mmc_ns02501.h, nvt_flash_spi, include/configs/novatek/
ns02501_a32.h):

- SHMINFO at 0xA00000, where the SDK's trees put /nvt_memory_cfg/shmem.
- Console: UART0 at 48 MHz (the vendor's CONFIG_SYS_NS16550_CLK; its
  kernel says base_baud 3000000 from the tree), not NA51089's 24.
- Reset: the watchdog's reset at CG+0x80 bit 8, its clock CG+0x74 bit
  19, its data word cleared, CTRL 0x102 under the key.
- HEADINFO: the vendor's tag, "ub02501 ".
- board_init(): the eFuse controller's 120 MHz timing with its reset
  held, the AXI bridge timeouts. Not its otp_init()'s 800 ms
  power-down wait, nor a USB PHY set-up (compiled out there); the pad
  power set-up reads /top nodes the SDK trees do not have. The CPU
  clock stays as the loader set it (the vendor caps it at 800 MHz unless
  an eFuse code allows more; the trees ask for 800).
- ft_board_setup(): /hdal-memory/media in its parent's cells; on
  NS02501 two address cells, [DDR id][address].
- Ethernet: its own pinmux bits (RMII_1 0x1, RMII_2 0x2, EXTPHYCLK
  0x100; the SDK boards' 0 is the embedded PHY), node /eth0@f02b0000,
  RMII pads at level 1, no PHY PLL reset; the embedded PHY gets MDIO
  address 1 and the vendor's trims for a part without eFuse ones (its
  eFuse reader is closed; Linux's driver keeps what it finds); AALE in
  the MAC's DMA, as the NT9852x one.
- SD: CGPIO13-18 off GPIO, clock source code 1 for 192 MHz (0 is 480
  there), the pads' 4-bit drive fields from PAD+0x50 at the tree's 2,
  the host's AXI channel enabled; sampling as on NA51089.
- Flash: TOP+0x04 [13:12] = 1 and 0x140F off GPIO, a 240 MHz source,
  the tree's clock (12 MHz) capped at 48, the vendor's fixed pad drive,
  TIME2 0x9F51, output delay 3 from 48 MHz; no SRAM shut-down bit and no
  auto-gating, which the vendor does not touch on this die.

Verified under qemu-hisilicon's nt98532 and nt98533 (OpenIPC/
qemu-hisilicon#222) with the targets of the next commit, the image's own
loader running: chip id 5521, 256 MiB; dhcp, ping, a 3 MB tftpboot with
the host's crc32, an unaligned sf erase/write/read, mmc info, fatls and
a 64 KiB mmc write/read compare; saveenv, and a second boot loads
it; reset: the watchdog resets the machine (qemu with -no-reboot
exits; without, the model does not run its loader again after any
reset, its own system_reset included); SCTLR 0x00c5187a at the prompt (the
loader enters with 0x00c5187d). The SDK's 5.10.168 kernel boots to its
shell with /memory <0 0x2400000> and media <0 0x2400000 0xdc00000>.
NT98525's kernel tree still gets <0x10000000 0x10000000 0x40000000
0x20000000>, and nt98562, nt98525 and nt98528 pass the same network,
flash and SD checks.
The NS02501 SDK's parts, one die (NVT_NS02501), booted by the NS02501
loader (board/novatek/ns02501/loader) into NA51089's image layout, the
device tree packed.

- Kconfig: TARGET_NT98532 and TARGET_NT98533, NVT_DDR_SIZE 256 MiB and
  NVT_OSMEM 36M, what the SDK boards give Linux.
- Device trees: openipc/ns02501.dtsi is the SDK's NT98532 NOR board
  (cfg_532_IPC_NOR_SQUASHFS_BD_EVB) flattened, with the OpenIPC chain in
  /nor, U-Boot at 0x03900000 and the loader's scratch below it, SHMINFO
  where the SDK has it (0xA00000). nt98533.dts carries what the SDK's
  533QD board (cfg_533_IPC_NAND_UBIFS_QD_EVB, the same memory split)
  changes past its storage: the engines the NT98533 has more of (DNE,
  PRE, MI; IME, IPE and IFE's ranges), its sensor list, I2C auto reset,
  the EIS and gyro modules, SDIO3's clock source, its BIN_NAME.
- build.sh: nt98532 builds the loader for CHIP 532BD, nt98533 for
  533QD, 2 Gbit at 1066 MHz as the SDK boards; the loader binary is
  named after the part's first three characters; NS02501 images get
  nvt-image.py --fdt-lzma. The other packages (532QB..533BE) are the
  same U-Boot with a loader built for their CHIP and NVT_DDR_SIZE to
  match, so they get no targets of their own.

Built as CI builds them (Ubuntu 24.04, arm-none-eabi 13.2,
gcc-arm-linux-gnueabi 13.3, gcc-aarch64-linux-gnu): every target of
build.sh builds; the NS02501 images are a 45056-byte loader, an
8487/8658-byte packed tree (96534/97963) and U-Boot 97439 packed
(243424). Under qemu-hisilicon (OpenIPC/qemu-bench#222), whose mask
ROM model runs the image's loader, nt98532 and nt98533 reach the prompt
twice, the second time with the environment the first saved; the
loaders report 532BD_DRAM1_1066_2048Mb and 533QD_DRAM1_1066_2048Mb.
The other targets' CI images pass the same two-boot test: nt98560,
nt98561, nt98562, nt98566, nt98523, nt98525, nt98528, nt98529 (and the
NT98520 / NT98522 images on nt98525 / nt98523), nt98332 (-smp 2, 16
MiB) and nt98633 (-smp 4, 128 MiB). Not on silicon: the DDR settings
are the SDK boards'.
CLAUDE.md: what NT98532 / NT98533 support is, where it differs from
NA51089 (the loader's own LZMA, the packed tree, SHMINFO, UART clock,
reset, flash, Ethernet, SD), what is not done, and what was verified
under qemu-hisilicon; NS02501 is no longer among the unsupported dies.
NS02501, two Cortex-A32s with NA51089's blocks: its loader (with its
own LZMA decoder: the SDK builds it without the ROM API, and its trees
are stored LZMA-packed, nvt-image.py --fdt-lzma), SHMINFO at 0xA00000,
the NS02501 watchdog, flash, Ethernet (embedded PHY) and SD set-up in
the NA51089 board and drivers.

Resolved against the NA51068 merge: ALL_SOCS of all sixteen; NVT_SFLASH
on every die but NA51068; UART0 at 48 MHz on NA51068 and NS02501; the
multi-instance nvt_eqos with AALE on the NT9852x dies and NS02501.

Verified: all sixteen targets build as CI would (Ubuntu 24.04,
arm-none-eabi 13.2, gcc-arm-linux-gnueabi, gcc-aarch64-linux-gnu) and
pass the two-boot smoke test under qemu-hisilicon
(OpenIPC/qemu-bench#222); three back-to-back 3 MB TFTPs on nt98525,
nt98562, nt98323 and nt98533.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Support 14 more Novatek SoCs and fix the loader-to-U-Boot hand-off

✨ Enhancement 🐞 Bug fix ⚙️ Configuration changes 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add 14 Novatek targets with die-specific loaders, device trees, drivers, and boot images.
• Shut down the inherited MMU and caches before AArch32 U-Boot uses DMA.
• Preserve existing loaders and BL31 on AArch64 NVR boards by replacing only U-Boot.
Diagram

graph TD
  B["Target builds"] --> L["SDK loaders"] --> P["Image packers"] --> F["Boot flash"] --> U["Novatek U-Boot"] --> D["Device drivers"]
  T["Device trees"] --> P
  B --> N["NVR slot packer"] --> F
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Split support by die family
  • ➕ Makes loader imports and board-specific behavior easier to review and validate.
  • ➕ Allows hardware-tested families to land independently.
  • ➖ Requires coordinating shared driver and build-script changes across several PRs.
  • ➖ Delays delivery of the complete target matrix.
2. Retain vendor U-Boot on additional targets
  • ➕ Avoids maintaining some imported loader sources and low-level drivers.
  • ➖ Cannot provide one consistent OpenIPC U-Boot feature set.
  • ➖ Still depends on board-specific vendor images and flash layouts.

Recommendation: The die-specific loader builds and slot-only NVR packaging fit the incompatible boot chains. Consider reviewing or landing die families separately, especially the imported loaders and new NAND path; QEMU results do not replace board validation of DDR and DMA.

Files changed (82) +27788 / -225

Enhancement (25) +14721 / -165
hardware.hSelect the correct die register map +23/-0

Select the correct die register map

• Dispatches shared board and driver includes to the NA51089, NA51068, or AArch64 NVR definitions.

arch/arm/mach-novatek/include/mach/hardware.h

na51068.hDefine NA51068 hardware addresses +75/-0

Define NA51068 hardware addresses

• Adds register, timer, DDR, and peripheral definitions for the DVR/NVR die.

arch/arm/mach-novatek/include/mach/na51068.h

na51089.hExtend camera-die hardware definitions +36/-6

Extend camera-die hardware definitions

• Expands the shared register map for the additional camera SoCs.

arch/arm/mach-novatek/include/mach/na51089.h

na511xx.hDefine AArch64 NVR hardware addresses +76/-0

Define AArch64 NVR hardware addresses

• Adds register and memory definitions used by NA51103 and NA51090.

arch/arm/mach-novatek/include/mach/na511xx.h

na51068.cInitialize NA51068 machine facilities +159/-0

Initialize NA51068 machine facilities

• Provides die-specific low-level support, including the A9 global timer.

arch/arm/mach-novatek/na51068.c

soc.cShare loader hand-off across Novatek dies +87/-8

Share loader hand-off across Novatek dies

• Adds loader-FDT discovery, die-specific watchdog resets and HEADINFO tags, plus an AArch64 DDR and I/O MMU map.

arch/arm/mach-novatek/soc.c

LzmaDec.cAdd NA51055 loader LZMA decoding +1033/-0

Add NA51055 loader LZMA decoding

• Imports the decoder needed to unpack compressed U-Boot within the loader's limited space.

board/novatek/na51055/loader/LibExt/LIBExt_src/Ctrl_Flow/LzmaDec.c

bl_lzma.cConnect NA51055 loader to LZMA +50/-0

Connect NA51055 loader to LZMA

• Adds the loader-side adapter for unpacking the U-Boot container.

board/novatek/na51055/loader/LibExt/LIBExt_src/Ctrl_Flow/bl_lzma.c

bl_func.cImport NA51055 loader boot flow +3392/-0

Import NA51055 loader boot flow

• Supplies the SDK boot logic used to load and hand off to U-Boot.

board/novatek/na51055/loader/LibExt/LIBExt_src/Ctrl_Flow/bl_func.c

bl_func.cImport NA51068 loader boot flow +2133/-0

Import NA51068 loader boot flow

• Adds SDK loader logic for DDR setup and loading U-Boot on NT98321 and NT98323.

board/novatek/na51068/loader/LibExt/LIBExt_src/Ctrl_Flow/bl_func.c

na51068.cAdd NA51068 board initialization +443/-0

Add NA51068 board initialization

• Handles the loader's FDT, vendor-kernel memory split, Ethernet setup, and SD host.

board/novatek/na51068/na51068.c

na51089.cGeneralize camera-board initialization +331/-27

Generalize camera-board initialization

• Adds die-specific clocks, PHY handling, and memory behavior while retaining the NA51089 board path.

board/novatek/na51089/na51089.c

na511xx.cAdd NVR board initialization +431/-0

Add NVR board initialization

• Provides AArch64 board setup for inherited device trees, memory, and peripherals.

board/novatek/na511xx/na511xx.c

LzmaDec.cAdd NS02501 loader LZMA decoding +1033/-0

Add NS02501 loader LZMA decoding

• Imports a decoder for compressed U-Boot and device-tree payloads.

board/novatek/ns02501/loader/LibExt/LIBExt_src/Ctrl_Flow/LzmaDec.c

bl_lzma.cConnect NS02501 loader to LZMA +52/-0

Connect NS02501 loader to LZMA

• Adds the loader-side decompression adapter.

board/novatek/ns02501/loader/LibExt/LIBExt_src/Ctrl_Flow/bl_lzma.c

bl_func.cImport NS02501 loader boot flow +3618/-0

Import NS02501 loader boot flow

• Supplies the SDK boot logic for the NT98532 and NT98533 packages.

board/novatek/ns02501/loader/LibExt/LIBExt_src/Ctrl_Flow/bl_func.c

build.shBuild all 16 targets through die-specific paths +135/-24

Build all 16 targets through die-specific paths

• Selects SDK loaders and DDR profiles, rejects an incompatible NT98528/529 loader toolchain, and builds AArch64 NVR slots plus QEMU images.

build.sh

openipc.cAdapt OpenIPC boot handling +1/-1

Adapt OpenIPC boot handling

• Adjusts shared boot behavior for the expanded Novatek targets.

common/openipc.c

nvt_mmc.cSupport SD on additional camera dies +45/-8

Support SD on additional camera dies

• Adds NS02501 pin, clock, and pad settings and NA51055 sampling-clock handling.

drivers/mmc/nvt_mmc.c

nvt_spinand.cAdd NT98633 SPI NAND access +651/-0

Add NT98633 SPI NAND access

• Implements non-DM raw-NAND integration, controller transfers, on-die ECC reporting, and bad-block handling.

drivers/mtd/nand/raw/nvt_spinand.c

nvt_sflash.cExtend shared Novatek SPI NOR support +170/-14

Extend shared Novatek SPI NOR support

• Adds die-specific clocks, pins, timing, and FIFO handling, including settings obtained from loader device trees.

drivers/mtd/spi/nvt_sflash.c

nvt_spi020.cAdd NA51068 FTSPI020 NOR driver +462/-0

Add NA51068 FTSPI020 NOR driver

• Provides SPI NOR access through the DVR/NVR die's distinct Faraday controller.

drivers/mtd/spi/nvt_spi020.c

nvt_eqos.cSupport multiple Novatek Ethernet MACs +129/-62

Support multiple Novatek Ethernet MACs

• Moves DMA rings and MDIO state per device, adds NA51068's second MAC, and handles NA51055's descriptor stride.

drivers/net/nvt_eqos.c

nvt-image.pyOptionally compress loader device trees +31/-15

Optionally compress loader device trees

• Adds BCL1/LZMA FDT packaging for NS02501 while retaining the existing full-image layout.

openipc/nvt-image.py

nvt-nvr-image.pyPackage replacement AArch64 U-Boot slots +125/-0

Package replacement AArch64 U-Boot slots

• Creates NT98332 bare-LZMA or NT98633 BCL1/LZMA slots with HEADINFO checksums and size checks; optionally patches a supplied flash dump.

openipc/nvt-nvr-image.py

Bug fix (1) +7 / -1
openipc_configCorrect AArch32 MMU and cache hand-off +7/-1

Correct AArch32 MMU and cache hand-off

• Replaces SKIP_LOWLEVEL_INIT with SKIP_LOWLEVEL_INIT_ONLY so cpu_init_cp15 disables the loader's live MMU and caches before DMA.

openipc/openipc_config

Documentation (1) +272 / -24
CLAUDE.mdDocument the expanded Novatek boot paths +272/-24

Document the expanded Novatek boot paths

• Describes the new dies, loaders, image layouts, build requirements, and inherited-MMU issue.

CLAUDE.md

Other (55) +12788 / -35
KconfigAllow Novatek AArch32 and AArch64 targets +8/-5

Allow Novatek AArch32 and AArch64 targets

• Broadens the architecture entry beyond NA51089 and selects CPU_V7A only for non-ARM64 targets.

arch/arm/Kconfig

KconfigDefine 14 targets and their memory defaults +166/-0

Define 14 targets and their memory defaults

• Adds SoC and die selections, AArch64 selection for NVRs, DDR sizes, and Linux memory allocations.

arch/arm/mach-novatek/Kconfig

MakefileBuild die-specific machine support +5/-0

Build die-specific machine support

• Includes the additional Novatek machine implementation in the architecture build.

arch/arm/mach-novatek/Makefile

.gitattributesMark NA51055 loader assets appropriately +2/-0

Mark NA51055 loader assets appropriately

• Sets attributes for files imported with the SDK loader.

board/novatek/na51055/loader/.gitattributes

make_combo_loader.shAdd NT9852x loader assembly helper +229/-0

Add NT9852x loader assembly helper

• Adds SDK tooling for combining loader components into a bootable binary.

board/novatek/na51055/loader/MakeCommon/make_combo_loader.sh

MakeConfig.txtImport NT9852x loader build options +983/-0

Import NT9852x loader build options

• Defines SDK model, chip, storage, and DDR build choices for NA51055 and NA51084.

board/novatek/na51055/loader/Project/Model/MakeConfig.txt

MakefileBuild the NA51068 board +3/-0

Build the NA51068 board

• Registers the new DVR/NVR board implementation.

board/novatek/na51068/Makefile

ModelConfig_321_DDR3_4GX1_NOR_EVB.txtAdd NT98321 NOR board loader profile +214/-0

Add NT98321 NOR board loader profile

• Provides the SDK board's external DDR3 and SPI NOR settings.

board/novatek/na51068/loader/Project/Model/ModelConfig_321_DDR3_4GX1_NOR_EVB.txt

ModelConfig_323_DDR4_4GX1_NOR_EVB.txtAdd NT98323 NOR board loader profile +216/-0

Add NT98323 NOR board loader profile

• Provides the SDK board's external DDR4 and SPI NOR settings.

board/novatek/na51068/loader/Project/Model/ModelConfig_323_DDR4_4GX1_NOR_EVB.txt

u-boot.ldsLink NA51068 U-Boot for loader hand-off +249/-0

Link NA51068 U-Boot for loader hand-off

• Adds the board's linker layout, including Novatek boot metadata.

board/novatek/na51068/u-boot.lds

MakefileBuild the AArch64 NVR board +3/-0

Build the AArch64 NVR board

• Registers shared NA51103 and NA51090 board code.

board/novatek/na511xx/Makefile

u-boot.ldsLink NVR U-Boot with Novatek metadata +184/-0

Link NVR U-Boot with Novatek metadata

• Defines the AArch64 board image layout expected by the existing boot chain.

board/novatek/na511xx/u-boot.lds

ModelConfig_EMU_EVB.txtAdd NS02501 loader package configuration +349/-0

Add NS02501 loader package configuration

• Defines the SDK model and package settings used to build the selected loader.

board/novatek/ns02501/loader/Project/Model/ModelConfig_EMU_EVB.txt

KconfigExpose flash commands for the new controller +1/-1

Expose flash commands for the new controller

• Adjusts command dependencies for Novatek SPI flash support.

cmd/Kconfig

KconfigConfigure Novatek SD support by die +5/-4

Configure Novatek SD support by die

• Adjusts MMC selection to accommodate the additional Novatek boards.

drivers/mmc/Kconfig

KconfigConfigure Novatek SPI NAND +10/-0

Configure Novatek SPI NAND

• Adds the NAND-controller selection used by NT98633.

drivers/mtd/nand/raw/Kconfig

MakefileBuild the Novatek SPI NAND driver +1/-0

Build the Novatek SPI NAND driver

• Includes the new driver when its Kconfig option is selected.

drivers/mtd/nand/raw/Makefile

KconfigSelect between Novatek NOR controllers +17/-9

Select between Novatek NOR controllers

• Adds FTSPI020 selection for NA51068 and extends the existing flash-controller configuration.

drivers/mtd/spi/Kconfig

MakefileBuild the FTSPI020 NOR driver +1/-0

Build the FTSPI020 NOR driver

• Registers the NA51068 SPI NOR implementation.

drivers/mtd/spi/Makefile

KconfigEnable Ethernet across Novatek dies +5/-4

Enable Ethernet across Novatek dies

• Adjusts networking selection for the additional camera and NVR targets.

drivers/net/Kconfig

KconfigPermit Novatek NAND environments +1/-1

Permit Novatek NAND environments

• Adjusts environment configuration for the NAND-backed NVR.

env/Kconfig

novatek.hDefine die-specific boot memory and flash writes +55/-9

Define die-specific boot memory and flash writes

• Uses configured DDR sizes and Linux memory splits, provides NVR slot-only update commands, and selects board-specific UART and timer settings.

include/configs/novatek.h

openipc-common.hAdd slot-aware NOR and UBI-backed NAND boot settings +41/-2

Add slot-aware NOR and UBI-backed NAND boot settings

• Makes load addresses and U-Boot writes overridable and adds NAND environment, UBI rootfs, and kernel-loading commands.

include/configs/openipc-common.h

na51055.dtsiAdd shared NA51055 device tree +1027/-0

Add shared NA51055 device tree

• Defines common NT9852x hardware, memory, and loader-visible partitions.

openipc/na51055.dtsi

na51068.dtsiAdd shared NA51068 device tree +925/-0

Add shared NA51068 device tree

• Defines DVR/NVR hardware, memory, and SPI NOR boot layout.

openipc/na51068.dtsi

na51084.dtsiAdd shared NA51084 device tree +1187/-0

Add shared NA51084 device tree

• Defines the NT98528/529 die's peripherals and loader memory layout.

openipc/na51084.dtsi

ns02501.dtsiAdd shared NS02501 device tree +6000/-0

Add shared NS02501 device tree

• Imports the extensive NT98532/533 hardware description and loader boot settings; the resulting tree is packed for its slot.

openipc/ns02501.dtsi

nt98321.dtsDescribe the NT98321 NOR board +30/-0

Describe the NT98321 NOR board

• Adds the NT98321-specific NA51068 board and memory settings.

openipc/nt98321.dts

nt98321_configConfigure the NT98321 build +11/-0

Configure the NT98321 build

• Selects the target and its U-Boot link address and features.

openipc/nt98321_config

nt98323.dtsDescribe the NT98323 NOR board +4/-0

Describe the NT98323 NOR board

• Selects the NA51068 tree with NT98323-specific identity.

openipc/nt98323.dts

nt98323_configConfigure the NT98323 build +11/-0

Configure the NT98323 build

• Selects the target and board-specific U-Boot settings.

openipc/nt98323_config

nt98332.dtsDescribe NT98332 for QEMU boot +172/-0

Describe NT98332 for QEMU boot

• Adds an emulator-facing AArch64 tree; flashed boards retain their existing loader device tree.

openipc/nt98332.dts

nt98332_configConfigure the NT98332 NVR slot +16/-0

Configure the NT98332 NVR slot

• Selects AArch64 board settings for the SPI NOR U-Boot replacement.

openipc/nt98332_config

nt98520.dtsDescribe the NT98520 external-DDR board +22/-0

Describe the NT98520 external-DDR board

• Specializes the NT9852x tree for the SDK board's external memory.

openipc/nt98520.dts

nt98520_configConfigure the NT98520 build +2/-0

Configure the NT98520 build

• Selects the target and its U-Boot link address.

openipc/nt98520_config

nt98522.dtsDescribe the NT98522 package +49/-0

Describe the NT98522 package

• Specializes the NA51055 tree for packaged DDR and board settings.

openipc/nt98522.dts

nt98522_configConfigure the NT98522 build +2/-0

Configure the NT98522 build

• Selects the target and its U-Boot link address.

openipc/nt98522_config

nt98523.dtsDescribe the NT98523 package +53/-0

Describe the NT98523 package

• Specializes the NA51055 tree for its larger packaged DDR and memory allocation.

openipc/nt98523.dts

nt98523_configConfigure the NT98523 build +2/-0

Configure the NT98523 build

• Selects the target and its U-Boot link address.

openipc/nt98523_config

nt98525.dtsDescribe the NT98525 board +8/-0

Describe the NT98525 board

• Selects NA51055 hardware settings for the two-external-DDR board.

openipc/nt98525.dts

nt98525_configConfigure the NT98525 build +2/-0

Configure the NT98525 build

• Selects the target and its U-Boot link address.

openipc/nt98525_config

nt98528.dtsDescribe the NT98528 board +8/-0

Describe the NT98528 board

• Selects the NA51084 hardware tree for its external-DDR layout.

openipc/nt98528.dts

nt98528_configConfigure the NT98528 build +2/-0

Configure the NT98528 build

• Selects the target and its U-Boot link address.

openipc/nt98528_config

nt98529.dtsDescribe the higher-clocked NT98529 +32/-0

Describe the higher-clocked NT98529

• Specializes the NA51084 tree for the NT98529 board and CPU clock.

openipc/nt98529.dts

nt98529_configConfigure the NT98529 build +2/-0

Configure the NT98529 build

• Selects the target and its U-Boot link address.

openipc/nt98529_config

nt98532.dtsDescribe the NT98532 package +8/-0

Describe the NT98532 package

• Selects the shared NS02501 hardware tree for its SDK board.

openipc/nt98532.dts

nt98532_configConfigure the NT98532 build +2/-0

Configure the NT98532 build

• Selects the target and its U-Boot link address.

openipc/nt98532_config

nt98533.dtsDescribe NT98533-specific hardware +157/-0

Describe NT98533-specific hardware

• Extends the NS02501 tree with the NT98533's additional engines, sensors, and board settings.

openipc/nt98533.dts

nt98533_configConfigure the NT98533 build +2/-0

Configure the NT98533 build

• Selects the target and its U-Boot link address.

openipc/nt98533_config

nt98560.dtsDescribe the NT98560 external-DDR board +39/-0

Describe the NT98560 external-DDR board

• Adds the SDK board's 512 MiB DDR layout and Linux/media memory split.

openipc/nt98560.dts

nt98560_configConfigure the NT98560 build +2/-0

Configure the NT98560 build

• Selects the target and its U-Boot link address.

openipc/nt98560_config

nt98561.dtsDescribe the NT98561 package +16/-0

Describe the NT98561 package

• Adds its 64 MiB packaged-DDR identity and board settings.

openipc/nt98561.dts

nt98561_configConfigure the NT98561 build +2/-0

Configure the NT98561 build

• Selects the target and its U-Boot link address.

openipc/nt98561_config

nt98633.dtsDescribe NT98633 for QEMU boot +206/-0

Describe NT98633 for QEMU boot

• Adds an emulator-facing AArch64 NAND tree; flashed boards retain their existing loader device tree.

openipc/nt98633.dts

nt98633_configConfigure NT98633 NAND and UBI boot +39/-0

Configure NT98633 NAND and UBI boot

• Selects AArch64, SPI NAND, a NAND environment, UBI commands, and memory addresses clear of BL31.

openipc/nt98633_config

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Oversized device trees corrupt QEMU images ✓ Resolved
Description
The inline QEMU image builder writes the loader-provided device tree into its fixed-size bytearray
without checking that it fits before the U-Boot slot. A tree larger than the fdt-to-slot gap
extends the bytearray past the declared boot-area size, producing an image with an invalid flash
layout.

2. A boot image can overwrite adjacent memory ✓ Resolved
Description
bl_load_uboot_from_flash passes the BCL1 header’s uncompressed size to bl_lzma_inflate without
checking it against p_dram_partition->uboot_size. On both NA51055 and NS02501, an oversized value
in a flash-supplied image lets decompression write beyond the U-Boot DRAM region before the later
image checks run.


Remediation recommended

3. SPI NAND breaks builds on other dies ✓ Resolved
Description
NAND_NVT_SPI depends only on ARCH_NOVATEK, although nvt_spinand.c uses clock and pad
definitions guarded by CONFIG_NVT_NA511XX. Selecting the option for another Novatek family
compiles the driver without those definitions and fails the build.

4. Two boards identify as the wrong die ✓ Resolved
Description
na51084.dtsi sets its root model and compatible string to NA51055 despite being the common tree
for NA51084. Both NT98528 and NT98529 include it, so the device tree handed to their kernels
advertises the wrong hardware identity.

5. A failed status read lets a flash write go ahead ✓ Resolved
Description
sf_read_reg() ignores what fc_xfer() returns and gives back its starting value of 0xff when the
status-register read times out. sf_write_enable() takes that 0xff as WEL set, so page program and
erase continue after a dead status read, and sf_unprotect() reads it as "no protection" and skips
the block-protection check.

View review recommended (1)
6. NS02501 sets one PHY-select bit but clears another ✓ Resolved
Description
nvt_eth_init_ns02501() selects the external PHY with PHY_SEL_EXT (BIT(4)) on the RMII path, but
deselects it with PHY_SEL_EXT_52X (BIT(8)) on the embedded-PHY path. Only one of the two can be
the NS02501 bit. If BIT(8) is right, RMII boards never route the MAC to their external PHY; if
BIT(4) is right, the embedded-PHY path never clears a select the loader may have left set.


Informational

7. Flashes larger than 64 MiB are seen as 8 MiB ✓ Resolved
Description
spi_flash_probe() accepts JEDEC capacity bytes only from 0x10 to 0x1a, so any other code,
including 0x1b for a 128 MiB part, falls back to 8 MiB. That also sets sf.alen to 3, so the MTD
device covers only the first 8 MiB, uses 3-byte opcodes, and cannot reach the rest of the chip.

Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

The NA51055, NA51068 and NS02501 loaders took the uncompressed size from
the BCL1 header as the decoder's output bound. Refuse an image larger
than /nvt_memory_cfg/uboot before decoding, as the plain path does.
sf_read_reg() returned 0xff on a timeout, which write enable took for
WEL set and the unprotect check for no status register. Return the
transfer's error instead. Capacity codes 0x1b and 0x1c (128, 256 MiB)
fell back to 8 MiB with 3-byte addresses.
Its clock and pad set-up is NA511XX's.
The vendor driver sets bit 4 for the external PHY, as on NA51089, but
clears bit 8, NT9852x's, for the embedded one. Clear both, so a select
left by the loader goes.
The SDK's tree names NA51055 for both dies; keep it as a fallback. The
vendor kernel matches only nvt,ca9.
Python's slice assignment grows the image instead of failing.
@dimerr
dimerr merged commit 9a0dbcd into openipc-novatek Nov 4, 2026
8 checks passed
@dimerr
dimerr deleted the novatek/more-socs branch November 4, 2026 05:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant