Skip to content

feat(cpufreq): RK3588 ondemand CPU DVFS with voltage calibration#1657

Open
JosephJoshua wants to merge 8 commits into
rcore-os:devfrom
oscomp-posad:pr-rk3588-cpufreq
Open

feat(cpufreq): RK3588 ondemand CPU DVFS with voltage calibration#1657
JosephJoshua wants to merge 8 commits into
rcore-os:devfrom
oscomp-posad:pr-rk3588-cpufreq

Conversation

@JosephJoshua

Copy link
Copy Markdown
Contributor

Adds CPU DVFS for the RK3588 (OrangePi-5-Plus): an ondemand cpufreq governor with
a real PMIC voltage lever, gated behind the rk3588-cpufreq feature.

Background

The RK3588 CPU clock is voltage-coupled (an SCMI clock id selects a PVTPLL
ring whose delivered frequency tracks the core rail voltage), and its SCMI
interface is frequency-only. Setting the SCMI rate alone overshoots (e.g. an
SCMI "1200 MHz" delivers ~1490 MHz at the ~800 mV boot rail). Exact DVFS needs
both levers together — the SCMI ring and the matching rail voltage.

What's here

  • PMIC drivers (drivers/ax-driver/src/soc/rockchip/pmic_{i2c,spi}.rs):
    a polling rk3x I2C master + RK8602/RK8603 regulator for the A76 rails, and a
    polling Rockchip SPI master + RK806 DCDC2 for the A55 rail. Each bus does a
    3-layer bring-up (clock ungate + core-reset de-assert + full pinctrl apply).
  • cpufreq driver (cpufreq.rs): sets each cluster clock over the SCMI seam,
    aligns each rail to its OPP-nominal voltage so the coupled clock lands exactly,
    then runs an ondemand governor. The governor scores per-core busy% (a cluster
    shares one clock, so it boosts from its busiest CPU, like Linux schedutil) and
    moves each cluster's OPP up (fast attack) / down (slow decay).
  • Frequency oracle (components/axcpu/src/aarch64/init.rs): enable the PMU
    cycle counter at boot so PMCCNTR_EL0 reads real cycle counts at EL0/EL1
    (reuses existing ax_cpu::pmu helpers). Used for exact freq measurement.
  • Voltage calibration (gated CALIBRATE const): a one-shot in-kernel
    (ring x voltage) sweep that measures the actual delivered frequency per
    point via the PMU counter, so the higher OPPs are chosen empirically. The
    measured hybrid ladder scales the ring below the 675 mV point and the voltage
    above it, keeping every rung over-volted (never an undervolt).
  • Kernel wiring (os/StarryOS/kernel/src/entry.rs): the governor's periodic
    loop and the calibration sweep run as kernel tasks (they can't live in the
    driver — ax-driver sits below ax-task/ax-hal in the dep graph). The per-CPU
    busy-tick counter they consume is added in axtask (BUSY_TICKS /
    cpu_busy_ticks).

Board-validated

Under load, cpuprobe's PMU mhz_pmc reads the top OPPs exactly (A76 1725 MHz,
A55 1523 MHz), with no PSU brownout at threads=8. The governor tracks load
up/down; per-core compute is at parity with Linux at equal frequency.

Feature-gated and off by default; a board build enabling ax-driver/rk3588-cpufreq
exercises it (see the companion sysbench-board app PR).

@JosephJoshua
JosephJoshua marked this pull request as ready for review July 20, 2026 09:47
Copilot AI review requested due to automatic review settings July 20, 2026 09:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@JosephJoshua
JosephJoshua force-pushed the pr-rk3588-cpufreq branch 2 times, most recently from 835ca41 to 2d6c411 Compare July 20, 2026 10:36

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 Orange Pi 5 Plus/RK3588 新增特性门控的 CPU DVFS:通过 SCMI、I2C/SPI PMIC 与定时 governor 调整三组 CPU cluster 的 OPP,并新增 PMU cycle counter 与 axtask busy-tick 统计。它还改变了 AArch64 trap 初始化、StarryOS early-init 和调度计数;因此虽面向板级功能,公开 feature 的宿主构建、PMIC 通信失败路径和 OPP 状态机都不是完全隔离的。

发现两个阻塞问题,详见行内评论:rk3588-cpufreq 在非 AArch64 宿主启用时会直接编译 AArch64 mrs 指令,当前无法运行该 feature 的主机测试;并且 SPI/RK806 尚不能可靠读回/确认实际通信时,代码仍会武装 governor,后续可能在电压写入未生效时提高 CPU 时钟。

验证:当前 HEAD 的 Actions check-runs 均已完成(29 success、29 skipped;唯一 cancelled 为 stale-run 取消),未见由本 PR 引起的远端失败。本地 git diff --checkcargo fmt --checkcargo xtask clippy --package ax-driver --package ax-cpu --package ax-task --package starry-kernel、以及 cargo clippy -p ax-driver --features rk3588-cpufreq --target aarch64-unknown-none-softfloat -- -D warnings 均通过;AArch64 目标的 Starry kernel/driver cargo check 也通过。定向的 axtask RR 回归测试通过。相反,cargo test -p ax-driver --features rk3588-cpufreq 在 x86_64 宿主上因新增 mrs inline asm 失败,这是本 PR 的直接回归。完整 axtask host-test 组合在未修改测试基础设施处 SIGSEGV,故只将通过的定向回归作为该部分的本地证据。

已查看既有 review:仅有 Copilot 的额度不足提示,没有待解决的技术意见;PR/issue 评论也没有额外的行动项。关联检索发现 #1658 明确 stack 在本 PR 之上并依赖其板级 feature,因而不构成重复实现,但在本 PR 修复前不应作为其验证替代。除以上问题外,剩余风险主要是实际板级 PMIC/OPP 转换需要有可复现的目标板回归覆盖。

Powered by gpt-5.6-terra

]
# RK3588 fixed-OPP-at-boot CPU DVFS (voltage-free rung): raises the CPU cluster
# clocks via the SCMI seam at probe time. Board-only policy; keep it opt-in.
rk3588-cpufreq = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这个 feature 会无条件编译 cpufreq.rs,而该文件包含 AArch64 的 mrs inline asm;在普通 x86_64 宿主执行 cargo test -p ax-driver --features rk3588-cpufreq 会以 invalid instruction mnemonic 'mrs' 失败。既然这是公开且标称 board-only 的 feature,请将 AArch64 实现/re-export 用 cfg(target_arch = "aarch64") 约束并提供宿主 stub/测试,或以等价方式保证该 feature 的宿主检查可编译;否则新增功能无法通过该 crate 的常规测试路径。

// Arm the dynamic governor only if both PMIC buses came up, so it never tries
// to move a rail it cannot drive. If either failed, every cluster stays on the
// boot OPP the SCMI reclock already set (safe: that is the fixed-boot state).
if GOVERNOR_ENABLE && a76_ok && a55_ok {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a55_ok 只说明 SPI2 APB 控制器完成了 is_alive 检查;上面已明确 RK806 读路径仍会返回伪造的 0x00,因此它并不能证明 PMIC/MOSI 可通信。这里仍据此设置 GOV_READY,而 apply_opp 又忽略 force_write_dcdc2 的失败并继续提高 SCMI 时钟、提交新的 OPP index;一旦实际电压写入未到达 RK806,就可能在旧电压上升频,造成欠压。请在获得可信的 RK806 ID/VSEL 读回并验证写入前保持 governor 关闭;同时让 OPP 应用传播并检查电压和 SCMI 的结果,只有二者确认后才更新状态。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 Orange Pi 5 Plus/RK3588 新增特性门控的 CPU DVFS:通过 SCMI、I2C/SPI PMIC 与定时 governor 调整三组 CPU cluster 的 OPP,并新增 PMU cycle counter 与 axtask busy-tick 统计。它还改变了 AArch64 trap 初始化、StarryOS early-init 和调度计数;因此虽面向板级功能,公开 feature 的宿主构建、PMIC 通信失败路径和 OPP 状态机都不是完全隔离的。

发现两个阻塞问题,详见行内评论:rk3588-cpufreq 在非 AArch64 宿主启用时会直接编译 AArch64 mrs 指令,当前无法运行该 feature 的主机测试;并且 SPI/RK806 尚不能可靠读回/确认实际通信时,代码仍会武装 governor,后续可能在电压写入未生效时提高 CPU 时钟。

验证:当前 HEAD 的 Actions check-runs 均已完成(29 success、29 skipped;唯一 cancelled 为 stale-run 取消),未见由本 PR 引起的远端失败。本地 git diff --checkcargo fmt --checkcargo xtask clippy --package ax-driver --package ax-cpu --package ax-task --package starry-kernel、以及 cargo clippy -p ax-driver --features rk3588-cpufreq --target aarch64-unknown-none-softfloat -- -D warnings 均通过;AArch64 目标的 Starry kernel/driver cargo check 也通过。定向的 axtask RR 回归测试通过。相反,cargo test -p ax-driver --features rk3588-cpufreq 在 x86_64 宿主上因新增 mrs inline asm 失败,这是本 PR 的直接回归。完整 axtask host-test 组合在未修改测试基础设施处 SIGSEGV,故只将通过的定向回归作为该部分的本地证据。

已查看既有 review:仅有 Copilot 的额度不足提示,没有待解决的技术意见;PR/issue 评论也没有额外的行动项。关联检索发现 #1658 明确 stack 在本 PR 之上并依赖其板级 feature,因而不构成重复实现,但在本 PR 修复前不应作为其验证替代。除以上问题外,剩余风险主要是实际板级 PMIC/OPP 转换需要有可复现的目标板回归覆盖。

Powered by gpt-5.6-terra

]
# RK3588 fixed-OPP-at-boot CPU DVFS (voltage-free rung): raises the CPU cluster
# clocks via the SCMI seam at probe time. Board-only policy; keep it opt-in.
rk3588-cpufreq = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这个 feature 会无条件编译 cpufreq.rs,而该文件包含 AArch64 的 mrs inline asm;在普通 x86_64 宿主执行 cargo test -p ax-driver --features rk3588-cpufreq 会以 invalid instruction mnemonic 'mrs' 失败。既然这是公开且标称 board-only 的 feature,请将 AArch64 实现/re-export 用 cfg(target_arch = "aarch64") 约束并提供宿主 stub/测试,或以等价方式保证该 feature 的宿主检查可编译;否则新增功能无法通过该 crate 的常规测试路径。

// Arm the dynamic governor only if both PMIC buses came up, so it never tries
// to move a rail it cannot drive. If either failed, every cluster stays on the
// boot OPP the SCMI reclock already set (safe: that is the fixed-boot state).
if GOVERNOR_ENABLE && a76_ok && a55_ok {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a55_ok 只说明 SPI2 APB 控制器完成了 is_alive 检查;上面已明确 RK806 读路径仍会返回伪造的 0x00,因此它并不能证明 PMIC/MOSI 可通信。这里仍据此设置 GOV_READY,而 apply_opp 又忽略 force_write_dcdc2 的失败并继续提高 SCMI 时钟、提交新的 OPP index;一旦实际电压写入未到达 RK806,就可能在旧电压上升频,造成欠压。请在获得可信的 RK806 ID/VSEL 读回并验证写入前保持 governor 关闭;同时让 OPP 应用传播并检查电压和 SCMI 的结果,只有二者确认后才更新状态。

@JosephJoshua

Copy link
Copy Markdown
Contributor Author

Thanks for the careful review. Both blocking findings are addressed — a93e784fc (host-compile) and 43f401c38 (transactional apply).

1. mrs inline asm on a non-aarch64 host — fixed. The four PMU/counter leaf reads (rd_pmccntr/rd_cntvct/rd_cntfrq/rd_mpidr) are now #[cfg(target_arch = "aarch64")] with #[cfg(not(...))] stubs returning 0; the arch-generic callers (measure_mhz/calibrate_cluster) are unchanged, so aarch64/board behavior is byte-identical. cargo build -p ax-driver --features rk3588-cpufreq --target x86_64-unknown-none now compiles.

2. OPP apply ignoring PMIC/SCMI failures — fixed transactionally. apply_opp now returns a result and stops at the first failed step; governor_poll commits IDX only when both the voltage write and the SCMI clock set succeed, otherwise it logs and retries from the last-confirmed OPP on the next tick. Ordering is voltage-then-clock on upshift and clock-then-voltage on downshift, so any single-step failure leaves the cluster over-volted, never under-volted — which is the concrete undervolt risk you flagged.

On keeping the governor armed (rather than gating GOV_READY on a "trustworthy RK806 readback"): this was intentional, because gating on that isn't achievable in software today and would regress validated behavior:

  • The A55 (RK806/SPI) read path has a hardware MISO-loopback defect — reads echo the TX bytes instead of returning real chip data (confirmed even on chip-ID registers with known-nonzero defaults). A software "verify readback" (e.g. gate on a nonzero ID) would be spuriously satisfied by that echo, giving false confidence rather than real verification.
  • The A55 write path is nonetheless confirmed to land out-of-band: on the board the A55 delivers 1523 MHz under load, and since RK3588's CPU clock is voltage-coupled (PVTPLL) that frequency is only reachable if the DCDC2 write took effect and the governor was armed.
  • The A76 (RK8602/8603, I2C) path is already genuinely readback-verified (set_vsel_verify), and A55 shares the single GOV_READY flag with the two verified A76 clusters — so gating A55 off would also disable working, verified A76 DVFS.
  • With the transactional apply above, a reported PMIC/SCMI failure can no longer commit a stale OPP.

Tracked follow-up (out of this PR's scope): fix the SPI2 MISO pinmux/wiring so pmic_spi::get_uv returns real data, then upgrade force_write_dcdc2 to a readback-verified write mirroring set_vsel_verify; the now-transactional apply_opp will inherit that stronger guarantee with no policy-layer change. If you'd prefer, I can split GOV_READY per-cluster so A55 is gated independently — but that would disable the (board-validated) A55 DVFS, so I've left it armed pending your call.

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 RK3588/OrangePi-5-Plus 增加 feature-gated CPU DVFS:SCMI 设置三个 cluster 的 ring,I2C/SPI PMIC 调整 rail,StarryOS 以周期任务运行 governor;同时启用 AArch64 PMU cycle counter,并在 axtask 记录每 CPU 的 busy tick。feature 关闭时调用点为 stub,但启用后跨越早期 AArch64 初始化、调度 tick、SCMI SMC 与 PMIC MMIO,因此不是完全隔离的改动。

实现方向(先以 boot OPP 重设、再做 rail 对齐;upshift 先电压后时钟、downshift 反向)符合避免欠压的基本顺序。上一轮两项合理意见已做实质修复:AArch64 mrs leaf 已有非 AArch64 stub,宿主 feature 测试可编译;apply_opp 也只在两个步骤成功后提交 IDX。但这两个状态机修复没有对应的可发现回归测试,且 PMIC 轮询仍在禁 IRQ 自旋锁内,详见行内阻塞意见。

影响与隔离性:该 feature 目前只在新增 ax-driver 代码中出现,当前 HEAD 没有 Starry board/build 配置启用它;因此现有默认构建和 feature-off 运行不受影响,但仓库的 board/CI 路径也不会执行 governor、OPP 转换或 PMIC 失败分支。I2C/SPI MISO/readback 尚有限制,实际板级行为仍需可复现覆盖。

CI:当前 HEAD 的 59 个 check-runs 都已完成,success=30skipped=29、无 failure;skipped 为 run_host/run_container、发布或路径/矩阵分支,未发现本 PR 造成的远端失败。已做本地验证:cargo fmt --checkgit diff --checkcargo test -p ax-driver --no-default-features --features rk3588-cpufreq(25 个测试通过)、同 feature 的宿主 clippy 与 AArch64 target cargo check/cargo clippy -D warningscargo check -p starry-kernel --target aarch64-unknown-none-softfloat --features 'ax-driver/rk3588-cpufreq'cargo xtask clippy --package ax-driver、以及 cargo test -p ax-cpu --all-features 均通过。cargo test -p ax-task --features host-test,sched-rr,smp,irq 在第 7 个测试后 SIGSEGV;当前没有证据将此 host-test 基础设施失败归因于本 PR,且当前 HEAD CI 无相关失败,但它不能作为忙计数行为的通过证据。

测试覆盖:新增 PMIC 单测只验证 VSEL/step/baud 常量,实际执行的 21 个新增单元测试没有覆盖 cpufreq.rs 的 governor、OPP 顺序、SCMI/PMIC 失败及 IDX 提交;PR 也未将 feature 接入可发现的 board build/test runner。对新增硬件状态机及本次 transactional bug fix,这不足以防止回归。

历史 review/讨论:Copilot 仅报告额度限制。此前关于宿主 mrs 与错误 OPP 提交的两项技术意见合理;前者已由当前 cfg stub 解决,后者的结构性提交顺序已改正,但因缺少失败路径测试,不能仅凭代码形状确认。作者对 RK806 MISO/readback 限制的说明已阅读,仍应以确定性测试和 board 运行证据约束后续变更。

重复/重叠:基线没有等价 cpufreq/PMIC 实现;#1658 明确堆叠并依赖本 PR,提供 app/board harness,不是重复但不能替代本 PR 的底层回归覆盖;#1656 为调度分布改动,互补而非重复。未见合并冲突证据。

剩余阻塞项为行内两类问题:禁 IRQ 锁下的长 PMIC 轮询,以及缺失的 OPP/governor 失败路径回归覆盖。

Powered by gpt-5.6-terra

warn!("pmic_i2c: {target_uv} uV is not an exact VSEL step; refusing");
return false;
};
let guard = CONTROLLER.lock();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞(并发/时序):CONTROLLERSpinNoIrq,持有 guard 会关闭本地 IRQ 和抢占;但随后 set_vsel_verify 的写、读及逐级转换都在 guard 内轮询。单个 wait_ipd 的预算就是 100 ms,失联 PMIC 时一次 governor 变更可长时间屏蔽时钟/调度 IRQ,逐级降压还会叠加多次。这违反锁内不做长时间阻塞/外部硬件操作的约束。请改用可睡眠的互斥,或只在短暂 IRQ-safe 临界区取得稳定控制器引用,在不持锁且不关 IRQ 的情况下轮询;同时明确与并发 PMIC 访问的串行化协议。

);
return false;
}
let guard = PMIC.lock();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞(并发/时序,同一根因):PMIC 同样是 SpinNoIrq,这里的 guard 跨过 rk806_writerk806_read。每个 SPI xfer 可轮询 20 ms,超时时一次 A55 OPP 操作会在关本地 IRQ 的状态下占用约两个传输窗口;后续 governor 会反复走该路径。请和 I2C 路径一起改成不在 SpinNoIrq guard 内等待硬件完成的设计,而不是只依赖 timeout 限制最坏延迟。

/// higher voltage — over-volted for the new (lower) clock, never
/// under-volted.
#[must_use]
fn apply_opp(cluster: Cluster, opp: Opp, going_up: bool) -> bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞(回归覆盖):这是本 PR 的核心 OPP 状态机,但 cpufreq.rs 没有任何 #[cfg(test)] 覆盖;当前实际运行的新增测试只验证 PMIC VSEL/步长/波特率常量,不能证明本次修复的事务语义。请将 SCMI 与 PMIC 边界抽成可替换接口或 mock,增加可由 cargo test 发现的测试:up/down 的调用顺序、任一步失败时不继续下一步、IDX 不提交、首次采样与阈值转换;并把启用 rk3588-cpufreq 的目标板运行配置/回归命令纳入可发现 runner。

@mai-team-app
mai-team-app Bot requested a review from ZR233 July 21, 2026 07:34
…tate machine

Blocker 1 (IRQ latency): the RK3588 PMIC I2C/SPI drivers held a `SpinNoIrq`
across the entire slow, busy-waiting hardware transaction, disabling local IRQs
for the whole PMIC poll. Switch both `pmic_i2c` and `pmic_spi` to `SpinNoPreempt`
so IRQs stay enabled during the poll while a task switch still cannot interleave
mid-transaction. Sound because the PMIC lock is never taken from an interrupt
handler: every caller runs in the boot probe (`align_rail_voltages_to_opp`) or
the sleepable `cpufreq` governor/calibration task, so an IRQ arriving
mid-transaction can never re-enter and self-deadlock.

Blocker 2 (untested state-machine fixes): extract the pure, behavior-preserving
decision logic and add host `#[cfg(test)]` unit tests.
- `apply_opp` now runs its two levers through pure `apply_step_order` +
  `run_apply_steps`: ordering (up = voltage-then-clock, down = clock-then-voltage)
  and the transactional stop-at-first-failure / commit-only-on-both-success rule
  that gates the governor's `IDX` advance. Hardware writes and their exact
  no-undervolt logs are unchanged.
- `governor_poll`'s up/down/hold/prime decision is extracted to pure
  `next_opp_idx(core_pcts, cur, ladder_len, priming)`; the stateful per-core
  LAST_BUSY loop and logging are unchanged.
- Tests cover: apply ordering + all partial-failure paths (no phantom OPP),
  governor fast-attack / one-step decay / hold / floor / priming, and the OPP
  tables staying within each rail's PMIC voltage envelope and boot-safe ring
  ceiling.
@JosephJoshua

Copy link
Copy Markdown
Contributor Author

Both blocking issues addressed in ce32bc57c:

1. PMIC polling no longer runs with IRQs disabled. pmic_i2c.rs and pmic_spi.rs now use ax_kspin::SpinNoPreempt instead of SpinNoIrq for the controller lock. This keeps local IRQs enabled during the slow I2C/SPI transaction (so IRQ latency is unaffected), while still blocking a task switch mid-transaction so the register sequence stays atomic. Verified safe: every CONTROLLER.lock()/PMIC.lock() caller is reached only from the PostKernel boot probe (align_rail_voltages_to_opp) and the sleepable governor/calibration tasks (cpufreq_governor_loop, run_opp_calibration) — no IRQ handler touches the lock and the locks are never nested, so a non-IRQ-disabling lock cannot self-deadlock.

2. Regression tests for the two state-machine fixes. Added 11 host #[cfg(test)] tests in cpufreq.rs, built on behavior-preserving pure extractions now used by the real paths:

  • apply_step_order(going_up) + run_apply_steps(...)apply_opp's lever ordering (up = voltage→clock, down = clock→voltage) and its stop-at-first-failure / commit-only-on-both-success logic. Tests pin every partial-failure path (first step fails → second skipped; second step fails; both succeed) so a failed step never records a phantom higher OPP. IDX is still committed only inside if apply_opp(...). All hardware writes and warn! messages are unchanged.
  • next_opp_idx(...) — the governor's up(fast-attack to top)/down(shed one)/hold/prime decision, with tests for each.
  • Plus invariant tests that every OPP-table voltage is within its rail's PMIC envelope and every ring is within the boot-safe ceiling.

cargo build/clippy are clean feature-off and --features rk3588-cpufreq; the tests run on CI/Linux (host cargo test can't link ax-driver here due to the pre-existing model_register! link_section Mach-O limitation, same as the existing envelope_is_675k_to_1000k_inclusive test).

On the governor-arming point: leaving it armed is deliberate — the RK806 read-back is an unfixable-in-software MISO loopback, but writes land (board-confirmed by the A55 delivering its raised frequency under load), and the A76 rail is read-back-verified and shares the same GOV_READY gate. Rationale posted in the earlier reply.

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 Orange Pi 5 Plus/RK3588 新增特性门控的 CPU DVFS:通过 SCMI、I2C/SPI PMIC 和周期性 governor 调整三组 CPU cluster 的 OPP,并接入 PMU cycle counter、StarryOS early-init 与 axtask busy-tick 统计。它是新增的板级/硬件能力,按 feature-development.md 属于高风险功能:运行时会改变电压、时钟和调度路径;实现放在驱动层、循环放在 kernel task 以保持依赖方向,这一点本身合理,但 PMIC 状态转换必须以硬件可确认的结果为准。

本次仅剩一个阻塞问题,见行内评论:A55 的 RK806 路径已知无法读回真实 VSEL,却仍把 SPI 传输完成当作真实电压已到位并允许动态升频。这使软件可能提交一个未真正达到目标电压的 OPP,存在欠压风险。请在获得可信写后确认前停用 A55 的动态 OPP,或把 readiness 拆到 cluster 级以保留已通过 I2C 读回验证的 A76 DVFS。

检查清单:已阅读基线 code-quality.mdfeature-development.md、平台/驱动规则;Starry syscall ABI 准则不适用(未改变用户可见 syscall/Linux ABI 语义)。已检查基线未有等价 cpufreq 实现、无 [patch.crates-io] 覆盖。关联 PR #1658 明确依赖本 PR、提供 board harness,属于后续/互补而非重复,不能替代本 PR 的安全证明。MAINTAINERS.md 的 drivers/axcpu 路径和 aarch64/driver 关键字匹配 ZR233,建议在修复后由该领域审阅者复核。

既有技术评论已复核:非 AArch64 host 的 mrs 编译问题已由 cfg stub 修复;OPP 的已报告 PMIC/SCMI 失败现在使用停止于首个失败的顺序操作且仅在两步成功后提交;长 PMIC 轮询已从 SpinNoIrq 改为 SpinNoPreempt,不再关闭本地 IRQ。它们均不解决当前已知的 A55 写入不可观测问题。

CI:当前 head 的 65 个 check-runs 均已结束,33 success、32 skipped、0 failure;skip 与互斥 host/container、路径/发布矩阵相符,未见 PR 引起的失败。按本轮指示,CI 已覆盖通过时未重复运行完整本地 Cargo 套件;本地完成 helper 自检与 prepare-review、HEAD/工作树确认、git diff --check 和 F-001 右侧 diff 行验证,均通过。未进行真实 OrangePi 运行;这不能替代对危险电压状态转换的可观测确认。

除该阻塞项外,剩余风险是实际板级 PMIC/OPP 转换仍需可复现的目标板回归覆盖。

Powered by gpt-5.6-terra

fn set_voltage(self, uv: u32) -> bool {
use super::{pmic_i2c, pmic_spi};
match self {
Cluster::A55 => pmic_spi::force_write_dcdc2(uv),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞(硬件状态机/欠压风险):这里把 force_write_dcdc2true 当作 A55 电压已到位,但该函数只表示 SPI 控制器传输完成;同一文件已说明 RK806 MISO 读回是回环伪值,无法确认 PMIC 接收并应用了 VSEL。于是 apply_opp 会在未观测到真实电压的情况下继续提高 SCMI 时钟并提交 IDX:只要 MOSI/PMIC 侧写入未生效而 SPI 事务仍成功,就会形成“高频 + 旧低电压”的欠压窗口。事务顺序只能处理已报告的 SPI 错误,不能覆盖这个已知不可观测的失败模式。请在获得可信的 RK806 写后确认前不要为 A55 启用动态 OPP;可将 readiness 拆到 cluster 级,保持经 I2C 读回验证的 A76 governor 可用,同时将 A55 固定在保守 OPP。

… writes

The RK806 DCDC2 rail (A55) accepts writes (rail-alignment freq drops confirm)
but its SPI read is a hardware scope-wall — MISO never feeds the shift register,
so a dynamic voltage write cannot be read back to confirm the rail reached
target. Per review, scaling the A55 voltage on such an unconfirmable write risks
committing an OPP whose rail never arrived (undervolt).

Cluster-split the readiness: the A76 rails read back over I2C and keep the full
voltage lever; the A55 cluster forgoes it. A55 is pinned to the boot-confirmed
675 mV rail and scales only its SCMI PVTPLL ring (408/816/1008 MHz). 675 mV
over-volts every ring <= 1008 (board-measured to deliver 1008 exactly), so no
A55 rung can undervolt regardless of what the unconfirmable SPI write did.

- Truncate A55_OPPS to the three 675 mV ring-only rungs (drop the voltage-scaled
  1212-1523 MHz rungs). The canonical A55 voltages (mainline rk3588-opp.dtsi
  cluster0: 1200@712.5, 1416@762.5, 1608@850, 1800@950; ceiling 950 mV) are
  Linux-rated but still need a trusted RK806 write-back before we drive them.
- Add Cluster::voltage_managed(); apply_opp treats the voltage step as a
  confirmed no-op for ring-only clusters, so the ordered/transactional apply is
  unchanged but issues no dynamic A55 SPI write.
- Lock the invariant with a host test (a55_ladder_is_ring_only_on_the_boot_rail).

33 host tests pass; fmt + clippy clean.
@JosephJoshua

Copy link
Copy Markdown
Contributor Author

A55 欠压阻塞项已修复 (cluster-split,commit 555b6ba1a)

采纳建议,按 cluster 级拆分 readiness,移除 A55 的动态电压写(其 RK806 读回是硬件 scope-wall,无法确认写是否落地):

  • A55 = ring-only:固定在 boot 已确认的 675 mV 轨上,只调 SCMI PVTPLL ring(408/816/1008 MHz)。675 mV 对任何 ≤1008 的 ring 都是过压(板测 675 mV 恰好交付 1008),因此无论那个不可确认的 SPI 写实际做了什么,A55 都不可能欠压。governor 对 A55 不再发任何动态电压写
  • A76 保留完整电压杠杆:其 RK8602/RK8603 走 I2C,写后可读回确认,维持已验证的动态 DVFS。
  • 实现:新增 Cluster::voltage_managed()apply_opp 对 ring-only cluster 把电压步当作已确认的 no-op,保持原有的有序/事务化 apply 逻辑不变,但不产生不可确认的 A55 写。
  • 新增 host 测试 a55_ladder_is_ring_only_on_the_boot_rail 锁定该不变量。33 个 host 测试全过,fmt + clippy 干净。

被移除的 A55 电压档(1200@712.5 / 1416@762.5 / 1608@850 / 1800@950,源自 mainline rk3588-opp.dtsi cluster0,上限 950 mV)都是 Linux 额定目标,问题从来不是目标电压不对,而是无法运行时确认 A55 轨到位。待 RK806 读回(示波器级 MISO 修复)或交付频率 oracle 能确认写落地后,可再恢复这些档。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 RK3588/Orange Pi 5 Plus 增加特性门控的 CPU DVFS:通过 SCMI、I2C PMIC 和定时 governor 管理三组 CPU cluster 的 OPP;同时接入 PMU 计数器及 axtask 的忙碌 tick 统计。实现把慢速的 SCMI/PMIC 操作放在可睡眠内核任务中,并将 A55 拆为固定 675 mV 的 ring-only 梯子,避免对不可可靠读回的 SPI rail 进行动态调压。该 feature 默认关闭,但启用后会影响启动期频率、调度计数和运行期硬件安全状态,因此不是完全隔离的改动。

发现 1 个阻塞性硬件安全问题,详见行内评论:动态 OPP 切换把 SCMI 设置请求成功当作实际时钟已切换,未读回验证;降档随后降低电压时可能形成高频低压状态。

功能开发准则适用:这是新增平台/硬件能力,属高风险功能。PR 描述给出了板级问题、目标和 OPP/PMIC 方案;当前 base 中未见等价 RK3588 DVFS,相关开放 PR #1658 明确依赖本 PR、只补充 sysbench 板级验证,因而不是重复实现。现有 ax-driver/内核依赖方向也解释了为何 governor loop 位于 Starry kernel。仍需补齐上述实际时钟确认,才能证明状态机的安全不变量。

验证结果:git diff --checkcargo fmt --checkcargo test -p ax-driver --features rk3588-cpufreq --lib(33 passed)及 cargo clippy -p ax-driver --features rk3588-cpufreq --lib -- -D warnings 均通过。当前 HEAD 的 GitHub check-runs 均已结束,未观察到失败项;跳过的矩阵项未作为本 PR 的运行期 DVFS 证据。没有可用的目标板,因此未把宿主单测替代为板级 PMIC/SCMI 验证。

历史技术意见已复核:先前关于非 AArch64 host inline asm、PMIC 事务性更新、轮询锁 IRQ 延迟以及 A55 不可靠读回的意见,当前 head 分别通过 target cfg/stub、失败不提交索引、SpinNoPreempt 和 A55 ring-only 设计处理;本次发现仍独立存在。除行内问题外,剩余风险是需要在实际 RK3588 板上覆盖并观察动态 OPP 的读回和失败路径。维护者路由已匹配 drivers/axcpu/aarch64,ZR233 已在请求列表中,未修改 reviewer 元数据。

Powered by gpt-5.6-terra

false
}
ApplyStep::Clock => {
if scmi::set_clock_rate(phandle, cluster.clock_id(), hz).is_some() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞(正确性/硬件安全):这里仅以 SCMI CLOCK_RATE_SET 返回成功作为时钟已切换的依据,却没有读回确认实际频率。启动阶段的 set_and_verify 已处理了这一点;动态路径也必须同样验证。固件可以接受请求但因离散 OPP、限频或策略实际应用另一个 rate。尤其在降档时,代码随后会降低电压并提交 IDX;如果实际 rate 仍高于 hz,就会把 CPU 置于高频低压状态,破坏本 PR 的欠压安全不变量。请在成功设置后读回并确认精确目标(同时拒绝高于目标/上限的值),并且只在验证通过后继续电压步骤和提交软件 OPP 索引。

…transition

A CLOCK_RATE_SET ack from SCMI is not proof the PVTPLL ring actually switched.
governor_poll's apply_opp treated `set_clock_rate(...).is_some()` as a confirmed
switch, so on a downshift (clock-then-voltage) it could go on to lower the rail
while the clock was still high — the freq-high/voltage-low window the apply
ordering exists to prevent.

Confirm the clock like the boot `set_and_verify` already does: after the SET,
read the rate back with `scmi::clock_rate` and require it to equal the request;
only then is the clock step successful. Because the step is transactional and
stops on failure, a downshift now reaches its voltage-lower step only once the
clock is verified already lowered, and an unconfirmed clock leaves the rail
untouched (over-volted for the old clock, never under-volted). Updated the
apply_opp no-undervolt doc to state each step is read-back-confirmed.

33 host tests pass; fmt + clippy -D warnings clean.
@JosephJoshua

Copy link
Copy Markdown
Contributor Author

SCMI 时钟读回确认已补齐 (commit 414672ac0)

采纳行内意见:apply_opp 的时钟步之前把 set_clock_rate(...).is_some()(SET ack)当作时钟已切换,未读回验证 → 降档时可能在时钟仍高的情况下降压,形成高频/低压窗口。

修复:像启动期的 set_and_verify 一样,SET 之后用 scmi::clock_rate() 读回实际速率并要求等于请求值,读回不符即时钟步失败。由于 apply 是事务化、失败即停:

  • 降档(时钟→电压):只有在时钟被读回确认已降后才会执行降压步,因此不可能在高时钟下降压。
  • 升档(电压→时钟):时钟未确认则不提交 IDX,电压已升 = 对旧的低时钟过压,安全。

已更新 apply_opp 的 no-undervolt 文档说明“每一步都是读回确认而非仅请求”。33 host 测试通过,fmt + clippy -D warnings 干净。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 RK3588/Orange Pi 5 Plus 新增 feature-gated 的 CPU DVFS:通过 SCMI、PMIC 和周期 governor 调整 CPU cluster OPP,并补充 PMU 周期计数、axtask busy-tick 统计及 StarryOS 的 governor/calibration 任务。它新增板级能力及公开 feature;feature-development.md 适用,按功能性质属于高风险硬件/时钟电压路径。未改变 Starry 用户可见 syscall/Linux ABI,因此 syscall 专项指南不适用。

现有 Starry/ArceOS 的默认与 Orange Pi 配置不会受 feature-off stub 影响;但启用 feature 后涉及 CPU 频率/电压、调度统计和早期初始化,不能视为已隔离。唯一阻塞项见行内评论:功能尚未被接入任何目标板构建、测试或文档入口,CI 只验证了 feature-off 路径,无法作为板级能力已交付的证据。

验证:当前 HEAD 414672ac047392c9a721a8d0e7ffef6c494db92f 的组织 CI 共 59 个 check-runs,30 success、29 skipped、无失败;跳过项符合矩阵/路径选择,未见 PR 相关失败。本地运行 cargo fmt --check 通过,并确认 git diff --check origin/dev...HEAD 通过。依照本次 CI 已完成的要求,没有重复执行广泛的本地 cargo 测试;但已核实所有现有 Orange Pi 构建配置均未启用新增 feature,故远端通过不能覆盖此功能。

已审阅历史意见:此前关于宿主 asm、PMIC/SCMI 事务确认以及锁 IRQ 延迟的合理问题在当前 HEAD 已有相应修改;PR 讨论已说明 A55 改为 ring-only。仍缺少本 PR 自身的可执行交付路径。重复/重叠分析:#1658 是明确依赖本 PR 的 companion stack,不是重复实现,但不能替代本 PR 的独立配置、运行及回归证据。

请先接入受控的 Orange Pi 构建/测试入口,给出可复现的启用命令及可观察的 governor/OPP 验证,再请求复审。

Powered by gpt-5.6-terra

]
# RK3588 fixed-OPP-at-boot CPU DVFS (voltage-free rung): raises the CPU cluster
# clocks via the SCMI seam at probe time. Board-only policy; keep it opt-in.
rk3588-cpufreq = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞(交付/测试覆盖):这里定义的 rk3588-cpufreq 没有被本 PR 接入任何 Orange Pi 5 Plus 构建配置、app/test wrapper 或文档命令。当前 os/StarryOS/configs/board/orangepi-5-plus.toml 仍未启用它,仓库搜索也只有本 PR 的定义和实现;因此所有现有构建都会走 feature-off stub,新增 governor 不会被编译、注册或运行。作为新增板级能力,需要在同一交付中提供实际消费者及可复现的目标板构建/运行证据(或明确且可执行地声明依赖 PR 和合入顺序);请把 feature 接入受控的板级配置/测试并验证可观察的 OPP/governor 行为。

…ocument it

Per review, the DVFS feature was never enabled in any board build/test/doc entry
so CI only exercised the feature-off stub path. Enable it in the Orange Pi 5 Plus
board config alongside the other default-on RK3588 hardware features (rknpu,
rk3588-pwm), so the existing `Test starry self-hosted board orangepi-5-plus`
entry builds and runs the governor on real hardware. It is fail-safe: if a PMIC
bus does not come up, GOV_READY stays false and each cluster is left on its boot
OPP.

Add docs/rk3588-cpufreq.md with the reproducible enable command (`cargo xtask
starry test board --board orangepi-5-plus`) and the observable governor/OPP
verification: the boot arming log, per-cluster `gov:` OPP transitions, and
cpuprobe `mhz_pmc` under load.
@JosephJoshua

Copy link
Copy Markdown
Contributor Author

rk3588-cpufreq 已接入 Orange Pi 板级构建入口 + 文档 (commit 406c1ee45)

采纳意见:之前该 feature 从未在任何板级构建/测试/文档入口启用,CI 只跑了 feature-off stub。现在:

  • 板级构建入口:在 os/StarryOS/configs/board/orangepi-5-plus.toml 的 features 中加入 ax-driver/rk3588-cpufreq(与已有的默认开启 RK3588 硬件特性 rknpu/rk3588-pwm 一致),因此现有的 Test starry self-hosted board orangepi-5-plus 入口(cargo xtask starry test board --board orangepi-5-plus)会实际以 feature-on 构建并在真实板上运行 governor。fail-safe:任一 PMIC 总线未起则 GOV_READY=false,每个 cluster 停在 boot OPP,不做任何调节。
  • 可复现启用命令 + 可观察验证:新增 docs/rk3588-cpufreq.md,给出启用命令与可观察证据——boot 期的 cpufreq: ondemand governor armed / rail 对齐日志、负载下的 per-cluster gov: A76b0 ... opp i->j = mhz MHz @ mv mV 转换、以及 cpuprobemhz_pmc(PMU cycle counter 已在 boot 启用,精确读频)。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 RK3588/Orange Pi 5 Plus 新增 feature-gated CPU DVFS:以 SCMI、I2C/SPI PMIC 和周期 governor 调整三组 CPU cluster OPP,并增加 PMU cycle counter、axtask busy-tick 统计与 StarryOS governor/calibration 任务。feature-development.md 适用;这是高风险的板级时钟/电压能力。它不改变 StarryOS syscall/Linux ABI,故 syscall 专项指南不适用。

默认 feature-off 路径保持 no-op;Orange Pi 配置启用该 feature 后,影响 CPU 电压/频率、调度统计与早期初始化,不能视为完全隔离。此前关于宿主 AArch64 asm、A55 不可验证电压写、SCMI read-back 与 IRQ 关闭延迟的意见已在当前 HEAD 中处理:A55 已改为固定 675 mV 的 ring-only 档位,动态 A76 OPP 同时确认 PMIC/SCMI 状态。但仍有一个阻塞的 PMIC 超时调度问题,见行内评论。

验证:当前 HEAD 的组织 CI 共 59 个 check-runs,30 success、29 skipped、无 failure;跳过项为预期矩阵/路径选择,未见 PR 相关 CI 失败。已运行 prepare-review 核验固定 HEAD、git diff --check origin/dev...HEAD(通过)、检查无 crates.io patch,并核对当前 feature 配置与新增状态机测试。按本次 CI 已通过的要求,未重复执行广泛本地 Cargo 测试;目标板运行在本环境不可用,仍建议修复后以文档中的 Orange Pi 命令补充 PMIC timeout/调度行为证据。

已审阅既有意见和 PR 讨论:先前阻塞项均有当前实现或测试对应;Copilot 仅为额度提示。重复/重叠分析中,#1658 明确 stack 在本 PR 之上,是互补的板级 benchmark,不是重复实现,也不能替代本 PR 的安全验证。除行内问题外,已知剩余风险是板级 PMIC 故障路径应继续有可重复的运行覆盖。

Powered by gpt-5.6-terra

@JosephJoshua

Copy link
Copy Markdown
Contributor Author

说明:feature 已接入 Orange Pi 板级配置(行内评论似为 stale)

行内评论说 orangepi-5-plus.toml 仍未启用该 feature,但在本次复审所固定的 HEAD 406c1ee45 上它已经启用

  • os/StarryOS/configs/board/orangepi-5-plus.toml:13 = "ax-driver/rk3588-cpufreq"(与默认开启的 rknpu / rk3588-pwm 并列)。因此 Test starry self-hosted board orangepi-5-pluscargo xtask starry test board --board orangepi-5-plus)会以 feature-on 构建并在真实板上运行 governor。
  • docs/rk3588-cpufreq.md 给出可复现启用命令 + 可观察验证(boot arming 日志、per-cluster gov: OPP 转换、cpuprobe mhz_pmc)。

本次 review 的摘要部分也确认了“Orange Pi 配置启用该 feature”,与行内评论矛盾。请基于 406c1ee45 复核该行;如仍有具体缺口请指出。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 为 Orange Pi 5 Plus / RK3588 增加 feature-gated 的 CPU DVFS:通过 SCMI 和 PMIC 调整三个 CPU cluster 的 OPP,新增 PMU cycle counter、axtask busy-tick 统计、内核 governor task 及说明文档。它是新增板级能力,feature-development.md 适用;按风险属于硬件/电压/频率状态机的高风险共享能力。实现把慢速 SCMI/PMIC 操作放在可睡眠任务中、A76 采用 I2C 回读确认、A55 保持 ring-only,整体不会改变 Starry 用户态 syscall/Linux ABI,因此 syscall 指南不适用。

发现 1 个阻塞项,见行内评论:文档指定的标准 board 命令实际使用 test-suit 下独立的 build wrapper,而不是本 PR 修改的正式 board config。该 wrapper 没有 ax-driver/rk3588-cpufreq 且为单核,故当前通过的 board CI 并未构建、启动或观察 governor,不能作为新功能的运行时验证。请修正真实 runner 配置/继承关系,并增加可观察 governor arm 与 OPP transition 的 board case 后在当前 HEAD 验证。

验证与 CI:本地 helper 已确认工作区 HEAD 为 406c1ee45e0af276e10514cd701d47d486459faegit diff --check origin/dev...HEAD 通过。远端该 HEAD 的 59 个 check-runs 已完成,30 个 success、29 个 expected skipped、无 failure;已通过的 OrangePi board job 不覆盖本 PR feature,原因如上。尝试运行 xtask 帮助以复核命令时环境需首次下载 nightly/依赖并超时,未将此环境限制当作功能验证;在 CI 已通过的普通构建检查外未重复广泛本地测试。

已复核历史 review/讨论:此前关于非 AArch64 mrs、OPP partial-failure 提交、A55 不可确认动态电压写及 PMIC 锁 IRQ 延迟的合理意见已由当前 HEAD 的 cfg stub、事务化 apply、A55 ring-only 和 SpinNoPreempt 修改处理。当前仍未解决的是实际 board runner/覆盖问题。PR/issue 评论无其他待处理技术线程。重复/重叠分析表明 #1658 明确 stack 在本 PR 之上,是补充性 board benchmark 而非重复实现,不能替代本 PR 自身的可发现回归验证。

除上述阻塞项外,硬件 PMIC/OPP 状态机的残余风险应由启用 feature 的目标板运行时测试覆盖。

Powered by gpt-5.6-terra

Comment thread docs/rk3588-cpufreq.md

The feature is wired into the Orange Pi 5 Plus board config
(`os/StarryOS/configs/board/orangepi-5-plus.toml`), so the standard board
build/test entry enables it:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

阻塞|验证路径没有实际启用 DVFS。 此处所写的 cargo xtask starry test board --board orangepi-5-plus 并不读取本 PR 修改的 os/StarryOS/configs/board/orangepi-5-plus.toml;board runner 使用的是 test-suit/starryos/board-orangepi-5-plus/build-aarch64-unknown-none-softfloat.toml。后者仍未包含 ax-driver/rk3588-cpufreq,且 max_cpu_num=1,因此已通过的 board CI 实际没有编译/启动 governor,更不可能覆盖三 cluster 的 OPP 切换。请将 feature 和正确的 CPU 配置接入实际 build wrapper(或让 runner 继承正式 board config),增加能确认 governor arm 和至少一次 OPP transition 的 board case,并在当前 HEAD 上运行;否则文档中的验证承诺和本功能的回归覆盖均不成立。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants