Skip to content

hw/arm/rk3566: model the camera pipeline and complete NPU reuse - #49

Merged
zevorn merged 9 commits into
develfrom
pm/rk3566-camera-npu
Nov 2, 2026
Merged

zevorn merged 9 commits into
develfrom
pm/rk3566-camera-npu

Conversation

@zevorn

@zevorn zevorn commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Model the RK3566 camera pipeline and complete the RK3566 NPU reuse.

Camera pipeline

  • Generate a moving colour-bar frame every 1/30 s in the ISP when no camera chardev is attached; the optional chardev still overrides the generator with injected 640x360 UYVY frames.
  • Report V_START and FRAME interrupts separately so the vendor rkisp driver queues SOF events, and write the AE, AWB, histogram and AF measurement blocks into the DDR statistics buffer announced through MI_SWS_3A_WR_BASE. The register readback path keeps reporting measurement done bits.
  • Model the GC2093 register contract: 16-bit register addresses with data auto-increment, chip ID, soft reset, streaming control, mode table, exposure, VTS, mirror/flip and gain registers, and drive the streaming GPIO from the power/reset/streaming state.
  • Update the RK3566 documentation with the camera pipeline, the frame generator, the 3A feedback path and the remaining limitations.

With these changes the official MicroDuck firmware captures 1920x1080 NV12 frames from /dev/video0 without a host frame source and rkaiq_3A completes rk_aiq_uapi_sysctl_start and rkisp_init engine without AWB or SOF errors.

RK3566 NPU

  • Add RockchipRKNNSocConfig to the shared RKNN core so per-SoC differences are described in one place: core count, command count scale, DMA address width, PC version and the amount window description. The rk3566-rknpu subtype selects the RK356x configuration.
  • Model the PC+0x8000 amount window (clear-all, DT write/read and WT read counters) and map it at 0xfde48000.
  • Clamp co-work requests to the configured core count so the single-core RK3566 completes requests locally instead of waiting for absent peers.
  • Add the rknpu-reset output to the RK3566 CRU (SOFTRST_CON2 bits 11/12) and connect it to the NPU reset input; reset clears the register file, LUT, pending command and interrupt state.
  • Add tests/qtest/rk3566-rknpu-test.c covering the version registers, pointer tags, command completion, interrupt masking, fetch errors, 32-bit DMA, the amount window, reset and single-core co-work.

Validation

  • checkpatch.pl --file reports 0 errors and 0 warnings for every changed file.
  • qemu:qtest-aarch64 and qemu:qtest-arm: no failures (details in the CI run).
  • Official MicroDuck firmware v0.1.0: gc2093, csi2-dphy and rkisp probe; three 1920x1080 NV12 frames captured from /dev/video0; rkaiq_3A starts the tuning engine; the rknpu driver reaches [drm] Initialized rknpu 0.9.8 with IOMMU enabled.

Known limitations

  • The ISP converts synthetic frames and does not model the individual processing blocks, so captured content does not originate from sensor Bayer data; the 3A measurements are derived from the synthetic frame.
  • The rkcif and MIPI CSI2 host models are not implemented and the machine device tree fixup keeps the corresponding nodes disabled.
  • The raw write/read and iqtool video nodes are visible in the guest but do not produce data.
  • The official images do not ship an RKNN runtime or model, so the NPU is validated through driver probe, debugfs and qtests rather than an end-to-end inference workload.

The ISP model only forwarded host camera frames and latched the capture
registers, so the vendor rkisp driver could stream but rkaiq had no SOF
event or measurements and the statistics video node never completed a
buffer.

Generate a moving colour-bar frame every 1/30 s when no camera chardev is
attached, keep the chardev path for injected frames, report V_START and
FRAME interrupts separately so the driver queues SOF events, and fill the
AE/AWB/histogram/AF blocks in the DDR statistics buffer announced through
MI_SWS_3A_WR_BASE.  The measurement register window keeps reporting done
bits for the register readback path.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
Implement the GC2093 I2C register contract used by the vendor driver:
16-bit register addressing with an auto-incrementing pointer, read-only
chip identification (0x2093), soft reset through 0x3fe=0xf0 that restores
the reset defaults while keeping the chip ID, streaming control through
CTRL_MODE (0x3e=0x91/0x11) with the streaming GPIO following the mode,
and register storage for the sensor mode table, long exposure, VTS,
mirror/flip and gain registers.  The exposure and VTS high bytes keep
their 14-bit field width, and power or reset assertion restores the reset
defaults.

Update the RK3566 board documentation with the camera pipeline, the
optional camera chardev and the known camera model limitations.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
The ISP generates frames and statistics without a host chardev, so update
the camera section accordingly.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
Introduce a RockchipRKNNSocConfig descriptor and make the RKNPU core
realize the per-SoC values instead of machine-set properties: core
count, command count scale, DMA address width, PC version and the
legacy PC+0x8000 amount window.  The rk3566-rknpu subtype now selects
the RK356x description (one core, 32-bit DMA, amount window).

Clamp co-work requests to the configured core count so a single-core
RK3566 completes multi-core CNA tasks on its own core instead of
waiting for peers that do not exist.  Scan peers up to the per-SoC core
count in the reset and migration paths.

Expose the RK356x amount window as an additional sysbus region and map
it at 0xfde48000 in the microduck machine.  The four registers model
the vendor driver clear-all strobe and the data read/write counters.

Add a rknpu-reset gpio output to the RK3566 CRU driven by SOFTRST_CON2
bits 11/12 (SRST_A_NPU/SRST_H_NPU) and connect it to the NPU reset
input, so the core register file, LUT, pending state, IRQ and amount
counters are reset through the CRU.

Add tests/qtest/rk3566-rknpu-test.c covering version/pointer tags,
control command completion, IRQ mask/clear, fetch error, 32-bit DMA
rejection, amount window semantics, CRU reset and single-core co-work.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T02:59:44.884663Z bd89dc9 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 520a0901c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread hw/misc/rk3566_isp.c Outdated
Comment on lines +309 to +310
isp_3a_store_words(buf, 0x0c00 + i * 0x800, s->stat_hist[i],
ISP_3A_HIST_BINS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the third histogram separate from the AF block

When DDR statistics are enabled, the i == 2 iteration writes stat_hist[2] at offset 0x1c00, but the subsequent stat_af_ram write uses the same offset and overwrites its first 225 bins. Consequently, the DDR buffer cannot contain both the third histogram and AF measurements correctly, and guest 3A consumers receive corrupted statistics. Use non-overlapping offsets matching the statistics buffer layout.

Useful? React with 👍 / 👎.

Comment thread hw/misc/rk3566_isp.c
static void isp_3a_store_words(uint8_t *buf, hwaddr offset,
const uint32_t *values, unsigned count)
{
memcpy(buf + offset, values, count * sizeof(uint32_t));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize DDR statistics in little-endian order

On a big-endian host, this memcpy serializes every measurement word in host byte order. address_space_write() copies those bytes unchanged, so the little-endian RK3566 guest reads byte-swapped AE, histogram, AWB and AF statistics even though MMIO readback remains correct. Store each word with an explicit little-endian operation rather than copying native uint32_t representations.

Useful? React with 👍 / 👎.

Comment thread hw/misc/rk3566_isp.c
Comment on lines +818 to +820
if (!s->busy) {
isp_synth_generate(s);
isp_submit_frame(s);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Advance the frame counter for generated frames

With no camera chardev attached, input_frames never advances: its only increment is in isp_receive(), which the synthetic path bypasses. Since isp_synth_generate() uses that counter as its animation tick, every generated frame is identical and the exposed input-frames property stays zero despite ongoing capture. Increment the counter for synthetic frames as well so the documented moving pattern actually changes between captures.

Useful? React with 👍 / 👎.

The third histogram block was written at the AF offset and the per-block
measurement done bits shared one flag, so rkaiq could read a histogram
filled with AF data and could observe measurements that were already
acknowledged.

Write the histogram blocks at 0x0c00, 0x1400 and 0x1800, track the
measurement done state per AE, histogram, AF and AWB block, advance the
synthetic frame counter so the generated pattern moves, and report a DMA
error when the statistics buffer cannot be reached.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
Keep the RK356x PC+0x8000 amount counters in the migration stream.

Signed-off-by: Chao Liu <chao.liu@processmission.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6f35b9222

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread hw/misc/rk3588_rknpu.c Outdated
Comment on lines +9727 to +9728
VMSTATE_UINT32_ARRAY_V(amount_counts, RockchipRKNNCoreState,
ROCKCHIP_RKNN_AMOUNT_COUNTERS, 2),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate the new amount counters on migration version 3

When loading a version-2 NPU migration stream or snapshot created before this change, this field is incorrectly considered present even though that format contains no amount counters. The loader consumes the first three CNA register words as counters, shifting all subsequent fields and causing state corruption or a load failure. This also affects RK3588, which uses the shared VMState description. Set the field's minimum version to 3, matching the version introduced by this commit.

Useful? React with 👍 / 👎.

@zevorn

zevorn commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

Validation on the final head (b6f35b9, build with media libraries):

  • checkpatch.pl --file: 0 errors, 0 warnings for all changed files.
  • Local meson test --suite qemu:qtest-aarch64 --suite qemu:qtest-arm --timeout-multiplier 2: 111 OK, 0 failed, 5 skipped (includes the new rk3566-rknpu-test and the existing rk3566 machine/ISP/CSI DPHY tests).
  • Official MicroDuck firmware, all four release images, serial runs, no camera chardev (ISP frame generator):
Release Kernel / rkisp /dev/video0 NV12 capture rkaiq 3A NPU mediad
v0.1.0 6.1.84 / v02.06.01 3 frames, 9331200 bytes start success, engine succeed, 0 AWB/SOF errors probe, IOMMU, DRM, debugfs, shared IRQ active, camera source, 28-29 fps
v1.0.0 6.1.172 / v03.03.00 3 frames, 9331200 bytes same same active, 28-30 fps
v1.0.1 6.1.172 / v03.03.00 3 frames, 9331200 bytes same same active, 27-29 fps
v1.1.0 6.1.172 / v03.03.00 3 frames, 9331200 bytes same same active, 28-29 fps

The v0.1.0 run also captured a 30-frame stream (93312000 bytes) and the mediad journal shows the 3A exposure loop adjusting the synthetic frame (mean luma 137.1 against a target of 90.0).

Remaining device-side warnings are unchanged and documented in the commit messages: the NPU driver falls back from the 64 KiB region request and the npu_irq name lookup, the MPP H.264 encoder path is not available for RK3566 in this image, and the GStreamer field/selection warnings come from the TCG frame pacing. None of them blocks the camera capture, the 3A loop or the NPU probe.

The matmul co-work case starts a functional task that the model executes
in an asynchronous worker and then steps the virtual clock in a tight
loop.  On a loaded CI host the worker may not have finished when the
loop ends, so the case observed a still busy PC.

Give the worker real time between the virtual clock steps and keep
stepping until the task status reports completion.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
@zevorn
zevorn force-pushed the pm/rk3566-camera-npu branch from 8d92032 to 2673c35 Compare November 1, 2026 15:48
Move the RKNPU register file, command decoder, execution backend, DMA and
interrupt logic into hw/misc/rockchip_rknpu.c and describe the per-SoC
differences with RockchipRKNNSocConfig.  RK3588 and RK3566 provide thin
subclasses that select their configuration, and the machines instantiate
the SoC-specific device type.

Drop the pre-release migration compatibility: the VMState stream has a
single version and all fields are unconditional, so the older version
checks and the versioned fields are removed.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
@zevorn

zevorn commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

Added a follow-up commit that shares the RKNPU core across SoCs:

  • hw/misc/rockchip_rknpu.c and include/hw/misc/rockchip_rknpu.h hold the RKNPU register file, command decoder, execution backend, IOMMU DMA, completion timer, interrupts, LUT and migration state. The QOM type is now rockchip.rknn-core.
  • hw/misc/rk3588_rknpu.c and hw/misc/rk3566_rknpu.c are thin subclasses that select RockchipRKNNSocConfig; the RK3588 machines instantiate rk3588-rknpu, the MicroDuck machine instantiates rk3566-rknpu.
  • Migration compatibility with the pre-release stream is removed: a single VMState version with unconditional fields, no version-dependent handling in post_load.
  • Kconfig gains a shared ROCKCHIP_RKNPU symbol selected by the per-SoC NPU symbols; MAINTAINERS lists the shared files.

Local validation after the refactor: checkpatch clean for the new and moved files; qemu:qtest-aarch64 and qemu:qtest-arm 111 OK, 0 failed, 5 skipped; official MicroDuck v0.1.0 still logs the rknpu 0.9.8 probe, IOMMU group, DRM registration and debugfs version, captures 3110400 bytes from /dev/video0, and rkaiq_3A completes sysctl_start and rkisp_init engine.

Boot the four official MicroDuck firmware releases with the
microduck-beta machine and verify that the guest reaches a shell, reports
the board model, exposes the rkisp video nodes, runs the rkaiq service,
registers the rknpu DRM and debugfs nodes, and captures a mainpath frame.

The release images are several gigabytes, so the assets are read from
QEMU_TEST_MICRODUCK_FIRMWARE_DIR instead of being downloaded, and the
tests are skipped unless that variable and QEMU_TEST_ALLOW_LARGE_STORAGE
are set.  Boot a release up to three times before failing it, because a
TCG boot of the v0.1.0 image occasionally stalls before the serial getty
starts, and keep the guest console quiet to avoid stalling the boot log.

The tests join the aarch64 thorough functional suite.

Signed-off-by: Chao Liu <chao.liu@processmission.com>
@zevorn

zevorn commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator Author

Added functional tests for the official firmware releases:

  • tests/functional/aarch64/test_microduck.py boots v0.1.0, v1.0.0, v1.0.1 and v1.1.0 with the microduck-beta machine and checks the guest shell, board model, rkisp video nodes, the running rkaiq_3A service, the rknpu DRM/debugfs nodes and a mainpath v4l2 capture.
  • The release images are several gigabytes, so the tests read the extracted Image, rk-kernel.dtb and raw *.wic from QEMU_TEST_MICRODUCK_FIRMWARE_DIR and are skipped unless that variable and QEMU_TEST_ALLOW_LARGE_STORAGE are set. The expected directory layout is documented in the test file.
  • The tests join the aarch64 thorough functional suite. The downstream CI runs the quick functional suite, so they remain skipped there and do not add boot time to PR checks.
  • Boots are retried up to three times because the v0.1.0 image occasionally stalls before the serial getty starts under TCG; the guest console runs with a quiet command line for the same reason.

Local validation on this commit (all four releases): boot to shell, model Pollen Robotics microduck beta, /sys/class/video4linux contains video0, rkaiq_3A reports active, debugfs reports RKNPU driver: v0.9.8, /dev/dri/renderD128 exists and v4l2-ctl --stream-count=1 returns 0.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd89dc9887

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread hw/misc/rk3566_isp.c

for (unsigned blk = 0; blk < ISP_3A_AE_BLOCKS; blk++) {
for (unsigned win = 0; win < ISP_3A_AE_WINDOWS; win++) {
unsigned lum = CLAMP(mean_y + (int)win * 4 - 6, 0, 0xff);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use signed arithmetic before clamping AE window luminance

With an external camera frame whose mean luminance is below 6, mean_y being unsigned makes the subtraction wrap before CLAMP runs. For example, a completely black frame produces lum == 255 for windows 0 and 1 rather than zero, so their AE sums report maximum brightness while the histogram and mean measurements report darkness. Cast mean_y to a signed type before applying the window adjustment, as the mean-grid calculation below already does.

Useful? React with 👍 / 👎.

@zevorn
zevorn merged commit 79aa108 into devel Nov 2, 2026
47 checks passed
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