Add Steam Deck max clock detection since OC can now be reported correctly

version 2.0.0-alpha3
This commit is contained in:
NGnius (Graham) 2024-02-10 12:52:21 -05:00
parent 1a4bfb9669
commit 3e3e9a68f4
9 changed files with 536 additions and 125 deletions

2
backend/Cargo.lock generated
View file

@ -1170,7 +1170,7 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "powertools" name = "powertools"
version = "2.0.0-alpha2" version = "2.0.0-alpha3"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"chrono", "chrono",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "powertools" name = "powertools"
version = "2.0.0-alpha2" version = "2.0.0-alpha3"
edition = "2021" edition = "2021"
authors = ["NGnius (Graham) <ngniusness@gmail.com>"] authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
description = "Backend (superuser) functionality for PowerTools" description = "Backend (superuser) functionality for PowerTools"

View file

@ -77,16 +77,16 @@ impl Default for Base {
}, },
limits: super::Limits { limits: super::Limits {
cpu: super::Limit { cpu: super::Limit {
provider: super::CpuLimitType::SteamDeck, provider: super::CpuLimitType::SteamDeckOLED,
limits: super::GenericCpusLimit::default_for(super::CpuLimitType::SteamDeck), limits: super::GenericCpusLimit::default_for(super::CpuLimitType::SteamDeckOLED),
}, },
gpu: super::Limit { gpu: super::Limit {
provider: super::GpuLimitType::SteamDeck, provider: super::GpuLimitType::SteamDeckOLED,
limits: super::GenericGpuLimit::default_for(super::GpuLimitType::SteamDeckOLED), limits: super::GenericGpuLimit::default_for(super::GpuLimitType::SteamDeckOLED),
}, },
battery: super::Limit { battery: super::Limit {
provider: super::BatteryLimitType::SteamDeck, provider: super::BatteryLimitType::SteamDeckOLED,
limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::SteamDeck), limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::SteamDeckOLED),
}, },
} }
}, },

View file

@ -93,13 +93,14 @@ pub struct GenericCpuLimit {
pub tdp_divisor: Option<u64>, pub tdp_divisor: Option<u64>,
pub tdp_step: Option<u64>, pub tdp_step: Option<u64>,
pub skip_resume_reclock: bool, pub skip_resume_reclock: bool,
pub experiments: bool, pub extras: super::LimitExtras,
} }
impl GenericCpuLimit { impl GenericCpuLimit {
pub fn default_for(t: &CpuLimitType, _index: usize) -> Self { pub fn default_for(t: &CpuLimitType, _index: usize) -> Self {
match t { match t {
CpuLimitType::SteamDeck | CpuLimitType::SteamDeckOLED => Self::default_steam_deck(), CpuLimitType::SteamDeck => Self::default_steam_deck(),
CpuLimitType::SteamDeckOLED => Self::default_steam_deck_oled(),
CpuLimitType::DevMode => Self { CpuLimitType::DevMode => Self {
clock_min: Some(RangeLimit { min: Some(100), max: Some(5000) }), clock_min: Some(RangeLimit { min: Some(100), max: Some(5000) }),
clock_max: Some(RangeLimit { min: Some(100), max: Some(4800) }), clock_max: Some(RangeLimit { min: Some(100), max: Some(4800) }),
@ -109,7 +110,7 @@ impl GenericCpuLimit {
tdp_divisor: Some(1_000_000), tdp_divisor: Some(1_000_000),
tdp_step: Some(1), tdp_step: Some(1),
skip_resume_reclock: false, skip_resume_reclock: false,
experiments: true, extras: Default::default(),
}, },
_ => Self { _ => Self {
clock_min: None, clock_min: None,
@ -120,7 +121,7 @@ impl GenericCpuLimit {
tdp_divisor: None, tdp_divisor: None,
tdp_step: None, tdp_step: None,
skip_resume_reclock: false, skip_resume_reclock: false,
experiments: false, extras: Default::default(),
}, },
} }
} }
@ -141,7 +142,32 @@ impl GenericCpuLimit {
tdp_divisor: None, tdp_divisor: None,
tdp_step: None, tdp_step: None,
skip_resume_reclock: false, skip_resume_reclock: false,
extras: Default::default(),
}
}
fn default_steam_deck_oled() -> Self {
Self {
clock_min: Some(RangeLimit {
min: Some(1400),
max: Some(3500),
}),
clock_max: Some(RangeLimit {
min: Some(400),
max: Some(3500),
}),
clock_step: Some(100),
tdp: None,
tdp_boost: None,
tdp_divisor: None,
tdp_step: None,
skip_resume_reclock: false,
extras: super::LimitExtras {
experiments: false, experiments: false,
quirks: vec![
"clock-autodetect".to_owned(),
].into_iter().collect()
},
} }
} }
@ -165,6 +191,6 @@ impl GenericCpuLimit {
} }
self.clock_step = limit_override.clock_step; self.clock_step = limit_override.clock_step;
self.skip_resume_reclock = limit_override.skip_resume_reclock; self.skip_resume_reclock = limit_override.skip_resume_reclock;
self.experiments = limit_override.experiments; self.extras = limit_override.extras;
} }
} }

