Files
maksyuki 8f5630fb41 feat(tiny): implement R2-P9 DVP capture and recovery
Connect DVP to Tiny DMA2/request 11, IRQ15 and the camera pad/reset lifecycle.
Harden shared capture CDC, frame statistics, per-row size validation and HAL
cleanup while preserving the Mini DMA3 binding and existing register ABI.

Add deterministic capture/recovery firmware, source-bound evidence tooling,
focused RTL/host tests and compact netlist acceptance. Preserve SAFE24,
128 KiB main SRAM, private Crypto storage and the locked dependencies.

Retained validation: focused RTL, host/policy checks, Mini firmware, and
ICS55/IHP130 RECOVERY, QVGA, synthesis and boot/DVP netlist checks pass.
Full-system VGA remains historical; long full Icarus and broad regressions
remain deferred. Global publication/format gaps and negative observational
STA are retained, not reported as passing qualification.

Specification: docs/ip/tiny-soc.md, TINY-R2-P9.
Evidence: docs/ip/tiny-soc-verification.md.
2026-10-17 15:32:59 +08:00

19 KiB

APB4 DVP

The DVP block captures an 8-bit parallel camera stream and presents the captured pixels through an AXI4-Stream source. APB4 is used for configuration, status, statistics, error reporting, and interrupts. The existing DMA engine can transfer the AXI4-Stream payload into AXI4 memory using DVP receive mode. The input path supports RGB565 and YUV422 byte formats, programmable VSYNC and HREF polarity, selectable PCLK sampling edge, snapshot and continuous capture, and rectangular cropping.

Integration

Property Value
APB4 base address 0x1000E000
APB4 interrupt group bit 13
Management-core interrupt 15
Input interface 8-bit parallel data, PCLK, HREF, VSYNC
AXI4-Stream data width 32 bits
AXI4-Stream frame markers TUSER[0] SOF, TLAST EOL
DMA request selector DVP_RX=11; Mini default bulk DMA channel 3
ABI version 0x00020000

The Tiny Gen1 R2 target reuses this IP specification and ABI unchanged at the same base/core IRQ, with product-selected DMA channel 2, PCLK host/stream, GPIO12-23 ALT1 camera routing and optional XPI NSS1 PSRAM frame buffers. Camera and I2S profiles are mutually exclusive. Its TINY-R2-P9 integration must validate exact transfer length, shared HAL channel/burst binding and final-word drain without changing the DVP registers, formats, FIFO or stream semantics. The product contract requires measuring the existing 512-byte FIFO's stall budget and qualifying PSRAM transport in TINY-R2-P8 before capture integration. Tiny support remains a frozen target, not existing end-to-end or physical evidence; Mini's channel-3 default remains unchanged.

The separately approved PPALite extension inserts an optional processing route after this existing CDC FIFO in the future standard Tiny product. RAW remains reset-default and preserves this DVP V2 stream/ABI. PROCESS performs pixel/line selection and row-aligned output packing before the same DVP_RX request11/DMA2 destination path. It adds no source format, Pad, FIFO depth, central-DMA request or private memory master to DVP. Mini retains RAW integration. No PPALite path is implemented by this freeze.

The pixel clock is buffered and can be inverted before the pixel-domain reset synchronizer. Configuration and frame statistics cross between the system and pixel domains through the common cdc_2phase primitive. Captured payloads use the common cdc_fifo_warm_flush primitive and carry {TUSER, TLAST, TKEEP, TSTRB, TDATA}. FIFO overflow drops the active frame, sets an error flag, and requires software to discard the affected DMA buffer.

Register ABI

All registers are 32 bits and naturally aligned. Unmapped, unaligned, and direction-invalid accesses complete with resp_err. Configuration writes are rejected while capture is active. Frame dimensions must be non-zero; invalid format or crop values set the configuration error path and do not start a valid capture. RW registers support byte strobes.

Offset Name Access Description
0x000 CTRL RW Enable, snapshot, and crop-enable controls.
0x004 RXDATA RO/pop PIO receive word when AXI4-Stream output is disabled.
0x008 STATUS RO Active, FIFO, stream, and error state.
0x00C STREAM_CTRL RW Enable AXI4-Stream output.
0x010 FORMAT RW RGB565/YUV422 selection and byte/pixel swap controls.
0x014 SYNC_CFG RW VSYNC, HREF, and PCLK polarity controls.
0x018 FRAME_SIZE RW Frame width in bits 15:0 and height in bits 31:16.
0x01C CROP_START RW Crop X coordinate in bits 15:0 and Y coordinate in bits 31:16.
0x020 CROP_SIZE RW Crop width in bits 15:0 and height in bits 31:16.
0x024 FRAME_COUNT RO Completed frame count.
0x028 LINE_COUNT RO Completed line count from the last frame.
0x02C PIXEL_COUNT RO Captured pixel count from the last frame.
0x030 WORD_COUNT RO Full 32-bit AXI4-Stream word count from the last frame.
0x034 DROP_COUNT RO Number of dropped words caused by overflow.
0x038 ERROR_STATUS RW1C Sticky overflow, sync, size, partial, config, and abort errors.
0x03C INTR_STATE RW1C Sticky frame, line, overflow, configuration, and abort events.
0x040 INTR_ENABLE RW Interrupt enable mask.
0x044 INTR_STATUS RO INTR_STATE & INTR_ENABLE.
0x048 INTR_TEST WO Write-one software interrupt injection.
0x04C COMMAND WO Abort and FIFO flush commands.
0x0F8 IP_VERSION RO ABI version, currently 0x00020000 (2.0).
0x0FC CAPABILITY RO Implemented format, crop, statistics, interrupt, and stream features.

CTRL bit 0 enables capture, bit 1 selects snapshot mode, and bit 2 enables cropping. STREAM_CTRL bit 0 enables AXI4-Stream output; when it is clear, software can consume captured words through RXDATA. FORMAT values 0 and 1 select RGB565 and YUV422 respectively. Values above 1 are invalid. FORMAT bits 2 and 3 control byte and pixel ordering. SYNC_CFG bits 0, 1, and 2 select active-low VSYNC, active-low HREF, and falling-edge PCLK.

The seven interrupt bits are frame start, line done, frame done, overflow, synchronization error, configuration error, and aborted capture. Error and interrupt state are write-one-to-clear. Hardware events have priority over a simultaneous software clear so that an event cannot be lost. The external interrupt is the reduction OR of INTR_STATE & INTR_ENABLE.

STATUS bit 0 is ENABLE, bit 1 is ACTIVE, bit 2 is FIFO_EMPTY and bit 5 is ERROR. ENABLE reports the configuration actually applied in the pixel domain; CTRL continues to read back the requested control value. Software can therefore acknowledge a disable/enable transition without a new register. ACTIVE is delivered with a coherent pixel-domain status snapshot; it is not an alias for ENABLE. An error W1C is retained until the pixel domain applies its mask and returns a status packet with the matching clear epoch. Old reports cannot acknowledge that operation. New source errors take priority over a simultaneous clear. APB response timing and register offsets remain unchanged; software must poll with a timeout. A stopped pixel clock cannot complete a clear or recovery operation. Configuration transfer is held behind pending error clears. A separate applied pixel configuration is updated only when the core accepts the mailbox; the mailbox's earlier data presentation cannot modify an active frame. Configuration and command transactions carry internal epochs; lifecycle idle stays low until the matching applied/drained status is returned. Waiting for the first VSYNC is armed work, not idle. Local reset-ready requires a native pixel-domain status after reset. Tiny global boot uses its existing internal leaf/APB/AXI prerequisites independently of this local-reset readiness, so an absent sensor clock does not become a global CPU boot dependency.

ABORT cancels older configuration requests still waiting in the APB register shell without changing requested-register readback. Its command mailbox also carries the last issued configuration epoch. If that configuration arrives or applies after ABORT, it completes the existing acknowledgement but cannot rearm the core. The cancellation record is retired by the next different applied configuration epoch, before the one-bit epoch can be reused. Repeated or coalesced ABORT commands do not advance configuration epochs. ABORT does not wait for configuration readiness, including when an active frame blocks configuration application. Later configuration writes remain eligible after the command drains; normal recovery still clears errors and acknowledges disable/enable before using a new frame. No register or FIFO ABI is added.

Error interrupt causes use a retained six-bit pending mask and an acknowledged mailbox, separate from the status snapshots. Repeated causes can coalesce while pending, but two events between status samples cannot cancel one another. New causes on mailbox acceptance remain pending for the next transfer. Clearing an interrupt does not repeatedly reassert it merely because ERROR_STATUS still holds an old error; a new occurrence does notify again.

The RTL ABI constants are maintained directly in rtl/ip/multimedia/dvp_define.svh. Matching HAL offsets and masks are maintained directly in crt/src/hal/dvp.c. Changes to either definition must update the other definition, this document, and the RTL/software tests in the same change.

AXI4-Stream and Capture Semantics

Two 16-bit pixels, each formed from two 8-bit sensor samples, are packed into one 32-bit stream word. The first pixel occupies TDATA[15:0] and the second pixel occupies TDATA[31:16]. TUSER[0] is asserted on the first word of a frame, and TLAST is asserted on the last word of each line. TID and TDEST are tied to zero.

For an even number of pixels, TKEEP and TSTRB are 4'b1111. For an odd number of pixels, the final word of each line uses 4'b0011 and the unused upper half of TDATA is zero. AXI4-Stream TVALID remains asserted and the payload remains stable while TREADY is low. The FIFO backpressures the pixel domain; an inability to accept a word during an active frame records an overflow and terminates that frame.

VSYNC rising after polarity normalization starts a frame. HREF qualifies pixel sampling and its falling edge completes a line. Snapshot mode stops after the next completed frame; continuous mode resets line and pixel counters and captures the next frame. Crop coordinates are applied in the normalized frame coordinate space, and a crop must fit within the configured frame size. Snapshot completion remains stopped until a disabled configuration rearms it. Source row width is checked against FRAME_SIZE, independently of crop selection. The first complete pixel beyond the configured width reports SIZE and ends the active frame before the column counter can wrap. HREF falling with fewer complete pixels also reports SIZE. Compensating long and short rows cannot form a valid frame merely because aggregate counts match. Rows outside the crop are checked too. An incomplete final byte additionally reports PARTIAL. These faults retain the existing sticky-error/event path; they do not flush already accepted FIFO or DMA data. Software discards the failed destination, drains/cancels DMA before source cleanup, and uses the existing ABORT, W1C and acknowledged disable/enable rearm sequence. An enabled source waiting for its first VSYNC does not treat the preceding partial frame as captured data. ABORT/FLUSH execute only on an accepted command handshake, not repeatedly from a retained CDC payload.

The PIO path and AXI4-Stream path are mutually exclusive at the output: RXDATA pops a word only while stream output is disabled. The DMA HAL uses a single-frame transfer length; descriptor rings, double buffering, and frame metadata chaining are not part of the current ABI.

DMA and Software Contract

The DMA MVP treats each full AXI4-Stream word as one 32-bit memory write. It accepts only TKEEP=4'hf; an odd-pixel DVP line produces a partial final word and therefore requires PIO handling or a future narrow-transfer/DRE DMA extension. Software should configure the frame and crop dimensions, clear stale error and interrupt state, program the product-selected DVP_RX destination and capacity, enable stream output, and then start DVP capture. A frame that reports overflow, synchronization, partial, DMA, or abort errors must not be consumed by software. The existing convenience helper uses Mini's channel-3 binding; Tiny must supply its product transport configuration as specified in its integration contract before that helper is advertised as supported there.

The public HAL exposes structured configuration, bounded status polling, command and interrupt control, capability discovery, and a convenience API for one-frame DMA capture. Applications should use rs_dvp_configure(), rs_dma_configure(), rs_dma_start(), rs_dvp_start(), and rs_dvp_capture_dma() rather than accessing the registers directly.

The snapshot helpers derive transfer length from the current frame/crop geometry. word_capacity bounds the destination; it is not a request to fill the entire allocation. DMA rejects odd active widths, insufficient capacity and address overflow before starting. PIO uses ceil(width / 2) * height storage words and preserves the zero-padded final halfword in each odd row. Success requires a new completed frame, exact pixel/word and DMA counts, an empty FIFO and all destination responses. The helper initializes CRC options explicitly. Tiny uses channel 2/four-beat bursts; Mini retains channel 3 and its existing maximum-burst default. Each convenience capture rearms the existing snapshot configuration through an acknowledged non-flushing disable/enable sequence; callers need not repeat rs_dvp_configure() between successful captures. PIO refuses a busy or suspended product-selected DMA consumer before changing stream mode, interrupts or FIFO contents. The source must also be inactive with an empty FIFO before rearm.

Recovery drains/aborts DMA before issuing a source abort that clears FIFO storage. A failed DMA drain is returned to the caller without clearing the source tail. rs_dvp_abort() refuses a busy product-selected DMA channel and waits for an acknowledged abort, FIFO empty and error clear. Recovery timeout is an error, not permission to reuse the buffer or rearm capture.

Frozen PPALite Source and Route Contract

The PPALite contract owns the processed pixel formats, derived geometry, padded row pitch and buffer metadata. In PROCESS, DVP cropping stays here, BYTE_SWAP/PIXEL_SWAP are zero, and the processor interprets the explicit sensor byte order. Raw DVP still exposes two16-bit pixels per full stream word, or a final halfword for an odd-width row. A legal halfword row tail must not be confused with an invalid incomplete sensor pixel.

RAW DMA retains its even-active-width requirement. PROCESS may consume the legal halfword tail and emit full padded words; that is a new downstream operation, not a retroactive change to this source stream or a narrow-DMA mode. Raw helpers on PPALite-capable Tiny must reject PROCESS before programming capture, and the PPALite HAL must use its derived length rather than raw 2 * width * height. The unchanged Mini default channel3 is not copied to Tiny.

Route changes require stopped/acknowledged DVP configuration and cleanup, empty source/processor endpoints and the full central-DMA barrier defined by PPALite. The route is locked through capture/failed cleanup. Fixed PROCESS may be retained between frames without stopping unrelated DMA clients. The Tiny source guard freezes geometry/format/crop while owned, verifies actual configuration/command CDC completion, and admits only the ordered source start, non-flushing snapshot stop and isolated cleanup operations. Diagnostic reads and the DVP register map remain unchanged.

Before processed capture is qualified, PPALITE-P2 must close or reuse current R2 evidence for source correctness: real SYNC/SIZE/PARTIAL detection, exact statistics beyond65535 words, coherent host-side active/configuration/status, every repeated frame event, error epochs and snapshot stop/rearm behavior. The R2-P9 candidate implements SYNC/SIZE/PARTIAL detection and a 32-bit word counter transported through a 144-bit completed-frame mailbox. These source guarantees still require matching validation; a downstream image/checksum alone does not establish them. Minimal shared correctness fixes must retain register offsets/meanings, the512 B payload FIFO and Mini compatibility.

The internal statistics layout is {drop[31:0], words[31:0], pixels[31:0], lines[15:0], frames[31:0]}. The existing two-phase CDC carries the entire 144-bit snapshot; register offsets and the separate 128-bit configuration channel are unchanged. VGA 640x480 at two bytes per pixel reports 153600 words rather than the former 16-bit wrapped value 22528. PIO counts one additional halfword-bearing word at each odd-width row end.

Valid processed completion requires this source's full-frame/statistic/error verdict, a checked non-flushing stop, processor counts and exact DMA length including final memory write responses. PPALite PIPE_DONE or a last EOL is not source-frame validity. Continue monitoring late source faults until the capturing HAL finalizes its result; do not publish a plausible prefix.

The current ABORT command also requests source FIFO clearing. Failed processed capture therefore closes admission, drains/aborts its DMA, acknowledges old stream isolation, and only then issues source ABORT/FLUSH and processor cleanup. Ordinary stream VALID cannot be withdrawn while a live consumer still owns the beat. Missing PIXCLK or flush/reset acknowledgement retains failed-session ownership; no fabricated padding or common-DMA reset substitutes for recovery. The existing helper's early success-path abort must be corrected/avoided with shared checked lifecycle helpers before either route is advertised as complete.

The original FIFO still receives raw sensor bytes. Its overflow budget is not enlarged simply by dividing final image width or extracting Y. Preserve raw-rate occupancy/margin calculations and validate any extra downstream buffer credit explicitly. These new obligations have no passing evidence yet.

Verification and Current Scope

The self-checking RTL test covers the versioned ABI, invalid APB4 accesses, configuration writes, RGB565 packing, SOF/EOL framing, even and odd line widths, AXI4-Stream output, frame statistics, and interrupt state handling. The SBY target proves APB4 response behavior, request/response progress, interrupt composition, and normal/error coverage for the register shell. Host tests compile and execute the DVP directed test, while the IHP130 regression exercises behavior simulation, synthesis, netlist simulation, and STA integration.

The current ABI does not include a native DVP AXI4 memory master, outstanding AXI transactions, frame descriptor rings, line stride configuration, JPEG or other compressed formats, external sync metadata, or multiple camera clocks. Those features require a versioned ABI extension and explicit SoC routing; existing register fields must not be repurposed for them.

RTL Coding-Style Migration

The current DVP maintenance pass is limited to source organization and naming; it does not change the register ABI, APB4 timing, AXI4-Stream framing, CDC topology, pixel packing, interrupt behavior, or error semantics. Register address macros retain their APB4_DVP_* names so the software HAL remains compatible. Internal field macros use the APB4_DVP__* namespace, and local parameters use UpperCamelCase. Internal configuration and command paths use the project abbreviations cfg and cmd, while public APB4 and AXI4-Stream interfaces remain unchanged.

Owned DVP modules use explicit named-port connections. Module ports and macro definitions are manually column-aligned only inside narrow verilog_format: off/on regions where Verible cannot preserve the alignment; ordinary declarations, assignments, and instances remain formatter-managed. The dvp_camera simulation model follows the same naming and named-port rules. Its delayed falling-edge assignment is intentionally retained because it models camera HREF timing and is not synthesizable IP behavior.

The local validation entry points are:

python3 -m pytest -q tests/test_dvp.py
make CONFIG=configs/ci/ihp130.mk formal-dvp
make format-check rtl-style-check-all rtl-readiness-check-all