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