Skip to content

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

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

bjorns163 wants to merge 22 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.

Twenty-two 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 the generic num-cs (u32; 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. Unlike the vendor driver, flushes and invalidates go one line at a time (by address, or by way and set for flush_all), the partial lines at the ends of an invalidate are cleaned first, the L2 is turned off before it is flushed on disable, and INTCLR is cleared write-1-to-clear. There is no combined clean+invalidate of a way, and a clean pass followed by an invalidate pass would drop lines evicted in between.
  • 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-bindings: commits (YAML) for the L2 cache, AHCI (with hisilicon,phy-config) and SFC compatibles, each before its driver.
  • 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. Each maintenance operation was also checked against DRAM through an uncached alias of the same page (by-address clean/invalidate, way/set clean and flush, partial-line invalidate: 64/64 each; flush_all passes)
  • 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
  • dt_binding_check passes for the new bindings, and dtbs_check reports nothing for their nodes

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.

@openipc-ai openipc-ai left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this port, and especially for the bring-up on real hardware. The DT, SFC, MDIO and watchdog parts read well. Two problems in arch/arm/mm/cache-hil2v200.c need fixing before this lands. Both come from reading the code; I haven't reproduced them. A passing boot wouldn't rule them out, because they depend on buffer alignment and timing.

1. hil2_inv_range() can discard dirty data next to the range

It rounds start down to a line and invalidates every line it touches, without cleaning the partial lines at each end. If a buffer shares a line with other data, a dirty copy of that data in L2 is lost. l2c210_inv_range() in cache-l2x0.c handles this by using clean+invalidate on an unaligned start and end. The same approach should work here with L2_CLEAN followed by L2_INVALID on the edge lines.

2. __hil2_flush_all() has a window where dirty lines are lost

It cleans all eight ways, then invalidates all eight in a second pass. The CPU keeps running between the passes, so a dirty L1 line evicted into L2 after its way was cleaned gets dropped by the invalidate. Disabling interrupts doesn't close this, since the code's own memory accesses can cause the eviction.

This isn't limited to shutdown: hil2_flush_range() calls it for any range of 128 KB or more, and __dma_clear_buffer() calls outer_flush_range() when allocating DMA memory.

The simplest fix I can see is for hil2_flush_range() to always work line by line (clean, then invalidate each line), as it already does for smaller ranges, perhaps in chunks to limit the time with interrupts off. If the controller has an atomic clean+invalidate-way operation, that would also fix flush_all.

Please also check

  • hi3520dv200_sata_phy_init() writes PORT_BUG_BYPASS to the AHCI block before it releases CRG_HRST. If the block is still in reset (cold boot, no SATA access from the bootloader), those writes may be lost. If this order comes from the vendor BSP, a short comment saying so would help.
  • hil2v200_of_init() writes 0 to L2_INTCLR under a "clear stale error state" comment, while hil2_way_op() clears by writing back the bits it read. If the register is write-1-to-clear, the 0 clears nothing. A stale RINT_AUTO_END would then make the first way operation look finished immediately.

Smaller things

  • The new compatibles hisilicon,hi3520dv200-l2cache, -ahci and -sfc, and the hisilicon,phy-config property, have no binding documentation. Only the MDIO binding was updated.
  • In hi3520dv200.dtsi, the hieth-sf comment block now sits above the sfc node, away from the Ethernet nodes it describes.

The SPI-NOR controller of the Hi3520DV200 (hardware version 0x350) has
the register layout of the v3xx controllers driven by spi-hisi-sfc-v3xx.
Document its compatible. The flash on the boards sits on CS1, so num-cs
is usually 2; without an interrupt the driver polls.
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 two-port AHCI controller needs its PHYs clocked, reset
and programmed through the SoC's SATA clock/reset register (PERI_CRG45),
given as a second reg entry. The port PHY value differs between boards:
add "hisilicon,phy-config" for it, defaulting to HiSilicon's Hi3520D
reference value.
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 is HiSilicon's own controller ("hil2v200"),
not a PL310: its ID register reads 0 and it has its own maintenance
registers. Document its compatible.
The Hi3520DV200's L2 cache at 0x20700000 is HiSilicon's own controller
(the vendor BSP's "hil2v200"), not a PL310: lines are maintained through
INVALID/CLEAN registers, by physical address or by way and set, whole
ways 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. "nol2" on the command line leaves it off.

Unlike the vendor driver:
- an invalidate cleans the partial lines at either end of its range
  first, so dirty data next to a DMA buffer is not lost;
- flush_all cleans and invalidates line by line, by way and set: the
  controller has no combined clean+invalidate of a way, and a clean of
  all ways followed by an invalidate of all ways drops whatever the CPU
  evicts into the L2 in between. Flush ranges always go line by line;
  only large clean ranges use whole-way cleans;
- range operations take the lock in 4 KB blocks, to bound the time with
  interrupts off;
- disable turns the L2 off before cleaning and invalidating it, as the
  vendor's suspend path does;
- INTCLR is cleared at init by writing back RINT: it is write-1-to-clear
  (measured), so the vendor's write of 0 leaves a stale AUTO_END.

On a XiongMai NBD6808T-PL each maintenance operation was checked through
an uncached alias of the same page (by-address clean and invalidate,
by way and set, partial-line invalidate, flush_all, which takes 130 us).
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
TCP transfers both ways 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. reboot -f still resets the board.
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.
@bjorns163

Copy link
Copy Markdown
Author

Thanks for the careful review. Both L2 problems were real, and both came from the vendor driver. I've fixed them, checked each maintenance operation on the board, and folded the fixes into the existing commits. The branch is force-pushed.

1. hil2_inv_range() and partial lines. Fixed as you suggested. An unaligned start or end line now gets L2_CLEAN and then L2_INVALID before the rest of the range is invalidated.

2. The flush_all window. There's no combined clean+invalidate of a way, but the INVALID/CLEAN registers also take a way and set index (bit 0 clear, way in 31:29, set from bit 5; it's in the vendor header, not used by their driver). So:

  • flush_all now cleans and invalidates line by line, by way and set. It takes 130 µs on this SoC.
  • flush_range always goes line by line. The ≥128 KB shortcut to flush_all was something I added, not the vendor's.
  • Range operations take the lock in 4 KB blocks.
  • disable writes CTRL=0 before cleaning and invalidating, so once the L2 is off, L1 evictions go straight to memory. The vendor's suspend path uses the same order.
  • Only large clean ranges still use whole-way cleans, which can't lose data.

To check this on hardware, I built a test kernel that maps one page twice: cached, and through an uncached alias that sees DRAM. It puts a dirty value in the L2 over a different value in DRAM, then checks each operation (64 lines each):

operation result
invalidate by address drops the dirty L2 copy 64/64
clean by address, then SYNC (or 5 µs), reaches DRAM 64/64
clean by way/set reaches DRAM 64/64
clean+invalidate by way/set: in DRAM, then gone from the L2 64/64
driver inv_range on a partial line keeps the dirty rest of the line 64/64
driver flush_all: in DRAM, then gone from the L2 pass

(One side note: a by-address clean is posted. Read back with no SYNC in between, it hadn't reached DRAM yet. That's fine, since the driver selects OUTER_CACHE_SYNC and DMA is always preceded by outer_sync().)

L2_INTCLR. You were right: it's write-1-to-clear. After a way operation RINT read 0x4000. Writing 0 left it at 0x4000, and writing the value back cleared it. Init now writes back the bits it reads from RINT.

SATA PORT_BUG_BYPASS before CRG_HRST. The order is the vendor's (hi_sata_phy_clk_sel() runs before hi_sata_unreset()), and it works because HRST is never asserted at power-on: PERI_CRG45 reads 0x00000000 at the U-Boot prompt after a cold boot, with only the clocks off. After a cold boot both ports' register reads back 0x3f24. A comment now says so.

Smaller things.

  • Added YAML bindings for hisilicon,hi3520dv200-l2cache, hisilicon,hi3520dv200-ahci (with hisilicon,phy-config) and hisilicon,hi3520dv200-sfc, each as its own dt-bindings: commit before its driver. dt_binding_check passes, and dtbs_check reports nothing for these nodes.
  • Writing the SFC binding showed that the generic num-cs is a u32, while I'd read it as u16 with /bits/ 16 in the DT. The driver now reads a u32 and the DT uses the plain form.
  • The hieth-sf comment is back above the MDIO/Ethernet nodes.

Retested on the NBD6808T-PL with the reworked L2: a 24 MB random file written to SATA and read back after dropping caches matches. 256 MB through ext4 runs at 64–69 MB/s writing and 72–74 MB/s reading, as before. TCP transfers both ways (24 MB out, 20 MB in) match by md5. gzip of 8 MB takes 4.8 s, where it was 4.95 s with the old driver. reboot -f resets the board through the new disable path. Every commit builds on its own, and checkpatch --strict is clean apart from MAINTAINERS notes.

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.

2 participants