adjustor 0.1.0__tar.gz → 0.2.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- adjustor-0.2.0/MANIFEST.in +2 -0
- {adjustor-0.1.0/src/adjustor.egg-info → adjustor-0.2.0}/PKG-INFO +20 -7
- {adjustor-0.1.0 → adjustor-0.2.0}/pyproject.toml +1 -1
- {adjustor-0.1.0 → adjustor-0.2.0}/readme.md +19 -6
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/const.py +13 -1
- adjustor-0.2.0/src/adjustor/drivers/lenovo/settings.yml +152 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/drivers/smu/__init__.py +58 -30
- adjustor-0.2.0/src/adjustor/drivers/smu/qam.yml +27 -0
- adjustor-0.2.0/src/adjustor/drivers/smu/smu.yml +155 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/hhd.py +31 -15
- adjustor-0.2.0/src/adjustor/settings.yml +21 -0
- {adjustor-0.1.0 → adjustor-0.2.0/src/adjustor.egg-info}/PKG-INFO +20 -7
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/SOURCES.txt +6 -1
- {adjustor-0.1.0 → adjustor-0.2.0}/LICENSE +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/setup.cfg +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/__init__.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/__main__.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/acpi.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/alib.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/asus.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/lenovo.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/drivers/__init__.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/drivers/lenovo/__init__.py +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/dependency_links.txt +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/entry_points.txt +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/requires.txt +0 -0
- {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: adjustor
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: Adjustor, a userspace program for managing the TDP of handheld devices.
|
5
5
|
Author-email: Kapenekakis Antheas <pypi@antheas.dev>
|
6
6
|
Project-URL: Homepage, https://github.com/hhd-dev/adjustor
|
@@ -35,22 +35,35 @@ As part of the latest Lenovo bios, it also allows for setting a custom fan curve
|
|
35
35
|
for the Legion Go.
|
36
36
|
|
37
37
|
## AMD TDP Control
|
38
|
-
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
39
|
-
which exposes a superset of the parameters that can be found in
|
38
|
+
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
39
|
+
of AMD, which exposes a superset of the parameters that can be currently found in
|
40
40
|
[RyzenAdj](https://github.dev/FlyGoat/RyzenAdj/), through ACPI.
|
41
|
-
This vendor
|
41
|
+
This vendor interface is part of the ACPI ASL library, and provided through the
|
42
42
|
ALIB method 0x0C.
|
43
|
+
The underlying implementation of the interface is SMU calls.
|
43
44
|
This means that as long as the kernel module `acpi_call` is loaded, Adjustor
|
44
45
|
can control TDP in an equivalent way to [RyzenAdj](https://github.dev/FlyGoat/RyzenAdj/).
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
Right now, Adjustor only implements a subset of useful ALIB parameters that are
|
48
|
+
well documented.
|
49
|
+
In addition, ALIB does not provide a way for reading the performance metrics table,
|
50
|
+
so Adjustor can only write (not read) TDP values.
|
48
51
|
From reverse engineering the Legion Go (see [here](./alib.md)), and seeing how it
|
49
52
|
interacts with ALIB, it was found that there are at least 10 parameters which control
|
50
53
|
the method STTv2 and are not part of RyzenAdj or have been documented elsewhere.
|
51
54
|
|
52
55
|
## Installation
|
53
|
-
|
56
|
+
Adjustor is available on [AUR](https://aur.archlinux.org/packages/adjustor)
|
57
|
+
and provided Handheld Daemon has been installed through
|
58
|
+
[AUR](https://aur.archlinux.org/packages/hhd) too, it will load it automatically
|
59
|
+
on restart.
|
60
|
+
COPR coming soon.
|
61
|
+
|
62
|
+
Alternatively, on a local install of Handheld Daemon you may:
|
63
|
+
```bash
|
64
|
+
~/.local/share/hhd/venv/bin/pip install --upgrade adjustor
|
65
|
+
```
|
66
|
+
However, the autoupdater in Handheld Daemon does not support updating yet.
|
54
67
|
|
55
68
|
## Development
|
56
69
|
Install to the same virtual environment as hhd to have Adjustor picked up
|
@@ -18,22 +18,35 @@ As part of the latest Lenovo bios, it also allows for setting a custom fan curve
|
|
18
18
|
for the Legion Go.
|
19
19
|
|
20
20
|
## AMD TDP Control
|
21
|
-
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
22
|
-
which exposes a superset of the parameters that can be found in
|
21
|
+
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
22
|
+
of AMD, which exposes a superset of the parameters that can be currently found in
|
23
23
|
[RyzenAdj](https://github.dev/FlyGoat/RyzenAdj/), through ACPI.
|
24
|
-
This vendor
|
24
|
+
This vendor interface is part of the ACPI ASL library, and provided through the
|
25
25
|
ALIB method 0x0C.
|
26
|
+
The underlying implementation of the interface is SMU calls.
|
26
27
|
This means that as long as the kernel module `acpi_call` is loaded, Adjustor
|
27
28
|
can control TDP in an equivalent way to [RyzenAdj](https://github.dev/FlyGoat/RyzenAdj/).
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
Right now, Adjustor only implements a subset of useful ALIB parameters that are
|
31
|
+
well documented.
|
32
|
+
In addition, ALIB does not provide a way for reading the performance metrics table,
|
33
|
+
so Adjustor can only write (not read) TDP values.
|
31
34
|
From reverse engineering the Legion Go (see [here](./alib.md)), and seeing how it
|
32
35
|
interacts with ALIB, it was found that there are at least 10 parameters which control
|
33
36
|
the method STTv2 and are not part of RyzenAdj or have been documented elsewhere.
|
34
37
|
|
35
38
|
## Installation
|
36
|
-
|
39
|
+
Adjustor is available on [AUR](https://aur.archlinux.org/packages/adjustor)
|
40
|
+
and provided Handheld Daemon has been installed through
|
41
|
+
[AUR](https://aur.archlinux.org/packages/hhd) too, it will load it automatically
|
42
|
+
on restart.
|
43
|
+
COPR coming soon.
|
44
|
+
|
45
|
+
Alternatively, on a local install of Handheld Daemon you may:
|
46
|
+
```bash
|
47
|
+
~/.local/share/hhd/venv/bin/pip install --upgrade adjustor
|
48
|
+
```
|
49
|
+
However, the autoupdater in Handheld Daemon does not support updating yet.
|
37
50
|
|
38
51
|
## Development
|
39
52
|
Install to the same virtual environment as hhd to have Adjustor picked up
|
@@ -1,5 +1,12 @@
|
|
1
1
|
from .alib import A, D, DeviceParams, AlibParams
|
2
2
|
|
3
|
+
ROG_ALLY_PP_MAP = [
|
4
|
+
("low-power", 0),
|
5
|
+
("quiet", 0),
|
6
|
+
("balanced", 13),
|
7
|
+
("performance", 20),
|
8
|
+
]
|
9
|
+
|
3
10
|
ALIB_PARAMS = {
|
4
11
|
# TDPs
|
5
12
|
"stapm_limit": A(0x05, 0, 54, 1000),
|
@@ -32,9 +39,14 @@ DEV_PARAMS_6040: dict[str, DeviceParams] = DEV_PARAMS_7040
|
|
32
39
|
|
33
40
|
DEV_PARAMS_LEGO = DEV_PARAMS_7040
|
34
41
|
|
42
|
+
DEV_DATA: dict[str, tuple[dict[str, DeviceParams], dict[str, AlibParams], bool]] = {
|
43
|
+
"NEO-01": (DEV_PARAMS_7040, ALIB_PARAMS_7040, False),
|
44
|
+
"83E1": (DEV_PARAMS_LEGO, ALIB_PARAMS_7040, False),
|
45
|
+
}
|
46
|
+
|
35
47
|
CPU_DATA: dict[str, tuple[dict[str, DeviceParams], dict[str, AlibParams]]] = {
|
36
48
|
"AMD Ryzen Z1 Extreme": (DEV_PARAMS_7040, ALIB_PARAMS_7040),
|
37
|
-
"AMD Ryzen 7
|
49
|
+
"AMD Ryzen 7 7840U": (DEV_PARAMS_7040, ALIB_PARAMS_7040),
|
38
50
|
# GPD Win 4
|
39
51
|
# model name : AMD Ryzen 7 6800U with Radeon Graphics
|
40
52
|
# 28W works fine, 30W is pushing it
|
@@ -0,0 +1,152 @@
|
|
1
|
+
title: Lenovo TDP
|
2
|
+
type: container
|
3
|
+
hint: >-
|
4
|
+
Uses the interface of Legion Space to set the TDP of the device.
|
5
|
+
children:
|
6
|
+
tdp:
|
7
|
+
type: mode
|
8
|
+
title: TDP Mode
|
9
|
+
modes:
|
10
|
+
quiet:
|
11
|
+
type: container
|
12
|
+
title: Quiet (8W)
|
13
|
+
balanced:
|
14
|
+
type: container
|
15
|
+
title: Balanced (15W)
|
16
|
+
performance:
|
17
|
+
type: container
|
18
|
+
title: Performance (20W)
|
19
|
+
custom:
|
20
|
+
type: container
|
21
|
+
title: Custom (up to 25-30W)
|
22
|
+
children:
|
23
|
+
tdp:
|
24
|
+
type: int
|
25
|
+
title: TDP
|
26
|
+
hint: >-
|
27
|
+
Maximum TDP in steady state.
|
28
|
+
Sets STAMP, Skin Power Limit to it (steady state).
|
29
|
+
If boost is enabled, interpolates slow and fast TDPs based
|
30
|
+
on those provided by Lenovo.
|
31
|
+
If disabled, it sets the Slow limit equal to TDP and the Fast
|
32
|
+
limit to +2W.
|
33
|
+
Boost is recommended for desktop use.
|
34
|
+
|
35
|
+
tags: [advanced]
|
36
|
+
min: 0
|
37
|
+
max: 30
|
38
|
+
step: 1
|
39
|
+
unit: W
|
40
|
+
boost:
|
41
|
+
type: bool
|
42
|
+
title: Boost
|
43
|
+
default: True
|
44
|
+
hint: >-
|
45
|
+
Allows the device to boost by setting appropriate slow and fast TDPs.
|
46
|
+
|
47
|
+
ffss:
|
48
|
+
type: bool
|
49
|
+
title: Set Fan to Full Speed
|
50
|
+
|
51
|
+
fan:
|
52
|
+
type: mode
|
53
|
+
title: Custom Fan Curve
|
54
|
+
hint: >-
|
55
|
+
Allows you to set a custom fan curve. This fan curve is only officially
|
56
|
+
supported on custom mode, but you can nevertheless use it in other power
|
57
|
+
modes at your own risk.
|
58
|
+
|
59
|
+
This fan curve needs to be reapplied every time you switch TDP modes.
|
60
|
+
default: disabled
|
61
|
+
modes:
|
62
|
+
disabled:
|
63
|
+
type: container
|
64
|
+
title: Disabled
|
65
|
+
hint: >-
|
66
|
+
Lets Legion GO manage the curve on its own. Setting this option will cause
|
67
|
+
a mode change to reset the fan curve.
|
68
|
+
manual:
|
69
|
+
type: container
|
70
|
+
title: Manual
|
71
|
+
children:
|
72
|
+
apply:
|
73
|
+
title: Apply Fan Curve
|
74
|
+
type: action
|
75
|
+
hint: >-
|
76
|
+
Reapplies the fan curve below if it got reset.
|
77
|
+
|
78
|
+
status:
|
79
|
+
title: Fan Curve Status
|
80
|
+
type: display
|
81
|
+
# For translation
|
82
|
+
choices:
|
83
|
+
startup: Unknown
|
84
|
+
not-set: Not Set
|
85
|
+
set: Set
|
86
|
+
|
87
|
+
|
88
|
+
st10: &speed_template
|
89
|
+
title: 10C
|
90
|
+
hint: Sets the speed at the named temperature.
|
91
|
+
tags: [slim]
|
92
|
+
type: int
|
93
|
+
min: 0
|
94
|
+
smin: 44
|
95
|
+
max: 115
|
96
|
+
step: 2
|
97
|
+
unit: "%"
|
98
|
+
|
99
|
+
st20:
|
100
|
+
<<: *speed_template
|
101
|
+
title: 20C
|
102
|
+
smin: 48
|
103
|
+
st30:
|
104
|
+
<<: *speed_template
|
105
|
+
title: 30C
|
106
|
+
smin: 55
|
107
|
+
st40:
|
108
|
+
<<: *speed_template
|
109
|
+
title: 40C
|
110
|
+
smin: 60
|
111
|
+
st50:
|
112
|
+
<<: *speed_template
|
113
|
+
title: 50C
|
114
|
+
smin: 71
|
115
|
+
st60:
|
116
|
+
<<: *speed_template
|
117
|
+
title: 60C
|
118
|
+
smin: 79
|
119
|
+
st70:
|
120
|
+
<<: *speed_template
|
121
|
+
title: 70C
|
122
|
+
smin: 87
|
123
|
+
st80:
|
124
|
+
<<: *speed_template
|
125
|
+
title: 80C
|
126
|
+
smin: 87
|
127
|
+
st90:
|
128
|
+
<<: *speed_template
|
129
|
+
title: 90C
|
130
|
+
smin: 100
|
131
|
+
st100:
|
132
|
+
<<: *speed_template
|
133
|
+
title: 100C
|
134
|
+
smin: 100
|
135
|
+
|
136
|
+
enforce_limits:
|
137
|
+
title: Enforce Windows Minimums
|
138
|
+
type: bool
|
139
|
+
default: True
|
140
|
+
hint: >-
|
141
|
+
Enforce the minimum fan curve from Legion Space.
|
142
|
+
|
143
|
+
reset:
|
144
|
+
title: Restore Default
|
145
|
+
type: action
|
146
|
+
hint: >-
|
147
|
+
Resets to the original fan curve provided by Lenovo in BIOS V28.
|
148
|
+
|
149
|
+
power_light:
|
150
|
+
tags: [advanced]
|
151
|
+
type: bool
|
152
|
+
title: Enable Power Light
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import logging
|
2
|
+
import time
|
2
3
|
|
3
4
|
from hhd.plugins import Context, HHDPlugin, load_relative_yaml
|
4
5
|
from hhd.plugins.conf import Config
|
@@ -38,10 +39,15 @@ def get_platform_profile():
|
|
38
39
|
return None
|
39
40
|
|
40
41
|
|
42
|
+
PP_DELAY = 0.2
|
43
|
+
|
44
|
+
|
41
45
|
class SmuQamPlugin(HHDPlugin):
|
42
46
|
|
43
47
|
def __init__(
|
44
|
-
self,
|
48
|
+
self,
|
49
|
+
dev: dict[str, DeviceParams],
|
50
|
+
pp_map: list[tuple[str, int]] | None,
|
45
51
|
) -> None:
|
46
52
|
self.name = f"adjustor_smu_qam"
|
47
53
|
self.priority = 7
|
@@ -53,14 +59,16 @@ class SmuQamPlugin(HHDPlugin):
|
|
53
59
|
self.emit = None
|
54
60
|
self.old_conf = None
|
55
61
|
|
56
|
-
self.check_pp = platform_profile
|
57
|
-
self.old_pp = None
|
58
|
-
self.has_pp = False
|
59
|
-
|
60
62
|
self.old_tdp = None
|
61
63
|
self.old_boost = None
|
62
64
|
self.is_set = False
|
63
65
|
|
66
|
+
self.pp_map = pp_map
|
67
|
+
if pp_map:
|
68
|
+
self.pps = get_platform_choices() or []
|
69
|
+
else:
|
70
|
+
self.pps = []
|
71
|
+
|
64
72
|
def settings(self):
|
65
73
|
if not self.enabled:
|
66
74
|
self.initialized = False
|
@@ -69,18 +77,6 @@ class SmuQamPlugin(HHDPlugin):
|
|
69
77
|
self.initialized = True
|
70
78
|
out = {"tdp": {"qam": load_relative_yaml("qam.yml")}}
|
71
79
|
|
72
|
-
# Limit platform profile choices or remove
|
73
|
-
choices = get_platform_choices()
|
74
|
-
if choices and self.check_pp:
|
75
|
-
options = out["tdp"]["qam"]["children"]["platform_profile"]["options"]
|
76
|
-
for c in list(options):
|
77
|
-
if c not in choices:
|
78
|
-
del options[c]
|
79
|
-
self.has_pp = True
|
80
|
-
else:
|
81
|
-
del out["tdp"]["qam"]["children"]["platform_profile"]
|
82
|
-
self.has_pp = False
|
83
|
-
|
84
80
|
# Set device limits based on stapm
|
85
81
|
lims = self.dev.get("skin_limit", self.dev.get("stapm_limit", None))
|
86
82
|
assert (
|
@@ -112,17 +108,6 @@ class SmuQamPlugin(HHDPlugin):
|
|
112
108
|
if not self.enabled or not self.initialized:
|
113
109
|
return
|
114
110
|
|
115
|
-
if self.has_pp:
|
116
|
-
cpp = conf["tdp.qam.platform_profile"].to(str)
|
117
|
-
|
118
|
-
if cpp and cpp != self.old_pp:
|
119
|
-
logger.info(f"Setting platform profile to '{cpp}'")
|
120
|
-
set_platform_profile(cpp)
|
121
|
-
|
122
|
-
pp = get_platform_profile()
|
123
|
-
conf["tdp.qam.platform_profile"] = pp
|
124
|
-
self.old_pp = pp
|
125
|
-
|
126
111
|
new_tdp = conf["tdp.qam.tdp"].to(int)
|
127
112
|
new_boost = conf["tdp.qam.boost"].to(bool)
|
128
113
|
changed = (
|
@@ -135,6 +120,14 @@ class SmuQamPlugin(HHDPlugin):
|
|
135
120
|
|
136
121
|
conf["tdp.smu.std.skin_limit"] = new_tdp
|
137
122
|
conf["tdp.smu.std.stapm_limit"] = new_tdp
|
123
|
+
|
124
|
+
if self.pp_map and conf["tdp.smu.platform_profile"].to(str) != "disabled":
|
125
|
+
pp = self.pp_map[0][0]
|
126
|
+
for npp, tdp in self.pp_map:
|
127
|
+
if tdp < new_tdp and npp in self.pps:
|
128
|
+
pp = npp
|
129
|
+
conf["tdp.smu.platform_profile"] = pp
|
130
|
+
|
138
131
|
if new_boost:
|
139
132
|
try:
|
140
133
|
fmax = self.dev["fast_limit"].smax
|
@@ -174,6 +167,7 @@ class SmuDriverPlugin(HHDPlugin):
|
|
174
167
|
self,
|
175
168
|
dev: dict[str, DeviceParams],
|
176
169
|
cpu: dict[str, AlibParams],
|
170
|
+
platform_profile: bool = True,
|
177
171
|
) -> None:
|
178
172
|
self.name = f"adjustor_smu"
|
179
173
|
self.priority = 9
|
@@ -185,7 +179,11 @@ class SmuDriverPlugin(HHDPlugin):
|
|
185
179
|
self.dev = dev
|
186
180
|
self.cpu = cpu
|
187
181
|
|
182
|
+
self.check_pp = platform_profile
|
183
|
+
self.has_pp = False
|
184
|
+
self.old_pp = None
|
188
185
|
self.old_vals = {}
|
186
|
+
self.is_set = False
|
189
187
|
|
190
188
|
for k in dev:
|
191
189
|
assert (
|
@@ -203,6 +201,18 @@ class SmuDriverPlugin(HHDPlugin):
|
|
203
201
|
}
|
204
202
|
}
|
205
203
|
|
204
|
+
# Limit platform profile choices or remove
|
205
|
+
choices = get_platform_choices()
|
206
|
+
if choices and self.check_pp:
|
207
|
+
options = out["tdp"]["smu"]["children"]["platform_profile"]["options"]
|
208
|
+
for c in list(options):
|
209
|
+
if c not in choices and c != "disabled":
|
210
|
+
del options[c]
|
211
|
+
self.has_pp = True
|
212
|
+
else:
|
213
|
+
del out["tdp"]["smu"]["children"]["platform_profile"]
|
214
|
+
self.has_pp = False
|
215
|
+
|
206
216
|
# Remove unsupported instructions
|
207
217
|
# Add absolute limits based on CPU
|
208
218
|
std = out["tdp"]["smu"]["children"]["std"]["children"]
|
@@ -270,19 +280,37 @@ class SmuDriverPlugin(HHDPlugin):
|
|
270
280
|
new_vals[k] = v
|
271
281
|
|
272
282
|
if set(new_vals.items()) != set(self.old_vals.items()):
|
273
|
-
|
283
|
+
self.is_set = False
|
284
|
+
|
285
|
+
if self.has_pp:
|
286
|
+
new_pp = conf["tdp.smu.platform_profile"].to(str)
|
287
|
+
if new_pp != self.old_pp and new_pp != "disabled":
|
288
|
+
self.is_set = False
|
289
|
+
self.old_pp = new_pp
|
274
290
|
|
275
291
|
if conf["tdp.smu.apply"].to(bool):
|
276
292
|
conf["tdp.smu.apply"] = False
|
293
|
+
|
294
|
+
if self.has_pp:
|
295
|
+
cpp = conf["tdp.smu.platform_profile"].to(str)
|
296
|
+
if cpp != "disabled":
|
297
|
+
logger.info(f"Setting platform profile to '{cpp}'")
|
298
|
+
set_platform_profile(cpp)
|
299
|
+
time.sleep(PP_DELAY)
|
300
|
+
|
277
301
|
alib(
|
278
302
|
new_vals,
|
279
303
|
self.cpu,
|
280
304
|
limit="device" if self.enforce_limits else "cpu",
|
281
305
|
dev=self.dev,
|
282
306
|
)
|
283
|
-
|
307
|
+
self.is_set = True
|
284
308
|
|
285
309
|
self.old_vals = new_vals
|
310
|
+
if self.is_set:
|
311
|
+
conf["tdp.smu.status"] = "Set"
|
312
|
+
else:
|
313
|
+
conf["tdp.smu.status"] = "Not Set"
|
286
314
|
|
287
315
|
def close(self):
|
288
316
|
pass
|
@@ -0,0 +1,27 @@
|
|
1
|
+
title: Quick Settings
|
2
|
+
type: container
|
3
|
+
children:
|
4
|
+
tdp:
|
5
|
+
title: TDP
|
6
|
+
hint: >-
|
7
|
+
Controls all Ryzen SMU settings through preset curves.
|
8
|
+
type: int
|
9
|
+
step: 1
|
10
|
+
unit: W
|
11
|
+
|
12
|
+
boost:
|
13
|
+
title: Allow Boost
|
14
|
+
type: bool
|
15
|
+
default: True
|
16
|
+
|
17
|
+
apply:
|
18
|
+
title: Apply TDP
|
19
|
+
type: action
|
20
|
+
|
21
|
+
status:
|
22
|
+
title: TDP Status
|
23
|
+
type: display
|
24
|
+
# For translation
|
25
|
+
choices:
|
26
|
+
uninit: Not Set
|
27
|
+
init: Set
|
@@ -0,0 +1,155 @@
|
|
1
|
+
type: container
|
2
|
+
title: Advanced Configurator
|
3
|
+
tags: [advanced, expert]
|
4
|
+
hint: >-
|
5
|
+
children:
|
6
|
+
apply:
|
7
|
+
type: action
|
8
|
+
title: Apply Settings
|
9
|
+
|
10
|
+
status:
|
11
|
+
title: TDP Status
|
12
|
+
type: display
|
13
|
+
# For translation
|
14
|
+
choices:
|
15
|
+
uninit: Not Set
|
16
|
+
init: Set
|
17
|
+
|
18
|
+
platform_profile:
|
19
|
+
type: multiple
|
20
|
+
title: Platform Profile
|
21
|
+
default: balanced
|
22
|
+
options:
|
23
|
+
disabled: Not Set
|
24
|
+
low-power: Low Power
|
25
|
+
cool: Cool
|
26
|
+
quiet: Quiet
|
27
|
+
balanced: Balanced
|
28
|
+
balanced-performance: Balanced Performance
|
29
|
+
performance: Performance
|
30
|
+
|
31
|
+
std:
|
32
|
+
tags: [advanced]
|
33
|
+
type: container
|
34
|
+
title: Standard Parameters
|
35
|
+
hint: >-
|
36
|
+
Standard TDP parameters for Ryzen processors. All need to be set to
|
37
|
+
properly control the TDP of the device.
|
38
|
+
|
39
|
+
Ryzen processors have 2 modes: STTv2 and STAPM (legacy). AMD suggests to
|
40
|
+
manufacturers to use STTv2, which makes the Legion Go the only device to
|
41
|
+
offer the STAPM alternative through a BIOS setting.
|
42
|
+
|
43
|
+
In STTv2, the device will keep boosting until the "skin" of the device
|
44
|
+
(hottest user accessible spot) reaches a manufacturer set temperature.
|
45
|
+
Then, the device will use the Skin Temp TDP limit.
|
46
|
+
In STAPM, the device averages the TDP values from the 1-3 previous minutes
|
47
|
+
and keeps that value under the STAPM TDP limit.
|
48
|
+
Either mode ignores the other mode's limit (STAPM limit does nothing on
|
49
|
+
STT and Skin Temp Limit does nothing on STAPM), so both should be set.
|
50
|
+
|
51
|
+
The Fast and Slow limits control boosting behavior.
|
52
|
+
The Fast TDP limit is the actual max TDP value of the device.
|
53
|
+
Then,the Slow TDP limit averages the last 10-20s of TDP values and keeps
|
54
|
+
the value below it.
|
55
|
+
|
56
|
+
# The Energy Policy is set automatically by the processor when connecting
|
57
|
+
# to a charger.
|
58
|
+
# It affects power consumption by around 2W, and its effect is mostly to
|
59
|
+
# allow or block the processor from downclocking below 1.6GHz.
|
60
|
+
# The battery profile was found to have an effect on VRR for the Ally.
|
61
|
+
|
62
|
+
children:
|
63
|
+
fast_limit:
|
64
|
+
type: int
|
65
|
+
title: Fast TDP Limit
|
66
|
+
min: 0
|
67
|
+
max: 55
|
68
|
+
step: 1
|
69
|
+
unit: W
|
70
|
+
default: 32
|
71
|
+
|
72
|
+
slow_limit:
|
73
|
+
type: int
|
74
|
+
title: Slow TDP Limit
|
75
|
+
min: 0
|
76
|
+
max: 55
|
77
|
+
step: 1
|
78
|
+
unit: W
|
79
|
+
default: 25
|
80
|
+
|
81
|
+
skin_limit:
|
82
|
+
type: int
|
83
|
+
title: Skin Temp TDP Limit
|
84
|
+
min: 0
|
85
|
+
max: 55
|
86
|
+
step: 1
|
87
|
+
unit: W
|
88
|
+
default: 15
|
89
|
+
|
90
|
+
stapm_limit:
|
91
|
+
type: int
|
92
|
+
title: STAPM TDP Limit
|
93
|
+
min: 0
|
94
|
+
max: 55
|
95
|
+
step: 1
|
96
|
+
unit: W
|
97
|
+
default: 15
|
98
|
+
|
99
|
+
# acdc:
|
100
|
+
# type: multiple
|
101
|
+
# title: Energy Policy Override
|
102
|
+
# options:
|
103
|
+
# disabled: Disabled
|
104
|
+
# power_saving: Battery
|
105
|
+
# max_performance: Plugged In
|
106
|
+
|
107
|
+
adv:
|
108
|
+
tags: [advanced]
|
109
|
+
type: container
|
110
|
+
title: Advanced Parameters
|
111
|
+
hint: >-
|
112
|
+
The Advanced Parameters below control boosting behavior and need to be
|
113
|
+
adjusted per device depending on its cooling system.
|
114
|
+
They mostly affect boosting behavior, which is important for desktop use.
|
115
|
+
|
116
|
+
The exception is the Temp Target (TCTL), which controls the max temperature
|
117
|
+
of the CPU die. On most devices, it can safely be raised up to 100C.
|
118
|
+
However, if a temperature spike makes the chip reach 105C, it will enter
|
119
|
+
a thermal protection mode, which is 5W, for a couple of minutes.
|
120
|
+
|
121
|
+
The integration times for Slow TDP and STAPM influence how many previous
|
122
|
+
TDP values the CPU will average to calculate its current Slow and STAPM
|
123
|
+
TDP values.
|
124
|
+
|
125
|
+
children:
|
126
|
+
temp_target:
|
127
|
+
type: int
|
128
|
+
title: Temp Target (TCTL)
|
129
|
+
min: 0
|
130
|
+
max: 105
|
131
|
+
default: 95
|
132
|
+
unit: C
|
133
|
+
|
134
|
+
slow_time:
|
135
|
+
type: int
|
136
|
+
title: Slow Limit Integration Time
|
137
|
+
min: 0
|
138
|
+
max: 20
|
139
|
+
step: 5
|
140
|
+
unit: s
|
141
|
+
default: 10
|
142
|
+
|
143
|
+
stapm_time:
|
144
|
+
type: int
|
145
|
+
title: STAPM Limit Integration Time
|
146
|
+
min: 0
|
147
|
+
max: 300
|
148
|
+
step: 5
|
149
|
+
unit: s
|
150
|
+
default: 200
|
151
|
+
|
152
|
+
enable:
|
153
|
+
type: bool
|
154
|
+
title: Enable Advanced Parameters
|
155
|
+
default: False
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from adjustor.core.acpi import initialize, check_perms
|
2
2
|
|
3
3
|
from typing import Sequence
|
4
|
-
from adjustor.core.const import CPU_DATA
|
4
|
+
from adjustor.core.const import CPU_DATA, ROG_ALLY_PP_MAP, DEV_DATA
|
5
5
|
|
6
6
|
import os
|
7
7
|
from hhd.plugins import (
|
@@ -56,7 +56,10 @@ class AdjustorPlugin(HHDPlugin):
|
|
56
56
|
self.enfoce_limits = True
|
57
57
|
|
58
58
|
def settings(self) -> HHDSettings:
|
59
|
-
|
59
|
+
out = {"tdp": {"general": load_relative_yaml("settings.yml")}}
|
60
|
+
if os.environ.get("HHD_ADJ_ENABLE_TDP"):
|
61
|
+
out['tdp']['general']['children']['enable']['default'] = True
|
62
|
+
return out
|
60
63
|
|
61
64
|
def open(
|
62
65
|
self,
|
@@ -91,27 +94,40 @@ def autodetect(existing: Sequence[HHDPlugin]) -> Sequence[HHDPlugin]:
|
|
91
94
|
cpuinfo = f.read().strip()
|
92
95
|
|
93
96
|
drivers_matched = False
|
94
|
-
legion_go = False
|
95
97
|
if prod == "83E1":
|
96
98
|
drivers.append(LenovoDriverPlugin())
|
97
99
|
drivers_matched = True
|
98
|
-
legion_go = True
|
99
100
|
|
100
|
-
if (
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
if os.environ.get("HHD_ADJ_DEBUG") or os.environ.get("HHD_ENABLE_SMU"):
|
102
|
+
drivers_matched = False
|
103
|
+
|
104
|
+
if not drivers_matched and prod in DEV_DATA:
|
105
|
+
dev, cpu, pp_enable = DEV_DATA[prod]
|
106
|
+
pp_enable |= bool(os.environ.get("HHD_ADJ_DEBUG"))
|
107
|
+
drivers.append(
|
108
|
+
SmuDriverPlugin(
|
109
|
+
dev,
|
110
|
+
cpu,
|
111
|
+
platform_profile=pp_enable,
|
112
|
+
)
|
113
|
+
)
|
114
|
+
drivers.append(
|
115
|
+
SmuQamPlugin(dev, ROG_ALLY_PP_MAP if pp_enable else None),
|
116
|
+
)
|
117
|
+
drivers_matched = True
|
118
|
+
|
119
|
+
if not drivers_matched:
|
105
120
|
for name, (dev, cpu) in CPU_DATA.items():
|
106
121
|
if name in cpuinfo:
|
107
|
-
drivers.append(SmuDriverPlugin(dev, cpu))
|
108
122
|
drivers.append(
|
109
|
-
|
123
|
+
SmuDriverPlugin(
|
110
124
|
dev,
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
125
|
+
cpu,
|
126
|
+
platform_profile=True,
|
127
|
+
)
|
128
|
+
)
|
129
|
+
drivers.append(
|
130
|
+
SmuQamPlugin(dev, ROG_ALLY_PP_MAP),
|
115
131
|
)
|
116
132
|
break
|
117
133
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
type: container
|
2
|
+
title: General Settings
|
3
|
+
tags: [ advanced ]
|
4
|
+
children:
|
5
|
+
enable:
|
6
|
+
title: Enable TDP Controls
|
7
|
+
type: bool
|
8
|
+
default: False
|
9
|
+
|
10
|
+
enforce_limits:
|
11
|
+
title: Enforce Device Limits
|
12
|
+
type: bool
|
13
|
+
tags: [ expert ]
|
14
|
+
default: True
|
15
|
+
|
16
|
+
error:
|
17
|
+
title: Error
|
18
|
+
type: display
|
19
|
+
tags: [error]
|
20
|
+
options:
|
21
|
+
nowrite: Can not write to ACPI Call file. ACPI Call is required for TDP.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: adjustor
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: Adjustor, a userspace program for managing the TDP of handheld devices.
|
5
5
|
Author-email: Kapenekakis Antheas <pypi@antheas.dev>
|
6
6
|
Project-URL: Homepage, https://github.com/hhd-dev/adjustor
|
@@ -35,22 +35,35 @@ As part of the latest Lenovo bios, it also allows for setting a custom fan curve
|
|
35
35
|
for the Legion Go.
|
36
36
|
|
37
37
|
## AMD TDP Control
|
38
|
-
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
39
|
-
which exposes a superset of the parameters that can be found in
|
38
|
+
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
39
|
+
of AMD, which exposes a superset of the parameters that can be currently found in
|
40
40
|
[RyzenAdj](https://github.dev/FlyGoat/RyzenAdj/), through ACPI.
|
41
|
-
This vendor
|
41
|
+
This vendor interface is part of the ACPI ASL library, and provided through the
|
42
42
|
ALIB method 0x0C.
|
43
|
+
The underlying implementation of the interface is SMU calls.
|
43
44
|
This means that as long as the kernel module `acpi_call` is loaded, Adjustor
|
44
45
|
can control TDP in an equivalent way to [RyzenAdj](https://github.dev/FlyGoat/RyzenAdj/).
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
Right now, Adjustor only implements a subset of useful ALIB parameters that are
|
48
|
+
well documented.
|
49
|
+
In addition, ALIB does not provide a way for reading the performance metrics table,
|
50
|
+
so Adjustor can only write (not read) TDP values.
|
48
51
|
From reverse engineering the Legion Go (see [here](./alib.md)), and seeing how it
|
49
52
|
interacts with ALIB, it was found that there are at least 10 parameters which control
|
50
53
|
the method STTv2 and are not part of RyzenAdj or have been documented elsewhere.
|
51
54
|
|
52
55
|
## Installation
|
53
|
-
|
56
|
+
Adjustor is available on [AUR](https://aur.archlinux.org/packages/adjustor)
|
57
|
+
and provided Handheld Daemon has been installed through
|
58
|
+
[AUR](https://aur.archlinux.org/packages/hhd) too, it will load it automatically
|
59
|
+
on restart.
|
60
|
+
COPR coming soon.
|
61
|
+
|
62
|
+
Alternatively, on a local install of Handheld Daemon you may:
|
63
|
+
```bash
|
64
|
+
~/.local/share/hhd/venv/bin/pip install --upgrade adjustor
|
65
|
+
```
|
66
|
+
However, the autoupdater in Handheld Daemon does not support updating yet.
|
54
67
|
|
55
68
|
## Development
|
56
69
|
Install to the same virtual environment as hhd to have Adjustor picked up
|
@@ -1,9 +1,11 @@
|
|
1
1
|
LICENSE
|
2
|
+
MANIFEST.in
|
2
3
|
pyproject.toml
|
3
4
|
readme.md
|
4
5
|
src/adjustor/__init__.py
|
5
6
|
src/adjustor/__main__.py
|
6
7
|
src/adjustor/hhd.py
|
8
|
+
src/adjustor/settings.yml
|
7
9
|
src/adjustor.egg-info/PKG-INFO
|
8
10
|
src/adjustor.egg-info/SOURCES.txt
|
9
11
|
src/adjustor.egg-info/dependency_links.txt
|
@@ -17,4 +19,7 @@ src/adjustor/core/const.py
|
|
17
19
|
src/adjustor/core/lenovo.py
|
18
20
|
src/adjustor/drivers/__init__.py
|
19
21
|
src/adjustor/drivers/lenovo/__init__.py
|
20
|
-
src/adjustor/drivers/
|
22
|
+
src/adjustor/drivers/lenovo/settings.yml
|
23
|
+
src/adjustor/drivers/smu/__init__.py
|
24
|
+
src/adjustor/drivers/smu/qam.yml
|
25
|
+
src/adjustor/drivers/smu/smu.yml
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|