mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-21 02:06:14 +08:00
[dm][dvfs] support Dynamic Voltage and Frequency Scaling (DVFS)
1. Support DVFS and finsh cmd, there are 6 governors: - conservative - freedom - performance - powersave - schedutil 2. Support DVFS for SCMI. 3. Port the Cooling device for DVFS. 4. Port the PM with DVFS. Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
- @subpage page_device_disk
|
||||
- @subpage page_device_partitions
|
||||
- @subpage page_device_hwcache
|
||||
- @subpage page_device_dvfs
|
||||
- @subpage page_device_can
|
||||
- @subpage page_device_can_dm
|
||||
- @subpage page_device_clk
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
@page page_device_dvfs DVFS
|
||||
|
||||
# Dynamic Voltage and Frequency Scaling (DVFS)
|
||||
|
||||
Headers: **`components/drivers/include/drivers/dvfs.h`**. Core: **`components/drivers/dvfs/dvfs.c`**, governors: **`components/drivers/dvfs/governor/`**, shell: **`components/drivers/dvfs/dvfs_cmd.c`**.
|
||||
|
||||
DVFS selects an **OPP (Operating Performance Point)** — a frequency and supply voltage pair — according to a **governor** policy. The framework owns the OPP table, governor lifecycle, and MSH commands; **BSP or SoC drivers** implement how a given OPP is applied (clock, regulator, firmware calls).
|
||||
|
||||
**Kconfig**: **`RT_USING_DVFS`** (requires **`RT_USING_DM`**, **`RT_USING_CLK`**, **`RT_USING_REGULATOR`**). Optional: **`RT_USING_DVFS_EVENT`**, **`RT_DVFS_SCMI_CPUFREQ`**, and BSP options under **`SOC_DM_DVFS_*`**.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Device tree (operating-points-v2, supplies, clocks)
|
||||
|
|
||||
v
|
||||
BSP cpufreq / devfreq driver (SOC_DM_DVFS_CPUFREQ_DIR, …)
|
||||
fills rt_dvfs_scaling_ops (set_opp, parse_opp, …)
|
||||
|
|
||||
v
|
||||
rt_dvfs_cpufreq_register() / rt_dvfs_devfreq_register()
|
||||
|
|
||||
v
|
||||
rt_dvfs_scaling (OPP table, cur_freq, governor)
|
||||
|
|
||||
+-- governor (performance / ondemand / …)
|
||||
+-- thermal-cool-dvfs (optional, RT_THERMAL_COOL_DVFS)
|
||||
+-- rt_dvfs_scaling_set_frequency() / apply_opp()
|
||||
```
|
||||
|
||||
| Layer | Location | Role |
|
||||
| --- | --- | --- |
|
||||
| Framework | `components/drivers/dvfs/` | OPP table, governors, load stats, PM hooks, MSH |
|
||||
| Generic SCMI | `dvfs-scmi-cpufreq.c` | Optional SCMI-based CPUfreq (**`RT_DVFS_SCMI_CPUFREQ`**) |
|
||||
| BSP | **`SOC_DM_DVFS_CPUFREQ_DIR`**, **`SOC_DM_DVFS_DEVFREQ_DIR`**, **`SOC_DM_DVFS_EVENT_DIR`** | Platform probe, **`set_opp`**, DT parsing |
|
||||
| Thermal | `thermal-cool-dvfs.c` | Map cooling levels to OPP indices — @ref page_device_thermal_cool |
|
||||
|
||||
When **`RT_USING_DVFS`** is enabled, **`struct rt_device::dvfs_scaling`** links a device to its scaling domain for **`list_dvfs`** / **`dvfs dump`**.
|
||||
|
||||
---
|
||||
|
||||
## Registering a scaling domain (BSP driver)
|
||||
|
||||
Typical CPU path:
|
||||
|
||||
1. Allocate **`struct rt_dvfs_cpufreq`** (embeds **`struct rt_dvfs_scaling`**).
|
||||
2. Fill **`scaling->ops`** — at minimum **`set_opp`** and **`parse_opp`** for DT-backed OPP tables.
|
||||
3. Obtain **`scaling->clk`** and **`scaling->supply`** from the CPU / cluster device node.
|
||||
4. Parse OPP nodes ( **`operating-points-v2`** ) into the scaling OPP table.
|
||||
5. Call **`rt_dvfs_cpufreq_register()`**, then **`rt_dvfs_scaling_set_governor()`** with the desired default governor.
|
||||
|
||||
Devfreq devices follow the same pattern with **`struct rt_dvfs_devfreq`** and optional **`struct rt_dvfs_event`** for load feedback (**`RT_USING_DVFS_EVENT`**).
|
||||
|
||||
If the driver does not provide **`ops->set_opp`**, the framework falls back to a generic sequence using **`rt_clk_set_rate`** and **`rt_regulator_set_voltage`** on **`scaling->clk`** / **`scaling->supply`**.
|
||||
|
||||
---
|
||||
|
||||
## Governors
|
||||
|
||||
| Name | Behavior |
|
||||
| --- | --- |
|
||||
| **`performance`** | Always **`max_freq`** |
|
||||
| **`powersave`** | Always **`min_freq`** |
|
||||
| **`freedom`** | No automatic changes; user sets frequency manually |
|
||||
| **`ondemand`** | Periodic load sampling; high load → max, low load → scaled down |
|
||||
| **`conservative`** | Step up/down by **`freq_step`** |
|
||||
| **`schedutil`** | Target frequency proportional to estimated load |
|
||||
|
||||
Dynamic governors depend on **`RT_USING_IDLE_HOOK`** (load estimation) and **`RT_USING_SYSTEM_WORKQUEUE`** (monitor timer). The default governor is chosen by the BSP driver at registration time.
|
||||
|
||||
Governor parameters (**`up_threshold`**, **`sampling_rate_ms`**, …) live in **`struct rt_dvfs_governor_params`** and can be adjusted via **`rt_dvfs_governor_set_params()`**.
|
||||
|
||||
---
|
||||
|
||||
## MSH commands
|
||||
|
||||
Requires **`RT_USING_CONSOLE`** and **`RT_USING_MSH`** (**`dvfs_cmd.c`**).
|
||||
|
||||
```text
|
||||
list_dvfs
|
||||
dvfs dump <name>
|
||||
dvfs set_governor <name> <governor>
|
||||
dvfs set_frequency <name> <Hz>
|
||||
```
|
||||
|
||||
**`set_frequency`** switches to **`freedom`** automatically when the active governor is not freedom.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
msh />dvfs set_governor cpu0 performance
|
||||
msh />dvfs dump cpu0
|
||||
```
|
||||
|
||||
The scaling device **`<name>`** is assigned by the BSP driver (commonly **`cpufreq0`**, **`dmc`**, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Device tree (typical CPU)
|
||||
|
||||
Minimal pattern (details vary by SoC BSP):
|
||||
|
||||
```dts
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a55";
|
||||
operating-points-v2 = <&cpu0_opp_table>;
|
||||
cpu-supply = <&cpu_reg>;
|
||||
/* optional: #cooling-cells for thermal-cool-dvfs */
|
||||
};
|
||||
|
||||
cpu0_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
opp-1000000000 {
|
||||
opp-hz = /bits/ 64 <1000000000>;
|
||||
opp-microvolt = <900000>;
|
||||
};
|
||||
/* additional OPP nodes … */
|
||||
};
|
||||
```
|
||||
|
||||
| Binding | Role |
|
||||
| --- | --- |
|
||||
| **`operating-points-v2`** | OPP table phandle on the scaling device |
|
||||
| **`opp-hz` / `opp-microvolt`** | Frequency (Hz) and voltage (µV) per OPP |
|
||||
| **`*-supply`** | Regulator phandle(s) used when scaling voltage |
|
||||
| **`#cooling-cells`** | Enables **`dvfs-cool`** thermal device on the CPU node |
|
||||
|
||||
Passive thermal **`cooling-maps`** can reference the DVFS cooling device to cap OPP on trip — see @ref page_device_thermal_cool.
|
||||
|
||||
---
|
||||
|
||||
## Kconfig
|
||||
|
||||
| Option | Role |
|
||||
| --- | --- |
|
||||
| **`RT_USING_DVFS`** | Core framework + governors |
|
||||
| **`RT_USING_DVFS_EVENT`** | **`dvfs_event.c`**, devfreq load via event devices |
|
||||
| **`RT_USING_DVFS_OPP_RETRY_MAX`** | Retries on **`-RT_EBUSY`** during OPP transition |
|
||||
| **`RT_DVFS_SCMI_CPUFREQ`** | Generic **`dvfs-scmi-cpufreq.c`** |
|
||||
| **`RT_THERMAL_COOL_DVFS`** | **`thermal-cool-dvfs.c`** (also needs **`RT_USING_THERMAL`**) |
|
||||
| **`RT_USING_IDLE_HOOK`** | Required for meaningful dynamic governor load stats |
|
||||
| **`SOC_DM_DVFS_CPUFREQ_DIR`** | BSP CPUfreq driver(s) |
|
||||
| **`SOC_DM_DVFS_DEVFREQ_DIR`** | BSP devfreq driver(s) |
|
||||
| **`SOC_DM_DVFS_EVENT_DIR`** | BSP devfreq event source(s) |
|
||||
|
||||
---
|
||||
|
||||
## OPP transition order
|
||||
|
||||
When **`ops->set_opp`** is provided, the BSP defines the safe ramp sequence ( voltage-before-frequency on scale-up, etc.).
|
||||
|
||||
When the framework generic path is used (**`dvfs.c`**):
|
||||
|
||||
- **Scale up**: raise voltage (if needed) → optional **`transition_latency`** delay → **`rt_clk_set_rate`**
|
||||
- **Scale down**: lower clock rate → lower voltage (if needed)
|
||||
|
||||
On failure, **`cur_freq`** and **`current_opp`** are not updated. **`RT_USING_DVFS_OPP_RETRY_MAX`** controls busy retries on regulator or clock calls.
|
||||
|
||||
---
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- **BSP `set_opp` must match hardware**: clocks, regulators, and any bus used to change voltage must remain usable across the full OPP range. Broken I2C/SPI/regulator access during a transition surfaces as stuck frequency or **`-RT_EBUSY`** retries.
|
||||
- **Governor switch vs. pending work**: dynamic governors schedule work on the system workqueue. After **`set_governor`**, monitor callbacks must verify the active governor type before changing frequency (see governor sources).
|
||||
- **Thermal cooling levels**: **`thermal-cool-dvfs`** maps cooling **level** to an OPP index; releasing cooling must restore full performance (highest OPP), not the most restrictive level. See **`rt_thermal_cooling_device_kick`** in **`thermal.c`**.
|
||||
- **Verifying dynamic governors**: do not run a tight CPU loop inside the **FinSH / shell thread** — it usually has higher priority than the system workqueue and can prevent load sampling. Use a **separate background thread** at lower priority, or compare **`performance`** vs **`powersave`** (static governors) to confirm the scaling path works before testing **`ondemand`** / **`schedutil`**.
|
||||
|
||||
---
|
||||
|
||||
## Related pages
|
||||
|
||||
- @ref page_device_clk — **`rt_clk_set_rate`**, consumer clock API
|
||||
- @ref page_device_regulator — supply rails referenced from OPP / CPU nodes
|
||||
- @ref page_device_scmi — SCMI clock/regulator when firmware owns scaling resources
|
||||
- @ref page_device_thermal_cool — **`thermal-cool-dvfs`**
|
||||
@@ -213,7 +213,7 @@ Call **`update`** from the zone poller (automatic after register) or manually fo
|
||||
| **`thermal-scmi.c`** | **`RT_SCMI_DRIVER_EXPORT`**, protocol sensor `"thermal"` | One zone per SCMI temperature sensor |
|
||||
| **`thermal-cool-pwm-fan.c`** | **`compatible = "pwm-fan"`** | PWM + optional regulator — @ref page_device_thermal_cool |
|
||||
| **`thermal-cool-gpio-fan.c`** | GPIO + speed table | Discrete fan speeds |
|
||||
| **`thermal-cool-dvfs.c`** | DVFS OPP levels as cooling steps | Throttle CPU/GPU via @ref page_device_clk / DVFS |
|
||||
| **`thermal-cool-dvfs.c`** | DVFS OPP levels as cooling steps | Throttle CPU/GPU via @ref page_device_dvfs |
|
||||
|
||||
BSP sensors (e.g. board thermal IC) typically **`rt_thermal_zone_device_register`** in platform **`probe`** after filling trips in code or relying entirely on **`thermal_ofw_setup`**.
|
||||
|
||||
@@ -251,6 +251,7 @@ Constants: **`RT_THERMAL_TEMP_INVALID`** (−274000), **`RT_THERMAL_NO_LIMIT`**.
|
||||
## See also
|
||||
|
||||
- @ref page_device_thermal_cool — PWM fan cooling device
|
||||
- @ref page_device_dvfs — DVFS framework and Rockchip cpufreq
|
||||
- @ref page_device_scmi — SCMI sensor protocol
|
||||
- @ref page_device_pwm
|
||||
- @ref page_device_regulator
|
||||
|
||||
Reference in New Issue
Block a user