The CeraLive RK3588 multimedia island: the Rockchip MPP service and the
multi_rga 2D engine driver, carried as maintained kernel source and
released as a git am mailbox series.
| What it holds | drivers/video/rockchip/mpp/ and drivers/video/rockchip/rga3/, the UAPI headers they publish, and the integration/ patches to mainline files they need |
| MPP clients compiled | RKVENC2, RKVDEC2, JPGDEC — those three and no others |
| Target kernel | v7.2 (8d3ae59288f1e7d58d76558a6ee96d533bc5019f), mirrored from kernel-pin.env |
| Boards | Radxa Rock 5B+, Orange Pi 5+ |
| Release artifact | a generated git am series, plus its .sha256 — no .deb, no kernel, no image |
| Versioning | CalVer, YYYY.MINOR.PATCH |
| Status | MPP + RGA OWNERSHIP INTEGRATED IN SOURCE. The complete donor/97-member replay, audited vendor backlog, mainline API port, three-core RGA ownership flip, generated series, and fail-closed RGA validation are present and CI-gated. Latest published tag v2026.9.5; both bench boards booted an image whose kernel carries it (patches_commit 6996f96b) from a production slot on 2026-09-21. See AGENTS.md KEY FACTS for what that boot does and does not prove. |
CeraLive already has a patch repository for the RK3588 kernel:
rk3588-kernel-patches. It
carries patch text, and it is very good at it — provenance lanes, byte-parity
proofs, a retirement registry, an ordinal discipline that never reuses a slot.
That model works because those patches are small, externally authored, and mostly
awaiting upstream. The MPP and RGA drivers are none of those things. They are
tens of thousands of lines of vendor code that CeraLive maintains, rebases,
fixes, sanitizes and tests over a long horizon. Code of that size needs what code
gets: review history per change, unit tests, KUnit and fuzz targets, static
analysis, and a release train. A giant opaque .patch file gets none of it.
So the island is source, and the series is generated from it. That inverts the usual relationship: the mailbox series is an output artifact, like a compiled binary, and hand-editing it is a defect rather than a shortcut.
Three merges, not one. Nothing about this stack may be planned as though a driver fix were a single pull request:
island tag ──▶ rk3588-kernel-patches `island/` lane bump
──▶ image `patches_commit` bump
──▶ image build ──▶ device
- Island release. An owner-approved dispatch from canonical
mainregenerates the series from source, byte-compares it against the checked-inpatches/, then atomically claims the requested tag and publishes the immutable release asset with its checksum. The workflow has no tag trigger: an existing tag is refused rather than used as release input. - Consumer lane bump.
rk3588-kernel-patchesconsumes that asset byte-preserved into itsisland/lane. Provenance on anisland/member is its own variant naming the island tag, commit and asset digest — never an upstream cherry-pick stamp, because there is no upstream commit to name. - Image bump. The image's single
kernel_source.patches_commitpin moves to the consumer repository's new commit. That mechanism is unchanged by the island's existence; the image still sees one patch repository and one pin.
The island produces no .deb, is absent from the device image REPOS array
and from fetch-debs.sh, and rides inside linux-image like every other kernel
change.
The Linux driver core binds one driver per platform device, and when two drivers
match one node the winner is module load order — non-deterministic, and therefore
not a design. Every island-owned node therefore carries exactly one
compatible string, matched by exactly one driver.
Mainline rkvdec and rockchip-rga stay built alongside the island. They are
not excluded by Kconfig, deliberately: keeping them built is what makes each
silicon handover reversible by a device-tree change rather than a kernel rebuild,
and it keeps the upstream-migration target alive in the same image.
The per-block table, and the CI lint that enforces it, are in
docs/OWNERSHIP.md.
rk3588-media-island/
├── kernel-pin.env # MIRROR of rk3588-kernel-patches' kernel coordinate — never edited here
├── drivers/video/rockchip/
│ ├── mpp/ # MPP service + the three compiled clients; compat shims nest at mpp/compat/
│ └── rga3/ # multi_rga
├── include/uapi/linux/ # the UAPI headers the drivers publish
├── integration/ # applied MAINLINE-file patches: hooks, providers and MPP DT
│ └── pending/ # linted, unshipped RGA3/RGA2 compatible flips
├── scripts/ # series generation, provenance and lint tooling
├── tests/
│ ├── board/ # hardware-gated drills and probes
│ ├── kunit/ # in-kernel unit tests
│ └── fuzz/ # UAPI fuzz targets
└── docs/
├── CI.md # what each CI job asserts + the mutation transcripts
├── COMPAT.md # shim + external-symbol inventory; ALSO the shim-lint input
├── KEEP-STUB.md # deliberate no-op contracts + reopening conditions
├── OWNERSHIP.md # silicon ownership table + the one-compatible rule
├── REFERENCES.md # every pinned coordinate
├── PROVENANCE.md # per-file import ledger
├── TELEMETRY.md # tracefs/debugfs schemas + frozen proc formats
├── VENDOR-BACKLOG.md # exhaustive post-donor vendor PICK/SKIP ledger
├── UPSTREAM-STATUS.md # what mainline is doing; the issue-only watch
└── BOARD-QUALIFICATION.md # what real hardware must demonstrate
The island's deliverables build out of tree as two modules against the pinned
kernel. CI first builds the configured vmlinux, then exposes its
vmlinux.symvers as the Module.symvers external modpost consumes. A following
modules_prepare generates the module linker script but not that symbol table,
so both steps are required to prove the REAL-DEPENDENCY link half. CI never
clones a sibling checkout — the kernel comes from the URL in kernel-pin.env.
# 1. Source the pin.
set -a && . ./kernel-pin.env && set +a
# 2. Clone the pinned kernel and verify BOTH the tag object and the peeled commit.
git clone --depth 1 --branch "$KERNEL_TAG" "$KERNEL_MIRROR" .work/linux
# 3. Apply the integration patches (mainline-file changes) and stage the island
# directories into the tree. This is what CI's cross-compile-modules job
# does step for step -- see docs/CI.md.
# 4. Generate the provider symbol table, then cross-build the two modules.
make -C .work/linux ARCH="$ISLAND_ARCH" CROSS_COMPILE="$ISLAND_CROSS_COMPILE" \
vmlinux
make -C .work/linux ARCH="$ISLAND_ARCH" CROSS_COMPILE="$ISLAND_CROSS_COMPILE" \
modules_prepare
cp .work/linux/vmlinux.symvers .work/linux/Module.symvers
make -C .work/linux ARCH="$ISLAND_ARCH" CROSS_COMPILE="$ISLAND_CROSS_COMPILE" \
M=drivers/video/rockchip/mpp modules
make -C .work/linux ARCH="$ISLAND_ARCH" CROSS_COMPILE="$ISLAND_CROSS_COMPILE" \
M=drivers/video/rockchip/rga3 modulesThe asserted outputs are rk_vcodec.ko and rga_multicore.ko. CI also inspects
both outputs with modinfo: every maintained MPP and
RGA device-tree match table must produce an OF alias, so the kernel can autoload
the module from a device-tree modalias rather than requiring a manual modprobe.
See docs/PROVENANCE.md for their measured version and
licence identity.
The build config is arm64 defconfig plus the device image's own kernel fragment
plus the island's Kconfig symbols — not a bare defconfig. Building against a
configuration the device does not run proves the wrong thing.
The RGA fault seam is independently opt-in via
CONFIG_ROCKCHIP_RGA_CERALIVE_TEST (DEBUG_FS-dependent, default off). Its four
one-shot controls have consumed counters, KUnit coverage of maintained driver
functions, and a separate fault-matrix.sh --driver island-rga --probe-rga <binary>
sweep. The existing 16-row MPP sweep is unchanged. Timeout/hang suppress START,
IOMMU injection directly invokes the fault callback, and reset injection changes
only the debugger write result. See the fault contract
for errno, placement, admission and proof limits. No production enablement or RGA
board qualification is implied by these source and host tests.
The test seam also has an optional idle-window IOMMU control. It schedules one
device-owned delayed callback after a selected encode completion, records the
observed runtime-PM state, and cancels before resource withdrawal. The dedicated
tests/board/fault-controls-probe.sh --row idle-iommu-fault probe is separate
from the 16-row matrix and requires its own authorized idle campaign. Source and
host tests are not a board-qualification result; see
docs/FAULT-CAMPAIGN.md.
Both board drills have now run on real silicon — the matrix and the five-control
sweep on a Rock 5B+ and an Orange Pi 5+ at island v2026.9.2. The idle-window row was attempted on the Rock
and returned no verdict; its outcome is INCONCLUSIVE. What each campaign measured,
and what it explicitly does not prove, is the campaign document's
"Fault-seam contract and the 2026-09 campaigns" section.
The MPP code-quality sweep and its per-finding dispositions are recorded in
docs/HARDENING-FINDINGS.md. Instrumented UML/QEMU
KUnit covers production helpers; full RK3588 driver runtime coverage still needs
a physical board boot. The SRAM sizing regression checks both encoder and decoder
use of a shared clamp before narrowing a resource-sized span to u32.
| Tier | Runs where | Proves |
|---|---|---|
tests/kunit/ |
CI, no hardware | MPP request boundaries and deterministic task/session recovery, plus RGA request validation and fence terminal states |
tests/fuzz/ |
CI, no hardware | the UAPI surface survives hostile input |
| static analysis | CI, no hardware | sparse findings are fatal and coccinelle inspects every selected object; smatch remains conditional on a suitable runner package |
every gate's --self-test |
CI, no hardware | each gate refuses a mutated tree AND accepts a correct one |
tests/board/fault-matrix.sh |
a real Rock 5B+ or Orange Pi 5+ | the sixteen fault rows recover the device, consume the armed one-shot exactly once, and leave a healthy session's throughput intact — via --driver island |
tests/board/fault-controls-probe.sh |
a real Rock 5B+ or Orange Pi 5+ | the five controls no matrix row consumes fire exactly once with their documented errno; --row idle-iommu-fault is the separate, explicit-only idle experiment |
tests/board/soak.sh |
a real Rock 5B+ or Orange Pi 5+ | a long media session holds its nine slope rules — RSS, slab, dma-buf objects, IOMMU mappings, fd count, thread count, fps, drops and the per-core split — or the one failing rule and the retained CSV that proves it; --self-test scores committed fixtures on a dev host and is not board proof |
| module contract | CI, source + built modules | every OF table is exported, the compiled aliases exist, and the hard-IRQ-only RKVENC2 path never uses IRQF_ONESHOT |
| telemetry contract | CI + KUnit | tracepoint call sites and ordering, debugfs counters and session snapshots, static-key definitions, and the frozen MPP formatters remain intact |
tests/dt/ |
CI, built DTBs | both supported boards carry sole island MPP compatibles and every MPP client bypasses the unavailable BSP PMU-idle request; RGA remains mainline-owned |
tests/board/ |
a real Rock 5B+ or Orange Pi 5+ | everything about silicon |
The board suite is deliberately outside the kernel build. Every script is gated,
takes board identity only through environment variables, and never locates
credentials or references a path above this repository's root. What each drill
must demonstrate before it may be ticked is
docs/BOARD-QUALIFICATION.md.
The tracefs event schemas, cumulative debugfs trees, and byte-frozen procfs
formats are documented in docs/TELEMETRY.md.
Phase-7 forced-IDR measurement uses tests/board/idr-latency.sh: an engine IPC
requester and an offline NAL/PTS scorer, with a software-recording self-test.
Its capture requirements include
a complete encoder-input timeline on the requester's host clock; self-test
success alone does not qualify hardware latency or DMA-BUF direct import.
The direct MPP/RGA ioctl suites compile byte-preserved handler and session
functions with bounded user-copy fixtures, rather than opening real device nodes.
MPP coverage includes the legacy zero-size discovery queries, their precise
offset/flag boundary and checked-word pointer access; other scalar sizes and
unimplemented clients retain their rejection tests.
See docs/IOCTL-BOUNDARY-TESTS.md for the complete
case table, reproduction commands, and the explicit hardware/uaccess limits.
The runtime-PM audit traces all eleven island nodes and every PM acquisition/error exit. Hardware devices use a 2000 ms autosuspend policy; the service and encoder CCU are software-only exceptions. RGA cancellation releases power by job ownership, and failed JPEG IRQ registration unwinds common PM setup. UML regressions exercise those paths without touching physical boards.
The RGA memory repair replaces the borrowed
page-table ring with job-owned tables and prepares legacy buffers before
memory-aware core selection. Explicit RGA2 work retains bounded DMA32 staging;
USERPTR aliases share original-page staging. bash scripts/check-rga-memory.sh
exercises the software regressions, including more live PTEs than the old ring
could hold. This is source repair, not a release or board qualification; the
H7/conservation causal links remain unproven. Local compilation databases and
clangd flags are ignored build artifacts, not repository build inputs.
The review follow-up makes reset failure fail-stop: retain the running job's memory and power until reboot, with unload/unbind blocked. Reachable RGA2 buffers now receive execution-device mappings and DMA-address PTEs rather than borrowing RGA3 ownership. Queue admission is bounded, expired queued work cannot start, and synchronous timeout cancels queued requests rather than reporting success. The strengthened host control and new KUnit lifetime/ownership/deadline cases are documented in the same memory-repair note; staging limits remain unchanged.
The round-2 regression receipt records isolated reset-order, timeout-unit and low-USERPTR ownership mutations, each followed by a restored full KUnit pass. It adds test coverage only, including real SG construction and nonidentity DMA PTEs; it changes no production driver.
The host verification of 465598e26
records 47 executed RGA-related KUnit cases, the Coccinelle findings and triage,
and the parent comparison proving the MPP hardening checker failure pre-existing.
It does not waive that failing gate or claim board qualification.
The separate MPP clock-checker repair
checks the actual unlocked enable/unwind helper and its wrapper's error return.
Run python3 scripts/check-mpp-hardening.py for all 23 source assertions and
add --self-test for the positive/negative mutation controls. The driver unwind
was correct; this tooling repair changes no driver or generated series.
CalVer, YYYY.MINOR.PATCH, matching the rest of the CeraLive stack. The tag is
what the consumer repository's island/ lane names, so a tag is immutable once
published: the release workflow claims it atomically and byte-compares the
uploaded asset before publishing.
GPL-2.0. The inherited MPP source carries Rockchip's dual
(GPL-2.0+ OR MIT) expression and the inherited RGA source carries GPL-2.0;
CeraLive uses the GPL-2.0 branch of both and never independently claims MIT.
CeraLive's own contributions are GPL-2.0-only. The full per-file census, and
the two upstream SHAs it was taken against, are in LICENSE.md.
Read CONTRIBUTING.md for the commit trailers, the branch and
PR shape, and the testing gate. AGENTS.md is the routing layer for
AI build agents and the canonical statement of this repository's anti-patterns.