Skip to content

allwinner: V3s and V851s machines; DRAM sizing and watchdog fixes - #205

Merged
dimerr merged 3 commits into
OpenIPC:masterfrom
dimerr:allwinner-cam
Oct 25, 2026
Merged

dimerr merged 3 commits into
OpenIPC:masterfrom
dimerr:allwinner-cam

Conversation

@dimerr

@dimerr dimerr commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

Two more Allwinner camera SoCs, -M v3s (sun8iw8) and -M v851s (sun8iw21), in hw/arm/allwinner-cam.c. They reuse the V831 machine's devices at these SoCs' addresses, which is enough for OpenIPC's mainline U-Boot (openipc-allwinner on OpenIPC/u-boot) and the kernels it boots. As on v831, an eGON.BT0 at SD sector 16 wins over the one at NOR offset 0, and boot_media says which.

V3s V851s
map H3 generation, SRAM at 0 D1/T113 ("NCAT2"), ROM at 0, SPL in SRAM at 0x20000
CCU aw-ccu gen=1 (sun6i PLL lock bits) aw-ccu
extras EMAC with the internal PHY SPI0's DRQs on aw-dma (the vendor SPI driver reads the root through it)

Model changes, also used by v831/v833:

  • aw-dramcom (the DRAM controller's COM block) remaps the 2 GiB DDR window while the geometry programmed in it differs from the part's. A DRAM driver's row, bank and column probes then alias where they do on silicon.
  • aw-dramc reports rank training as a single-rank part does, so the dual-rank probe fails correctly.
  • With these, the vendor V833 boot0 finds 128 MiB, not 4160 MiB. The YI V831 dump still passes every test-v831-boot.sh milestone.
  • aw-wdt reloads only when MODE changes, not on every write. The sun8iw21 kernel rewrites MODE in its restart loop and never saw the watchdog expire.

Tested

  • openipc-allwinner's -nor and -mmc images on both machines: the environment is saved and read back, reset works, and SD unbricking writes an erased NOR.
  • v851s: OpenIPC's published uImage.v851s + rootfs.squashfs.v851s boot from the NOR to a shell (HYP, root on mtdblock3), and reboot -f comes back through the SPL.
  • v851s: the published u-boot-v851s-nor.bin (OpenIPC/u-boot-allwinner, mainline 2024.10) reaches its prompt. Its DRAM, CCU and PRCM registers equal those of openipc-allwinner's build.

docs/allwinner-cam.md has the maps and details. The U-Boot side is in the OpenIPC/u-boot PRs that add the V3s and V851s; their CI smoke legs need these machines.

…ites

aw-dramcom (the DRAM controller's COM block) remaps the 2 GiB DDR window
while the geometry programmed in its first register is not the part's,
as the controller's address mapping would: a DRAM driver's row, bank and
column probes alias where they do on silicon. aw-dramc reports rank
training as a single-rank part does (DTCR rank 1 enabled -> PGSR0 and the
DX GSR0 rank errors), so the dual-rank probe fails as it should.

The V831's and V833's geometry (8K rows, 4 or 8 banks, 2 KiB pages) is
in their machine config. The vendor V833 boot0 now finds 128 MiB, not
4160; the V831 dump boots as before (test-v831-boot.sh, every milestone).

aw-wdt reloaded its counter on every MODE write. The sun8iw21 kernel's
restart handler rewrites MODE in its wait loop and never saw it expire;
now only enabling it or a new interval reloads, as on silicon.
Two more Allwinner camera SoCs with the V831 machine's devices at their
addresses, for OpenIPC's mainline U-Boot (openipc-allwinner) and the
kernels it boots:

- v3s (sun8iw8): the H3 generation, SRAM at 0, its EMAC with the PHY
  inside; aw-ccu gen=1 for the sun6i PLL lock bits.
- v851s (sun8iw21): the D1/T113 map, the ROM at 0 and the SPL in SRAM at
  0x20000, SPI0's DRQs on aw-dma (the vendor SPI driver reads the root
  through it).

As on the V831 machine, an eGON.BT0 at SD sector 16 wins over the one at
NOR offset 0, and boot_media says which.

Tested: openipc-allwinner's -nor and -mmc images on both (environment
saved and read back, reset, SD unbricking onto an erased NOR); on the
v851s, OpenIPC's published kernel and rootfs to a shell from the NOR and
reboot -f back to the SPL, and the published u-boot-v851s-nor.bin to its
prompt with the same DRAM registers. docs/allwinner-cam.md.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add V3s and V851s machines and correct Allwinner DRAM sizing and watchdog

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

