1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <acpi/acpigen.h>
4 #include <acpi/acpigen_dptf.h>
9 #define DEFAULT_RAW_UNIT "ma"
11 /* DPTF-specific UUIDs */
12 #define DPTF_PASSIVE_POLICY_1_0_UUID "42A441D6-AE6A-462B-A84B-4A8CE79027D3"
13 #define DPTF_CRITICAL_POLICY_UUID "97C68AE7-15FA-499c-B8C9-5DA81D606E0A"
14 #define DPTF_ACTIVE_POLICY_UUID "3A95C389-E4B8-4629-A526-C52C88626BAE"
18 DEFAULT_PRIORITY
= 100,
19 DEFAULT_TRIP_POINT
= 0xFFFFFFFFull
,
21 DPTF_MAX_ART_THRESHOLDS
= 10,
28 /* Convert degrees C to 1/10 degree Kelvin for ACPI */
29 static int to_acpi_temp(int deg_c
)
31 return deg_c
* 10 + 2732;
34 /* Converts ms to 1/10th second for ACPI */
35 static int to_acpi_time(int ms
)
40 /* Writes out a 0-argument non-Serialized Method that returns an Integer */
41 static void write_simple_return_method(const char *name
, int value
)
43 acpigen_write_method(name
, 0);
44 acpigen_write_return_integer(value
);
45 acpigen_pop_len(); /* Method */
48 /* Writes out 'count' ZEROs in a row */
49 static void write_zeros(int count
)
51 for (; count
; --count
)
52 acpigen_write_integer(0);
55 /* Return the assigned namestring of any participant */
56 static const char *namestring_of(enum dptf_participant participant
)
58 switch (participant
) {
65 case DPTF_TEMP_SENSOR_0
:
67 case DPTF_TEMP_SENSOR_1
:
69 case DPTF_TEMP_SENSOR_2
:
71 case DPTF_TEMP_SENSOR_3
:
73 case DPTF_TEMP_SENSOR_4
:
86 /* Helper to get Scope for participants underneath \_SB.DPTF */
87 static const char *scope_of(enum dptf_participant participant
)
89 static char scope
[16];
91 if (participant
== DPTF_CPU
)
92 snprintf(scope
, sizeof(scope
), TCPU_SCOPE
".%s", namestring_of(participant
));
94 snprintf(scope
, sizeof(scope
), DPTF_DEVICE_PATH
".%s",
95 namestring_of(participant
));
101 * Most of the DPTF participants are underneath the \_SB.DPTF scope, so we can just get away
102 * with using the simple namestring for references, but the TCPU has a different scope, so
103 * either an absolute or relative path must be used instead.
105 static const char *path_of(enum dptf_participant participant
)
107 if (participant
== DPTF_CPU
)
108 return scope_of(participant
);
110 return namestring_of(participant
);
113 /* Write out scope of a participant */
114 void dptf_write_scope(enum dptf_participant participant
)
116 acpigen_write_scope(scope_of(participant
));
120 * This table describes active cooling relationships between the system's fan and the
121 * temperature sensors that it can have an effect on. As ever-increasing temperature thresholds
122 * are crossed (_AC9.._AC0, low to high), the corresponding fan percentages listed in this table
123 * are used to increase the speed of the fan in order to speed up cooling.
125 static void write_active_relationship_table(const struct dptf_active_policy
*policies
,
132 if (!max_count
|| policies
[0].target
== DPTF_NONE
)
135 acpigen_write_scope(DPTF_DEVICE_PATH
);
136 acpigen_write_method("_ART", 0);
138 /* Return this package */
139 acpigen_emit_byte(RETURN_OP
);
141 /* Keep track of items added to the package */
142 pkg_count
= acpigen_write_package(1); /* The '1' here is for the revision */
143 acpigen_write_integer(ART_REVISION
);
145 for (i
= 0; i
< max_count
; ++i
) {
147 * These have to be filled out from AC0 down to AC9, filling in only as many
148 * as are used. As soon as one isn't filled in, we're done.
150 if (policies
[i
].target
== DPTF_NONE
)
155 /* Source, Target, Percent, Fan % for each of _AC0 ... _AC9 */
156 acpigen_write_package(13);
157 acpigen_emit_namestring(path_of(DPTF_FAN
));
158 acpigen_emit_namestring(path_of(policies
[i
].target
));
159 acpigen_write_integer(DEFAULT_IF_0(policies
[i
].weight
, DEFAULT_WEIGHT
));
161 /* Write out fan %; corresponds with target's _ACx methods */
162 for (j
= 0; j
< DPTF_MAX_ART_THRESHOLDS
; ++j
)
163 acpigen_write_integer(policies
[i
].thresholds
[j
].fan_pct
);
165 acpigen_pop_len(); /* inner Package */
168 acpigen_pop_len(); /* outer Package */
169 acpigen_pop_len(); /* Method _ART */
170 acpigen_pop_len(); /* Scope */
174 * _AC9 through _AC0 represent temperature thresholds, in increasing order, defined from _AC0
175 * down, that, when reached, DPTF will activate TFN1 in order to actively cool the temperature
176 * sensor(s). As increasing thresholds are reached, the fan is spun faster.
178 static void write_active_cooling_methods(const struct dptf_active_policy
*policies
,
185 if (!max_count
|| policies
[0].target
== DPTF_NONE
)
188 for (i
= 0; i
< max_count
; ++i
) {
189 if (policies
[i
].target
== DPTF_NONE
)
192 dptf_write_scope(policies
[i
].target
);
194 /* Write out as many of _AC0 through _AC9 that are applicable */
195 for (j
= 0; j
< DPTF_MAX_ACX
; ++j
) {
196 if (!policies
[i
].thresholds
[j
].temp
)
199 snprintf(name
, sizeof(name
), "_AC%1X", j
);
200 write_simple_return_method(name
, to_acpi_temp(
201 policies
[i
].thresholds
[j
].temp
));
204 acpigen_pop_len(); /* Scope */
208 void dptf_write_active_policies(const struct dptf_active_policy
*policies
, int max_count
)
210 write_active_relationship_table(policies
, max_count
);
211 write_active_cooling_methods(policies
, max_count
);
215 * This writes out the Thermal Relationship Table, which describes the thermal relationships
216 * between participants in a thermal zone. This information is used to passively cool (i.e.,
217 * throttle) the Source (source of heat), in order to indirectly cool the Target (temperature
220 static void write_thermal_relationship_table(const struct dptf_passive_policy
*policies
,
227 if (!max_count
|| policies
[0].source
== DPTF_NONE
)
230 acpigen_write_scope(DPTF_DEVICE_PATH
);
233 * A _TRT Revision (TRTR) of 1 means that the 'Priority' field is an arbitrary priority
234 * value to be used for this specific relationship. The priority value determines the
235 * order in which various sources are used in a passive thermal action for a given
238 acpigen_write_name_integer("TRTR", 1);
240 /* Thermal Relationship Table */
241 acpigen_write_method("_TRT", 0);
243 /* Return this package */
244 acpigen_emit_byte(RETURN_OP
);
245 pkg_count
= acpigen_write_package(0);
247 for (i
= 0; i
< max_count
; ++i
) {
248 /* Stop writing the table once an entry is empty */
249 if (policies
[i
].source
== DPTF_NONE
)
252 /* Keep track of outer package item count */
255 acpigen_write_package(8);
257 /* Source, Target, Priority, Sampling Period */
258 acpigen_emit_namestring(path_of(policies
[i
].source
));
259 acpigen_emit_namestring(path_of(policies
[i
].target
));
260 acpigen_write_integer(DEFAULT_IF_0(policies
[i
].priority
, DEFAULT_PRIORITY
));
261 acpigen_write_integer(to_acpi_time(policies
[i
].period
));
266 acpigen_pop_len(); /* Package */
269 acpigen_pop_len(); /* Package */
270 acpigen_pop_len(); /* Method */
271 acpigen_pop_len(); /* Scope */
275 * When a temperature sensor measures above its the temperature returned in its _PSV Method,
276 * DPTF will begin throttling Sources in order to indirectly cool the sensor.
278 static void write_all_PSV(const struct dptf_passive_policy
*policies
, int max_count
)
282 for (i
= 0; i
< max_count
; ++i
) {
283 if (policies
[i
].source
== DPTF_NONE
)
286 dptf_write_scope(policies
[i
].target
);
287 write_simple_return_method("_PSV", to_acpi_temp(policies
[i
].temp
));
288 acpigen_pop_len(); /* Scope */
292 void dptf_write_passive_policies(const struct dptf_passive_policy
*policies
, int max_count
)
294 write_thermal_relationship_table(policies
, max_count
);
295 write_all_PSV(policies
, max_count
);
298 void dptf_write_critical_policies(const struct dptf_critical_policy
*policies
, int max_count
)
302 for (i
= 0; i
< max_count
; ++i
) {
303 if (policies
[i
].source
== DPTF_NONE
)
306 dptf_write_scope(policies
[i
].source
);
308 /* Choose _CRT or _HOT */
309 write_simple_return_method(policies
[i
].type
== DPTF_CRITICAL_SHUTDOWN
?
310 "_CRT" : "_HOT", to_acpi_temp(policies
[i
].temp
));
312 acpigen_pop_len(); /* Scope */
316 void dptf_write_charger_perf(const struct dptf_charger_perf
*states
, int max_count
)
321 if (!max_count
|| !states
[0].control
)
324 dptf_write_scope(DPTF_CHARGER
);
326 /* PPSS - Participant Performance Supported States */
327 acpigen_write_method("PPSS", 0);
328 acpigen_emit_byte(RETURN_OP
);
330 pkg_count
= acpigen_write_package(0);
331 for (i
= 0; i
< max_count
; ++i
) {
332 if (!states
[i
].control
)
338 * 0, 0, 0, 0, # Reserved
339 * Control, Raw Performance, Raw Unit, 0 # Reserved
341 acpigen_write_package(8);
343 acpigen_write_integer(states
[i
].control
);
344 acpigen_write_integer(states
[i
].raw_perf
);
345 acpigen_write_string(DEFAULT_RAW_UNIT
);
346 acpigen_write_integer(0);
347 acpigen_pop_len(); /* inner Package */
350 acpigen_pop_len(); /* outer Package */
351 acpigen_pop_len(); /* Method PPSS */
352 acpigen_pop_len(); /* Scope */
355 void dptf_write_fan_perf(const struct dptf_fan_perf
*states
, int max_count
)
360 if (!max_count
|| !states
[0].percent
)
363 dptf_write_scope(DPTF_FAN
);
365 /* _FPS - Fan Performance States */
366 acpigen_write_name("_FPS");
367 pkg_count
= acpigen_write_package(1); /* 1 for Revision */
368 acpigen_write_integer(FPS_REVISION
); /* revision */
370 for (i
= 0; i
< max_count
; ++i
) {
372 * Some _FPS tables do include a last entry where Percent is 0, but Power is
373 * called out, so this table is finished when both are zero.
375 if (!states
[i
].percent
&& !states
[i
].power
)
379 acpigen_write_package(5);
380 acpigen_write_integer(states
[i
].percent
);
381 acpigen_write_integer(DEFAULT_TRIP_POINT
);
382 acpigen_write_integer(states
[i
].speed
);
383 acpigen_write_integer(states
[i
].noise_level
);
384 acpigen_write_integer(states
[i
].power
);
385 acpigen_pop_len(); /* inner Package */
388 acpigen_pop_len(); /* Package */
389 acpigen_pop_len(); /* Scope */
392 void dptf_write_power_limits(const struct dptf_power_limits
*limits
)
397 if (!limits
->pl1
.min_power
&& !limits
->pl2
.min_power
)
400 dptf_write_scope(DPTF_CPU
);
401 acpigen_write_method("PPCC", 0);
403 acpigen_emit_byte(RETURN_OP
);
405 pkg_count
= acpigen_write_package(1); /* 1 for the Revision */
406 acpigen_write_integer(PPCC_REVISION
); /* revision */
408 if (limits
->pl1
.min_power
) {
410 acpigen_write_package(6);
411 acpigen_write_integer(RAPL_PL1_INDEX
);
412 acpigen_write_integer(limits
->pl1
.min_power
);
413 acpigen_write_integer(limits
->pl1
.max_power
);
414 acpigen_write_integer(limits
->pl1
.time_window_min
);
415 acpigen_write_integer(limits
->pl1
.time_window_max
);
416 acpigen_write_integer(limits
->pl1
.granularity
);
417 acpigen_pop_len(); /* inner Package */
420 if (limits
->pl2
.min_power
) {
422 acpigen_write_package(6);
423 acpigen_write_integer(RAPL_PL2_INDEX
);
424 acpigen_write_integer(limits
->pl2
.min_power
);
425 acpigen_write_integer(limits
->pl2
.max_power
);
426 acpigen_write_integer(limits
->pl2
.time_window_min
);
427 acpigen_write_integer(limits
->pl2
.time_window_max
);
428 acpigen_write_integer(limits
->pl2
.granularity
);
429 acpigen_pop_len(); /* inner Package */
432 acpigen_pop_len(); /* outer Package */
433 acpigen_pop_len(); /* Method */
434 acpigen_pop_len(); /* Scope */
437 void dptf_write_STR(const char *str
)
442 acpigen_write_name_string("_STR", str
);
445 void dptf_write_fan_options(bool fine_grained
, int step_size
, bool low_speed_notify
)
447 acpigen_write_name("_FIF");
448 acpigen_write_package(4);
450 acpigen_write_integer(0); /* Revision */
451 acpigen_write_integer(fine_grained
);
452 acpigen_write_integer(step_size
);
453 acpigen_write_integer(low_speed_notify
);
454 acpigen_pop_len(); /* Package */
457 void dptf_write_tsr_hysteresis(uint8_t hysteresis
)
462 acpigen_write_name_integer("GTSH", hysteresis
);
465 void dptf_write_enabled_policies(const struct dptf_active_policy
*active_policies
,
467 const struct dptf_passive_policy
*passive_policies
,
469 const struct dptf_critical_policy
*critical_policies
,
473 bool is_passive_used
;
474 bool is_critical_used
;
477 is_active_used
= (active_count
&& active_policies
[0].target
!= DPTF_NONE
);
478 is_passive_used
= (passive_count
&& passive_policies
[0].target
!= DPTF_NONE
);
479 is_critical_used
= (critical_count
&& critical_policies
[0].source
!= DPTF_NONE
);
480 pkg_count
= is_active_used
+ is_passive_used
+ is_critical_used
;
485 acpigen_write_scope(DPTF_DEVICE_PATH
);
486 acpigen_write_name("IDSP");
487 acpigen_write_package(pkg_count
);
490 acpigen_write_uuid(DPTF_ACTIVE_POLICY_UUID
);
493 acpigen_write_uuid(DPTF_PASSIVE_POLICY_1_0_UUID
);
495 if (is_critical_used
)
496 acpigen_write_uuid(DPTF_CRITICAL_POLICY_UUID
);
498 acpigen_pop_len(); /* Package */
499 acpigen_pop_len(); /* Scope */