Skip to content

hi3520dv200 agent: complete hardware verification once power-cycle relay is available #97

@widgetii

Description

@widgetii

Context

#96 lands the bare-metal flash agent for hi3520dv200 (V1-era HiSilicon DVR/NVR SoC, Cortex-A9, MX25L25635E 32 MiB NOR on CS1). The PR is verified end-to-end for the parts that don't need many iterations:

  • ✅ Agent boots via the standard fastboot SPL handoff
  • ✅ HISFC350 driver detects the chip on CS1
  • ✅ Macronix EAR-banking exposes the full 32 MiB (lower and upper halves return distinct real data)
  • ✅ Selfupdate works (cache-aware trampoline + cache-flush around copy)
  • ✅ INFO v3 `flash_mem` lets the host stop hardcoding `0x14000000`

Everything else needs a power-cycle relay so we can iterate without burning a manual reset for every guess. Once the relay arrives, the work below should be picked up.

TODO (in order)

1. Stock-firmware backup

Before any write/erase test:
```
defib agent read -p $PORT -a 0x58000000 -s 32MB -o dumps/hi3520dv200-stock-$(date +%Y%m%d-%H%M%S).bin
```
Verify the dump matches a fresh boot (CRC over the same range twice). Store the dump in the repo's `dumps/` (or wherever the project keeps stock backups).

2. High-baud UART (the big blocker)

The bootrom hands UART running off a slow ~2 MHz reference clock (IBRD=1, FBRD=5 → 115200 baud). Anything above ~125 kbaud needs IBRD < 1, which is illegal — `uart_set_baud` rejects it (safety check), and the agent stays at 115200.

Vendor U-Boot `board/godarm/board.c` does:
```c
reg = readl(CRG_REG_BASE + 0xe4);
reg &= ~UART_CKSEL_APB; /* clear bit 13 */
writel(reg, CRG_REG_BASE + 0xe4);
```
to switch UART onto APB clock, then assumes `CONFIG_PL011_CLOCK = CFG_CLK_BUS/4 = 99 MHz` for divisor calculation.

In this PR I implemented the same switch (gated by `UART_CKSEL_REG` / `UART_CKSEL_BIT` Makefile defines) and tried both 99 MHz (vendor U-Boot value) and 198 MHz (`busclk/2`, the value vendor Linux `mach-godarm/core.c uart_clk_init` uses) — neither produced clean 115200 from the agent. Empirical measurements suggested actual rate around 760 kbaud at host=115200 sampling, which doesn't map cleanly to any standard PLL divider.

With a relay, iterate quickly:

  • (a) Read CRG state via `defib agent read -a 0x20030000 -s 4096` to dump the full PLL/divider config; correlate against vendor's `get_bus_clk()` formula in `include/configs/hi3520d.h`.
  • (b) Build with various `UART_CLOCK` values (24M, 54M, 99M, 198M, 396M, 792M); for each, check whether the agent talks at 115200 after CKSEL clear.
  • (c) Once the right value is found, re-enable `UART_CKSEL_REG` in the Makefile, drop the IBRD safety bypass, and confirm `set_baud(921600)` works.
  • (d) Optional: PMU-based runtime calibration (transmit known sequence in PL011 loopback mode, time with CCNT) so the agent self-derives UART_CLOCK without a hardcoded constant.

3. Write / erase / scan verification

After (1) and (2):

  • Erase a known-empty sector (likely `0xFE0000` or anywhere in the upper half), read back, confirm 0xFF.
  • Write a small known pattern (e.g. 256 B of incrementing bytes), read back, confirm match.
  • Re-flash the original sector contents, verify chip back to stock.
  • Run `defib agent scan -p $PORT` over the full 32 MiB and confirm reasonable per-sector classification.

4. Bank-switch boundary cases

Make sure operations that span the 16 MiB boundary work cleanly:

  • A flash_read of length 1 MiB starting at offset `0x0FF8000` (crosses the boundary by 32 KiB).
  • A CRC32 over the full chip — should match the stock dump's CRC.
  • A flash_write_page of a page that lies right on `0x1000000` (first page of upper half).

5. True 4-byte mode investigation (optional, low priority)

EN4B (0xB7) was tried and rejected by the chip even though the controller's `GLOBAL_CONFIG.ADDR_MODE_4B` latched. EAR-banking is a fine workaround for now, but figuring out why the chip ignores EN4B might unlock a small simplification (no per-operation bank-switch overhead). Theories: needs WREN before EN4B, needs reset (RSTEN+RST 0x66/0x99) first, or chip is in a sticky state from boot. Not worth chasing until everything else is solid.

6. Profile JSON

The existing `src/defib/profiles/data/hi3520dv200.json` already has the right `ADDRESS`/`SRAMLIMIT`/etc. for the boot-protocol path. After hardware verification, update its description / tested-flag to mark it as agent-supported.

Hardware pin notes (for whoever picks this up)

  • Board on `/dev/ttyUSB3` (FT232R, ID `A5069RR4`)
  • Vendor SDK U-Boot used as SPL: `/home/dima/work/hi3520dv200_sdk/Hi3520D_SDK_V2.0.5.1/package/image_glibc/u-boot_hi3520d.bin` (228344 B). Cached as `u-boot-hi3520dv200-universal.bin` in defib's firmware cache.
  • Bootrom enters serial-boot mode only on cold reset and only when host floods 0xAA before flash boot — defib's manual-mode handshake handles this when the board is power-cycled while defib is already listening.
  • Board has valid stock firmware in NOR, so power-on always boots into vendor U-Boot. defib catches the bootrom on the next cold reset by detecting silence-after-activity and starting to flood 0xAA.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions