Skip to content

arm: hisilicon: add hi3520dv200 SoC support (DT + mach-hibvt, L2, SATA, SFC), tested on hardware - #82

Open
bjorns163 wants to merge 19 commits into
OpenIPC:upstream-patchesfrom
bjorns163:hi3520dv200
Open

bjorns163 wants to merge 19 commits into
OpenIPC:upstream-patchesfrom
bjorns163:hi3520dv200

Conversation

@bjorns163

@bjorns163 bjorns163 commented Oct 13, 2026 •

Copy link
Copy Markdown

Summary

Adds the Hi3520DV200, a single Cortex-A9 NVR/DVR SoC, to upstream-patches, with a board DT for the XiongMai NBD6808T-PL (PCB MBD0157, 8 MB MX25L6406E). Unlike the other mach-hibvt ports, this one was brought up and tested on real hardware rather than in QEMU. It boots from the board's stock 2010 U-Boot (DTB appended, ATAGs) to the OpenIPC userspace.

Nineteen commits:

  • SoC support (DT + mach-hibvt). Addresses and interrupts come from the vendor 3.0.8 BSP (arch/arm/mach-hi3520d), not from the existing 4.9 port. That port was QEMU-only and has two mistakes that stop real hardware:
    • The UARTs and SP804s run from bus/4 (82.5 MHz: PLL 1320 MHz, bus 330 MHz, read from CRG0/CRG1/AXI scale on the board), not from the 24 MHz crystal. The bootloader leaves the UART on its APB source (PERI_CRG57 bit 14 clear).
    • 0x20700000 is not a PL310. Its ID register reads 0, and probing it as arm,pl310-cache hangs the boot right after the errata line.
  • net: hisilicon: hisi_femac: make the MAC core reset optional. The Hi3520DV200's "hieth-sf" switch-fabric MAC has an up port whose registers and bits match hisi-femac exactly (MAC_PORTSEL/PORTSET/SET, the queue registers, the up-port bits of FWCTRL/MACTCTRL/IRQ_ENA and the MAC filter). The global block sits at +0x1300 and is passed as hisi-femac's second region, and the MDIO block at +0x1100. There is no reset controller yet, so the MAC reset becomes optional, as the PHY reset already is.
  • net: mdio: hisi-femac: set the Hi3520DV200 internal PHY address (with a dt-bindings commit). The internal PHY answers at the address in bits 4:0 of SYS_CTRL PERI24 (0x20050094). That register is 0 after power-on, and only the bootloader's network code sets it. So a kernel booted straight from flash finds no PHY: MDIO device at address 3 is missing, and no eth0. The driver's existing internal-PHY path also writes the address, but then runs the festa PHY trim, and this SoC has no trim data and a different PHY. The new compatible takes an address-only path, with the register as the MDIO node's second reg entry.
  • spi: hisi-sfc-v3xx: support the Hi3520DV200 SFC v350 via device tree. The SFC v350 (hw version 0x350) has the register layout of the Kunpeng v3xx parts: GLB_CFG 0x100, interrupts 0x120–0x12c, CMD_CFG/INS/ADDR 0x300–0x30c with identical fields, and a 16-word data buffer at 0x400. The commit adds an OF match, allows the driver on ARCH_HISI_BVT, and honours num-cs (the flash is on CS1).
  • ata: add AHCI glue for the HiSilicon Hi3520DV200. A small ahci_platform-style driver. It runs the vendor PHY bring-up (clocks, the per-port bug-bypass value, PHY/OOB settings, reset sequence) and then hands the controller to the generic AHCI code. The port PHY value can be set with hisilicon,phy-config: XiongMai boards need 0x0e262709 (the Hi3531/Hi3521 value, which their stock kernel writes). With HiSilicon's Hi3520D reference value the link keeps resetting. This matches hi3520dv200: enable SCSI and the SoC's SATA controller firmware#2579 for the 3.0.8 kernel.
  • ARM: hisilicon: add the hil2v200 L2 cache controller. HiSilicon's own L2 (128 KB, 8 ways, 32-byte lines), ported from the vendor driver as an outer cache. It is brought up from the machine's init_irq, where the core would set up a PL310. nol2 on the command line leaves it off.
  • watchdog: sp805: restart with a load of 1, not 0. This SoC's SP805 never resets with a load of 0. Before the change, a reboot ended in Reboot failed -- System halted and the board stayed hung. With LOAD_MIN it resets at once.
  • DT commits for Ethernet, the SPI-NOR controller and flash, SATA and USB (generic EHCI/OHCI; the bootloader already enables their clock and PHY exactly as the vendor kernel does).
  • hi3520dv200_defconfig. It fits the 2048 KB kernel partition of an 8 MB NOR layout: 1731 KB with everything below (xz, which is 88 KB smaller than LZMA here and unpacks in the same ~1 s). It also enables MTD_CMDLINE_PARTS, which OpenIPC's flash images rely on, and WireGuard as a module (133 KB of .ko on the rootfs), as on the other OpenIPC boards, so their modprobe wireguard start-up works unchanged.
  • ARM: configs: hi3520dv200: enable sysctl. Restores PROC_SYSCTL, which the size trims had dropped. Without /proc/sys, OpenIPC's sysctl start-up fails, mdev cannot register as the hotplug helper, and net.ipv4.ip_forward cannot be set. 18 KB.
  • ARM: dts: hi3520dv200: nbd6808t: describe all 256 MB of DDR. The vendor firmware gave Linux only the first 128 MB and kept the rest for the MPP's media memory. Without the MPP, all 256 MB is ordinary memory, apart from the VGA framebuffer, which stays reserved. With 128 MB, eight camera streams through go2rtc ran the system out of memory.
  • spi: hisi-sfc-v3xx: name the flash after its DT label and the board DT labelling its flash hi_sfc. Both the vendor and the OpenIPC bootloader pass the layout as mtdparts=hi_sfc:.... Through spi-mem the MTD device would otherwise be named after the SPI device, so the command-line layout never applied. The hook returns the DT label when there is one and the default name otherwise, so the ACPI parts are unaffected.
  • VGA through a simple-framebuffer. The vendor bootloader can drive the display controller by itself: startvo 0 4 10; startgx 0 0x8f000000 3840 0 0 1920 1080 opens VGA at 1080p60 and scans graphics layer 0 out of a buffer at 0x8f000000 (ARGB1555, alpha bit ignored; checked with colour bands). The board DT describes that buffer as a reserved simple-framebuffer (x1r5g5b5), and the defconfig enables simplefb, /dev/fb0 and fbcon. That adds 107 KB. Without those bootloader commands the buffer is ordinary reserved memory and nothing is shown.

