RK628F hardware adaptation
Aico Link SCH v1 uses J3 for both USB2 ECM and Type-C video. The video path is
CSA171 -> CS5366 -> RK628F HDMI RX -> four CSI lanes -> RV1106.
RK628_Plugin_DET is routed to the MCU, not to an RV1106 GPIO. The device
tree therefore deliberately has no plugin-det-gpios property.
The older RK628D driver cannot initialize this silicon. The board reports
0x20230321 at register 0x0200, identifying RK628F/H. The SDK now
backports the coherent RK628 receiver, clock/reset, MIPI PHY and
post-processing drivers from Rockchip commit
81417fbf13edb25f203ea794a723b8bf1f457d5c. See
pico-sdk/sysdrv/source/kernel/drivers/media/i2c/rk628/README.aico for
the source and local compatibility changes.
The board retains its onboard 24 MHz oscillator, I2C4 M1 at 100 kHz,
GPIO1_A0 power enable, GPIO1_A1 active-low reset, GPIO1_B1 interrupt,
and four continuous-clock CSI lanes. HPD is controlled by the receiver
driver, not a GPIO-high startup workaround. The built-in EDID matches
edid/hdmi_1080p60_cta.hex and advertises 1080p60 by default. The frame
service applies the selected profile specifically to RK628; the generic
libaico fallback remains 1080p30 for TC358743 compatibility. A persistent
1080p30 compatibility profile
preserves 1920x1080 capture while limiting the HDMI pixel clock to 74.25 MHz. With the tested Android source, the
onboard Type-C bridge path repeatedly lost all three data-channel locks at
148.5 MHz, including with capture stopped and HPD held steady. Both 720p60
and 1080p30 locked correctly at 74.25 MHz. This is a compatibility limit for
the observed path; it does not establish which physical component causes
the higher-rate instability.
Persistent input mode
On the board, use:
sudo aico-hdmi-mode 1080p30 # Apply compatibility mode and save it
sudo aico-hdmi-mode 1080p60 # Return to 60 Hz and save it
aico-hdmi-mode status # Show the configured selection
The command atomically saves /userdata/system/hdmi-mode and restarts
aico-frame.service. The selection survives reboot and rootfs slot changes;
without a saved selection, the default is 1080p60. Status reports the configured
mode, not confirmation of a locked video input. There is no automatic downgrade.
After discovering an RK628 receiver, the frame service applies the selection
before opening capture, including when the bridge appears after service startup.
It compares the current EDID first and applies a changed profile once; ordinary
capture recovery does not repeat that negotiation. TC358743 retains its existing
policy. An explicitly configured FRAME_SERVICE_EDID overrides this mode policy;
keep it set to auto when using the mode command.
An EDID change can take the Android source about 30 seconds to finish renegotiating. A temporary zero pixel clock during that interval does not establish that the new mode is unsupported. Observe source display state and receiver lock before evaluating capture.
Userspace EDID updates stop streaming, hold HPD low, and schedule receiver
configuration again. An absent input returns ENOLCK rather than a
successful fallback VGA timing. Without a plugin GPIO, failed training
retries autonomously with a ten-second delay.
Receiver recovery
Receiver configuration samples character errors once and uses that result for both readiness and retry decisions. Reading the counters can update their baseline and the equalizer, so a second read could appear clear and incorrectly suppress a required retry. When character-error monitoring is enabled, sampling its counters can retune the equalizer based on errors accumulated during a long idle and disrupt a locked input. Stream start therefore leaves these counters alone; equalizer changes stay in receiver training. The board device tree leaves character-error monitoring and dynamic EQ disabled because trials with dynamic EQ did not establish reliable capture. Character-error counters alone do not identify a cable fault.
RK628F can raise vertical-active-line interrupts while its measurement settles even though the HDMI clock, all three data channels, and decoded input mode remain stable. The driver debounces these interrupts for 100 ms and compares the input with the last configured timings and color metadata. Channel-lock checks retry over 80 ms so a brief lock-status drop does not reset an otherwise unchanged input; persistent lock loss still retrains it. Unchanged input, allowing 0.1% pixel-clock measurement variation, keeps the current stream running. Link loss or a real mode/color change still stops the stream and retrains the receiver. Timing queries cannot replace the configured comparison baseline during the debounce interval.
AVI packets can continue advertising 1080p60 while the receiver loses data-channel
lock and measures fewer than 1080 active lines. The standard-mode lookup alone
therefore cannot establish stable video. Each sample used for timing acquisition
checks the clock and all three data-channel locks before and after reading the
timings. Lock loss breaks the sequence of eight stable samples, returns ENOLCK,
and clears the output timings; register-read errors retain their original errno.
This prevents stale AVI metadata from publishing input readiness. It does not
repair an unstable HDMI link or guarantee subsequent frame delivery.
The parent HDMI interrupt stays masked during recovery and leaf-mask
updates. This prevents a pending interrupt from monopolizing I2C while the
recovery worker holds its configuration mutex. CSI interrupt routing is
preserved. A shared mutex serializes the threaded HDMI handler with mask
updates. VIDIOC_QUERY_DV_TIMINGS returns EAGAIN while configuration is busy
and ENOLCK when no signal is available.
Routine timing queries select single or dual MIPI mode on every successful query. Both 1080p60 (148.5 MHz) and 1080p30 (74.25 MHz) use single MIPI mode. These selection messages are available at driver debug level 1; their repetition alone does not indicate receiver recovery or a capture failure.
Stream start/stop and format-readiness checks share the receiver configuration
mutex so recovery cannot reset CSI halfway through a stream transition.
STREAMON returns ENOLCK when the input is unavailable and EAGAIN when
stream setup itself triggers recovery. A failed start disables CSI before
returning the error, allowing the capture service to reopen the source.
CSI PHY lock and lane stop-state polling failures return their original error,
such as ETIMEDOUT or an I2C error, through STREAMON. Failed setup leaves both
the transmitter and PHY disabled instead of reporting a working stream.
On an affected image, the frame service can remain RECOVERING with
latest_seq=0, frame_age_ms=0, and last_error=open failed. Here a zero
frame age means that no frame timestamp exists. Check
/var/log/frame_service/frame_service.log and the RK628 kernel log for
repeated receiver resets. Display enumeration alone does not establish that
capture is working.
CIF startup can fail before it enables its frame-completion tasklet, for
example when receiver format readiness returns EAGAIN or ENOLCK.
Failure cleanup must disable the tasklet only if that startup attempt enabled
it. Otherwise each early failure increases the disable count, and later
successful STREAMON calls leave frame completion disabled. A pending tasklet
then repeatedly wakes ksoftirqd, capture dequeues time out, and reopening the
camera does not clear the imbalance. The startup path tracks whether it enabled
the tasklet before balancing that operation during cleanup. Deploying the
corrected CIF module requires a reboot to clear an already affected instance.
This addresses a persistent capture stall after transient receiver failures;
receiver lock loss still needs to be evaluated independently.
Hardware verification
Check all of the following with the connected host awake:
- Kernel log reports
RK628F/H (20230321). - The host enumerates
Linux FHD60at 1920x1080, 60 Hz by default, orLinux FHD30at 30 Hz after selecting compatibility mode. v4l2-ctl -d /dev/v4l-subdev2 --query-dv-timingsreturns locked, nonzero input timings. Discover the actual subdevice usingmedia-ctl -pif numbering changes./sys/kernel/debug/rk628/4-0050/hdmirx/statusshows clock and all three HDMI data channels locked.frame_service_cli --socket /run/frame_service/frame_service.sock screenshot --out /tmp/capture.jpgreturns an actual image, and successive captures change when the host image changes.- Repeat after software reboot and verify Wi-Fi recovery and
systemctl --failed.
Host display enumeration alone verifies HPD/DDC, not pixel transport. A sleeping host can keep its display enumerated while transmitting no video clock. The driver must report no signal in that condition.
The SDK BSP build and audit compile the hardware driver. The Docker suite
bash scripts/run_tests_in_docker.sh --suite rk628-recovery exercises the
production recovery functions with simulated registers, exercises CIF startup
after repeated early and late failures, and checks the
board/EDID integration contract. Run the required local make check profile
after changes; CI runs make check-full.