Grey Divider

AI Description

• Add V3s and V851s machines that boot OpenIPC firmware from SD or SPI NOR.
• Model DRAM geometry and rank probes so firmware detects the installed memory size.
• Preserve watchdog expiry during kernel restart loops and document the new machines.
Diagram

graph TD
  M["Allwinner machines"] --> B["SD or NOR"] --> S["SPL boot"] --> P["Mapped devices"] --> C["DRAM COM"] --> R[("DDR window")]
  S --> T["DRAM PHY"]
  P --> W["Watchdog"]
  M --> C
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Extend the V83x machine with shared SoC configuration
  • ➕ Could reduce duplicated boot and peripheral setup across four machines.
  • ➖ Would broaden the regression surface for V831/V833.
  • ➖ The SRAM layouts, addresses and optional devices require substantial per-SoC branching.

Recommendation: Keep the separate V3s/V851s machine model for this PR: it isolates their distinct maps while sharing the DRAM and peripheral device models. Consider extracting common machine setup later if additional SoCs make the duplication costly.

Files changed (8) +934 / -8

Enhancement (2) +579 / -1
allwinner-cam.cIntroduce V3s and V851s QEMU machines +562/-0

Introduce V3s and V851s QEMU machines

• Defines their SoC-specific memory maps, interrupts and peripheral wiring, including the V3s internal EMAC PHY and V851s SPI DMA. Emulates SD-first eGON.BT0 boot, SRAM loading, NOR persistence and the V851s ROM entry stub.

qemu/hw/arm/allwinner-cam.c

aw-ccu.cSupport sun6i-generation CCU update bits +17/-1

Support sun6i-generation CCU update bits

• Adds a generation property so the V3s clears its older PLL and DRAM update bits, while existing machines retain the current layout.

qemu/hw/misc/aw-ccu.c

Bug fix (3) +271 / -7
allwinner-v83x.cConnect V831/V833 to geometry-aware DRAM COM +18/-1

Connect V831/V833 to geometry-aware DRAM COM

• Replaces the passive COM register bank with aw-dramcom and supplies each machine's physical DDR geometry. This lets firmware sizing probes see the expected aliases.

qemu/hw/arm/allwinner-v83x.c

aw-dramc.cModel DRAM geometry aliases and single-rank training +244/-4

Model DRAM geometry aliases and single-rank training

• Adds aw-dramcom translation over the DDR window when programmed geometry differs from the installed part. DRAM PHY training now reports missing rank-one status, allowing firmware to reject a dual-rank configuration.

qemu/hw/misc/aw-dramc.c

aw-wdt.cAvoid reloading watchdog on unchanged MODE writes +9/-2

Avoid reloading watchdog on unchanged MODE writes

• Reloads the counter only when the effective MODE value changes. This lets the V851s kernel's restart loop reach watchdog expiry.

qemu/hw/watchdog/aw-wdt.c

Documentation (2) +76 / -0
README.mdList V3s and V851s boot support +10/-0

List V3s and V851s boot support

• Adds both machines to the Allwinner support table and summarizes their tested firmware and boot media.

README.md

allwinner-cam.mdDocument camera-SoC maps, boot behavior and limits +66/-0

Document camera-SoC maps, boot behavior and limits

• Provides a launch example, device address comparison, DRAM sizing behavior and tested boot paths. It also identifies hardware that is not modeled or tested.

docs/allwinner-cam.md

Other (1) +8 / -0
setup.shInclude the camera machines in QEMU setup +8/-0

Include the camera machines in QEMU setup

• Copies allwinner-cam.c into the QEMU source tree and adds it to the existing ALLWINNER_V83X Meson configuration.

qemu/setup.sh

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

qodo-free-for-open-source-projects Bot commented Oct 25, 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. New camera models have no regression test ✓ Resolved
Description
The PR registers v3s and v851s without repository smoke, register-level, or firmware regression
tests, and CI invokes neither machine. When their device maps, DRAM sizing, DMA wiring, watchdog
behavior, or NOR/SD boot paths change, the existing V831/V833 boot script and unrelated CI checks
cannot detect regressions in the new targets.
Code

qemu/hw/arm/allwinner-cam.c[R545-562]

+#define DEFINE_AWC_MACHINE(namestr, tag, config)                     \
+    static void tag##_init(MachineState *machine)                    \
+    {                                                                \
+        awc_common_init(machine, &config);                           \
+    }                                                                \
+    static void tag##_class_init(MachineClass *mc)                   \
+    {                                                                \
+        mc->desc = config.desc;                                      \
+        mc->init = tag##_init;                                       \
+        mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");       \
+        mc->default_ram_size = config.ram_size;                      \
+    }                                                                \
+    DEFINE_MACHINE_EXTENDED(namestr, AWC_MACHINE, AwcMachineState,   \
+                            tag##_class_init, false,                 \
+                            arm_machine_interfaces)
+
+DEFINE_AWC_MACHINE("v3s", v3s, v3s_soc)
+DEFINE_AWC_MACHINE("v851s", v851s, v851s_soc)
Evidence
The changed machine file registers both firmware-capable targets and adds device behavior, while the
related boot script covers only V831/V833. The CI workflow checks other machine families but has no
job for either new target or an Allwinner camera firmware boot; the documented manual boot testing
provides no executable regression coverage.

CLAUDE.md: Provide Appropriate Machine and Device Regression Coverage: CLAUDE.md: Provide Appropriate Machine and Device Regression Coverage: CLAUDE.md: Provide Appropriate Machine and Device Regression Coverage: CLAUDE.md: Provide Appropriate Machine and Device Regression Coverage
qemu/hw/arm/allwinner-cam.c[545-562]
qemu-boot/test-v831-boot.sh[1-8]
docs/allwinner-cam.md[49-59]
qemu/hw/arm/allwinner-cam.c[561-562]
.github/workflows/ci.yml[27-52]
README.md[278-286]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `v3s` and `v851s` machines and their DRAM, DMA, CCU, watchdog, and boot-ROM behavior lack repository regression coverage, and CI does not boot either target.
## Fix Focus Areas
- qemu/hw/arm/allwinner-cam.c[545-562]
- qemu-boot/test-v831-boot.sh[1-8]
- .github/workflows/ci.yml[27-140]
## Recommended Fix
Add a focused qtest or smoke test for both machines that checks registration, key device mappings, DRAM sizing, watchdog expiry after MODE rewrites, and boot from NOR and SD. Include any required firmware fixtures, run the tests in CI, and fail on unsuccessful startup or reset, assertions, core dumps, and unexpected QEMU errors rather than relying on manual firmware testing.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. V3s clock unit boots with wrong PLL value ✓ Resolved
Description
aw_ccu_reset_hold() applies the H6-layout PLL_PERI0 preset 0xA0006300 at offset 0x020 for
every gen, although gen=1 maps that offset to PLL_DDR and places PLL_PERIPH0 at 0x028. On `-M
v3s`, firmware reads the peripheral-PLL factors from PLL_DDR while PLL_PERIPH0 reads as zero,
affecting clocks used before DRAM and SPI configuration.
Code

qemu/hw/misc/aw-ccu.c[R72-77]

+    if (s->gen == 1) {
+        if (addr == 0x0f4) {
+            val &= ~(1u << 16);
+        } else if (addr == 0x020) {
+            val &= ~(1u << 20);
+        }
Evidence
The V3s machine selects gen=1, and the CCU model's gen=1 branch treats offset 0x020 as the sun6i
DDR PLL, including its bit-20 update behavior. The unconditional reset table instead labels and
initializes that offset as the other generation's peripheral PLL, leaving the gen=1 peripheral PLL
offset without its intended preset.

qemu/hw/misc/aw-ccu.c[41-51]
qemu/hw/misc/aw-ccu.c[92-101]
qemu/hw/misc/aw-ccu.c[72-79]
qemu/hw/arm/allwinner-cam.c[128-130]
qemu/hw/misc/aw-ccu.c[8-12]
qemu/hw/misc/aw-ccu.c[46-52]
qemu/hw/misc/aw-ccu.c[72-77]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
V3s selects the sun6i CCU layout, but `aw_ccu_reset_hold()` seeds its DDR PLL register at `0x020` with the H6-layout peripheral PLL value and leaves its peripheral PLL register at `0x028` uninitialized.
## Fix Focus Areas
- qemu/hw/arm/allwinner-cam.c[128-130]
- qemu/hw/misc/aw-ccu.c[41-54]
- qemu/hw/misc/aw-ccu.c[92-105]
## Recommended Fix
Select reset values based on `s->gen` in `aw_ccu_reset_hold()`. Use a separate `gen=1` reset table that puts the sun6i PLL_PERIPH0 default `0x90041811` at `0x028` and leaves PLL_DDR at `0`, while preserving the existing `gen=0` reset layout.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Oversized V3s boot image is silently truncated ✓ Resolved
Description
awc_boot0_ok() accepts eGON.BT0 lengths up to AWC_BOOT0_MAX (0x18000), but V3s maps only 0x10000
bytes of SRAM and rom_add_blob_fixed() loads the validated plen at c->sram_base. When an SD or
NOR boot image declares between 64 and 96 KiB, its tail extends beyond mapped SRAM, leaving
subsequent guest execution or data access without backing instead of reporting an invalid boot
image.
Code

qemu/hw/arm/allwinner-cam.c[R495-496]

+    boot0[AWC_EGON_BOOT_MEDIA] = media;
+    rom_add_blob_fixed("awc.boot0", boot0, plen, c->sram_base);
Evidence
AWC_BOOT0_MAX is 0x18000 at line 57, while v3s_soc.sram_size is 0x10000 at line 103. The
validator checks the declared length only against AWC_BOOT0_MAX at line 256, and the loader passes
that validated length to rom_add_blob_fixed() at line 496 without checking the selected SoC's SRAM
capacity.

qemu/hw/arm/allwinner-cam.c[57-57]
qemu/hw/arm/allwinner-cam.c[102-103]
qemu/hw/arm/allwinner-cam.c[250-257]
qemu/hw/arm/allwinner-cam.c[54-59]
qemu/hw/arm/allwinner-cam.c[98-104]
qemu/hw/arm/allwinner-cam.c[250-256]
qemu/hw/arm/allwinner-cam.c[298-300]
qemu/hw/arm/allwinner-cam.c[484-496]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The V3s boot-image validator accepts eGON.BT0 lengths larger than the SRAM mapped at the load address, so a validated SD or NOR image can extend into unmapped memory.
## Fix Focus Areas
- qemu/hw/arm/allwinner-cam.c[98-104]
- qemu/hw/arm/allwinner-cam.c[250-256]
- qemu/hw/arm/allwinner-cam.c[475-496]
## Recommended Fix
Before `rom_add_blob_fixed()`, check the declared `plen` against the selected SoC's `c->sram_size` for both SD and NOR candidates. If it exceeds that size, call `error_report()` with the image and SRAM sizes and exit with status 1. Retain the larger boot-image limit for V851s, whose SRAM mapping supports it.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread qemu/hw/arm/allwinner-cam.c
Comment thread qemu/hw/misc/aw-ccu.c
Comment thread qemu/hw/arm/allwinner-cam.c
…esets, SPL size

- qemu/tests/test-allwinner-cam.py, run in CI: for v3s and v851s, the
  boot ROM stand-in (the NOR's SPL, the SD card's winning, boot_media,
  the ROM stub, an SPL past the SRAM refused), aw-ccu's lock bits and the
  sun6i update bits and presets, single-rank training, aw-dramcom's
  aliasing by the programmed geometry, and the watchdog: restarted it
  stays armed, MODE rewrites do not hold off the reset (the old model
  fails that). Verify machines also lists v831, v833, v3s, v851s.
- aw-ccu: gen 1 (the sun6i layout) gets its own reset presets:
  PLL_PERIPH0 at 0x028, PLL_DDR at 0x020 off, instead of the H6's
  PLL_PERI0 value at 0x020.
- allwinner-cam: an eGON.BT0 longer than the SoC's SRAM (64 KiB on the
  V3s) is an error, not loaded past the SRAM.

openipc-allwinner's images on all four machines and the V831 vendor dump
boot as before.
@dimerr
dimerr merged commit d864735 into OpenIPC:master Oct 25, 2026
23 checks passed
@dimerr
dimerr deleted the allwinner-cam branch October 25, 2026 08:55
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