blob: c44138f58758c23fbae5a95754b4e824a34a649d [file] [log] [blame]
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpigen.h>
4#include <acpi/acpigen_dptf.h>
5#include <ec/google/common/dptf.h>
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +05306#include <drivers/intel/dptf/chip.h>
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -06007
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +05308#include "chip.h"
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -06009/*
10 * The Chrome EC is typically in charge of many system functions, including battery charging and
11 * fan PWM control. This places it in the middle of a DPTF implementation and therefore, many of
12 * the "helper" ACPI Methods themselves call EC Methods. Because of that, the responsibility for
13 * producing the corresponding AML lies here.
14 */
15
16/* DPTF Event types */
17enum {
18 TRIP_POINTS_CHANGED_EVENT = 0x81,
19 THERMAL_EVENT = 0x90,
20};
21
22/* EC constants */
23enum {
24 EC_FAN_DUTY_AUTO = 0xFF,
25};
26
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +053027/* Return the fan number as a string for the FAN participant */
28static const char *fan_num_namestring_of(enum dptf_participant participant)
29{
30 switch (participant) {
31 case DPTF_FAN:
32 return "FAN0";
33 case DPTF_FAN_2:
34 return "FAN1";
35 default:
36 return "";
37 }
38}
39
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -060040static void write_charger_PPPC(const struct device *ec)
41{
42 acpigen_write_method_serialized("PPPC", 0);
43
44 /*
45 * Convert size of PPSS table to index
46 *
47 * Store (SizeOf (PPSS), Local0)
48 * Decrement (Local0)
49 */
50 acpigen_write_store();
51 acpigen_emit_byte(SIZEOF_OP);
52 acpigen_emit_namestring("PPSS");
53 acpigen_emit_byte(LOCAL0_OP);
54 acpigen_emit_byte(DECREMENT_OP);
55 acpigen_emit_byte(LOCAL0_OP);
56
57 /*
58 * Check if charging is disabled (AC removed)
59 *
60 * If (\_SB.PCI0.LPCB.EC0.ACEX () = Zero) {
61 * Return (Local0)
62 * }
63 */
64 acpigen_write_if();
65 acpigen_emit_byte(LEQUAL_OP);
66 acpigen_emit_namestring(acpi_device_path_join(ec, "ACEX"));
67 acpigen_emit_byte(ZERO_OP);
68 acpigen_write_return_op(LOCAL0_OP);
69 acpigen_pop_len(); /* If */
70
71 /* Return highest power state (index 0) */
72 acpigen_write_return_op(ZERO_OP);
73
74 acpigen_pop_len(); /* Method */
75}
76
77static void write_charger_SPPC(const struct device *ec)
78{
79 /*
80 * SPPC - Set charger current limit
81 * Method(SPPC, 1) {
82 * Store (DeRefOf (Index (DeRefOf (Index
83 * (PPSS, ToInteger (Arg0))), 4)), Local0)
84 * \_SB.PCI0.LPCB.EC0.CHGS (Local0)
85 * }
86 */
87
88 acpigen_write_method_serialized("SPPC", 1);
89
90 /* Retrieve Control (index 4) for specified PPSS level */
91 acpigen_emit_byte(STORE_OP);
92 acpigen_emit_byte(DEREF_OP);
93 acpigen_emit_byte(INDEX_OP);
94 acpigen_emit_byte(DEREF_OP);
95 acpigen_emit_byte(INDEX_OP);
96 acpigen_emit_namestring("PPSS");
97 acpigen_write_to_integer(ARG0_OP, ZERO_OP);
98 acpigen_emit_byte(ZERO_OP); /* 3rd arg to Index */
99 acpigen_write_integer(4); /* Index */
100 acpigen_emit_byte(ZERO_OP); /* 3rd arg to Index */
101 acpigen_emit_byte(LOCAL0_OP);
102
103 /* Pass Control value to EC to limit charging */
104 acpigen_emit_namestring(acpi_device_path_join(ec, "CHGS"));
105 acpigen_emit_byte(LOCAL0_OP);
106 acpigen_pop_len(); /* Method */
107}
108
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530109static void write_fan_fst(const struct device *ec, int participant)
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600110{
111 /* TFST is a package that is used to store data from FAND */
112 acpigen_write_name("TFST");
113 acpigen_write_package(3);
114 acpigen_write_integer(0); /* Revision */
115 acpigen_write_integer(0); /* Control */
116 acpigen_write_integer(0); /* Speed */
117 acpigen_pop_len(); /* Package */
118
119 /* _FST */
120 acpigen_write_method_serialized("_FST", 0);
121 acpigen_write_store();
122 acpigen_emit_namestring(acpi_device_path_join(ec, "FAND"));
123 acpigen_emit_byte(INDEX_OP);
124 acpigen_emit_namestring("TFST");
125 acpigen_write_integer(1);
126 acpigen_emit_byte(ZERO_OP); /* 3rd arg to Index */
Sumeet Pawnikaredbbabc2022-03-14 17:13:33 +0530127 acpigen_write_store();
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530128 acpigen_emit_namestring(acpi_device_path_join(ec, fan_num_namestring_of(participant)));
Sumeet Pawnikaredbbabc2022-03-14 17:13:33 +0530129 acpigen_emit_byte(INDEX_OP);
130 acpigen_emit_namestring("TFST");
131 acpigen_write_integer(2);
132 acpigen_emit_byte(ZERO_OP);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600133 acpigen_emit_byte(RETURN_OP);
134 acpigen_emit_namestring("TFST");
135 acpigen_pop_len(); /* Method _FST */
136}
137
138static void write_fan_fsl(const struct device *ec)
139{
140 /* _FSL */
141 acpigen_write_method_serialized("_FSL", 1);
142 acpigen_write_store();
143 acpigen_emit_byte(ARG0_OP);
144 acpigen_emit_namestring(acpi_device_path_join(ec, "FAND"));
145 acpigen_pop_len(); /* Method _FSL */
146}
147
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600148/*
149 * Emit code to execute if the policy is enabled after this function is called, and also
150 * remember to manually add a acpigen_pop_len() afterwards!
151 */
152static void write_is_policy_enabled(bool enabled)
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600153{
154 /*
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600155 * Local0 = SizeOf (IDSP)
156 * Local1 = 0
157 * Local2 = 0
158 *
Tim Wawrzynczak5a1e2d32020-07-24 12:48:22 -0600159 * While (Local1 < Local0) {
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600160 * If (IDSP[Local1] == Arg0 && Arg1 == enabled) {
161 * Local2 = 1
162 * }
163 * Local1++
164 * }
165 *
166 * If (Local2 == 1) {
167 * ..........
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600168 */
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600169
170 /* Local0 = SizeOf (IDSP) */
171 acpigen_write_store();
172 acpigen_emit_byte(SIZEOF_OP);
173 acpigen_emit_namestring("IDSP");
174 acpigen_emit_byte(LOCAL0_OP);
175
176 /* Local1 = 0 (index variable) */
177 acpigen_write_store();
178 acpigen_write_zero();
179 acpigen_emit_byte(LOCAL1_OP);
180
181 /* Local2 = 0 (out variable, 1=found, 0=not found) */
182 acpigen_write_store();
183 acpigen_write_zero();
184 acpigen_emit_byte(LOCAL2_OP);
185
186 /*
187 * While (Local1 < Local0) {
188 */
189 acpigen_emit_byte(WHILE_OP);
190 acpigen_write_len_f();
Tim Wawrzynczak5a1e2d32020-07-24 12:48:22 -0600191 acpigen_emit_byte(LLESS_OP);
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600192 acpigen_emit_byte(LOCAL1_OP);
193 acpigen_emit_byte(LOCAL0_OP);
194
195 /* If (IDSP[Local1] == Arg0 && Arg1 == 1) { */
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600196 acpigen_write_if();
197 acpigen_emit_byte(LAND_OP);
198 acpigen_emit_byte(LEQUAL_OP);
199 acpigen_emit_byte(DEREF_OP);
200 acpigen_emit_byte(INDEX_OP);
201 acpigen_emit_namestring("IDSP");
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600202 acpigen_emit_byte(LOCAL1_OP);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600203 acpigen_emit_byte(ZERO_OP); /* 3rd arg of index - unused */
204 acpigen_emit_byte(ARG0_OP); /* end lequal */
205 acpigen_emit_byte(LEQUAL_OP);
206 acpigen_emit_byte(ARG1_OP);
207 acpigen_write_integer(enabled ? 1 : 0);
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600208
209 /* { Local2 = 1 } */
210 acpigen_write_store();
211 acpigen_write_one();
212 acpigen_emit_byte(LOCAL2_OP);
213 acpigen_pop_len(); /* If */
214
215 /*
216 * Local1++
217 * } # End of While
218 */
219 acpigen_emit_byte(INCREMENT_OP);
220 acpigen_emit_byte(LOCAL1_OP);
221 acpigen_pop_len(); /* While */
222
223 /*
224 * If (Local2 == 1)
225 */
226 acpigen_write_if();
227 acpigen_emit_byte(LEQUAL_OP);
228 acpigen_emit_byte(LOCAL2_OP);
229 acpigen_write_one();
230
231 /* caller must insert acpigen_pop_len() ! */
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600232}
233
234static void write_dptf_OSC(const struct device *ec)
235{
236 char name[16];
237 int i;
238
239 /*
240 * Arg0: Buffer containing UUID
241 * Arg1: "Integer containing Revision ID of buffer format", but Linux passes whether
242 * it is enabling (1) or disabling (0) the policy in Arg1.
243 * Arg2: Integer containing count of entries in Arg3
244 * Arg3: Buffer containing list of DWORD capabilities
245 * Return: Buffer containing list of DWORD capabilities
246 */
247 acpigen_write_method_serialized("_OSC", 4);
248
249 /*
250 * If the Passive Policy is enabled:
251 * 1) Disable temperature sensor trip points in the EC (replaces TINI)
252 * 2) Disable the charge limit in the EC (replaces TCHG.INIT)
253 */
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600254 write_is_policy_enabled(true);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600255 for (i = 0; i < DPTF_MAX_TSR; ++i) {
256 snprintf(name, sizeof(name), "^TSR%1d.PATD", i);
257 acpigen_emit_namestring(name);
258 }
259
260 acpigen_emit_namestring(acpi_device_path_join(ec, "CHGD"));
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600261 acpigen_pop_len(); /* If (from write_is_policy_enabled) */
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600262
263 /* If the Active Policy is disabled, disable DPTF fan control in the EC */
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600264 write_is_policy_enabled(false);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600265 acpigen_write_store();
266 acpigen_write_integer(EC_FAN_DUTY_AUTO);
267 acpigen_emit_namestring(acpi_device_path_join(ec, "FAND"));
Tim Wawrzynczakbec67312020-07-16 13:23:25 -0600268 acpigen_pop_len(); /* If (from write_is_policy_enabled) */
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600269
270 acpigen_write_return_op(ARG3_OP);
271 acpigen_pop_len(); /* Method _OSC */
272}
273
274static void write_dppm_methods(const struct device *ec)
275{
276 enum dptf_participant p;
277 char name[16];
278 int i;
279
280 acpigen_write_scope("\\_SB.DPTF");
281 write_dptf_OSC(ec);
282
283 /* TEVT */
284 if (CONFIG(EC_SUPPORTS_DPTF_TEVT)) {
Tim Wawrzynczakf5241882020-07-16 14:01:35 -0600285 acpigen_write_method("TEVT", 1);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600286
287 /* Local0 = ToInteger(Arg0) */
288 acpigen_write_to_integer(ARG0_OP, LOCAL0_OP);
Tim Wawrzynczak9234d922021-11-24 09:19:56 -0700289 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_4; ++p, ++i) {
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600290 snprintf(name, sizeof(name), "^TSR%1d", i);
291 acpigen_write_if_lequal_op_int(LOCAL0_OP, i);
292 acpigen_notify(name, THERMAL_EVENT);
293 acpigen_pop_len(); /* If */
294 }
295
296 acpigen_pop_len(); /* Method */
297 }
298
299 /* TPET */
300 acpigen_write_method("TPET", 0);
Tim Wawrzynczak9234d922021-11-24 09:19:56 -0700301 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_4; ++p, ++i) {
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600302 snprintf(name, sizeof(name), "^TSR%1d", i);
303 acpigen_notify(name, TRIP_POINTS_CHANGED_EVENT);
304 }
305
306 acpigen_pop_len(); /* Method */
307 acpigen_pop_len(); /* Scope */
308}
309
310static void write_charger_methods(const struct device *ec)
311{
312 dptf_write_scope(DPTF_CHARGER);
313 write_charger_PPPC(ec);
314 write_charger_SPPC(ec);
315 acpigen_pop_len(); /* Scope */
316}
317
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530318static void write_fan_methods(const struct device *ec, int participant)
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600319{
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530320 dptf_write_scope(participant);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600321 write_fan_fsl(ec);
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530322 write_fan_fst(ec, participant);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600323 acpigen_pop_len(); /* Scope */
324}
325
326static void write_thermal_methods(const struct device *ec, enum dptf_participant participant,
327 int tsr_index)
328{
329 dptf_write_scope(participant);
330
Tim Wawrzynczakf5241882020-07-16 14:01:35 -0600331 /*
332 * GTSH - Amount of hysteresis inherent in temperature reading (2 degrees, in units of
333 * 1/10th degree K)
334 */
335 acpigen_write_name_integer("GTSH", 20);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600336
337 /* _TMP - read temperature from EC */
338 acpigen_write_method_serialized("_TMP", 0);
339 acpigen_emit_byte(RETURN_OP);
340 acpigen_emit_namestring(acpi_device_path_join(ec, "TSRD"));
341 acpigen_write_integer(tsr_index);
342 acpigen_pop_len(); /* Method _TMP */
343
344 /* PATC - Aux trip point count */
345 acpigen_write_name_integer("PATC", 2);
346
347 /* PAT0 - Set Aux trip point 0 */
348 acpigen_write_method_serialized("PAT0", 1);
349 acpigen_emit_namestring(acpi_device_path_join(ec, "PAT0"));
350 acpigen_write_integer(tsr_index);
351 acpigen_emit_byte(ARG0_OP);
352 acpigen_pop_len(); /* Method PAT0 */
353
354 /* PAT1 - Set Aux trip point 1 */
355 acpigen_write_method_serialized("PAT1", 1);
356 acpigen_emit_namestring(acpi_device_path_join(ec, "PAT1"));
357 acpigen_write_integer(tsr_index);
358 acpigen_emit_byte(ARG0_OP);
359 acpigen_pop_len(); /* Method PAT0 */
360
361 /* PATD - Disable Aux trip point */
362 acpigen_write_method_serialized("PATD", 0);
363 acpigen_emit_namestring(acpi_device_path_join(ec, "PATD"));
364 acpigen_write_integer(tsr_index);
365 acpigen_pop_len(); /* Method PAT0 */
366
367 acpigen_pop_len(); /* Scope */
368}
369
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530370void ec_fill_dptf_helpers(const struct device *ec, const struct device *fan_dev)
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600371{
372 enum dptf_participant p;
373 int i;
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530374 struct ec_google_chromeec_config *config = fan_dev->chip_info;
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600375
376 write_dppm_methods(ec);
377 write_charger_methods(ec);
Sumeet Pawnikar2f7fa552022-06-08 17:43:36 +0530378
379 if (config->ec_multifan_support) {
380 for (p = DPTF_FAN; p <= DPTF_FAN_2; ++p)
381 write_fan_methods(ec, p);
382 } else
383 write_fan_methods(ec, DPTF_FAN);
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600384
Tim Wawrzynczak9234d922021-11-24 09:19:56 -0700385 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_4; ++p, ++i)
Tim Wawrzynczak93d7bcb2020-05-29 15:44:25 -0600386 write_thermal_methods(ec, p, i);
387}