Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions components/axcpu/src/aarch64/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ pub fn init_trap() {
#[cfg(feature = "uspace")]
{
CNTKCTL_EL1.modify(CNTKCTL_EL1::EL0VCTEN::TrappedNone + CNTKCTL_EL1::EL0PCTEN::TrappedNone);
// Start this CPU's free-running PMU cycle counter and let EL0 read it, so
// `PMCCNTR_EL0` yields real cycle counts at both EL1 and EL0. This is the
// exact-frequency oracle the DVFS calibration reads in-kernel and that
// `cpuprobe`'s `mhz_pmc` reads from userspace (both were 0/trapping before,
// because these registers were only ever set on the lazy perf_event_open
// path). Guarded on PMUv3 being present; a live system-wide `perf stat -e
// cycles` may momentarily reset/disable this shared counter, which is fine
// for a boot/idle calibration.
if crate::pmu::probe().is_some() {
crate::pmu::init_cpu();
crate::pmu::cycles::configure(false, false);
crate::pmu::cycles::enable();
}
barrier::isb(barrier::SY);
}
unsafe extern "C" {
Expand Down
62 changes: 62 additions & 0 deletions docs/rk3588-cpufreq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# RK3588 CPU DVFS (cpufreq)

Feature-gated ondemand CPU frequency/voltage scaling for the Orange Pi 5 Plus
(RK3588). It is off by default in the generic and QEMU builds — the
`ax-driver/rk3588-cpufreq` feature compiles the driver to no-ops there — and is
enabled on the Orange Pi board build.

## What it does

The RK3588 CPU clock is a voltage-coupled PVTPLL. An **ondemand** governor scales
each of the three CPU clusters (A55 little `cpu0-3`, two A76 big pairs `cpu4-5` /
`cpu6-7`) between OPPs by pairing an SCMI PVTPLL ring target with a PMIC rail
voltage:

- **A76** uses the full voltage lever — its RK8602/RK8603 rails read back over I2C,
so every voltage write is confirmed and the SCMI clock rate is read back before an
OPP is committed.
- **A55** is **ring-only**: its RK806 rail cannot be read back (a MISO hardware
limit), so it stays on the boot-confirmed 675 mV rail and scales only its SCMI
ring. 675 mV over-volts every A55 ring ≤ 1008 MHz, so it can never undervolt.

It is **fail-safe**: if either PMIC bus does not come up at boot, `GOV_READY` stays
`false` and every cluster is left on its boot OPP (no scaling).

## Enable and build

The feature is enabled in both Orange Pi 5 Plus build configs:

- `test-suit/starryos/board-orangepi-5-plus/build-aarch64-unknown-none-softfloat.toml`
— the config the **board CI runner** actually builds, so the standard board
test entry compiles, boots and runs the governor on real hardware:

```bash
cargo xtask starry test board --board orangepi-5-plus
```

Every case there boots this kernel; a governor-induced boot panic/hang trips the
cases' `panic` fail-regex, so the board CI regression-guards the feature.
- `os/StarryOS/configs/board/orangepi-5-plus.toml` — the general board build
template (for a full-board `max_cpu_num` build outside CI).

To enable it in a custom build, add `"ax-driver/rk3588-cpufreq"` to that config's
`features` list.

## Observable verification

At boot (early init, before the console handoff) the driver logs the rail bring-up
and governor arming to the serial console:

```
cpufreq: A55 rail boot voltage = <uV> uV
cpufreq: A55 <before>-><after>, A76 <before>-><after> MHz
cpufreq: ondemand governor armed (both PMIC buses up)
```

Under load, per-cluster OPP transitions are logged
(`gov: A76b0 peak=<n>% opp <i>-><j> = <mhz> MHz @ <mv> mV`), and the delivered
frequency can be read exactly with `cpuprobe`'s `mhz_pmc` (the PMU cycle counter is
enabled at boot): a busy cluster climbs toward its top OPP, an idle cluster sheds
back down one step at a time. The companion `apps/starry/sysbench-board` harness
(PR #1658) drives an all-core load and captures these numbers against a Linux
baseline.
6 changes: 6 additions & 0 deletions drivers/ax-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ rockchip-soc = [
"dep:rdif-reset",
"dep:rockchip-soc",
]
# 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 的常规测试路径。

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 的常规测试路径。

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 行为。

"rockchip-soc",
"dep:arm-scmi-rs",
]
rockchip-pm = ["rockchip-soc", "dep:rdif-power", "dep:rockchip-pm"]
list-pci-devices = ["pci"]
pci-list-devices = ["list-pci-devices"]
Expand Down
38 changes: 38 additions & 0 deletions drivers/ax-driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,44 @@ pub mod usb;
#[cfg(virtio_dev)]
pub mod virtio;

/// RK3588 CPU DVFS ondemand governor, exposed as a stable, arch-neutral entry
/// the kernel can drive from a periodic task without knowing the SoC specifics.
///
/// The governor's *policy + apply* live in the (arch-specific) cpufreq driver,
/// but its *loop* — sleeping between samples and reading the per-CPU busy
/// counters — cannot live in this crate: ax-driver sits below ax-task/ax-hal in
/// the dependency graph, so spawning a task here would be a cyclic dependency.
/// The kernel therefore owns the loop and calls [`cpufreq::governor_poll`] each
/// tick. When the DVFS feature is off these are no-ops so callers stay generic.
pub mod cpufreq {
#[cfg(feature = "rk3588-cpufreq")]
pub use crate::soc::rockchip::cpufreq::{
calibrate_cluster, calibrate_wanted, governor_period_ms, governor_poll, governor_wanted,
};

/// Feature-off stub: no governor, so the kernel never spawns its task.
#[cfg(not(feature = "rk3588-cpufreq"))]
pub fn governor_wanted() -> bool {
false
}
/// Feature-off stub.
#[cfg(not(feature = "rk3588-cpufreq"))]
pub fn governor_period_ms() -> u64 {
100
}
/// Feature-off stub.
#[cfg(not(feature = "rk3588-cpufreq"))]
pub fn governor_poll(_busy: &[u64]) {}
/// Feature-off stub: no calibration.
#[cfg(not(feature = "rk3588-cpufreq"))]
pub fn calibrate_wanted() -> bool {
false
}
/// Feature-off stub.
#[cfg(not(feature = "rk3588-cpufreq"))]
pub fn calibrate_cluster(_cluster_idx: usize, _intended_cpu: usize) {}
}

#[cfg(feature = "pci")]
pub use binding_info::PciIrqRequirement;
pub use binding_info::{BindingInfo, BindingIrq, BindingIrqBinding, BindingIrqSource, FdtIrqSpec};
Expand Down
4 changes: 2 additions & 2 deletions drivers/ax-driver/src/soc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#[cfg(feature = "pinctrl")]
mod fixed_regulator;
#[cfg(feature = "rockchip-soc")]
mod rockchip;
#[cfg(feature = "rockchip-dwmmc")]
pub(crate) mod rockchip;
#[cfg(any(feature = "rockchip-dwmmc", feature = "rk3588-cpufreq"))]
pub mod scmi;
#[cfg(feature = "starfive-soc")]
mod starfive;
Expand Down
Loading