Not covered: HDMI (the bootloader's startvo does not start the HDMI transmitter), display-controller set-up from Linux itself, and the video decoder. Those depend on the vendor's MPP modules, which exist only for 3.0.8. There is no CRG/clock driver yet; the DT uses fixed-clocks matching the bootloader's PLL settings.

Test plan

All on a XiongMai NBD6808T-PL, RAM-booted from the stock U-Boot (uImage of zImage + DTB at 0x80008000, OpenIPC hi3520dv200 rootfs as an initrd). The flash was not written; its partitions were read-only in the DT.

  • hi3520dv200_defconfig builds from scratch, and every commit in the series builds on its own
  • Boots to the OpenIPC login prompt; no Oops/panic/BUG in dmesg; interactive SSH gets /dev/pts/0
  • Ethernet: 100 Mbps/Full on the internal PHY (id 0x001cc816); a 50 MB TCP send arrives complete at 11.7 MB/s; a TFTP download's md5 matches
  • Ethernet without the bootloader's network set-up: PERI24 cleared in U-Boot (mw.l 0x20050094 0) right before bootm, giving the power-on state of a plain flash boot. The driver writes address 3, the PHY attaches at 10091100.mdio:03, the link comes up, and a 20 MB transfer over SSH arrives complete. Before the change, a boot from flash showed MDIO device at address 3 is missing and no eth0
  • SPI-NOR: hw version 0x350; the bootloader, kernel, application and logo partitions read back byte-identical to a dump taken with the vendor bootloader (the jffs2 settings partition differs only because the stock firmware rewrote it since); full 8 MB in 4.4 s
  • SATA: 320 GB 2.5" disk detected on the first attempt with no link resets; ext4 created and mounted from 7.0; 256 MB written at 65–73 MB/s and read at 73–76 MB/s; a 24 MB random file written and read back after dropping caches matches. With no disk, both ports report link down within a second
  • USB: a 15.6 GB stick is detected through EHCI and usb-storage, and its partition table read
  • L2: same kernel with and without nol2. gzip of 8 MB takes 4.95 s instead of 8.40 s, and ext4 writes run at 73 instead of 53 MB/s. All the DMA checks above pass with the L2 on
  • Watchdog: reboot -f and a sysrq-triggered panic with panic=20 both reset the board to the bootloader
  • VGA: after the bootloader commands above, fbcon shows the kernel log at 240x67 on a VGA monitor, and data written to /dev/fb0 appears on screen; checked with the defconfig build (1643 KB zImage)
  • Command-line partitions: an OpenIPC firmware build using this kernel (a hi3520dv200_neo defconfig, see below) RAM-booted with mtdparts=hi_sfc:256k(boot)ro,64k(env)ro,2048k(kernel)ro,5120k(rootfs)ro,-(rootfs_data)ro gives 5 cmdlinepart partitions found on MTD device hi_sfc, with boot, env, kernel, rootfs and rootfs_data at the expected offsets
  • sysctl: the OpenIPC boot reports Running sysctl: OK (it was FAIL), kernel.printk is applied, /proc/sys/kernel/hotplug is /sbin/mdev, and /proc/sys/net/ipv4/ip_forward exists
  • Memory: with mem=256M, Memory: 249560K/262144K available, the framebuffer is still reserved and registers, and 150 MB of random data in tmpfs reads back identical. An eight-camera go2rtc load peaks at 115 MB with 79 MB still free
  • checkpatch.pl --strict clean apart from MAINTAINERS and Signed-off-by notes

A sibling OpenIPC/firmware PR adding a hi3520dv200_neo variant will follow.

Single Cortex-A9 NVR/DVR SoC. Boots on real hardware (XiongMai
NBD6808T-PL) from the stock 2010 U-Boot with an appended DTB, to an
OpenIPC userspace shell on ttyAMA0.

Addresses and interrupts follow the vendor 3.0.8 BSP. Details that differ
from the existing QEMU-only 4.9 port:

- The UARTs run from bus/4 (82.5 MHz with the APB source the bootloader
  selects in PERI_CRG57), not from the 24 MHz crystal.
- 0x20700000 is HiSilicon's own L2 controller (vendor "hil2v200"), not a
  PL310: its ID register reads 0 and treating it as a PL310 hangs the
  boot. The bootloader leaves it off; no driver yet.
- The SP805 watchdog at 0x20040000 runs at 3 MHz (measured).

Clocks are fixed-clocks until there is a CRG driver.
The MAC reset line is only asserted and released around probe, and the
reset API treats a missing optional reset as a no-op. SoCs without a
reset controller driver yet (Hi3520DV200, whose "hieth-sf" up port is
register-compatible with this MAC) can then probe the driver, as the PHY
reset already allows.
The Hi3520DV200's internal PHY answers at the address held in the low
five bits of a system-control register, which reads 0 after power-on.
Add a compatible for it, with that register as a second reg entry.
The Hi3520DV200's internal PHY answers at the address in bits 4:0 of
SYS_CTRL PERI24 (0x20050094). The register is 0 after power-on and only
the bootloader's network code sets it, so a kernel booted straight from
flash finds nothing at the address in the DT ("MDIO device at address 3
is missing", no eth0). Booting after a TFTP transfer hid this.

The existing internal-PHY path writes the address too, but then runs the
festa PHY trim, and this SoC has no trim data and a different PHY (id
0x001cc816). Its compatible therefore takes an address-only path: with
the register as the second reg entry, the driver writes the PHY address
from the DT before the bus is scanned.

Tested on an NBD6808T-PL by clearing the register in U-Boot before bootm:
the PHY is found at address 3 and the link comes up at 100 Mbps.
The Hi3520DV200 "hieth-sf" switch-fabric MAC has an up port at the block
base and a down port at +0x2000, sharing global registers at +0x1300 and
an MDIO controller at +0x1100. The up port's registers and bit layout
match hisi-femac (MAC_PORTSEL/PORTSET/SET, the queue registers, and the
up-port bits in FWCTRL, MACTCTRL, IRQ_ENA and the MAC filter), so it is
described as a hisi-femac with the global block as its second region.

On the NBD6808T-PL the RJ45 is on the up port through the SoC's internal
PHY at MDIO address 3 (id 0x001cc816). Link comes up at 100 Mbps full
duplex, with ping and bulk TCP transfers working.
The SPI-NOR controller in HiSilicon's Hi3520DV200 (hardware version
0x350) has the register layout of the v3xx parts this driver handles:
GLB_CFG at 0x100 with the address-mode bit, interrupts at 0x120-0x12c,
CMD_CFG/INS/ADDR at 0x300-0x30c with the same CMD_CFG fields, and the
data buffer at 0x400 (16 words, which the driver already picks for
versions below 0x351).

Add an OF match for it, let it build on ARCH_HISI_BVT, and take the
number of chip selects from the generic "num-cs" property: the ACPI parts
expose one, while the Hi3520DV200 boards put their flash on CS1.

Tested on a XiongMai NBD6808T-PL (8 MB MX25L6406E on CS1): reading every
partition back gives the same bytes as a dump taken with the vendor
bootloader; a full 8 MB read takes about 4.4 s in polling mode.
Describe the SFC v350 at 0x10010000 (driven by spi-hisi-sfc-v3xx) and,
on the NBD6808T-PL, the 8 MB MX25L6406E on chip select 1 with the
stock firmware's partition layout. All partitions are read-only while
the board still carries its vendor firmware.
The Hi3520DV200's SATA controller is a standard two-port AHCI block,
but its PHYs have to be clocked, released from reset and programmed
before the AHCI core sees a link. Port the vendor 3.0.8 BSP's sequence
(CONFIG_HI_SATA, 1.5 Gbps mode): clocks and the per-port bug-bypass
setting, bus and PHY out of reset, PHY control/OOB values, the port PHY
configuration, a PHY reset pulse and the core resets.

The port PHY value defaults to HiSilicon's Hi3520D reference value and
can be overridden with "hisilicon,phy-config"; XiongMai boards need the
Hi3531/Hi3521 value their vendor firmware writes, without which the link
keeps resetting.

Tested on a XiongMai NBD6808T-PL with a 2.5" 320 GB disk: detected on
the first attempt at boot, 63 MB/s writing and 75 MB/s reading 256 MB
through ext4; with no disk both ports report link down within a second.
SATA at 0x10080000 with PERI_CRG45 as its clock/reset register, driven
by ahci-hi3520dv200; the NBD6808T-PL uses the PHY value its vendor
firmware writes. EHCI and OHCI at 0x100b0000/0x100a0000 are generic
platform controllers; the bootloader already enables their clock and
PHY (PERI_CRG46, PERI_USB) exactly as the vendor kernel does.
The Hi3520DV200's L2 cache at 0x20700000 is HiSilicon's own controller
(the vendor BSP's "hil2v200"), not a PL310: maintenance is by physical
address through INVALID/CLEAN registers or by whole way through an AUTO
register, and a read of SYNC drains it. Port the vendor 3.0.8 driver as
an outer cache (128 KB, 8 ways, 32-byte lines), brought up from the
machine's init_irq where the core would initialise a PL310. Large clean
and flush ranges fall back to whole-cache operations; invalidates never
do. "nol2" on the command line leaves it off.

On a XiongMai NBD6808T-PL, with the L2 on, DMA data stays intact (TFTP
download, a random file written to SATA and read back after dropping
caches, SPI-NOR reads and a 50 MB TCP send all match), and compared to
nol2 on the same kernel gzip of 8 MB takes 4.99 s instead of 8.40 s and
256 MB ext4 writes run at 73 instead of 53 MB/s.
The restart handler loads 0 to make the watchdog fire at once. The SP805
in HiSilicon's Hi3520DV200 never resets the system with a load of 0:
reboot ends in "Reboot failed -- System halted", and the board then stays
hung even though a timeout had been running before the restart handler
reprogrammed it. Loaded with 1 (LOAD_MIN, the smallest value
wdt_setload() itself would program), the same watchdog resets the board
immediately.

Tested on a XiongMai NBD6808T-PL: "reboot -f" and a sysrq-triggered
panic with panic=20 both come back to the bootloader.
A configuration for Hi3520DV200 NVR boards that fits the 2048 KB kernel
partition of an 8 MB NOR layout (1537 KB zImage, xz, DTB appended for
bootloaders without DT support): serial console, Ethernet, SPI-NOR with
JFFS2/squashfs/overlayfs, SATA and USB storage with ext4/vfat, the
hil2v200 L2 cache and the SP805 watchdog, with debugging aids, IPv6, VT
and input left out. xz is 88 KB smaller than LZMA here and takes the
same ~1 s to unpack.
The vendor bootloader can drive the display controller: "startvo 0 4 10"
opens VGA at 1080p60 and "startgx 0 0x8f000000 3840 0 0 1920 1080" scans
graphics layer 0 out of a buffer at 0x8f000000, as ARGB1555 with the
alpha bit ignored. Describe that buffer as a simple-framebuffer
(x1r5g5b5) and reserve it, so Linux can draw on the VGA output without a
display driver. Without those bootloader commands the buffer is ordinary
reserved memory and nothing is shown.

Tested on the NBD6808T-PL: fbcon shows the kernel log at 240x67 on a VGA
monitor and data written to /dev/fb0 appears on screen.
Enable simplefb with /dev/fb0, the VT and the framebuffer console, so a
monitor on the VGA output shows the console when the bootloader has set
the display up. 107 KB more: the zImage is 1644 KB of the 2048 KB
partition.
Bootloaders on Hi3520DV200 boards (the vendor's and OpenIPC's) pass the
flash layout as "mtdparts=hi_sfc:...", which the command-line partition
parser only applies to an MTD device of that name. Through spi-mem the
flash is named after the SPI device instead. Provide a get_name hook
that returns the flash node's "label" when it has one, and the default
name otherwise, so ACPI parts are unaffected.
Both the vendor and the OpenIPC bootloader describe this board's flash
as "mtdparts=hi_sfc:...". With the label the command-line layout
applies; the stock partitions in the DT remain as the fallback when the
bootloader passes none.
Enable MTD_CMDLINE_PARTS so the bootloader's "mtdparts=" layout is used
(the flash images OpenIPC builds rely on it), and WireGuard for remote
access without exposing other services.

WireGuard is a module, as on the other OpenIPC boards, so their
userspace (which runs "modprobe wireguard") works unchanged; that needs
MODULES and MODULE_UNLOAD. The zImage is 1712 KB of the 2048 KB
partition, with 133 KB of modules on the root filesystem.
PROC_SYSCTL went with the other EXPERT trims, which left no /proc/sys:
OpenIPC's sysctl start-up failed ("Running sysctl: FAIL"), mdev could
not register as the hotplug helper, and nothing could set
net.ipv4.ip_forward, which routing over WireGuard needs. 18 KB: the
zImage is 1731 KB of the 2048 KB partition.
The board has 256 MB. The vendor firmware gave Linux the first 128 MB
(mem=132M) and the rest to the MPP's media memory zone, and the DT copied
that split. Without the MPP all of it is ordinary memory, apart from the
VGA framebuffer at 0x8f000000, which is already reserved no-map.

With 128 MB, eight camera streams through go2rtc left the system out of
memory. With 256 MB, Linux reports 249560K available; 150 MB of random
data in tmpfs reads back identical, and the framebuffer still registers.
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