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.
Files changed (27) hide show
  1. adjustor-0.2.0/MANIFEST.in +2 -0
  2. {adjustor-0.1.0/src/adjustor.egg-info → adjustor-0.2.0}/PKG-INFO +20 -7
  3. {adjustor-0.1.0 → adjustor-0.2.0}/pyproject.toml +1 -1
  4. {adjustor-0.1.0 → adjustor-0.2.0}/readme.md +19 -6
  5. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/const.py +13 -1
  6. adjustor-0.2.0/src/adjustor/drivers/lenovo/settings.yml +152 -0
  7. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/drivers/smu/__init__.py +58 -30
  8. adjustor-0.2.0/src/adjustor/drivers/smu/qam.yml +27 -0
  9. adjustor-0.2.0/src/adjustor/drivers/smu/smu.yml +155 -0
  10. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/hhd.py +31 -15
  11. adjustor-0.2.0/src/adjustor/settings.yml +21 -0
  12. {adjustor-0.1.0 → adjustor-0.2.0/src/adjustor.egg-info}/PKG-INFO +20 -7
  13. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/SOURCES.txt +6 -1
  14. {adjustor-0.1.0 → adjustor-0.2.0}/LICENSE +0 -0
  15. {adjustor-0.1.0 → adjustor-0.2.0}/setup.cfg +0 -0
  16. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/__init__.py +0 -0
  17. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/__main__.py +0 -0
  18. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/acpi.py +0 -0
  19. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/alib.py +0 -0
  20. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/asus.py +0 -0
  21. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/core/lenovo.py +0 -0
  22. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/drivers/__init__.py +0 -0
  23. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor/drivers/lenovo/__init__.py +0 -0
  24. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/dependency_links.txt +0 -0
  25. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/entry_points.txt +0 -0
  26. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/requires.txt +0 -0
  27. {adjustor-0.1.0 → adjustor-0.2.0}/src/adjustor.egg-info/top_level.txt +0 -0
@@ -0,0 +1,2 @@
1
+ recursive-include src/adjustor *.yml
2
+ recursive-include src/adjustor *.yaml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: adjustor
3
- Version: 0.1.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 function is part of the ACPI ASL library, and provided through the
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
- ALIB does not provide a way for reading the performance metrics table, so
47
- Adjustor can only write TDP values.
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
- Installation instructions coming the following days.
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,6 +1,6 @@
1
1
  [project]
2
2
  name = "adjustor"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  authors = [
5
5
  { name="Kapenekakis Antheas", email="pypi@antheas.dev" },
6
6
  ]
@@ -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 function is part of the ACPI ASL library, and provided through the
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
- ALIB does not provide a way for reading the performance metrics table, so
30
- Adjustor can only write TDP values.
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
- Installation instructions coming the following days.
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 7800U": (DEV_PARAMS_7040, ALIB_PARAMS_7040),
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, dev: dict[str, DeviceParams], platform_profile: bool = True
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
- conf["tdp.smu.status"] = "Not Set"
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
- conf["tdp.smu.status"] = "Set"
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
- return {"tdp": {"general": load_relative_yaml("settings.yml")}}
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
- os.environ.get("HHD_ADJ_DEBUG")
102
- or os.environ.get("HHD_ENABLE_SMU")
103
- or not drivers_matched
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
- SmuQamPlugin(
123
+ SmuDriverPlugin(
110
124
  dev,
111
- platform_profile=(
112
- not legion_go or bool(os.environ.get("HHD_ADJ_DEBUG"))
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.1.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 function is part of the ACPI ASL library, and provided through the
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
- ALIB does not provide a way for reading the performance metrics table, so
47
- Adjustor can only write TDP values.
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
- Installation instructions coming the following days.
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/smu/__init__.py
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