View file

@ -93,6 +93,7 @@ impl GenericGpuLimit {
fn default_steam_deck_oled() -> Self { fn default_steam_deck_oled() -> Self {
let mut sd = Self::default_steam_deck(); let mut sd = Self::default_steam_deck();
sd.memory_clock_step = Some(200); sd.memory_clock_step = Some(200);
sd.extras.quirks.insert("clock-autodetect".to_owned());
sd sd
} }

File diff suppressed because it is too large Load diff

View file

@ -102,6 +102,9 @@ impl Cpus {
pub fn variant(mut self, model: super::Model) -> Self { pub fn variant(mut self, model: super::Model) -> Self {
self.variant = model; self.variant = model;
for cpu in self.cpus.iter_mut() {
cpu.variant(model)
}
self self
} }
} }
@ -125,7 +128,12 @@ impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
} }
} }
let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) { let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) {
Cpu::from_json_and_limits(cpu, version, i, cpu_limit.to_owned()) let mut cpu_limit_clone = cpu_limit.to_owned();
for item in &limits.extras.quirks {
cpu_limit_clone.extras.quirks.insert(item.to_owned());
}
cpu_limit_clone.extras.experiments |= limits.extras.experiments;
Cpu::from_json_and_limits(cpu, version, i, cpu_limit_clone)
} else { } else {
Cpu::from_json(cpu, version, i) Cpu::from_json(cpu, version, i)
}; };
@ -262,6 +270,7 @@ pub struct Cpu {
index: usize, index: usize,
state: crate::state::steam_deck::Cpu, state: crate::state::steam_deck::Cpu,
sysfs: BasicEntityPath, sysfs: BasicEntityPath,
variant: super::Model,
} }
//const CPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage"; //const CPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
@ -289,6 +298,7 @@ impl Cpu {
index: i, index: i,
state: crate::state::steam_deck::Cpu::default(), state: crate::state::steam_deck::Cpu::default(),
sysfs: Self::find_card_sysfs(other.root), sysfs: Self::find_card_sysfs(other.root),
variant: super::Model::LCD,
}, },
_ => Self { _ => Self {
online: other.online, online: other.online,
@ -298,6 +308,7 @@ impl Cpu {
index: i, index: i,
state: crate::state::steam_deck::Cpu::default(), state: crate::state::steam_deck::Cpu::default(),
sysfs: Self::find_card_sysfs(other.root), sysfs: Self::find_card_sysfs(other.root),
variant: super::Model::LCD,
}, },
} }
} }
@ -341,6 +352,19 @@ impl Cpu {
} }
} }
fn read_max_cpu_clock(&self) -> u64 {
if !(self.limits.extras.experiments || self.limits.extras.quirks.contains("clock-autodetect")) {
return MAX_CLOCK;
}
if let super::Model::OLED = self.variant {
if let Ok(freq_khz) = usdpl_back::api::files::read_single::<_, u64, _>(cpu_max_clock_path(self.index)) {
log::debug!("Detected CPU max clock of {}KHz", freq_khz);
return freq_khz / 1000
}
}
MAX_CLOCK
}
fn set_clock_limit( fn set_clock_limit(
&self, &self,
index: usize, index: usize,
@ -591,6 +615,7 @@ impl Cpu {
index: cpu_index, index: cpu_index,
state: crate::state::steam_deck::Cpu::default(), state: crate::state::steam_deck::Cpu::default(),
sysfs: Self::find_card_sysfs(None::<&'static str>), sysfs: Self::find_card_sysfs(None::<&'static str>),
variant: super::Model::LCD,
} }
} }
@ -602,14 +627,15 @@ impl Cpu {
} }
fn limits(&self) -> crate::api::CpuLimits { fn limits(&self) -> crate::api::CpuLimits {
let max_cpu_clock = self.read_max_cpu_clock();
crate::api::CpuLimits { crate::api::CpuLimits {
clock_min_limits: Some(RangeLimit { clock_min_limits: Some(RangeLimit {
min: range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), // allows min to be set by max (it's weird, blame the kernel) min: range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), // allows min to be set by max (it's weird, blame the kernel)
max: range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK), max: range_max_or_fallback(&self.limits.clock_min, max_cpu_clock),
}), }),
clock_max_limits: Some(RangeLimit { clock_max_limits: Some(RangeLimit {
min: range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), min: range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK),
max: range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), max: range_max_or_fallback(&self.limits.clock_max, max_cpu_clock),
}), }),
clock_step: self.limits.clock_step.unwrap_or(CLOCK_STEP), clock_step: self.limits.clock_step.unwrap_or(CLOCK_STEP),
governors: self.governors(), governors: self.governors(),
@ -628,6 +654,10 @@ impl Cpu {
}; };
gov_str.split(' ').map(|s| s.to_owned()).collect() gov_str.split(' ').map(|s| s.to_owned()).collect()
} }
pub fn variant(&mut self, model: super::Model) {
self.variant = model;
}
} }
impl Into<CpuJson> for Cpu { impl Into<CpuJson> for Cpu {
@ -714,3 +744,8 @@ fn cpu_available_governors_path(index: usize) -> String {
index index
) )
} }
#[inline]
fn cpu_max_clock_path(index: usize) -> String {
format!("/sys/devices/system/cpu/cpufreq/policy{}/cpuinfo_max_freq", index)
}

