Skip to content

allwinner: add U-Boot for V831 and V833 - #65

Merged
dimerr merged 8 commits into
openipc-allwinnerfrom
allwinner/v83x-port
Oct 25, 2026
Merged

dimerr merged 8 commits into
openipc-allwinnerfrom
allwinner/v83x-port

Conversation

@dimerr

@dimerr dimerr commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

U-Boot for the Allwinner V831 (64 MiB DDR2 in the package) and V833 (128 MiB DDR3): mainline v2022.10 with the same OpenIPC boot layer as openipc-novatek (identical common/openipc.c), as a new mainline sunxi SoC, MACH_SUN8I_V831 (H6-style peripherals, clocks and memory map). It has its own SPL, so no vendor boot0, OP-TEE or boot package is carried. The base branch is v2022.10, as openipc-novatek's was.

Two images per SoC, the same layout:

Offset Contents
0x00000 the SPL (eGON.BT0): clocks, DDR, then U-Boot
0x08000 U-Boot, an LZMA legacy image (unpacked it is 257 KiB, over the partition)
0x40000 the environment; kernel at 0x50000, as on the other families
  • u-boot-<soc>-nor.bin (~170 KiB) is written at flash offset 0.
  • u-boot-<soc>-mmc.bin is for unbricking. Write it to an SD card at 8 KiB (dd ... bs=1k seek=8); the boot ROM tries the card before the flash. Booted from the card, source is fatload mmc 0, so run ub and run fwupd take u-boot-<soc>-nor.bin, uImage.<soc> and rootfs.squashfs.<soc> from its FAT partition. The environment stays in the NOR.

DRAM

  • The vendor boot0's DRAM library (libdram, shipped as a binary object) is translated to C function for function: arch/arm/mach-sunxi/dram_sun8i_v831.c. It is an older revision of mainline's D1/T113 dram_sun20i_d1.c, at other addresses.
  • Checked under qemu against the vendor boot0 from a YI camera's flash. After both, every DRAM controller, PHY, PLL_DDR, MBUS, DRAM clock and ZQ register is equal, with the V831's parameters and with the V833's (DDR3, rank/width/size scan).
  • The parameters are the vendor's dram_para, from sys_config.fex.

Kernel hand-off

  • OpenIPC's allwinner-v83x kernels carry no device tree. U-Boot boots them with the vendor one it carries, gzipped (12 KiB): the Tina SDK's reference board, with the changes the vendor U-Boot makes before booting from NOR, traced under qemu.
  • It boots them through ${fdtaddr}, the same small boot/image-fdt.c change as on openipc-novatek.
  • The kernel runs in the normal world (HYP), with PSCI 1.0 from U-Boot's monitor, as it expects from OP-TEE.

Small mainline patches

  • lib/lzma/LzmaTools.c: the SPL link fix for SPL_LZMA.
  • common/spl/spl_mmc.c: unpack an LZMA image from the card.
  • sunxi env_get_location(): fall back to the SPI flash after an MMC boot.
  • ARCH_SUNXI without binman for this SoC: pylibfdt no longer builds with current setuptools, so build.sh puts the image together.

CLAUDE.md has the boot flow, the patched mainline files and what was verified where.

Verified under qemu-bench v831/v833:

  • The DRAM register comparison with the vendor boot0.
  • The two-boot smoke test, NOR and SD card, both SoCs (64/128 MiB).
  • An OpenIPC allwinner-v83x kernel (v83x.generic.config) boots on a SquashFS root to a shell: PSCI 1.0, cmdlinepart on spi0.0 with the OpenIPC partitions, root on mtdblock3. Its sunxi-gmac pings the host, and reboot comes back through the SPL.
  • U-Boot: ping and tftp, mmc info and fatls, saveenv and reset, the boot-limit failsafe, TFTP and SD unbricking of an erased flash.

Not verified on silicon yet.

  • qemu completes the DRAM training at once, so DDR timing, PLL rates and dividers, pads, the PHY reset and clock are untested.
  • The SD SPL relies on the boot ROM writing the boot-media byte, as the H6's does. That the V831's ROM does is assumed.

