adjustor 2.0.0__tar.gz → 2.1.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {adjustor-2.0.0/src/adjustor.egg-info → adjustor-2.1.0}/PKG-INFO +8 -7
- {adjustor-2.0.0 → adjustor-2.1.0}/pyproject.toml +2 -2
- {adjustor-2.0.0 → adjustor-2.1.0}/readme.md +6 -5
- adjustor-2.1.0/src/adjustor/core/platform.py +34 -0
- adjustor-2.1.0/src/adjustor/drivers/__init__.py +0 -0
- adjustor-2.1.0/src/adjustor/drivers/asus/__init__.py +256 -0
- adjustor-2.1.0/src/adjustor/drivers/asus/settings.yml +99 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/drivers/lenovo/__init__.py +5 -3
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/drivers/lenovo/settings.yml +1 -1
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/drivers/smu/__init__.py +1 -31
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/drivers/smu/smu.yml +1 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/hhd.py +7 -1
- {adjustor-2.0.0 → adjustor-2.1.0/src/adjustor.egg-info}/PKG-INFO +8 -7
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor.egg-info/SOURCES.txt +4 -1
- adjustor-2.0.0/src/adjustor/core/asus.py +0 -50
- {adjustor-2.0.0 → adjustor-2.1.0}/LICENSE +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/MANIFEST.in +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/setup.cfg +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/__init__.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/__main__.py +0 -0
- {adjustor-2.0.0/src/adjustor/drivers → adjustor-2.1.0/src/adjustor/core}/__init__.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/core/acpi.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/core/alib.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/core/const.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/core/lenovo.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/drivers/smu/qam.yml +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/events.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/settings.yml +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor/utils.py +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor.egg-info/dependency_links.txt +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor.egg-info/entry_points.txt +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor.egg-info/requires.txt +0 -0
- {adjustor-2.0.0 → adjustor-2.1.0}/src/adjustor.egg-info/top_level.txt +0 -0
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: adjustor
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.1.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
|
7
7
|
Project-URL: Bug Tracker, https://github.com/hhd-dev/adjustor/issues
|
8
|
-
Classifier: License :: OSI Approved ::
|
8
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
9
9
|
Classifier: Programming Language :: Python :: 3.10
|
10
10
|
Classifier: Programming Language :: Python :: 3.11
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -29,11 +29,12 @@ setting TDP on demand in Ryzen processors, through ACPI.
|
|
29
29
|
This means that it can be used regardless of the current memory policy
|
30
30
|
or secure-boot/lockdown status (provided the module `acpi_call` is installed.).
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
the
|
35
|
-
|
36
|
-
|
32
|
+
For the ROG Ally and Legion Go that have an ACPI/EC implementation for bios and fan curves,
|
33
|
+
Adjustor uses the manufactuer way for setting TDP.
|
34
|
+
For the ally, the asus-wmi kernel driver is used to set the tdp and manage the
|
35
|
+
fan curves.
|
36
|
+
For the go, Lenovo's WMI methods are called through `acpi_call`, which will hopefully
|
37
|
+
become part of a driver in the future.
|
37
38
|
|
38
39
|
## AMD TDP Control
|
39
40
|
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "adjustor"
|
3
|
-
version = "2.
|
3
|
+
version = "2.1.0"
|
4
4
|
authors = [
|
5
5
|
{ name="Kapenekakis Antheas", email="pypi@antheas.dev" },
|
6
6
|
]
|
@@ -8,7 +8,7 @@ description = "Adjustor, a userspace program for managing the TDP of handheld de
|
|
8
8
|
readme = "readme.md"
|
9
9
|
requires-python = ">=3.10"
|
10
10
|
classifiers = [
|
11
|
-
"License :: OSI Approved ::
|
11
|
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
12
12
|
"Programming Language :: Python :: 3.10",
|
13
13
|
"Programming Language :: Python :: 3.11",
|
14
14
|
"Programming Language :: Python :: 3.12",
|
@@ -11,11 +11,12 @@ setting TDP on demand in Ryzen processors, through ACPI.
|
|
11
11
|
This means that it can be used regardless of the current memory policy
|
12
12
|
or secure-boot/lockdown status (provided the module `acpi_call` is installed.).
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
the
|
17
|
-
|
18
|
-
|
14
|
+
For the ROG Ally and Legion Go that have an ACPI/EC implementation for bios and fan curves,
|
15
|
+
Adjustor uses the manufactuer way for setting TDP.
|
16
|
+
For the ally, the asus-wmi kernel driver is used to set the tdp and manage the
|
17
|
+
fan curves.
|
18
|
+
For the go, Lenovo's WMI methods are called through `acpi_call`, which will hopefully
|
19
|
+
become part of a driver in the future.
|
19
20
|
|
20
21
|
## AMD TDP Control
|
21
22
|
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
logger = logging.getLogger(__name__)
|
4
|
+
|
5
|
+
|
6
|
+
def get_platform_choices():
|
7
|
+
try:
|
8
|
+
with open("/sys/firmware/acpi/platform_profile_choices", "r") as f:
|
9
|
+
return f.read().strip().split(" ")
|
10
|
+
except Exception:
|
11
|
+
logger.info(
|
12
|
+
f"Could not enumerate platform profile choices. Disabling platform profile."
|
13
|
+
)
|
14
|
+
return None
|
15
|
+
|
16
|
+
|
17
|
+
def set_platform_profile(prof: str):
|
18
|
+
try:
|
19
|
+
logger.info(f"Setting platform profile to '{prof}'")
|
20
|
+
with open("/sys/firmware/acpi/platform_profile", "w") as f:
|
21
|
+
f.write(prof)
|
22
|
+
return True
|
23
|
+
except Exception as e:
|
24
|
+
logger.error(f"Could not set platform profile with error:\n{e}")
|
25
|
+
return False
|
26
|
+
|
27
|
+
|
28
|
+
def get_platform_profile():
|
29
|
+
try:
|
30
|
+
with open("/sys/firmware/acpi/platform_profile", "r") as f:
|
31
|
+
return f.read().replace("\n", "")
|
32
|
+
except Exception as e:
|
33
|
+
logger.error(f"Could not read platform profile with error:\n{e}")
|
34
|
+
return None
|
File without changes
|
@@ -0,0 +1,256 @@
|
|
1
|
+
import logging
|
2
|
+
import time
|
3
|
+
from typing import cast
|
4
|
+
import os
|
5
|
+
|
6
|
+
from hhd.plugins import Context, HHDPlugin, load_relative_yaml
|
7
|
+
from hhd.plugins.conf import Config
|
8
|
+
from adjustor.core.platform import get_platform_choices, set_platform_profile
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
APPLY_DELAY = 1.5
|
13
|
+
TDP_DELAY = 0.2
|
14
|
+
MIN_TDP_START = 7
|
15
|
+
MAX_TDP_START = 30
|
16
|
+
MAX_TDP = 54
|
17
|
+
|
18
|
+
FTDP_FN = "/sys/devices/platform/asus-nb-wmi/ppt_fppt"
|
19
|
+
STDP_FN = "/sys/devices/platform/asus-nb-wmi/ppt_pl2_sppt"
|
20
|
+
CTDP_FN = "/sys/devices/platform/asus-nb-wmi/ppt_pl1_spl"
|
21
|
+
|
22
|
+
FAN_CURVE_ENDPOINT = "/sys/class/hwmon"
|
23
|
+
FAN_CURVE_NAME = "asus_custom_fan_curve"
|
24
|
+
|
25
|
+
# Default Ally curve is the following
|
26
|
+
# [40 45 55 63 68 74 74 74]
|
27
|
+
# [10 20 66 86 132 188 188 188] / 2.55
|
28
|
+
# [ 4 8 ]
|
29
|
+
|
30
|
+
POINTS = [30, 40, 50, 60, 70, 80, 90, 100]
|
31
|
+
MIN_CURVE = [2, 5, 17, 17, 17, 17, 17, 17]
|
32
|
+
DEFAULT_CURVE = [5, 10, 20, 35, 55, 75, 75, 75]
|
33
|
+
|
34
|
+
|
35
|
+
def set_tdp(pretty: str, fn: str, val: int):
|
36
|
+
logger.info(f"Setting tdp value '{pretty}' to {val} by writing to:\n{fn}")
|
37
|
+
try:
|
38
|
+
with open(fn, "w") as f:
|
39
|
+
f.write(f"{val}\n")
|
40
|
+
return True
|
41
|
+
except Exception as e:
|
42
|
+
logger.error(f"Failed writing value with error:\n{e}")
|
43
|
+
return False
|
44
|
+
|
45
|
+
|
46
|
+
def find_fan_curve_dir():
|
47
|
+
for dir in os.listdir(FAN_CURVE_ENDPOINT):
|
48
|
+
name_fn = os.path.join(FAN_CURVE_ENDPOINT, dir, "name")
|
49
|
+
with open(name_fn, "r") as f:
|
50
|
+
name = f.read().strip()
|
51
|
+
if name == FAN_CURVE_NAME:
|
52
|
+
return os.path.join(FAN_CURVE_ENDPOINT, dir)
|
53
|
+
return None
|
54
|
+
|
55
|
+
|
56
|
+
def set_fan_curve(points: list[int], curve: list[int]):
|
57
|
+
point_str = ",".join([f"{p:> 4d} C" for p in points])
|
58
|
+
curve_str = ",".join([f"{p:> 4d} /" for p in curve])
|
59
|
+
logger.info(f"Setting the following fan curve:\n{point_str}\n{curve_str} 255")
|
60
|
+
|
61
|
+
dir = find_fan_curve_dir()
|
62
|
+
if not dir:
|
63
|
+
logger.error(f"Could not find hwmon with name:\n'{FAN_CURVE_NAME}'")
|
64
|
+
return False
|
65
|
+
|
66
|
+
for fan in (1, 2):
|
67
|
+
for i, (temp, speed) in enumerate(zip(points, curve)):
|
68
|
+
with open(os.path.join(dir, f"pwm{fan}_auto_point{i+1}_temp"), "w") as f:
|
69
|
+
f.write(f"{temp}")
|
70
|
+
with open(os.path.join(dir, f"pwm{fan}_auto_point{i+1}_pwm"), "w") as f:
|
71
|
+
f.write(f"{speed}")
|
72
|
+
|
73
|
+
for fan in (1, 2):
|
74
|
+
with open(os.path.join(dir, f"pwm{fan}_enable"), "w") as f:
|
75
|
+
f.write(f"1")
|
76
|
+
|
77
|
+
return True
|
78
|
+
|
79
|
+
|
80
|
+
def disable_fan_curve():
|
81
|
+
logger.info(f"Disabling custom fan curve.")
|
82
|
+
|
83
|
+
dir = find_fan_curve_dir()
|
84
|
+
if not dir:
|
85
|
+
logger.error(f"Could not find hwmon with name:\n'{FAN_CURVE_NAME}'")
|
86
|
+
return False
|
87
|
+
|
88
|
+
for fan in (1, 2):
|
89
|
+
with open(os.path.join(dir, f"pwm{fan}_enable"), "w") as f:
|
90
|
+
f.write(f"3")
|
91
|
+
|
92
|
+
return True
|
93
|
+
|
94
|
+
|
95
|
+
class AsusDriverPlugin(HHDPlugin):
|
96
|
+
def __init__(self) -> None:
|
97
|
+
self.name = f"asus"
|
98
|
+
self.priority = 6
|
99
|
+
self.log = "adja"
|
100
|
+
self.enabled = False
|
101
|
+
self.initialized = False
|
102
|
+
self.enforce_limits = True
|
103
|
+
self.startup = True
|
104
|
+
self.old_conf = None
|
105
|
+
|
106
|
+
self.queue_fan = None
|
107
|
+
self.queue_tdp = None
|
108
|
+
|
109
|
+
def settings(self):
|
110
|
+
if not self.enabled:
|
111
|
+
self.initialized = False
|
112
|
+
self.old_conf = None
|
113
|
+
self.startup = True
|
114
|
+
return {}
|
115
|
+
|
116
|
+
self.initialized = True
|
117
|
+
out = {"tdp": {"asus": load_relative_yaml("settings.yml")}}
|
118
|
+
if not self.enforce_limits:
|
119
|
+
out["tdp"]["asus"]["children"]["tdp"]["max"] = 40
|
120
|
+
return out
|
121
|
+
|
122
|
+
def open(
|
123
|
+
self,
|
124
|
+
emit,
|
125
|
+
context: Context,
|
126
|
+
):
|
127
|
+
pass
|
128
|
+
|
129
|
+
def update(self, conf: Config):
|
130
|
+
self.enabled = conf["hhd.settings.tdp_enable"].to(bool)
|
131
|
+
new_enforce_limits = conf["hhd.settings.enforce_limits"].to(bool)
|
132
|
+
new_lims = new_enforce_limits != self.enforce_limits
|
133
|
+
self.enforce_limits = new_enforce_limits
|
134
|
+
|
135
|
+
if not self.enabled or not self.initialized or new_lims:
|
136
|
+
self.old_conf = None
|
137
|
+
self.startup = True
|
138
|
+
return
|
139
|
+
|
140
|
+
# If not old config, exit, as values can not be set
|
141
|
+
if not self.old_conf:
|
142
|
+
self.old_conf = conf["tdp.asus"]
|
143
|
+
return
|
144
|
+
|
145
|
+
curr = time.time()
|
146
|
+
|
147
|
+
#
|
148
|
+
# TDP
|
149
|
+
#
|
150
|
+
|
151
|
+
# Reset fan curve on mode change
|
152
|
+
# Has to happen before setting the stdp, ftdp values, in case
|
153
|
+
# we are in custom mode
|
154
|
+
fan_mode = conf["tdp.asus.fan.mode"].to(str)
|
155
|
+
if fan_mode != self.old_conf["fan.mode"].to(str) and fan_mode != "manual":
|
156
|
+
pass
|
157
|
+
|
158
|
+
# Check user changed values
|
159
|
+
steady = conf["tdp.asus.tdp"].to(int)
|
160
|
+
|
161
|
+
steady_updated = steady and steady != self.old_conf["tdp"].to(int)
|
162
|
+
|
163
|
+
if self.startup and (steady > MAX_TDP_START or steady < MIN_TDP_START):
|
164
|
+
logger.warning(
|
165
|
+
f"TDP ({steady}) outside the device spec. Resetting for stability reasons."
|
166
|
+
)
|
167
|
+
steady = min(max(steady, MIN_TDP_START), MAX_TDP_START)
|
168
|
+
conf["tdp.asus.tdp"] = steady
|
169
|
+
steady_updated = True
|
170
|
+
|
171
|
+
boost = conf["tdp.asus.boost"].to(bool)
|
172
|
+
boost_updated = boost != self.old_conf["boost"].to(bool)
|
173
|
+
|
174
|
+
# If yes, queue an update
|
175
|
+
# Debounce
|
176
|
+
if self.startup or steady_updated or boost_updated:
|
177
|
+
self.queue_tdp = curr + APPLY_DELAY
|
178
|
+
|
179
|
+
tdp_set = self.queue_tdp and self.queue_tdp < curr
|
180
|
+
if tdp_set:
|
181
|
+
if steady < 5:
|
182
|
+
steady = 5
|
183
|
+
if steady < 13:
|
184
|
+
set_platform_profile("quiet")
|
185
|
+
elif steady < 20:
|
186
|
+
set_platform_profile("balanced")
|
187
|
+
else:
|
188
|
+
set_platform_profile("performance")
|
189
|
+
|
190
|
+
self.queue_tdp = None
|
191
|
+
if boost:
|
192
|
+
set_tdp("steady", CTDP_FN, steady)
|
193
|
+
time.sleep(TDP_DELAY)
|
194
|
+
set_tdp("slow", STDP_FN, min(MAX_TDP, int(steady * 43 / 30)))
|
195
|
+
time.sleep(TDP_DELAY)
|
196
|
+
set_tdp("fast", FTDP_FN, min(MAX_TDP, int(steady * 53 / 30)))
|
197
|
+
else:
|
198
|
+
set_tdp("steady", CTDP_FN, steady)
|
199
|
+
time.sleep(TDP_DELAY)
|
200
|
+
set_tdp("slow", STDP_FN, steady)
|
201
|
+
time.sleep(TDP_DELAY)
|
202
|
+
set_tdp("fast", FTDP_FN, steady)
|
203
|
+
|
204
|
+
# Handle fan curve resets
|
205
|
+
if conf["tdp.asus.fan.manual.reset"].to(bool):
|
206
|
+
conf["tdp.asus.fan.manual.reset"] = False
|
207
|
+
for k, v in zip(POINTS, DEFAULT_CURVE):
|
208
|
+
conf[f"tdp.asus.fan.manual.st{k}"] = v
|
209
|
+
|
210
|
+
# Handle fan curve limits
|
211
|
+
if conf["tdp.asus.fan.manual.enforce_limits"].to(bool):
|
212
|
+
for k, v in zip(POINTS, MIN_CURVE):
|
213
|
+
if conf[f"tdp.asus.fan.manual.st{k}"].to(int) < v:
|
214
|
+
conf[f"tdp.asus.fan.manual.st{k}"] = v
|
215
|
+
|
216
|
+
# Check if fan curve has changed
|
217
|
+
# Use debounce logic on these changes
|
218
|
+
if tdp_set and conf["tdp.asus.fan.mode"].to(str) == "manual":
|
219
|
+
self.queue_fan = curr + APPLY_DELAY
|
220
|
+
if conf["tdp.asus.fan.mode"].to(str) != self.old_conf["fan.mode"].to(str):
|
221
|
+
self.queue_fan = curr + APPLY_DELAY
|
222
|
+
for i in POINTS:
|
223
|
+
if conf[f"tdp.asus.fan.manual.st{i}"].to(int) != self.old_conf[
|
224
|
+
f"fan.manual.st{i}"
|
225
|
+
].to(int):
|
226
|
+
self.queue_fan = curr + APPLY_DELAY
|
227
|
+
|
228
|
+
apply_curve = self.queue_fan and self.queue_fan < curr
|
229
|
+
if apply_curve:
|
230
|
+
try:
|
231
|
+
# Always disable fan curve first
|
232
|
+
disable_fan_curve()
|
233
|
+
if conf["tdp.asus.fan.mode"].to(str) == "manual":
|
234
|
+
time.sleep(TDP_DELAY)
|
235
|
+
set_fan_curve(
|
236
|
+
POINTS,
|
237
|
+
[
|
238
|
+
min(
|
239
|
+
int(conf[f"tdp.asus.fan.manual.st{i}"].to(int) * 2.55),
|
240
|
+
255,
|
241
|
+
)
|
242
|
+
for i in POINTS
|
243
|
+
],
|
244
|
+
)
|
245
|
+
except Exception as e:
|
246
|
+
logger.error(f"Could not set fan curve. Error:\n{e}")
|
247
|
+
self.queue_fan = None
|
248
|
+
|
249
|
+
# Save current config
|
250
|
+
self.old_conf = conf["tdp.asus"]
|
251
|
+
|
252
|
+
if self.startup:
|
253
|
+
self.startup = False
|
254
|
+
|
255
|
+
def close(self):
|
256
|
+
pass
|
@@ -0,0 +1,99 @@
|
|
1
|
+
title: Asus TDP
|
2
|
+
type: container
|
3
|
+
tags: [hide-title]
|
4
|
+
hint: >-
|
5
|
+
Uses the interface of Legion Space to set the TDP of the device.
|
6
|
+
children:
|
7
|
+
tdp:
|
8
|
+
type: int
|
9
|
+
title: TDP
|
10
|
+
hint: >-
|
11
|
+
Average TDP Target.
|
12
|
+
|
13
|
+
Sets the values STAMP and Skin Power Limit to it.
|
14
|
+
If it is not, it sets the Slow limit equal to TDP and the Fast
|
15
|
+
limit to +2W.
|
16
|
+
Boost is recommended for desktop use.
|
17
|
+
|
18
|
+
min: 5
|
19
|
+
max: 30
|
20
|
+
step: 1
|
21
|
+
default: 30
|
22
|
+
unit: W
|
23
|
+
boost:
|
24
|
+
type: bool
|
25
|
+
title: TDP Boost
|
26
|
+
default: True
|
27
|
+
hint: >-
|
28
|
+
Allows the device to boost by setting appropriate slow and fast TDPs.
|
29
|
+
|
30
|
+
fan:
|
31
|
+
type: mode
|
32
|
+
title: Custom Fan Curve
|
33
|
+
hint: >-
|
34
|
+
Allows you to set a custom fan curve.
|
35
|
+
default: disabled
|
36
|
+
modes:
|
37
|
+
disabled:
|
38
|
+
type: container
|
39
|
+
title: Disabled
|
40
|
+
hint: >-
|
41
|
+
Lets the device manage the fan curve on its own.
|
42
|
+
manual:
|
43
|
+
type: container
|
44
|
+
title: Manual [BETA]
|
45
|
+
tags: [ non-essential ]
|
46
|
+
children:
|
47
|
+
|
48
|
+
st30: &speed_template
|
49
|
+
title: 30C
|
50
|
+
hint: Sets the speed at the named temperature.
|
51
|
+
tags: [slim]
|
52
|
+
type: int
|
53
|
+
min: 0
|
54
|
+
default: 5
|
55
|
+
max: 100
|
56
|
+
step: 2
|
57
|
+
unit: "%"
|
58
|
+
|
59
|
+
st40:
|
60
|
+
<<: *speed_template
|
61
|
+
title: 40C
|
62
|
+
default: 10
|
63
|
+
st50:
|
64
|
+
<<: *speed_template
|
65
|
+
title: 50C
|
66
|
+
default: 20
|
67
|
+
st60:
|
68
|
+
<<: *speed_template
|
69
|
+
title: 60C
|
70
|
+
default: 35
|
71
|
+
st70:
|
72
|
+
<<: *speed_template
|
73
|
+
title: 70C
|
74
|
+
default: 55
|
75
|
+
st80:
|
76
|
+
<<: *speed_template
|
77
|
+
title: 80C
|
78
|
+
default: 75
|
79
|
+
st90:
|
80
|
+
<<: *speed_template
|
81
|
+
title: 90C
|
82
|
+
default: 75
|
83
|
+
st100:
|
84
|
+
<<: *speed_template
|
85
|
+
title: 100C
|
86
|
+
default: 75
|
87
|
+
|
88
|
+
enforce_limits:
|
89
|
+
title: Enforce Minimums
|
90
|
+
type: bool
|
91
|
+
default: True
|
92
|
+
hint: >-
|
93
|
+
Enforce a reasonable minimum fan curve.
|
94
|
+
|
95
|
+
reset:
|
96
|
+
title: Restore Default
|
97
|
+
type: action
|
98
|
+
hint: >-
|
99
|
+
Restore a default sane fan curve.
|
@@ -25,8 +25,8 @@ from adjustor.core.lenovo import (
|
|
25
25
|
|
26
26
|
logger = logging.getLogger(__name__)
|
27
27
|
|
28
|
-
APPLY_DELAY =
|
29
|
-
TDP_DELAY = 0.
|
28
|
+
APPLY_DELAY = 2.2
|
29
|
+
TDP_DELAY = 0.2
|
30
30
|
|
31
31
|
|
32
32
|
class LenovoDriverPlugin(HHDPlugin):
|
@@ -132,6 +132,7 @@ class LenovoDriverPlugin(HHDPlugin):
|
|
132
132
|
tdp_mode = get_tdp_mode()
|
133
133
|
if tdp_mode:
|
134
134
|
set_tdp_mode("performance")
|
135
|
+
time.sleep(TDP_DELAY)
|
135
136
|
set_tdp_mode(tdp_mode)
|
136
137
|
tdp_reset = True
|
137
138
|
|
@@ -178,7 +179,8 @@ class LenovoDriverPlugin(HHDPlugin):
|
|
178
179
|
# Fan curve stuff
|
179
180
|
# If tdp reset, so was the curve
|
180
181
|
if tdp_reset:
|
181
|
-
|
182
|
+
# 2x to apply after tdp
|
183
|
+
self.queue_fan = curr + 2 * APPLY_DELAY
|
182
184
|
|
183
185
|
# Handle fan curve resets
|
184
186
|
if conf["tdp.lenovo.fan.manual.reset"].to(bool):
|
@@ -5,40 +5,10 @@ from hhd.plugins import Context, HHDPlugin, load_relative_yaml
|
|
5
5
|
from hhd.plugins.conf import Config
|
6
6
|
|
7
7
|
from adjustor.core.alib import AlibParams, DeviceParams, alib
|
8
|
+
from adjustor.core.platform import get_platform_choices, set_platform_profile
|
8
9
|
|
9
10
|
logger = logging.getLogger(__name__)
|
10
11
|
|
11
|
-
|
12
|
-
def get_platform_choices():
|
13
|
-
try:
|
14
|
-
with open("/sys/firmware/acpi/platform_profile_choices", "r") as f:
|
15
|
-
return f.read().strip().split(" ")
|
16
|
-
except Exception:
|
17
|
-
logger.info(
|
18
|
-
f"Could not enumerate platform profile choices. Disabling platform profile."
|
19
|
-
)
|
20
|
-
return None
|
21
|
-
|
22
|
-
|
23
|
-
def set_platform_profile(prof: str):
|
24
|
-
try:
|
25
|
-
with open("/sys/firmware/acpi/platform_profile", "w") as f:
|
26
|
-
f.write(prof)
|
27
|
-
return True
|
28
|
-
except Exception as e:
|
29
|
-
logger.error(f"Could not set platform profile with error:\n{e}")
|
30
|
-
return False
|
31
|
-
|
32
|
-
|
33
|
-
def get_platform_profile():
|
34
|
-
try:
|
35
|
-
with open("/sys/firmware/acpi/platform_profile", "r") as f:
|
36
|
-
return f.read().replace("\n", "")
|
37
|
-
except Exception as e:
|
38
|
-
logger.error(f"Could not read platform profile with error:\n{e}")
|
39
|
-
return None
|
40
|
-
|
41
|
-
|
42
12
|
PP_DELAY = 0.2
|
43
13
|
APPLY_DELAY = 1
|
44
14
|
|
@@ -78,7 +78,8 @@ class AdjustorInitPlugin(HHDPlugin):
|
|
78
78
|
self.enabled = False
|
79
79
|
return
|
80
80
|
|
81
|
-
|
81
|
+
initialize()
|
82
|
+
if not check_perms():
|
82
83
|
conf["hhd.settings.tdp_enable"] = False
|
83
84
|
conf["tdp.tdp.tdp_error"] = (
|
84
85
|
"Can not write to 'acpi_call'. It is required for TDP."
|
@@ -167,6 +168,7 @@ def autodetect(existing: Sequence[HHDPlugin]) -> Sequence[HHDPlugin]:
|
|
167
168
|
return existing
|
168
169
|
|
169
170
|
from .drivers.lenovo import LenovoDriverPlugin
|
171
|
+
from .drivers.asus import AsusDriverPlugin
|
170
172
|
from .drivers.smu import SmuDriverPlugin, SmuQamPlugin
|
171
173
|
|
172
174
|
drivers = []
|
@@ -180,6 +182,10 @@ def autodetect(existing: Sequence[HHDPlugin]) -> Sequence[HHDPlugin]:
|
|
180
182
|
drivers.append(LenovoDriverPlugin())
|
181
183
|
drivers_matched = True
|
182
184
|
|
185
|
+
if "ROG Ally RC71L" in prod:
|
186
|
+
drivers.append(AsusDriverPlugin())
|
187
|
+
drivers_matched = True
|
188
|
+
|
183
189
|
if os.environ.get("HHD_ADJ_DEBUG") or os.environ.get("HHD_ENABLE_SMU"):
|
184
190
|
drivers_matched = False
|
185
191
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: adjustor
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.1.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
|
7
7
|
Project-URL: Bug Tracker, https://github.com/hhd-dev/adjustor/issues
|
8
|
-
Classifier: License :: OSI Approved ::
|
8
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
9
9
|
Classifier: Programming Language :: Python :: 3.10
|
10
10
|
Classifier: Programming Language :: Python :: 3.11
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -29,11 +29,12 @@ setting TDP on demand in Ryzen processors, through ACPI.
|
|
29
29
|
This means that it can be used regardless of the current memory policy
|
30
30
|
or secure-boot/lockdown status (provided the module `acpi_call` is installed.).
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
the
|
35
|
-
|
36
|
-
|
32
|
+
For the ROG Ally and Legion Go that have an ACPI/EC implementation for bios and fan curves,
|
33
|
+
Adjustor uses the manufactuer way for setting TDP.
|
34
|
+
For the ally, the asus-wmi kernel driver is used to set the tdp and manage the
|
35
|
+
fan curves.
|
36
|
+
For the go, Lenovo's WMI methods are called through `acpi_call`, which will hopefully
|
37
|
+
become part of a driver in the future.
|
37
38
|
|
38
39
|
## AMD TDP Control
|
39
40
|
Adjustor controls TDP through the Dynamic Power and Thermal Configuration Interface
|
@@ -14,12 +14,15 @@ src/adjustor.egg-info/dependency_links.txt
|
|
14
14
|
src/adjustor.egg-info/entry_points.txt
|
15
15
|
src/adjustor.egg-info/requires.txt
|
16
16
|
src/adjustor.egg-info/top_level.txt
|
17
|
+
src/adjustor/core/__init__.py
|
17
18
|
src/adjustor/core/acpi.py
|
18
19
|
src/adjustor/core/alib.py
|
19
|
-
src/adjustor/core/asus.py
|
20
20
|
src/adjustor/core/const.py
|
21
21
|
src/adjustor/core/lenovo.py
|
22
|
+
src/adjustor/core/platform.py
|
22
23
|
src/adjustor/drivers/__init__.py
|
24
|
+
src/adjustor/drivers/asus/__init__.py
|
25
|
+
src/adjustor/drivers/asus/settings.yml
|
23
26
|
src/adjustor/drivers/lenovo/__init__.py
|
24
27
|
src/adjustor/drivers/lenovo/settings.yml
|
25
28
|
src/adjustor/drivers/smu/__init__.py
|
@@ -1,50 +0,0 @@
|
|
1
|
-
from .acpi import call, read
|
2
|
-
from typing import Sequence, Literal
|
3
|
-
|
4
|
-
import logging
|
5
|
-
|
6
|
-
logger = logging.getLogger(__name__)
|
7
|
-
|
8
|
-
POINTS = [
|
9
|
-
30,
|
10
|
-
40,
|
11
|
-
50,
|
12
|
-
60,
|
13
|
-
70,
|
14
|
-
80,
|
15
|
-
90,
|
16
|
-
90,
|
17
|
-
]
|
18
|
-
|
19
|
-
MIN_CURVE = [
|
20
|
-
30,
|
21
|
-
30,
|
22
|
-
30,
|
23
|
-
45,
|
24
|
-
50,
|
25
|
-
50,
|
26
|
-
50,
|
27
|
-
50,
|
28
|
-
]
|
29
|
-
|
30
|
-
|
31
|
-
def write_fan_curve(arr: list[int]):
|
32
|
-
logger.info(f"Setting fan curve to:\n{arr}")
|
33
|
-
if len(arr) != 8:
|
34
|
-
logger.error(f"Invalid fan curve length: {len(arr)}. Should be 10.")
|
35
|
-
return False
|
36
|
-
if any(not isinstance(d, int) or d > 100 for d in arr):
|
37
|
-
logger.error(f"Curve has null value or higher than 100, not setting.")
|
38
|
-
return False
|
39
|
-
|
40
|
-
for c in (0x00110024, 0x00110025):
|
41
|
-
call(
|
42
|
-
r" \_SB_.ATKD.WMNB",
|
43
|
-
[
|
44
|
-
0,
|
45
|
-
0x53564544,
|
46
|
-
int.to_bytes(c, length=4, byteorder="little", signed=False)
|
47
|
-
+ bytes(POINTS)
|
48
|
-
+ bytes(arr),
|
49
|
-
],
|
50
|
-
)
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|