forked from marfrit/kernel-agent
Compare commits
6 Commits
main
..
ea3b2fb813
| Author | SHA1 | Date | |
|---|---|---|---|
| ea3b2fb813 | |||
| 62a6f88abd | |||
| ad7c61a81b | |||
| a6549605f0 | |||
| e53db55959 | |||
| 18da673ccc |
@@ -115,7 +115,7 @@ ka-pause-prune / ka-resume-prune
|
||||
ka-restore-archive <job-id>
|
||||
ka-snooze <issue-id> [--for <duration>]
|
||||
ka-debug <job-id> # shells into the same container that ran the build
|
||||
ka-status # per-host one-liner with drift/pending state
|
||||
ka-status # per-host one-liner with drift/pending state [bin/ka-status — implemented Phase 1]
|
||||
ka-migrate-tree --from <p> --to <p>
|
||||
ka-wake-data # wraps wake-host data through His
|
||||
```
|
||||
@@ -162,11 +162,13 @@ manifest rewrite); paths stable otherwise.
|
||||
## Build hosts
|
||||
|
||||
```
|
||||
Host Where Role Wake? Notes
|
||||
Host Where Role Wake? Notes
|
||||
──────────────────────────────────────────────────────────────────────────
|
||||
boltzmann Rock 5 ITX+ aarch64 primary always container kbuild-aarch64
|
||||
fermi hertz LXD aarch64 fallback always matches kbuild-aarch64 profile
|
||||
kbuild-x86 data CT x86_64 on-demand wakes via His; idle 30 min → release
|
||||
boltzmann Rock 5 ITX+ aarch64 primary always container kbuild-aarch64
|
||||
ampere CoolPi GenBook aarch64 secondary on-demand RK3588 32GB; same uarch as boltzmann,
|
||||
wakes via His; idle 30 min → release
|
||||
fermi hertz LXD aarch64 fallback always matches kbuild-aarch64 profile
|
||||
kbuild-x86 data CT x86_64 on-demand wakes via His; idle 30 min → release
|
||||
```
|
||||
|
||||
Native make on the assigned build host. **No distcc** for kernel-agent
|
||||
@@ -288,10 +290,16 @@ build.
|
||||
|
||||
### Out of scope this round (explicit defer)
|
||||
|
||||
- **vb2 dma_resv RFC v2** + panfrost IOMMU_CACHE for RK3399 — would have closed
|
||||
the fresnel-fourier campaign criterion-4 readback transitive-proof gap, but
|
||||
v2 isn't implemented (RFC v1 rejected upstream). Deferred to a follow-up
|
||||
build once v2 lands. See `marfrit/dmabuf-modifier-triage#3`.
|
||||
- **vb2 dma_resv RFC v2** — *resolved 2026-05-15.* Markus iterated v2 locally
|
||||
on boltzmann reaching pkgrel=14; the v2 series attaches the fence at
|
||||
`device_run` (slept-OK context per Dufresne's v1 review). Now carried in
|
||||
`patches/subsystem/media/videobuf2/dma-resv-release-fence/` and included
|
||||
in `fleet/fresnel.yaml`. Still in scope for upstream targeting; default
|
||||
remains "build-tree only, no PR until explicitly asked"
|
||||
(`feedback_no_upstream.md`).
|
||||
- **panfrost IOMMU_CACHE for RK3399** — sibling kernel work that targets the
|
||||
readback transitive-proof gap that vb2_dma_resv alone doesn't close.
|
||||
Still deferred until that lands; ship together when ready.
|
||||
- **Replace** `linux-eos-arm` rather than coexist alongside — preserves easy
|
||||
rollback at u-boot. Can flip to `provides=(linux-eos-arm) conflicts=(...)`
|
||||
later once burn-in proves the OC kernel reliable.
|
||||
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# ka-status — per-host kernel-agent state summary.
|
||||
#
|
||||
# Reads fleet/*.yaml manifests + queries Gitea for open [ka:*] issues +
|
||||
# probes each host (where reachable) for the installed kernel-package
|
||||
# version. Designed to give a first-look "what's the state" before any
|
||||
# ka-promote / ka-install action.
|
||||
#
|
||||
# Usage:
|
||||
# ka-status # summary across all manifests
|
||||
# ka-status <host> # detail for one host
|
||||
#
|
||||
# Read-only. Never mutates state. No sudo. No SSH-into-host writes.
|
||||
#
|
||||
# Phase 1 deliverable. Future ka-* CLI verbs (ka-promote / ka-close /
|
||||
# ka-install) build on the same Gitea-API + manifest-parsing skeleton.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_URL="${GITEA_URL:-https://git.reauktion.de}"
|
||||
REPO="${KERNEL_AGENT_REPO:-marfrit/kernel-agent}"
|
||||
TOKEN_FILE="${KERNEL_AGENT_TOKEN_FILE:-/opt/herding/etc/claude-identities/noether.creds}"
|
||||
|
||||
# Resolve token from per-host claude-identity creds, or env override.
|
||||
token=""
|
||||
if [ -n "${GITEA_TOKEN:-}" ]; then
|
||||
token="$GITEA_TOKEN"
|
||||
elif [ -r "$TOKEN_FILE" ]; then
|
||||
token="$(grep -E '^GITEA_TOKEN=' "$TOKEN_FILE" | head -1 | cut -d= -f2)"
|
||||
fi
|
||||
|
||||
# Locate fleet/ — script lives in bin/ next to fleet/.
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
fleet_dir="${script_dir}/../fleet"
|
||||
[ -d "$fleet_dir" ] || { echo "fleet/ not found relative to $script_dir" >&2; exit 2; }
|
||||
|
||||
api_get() {
|
||||
local path="$1"
|
||||
local args=(--silent --show-error --max-time 15)
|
||||
[ -n "$token" ] && args+=(-H "Authorization: token $token")
|
||||
curl "${args[@]}" "${GITEA_URL}/api/v1/${path}"
|
||||
}
|
||||
|
||||
# Open ka-prefixed issues, JSON array on stdout.
|
||||
fetch_ka_issues() {
|
||||
api_get "repos/${REPO}/issues?state=open&type=issues&limit=50" \
|
||||
| python3 -c '
|
||||
import json, sys
|
||||
issues = json.load(sys.stdin)
|
||||
def kind(t):
|
||||
if not t.startswith("["): return None
|
||||
p = t.find("]")
|
||||
return t[1:p] if p > 0 else None
|
||||
out = [{
|
||||
"number": i["number"],
|
||||
"title": i["title"],
|
||||
"kind": kind(i["title"]),
|
||||
} for i in issues if kind(i["title"]) and kind(i["title"]).startswith("ka:")]
|
||||
print(json.dumps(out))
|
||||
' 2>/dev/null || echo "[]"
|
||||
}
|
||||
|
||||
# Parse a fleet/<host>.yaml manifest (very-narrow YAML subset).
|
||||
manifest_field() {
|
||||
local file="$1" key="$2"
|
||||
grep -E "^[[:space:]]*${key}:" "$file" | head -1 | sed -E "s/^[^:]*:[[:space:]]*//; s/[[:space:]]+#.*//; s/^[\"']//; s/[\"']$//"
|
||||
}
|
||||
|
||||
manifest_pkgname() {
|
||||
local file="$1"
|
||||
awk '/^package:/{p=1; next} p && /^[a-z]/{p=0} p && /^[[:space:]]+name:/{sub(/^[[:space:]]+name:[[:space:]]*/,""); print; exit}' "$file"
|
||||
}
|
||||
|
||||
# Probe a host for installed kernel-package version (best-effort, non-blocking).
|
||||
probe_installed() {
|
||||
local host="$1" pkg="$2"
|
||||
ssh -o ConnectTimeout=3 -o BatchMode=yes -o StrictHostKeyChecking=accept-new \
|
||||
"${host}.fritz.box" "pacman -Q '$pkg' 2>/dev/null || dpkg-query -W -f='\${Package} \${Version}\n' '$pkg' 2>/dev/null || echo 'host-up:not-installed'" 2>/dev/null \
|
||||
|| echo "host-down"
|
||||
}
|
||||
|
||||
issues_json="$(fetch_ka_issues)"
|
||||
|
||||
# Per-host issue grouping — match on title containing the host name (cheap heuristic;
|
||||
# proper kernel-agent will tag issues with a host label).
|
||||
issues_for_host() {
|
||||
local host="$1"
|
||||
echo "$issues_json" | python3 -c "
|
||||
import json, sys
|
||||
host = '$host'
|
||||
issues = json.load(sys.stdin)
|
||||
hits = [i for i in issues if host in i['title'].lower()]
|
||||
for h in hits:
|
||||
print(f\" #{h['number']} [{h['kind']}] {h['title']}\")
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
print_host() {
|
||||
local file="$1"
|
||||
local host pkg
|
||||
host="$(basename "$file" .yaml)"
|
||||
pkg="$(manifest_pkgname "$file")"
|
||||
local arch="$(manifest_field "$file" arch)"
|
||||
local soc="$(manifest_field "$file" soc)"
|
||||
local board="$(manifest_field "$file" board)"
|
||||
|
||||
printf '\n══ %s ══\n' "$host"
|
||||
printf ' manifest: arch=%s soc=%s board=%s\n' "$arch" "$soc" "$board"
|
||||
printf ' package: %s\n' "$pkg"
|
||||
if [ -n "$pkg" ]; then
|
||||
printf ' installed: %s\n' "$(probe_installed "$host" "$pkg")"
|
||||
fi
|
||||
|
||||
local n=0
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
if [ $n -eq 0 ]; then printf ' open ka-issues:\n'; fi
|
||||
printf '%s\n' "$line"
|
||||
n=$((n+1))
|
||||
done < <(issues_for_host "$host")
|
||||
[ $n -eq 0 ] && printf ' open ka-issues: (none for this host)\n'
|
||||
}
|
||||
|
||||
if [ $# -ge 1 ]; then
|
||||
f="${fleet_dir}/${1}.yaml"
|
||||
[ -r "$f" ] || { echo "no manifest for host '$1'" >&2; exit 2; }
|
||||
print_host "$f"
|
||||
else
|
||||
printf 'kernel-agent status (repo: %s)\n' "$REPO"
|
||||
printf 'open [ka:*] issues total: %s\n' "$(echo "$issues_json" | python3 -c 'import json,sys; print(len(json.load(sys.stdin)))')"
|
||||
for f in "$fleet_dir"/*.yaml; do
|
||||
[ -e "$f" ] || continue
|
||||
print_host "$f"
|
||||
done
|
||||
fi
|
||||
@@ -0,0 +1,111 @@
|
||||
# kernel-agent manifest for ampere (CoolPi GenBook / Rockchip RK3588)
|
||||
#
|
||||
# Status: bootstrap. ka-promote / ka-build / ka-install CLI not yet
|
||||
# implemented; the canonical patch set + baseline below is the input
|
||||
# for the manual flow that produces linux-ampere-fourier (same shape
|
||||
# as fresnel's bootstrap reference build).
|
||||
#
|
||||
# Asks #2 (VP9 enablement on RK3588 rkvdec) and #3 (AV1 dec integration)
|
||||
# from kernel-agent issue #6 are NOT addressed in this manifest —
|
||||
# tracked separately for a follow-up sprint.
|
||||
|
||||
host: ampere
|
||||
arch: arm64
|
||||
soc: rockchip/rk3588
|
||||
module: coolpi-cm5
|
||||
board: coolpi-cm5-genbook
|
||||
distro: archlinux-arm
|
||||
|
||||
baseline:
|
||||
tree: torvalds/linux
|
||||
url: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
||||
ref: v7.0-rc3
|
||||
upstream_compat: linux-7.0-rc3
|
||||
|
||||
# 2026-05-16 bisect note: the linux-rk3588-marfrit branch tip @ f8f3ad9
|
||||
# (18 commits ahead of v7.0-rc3) BLACK-SCREENS ampere — connector
|
||||
# reports connected/enabled/dpms On + SDDM starts + backlight on, but
|
||||
# panel shows no pixels. Decomposing the suspend/resume patch (0010
|
||||
# family) into 5 atomic sub-commits and reverting all 5 did NOT recover
|
||||
# display (test-arch-plus-pcie3 branch). The 6 patches listed below
|
||||
# applied on top of v7.0-rc3 directly DO boot with working display
|
||||
# (ampere-minimal-devices branch @ 7c241f2). Regression source is in
|
||||
# one of the remaining 12 commits in f8f3ad9 — top suspect:
|
||||
# 55d1b3dcc05e "clk: rockchip: rk3588: Drop CLK_SET_RATE_PARENT from
|
||||
# DCLK_VOP2_SRC" (touches display controller clock parent rate). Other
|
||||
# excluded commits: Shawn Lin pcie3 phy series, Cristian Ciocaltea
|
||||
# clk/dts/dw-dp fixes, Sebastian Reichel hdmirx Rock 5 ITX, Pedro Alves
|
||||
# btrtl, and the suspend/resume patch 0010 family. Bisect campaign
|
||||
# separately.
|
||||
#
|
||||
# Branch ampere-minimal-devices on git.reauktion.de/marfrit/linux-rk3588-marfrit
|
||||
# is the verified-working tip if you want a ready-to-fetch ref instead
|
||||
# of patches-on-mainline.
|
||||
|
||||
# Scope-tagged patch includes. Resolve to patches/<scope>/<file>.patch.
|
||||
# Apply order matters: pwm15 pinctrl (soc) must precede the genbook
|
||||
# pwm-fan node consumer.
|
||||
includes:
|
||||
- soc/rockchip/rk3588/0001-arm64-dts-rockchip-rk3588-Add-pwm15-pinctrl-entries.patch
|
||||
- board/coolpi-cm5-genbook/0002-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Add-pwm-fan.patch
|
||||
- module/coolpi-cm5/0003-arm64-dts-rockchip-rk3588-coolpi-cm5-Fix-power-off-by-enabling-RK806-as-system-power-controller.patch
|
||||
- board/coolpi-cm5-genbook/0004-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Enable-speaker-output-via-audio-graph-card.patch
|
||||
- board/coolpi-cm5-genbook/0005-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Enable-USB-C-PD-charging-via-FUSB302.patch
|
||||
- board/coolpi-cm5-genbook/0008-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Add-lid-switch-and-USB3-PHY-lane-config.patch
|
||||
|
||||
# Explicitly NOT included this round (tracked for later sprints):
|
||||
# - VP9 enablement for RK3588 rkvdec (issue #6 ask 2). /dev/video0 only
|
||||
# advertises S265 + S264 today; vainfo lists 9 profiles, target is
|
||||
# 10. Requires identifying the VDPU381/383 patch chain + possible
|
||||
# DTS additions. RFC-stage work, scope unclear until research lands.
|
||||
# - AV1 decoder integration (issue #6 ask 3). Kernel side is fine
|
||||
# (/dev/video4 advertises AV1F). Backend libva-v4l2-request-fourier
|
||||
# needs iter39 for a third fd. Backend work, not kernel.
|
||||
# - misc_patches/genbook/kernel/0006 (arm64 Kconfig: do not select
|
||||
# HAVE_GCC_PLUGINS). Local-only build-config; not for upstream and
|
||||
# possibly redundant with the linux-rk3588-marfrit branch already.
|
||||
# - misc_patches/genbook/kernel/0009 (Bluetooth btrtl RTL_SEC_PROJ
|
||||
# non-fatal). Different subsystem; promote under driver/bluetooth/
|
||||
# when a campaign demands.
|
||||
# - misc_patches/genbook/kernel/0010 (multi-driver suspend/wakeup fix).
|
||||
# Promote under soc/rockchip/rk3588/ or split per affected driver
|
||||
# once the RockHard campaign decides the upstream-targeting shape.
|
||||
|
||||
config:
|
||||
source: /proc/config.gz on running ampere kernel (7.0.0-rc3-ARCH+, hand-managed before this bootstrap)
|
||||
strategy: snapshot, fold to baseline, accept-new with rationale on diff
|
||||
|
||||
package:
|
||||
name: linux-ampere-fourier
|
||||
versioning: "${baseline_ref}.kafr${pkgrel}" # 7.0.rc3.kafr1 etc.
|
||||
install_mode: alongside
|
||||
conflicts: []
|
||||
provides: []
|
||||
kernel_suffix: -ampere-fourier # /boot/firmware/Image-7.0.0-rc3-ampere-fourier
|
||||
bootloader: extlinux
|
||||
bootloader_path: /boot/firmware/extlinux/extlinux.conf # vfat partition on mmcblk0p1
|
||||
boot_path: /boot/firmware/ # vfat, 1.5G, ~1G free
|
||||
# ampere boots from a separate FAT partition (mmcblk0p1), unlike fresnel which
|
||||
# uses the root partition's /boot/. The extlinux-add hook needs to write to
|
||||
# /boot/firmware/extlinux/extlinux.conf, not /boot/extlinux/.
|
||||
|
||||
verify:
|
||||
bar1_ssh_heartbeat: required
|
||||
bar2_pkg_version: required
|
||||
bar3_dtb_match:
|
||||
- power-off via 'shutdown -h' actually powers down (RK806 system-power-controller wired)
|
||||
- pwm15 pinctrl exposes group3-pwm15-m0..m3 entries
|
||||
- audio: speakers driven via ES8316 graph (not just headphone)
|
||||
bar4_per_patch_probe: opt-in
|
||||
bar5_burn_in: skip # laptop, runtime not constant
|
||||
|
||||
build_host:
|
||||
primary: ampere # self-host, 8 cores RK3588, 32 GB RAM, native arch
|
||||
secondary: boltzmann # also RK3588 32 GB, kbuild-aarch64 container surrogate
|
||||
fallback: fermi # hertz LXD, ALARM aarch64
|
||||
# No distcc for kernel-agent builds — native make on the assigned host only.
|
||||
# ampere is self-hosting today because boltzmann was busy with userspace
|
||||
# builds when the bootstrap ran; either host can take the work.
|
||||
|
||||
backup:
|
||||
pre_install: hertz:/sparfuxdata/kernel-agent-backups/ampere/${replaced_version}/
|
||||
+8
-4
@@ -23,13 +23,17 @@ includes:
|
||||
- board/pinebook-pro/0001-arm64-dts-rk3399-pinebook-pro-add-OC-OPP-tables-1704-2184.patch
|
||||
- board/pinebook-pro/0002-arm64-dts-rk3399-pinebook-pro-enable-hdmi-sound.patch
|
||||
- board/pinebook-pro/0003-arm64-dts-rk3399-pinebook-pro-spi1-max-freq-10MHz.patch
|
||||
# vb2_dma_resv RFC v2 series — added 2026-05-15 (Markus iterated v2 locally
|
||||
# on boltzmann reaching pkgrel=14; pre-v2 decision was "defer". v2 attaches
|
||||
# the fence at device_run in slept-OK context per Dufresne's v1 review).
|
||||
- subsystem/media/videobuf2/dma-resv-release-fence/0004-media-videobuf2-add-opt-in-dma_resv-producer-fence-h.patch
|
||||
- subsystem/media/videobuf2/dma-resv-release-fence/0005-media-hantro-attach-dma_resv-release-fence-at-device.patch
|
||||
- subsystem/media/videobuf2/dma-resv-release-fence/0006-media-rockchip-rga-attach-dma_resv-release-fence-at-.patch
|
||||
|
||||
# Explicitly NOT included (tracked elsewhere, decision logged):
|
||||
# - subsystem/media/videobuf2/dma-resv-release-fence/ (RFC v1 rejected;
|
||||
# v2 in design — see marfrit/dmabuf-modifier-triage#3. Skip until v2 lands
|
||||
# or we explicitly accept v1-shape parity with ohm.)
|
||||
# - driver/panfrost/iommu-cache-rk3399/ (sibling kernel work; ship together
|
||||
# with vb2_dma_resv when it lands.)
|
||||
# once it lands. Targets the readback transitive-proof gap that vb2_dma_resv
|
||||
# alone doesn't close.)
|
||||
|
||||
config:
|
||||
source: /proc/config.gz on running fresnel kernel (linux-eos-arm 6.19.9-99)
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
From: Markus Fritsche <mfritsche@localhost>
|
||||
Subject: [PATCH 2/2] arm64: dts: rockchip: rk3588-coolpi-cm5-genbook: Add pwm-fan with thermal cooling
|
||||
|
||||
The CoolPi CM5 GenBook has a PWM-controlled fan connected to pwm15
|
||||
(mux m3, GPIO1_D7). Add a pwm-fan node driven at 20 kHz (50000 ns
|
||||
period) with six cooling levels, and wire it into the package thermal
|
||||
zone with two trip points at 55 °C and 65 °C.
|
||||
|
||||
Generated-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
1 file changed, 43 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
@@ -23,6 +23,13 @@
|
||||
pwms = <&pwm6 0 25000 0>;
|
||||
};
|
||||
|
||||
+ fan: pwm-fan {
|
||||
+ compatible = "pwm-fan";
|
||||
+ #cooling-cells = <2>;
|
||||
+ pwms = <&pwm15 0 50000 0>;
|
||||
+ cooling-levels = <1 50 100 150 200 254>;
|
||||
+ };
|
||||
+
|
||||
battery: battery {
|
||||
compatible = "simple-battery";
|
||||
charge-full-design-microamp-hours = <9800000>;
|
||||
@@ -443,3 +450,39 @@
|
||||
remote-endpoint = <&edp1_in_vp2>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+&package_thermal {
|
||||
+ polling-delay = <1000>;
|
||||
+
|
||||
+ trips {
|
||||
+ package_fan0: package-fan0 {
|
||||
+ temperature = <55000>;
|
||||
+ hysteresis = <2000>;
|
||||
+ type = "active";
|
||||
+ };
|
||||
+
|
||||
+ package_fan1: package-fan1 {
|
||||
+ temperature = <65000>;
|
||||
+ hysteresis = <2000>;
|
||||
+ type = "active";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ cooling-maps {
|
||||
+ map0 {
|
||||
+ trip = <&package_fan0>;
|
||||
+ cooling-device = <&fan THERMAL_NO_LIMIT 2>;
|
||||
+ };
|
||||
+
|
||||
+ map1 {
|
||||
+ trip = <&package_fan1>;
|
||||
+ cooling-device = <&fan 3 THERMAL_NO_LIMIT>;
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&pwm15 {
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pwm15m3_pins>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
From: Markus Fritsche <mfritsche@localhost>
|
||||
Subject: [PATCH 4/4] arm64: dts: rockchip: rk3588-coolpi-cm5-genbook: enable speaker output
|
||||
|
||||
The GenBook carrier board routes the ES8316 HPOL/HPOR outputs to both a
|
||||
headphone jack and an external speaker amplifier. The amplifier is
|
||||
enabled by GPIO1_A6 (active-high) and headphone insertion is detected by
|
||||
GPIO1_B5 (active-high, pull-up).
|
||||
|
||||
Add a label to the shared analog-sound node in the CM5 DTSI so the
|
||||
GenBook DTS can extend it, then override the node to:
|
||||
|
||||
- add pa-gpios for the speaker amplifier enable line (GPIO1_A6)
|
||||
- add hp-det-gpios for headphone jack detection (GPIO1_B5)
|
||||
- extend widgets/routing to include the Speaker path through the
|
||||
audio-graph-card built-in "Amplifier" DAPM output-driver widget,
|
||||
which gates the pa-gpios GPIO on widget power-up/down
|
||||
- add the hp-det pinctrl group for GPIO1_B5
|
||||
|
||||
The "Amplifier" DAPM widget (snd_soc_dapm_out_drv) is provided by
|
||||
audio-graph-card.c and registered at card level. Its event handler
|
||||
drives pa-gpios high on SND_SOC_DAPM_POST_PMU and low on
|
||||
SND_SOC_DAPM_PRE_PMD, giving automatic speaker enable/disable in step
|
||||
with DAPM power management.
|
||||
|
||||
DAPM path for speaker output:
|
||||
ES8316 AIF1RX (DAI) -> Left/Right DAC -> Left/Right Headphone Mixer
|
||||
-> Left/Right Headphone Driver -> HPOL/HPOR [codec OUTPUT pins]
|
||||
-> Amplifier [card OUT_DRV, fires pa-gpios] -> Speaker [SPK terminal]
|
||||
|
||||
The Left/Right Headphone Mixer Left/Right DAC Switch controls, which
|
||||
gate the DAC-to-mixer connections in the DAPM graph, are set on by the
|
||||
UCM BootSequence in the rk3588-es8316 ALSA UCM profile and must remain
|
||||
enabled for the path to be traversable.
|
||||
|
||||
The HPOL/HPOR codec output pins also feed the Headphones HP widget:
|
||||
|
||||
HPOL/HPOR -> Headphones [HP terminal, jack-controlled via hp-det-gpios]
|
||||
|
||||
Both the Speaker and Headphones paths are active whenever a PCM stream
|
||||
is running. Speaker-muting when headphones are inserted is handled at
|
||||
the userspace (UCM) level via JackHWMute on the Speaker UCM device: when
|
||||
PipeWire routes audio away from the Speaker sink on headphone insertion,
|
||||
the absence of an active PCM consumer causes DAPM to power down the
|
||||
Amplifier widget and drive GPIO1_A6 low.
|
||||
|
||||
Note: full speaker output also requires a Speaker SectionDevice in the
|
||||
rk3588-es8316 ALSA UCM HiFi.conf. Without it the HiFi profile's only
|
||||
playback port is Headphones (jack-controlled), causing the profile to be
|
||||
reported as "not available" when no headphones are inserted, and
|
||||
PipeWire falls back to the pro-audio profile with no speaker sub-device.
|
||||
A separate patch to alsa-ucm-conf adds the missing Speaker device.
|
||||
|
||||
Generated-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
2 files changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
@@ -283,7 +283,31 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&analog_sound {
|
||||
+ pa-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_HIGH>;
|
||||
+ hp-det-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&hp_det>;
|
||||
+
|
||||
+ widgets = "Microphone", "Mic Jack",
|
||||
+ "Headphone", "Headphones",
|
||||
+ "Speaker", "Speaker";
|
||||
+
|
||||
+ routing = "MIC2", "Mic Jack",
|
||||
+ "Headphones", "HPOL",
|
||||
+ "Headphones", "HPOR",
|
||||
+ "Amplifier", "HPOL",
|
||||
+ "Amplifier", "HPOR",
|
||||
+ "Speaker", "Amplifier";
|
||||
+};
|
||||
+
|
||||
&pinctrl {
|
||||
+ headphone {
|
||||
+ hp_det: hp-det {
|
||||
+ rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
lcd {
|
||||
lcdpwr_en: lcdpwr-en {
|
||||
rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>;
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi
|
||||
@@ -21,7 +21,7 @@
|
||||
serial2 = &uart2;
|
||||
};
|
||||
|
||||
- analog-sound {
|
||||
+ analog_sound: analog-sound {
|
||||
compatible = "audio-graph-card";
|
||||
dais = <&i2s0_8ch_p0>;
|
||||
label = "rk3588-es8316";
|
||||
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
From: Markus Fritsche <mfritsche@localhost>
|
||||
Date: Tue, 24 Mar 2026 00:00:00 +0000
|
||||
Subject: [PATCH] arm64: dts: rockchip: rk3588-coolpi-cm5-genbook: add USB-C PD charging
|
||||
|
||||
The GenBook carrier board exposes a USB Type-C port driven by the
|
||||
RK3588 USB3OTG0 controller (usb_host0_xhci / usbdp_phy0 combo). The
|
||||
port uses a Fairchild FUSB302 (I²C address 0x22, bus i2c4) for USB
|
||||
Power Delivery negotiation. Hardware signals:
|
||||
|
||||
GPIO0_PD5 – FUSB302 interrupt (active-low, shared with CC logic)
|
||||
GPIO0_PA0 – VBUS switch enable (active-high)
|
||||
|
||||
Without these changes the kernel registers usb_host0_xhci in
|
||||
peripheral-only, high-speed mode, which prevents PD negotiation and
|
||||
leaves the port unable to charge the battery.
|
||||
|
||||
Changes:
|
||||
|
||||
* Add #include <dt-bindings/usb/pd.h> for PDO_FIXED macros.
|
||||
|
||||
* Add vcc5v0_otg regulator: GPIO0_PA0 active-high switch that gates
|
||||
VBUS; used as vbus-supply for the FUSB302 and connected via the new
|
||||
typec5v_pwren pinctrl entry. The previously defined but unreferenced
|
||||
usb_otg_pwren entry (same pin, wrong pull direction) is removed.
|
||||
|
||||
* Add usbc0 (FUSB302) node inside &i2c4:
|
||||
- compatible "fcs,fusb302", reg 0x22
|
||||
- interrupt GPIO0_PD5 (IRQ_TYPE_LEVEL_LOW), pinctrl usbc0_int
|
||||
- usb-c-connector child with:
|
||||
data-role / power-role "dual", try-power-role "sink"
|
||||
pd-revision 2.0 Ver 1.2 (maximum supported by FUSB302)
|
||||
sink-pdos: 5 V/3 A, 9 V/3 A, 12 V/3 A, 15 V/3 A
|
||||
source-pdos: 5 V/3 A
|
||||
DisplayPort alt-mode (SVID 0xff01) declared for orientation
|
||||
switching; three connector ports linking HS (→ usb_host0_xhci),
|
||||
SS (→ usbdp_phy0) and SBU (→ usbdp_phy0) endpoints.
|
||||
|
||||
* Expand &usbdp_phy0 to add mode-switch and orientation-switch
|
||||
capabilities; register endpoint@0 (SS, linked to usbc0_ss) and
|
||||
endpoint@1 (SBU, linked to usbc0_sbu).
|
||||
|
||||
* Replace the &usb_host0_xhci override:
|
||||
- remove dr_mode "peripheral" and maximum-speed "high-speed"
|
||||
(the base DTSI already sets dr_mode "otg")
|
||||
- add usb-role-switch and the port endpoint linked to usbc0_hs
|
||||
This allows the TCPM stack to switch the controller between host
|
||||
and device role as the PD contract dictates.
|
||||
|
||||
* Add pinctrl group usb-typec with:
|
||||
- usbc0_int: GPIO0_PD5 pull-up (FUSB302 /INT)
|
||||
- typec5v_pwren: GPIO0_PA0 pull-down (VBUS switch, default off)
|
||||
|
||||
DAPM / power flow:
|
||||
USB-C charger → FUSB302 CC negotiation → TCPM requests VBUS →
|
||||
vcc5v0_otg regulator enables GPIO0_PA0 → VBUS present on port →
|
||||
DWC3 OTG detects VBUS, enters device/host mode per PD data-role.
|
||||
|
||||
Generated-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
Signed-off-by: Markus Fritsche <mfritsche@localhost>
|
||||
---
|
||||
1 file changed, 106 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include <dt-bindings/soc/rockchip,vop2.h>
|
||||
+#include <dt-bindings/usb/pd.h>
|
||||
#include "rk3588-coolpi-cm5.dtsi"
|
||||
|
||||
/ {
|
||||
@@ -153,6 +154,18 @@
|
||||
pinctrl-0 = <&usb_host_pwren>;
|
||||
vin-supply = <&vcc5v0_usb>;
|
||||
};
|
||||
+
|
||||
+ vcc5v0_otg: regulator-vcc5v0-otg {
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "vcc5v0_otg";
|
||||
+ regulator-min-microvolt = <5000000>;
|
||||
+ regulator-max-microvolt = <5000000>;
|
||||
+ enable-active-high;
|
||||
+ gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&typec5v_pwren>;
|
||||
+ vin-supply = <&vcc5v0_sys>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&edp1 {
|
||||
@@ -239,6 +252,65 @@
|
||||
monitored-battery = <&battery>;
|
||||
power-supplies = <&charger>;
|
||||
};
|
||||
+
|
||||
+ usbc0: usb-typec@22 {
|
||||
+ compatible = "fcs,fusb302";
|
||||
+ reg = <0x22>;
|
||||
+ interrupt-parent = <&gpio0>;
|
||||
+ interrupts = <RK_PD5 IRQ_TYPE_LEVEL_LOW>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&usbc0_int>;
|
||||
+ vbus-supply = <&vcc5v0_otg>;
|
||||
+
|
||||
+ usb_con: connector {
|
||||
+ compatible = "usb-c-connector";
|
||||
+ label = "USB-C";
|
||||
+ data-role = "dual";
|
||||
+ power-role = "dual";
|
||||
+ try-power-role = "sink";
|
||||
+ op-sink-microwatt = <1000000>;
|
||||
+ /* FUSB302 supports PD Rev 2.0 Ver 1.2 */
|
||||
+ pd-revision = /bits/ 8 <0x2 0x0 0x1 0x2>;
|
||||
+ sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>,
|
||||
+ <PDO_FIXED(9000, 3000, PDO_FIXED_USB_COMM)>,
|
||||
+ <PDO_FIXED(12000, 3000, PDO_FIXED_USB_COMM)>,
|
||||
+ <PDO_FIXED(15000, 3000, PDO_FIXED_USB_COMM)>;
|
||||
+ source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
|
||||
+
|
||||
+ altmodes {
|
||||
+ displayport {
|
||||
+ svid = /bits/ 16 <0xff01>;
|
||||
+ vdo = <0xffffffff>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ ports {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ port@0 {
|
||||
+ reg = <0>;
|
||||
+ usbc0_hs: endpoint {
|
||||
+ remote-endpoint = <&usb_host0_xhci_to_usbc0>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ usbc0_ss: endpoint {
|
||||
+ remote-endpoint = <&usbdp_phy0_ss>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ port@2 {
|
||||
+ reg = <2>;
|
||||
+ usbc0_sbu: endpoint {
|
||||
+ remote-endpoint = <&usbdp_phy0_sbu>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&i2c5 {
|
||||
@@ -323,15 +395,21 @@
|
||||
rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
|
||||
- usb_otg_pwren: usb-otg-pwren {
|
||||
- rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
- };
|
||||
-
|
||||
usb_host_pwren: usb-host-pwren {
|
||||
rockchip,pins = <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
+ usb-typec {
|
||||
+ usbc0_int: usbc0-int {
|
||||
+ rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
+ };
|
||||
+
|
||||
+ typec5v_pwren: typec5v-pwren {
|
||||
+ rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
wifi {
|
||||
bt_pwron: bt-pwron {
|
||||
rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
@@ -387,7 +465,24 @@
|
||||
};
|
||||
|
||||
&usbdp_phy0 {
|
||||
+ mode-switch;
|
||||
+ orientation-switch;
|
||||
status = "okay";
|
||||
+
|
||||
+ port {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ usbdp_phy0_ss: endpoint@0 {
|
||||
+ reg = <0>;
|
||||
+ remote-endpoint = <&usbc0_ss>;
|
||||
+ };
|
||||
+
|
||||
+ usbdp_phy0_sbu: endpoint@1 {
|
||||
+ reg = <1>;
|
||||
+ remote-endpoint = <&usbc0_sbu>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&u2phy1 {
|
||||
@@ -431,9 +526,14 @@
|
||||
|
||||
/* Type C port */
|
||||
&usb_host0_xhci {
|
||||
- dr_mode = "peripheral";
|
||||
- maximum-speed = "high-speed";
|
||||
+ usb-role-switch;
|
||||
status = "okay";
|
||||
+
|
||||
+ port {
|
||||
+ usb_host0_xhci_to_usbc0: endpoint {
|
||||
+ remote-endpoint = <&usbc0_hs>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
/* connected to a HUB for camera and BT */
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
From: Markus Fritsche <mfritsche@localhost>
|
||||
Date: Tue, 24 Mar 2026 00:00:00 +0000
|
||||
Subject: [PATCH] arm64: dts: rockchip: rk3588-coolpi-cm5-genbook: add lid switch and USB3 PHY lane config
|
||||
|
||||
The GenBook laptop has two features missing from the mainline DTS:
|
||||
|
||||
1. Lid switch (MH248 hall-effect sensor on GPIO0_PB0)
|
||||
The lid state is reported via a gpio-keys node using SW_LID / EV_SW.
|
||||
The GPIO is active-low (low = lid closed) and pulled up.
|
||||
wakeup-source is set so that opening the lid can wake the system from
|
||||
suspend. A sensor pinctrl group is added for the GPIO configuration.
|
||||
|
||||
2. usbdp_phy1 lane mux (rockchip,dp-lane-mux = <2 3>)
|
||||
The RK3588 usbdp_phy1 is a combo USB3 + DisplayPort PHY shared between
|
||||
the USB3 host1 port (USB-A connector) and the DisplayPort output on the
|
||||
GenBook board. Lanes 0+1 carry USB3 SuperSpeed to the USB-A socket;
|
||||
lanes 2+3 are routed to the DP connector.
|
||||
|
||||
Without this property the phy-rockchip-usbdp driver selects
|
||||
UDPHY_MODE_USB and configures all four lanes as USB3. That conflicts
|
||||
with the physical routing on this board: lanes 2+3 are not connected to
|
||||
the USB-A socket, so the 4-lane USB3 training fails silently and the
|
||||
USB3 host1 DWC3 controller (usb_host1_xhci) cannot enumerate devices.
|
||||
|
||||
Setting rockchip,dp-lane-mux = <2 3> restricts USB3 to lanes 0+1,
|
||||
matching the physical wiring, and enables correct SuperSpeed operation
|
||||
on the USB-A port.
|
||||
|
||||
The USB2 EHCI host1 controller (usb_host1_ehci) shares the USB power
|
||||
domain with usb_host1_xhci. A stalled USB3 DWC3 probe can delay
|
||||
power-domain activation in a way that prevents the EHCI hub (which
|
||||
carries the integrated webcam) from being enumerated. With the correct
|
||||
lane mux both controllers probe cleanly and the webcam is detected.
|
||||
|
||||
Generated-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
Signed-off-by: Markus Fritsche <mfritsche@localhost>
|
||||
---
|
||||
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include <dt-bindings/soc/rockchip,vop2.h>
|
||||
+#include <dt-bindings/input/linux-event-codes.h>
|
||||
#include <dt-bindings/usb/pd.h>
|
||||
#include "rk3588-coolpi-cm5.dtsi"
|
||||
|
||||
@@ -166,6 +167,21 @@
|
||||
pinctrl-0 = <&typec5v_pwren>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
+
|
||||
+ gpio-key-lid {
|
||||
+ compatible = "gpio-keys";
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&mh248_irq_gpio>;
|
||||
+
|
||||
+ lid {
|
||||
+ debounce-interval = <20>;
|
||||
+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>;
|
||||
+ label = "Lid";
|
||||
+ linux,code = <SW_LID>;
|
||||
+ linux,input-type = <EV_SW>;
|
||||
+ wakeup-source;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&edp1 {
|
||||
@@ -431,6 +447,12 @@
|
||||
rockchip,pins = <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sensor {
|
||||
+ mh248_irq_gpio: mh248-irq-gpio {
|
||||
+ rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&pwm6 {
|
||||
@@ -512,6 +534,7 @@
|
||||
};
|
||||
|
||||
&usbdp_phy1 {
|
||||
+ rockchip,dp-lane-mux = <2 3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# board/coolpi-cm5-genbook
|
||||
|
||||
Patches specific to the CoolPi GenBook laptop carrier (RK3588 +
|
||||
CoolPi-CM5 SoM, ARM laptop form factor). The board adds an
|
||||
ES8316-routed audio path, FUSB302 USB-C-PD controller, lid switch,
|
||||
USB3 phy-lane config, and a pwm-controlled fan — none of which are
|
||||
in mainline upstream because the board ships outside Rockchip's
|
||||
official reference designs.
|
||||
|
||||
## Patches
|
||||
|
||||
| File | Adds |
|
||||
|---|---|
|
||||
| `0002-...Add-pwm-fan.patch` | pwm15-driven thermal cooling fan node (depends on `soc/rockchip/rk3588/0001-...pwm15-pinctrl-entries.patch`) |
|
||||
| `0004-...Enable-speaker-output-via-audio-graph-card.patch` | rewires the ES8316 sound graph so HPOL/HPOR also drive the laptop speakers |
|
||||
| `0005-...Enable-USB-C-PD-charging-via-FUSB302.patch` | FUSB302 controller binding for USB-C PD charging |
|
||||
| `0008-...Add-lid-switch-and-USB3-PHY-lane-config.patch` | lid GPIO + USB3 phy-lane config |
|
||||
|
||||
Numbered 2/4/5/8 to match the upstream-series numbering Markus uses in
|
||||
`misc_patches/genbook/kernel/` — gap at 0006 (an SoC-wide
|
||||
`arm64/Kconfig` build-flag patch tracked elsewhere) and 0007 (skipped
|
||||
in the upstream series). 0009 (Bluetooth btrtl) and 0010 (multi-driver
|
||||
suspend/wakeup fix) are tracked in other scopes (driver/bluetooth,
|
||||
soc/rockchip/rk3588) and will be promoted as their respective
|
||||
campaigns demand.
|
||||
|
||||
## Fleet eligibility
|
||||
|
||||
- **ampere** (CoolPi CM5 GenBook): primary target, all 4 patches
|
||||
included in `fleet/ampere.yaml`.
|
||||
|
||||
No other current fleet host uses the CoolPi CM5 GenBook carrier, so
|
||||
no second consumer yet.
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
From: Markus Fritsche <mfritsche@localhost>
|
||||
Subject: [PATCH 3/3] arm64: dts: rockchip: rk3588-coolpi-cm5: fix power-off by enabling RK806 as system power controller
|
||||
|
||||
Without the system-power-controller property the rk8xx-core driver never
|
||||
registers its sys_off handler (rk808_power_off), which writes the DEV_OFF
|
||||
bit to RK806_SYS_CFG3 at shutdown time. As a result the RK806 PMIC does
|
||||
not cut power and the board remains partially active after "poweroff" —
|
||||
the heartbeat LED stops but internal activity continues.
|
||||
|
||||
All other mainline RK3588 boards that use the RK806 carry this property
|
||||
(NanoPC-T6, Rock 5A, OrangePi 5, Jaguar, ...). Add it to the CoolPi CM5
|
||||
PMIC node to restore proper power-off behaviour.
|
||||
|
||||
Generated-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi
|
||||
@@ -346,6 +346,7 @@
|
||||
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
+ system-power-controller;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
|
||||
<&rk806_dvs2_null>, <&rk806_dvs3_null>;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# module/coolpi-cm5
|
||||
|
||||
Patches that target the CoolPi CM5 system-on-module (RK3588-based,
|
||||
sold as a carrier-board-agnostic compute module). They apply to any
|
||||
carrier board that hosts the CM5 — currently only the GenBook in our
|
||||
fleet, but the scope tag exists so that a hypothetical second carrier
|
||||
wouldn't have to clone the patch under `board/<other-carrier>/`.
|
||||
|
||||
## Patches
|
||||
|
||||
- `0003-arm64-dts-rockchip-rk3588-coolpi-cm5-Fix-power-off-by-enabling-RK806-as-system-power-controller.patch` —
|
||||
marks the on-module RK806 PMIC as `system-power-controller` so the
|
||||
rk8xx-core driver registers it for the `pm_power_off` hook. Without
|
||||
this, `poweroff` reaches `arm_pm_restart` instead and the CM5 reboots
|
||||
on shutdown.
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
From: Markus Fritsche <mfritsche@localhost>
|
||||
Subject: [PATCH 1/2] arm64: dts: rockchip: rk3588: Add pwm15 pinctrl entries
|
||||
|
||||
Add pinctrl entries for all four mux options of the RK3588 pwm15
|
||||
controller (m0-m3) to rk3588-extra-pinctrl.dtsi, marked with
|
||||
/omit-if-no-ref/ so they are only compiled in when referenced.
|
||||
|
||||
Generated-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
1 file changed, 30 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3588-extra-pinctrl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra-pinctrl.dtsi
|
||||
@@ -342,6 +342,36 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ pwm15 {
|
||||
+ /omit-if-no-ref/
|
||||
+ pwm15m0_pins: pwm15m0-pins {
|
||||
+ rockchip,pins =
|
||||
+ /* pwm15_ir_m0 */
|
||||
+ <3 RK_PC3 11 &pcfg_pull_none>;
|
||||
+ };
|
||||
+
|
||||
+ /omit-if-no-ref/
|
||||
+ pwm15m1_pins: pwm15m1-pins {
|
||||
+ rockchip,pins =
|
||||
+ /* pwm15_ir_m1 */
|
||||
+ <4 RK_PB3 11 &pcfg_pull_none>;
|
||||
+ };
|
||||
+
|
||||
+ /omit-if-no-ref/
|
||||
+ pwm15m2_pins: pwm15m2-pins {
|
||||
+ rockchip,pins =
|
||||
+ /* pwm15_ir_m2 */
|
||||
+ <1 RK_PC6 11 &pcfg_pull_none>;
|
||||
+ };
|
||||
+
|
||||
+ /omit-if-no-ref/
|
||||
+ pwm15m3_pins: pwm15m3-pins {
|
||||
+ rockchip,pins =
|
||||
+ /* pwm15_ir_m3 */
|
||||
+ <1 RK_PD7 11 &pcfg_pull_none>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
sdio {
|
||||
/omit-if-no-ref/
|
||||
sdiom0_pins: sdiom0-pins {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# soc/rockchip/rk3588
|
||||
|
||||
SoC-wide RK3588 patches that any board built on this SoC benefits from.
|
||||
Distinct from `board/<name>/` (specific board configuration) and
|
||||
`module/<som-name>/` (specific SoM configuration that several boards
|
||||
share).
|
||||
|
||||
## Patches
|
||||
|
||||
- `0001-arm64-dts-rockchip-rk3588-Add-pwm15-pinctrl-entries.patch` —
|
||||
fills in the four mux options for RK3588's `pwm15`. Cosmetic
|
||||
upstream-quality fix; required as a *prerequisite* by board patches
|
||||
that want to wire pwm15 to a real consumer (e.g. CoolPi GenBook's
|
||||
pwm-fan, see `patches/board/coolpi-cm5-genbook/0002-...`).
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
From a202de1646d4c8f8ee2ebc2e4c100b621975754a Mon Sep 17 00:00:00 2001
|
||||
In-Reply-To: <20260429195306.239666-1-mfritsche@reauktion.de>
|
||||
References: <20260429195306.239666-1-mfritsche@reauktion.de>
|
||||
From: Markus Fritsche <mfritsche@reauktion.de>
|
||||
Date: Sat, 9 May 2026 16:16:07 +0200
|
||||
Subject: [PATCH RFC v2] media: videobuf2: add opt-in dma_resv producer fence
|
||||
helper
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
V4L2 producers historically don't propagate buffer-state-done into
|
||||
the dmabuf's dma_resv exclusive fence. Userspace consumers that
|
||||
import V4L2-produced dmabufs and wait on the dmabuf's implicit-sync
|
||||
fence (poll(POLLIN), DMA_BUF_IOCTL_EXPORT_SYNC_FILE,
|
||||
EGL_LINUX_DMA_BUF_EXT) currently see either zero fences or a stub
|
||||
fence from dma_fence_get_stub(). This is correct by accident for the
|
||||
common DQBUF-then-import case but represents a contract gap that
|
||||
breaks Wayland compositors importing CAPTURE buffers from a stateless
|
||||
H.264 decoder under continuous playback on implicit-sync GPU stacks
|
||||
(observed on RK3566 + hantro VPU + Mali-G52 panfrost; manifests as
|
||||
green frames -- BT.709 limited-range YUV(0,0,0) -> RGB(0,77,0) -- when
|
||||
the GPU samples the dmabuf before the producer's decode completes).
|
||||
|
||||
Add an opt-in API gated by both a per-driver runtime flag
|
||||
(vb2_queue::supports_release_fences) and a Kconfig
|
||||
(CONFIG_VIDEOBUF2_RELEASE_FENCES, default n) that lets producers
|
||||
populate a real dma_resv exclusive write fence on the dmabufs they
|
||||
export. Drivers call vb2_buffer_attach_release_fence(vb) at a
|
||||
finite-time-fenced point in their pipeline (typically m2m
|
||||
device_run, just before the HW kick); vb2_buffer_done() signals and
|
||||
puts the fence as part of its state transition.
|
||||
|
||||
The publish and signal paths are wrapped in
|
||||
dma_fence_begin_signalling() / dma_fence_end_signalling() so
|
||||
PROVE_LOCKING can validate that nothing taken in those critical
|
||||
sections deadlocks against the signal path. dma_resv_lock is
|
||||
sleepable but not taken on the signal path, so taking it inside the
|
||||
publish critical section is safe under lockdep.
|
||||
|
||||
Skips planes whose vb2_plane.dbuf is NULL -- buffers never exported
|
||||
via VIDIOC_EXPBUF (or imported via V4L2_MEMORY_DMABUF) have no
|
||||
dmabuf for userspace to wait on.
|
||||
|
||||
Drivers that don't opt in pay nothing: the helper is a no-op stub
|
||||
when CONFIG_VIDEOBUF2_RELEASE_FENCES=n, and an early-return check
|
||||
of supports_release_fences when =y but the flag is unset.
|
||||
|
||||
Validated on RK3566 PineTab2 with PROVE_LOCKING enabled: 30s of
|
||||
bbb_1080p30 H.264 stateless decode + zero-copy panfrost EGL import
|
||||
via dmabuf-wayland (mpv 0.41 + KWin 6.6.4 + Mesa panfrost 26.0.5)
|
||||
produces 31,816 dma_fence init/signal pairs across 5,724 vb2 buffer
|
||||
cycles with zero lockdep splats from videobuf2 / dma_resv code paths.
|
||||
|
||||
Subsequent patches in this series opt the hantro and rockchip-rga
|
||||
drivers in.
|
||||
|
||||
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Cc: Christian König <christian.koenig@amd.com>
|
||||
Cc: Nicolas Dufresne <nicolas@ndufresne.ca>
|
||||
Cc: Sumit Semwal <sumit.semwal@linaro.org>
|
||||
Cc: Hans Verkuil <hverkuil@xs4all.nl>
|
||||
Cc: Tomasz Figa <tfiga@chromium.org>
|
||||
Cc: linux-media@vger.kernel.org
|
||||
Cc: dri-devel@lists.freedesktop.org
|
||||
Cc: linaro-mm-sig@lists.linaro.org
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
drivers/media/common/videobuf2/Kconfig | 29 ++++
|
||||
.../media/common/videobuf2/videobuf2-core.c | 135 ++++++++++++++++++
|
||||
include/media/videobuf2-core.h | 51 +++++++
|
||||
3 files changed, 215 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/common/videobuf2/Kconfig b/drivers/media/common/videobuf2/Kconfig
|
||||
index d2223a12c..bbfa26984 100644
|
||||
--- a/drivers/media/common/videobuf2/Kconfig
|
||||
+++ b/drivers/media/common/videobuf2/Kconfig
|
||||
@@ -30,3 +30,32 @@ config VIDEOBUF2_DMA_SG
|
||||
config VIDEOBUF2_DVB
|
||||
tristate
|
||||
select VIDEOBUF2_CORE
|
||||
+
|
||||
+config VIDEOBUF2_RELEASE_FENCES
|
||||
+ bool "videobuf2: opt-in dma_resv producer fences for V4L2 dmabuf exports"
|
||||
+ depends on VIDEOBUF2_CORE
|
||||
+ depends on DMA_SHARED_BUFFER
|
||||
+ default n
|
||||
+ help
|
||||
+ Enables an opt-in API that lets vb2 producers populate a dma_resv
|
||||
+ exclusive write fence on the dmabufs they export to userspace.
|
||||
+ The fence is signalled when the buffer transitions to
|
||||
+ VB2_BUF_STATE_DONE.
|
||||
+
|
||||
+ This gives userspace consumers that import V4L2-produced dmabufs
|
||||
+ and wait on the dmabuf's implicit-sync fence (poll(POLLIN),
|
||||
+ DMA_BUF_IOCTL_EXPORT_SYNC_FILE, EGL_LINUX_DMA_BUF_EXT) a real
|
||||
+ producer fence to wait on, instead of a stub fence from
|
||||
+ dma_fence_get_stub() that the dma_buf core substitutes when
|
||||
+ dma_resv is empty.
|
||||
+
|
||||
+ Drivers individually opt in by setting
|
||||
+ vb2_queue::supports_release_fences = true and calling
|
||||
+ vb2_buffer_attach_release_fence() at the right point in their
|
||||
+ pipeline (typically m2m device_run, just before HW kick).
|
||||
+
|
||||
+ Distributors leave this off unless targeting Wayland/EGL
|
||||
+ consumers of V4L2 stateless decoder output on
|
||||
+ implicit-sync-only GPU stacks (e.g. mainline panfrost).
|
||||
+
|
||||
+ If unsure, say N.
|
||||
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
|
||||
index adf668b21..85d7fddbd 100644
|
||||
--- a/drivers/media/common/videobuf2/videobuf2-core.c
|
||||
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
|
||||
@@ -26,6 +26,12 @@
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
+#ifdef CONFIG_VIDEOBUF2_RELEASE_FENCES
|
||||
+#include <linux/dma-fence.h>
|
||||
+#include <linux/dma-resv.h>
|
||||
+#include <linux/dma-buf.h>
|
||||
+#endif
|
||||
+
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/v4l2-mc.h>
|
||||
|
||||
@@ -1173,6 +1179,120 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vb2_plane_cookie);
|
||||
|
||||
+#ifdef CONFIG_VIDEOBUF2_RELEASE_FENCES
|
||||
+/*
|
||||
+ * dma_resv release-fence integration.
|
||||
+ *
|
||||
+ * Optional, opt-in path that lets producers publish a real
|
||||
+ * dma_fence on their CAPTURE-side dmabufs so userspace consumers
|
||||
+ * (compositors, EGL importers) get spec-clean implicit-sync
|
||||
+ * semantics instead of the dma_buf core's stub fence. Drivers
|
||||
+ * call vb2_buffer_attach_release_fence() at a finite-time-fenced
|
||||
+ * point (typically m2m device_run) and the fence is signalled by
|
||||
+ * vb2_buffer_done(). Gated at runtime by
|
||||
+ * vb2_queue::supports_release_fences and at compile time by
|
||||
+ * CONFIG_VIDEOBUF2_RELEASE_FENCES.
|
||||
+ */
|
||||
+
|
||||
+static const char *vb2_dma_resv_get_driver_name(struct dma_fence *fence)
|
||||
+{
|
||||
+ return "videobuf2";
|
||||
+}
|
||||
+
|
||||
+static const char *vb2_dma_resv_get_timeline_name(struct dma_fence *fence)
|
||||
+{
|
||||
+ return "vb2-release-fence";
|
||||
+}
|
||||
+
|
||||
+static const struct dma_fence_ops vb2_dma_resv_fence_ops = {
|
||||
+ .get_driver_name = vb2_dma_resv_get_driver_name,
|
||||
+ .get_timeline_name = vb2_dma_resv_get_timeline_name,
|
||||
+};
|
||||
+
|
||||
+int vb2_buffer_attach_release_fence(struct vb2_buffer *vb)
|
||||
+{
|
||||
+ struct vb2_queue *q = vb->vb2_queue;
|
||||
+ struct dma_fence *fence;
|
||||
+ unsigned int plane;
|
||||
+ bool cookie;
|
||||
+
|
||||
+ if (!q->supports_release_fences)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (WARN_ON(vb->release_fence))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
||||
+ if (!fence)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ dma_fence_init(fence, &vb2_dma_resv_fence_ops, &q->dma_resv_fence_lock,
|
||||
+ q->dma_resv_fence_context,
|
||||
+ atomic64_inc_return(&q->dma_resv_fence_seqno));
|
||||
+
|
||||
+ /*
|
||||
+ * Annotate the publish-side critical section. Per
|
||||
+ * Documentation/driver-api/dma-buf.rst, lockdep validates
|
||||
+ * that nothing taken in this region can deadlock against
|
||||
+ * the signal path in vb2_buffer_signal_release_fence().
|
||||
+ * dma_resv_lock is sleepable but is not taken on the signal
|
||||
+ * path, so taking it inside the critical section is safe.
|
||||
+ */
|
||||
+ cookie = dma_fence_begin_signalling();
|
||||
+ for (plane = 0; plane < vb->num_planes; plane++) {
|
||||
+ struct dma_buf *dbuf = vb->planes[plane].dbuf;
|
||||
+
|
||||
+ if (!dbuf)
|
||||
+ continue;
|
||||
+
|
||||
+ dma_resv_lock(dbuf->resv, NULL);
|
||||
+ dma_resv_add_fence(dbuf->resv, fence, DMA_RESV_USAGE_WRITE);
|
||||
+ dma_resv_unlock(dbuf->resv);
|
||||
+ }
|
||||
+ dma_fence_end_signalling(cookie);
|
||||
+
|
||||
+ /* One reference for the eventual signal in vb2_buffer_done. */
|
||||
+ vb->release_fence = dma_fence_get(fence);
|
||||
+
|
||||
+ /* The dma_resv held its own reference per plane. Drop ours. */
|
||||
+ dma_fence_put(fence);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(vb2_buffer_attach_release_fence);
|
||||
+
|
||||
+static void vb2_buffer_signal_release_fence(struct vb2_buffer *vb,
|
||||
+ enum vb2_buffer_state state)
|
||||
+{
|
||||
+ struct dma_fence *fence = vb->release_fence;
|
||||
+ bool cookie;
|
||||
+
|
||||
+ if (!fence)
|
||||
+ return;
|
||||
+
|
||||
+ cookie = dma_fence_begin_signalling();
|
||||
+ if (state == VB2_BUF_STATE_ERROR)
|
||||
+ dma_fence_set_error(fence, -EIO);
|
||||
+ dma_fence_signal(fence);
|
||||
+ dma_fence_end_signalling(cookie);
|
||||
+
|
||||
+ dma_fence_put(fence);
|
||||
+ vb->release_fence = NULL;
|
||||
+}
|
||||
+#else /* !CONFIG_VIDEOBUF2_RELEASE_FENCES */
|
||||
+
|
||||
+int vb2_buffer_attach_release_fence(struct vb2_buffer *vb)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(vb2_buffer_attach_release_fence);
|
||||
+
|
||||
+static inline void vb2_buffer_signal_release_fence(struct vb2_buffer *vb,
|
||||
+ enum vb2_buffer_state state)
|
||||
+{
|
||||
+}
|
||||
+#endif /* CONFIG_VIDEOBUF2_RELEASE_FENCES */
|
||||
+
|
||||
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
|
||||
{
|
||||
struct vb2_queue *q = vb->vb2_queue;
|
||||
@@ -1199,6 +1319,9 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
|
||||
if (state != VB2_BUF_STATE_QUEUED)
|
||||
__vb2_buf_mem_finish(vb);
|
||||
|
||||
+ if (state != VB2_BUF_STATE_QUEUED)
|
||||
+ vb2_buffer_signal_release_fence(vb, state);
|
||||
+
|
||||
spin_lock_irqsave(&q->done_lock, flags);
|
||||
if (state == VB2_BUF_STATE_QUEUED) {
|
||||
vb->state = VB2_BUF_STATE_QUEUED;
|
||||
@@ -2651,6 +2774,18 @@ int vb2_core_queue_init(struct vb2_queue *q)
|
||||
mutex_init(&q->mmap_lock);
|
||||
init_waitqueue_head(&q->done_wq);
|
||||
|
||||
+#ifdef CONFIG_VIDEOBUF2_RELEASE_FENCES
|
||||
+ /*
|
||||
+ * Per-queue dma_resv release-fence context. Drivers that
|
||||
+ * opt in via supports_release_fences and call
|
||||
+ * vb2_buffer_attach_release_fence() use these to allocate
|
||||
+ * fences on a single per-queue timeline.
|
||||
+ */
|
||||
+ q->dma_resv_fence_context = dma_fence_context_alloc(1);
|
||||
+ atomic64_set(&q->dma_resv_fence_seqno, 0);
|
||||
+ spin_lock_init(&q->dma_resv_fence_lock);
|
||||
+#endif
|
||||
+
|
||||
q->memory = VB2_MEMORY_UNKNOWN;
|
||||
|
||||
if (q->buf_struct_size == 0)
|
||||
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
|
||||
index 4424d481d..766ff2194 100644
|
||||
--- a/include/media/videobuf2-core.h
|
||||
+++ b/include/media/videobuf2-core.h
|
||||
@@ -288,6 +288,16 @@ struct vb2_buffer {
|
||||
unsigned int skip_cache_sync_on_finish:1;
|
||||
|
||||
struct vb2_plane planes[VB2_MAX_PLANES];
|
||||
+#ifdef CONFIG_VIDEOBUF2_RELEASE_FENCES
|
||||
+ /*
|
||||
+ * Producer release fence published on each plane's
|
||||
+ * dmabuf->resv when the driver opts in via
|
||||
+ * vb2_buffer_attach_release_fence(). Signalled and put by
|
||||
+ * vb2_buffer_done() on transition to DONE/ERROR. NULL when
|
||||
+ * the driver did not opt in for this buffer.
|
||||
+ */
|
||||
+ struct dma_fence *release_fence;
|
||||
+#endif
|
||||
struct list_head queued_entry;
|
||||
struct list_head done_entry;
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
@@ -648,6 +658,19 @@ struct vb2_queue {
|
||||
spinlock_t done_lock;
|
||||
wait_queue_head_t done_wq;
|
||||
|
||||
+#ifdef CONFIG_VIDEOBUF2_RELEASE_FENCES
|
||||
+ /*
|
||||
+ * dma_resv release-fence context. Drivers that set
|
||||
+ * supports_release_fences and call
|
||||
+ * vb2_buffer_attach_release_fence() use these to allocate
|
||||
+ * fences on a per-queue timeline.
|
||||
+ */
|
||||
+ u64 dma_resv_fence_context;
|
||||
+ atomic64_t dma_resv_fence_seqno;
|
||||
+ spinlock_t dma_resv_fence_lock;
|
||||
+#endif
|
||||
+
|
||||
+ unsigned int supports_release_fences:1;
|
||||
unsigned int streaming:1;
|
||||
unsigned int start_streaming_called:1;
|
||||
unsigned int error:1;
|
||||
@@ -735,6 +758,34 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no);
|
||||
*/
|
||||
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
|
||||
|
||||
+/**
|
||||
+ * vb2_buffer_attach_release_fence() - opt-in dma_resv release fence.
|
||||
+ * @vb: the buffer being committed to the producer.
|
||||
+ *
|
||||
+ * Drivers that have set vb2_queue::supports_release_fences may call
|
||||
+ * this from any sleepable context where they have committed to
|
||||
+ * running the operation in finite time -- typically m2m
|
||||
+ * device_run(), just before the HW kick. The helper allocates a
|
||||
+ * dma_fence on the queue's per-queue timeline, attaches it as
|
||||
+ * DMA_RESV_USAGE_WRITE on each plane's dmabuf->resv, and stashes
|
||||
+ * it in vb->release_fence. vb2_buffer_done() signals and puts the
|
||||
+ * fence as part of the buffer's state transition.
|
||||
+ *
|
||||
+ * Skips planes whose vb2_plane.dbuf is NULL -- buffers never
|
||||
+ * exported via VIDIOC_EXPBUF (or imported via V4L2_MEMORY_DMABUF)
|
||||
+ * have no dmabuf for userspace to wait on.
|
||||
+ *
|
||||
+ * No-op when vb2_queue::supports_release_fences is not set
|
||||
+ * (regardless of CONFIG_VIDEOBUF2_RELEASE_FENCES). When
|
||||
+ * CONFIG_VIDEOBUF2_RELEASE_FENCES=n, this is a stub that returns 0.
|
||||
+ *
|
||||
+ * Returns 0 on success or when the no-op stub is in effect,
|
||||
+ * negative errno on allocation failure when fence publishing was
|
||||
+ * attempted. Best-effort: drivers should ignore the return value
|
||||
+ * unless they want diagnostics.
|
||||
+ */
|
||||
+int vb2_buffer_attach_release_fence(struct vb2_buffer *vb);
|
||||
+
|
||||
/**
|
||||
* vb2_discard_done() - discard all buffers marked as DONE.
|
||||
* @q: pointer to &struct vb2_queue with videobuf2 queue.
|
||||
--
|
||||
2.53.0
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
From 1844c263bde8dd244d7db46f8c508e7c70da459c Mon Sep 17 00:00:00 2001
|
||||
In-Reply-To: <20260429195306.239666-1-mfritsche@reauktion.de>
|
||||
References: <20260429195306.239666-1-mfritsche@reauktion.de>
|
||||
From: Markus Fritsche <mfritsche@reauktion.de>
|
||||
Date: Sat, 9 May 2026 16:24:01 +0200
|
||||
Subject: [PATCH RFC v2] media: hantro: attach dma_resv release fence at
|
||||
device_run
|
||||
|
||||
Opt the hantro driver into the new vb2 release-fence helper so its
|
||||
CAPTURE-side dmabufs carry a real producer fence that wayland
|
||||
compositors and other implicit-sync consumers can wait on, instead
|
||||
of the dma_buf core's stub fence.
|
||||
|
||||
Attach point is m2m device_run, immediately after
|
||||
v4l2_m2m_buf_copy_metadata() and before ctx->codec_ops->run().
|
||||
Per Nicolas Dufresne's v1 review (lore.kernel.org/linux-media/
|
||||
3d8deeb15581b754e4c061d4c4a13657aa08bc3c.camel@ndufresne.ca/),
|
||||
this satisfies the dma_fence finite-time contract: the m2m core
|
||||
has committed to running the job by this point, codec_ops->run
|
||||
either kicks the HW (decode-complete signals the fence via
|
||||
vb2_buffer_done) or fails immediately (job_finish with
|
||||
VB2_BUF_STATE_ERROR signals with -EIO). PM and clocks are already
|
||||
up by this point, so no allocation context restrictions.
|
||||
|
||||
The CAPTURE queue is opted in with supports_release_fences=true at
|
||||
queue_init.
|
||||
|
||||
Userspace consumers that import hantro CAPTURE dmabufs and wait on
|
||||
their implicit-sync fence (Wayland zwp_linux_dmabuf_v1 +
|
||||
panfrost EGL_LINUX_DMA_BUF_EXT) now wait on a real fence
|
||||
representing the producer's actual completion, fixing green-frame
|
||||
corruption observed on RK3566 PineTab2 + Mali-G52 panfrost (the
|
||||
GPU was sampling zero pages because the dmabuf's implicit fence
|
||||
was the dma_buf core's pre-signalled stub).
|
||||
|
||||
Validated end-to-end on PineTab2 (RK3566 / hantro G1 / Mali-G52
|
||||
mainline panfrost): 30s of bbb_1080p30 H.264 stateless decode +
|
||||
zero-copy panfrost EGL import via dmabuf-wayland (mpv 0.41 +
|
||||
KWin 6.6.4 + Mesa panfrost 26.0.5) renders correctly with no
|
||||
green-frame corruption and no PROVE_LOCKING splats.
|
||||
|
||||
Cc: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
|
||||
Cc: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Cc: Nicolas Dufresne <nicolas@ndufresne.ca>
|
||||
Cc: linux-media@vger.kernel.org
|
||||
Cc: linux-rockchip@lists.infradead.org
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
.../media/platform/verisilicon/hantro_drv.c | 23 +++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
|
||||
index 2e81877f6..6a66c47ed 100644
|
||||
--- a/drivers/media/platform/verisilicon/hantro_drv.c
|
||||
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
|
||||
@@ -186,6 +186,22 @@ static void device_run(void *priv)
|
||||
|
||||
v4l2_m2m_buf_copy_metadata(src, dst);
|
||||
|
||||
+ /*
|
||||
+ * Attach a producer fence on the CAPTURE-side dmabuf so userspace
|
||||
+ * importers (e.g. Wayland compositors) get spec-clean implicit-sync
|
||||
+ * semantics. Called from device_run rather than buf_queue: the
|
||||
+ * dma_fence finite-time contract requires that once a fence is
|
||||
+ * published, the producer must signal it in finite time. By the
|
||||
+ * time we reach device_run, the m2m core has committed to running
|
||||
+ * this job, and the next hop (codec_ops->run) either kicks the HW
|
||||
+ * (decode-complete signals the fence via vb2_buffer_done) or
|
||||
+ * fails immediately (job_finish with VB2_BUF_STATE_ERROR signals
|
||||
+ * the fence with -EIO). Either path resolves the fence in finite
|
||||
+ * time. Best-effort: a NOMEM here means we lose implicit-sync
|
||||
+ * precision for this frame, no functional regression.
|
||||
+ */
|
||||
+ (void)vb2_buffer_attach_release_fence(&dst->vb2_buf);
|
||||
+
|
||||
if (ctx->codec_ops->run(ctx))
|
||||
goto err_cancel_job;
|
||||
|
||||
@@ -249,6 +265,13 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
|
||||
dst_vq->lock = &ctx->dev->vpu_mutex;
|
||||
dst_vq->dev = ctx->dev->v4l2_dev.dev;
|
||||
|
||||
+ /*
|
||||
+ * Opt the CAPTURE queue into vb2 release-fence publishing.
|
||||
+ * No-op unless CONFIG_VIDEOBUF2_RELEASE_FENCES=y; runtime cost
|
||||
+ * is one extra fence allocation + dma_resv update per device_run.
|
||||
+ */
|
||||
+ dst_vq->supports_release_fences = true;
|
||||
+
|
||||
return vb2_queue_init(dst_vq);
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
From 2c63a63bf65739763051dc4ce7ce2ffaf2d514c4 Mon Sep 17 00:00:00 2001
|
||||
In-Reply-To: <20260429195306.239666-1-mfritsche@reauktion.de>
|
||||
References: <20260429195306.239666-1-mfritsche@reauktion.de>
|
||||
From: Markus Fritsche <mfritsche@reauktion.de>
|
||||
Date: Sat, 9 May 2026 16:50:51 +0200
|
||||
Subject: [PATCH RFC v2] media: rockchip-rga: attach dma_resv release fence at
|
||||
device_run
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Opt the rockchip-rga driver into the new vb2 release-fence helper.
|
||||
|
||||
Same shape as the hantro patch: attach a producer fence on the
|
||||
CAPTURE-side dmabuf at m2m device_run, signalled by
|
||||
vb2_buffer_done() when RGA completes the m2m operation.
|
||||
|
||||
Differs from hantro in one mechanical detail: rga's device_run
|
||||
wraps the entire body in spin_lock_irqsave(&rga->ctrl_lock). Our
|
||||
helper calls dma_resv_lock(), which is sleepable, so the
|
||||
buffer-fetch + fence-attach sequence has to run above the spinlock.
|
||||
Restructure device_run so:
|
||||
|
||||
- v4l2_m2m_next_src_buf / next_dst_buf,
|
||||
- src->sequence increment,
|
||||
- vb2_buffer_attach_release_fence(&dst->vb2_buf)
|
||||
|
||||
run before spin_lock_irqsave; only the rga->curr assignment and
|
||||
rga_hw_start() (the actual HW kick) remain inside the spinlock.
|
||||
|
||||
This is safe under the m2m-job ownership model: by the time
|
||||
device_run is called, the m2m core has selected this context and
|
||||
serializes one device_run per context, so v4l2_m2m_next_*_buf
|
||||
returns stable pointers until the corresponding *_buf_remove in
|
||||
rga_isr. ctrl_lock was previously protecting per-device state
|
||||
(rga->curr) and the HW register access, neither of which depends on
|
||||
the buffer-fetch happening inside the lock.
|
||||
|
||||
The CAPTURE queue is opted in with supports_release_fences=true at
|
||||
queue_init.
|
||||
|
||||
Userspace consumers of RGA-produced dmabufs (image-processing
|
||||
pipelines, screen-rotation servers, gstreamer flows on Rockchip
|
||||
boards) get spec-clean implicit-sync semantics, matching what
|
||||
hantro does in the previous patch in this series.
|
||||
|
||||
Sven Püschel's ongoing "media: platform: rga: Add RGA3 support"
|
||||
v5 series (linux-rockchip 2026-04-28) restructures rga.c
|
||||
substantially. If that lands first, the device_run restructure
|
||||
here will need a rebase against the new shape; the locking story
|
||||
itself is invariant.
|
||||
|
||||
Cc: Jacob Chen <jacob-chen@iotwrt.com>
|
||||
Cc: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
|
||||
Cc: Sven Püschel <s.pueschel@pengutronix.de>
|
||||
Cc: Heiko Stuebner <heiko@sntech.de>
|
||||
Cc: Hans Verkuil <hverkuil@xs4all.nl>
|
||||
Cc: linux-media@vger.kernel.org
|
||||
Cc: linux-rockchip@lists.infradead.org
|
||||
Signed-off-by: Markus Fritsche <mfritsche@reauktion.de>
|
||||
---
|
||||
drivers/media/platform/rockchip/rga/rga.c | 27 +++++++++++++++++++----
|
||||
1 file changed, 23 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
|
||||
index fea63b94c..03030c7ea 100644
|
||||
--- a/drivers/media/platform/rockchip/rga/rga.c
|
||||
+++ b/drivers/media/platform/rockchip/rga/rga.c
|
||||
@@ -38,15 +38,28 @@ static void device_run(void *prv)
|
||||
struct vb2_v4l2_buffer *src, *dst;
|
||||
unsigned long flags;
|
||||
|
||||
- spin_lock_irqsave(&rga->ctrl_lock, flags);
|
||||
-
|
||||
- rga->curr = ctx;
|
||||
-
|
||||
+ /*
|
||||
+ * Fetch the next-job buffers and (best-effort) attach a producer
|
||||
+ * fence on CAPTURE before taking ctrl_lock below.
|
||||
+ * vb2_buffer_attach_release_fence() takes dma_resv_lock, which is
|
||||
+ * sleepable; ctrl_lock is taken with spin_lock_irqsave so any
|
||||
+ * sleepable call must happen above it. Buffer ownership is
|
||||
+ * already committed at this point: the m2m core has selected
|
||||
+ * this context for device_run and serializes one device_run per
|
||||
+ * context, so v4l2_m2m_next_*_buf returns stable pointers until
|
||||
+ * the corresponding *_buf_remove in rga_isr.
|
||||
+ */
|
||||
src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
|
||||
src->sequence = ctx->osequence++;
|
||||
|
||||
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
|
||||
|
||||
+ (void)vb2_buffer_attach_release_fence(&dst->vb2_buf);
|
||||
+
|
||||
+ spin_lock_irqsave(&rga->ctrl_lock, flags);
|
||||
+
|
||||
+ rga->curr = ctx;
|
||||
+
|
||||
rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
|
||||
|
||||
spin_unlock_irqrestore(&rga->ctrl_lock, flags);
|
||||
@@ -123,6 +136,12 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
|
||||
dst_vq->lock = &ctx->rga->mutex;
|
||||
dst_vq->dev = ctx->rga->v4l2_dev.dev;
|
||||
|
||||
+ /*
|
||||
+ * Opt the CAPTURE queue into vb2 release-fence publishing.
|
||||
+ * Compile-time gated by CONFIG_VIDEOBUF2_RELEASE_FENCES.
|
||||
+ */
|
||||
+ dst_vq->supports_release_fences = true;
|
||||
+
|
||||
return vb2_queue_init(dst_vq);
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# vb2_dma_resv release-fence — RFC v2 series
|
||||
|
||||
Three-patch series that opts V4L2 m2m drivers into attaching real
|
||||
producer fences to CAPTURE-side dmabufs, so implicit-sync GPU
|
||||
consumers (Wayland / panfrost / panthor) wait correctly on the
|
||||
producer's decode-completion rather than seeing the dma_buf core's
|
||||
stub fence.
|
||||
|
||||
| Patch | Subject |
|
||||
|---|---|
|
||||
| `0004` | media: videobuf2: add opt-in dma_resv producer fence helper |
|
||||
| `0005` | media: hantro: attach dma_resv release fence at device_run |
|
||||
| `0006` | media: rockchip-rga: attach dma_resv release fence at device_run |
|
||||
|
||||
Numbered with the leading 4/5/6 because the fresnel build series carries
|
||||
these alongside the 3 board-scoped `0001/0002/0003` Pinebook Pro DTS
|
||||
patches; the numbers reflect apply-order in the PKGBUILD, not the
|
||||
upstream lore series ordering (which starts at 1/4..4/4 with a cover).
|
||||
|
||||
## Status
|
||||
|
||||
**RFC v2.** Iterated on `lore.kernel.org/linux-media` after v1 was
|
||||
rejected over the dma_fence finite-time contract gap and bus-locked
|
||||
allocation issues. v2 attaches the fence at `device_run` instead of
|
||||
QBUF, which puts allocation in slept-OK context (PM and clocks up,
|
||||
job committed) — per Nicolas Dufresne's v1 review feedback.
|
||||
|
||||
Cover-letter reference: `marfrit/dmabuf-modifier-triage#3` (campaign
|
||||
session that owns the upstream-targeting work; this directory ships
|
||||
the build-tree-ready form for kernel-agent fleet consumption).
|
||||
|
||||
## Scope
|
||||
|
||||
`subsystem/media/videobuf2/` for the helper (0004), with two
|
||||
driver opt-ins (0005/0006) shipped together because hantro and
|
||||
rockchip-rga both need the helper to be useful on the RK35xx fleet.
|
||||
Splitting 0005/0006 into `driver/hantro/` and `driver/rockchip-rga/`
|
||||
was considered but rejected: they're a single contract series, and
|
||||
their apply-order matters (0004 must precede). Series-as-unit beats
|
||||
per-driver promote eligibility here.
|
||||
|
||||
## Fleet eligibility
|
||||
|
||||
- **fresnel** (RK3399 + hantro + Mali-G52): eligible. Carried in
|
||||
`fleet/fresnel.yaml` since 2026-05-15 (decision flipped from "defer
|
||||
to v2" to "include — v2 in this tree").
|
||||
- **ohm** (RK3566 + hantro + Mali-G52): eligible. Was the original
|
||||
reproducer for the green-frames symptom. Will be carried in
|
||||
`fleet/ohm.yaml` once that manifest lands.
|
||||
- **ampere** (RK3588 + hantro for some codecs): eligibility deferred —
|
||||
RK3588 uses rkvdec2 for primary decode, hantro role is narrower.
|
||||
Re-assess when `fleet/ampere.yaml` lands per issue #6.
|
||||
- **boltzmann** (RK3588): same as ampere — defer.
|
||||
|
||||
## Upstream targeting
|
||||
|
||||
Not yet posted to linux-media in v2 form. Per `feedback_no_upstream.md`
|
||||
the default is "build-tree only, wait for explicit ask". When/if the
|
||||
upstream submission happens, this directory's `0004/0005/0006` are the
|
||||
canonical source — they include the v2 commit headers (`PATCH RFC v2`,
|
||||
`In-Reply-To` chain to the v1 cover-letter Message-Id).
|
||||
Reference in New Issue
Block a user