Keep a flash backup and a programmer (or the SD card) at hand.

CI (build-allwinner.yml) comes in the PR against openipc. Its -mmc smoke legs need OpenIPC/qemu-bench#204, the boot ROM stand-in booting from the SD card.

The firmware scan, recovery and boot-limit failsafe of the
openipc-hisilicon branch, for the Allwinner V831/V833: common/openipc.c
and include/openipc.h as on openipc-novatek and openipc-anyka, unchanged.
CONFIG_OPENIPC builds it; PRODUCT_SOC and PRODUCT_SOCMODEL name the
target in the environment.
LzmaTools.c was guarded by CONFIG_LZMA, so with SPL_LZMA alone the SPL's
spl_load_legacy_img() did not link (undefined lzmaBuffToBuffDecompress).
CONFIG_IS_ENABLED(LZMA), as later mainline has it.
One Cortex-A7 with the H6's peripherals, clocks and memory map, and the
DDR in the package (V831: 64 MiB DDR2, V833: 128 MiB DDR3): a new SoC,
MACH_SUN8I_V831, selecting SUN50I_GEN_H6, with its own SPL in place of
the vendor's boot0, OP-TEE and boot package.

- DRAM: dram_sun8i_v831.c is the vendor boot0's DRAM library (libdram,
  shipped as a binary object), translated to C function for function and
  register write for register write. It drives the D1/T113 controller of
  mainline's dram_sun20i_d1.c, at 0x04002000/0x04003000, in an older
  revision of the library (timings computed and stored back, DDR2/DDR3
  scan). Checked under QEMU against the vendor's boot0 on a camera's
  flash: with the V831's and with the V833's parameters every DRAM
  controller, PHY, PLL_DDR, MBUS, DRAM clock and ZQ register is equal
  after both. The size it finds is checked with get_ram_size().
- Clocks as boot0 sets them: PLL_PERI0 1.2 GHz (2X), AHB 200, APB1
  100 MHz, the MBUS reset released (its clock follows the DRAM's), CPU
  816 MHz after the DDR, as the vendor U-Boot sets it.
- SPL from SPI NOR: the H6's SPI0 on the H3's pins (PC0-PC3, function
  4), and an LZMA legacy image (U-Boot does not fit the 256 KiB boot
  partition unpacked). The images boot from SPI NOR alone, so a valid
  eGON header means SPI: QEMU's boot ROM does not write the boot-media
  byte.
- UART0 on PH9/PH10 (function 5). The SPL's BSS inside 64 MiB.
- PSCI 1.0 for the vendor kernels, which expect OP-TEE's: version,
  features, CPU_OFF, SYSTEM_RESET (the watchdog). One core, no CPU_ON.
- U-Boot's device tree (sun8i-v831.dtsi): the CCU is the H6's for every
  gate U-Boot uses (vendor clk-sun8iw19.h), so it maps to the H6 table;
  a V831 pinctrl table; SPI as the H3's, MMC as the H6's, the EMAC as the
  A64's (no internal PHY).
- No binman for this SoC: it needs pylibfdt, which current setuptools
  no longer builds for 2022.10; build.sh puts the image together.
OpenIPC's V83x kernels (Linux 4.9) carry no device tree; the vendor
U-Boot gives them its own. v83x-kernel.dts is that tree: the Tina V83x
SDK's reference board over the kernel's sun8iw19p1.dtsi, flattened, with
what the vendor U-Boot changes in it before booting from SPI NOR, traced
under QEMU from a camera's flash: SPI0 enabled (the flash, the root
filesystem); OP-TEE's memreserve dropped. It is gzipped into U-Boot
(12 KiB), unpacked at misc_init_r() to ${fdtaddr}, and a plain uImage
boots with it (boot/image-fdt.c, as on openipc-novatek). ft_board_setup()
sets /dram/dram_para2 to the size, as the vendor does.

The board also clocks the RMII PHY (EPHY_25M, the vendor tree's
use_ephy25m) and runs the OpenIPC helper from misc_init_r().

Under QEMU an OpenIPC allwinner-v83x kernel boots on it to a shell:
PSCIv1.0, HYP mode, cmdlinepart on spi0.0, SquashFS root on mtdblock3,
sunxi-gmac pings the host, reboot comes back through the SPL.
build.sh builds u-boot-v831-nor.bin and u-boot-v833-nor.bin: the SPL
(eGON.BT0) padded to 0x8000, then U-Boot as an LZMA legacy image, ~170 KiB
in all; it fails a build over the 256 KiB boot partition or with an SPL
over 32 KiB. The configuration is openipc/openipc_config plus the SoC's
fragment, which carries the vendor's dram_para words: the V831 reference
boards' (DDR2, 528 MHz, fixed geometry) and the V833 lindenis board's
(DDR3, 792 MHz, scanned).

include/configs/openipc-common.h is openipc-novatek's environment with
this family's parameters: vendor "allwinner", mem= the whole DDR, the
kernel staged at 0x41000000, the flash's MTD name spi0.0, console ttyS0.

Under QEMU (qemu-bench -M v831/v833) both images reach the autoboot
prompt, and a second boot loads the environment the first saved.
The boot ROM tries the SD card before the SPI NOR: an eGON.BT0 at
sector 16 wins. build.sh now also builds u-boot-<soc>-mmc.bin, the NOR
image's layout with an SPL that loads U-Boot from the card
(openipc/mmc_config: SPL_MMC; U-Boot 32 KiB after the SPL, sunxi's
default), to be written to the card at 8 KiB. It is the unbricking path:

- Booted from the card, `source` is `fatload mmc 0` for that boot (as
  after srcmmc, not saved), so ub, ur, uk and fwupd take their files
  from the card's FAT partition and write them to the NOR.
- The environment stays in the SPI NOR. sunxi's env_get_location()
  picks FAT or MMC after an MMC boot, neither of which is built in, and
  env_init() failed with -ENODEV before the console came up: fall back
  to the SPI flash.
- The SPL's MMC raw loader read legacy images to their load address as
  they are; an LZMA one is now read whole and unpacked by
  spl_load_legacy_img().

Under qemu-bench (whose ROM stand-in now tries the card first and writes
the boot-media byte): both SoCs boot from a card with an erased NOR, and
a second boot loads the environment the first saved. A card with the
-mmc image and u-boot-v831-nor.bin, uImage.v831, rootfs.squashfs.v831
unbricks an erased NOR: run ub, run fwupd, then the NOR boots the
kernel to its root without the card.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add OpenIPC U-Boot support for Allwinner V831 and V833

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

Grey Divider

AI Description

• Add self-contained V831/V833 SPL and U-Boot images for NOR boot and SD-card recovery.
• Initialize packaged DDR and peripherals; supply PSCI and a device tree to OpenIPC kernels.
• Reuse OpenIPC recovery and failsafe flows; document QEMU verification and silicon risks.
Diagram

graph TD
  ROM["Boot ROM"] --> SPL["V83x SPL"] --> DRAM["DDR init"] --> UB["LZMA U-Boot"] --> OI["OpenIPC boot"] --> K["Vendor kernel"]
  MEDIA[("NOR or SD")] --> SPL
  MEDIA --> OI
  DT["Bundled DT"] --> K
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Retain the vendor boot chain
  • ➕ Avoids replacing silicon-dependent DRAM training before hardware validation.
  • ➕ Uses an established kernel hand-off.
  • ➖ Requires vendor boot artifacts instead of a self-contained SPL.
  • ➖ Does not meet the mainline-based boot objective.
2. Adapt the mainline D1/T113 DRAM driver
  • ➕ Could reduce long-term duplication of controller logic.
  • ➖ V83x addresses and its older training sequence differ.
  • ➖ A rewrite would complicate register-by-register comparison with vendor boot0.

Recommendation: Keep the self-contained SPL and function-for-function DRAM translation: they meet the packaging goal and support direct comparison with vendor boot0. Require silicon validation of DDR training, clocks, pads, and SD boot-media detection before deployment.

Files changed (43) +6634 / -17

Enhancement (26) +5748 / -11
MakefileSelect the V83x PSCI implementation +4/-0

Select the V83x PSCI implementation

• Links the V83x-specific monitor instead of the generic sunxi PSCI object for this SoC.

arch/arm/cpu/armv7/sunxi/Makefile

psci_v831.cImplement single-core PSCI 1.0 services +80/-0

Implement single-core PSCI 1.0 services

• Provides version and feature reporting, CPU-off behavior, and watchdog-backed reset without OP-TEE.

arch/arm/cpu/armv7/sunxi/psci_v831.c

sun8i-v831-openipc.dtsDescribe OpenIPC V83x board wiring +75/-0

Describe OpenIPC V83x board wiring

• Enables UART, SPI NOR, SD, and RMII Ethernet with board-specific PHY settings.

arch/arm/dts/sun8i-v831-openipc.dts

sun8i-v831.dtsiDescribe V831/V833 hardware for U-Boot +209/-0

Describe V831/V833 hardware for U-Boot

• Defines CPU, clocks, interrupt controller, pinctrl, UART, SPI, MMC, and EMAC at V83x addresses.

arch/arm/dts/sun8i-v831.dtsi

clock_sun50i_h6.hDefine V83x early-clock settings +12/-0

Define V83x early-clock settings

• Adds PLL_PERI0 and bus-clock defaults matching the vendor boot configuration.

arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h

dram.hSelect V83x DRAM definitions +2/-0

Select V83x DRAM definitions

• Includes the SoC-specific DRAM header.

arch/arm/include/asm/arch-sunxi/dram.h

dram_sun8i_v831.hDefine V83x DRAM type identifiers +15/-0

Define V83x DRAM type identifiers

• Names DDR2, DDR3, LPDDR2, and LPDDR3 values consumed by DRAM initialization.

arch/arm/include/asm/arch-sunxi/dram_sun8i_v831.h

gpio.hDefine the V83x UART pin function +1/-0

Define the V83x UART pin function

• Adds the mux value for UART0 on PH9 and PH10.

arch/arm/include/asm/arch-sunxi/gpio.h

MakefileLink V83x DRAM initialization +1/-0

Link V83x DRAM initialization

• Builds the new DRAM source when its controller selection is enabled.

arch/arm/mach-sunxi/Makefile

board.cInitialize UART pins and distinguish boot media +13/-0

Initialize UART pins and distinguish boot media

• Sets V83x UART pins and treats valid NOR-only SPL headers as SPI boots regardless of the boot-media byte.

arch/arm/mach-sunxi/board.c

clock_sun50i_h6.cAdapt early H6 clock setup for V83x +15/-1

Adapt early H6 clock setup for V83x

• Applies vendor-style power and CPU-clock settings and releases MBUS reset using the V83x clock arrangement.

arch/arm/mach-sunxi/clock_sun50i_h6.c

cpu_info.cIdentify V831/V833 on the console +2/-0

Identify V831/V833 on the console

• Prints the new SoC family name during CPU identification.

arch/arm/mach-sunxi/cpu_info.c

dram_sun8i_v831.cBring up packaged V831/V833 DRAM +1069/-0

Bring up packaged V831/V833 DRAM

• Translates the vendor DRAM library's clock, controller, PHY, training, and geometry-scan sequence into C. Checks the detected capacity against accessible RAM.

arch/arm/mach-sunxi/dram_sun8i_v831.c

spl_spi_sunxi.cLoad compressed U-Boot from V83x SPI NOR +28/-10

Load compressed U-Boot from V83x SPI NOR

• Reuses the H6-style SPI controller and adds an SPL path for LZMA legacy images.

arch/arm/mach-sunxi/spl_spi_sunxi.c

MakefileEmbed the compressed vendor kernel tree +16/-0

Embed the compressed vendor kernel tree

• Builds V83x board hooks and compiles a gzipped kernel DTB into U-Boot proper.

board/sunxi/Makefile

board.cWire V83x board and OpenIPC boot hooks +29/-0

Wire V83x board and OpenIPC boot hooks

• Initializes board hardware, unpacks the kernel tree, runs OpenIPC recovery and scan logic, and selects SD as an update source after SD boot. Keeps the environment in SPI NOR.

board/sunxi/board.c

v83x-kernel.dtsBundle a vendor-compatible kernel device tree +3227/-0

Bundle a vendor-compatible kernel device tree

• Carries the flattened Tina reference-board tree expected by OpenIPC V83x kernels, including SPI NOR and peripheral descriptions.

board/sunxi/v83x-kernel.dts

v83x.cPrepare board hardware and kernel hand-off +82/-0

Prepare board hardware and kernel hand-off

• Enables the PHY clock, unpacks and exposes the kernel DTB, selects the SD update source when appropriate, and fixes up DRAM size.

board/sunxi/v83x.c

v83x_kernel_dtb.SExpose embedded kernel DTB symbols +10/-0

Expose embedded kernel DTB symbols

• Includes the gzipped vendor kernel DTB in read-only data for board initialization.

board/sunxi/v83x_kernel_dtb.S

image-fdt.cPass the bundled tree to legacy kernels +13/-0

Pass the bundled tree to legacy kernels

• Allows a V83x plain uImage to boot with the validated device tree referenced by fdtaddr.

boot/image-fdt.c

MakefileBuild the OpenIPC helper when enabled +2/-0

Build the OpenIPC helper when enabled

• Links the shared firmware boot and recovery implementation under CONFIG_OPENIPC.

common/Makefile

openipc.cAdd OpenIPC firmware scanning and recovery +765/-0

Add OpenIPC firmware scanning and recovery

• Carries firmware detection, removable-media recovery, environment initialization, and boot-limit failsafe migration.

common/openipc.c

spl_mmc.cUnpack compressed legacy images from SD +46/-0

Unpack compressed legacy images from SD

• Reads a complete LZMA legacy image from MMC before invoking the SPL decompressor.

common/spl/spl_mmc.c

clk_sunxi.cBind V83x CCU to H6 clock descriptors +2/-0

Bind V83x CCU to H6 clock descriptors

• Adds the V83x CCU compatible string to the existing H6 clock-driver match table.

drivers/clk/sunxi/clk_sunxi.c

pinctrl-sunxi.cMap V83x peripheral pin functions +23/-0

Map V83x peripheral pin functions

• Defines GPIO, EMAC, MMC, SPI, and UART mux functions and binds the V83x pinctrl compatible string.

drivers/pinctrl/sunxi/pinctrl-sunxi.c

openipc.hDeclare OpenIPC board helper interfaces +7/-0

Declare OpenIPC board helper interfaces

• Exposes RAM-sizing and boot-helper declarations to board code.

include/openipc.h

Bug fix (1) +1 / -1
LzmaTools.cInclude LZMA decompression in SPL builds +1/-1

Include LZMA decompression in SPL builds

• Uses an SPL-aware configuration check so SPL_LZMA links the decompressor without full U-Boot LZMA.

lib/lzma/LzmaTools.c

Documentation (1) +236 / -0
CLAUDE.mdDocument the V83x port and verification limits +236/-0

Document the V83x port and verification limits

• Explains boot layout, DRAM provenance, kernel hand-off, builds, QEMU checks, and untested silicon behavior.

CLAUDE.md

Other (15) +649 / -5
ci.ymlCall the shared Allwinner build workflow +25/-0

Call the shared Allwinner build workflow

• Runs the shared build and smoke workflow on branch pushes and pull requests, passing the checked-out SHA.

.github/workflows/ci.yml

KconfigAvoid binman for V83x +1/-1

Avoid binman for V83x

• Makes sunxi's binman selection conditional so the build script can assemble V83x images without pylibfdt.

arch/arm/Kconfig

MakefileBuild the V83x U-Boot device tree +2/-0

Build the V83x U-Boot device tree

• Registers the OpenIPC board DTB when the new SoC is selected.

arch/arm/dts/Makefile

KconfigConfigure the V831/V833 sunxi SoC +107/-3

Configure the V831/V833 sunxi SoC

• Introduces SoC and DRAM selections, vendor-derived DRAM parameters, clock defaults, and SPL SPI eligibility.

arch/arm/mach-sunxi/Kconfig

build.shBuild bounded NOR and SD images +102/-0

Build bounded NOR and SD images

• Combines configuration fragments, builds both SoCs out of tree, LZMA-packs U-Boot, and places it after SPL. Rejects images exceeding SPL or boot-partition limits.

build.sh

KconfigConfigure OpenIPC boot and product identity +21/-0

Configure OpenIPC boot and product identity

• Adds the OpenIPC selection and product SoC strings exposed in the environment.

common/Kconfig

KconfigPlace V83x SPL BSS within packaged DDR +1/-0

Place V83x SPL BSS within packaged DDR

• Sets an SPL BSS address that fits the 64 MiB V831 configuration.

common/spl/Kconfig

KconfigEnable H6 clock support on V83x +1/-1

Enable H6 clock support on V83x

• Selects the existing H6 clock driver by default for the new SoC.

drivers/clk/sunxi/Kconfig

KconfigEnable V83x pinctrl support +5/-0

Enable V83x pinctrl support

• Adds a V83x PIO driver selection defaulting on for the new SoC.

drivers/pinctrl/sunxi/Kconfig

openipc-common.hDefine the OpenIPC NOR boot environment +135/-0

Define the OpenIPC NOR boot environment

• Provides memory and flash layout values alongside boot, update, recovery, network, and failsafe commands.

include/configs/openipc-common.h

v83x.hSet V83x memory, GIC, and environment defaults +30/-0

Set V83x memory, GIC, and environment defaults

• Selects packaged-DDR capacity, identifies the GIC for non-secure hand-off, and replaces the distro environment with OpenIPC settings.

include/configs/v83x.h

mmc_configEnable raw SD-card SPL loading +8/-0

Enable raw SD-card SPL loading

• Adds SPL MMC settings for loading U-Boot at the expected sector offset after the SD boot header.

openipc/mmc_config

openipc_configDefine the shared V83x OpenIPC build profile +178/-0

Define the shared V83x OpenIPC build profile

• Configures SPL, PSCI, compressed loading, NOR environment, SD recovery, networking, and OpenIPC commands.

openipc/openipc_config

v831_configSupply V831 DDR2 parameters +16/-0

Supply V831 DDR2 parameters

• Sets V831 identity and vendor-derived 64 MiB DDR2 clock, timing, and training parameters.

openipc/v831_config

v833_configSupply V833 DDR3 parameters +17/-0

Supply V833 DDR3 parameters

• Sets V833 identity and vendor-derived 128 MiB DDR3 parameters, including geometry scanning.

openipc/v833_config

@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 (2) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Target builds fail without model names 📘 Rule violation ≡ Correctness
Description
The V831 and V833 configuration fragments define CONFIG_PRODUCT_SOC but omit
CONFIG_PRODUCT_SOCMODEL, which the shared environment header unconditionally expands. Building
either target therefore leaves an undefined token in the generated C configuration and cannot
produce U-Boot.
Code

openipc/v831_config[R3-4]

+CONFIG_PRODUCT_SOC="v831"
+CONFIG_DRAM_CLK=528
Evidence
The per-SoC fragments define only CONFIG_PRODUCT_SOC, while the shared environment header
concatenates CONFIG_PRODUCT_SOCMODEL into the default environment. Since build.sh creates each
target configuration solely from the shared fragment and its per-SoC fragment, both target builds
lack the required model macro.

CLAUDE.md: Register New or Removed SoCs in Build Targets and Configuration: CLAUDE.md: Register New or Removed SoCs in Build Targets and Configuration: CLAUDE.md: Register New or Removed SoCs in Build Targets and Configuration: CLAUDE.md: Register New or Removed SoCs in Build Targets and Configuration
openipc/v831_config[3-4]
openipc/v833_config[4-5]
include/configs/openipc-common.h[81-84]
build.sh[42-49]

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 V831 and V833 configuration fragments do not define `CONFIG_PRODUCT_SOCMODEL`, but the shared OpenIPC environment requires it, so either target can fail during compilation.
## Fix Focus Areas
- openipc/v831_config[3-4]
- openipc/v833_config[4-5]
- include/configs/openipc-common.h[81-84]
## Recommended Fix
Add a target-appropriate `CONFIG_PRODUCT_SOCMODEL` definition to both per-SoC configuration fragments, using the values expected by the V83x environment and preserving the existing `CONFIG_PRODUCT_SOC` definitions.

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


2. SD recovery leaves the kernel unbootable 🐞 Bug ≡ Correctness
Description
recovery_write() skips the legacy image header and writes only its payload to the NOR kernel
offset. When recovery finds uImage..img, the normal flash boot later reads that region and passes
its headerless contents to bootm, while the ordinary update command writes the complete image.
Code

common/openipc.c[R398-401]

+  if (image_check_magic(&hdr)) {
+    addr = image_get_load(&hdr);
+    offset = sizeof(hdr);
+    size = image_get_data_size(&hdr);
Evidence
Recovery selects the suffixed kernel image, advances past its header before reading, and writes only
those bytes to flash. Normal boot invokes bootm on the same flash region; the regular update path
instead writes the whole downloaded image.

common/openipc.c[398-426]
common/openipc.c[482-490]
include/configs/openipc-common.h[99-120]

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

## Issue description
SD recovery strips the legacy header before flashing the kernel, but normal NOR boot requires a bootable image at that offset.
## Fix Focus Areas
- common/openipc.c[398-426]
- include/configs/openipc-common.h[99-120]
## Recommended Fix
Make recovery write a complete, bootable kernel image at the configured kernel flash offset. Ensure its legacy header specifies a valid RAM load address; do not use the image's flash destination as its kernel load address.

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



Remediation recommended

3. The kernel's advertised idle states fail ✓ Resolved
Description
v83x-kernel.dts assigns the CPU three PSCI idle states, but the new monitor provides no
psci_cpu_suspend() implementation. When the kernel attempts one of those states, the assembly
dispatch reaches the default handler and returns “not implemented.”
Code

board/sunxi/v83x-kernel.dts[R2945-2950]

+		idle-states {
+			entry-method = "arm,psci";
+
+			cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x10000>;
Evidence
The CPU references all three new idle states, each defined with a PSCI suspend parameter. The V831
feature list omits CPU suspend, and the generic dispatch routes it to a handler that returns not
implemented.

board/sunxi/v83x-kernel.dts[2928-2977]
arch/arm/cpu/armv7/sunxi/psci_v831.c[17-76]
arch/arm/cpu/armv7/psci.S[49-76]
arch/arm/cpu/armv7/psci.S[99-119]

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 supplied kernel device tree advertises PSCI CPU idle states, but the V831 monitor does not implement CPU suspend.
## Fix Focus Areas
- board/sunxi/v83x-kernel.dts[2938-2977]
- arch/arm/cpu/armv7/sunxi/psci_v831.c[17-34]
## Recommended Fix
Remove the unsupported CPU idle-state references and definitions from the supplied tree, or implement and advertise CPU suspend for the states the tree exposes.

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


4. Oversized recovery file overwrites U-Boot in RAM 🐞 Bug ☼ Reliability
Description
recovery_write() takes size from the card file's uImage/FIT header and reads that many bytes to
CONFIG_SYS_LOAD_ADDR (0x41000000). Nothing checks the size against RAM or the flash partition. On
the 64 MiB V831, RAM ends at 0x44000000, so a corrupt or oversized image on the SD card overwrites
the relocated U-Boot, its 4 MiB heap or its stack. This happens before the flash write is even
tried.
Code

common/openipc.c[R412-416]

+  if (ret || actread != size) {
+    printf("Recovery: failed to read %s\n", name);
+    return -1;
+  }
+
Evidence
size comes straight from image_get_data_size() or fdt_totalsize() on the file header and goes
straight into fs_read() at the fixed load address. The V831 config sets 64 MiB of RAM and a load
address of 0x41000000.

common/openipc.c[397-416]
include/configs/v83x.h[16-21]
openipc/openipc_config[9-14]

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 recovery code reads a header-declared size into RAM with no upper bound.
## Fix Focus Areas
- common/openipc.c[397-416]
- common/openipc.c[290-302]
## Recommended Fix
Before `fs_read`, reject the image if `size` is larger than the space between `CONFIG_SYS_LOAD_ADDR` and `gd->relocaddr` minus the malloc area, or larger than `recovery_flash->size - addr`. Also reject an `addr` below the kernel partition offset, so the SPL and env cannot be hit.

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



Informational

5. Every sunxi board now falls back to SPI flash env ✓ Resolved
Description
The new ENV_IS_IN_SPI_FLASH fallback sits in the shared prio == 0 default block of
env_get_location(), not behind CONFIG_MACH_SUN8I_V831, even though its comment says it is only
for the V831/V833 images. Any other sunxi build with SPI-flash env enabled will now read and
saveenv to the SPI NOR when it boots from MMC, NAND or FEL (BOOT_DEVICE_BOARD). Before this
change it used the default environment and never touched the flash in those cases.
Code

board/sunxi/board.c[R192-193]

+		if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
+			return ENVL_SPI_FLASH;
Evidence
The fallback is reached for every boot device that did not return earlier in the switch, on every
sunxi SoC. The guard only checks the env backend, not the SoC.

board/sunxi/board.c[149-193]

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 SPI-flash fallback in `env_get_location()` applies to all sunxi SoCs, although it is meant only for V831/V833.
## Fix Focus Areas
- board/sunxi/board.c[188-193]
## Recommended Fix
Change the condition to `if (IS_ENABLED(CONFIG_MACH_SUN8I_V831) && IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH)) return ENVL_SPI_FLASH;` so other sunxi boards keep their old behaviour.

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


6. DRAM tpr3 setting has no effect ✓ Resolved
Description
DRAM_SUN8I_V831_TPR3 is a Kconfig option and sunxi_dram_init() copies it into para->tpr3, but
no code in dram_sun8i_v831.c ever reads para->tpr3. A board config that overrides dram_tpr3
(for example a V833 variant) silently gets no change, which hides any part of the vendor library's
tpr3 handling that was not translated.
Code

arch/arm/mach-sunxi/Kconfig[R578-580]

+config DRAM_SUN8I_V831_TPR3
+	hex "dram_tpr3"
+	default 0xb4787896
Evidence
The Kconfig option exists and goes into the parameter struct, but the driver never reads the field.
By contrast tpr0-2, tpr5-7 and tpr11-13 are all read.

arch/arm/mach-sunxi/Kconfig[566-605]

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

## Issue description
`DRAM_SUN8I_V831_TPR3` is exposed in Kconfig but never used by the DRAM driver.
## Fix Focus Areas
- arch/arm/mach-sunxi/Kconfig[578-580]
- arch/arm/mach-sunxi/dram_sun8i_v831.c
## Recommended Fix
Check the vendor libdram for where tpr3 is used. Then either translate that code, or remove the Kconfig symbol and the struct initialiser so nobody expects it to work.

ⓘ 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 openipc/v831_config Resolved
Comment thread common/openipc.c Resolved
Comment thread board/sunxi/v83x-kernel.dts Resolved
Comment thread board/sunxi/board.c Resolved
Comment thread common/openipc.c Resolved
Comment thread arch/arm/mach-sunxi/Kconfig Resolved
- The kernel device tree advertised three PSCI CPU idle states, which
  U-Boot's PSCI does not implement (no CPU_SUSPEND): left out of
  v83x-kernel.dts, as is the cpu node's reference to them.
- The SPI flash fallback in sunxi's env_get_location() applied to every
  sunxi board with ENV_IS_IN_SPI_FLASH, which would have moved theirs to
  the NOR after an MMC or FEL boot: V831/V833 only.
- DRAM_SUN8I_V831_TPR3 went nowhere: in the vendor library dram_tpr3
  carries the DRAM supply voltages for dram_vol_set(), the PMIC step
  that is not translated. The option is gone; the struct keeps the word,
  so the parameter block is still the vendor's.

Both SoCs' NOR and SD images pass the two-boot smoke test, and the
OpenIPC kernel boots on the new device tree as before.
@dimerr
dimerr merged commit 4b8d9a4 into openipc-allwinner Oct 25, 2026
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