View file

@ -37,6 +37,7 @@ pub struct Gpu {
const GPU_CLOCK_LIMITS_ATTRIBUTE: &str = "device/pp_od_clk_voltage"; const GPU_CLOCK_LIMITS_ATTRIBUTE: &str = "device/pp_od_clk_voltage";
const GPU_MEMORY_DOWNCLOCK_ATTRIBUTE: &str = "device/pp_dpm_fclk"; const GPU_MEMORY_DOWNCLOCK_ATTRIBUTE: &str = "device/pp_dpm_fclk";
const GPU_CLOCK_READOUT_ATTRIBUTE: &str = "device/pp_dpm_sclk";
const CARD_EXTENSIONS: &[&'static str] = &[ const CARD_EXTENSIONS: &[&'static str] = &[
GPU_CLOCK_LIMITS_ATTRIBUTE, GPU_CLOCK_LIMITS_ATTRIBUTE,
@ -141,6 +142,29 @@ impl Gpu {
}) })
} }
fn read_max_gpu_clock(&self) -> u64 {
if !(self.limits.extras.experiments || self.limits.extras.quirks.contains("clock-autodetect")) {
return MAX_CLOCK;
}
if let super::Model::OLED = self.variant {
if let Ok(f) = self
.sysfs_card
.read_value(GPU_CLOCK_READOUT_ATTRIBUTE.to_owned())
{
let options = parse_pp_dpm_sclk(&String::from_utf8_lossy(&f));
return options.get(options.len() - 1)
.map(|x| {
let x = x.1 as u64;
log::debug!("Detected GPU max clock of {}MHz", x);
x
})
.unwrap_or(MAX_CLOCK);
}
}
MAX_CLOCK
}
fn is_memory_clock_maxed(&self) -> bool { fn is_memory_clock_maxed(&self) -> bool {
if let Some(clock) = &self.memory_clock { if let Some(clock) = &self.memory_clock {
if let Some(limit) = &self.limits.memory_clock { if let Some(limit) = &self.limits.memory_clock {
@ -611,6 +635,7 @@ impl crate::settings::OnUnload for Gpu {
impl TGpu for Gpu { impl TGpu for Gpu {
fn limits(&self) -> crate::api::GpuLimits { fn limits(&self) -> crate::api::GpuLimits {
let max_gpu_clock = self.read_max_gpu_clock();
crate::api::GpuLimits { crate::api::GpuLimits {
fast_ppt_limits: Some(RangeLimit { fast_ppt_limits: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.fast_ppt, MIN_FAST_PPT) min: super::util::range_min_or_fallback(&self.limits.fast_ppt, MIN_FAST_PPT)
@ -630,11 +655,11 @@ impl TGpu for Gpu {
tdp_step: 42, tdp_step: 42,
clock_min_limits: Some(RangeLimit { clock_min_limits: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.clock_min, MIN_CLOCK), min: super::util::range_min_or_fallback(&self.limits.clock_min, MIN_CLOCK),
max: super::util::range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK), max: super::util::range_max_or_fallback(&self.limits.clock_min, max_gpu_clock),
}), }),
clock_max_limits: Some(RangeLimit { clock_max_limits: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.clock_max, MIN_CLOCK), min: super::util::range_min_or_fallback(&self.limits.clock_max, MIN_CLOCK),
max: super::util::range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), max: super::util::range_max_or_fallback(&self.limits.clock_max, max_gpu_clock),
}), }),
clock_step: self.limits.clock_step.unwrap_or(100), clock_step: self.limits.clock_step.unwrap_or(100),
memory_control: Some(RangeLimit { memory_control: Some(RangeLimit {
@ -693,7 +718,7 @@ impl TGpu for Gpu {
} }
} }
fn parse_pp_dpm_fclk(s: &str) -> Vec<(usize, usize)> { fn parse_sysfs_clk_selector_str(s: &str) -> Vec<(usize, usize)> {
// (value, MHz) // (value, MHz)
let mut result = Vec::new(); let mut result = Vec::new();
for line in s.split('\n') { for line in s.split('\n') {
@ -715,3 +740,13 @@ fn parse_pp_dpm_fclk(s: &str) -> Vec<(usize, usize)> {
} }
result result
} }
#[inline]
fn parse_pp_dpm_fclk(s: &str) -> Vec<(usize, usize)> {
parse_sysfs_clk_selector_str(s)
}
#[inline]
fn parse_pp_dpm_sclk(s: &str) -> Vec<(usize, usize)> {
parse_sysfs_clk_selector_str(s)
}

View file

@ -1,6 +1,6 @@
{ {
"name": "PowerTools", "name": "PowerTools",
"version": "2.0.0-alpha2", "version": "2.0.0-alpha3",
"description": "Power tweaks for power users", "description": "Power tweaks for power users",
"scripts": { "scripts": {
"build": "shx rm -rf dist && rollup -c", "build": "shx rm -rf dist && rollup -c",