• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpigen.h>
4 #include <acpi/acpigen_pci.h>
5 #include <console/console.h>
6 #include <device/device.h>
7 #include <intelblocks/pmc_ipc.h>
8 #include <stdio.h>
9 #include <soc/dptf.h>
10 #include <soc/pci_devs.h>
11 #include "chip.h"
12 #include "dptf.h"
13 
14 /* Generic DPTF participants have a PTYP field to distinguish them */
15 enum dptf_generic_participant_type {
16 	DPTF_GENERIC_PARTICIPANT_TYPE_TSR	= 0x3,
17 	DPTF_GENERIC_PARTICIPANT_TYPE_FAN	= 0x4,
18 	DPTF_GENERIC_PARTICIPANT_TYPE_TPCH	= 0x5,
19 	DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER	= 0xB,
20 	DPTF_GENERIC_PARTICIPANT_TYPE_BATTERY	= 0xC,
21 	DPTF_GENERIC_PARTICIPANT_TYPE_POWER	= 0x11,
22 };
23 
24 #define DEFAULT_CHARGER_STR		"Battery Charger"
25 #define DEFAULT_TPCH_STR		"Intel PCH FIVR Participant"
26 #define DEFAULT_POWER_STR		"Power Participant"
27 #define DEFAULT_BATTERY_STR		"Battery Participant"
28 #define DEFAULT_FAN_STR			"Fan Participant"
29 
30 #define PMC_IPC_COMMAND_FIVR_SIZE	0x8
31 
32 /*
33  * Helper method to determine if a device is "used" (called out anywhere as a source or a target
34  * of any policies, and therefore should be included in the ACPI tables.
35  */
is_participant_used(const struct drivers_intel_dptf_config * config,enum dptf_participant participant)36 static bool is_participant_used(const struct drivers_intel_dptf_config *config,
37 				enum dptf_participant participant)
38 {
39 	int i;
40 
41 	/* Active? */
42 	for (i = 0; i < DPTF_MAX_ACTIVE_POLICIES; ++i)
43 		if (config->policies.active[i].target == participant)
44 			return true;
45 
46 	/* Passive? */
47 	for (i = 0; i < DPTF_MAX_PASSIVE_POLICIES; ++i)
48 		if (config->policies.passive[i].source == participant ||
49 		    config->policies.passive[i].target == participant)
50 			return true;
51 
52 	/* Critical? */
53 	for (i = 0; i < DPTF_MAX_CRITICAL_POLICIES; ++i)
54 		if (config->policies.critical[i].source == participant)
55 			return true;
56 
57 	/* Check fan as well (its use is implicit in the Active policy) */
58 	if ((participant == DPTF_FAN || participant == DPTF_FAN_2) &&
59 		config->policies.active[0].target != DPTF_NONE)
60 		return true;
61 
62 	return false;
63 }
64 
65 /* Return the assigned namestring of the FAN participant */
fan_namestring_of(enum dptf_participant participant)66 static const char *fan_namestring_of(enum dptf_participant participant)
67 {
68 	switch (participant) {
69 	case DPTF_FAN:
70 		return "TFN1";
71 	case DPTF_FAN_2:
72 		return "TFN2";
73 	default:
74 		return "";
75 	}
76 }
77 
dptf_acpi_name(const struct device * dev)78 static const char *dptf_acpi_name(const struct device *dev)
79 {
80 	return "DPTF";
81 }
82 
get_STA_value(const struct drivers_intel_dptf_config * config,enum dptf_participant participant)83 static int get_STA_value(const struct drivers_intel_dptf_config *config,
84 			 enum dptf_participant participant)
85 {
86 	return is_participant_used(config, participant) ?
87 		ACPI_STATUS_DEVICE_ALL_ON :
88 		ACPI_STATUS_DEVICE_ALL_OFF;
89 }
90 
dptf_write_hid(bool is_eisa,const char * hid)91 static void dptf_write_hid(bool is_eisa, const char *hid)
92 {
93 	if (is_eisa)
94 		acpigen_emit_eisaid(hid);
95 	else
96 		acpigen_write_string(hid);
97 }
98 
99 /* Devices with GENERIC _HID (distinguished by PTYP) */
dptf_write_generic_participant(const char * name,enum dptf_generic_participant_type ptype,const char * str,int sta_val,const struct dptf_platform_info * platform_info)100 static void dptf_write_generic_participant(const char *name,
101 					   enum dptf_generic_participant_type ptype,
102 					   const char *str, int sta_val,
103 					   const struct dptf_platform_info *platform_info)
104 {
105 	/* Auto-incrementing UID for generic participants */
106 	static int generic_uid = 0;
107 
108 	acpigen_write_device(name);
109 	acpigen_write_name("_HID");
110 	dptf_write_hid(platform_info->use_eisa_hids, platform_info->generic_hid);
111 
112 	acpigen_write_name_integer("_UID", generic_uid++);
113 	acpigen_write_STA(sta_val);
114 
115 	if (str)
116 		acpigen_write_name_unicode("_STR", str);
117 
118 	acpigen_write_name_integer("PTYP", ptype);
119 
120 	acpigen_pop_len(); /* Device */
121 }
122 
123 /* \_SB.PCI0.TCPU */
write_tcpu(const struct device * pci_dev,const struct drivers_intel_dptf_config * config)124 static void write_tcpu(const struct device *pci_dev,
125 		       const struct drivers_intel_dptf_config *config)
126 {
127 	/* DPTF CPU device - \_SB.PCI0.TCPU */
128 	acpigen_write_scope(TCPU_SCOPE);
129 	acpigen_write_device("TCPU");
130 	acpigen_write_ADR_pci_device(pci_dev);
131 	acpigen_write_STA(get_STA_value(config, DPTF_CPU));
132 	acpigen_pop_len(); /* Device */
133 	acpigen_pop_len(); /* TCPU Scope */
134 }
135 
136 /* \_SB.DPTF.TFNx */
write_fan(const struct drivers_intel_dptf_config * config,const struct dptf_platform_info * platform_info,enum dptf_participant participant)137 static void write_fan(const struct drivers_intel_dptf_config *config,
138 			const struct dptf_platform_info *platform_info,
139 			enum dptf_participant participant)
140 {
141 	static int fan_uid = 0;
142 
143 	acpigen_write_device(fan_namestring_of(participant));
144 	acpigen_write_name("_HID");
145 	dptf_write_hid(platform_info->use_eisa_hids, platform_info->fan_hid);
146 	acpigen_write_name_integer("_UID", fan_uid++);
147 	acpigen_write_name_unicode("_STR", DEFAULT_FAN_STR);
148 	acpigen_write_name_integer("PTYP", DPTF_GENERIC_PARTICIPANT_TYPE_FAN);
149 	acpigen_write_STA(get_STA_value(config, participant));
150 	acpigen_pop_len(); /* Device */
151 }
152 
153 /* \_SB.DPTF */
write_imok(void)154 static void write_imok(void)
155 {
156 	acpigen_write_method("IMOK", 1);
157 	/* Return (Arg0) */
158 	acpigen_emit_byte(RETURN_OP);
159 	acpigen_emit_byte(ARG0_OP);
160 	acpigen_write_method_end();
161 }
162 
write_dcfg_variable(const struct drivers_intel_dptf_config * config)163 static void write_dcfg_variable(const struct drivers_intel_dptf_config *config)
164 {
165 	acpigen_write_name_integer("DCFG", config->dcfg);
166 }
167 
168 /* \_SB.DPTF */
write_oem_variables(const struct drivers_intel_dptf_config * config)169 static void write_oem_variables(const struct drivers_intel_dptf_config *config)
170 {
171 	int i;
172 
173 	acpigen_write_name("ODVX");
174 	acpigen_write_package(DPTF_OEM_VARIABLE_COUNT);
175 	for (i = 0; i < DPTF_OEM_VARIABLE_COUNT; i++)
176 		acpigen_write_dword(config->oem_data.oem_variables[i]);
177 	acpigen_write_package_end();
178 
179 	/*
180 	 * Method (ODUP, 2)
181 	 * Arg0 = Index of ODVX to update
182 	 * Arg1 = Value to place in ODVX[Arg0]
183 	 */
184 	acpigen_write_method_serialized("ODUP", 2);
185 	/* ODVX[Arg0] = Arg1 */
186 	acpigen_write_store();
187 	acpigen_emit_byte(ARG1_OP);
188 	acpigen_emit_byte(INDEX_OP);
189 	acpigen_emit_namestring("ODVX");
190 	acpigen_emit_byte(ARG0_OP);
191 	acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
192 	acpigen_write_method_end();
193 
194 	/*
195 	 * Method (ODGT, 1)
196 	 * Arg0 = Index of ODVX to get
197 	 */
198 	acpigen_write_method_serialized("ODGT", 1);
199 	 /* Return (ODVX[Arg0]) */
200 	acpigen_emit_byte(RETURN_OP);
201 	acpigen_emit_byte(DEREF_OP);
202 	acpigen_emit_byte(INDEX_OP);
203 	acpigen_emit_namestring("ODVX");
204 	acpigen_emit_byte(ARG0_OP);
205 	acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
206 	acpigen_write_method_end();
207 
208 	/* Method (ODVP) { Return (ODVX) } */
209 	acpigen_write_method_serialized("ODVP", 0);
210 	acpigen_emit_byte(RETURN_OP);
211 	acpigen_emit_namestring("ODVX");
212 	acpigen_write_method_end();
213 }
214 
215 /* \_SB.DPTF.xxxx */
write_generic_devices(const struct drivers_intel_dptf_config * config,const struct dptf_platform_info * platform_info)216 static void write_generic_devices(const struct drivers_intel_dptf_config *config,
217 				  const struct dptf_platform_info *platform_info)
218 {
219 	enum dptf_participant participant;
220 	char name[ACPI_NAME_BUFFER_SIZE];
221 	int i;
222 
223 	dptf_write_generic_participant("TCHG", DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER,
224 				       DEFAULT_CHARGER_STR,
225 				       get_STA_value(config, DPTF_CHARGER),
226 				       platform_info);
227 
228 	for (i = 0, participant = DPTF_TEMP_SENSOR_0; i < DPTF_MAX_TSR; ++i, ++participant) {
229 		snprintf(name, sizeof(name), "TSR%1d", i);
230 		dptf_write_generic_participant(name, DPTF_GENERIC_PARTICIPANT_TYPE_TSR,
231 					       NULL, get_STA_value(config, participant),
232 					       platform_info);
233 	}
234 }
235 
get_pmc_ipcs_method(void)236 static const char *get_pmc_ipcs_method(void)
237 {
238 	const char *method = acpi_device_path_join(
239 				pcidev_path_on_root(PCH_DEVFN_PMC), "IPCS");
240 	if (!method) {
241 		printk(BIOS_ERR, "%s: Unable to find PMC device IPCS method\n", __func__);
242 		return NULL;
243 	}
244 	return method;
245 }
246 
write_tpch_write_method(const char * tpch_write_method_name,unsigned int ipc_subcmd_ctrl_value)247 static void write_tpch_write_method(const char *tpch_write_method_name,
248 				unsigned int ipc_subcmd_ctrl_value)
249 {
250 	/* Get IPCS method from the PMC device */
251 	const char *ipcs = get_pmc_ipcs_method();
252 	acpigen_write_method_serialized(tpch_write_method_name, 1);
253 	acpigen_emit_namestring(ipcs);
254 	acpigen_write_integer(PMC_IPC_CMD_COMMAND_FIVR);
255 	acpigen_write_integer(PMC_IPC_CMD_CMD_ID_FIVR_WRITE);
256 	acpigen_write_integer(PMC_IPC_COMMAND_FIVR_SIZE);
257 	acpigen_write_integer(ipc_subcmd_ctrl_value);
258 	acpigen_emit_byte(ARG0_OP);
259 	acpigen_write_zero();
260 	acpigen_write_zero();
261 	/* The reason for returning a value here is a W/A for the ESIF shell */
262 	acpigen_emit_byte(RETURN_OP);
263 	acpigen_write_package(1);
264 	acpigen_write_zero();
265 	acpigen_write_package_end();
266 	acpigen_write_method_end();
267 }
268 
write_ppkg_package(const uint8_t i)269 static void write_ppkg_package(const uint8_t i)
270 {
271 	acpigen_write_store();
272 	acpigen_emit_byte(DEREF_OP);
273 	acpigen_emit_byte(INDEX_OP);
274 	acpigen_emit_byte(ARG0_OP);
275 	acpigen_write_integer(i);
276 	acpigen_emit_byte(ZERO_OP);
277 	acpigen_emit_byte(INDEX_OP);
278 	acpigen_emit_namestring("PPKG");
279 	acpigen_write_integer(i);
280 	acpigen_emit_byte(ZERO_OP);
281 }
282 
283 /*
284  * Truncate Package received from IPC
285  * Arguments:
286  *  Arg0: Package returned from the IPCS read call from the Pmc
287  * Return Value:
288  *  Return Package with just the Status and ReadBuf0
289  *  Status returns 0 for success and 2 for device error
290  */
write_pkgc_method(void)291 static void write_pkgc_method(void)
292 {
293 	acpigen_write_method_serialized("PKGC", 1);
294 	acpigen_write_name("PPKG");
295 	acpigen_write_package(2);
296 	acpigen_write_zero();
297 	acpigen_write_zero();
298 	acpigen_write_package_end();
299 
300 	write_ppkg_package(0);
301 	write_ppkg_package(1);
302 
303 	acpigen_write_return_namestr("PPKG");
304 	acpigen_write_method_end();
305 }
306 
write_tpch_read_method(const char * tpch_read_method_name,unsigned int ipc_subcmd_ctrl_value)307 static void write_tpch_read_method(const char *tpch_read_method_name,
308 				unsigned int ipc_subcmd_ctrl_value)
309 {
310 	/* Get IPCS method from the PMC device */
311 	const char *ipcs = get_pmc_ipcs_method();
312 	acpigen_write_method_serialized(tpch_read_method_name, 0);
313 	acpigen_write_store();
314 	acpigen_emit_namestring(ipcs);
315 	acpigen_write_integer(PMC_IPC_CMD_COMMAND_FIVR);
316 	acpigen_write_integer(PMC_IPC_CMD_CMD_ID_FIVR_READ);
317 	acpigen_write_integer(PMC_IPC_COMMAND_FIVR_SIZE);
318 	acpigen_write_integer(ipc_subcmd_ctrl_value);
319 	acpigen_write_zero();
320 	acpigen_write_zero();
321 	acpigen_write_zero();
322 	acpigen_emit_byte(LOCAL0_OP);
323 
324 	acpigen_write_store();
325 	acpigen_emit_namestring("PKGC");
326 	acpigen_emit_byte(LOCAL0_OP);
327 	acpigen_emit_byte(LOCAL1_OP);
328 
329 	acpigen_emit_byte(RETURN_OP);
330 	acpigen_emit_byte(LOCAL1_OP);
331 	acpigen_write_method_end();
332 }
333 
write_create_tpch(const struct dptf_platform_info * platform_info)334 static void write_create_tpch(const struct dptf_platform_info *platform_info)
335 {
336 	acpigen_write_device("TPCH");
337 	acpigen_write_name("_HID");
338 	dptf_write_hid(platform_info->use_eisa_hids, platform_info->tpch_device_hid);
339 	acpigen_write_name_unicode("_STR", DEFAULT_TPCH_STR);
340 	acpigen_write_name_integer("PTYP", DPTF_GENERIC_PARTICIPANT_TYPE_TPCH);
341 	acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
342 }
343 
write_tpch_methods(const struct dptf_platform_info * platform_info)344 static void write_tpch_methods(const struct dptf_platform_info *platform_info)
345 {
346 	write_create_tpch(platform_info);
347 
348 	const struct {
349 		enum { READ, WRITE } type;
350 		const char *method_name;
351 		unsigned int subcommand;
352 	} tpch_methods[] = {
353 		{	.type = WRITE,
354 			.method_name =
355 				platform_info->tpch_method_names.set_fivr_low_clock_method,
356 			.subcommand = PMC_IPC_SUBCMD_RFI_CTRL0_LOGIC
357 		},
358 		{	.type = WRITE,
359 			.method_name =
360 				platform_info->tpch_method_names.set_fivr_high_clock_method,
361 			.subcommand = PMC_IPC_SUBCMD_RFI_CTRL4_LOGIC
362 		},
363 		{	.type = READ,
364 			.method_name =
365 				platform_info->tpch_method_names.get_fivr_low_clock_method,
366 			.subcommand = PMC_IPC_SUBCMD_RFI_CTRL0_LOGIC
367 		},
368 		{	.type = READ,
369 			.method_name =
370 				platform_info->tpch_method_names.get_fivr_high_clock_method,
371 			.subcommand = PMC_IPC_SUBCMD_RFI_CTRL4_LOGIC
372 		},
373 		{	.type = READ,
374 			.method_name =
375 				platform_info->tpch_method_names.get_fivr_ssc_method,
376 			.subcommand = PMC_IPC_SUBCMD_EMI_CTRL0_LOGIC
377 		},
378 		{	.type = READ,
379 			.method_name =
380 			platform_info->tpch_method_names.get_fivr_switching_fault_status,
381 			.subcommand = PMC_IPC_SUBCMD_FFFC_FAULT_STATUS
382 		},
383 		{	.type = READ,
384 			.method_name =
385 				platform_info->tpch_method_names.get_fivr_switching_freq_mhz,
386 			.subcommand = PMC_IPC_SUBCMD_FFFC_RFI_STATUS
387 		},
388 	};
389 
390 	write_pkgc_method();
391 	for (size_t i = 0; i < ARRAY_SIZE(tpch_methods); i++) {
392 		if (tpch_methods[i].type == READ) {
393 			write_tpch_read_method(tpch_methods[i].method_name,
394 						tpch_methods[i].subcommand);
395 		} else if (tpch_methods[i].type == WRITE) {
396 			write_tpch_write_method(tpch_methods[i].method_name,
397 						tpch_methods[i].subcommand);
398 		}
399 	}
400 
401 	acpigen_write_device_end(); /* TPCH Device */
402 }
403 
write_create_tpwr(const struct drivers_intel_dptf_config * config,const struct dptf_platform_info * platform_info)404 static void write_create_tpwr(const struct drivers_intel_dptf_config *config,
405 			      const struct dptf_platform_info *platform_info)
406 {
407 	acpigen_write_device("TPWR");
408 	acpigen_write_name("_HID");
409 	if (platform_info->tpwr_device_hid != NULL)
410 		dptf_write_hid(platform_info->use_eisa_hids, platform_info->tpwr_device_hid);
411 	acpigen_write_name_string("_UID", "TPWR");
412 	acpigen_write_name_unicode("_STR", DEFAULT_POWER_STR);
413 	acpigen_write_name_integer("PTYP", DPTF_GENERIC_PARTICIPANT_TYPE_POWER);
414 	acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
415 
416 	/* PROP method */
417 	if(config->prop != 0) {
418 		acpigen_write_method_serialized("PROP", 0);
419 		acpigen_emit_byte(RETURN_OP);
420 		acpigen_write_integer(config->prop);
421 		acpigen_pop_len(); /* Method PROP */
422 	}
423 	acpigen_write_device_end(); /* TPWR Power Participant Device */
424 }
425 
write_tpwr_methods(const struct drivers_intel_dptf_config * config,const struct dptf_platform_info * platform_info)426 static void write_tpwr_methods(const struct drivers_intel_dptf_config *config,
427 			       const struct dptf_platform_info *platform_info)
428 {
429 	write_create_tpwr(config, platform_info);
430 }
431 
write_create_tbat(const struct dptf_platform_info * platform_info)432 static void write_create_tbat(const struct dptf_platform_info *platform_info)
433 {
434 	acpigen_write_device("TBAT");
435 	acpigen_write_name("_HID");
436 	if (platform_info->tbat_device_hid != NULL)
437 		dptf_write_hid(platform_info->use_eisa_hids, platform_info->tbat_device_hid);
438 	acpigen_write_name_string("_UID", "1");
439 	acpigen_write_name_unicode("_STR", DEFAULT_BATTERY_STR);
440 	acpigen_write_name_integer("PTYP", DPTF_GENERIC_PARTICIPANT_TYPE_BATTERY);
441 	acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
442 	acpigen_write_device_end(); /* TBAT Battery Participant Device */
443 }
444 
445 
write_tbat_methods(const struct dptf_platform_info * platform_info)446 static void write_tbat_methods(const struct dptf_platform_info *platform_info)
447 {
448 	write_create_tbat(platform_info);
449 }
450 
451 
452 /* \_SB.DPTF - note: leaves the Scope open for child devices */
write_open_dptf_device(const struct device * dev,const struct dptf_platform_info * platform_info)453 static void write_open_dptf_device(const struct device *dev,
454 				   const struct dptf_platform_info *platform_info)
455 {
456 	acpigen_write_scope("\\_SB");
457 	acpigen_write_device(acpi_device_name(dev));
458 	acpigen_write_name("_HID");
459 	dptf_write_hid(platform_info->use_eisa_hids, platform_info->dptf_device_hid);
460 	acpigen_write_name_integer("_UID", 0);
461 	acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
462 }
463 
464 static const struct dptf_platform_info generic_dptf_platform_info = {
465 	.use_eisa_hids = CONFIG(DPTF_USE_EISA_HID),
466 	/* _HID for the toplevel DPTF device, typically \_SB.DPTF */
467 	.dptf_device_hid = DPTF_DPTF_DEVICE,
468 	/* _HID for Intel DPTF Generic Device (these require PTYP as well) */
469 	.generic_hid = DPTF_GEN_DEVICE,
470 	/* _HID for Intel DPTF Fan Device */
471 	.fan_hid = DPTF_FAN_DEVICE,
472 
473 #if CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TPWR)
474 	/* _HID for the toplevel TPWR device, typically \_SB.DPTF.TPWR */
475 	.tpwr_device_hid = DPTF_TPWR_DEVICE,
476 #endif
477 
478 #if CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TBAT)
479 	/* _HID for the toplevel BAT1 device, typically \_SB.DPTF.BAT1 */
480 	.tbat_device_hid = DPTF_BAT1_DEVICE,
481 #endif
482 
483 #if CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TPCH)
484 	/* _HID for the toplevel TPCH device, typically \_SB.TPCH */
485 	.tpch_device_hid = DPTF_TPCH_DEVICE,
486 
487 	.tpch_method_names = {
488 		.set_fivr_low_clock_method = "RFC0",
489 		.set_fivr_high_clock_method = "RFC1",
490 		.get_fivr_low_clock_method = "GFC0",
491 		.get_fivr_high_clock_method = "GFC1",
492 		.get_fivr_ssc_method = "GEMI",
493 		.get_fivr_switching_fault_status = "GFFS",
494 		.get_fivr_switching_freq_mhz = "GFCS",
495 	},
496 #endif
497 };
498 
get_dptf_platform_info(void)499 static const struct dptf_platform_info *get_dptf_platform_info(void)
500 {
501 	return &generic_dptf_platform_info;
502 }
503 
504 /* Add minimal definitions of DPTF devices into the SSDT */
write_device_definitions(const struct device * dev)505 static void write_device_definitions(const struct device *dev)
506 {
507 	const struct dptf_platform_info *platform_info = get_dptf_platform_info();
508 	const struct drivers_intel_dptf_config *config;
509 	struct device *parent;
510 	enum dptf_participant p;
511 
512 	/* The CPU device gets an _ADR that matches the ACPI PCI address for 00:04.00 */
513 	parent = dev && dev->upstream ? dev->upstream->dev : NULL;
514 	if (!parent || parent->path.type != DEVICE_PATH_PCI) {
515 		printk(BIOS_ERR, "%s: DPTF objects must live under 00:04.0 PCI device\n",
516 		       __func__);
517 		return;
518 	}
519 
520 	config = config_of(dev);
521 	write_tcpu(parent, config);
522 	write_open_dptf_device(dev, platform_info);
523 
524 	if (config->dptf_multifan_support) {
525 		for (p = DPTF_FAN; p <= DPTF_FAN_2; ++p)
526 			write_fan(config, platform_info, p);
527 	} else
528 		write_fan(config, platform_info, DPTF_FAN);
529 
530 	write_dcfg_variable(config);
531 	write_oem_variables(config);
532 	write_imok();
533 	write_generic_devices(config, platform_info);
534 
535 	if (CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TPCH))
536 		write_tpch_methods(platform_info);
537 
538 	if (CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TPWR))
539 		write_tpwr_methods(config, platform_info);
540 
541 	if (CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TBAT))
542 		write_tbat_methods(platform_info);
543 
544 	acpigen_pop_len(); /* DPTF Device (write_open_dptf_device) */
545 	acpigen_pop_len(); /* Scope */
546 }
547 
548 /* Emits policy definitions for each policy type */
write_policies(const struct drivers_intel_dptf_config * config)549 static void write_policies(const struct drivers_intel_dptf_config *config)
550 {
551 	dptf_write_enabled_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES,
552 				    config->policies.passive, DPTF_MAX_PASSIVE_POLICIES,
553 				    config->policies.critical, DPTF_MAX_CRITICAL_POLICIES);
554 
555 	dptf_write_active_policies(config->policies.active,
556 				   DPTF_MAX_ACTIVE_POLICIES, config->dptf_multifan_support);
557 
558 	dptf_write_passive_policies(config->policies.passive,
559 				    DPTF_MAX_PASSIVE_POLICIES);
560 
561 	dptf_write_critical_policies(config->policies.critical,
562 				     DPTF_MAX_CRITICAL_POLICIES);
563 }
564 
565 /* Writes other static tables that are used by DPTF */
write_controls(const struct drivers_intel_dptf_config * config)566 static void write_controls(const struct drivers_intel_dptf_config *config)
567 {
568 	enum dptf_participant p;
569 	int fan_num;
570 
571 	dptf_write_charger_perf(config->controls.charger_perf, DPTF_MAX_CHARGER_PERF_STATES);
572 
573 	/* Write TFN perf states based on the number of fans on the platform */
574 	if (config->dptf_multifan_support) {
575 		for (p = DPTF_FAN, fan_num = 0; p <= DPTF_FAN_2; ++p, ++fan_num)
576 			dptf_write_multifan_perf(config->controls.multifan_perf,
577 					DPTF_MAX_FAN_PERF_STATES, p, fan_num);
578 	} else
579 		dptf_write_fan_perf(config->controls.fan_perf, DPTF_MAX_FAN_PERF_STATES,
580 			DPTF_FAN);
581 
582 	dptf_write_power_limits(&config->controls.power_limits);
583 }
584 
585 /* Options to control the behavior of devices */
write_options(const struct drivers_intel_dptf_config * config)586 static void write_options(const struct drivers_intel_dptf_config *config)
587 {
588 	enum dptf_participant p;
589 	int i, fan_num;
590 
591 	/* Configure Fan options based on the number of fans on the platform */
592 	if (config->dptf_multifan_support) {
593 		for (p = DPTF_FAN, fan_num = 0; p <= DPTF_FAN_2; ++p, ++fan_num) {
594 			dptf_write_scope(p);
595 			dptf_write_fan_options(
596 				config->options.multifan_options[fan_num].fine_grained_control,
597 				config->options.multifan_options[fan_num].step_size,
598 				config->options.multifan_options[fan_num].low_speed_notify);
599 			acpigen_pop_len(); /* Scope */
600 		}
601 	} else {
602 		dptf_write_scope(DPTF_FAN);
603 		dptf_write_fan_options(config->options.fan.fine_grained_control,
604 			config->options.fan.step_size,
605 			config->options.fan.low_speed_notify);
606 		acpigen_pop_len(); /* Scope */
607 	}
608 
609 	/* TSR options */
610 	for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_4; ++p, ++i) {
611 		if (is_participant_used(config, p) && (config->options.tsr[i].hysteresis ||
612 						       config->options.tsr[i].desc)) {
613 			dptf_write_scope(p);
614 			dptf_write_tsr_hysteresis(config->options.tsr[i].hysteresis);
615 			dptf_write_STR(config->options.tsr[i].desc);
616 			acpigen_pop_len(); /* Scope */
617 		}
618 	}
619 }
620 
621 /* Add custom tables and methods to SSDT */
dptf_fill_ssdt(const struct device * dev)622 static void dptf_fill_ssdt(const struct device *dev)
623 {
624 	struct drivers_intel_dptf_config *config = config_of(dev);
625 
626 	write_device_definitions(dev);
627 	write_policies(config);
628 	write_controls(config);
629 	write_options(config);
630 
631 	printk(BIOS_INFO, DPTF_DEVICE_PATH ": %s at %s\n", dev->chip_ops->name, dev_path(dev));
632 }
633 
634 static struct device_operations dptf_ops = {
635 	.read_resources		= noop_read_resources,
636 	.set_resources		= noop_set_resources,
637 	.acpi_name		= dptf_acpi_name,
638 	.acpi_fill_ssdt		= dptf_fill_ssdt,
639 };
640 
dptf_enable_dev(struct device * dev)641 static void dptf_enable_dev(struct device *dev)
642 {
643 	dev->ops = &dptf_ops;
644 }
645 
646 struct chip_operations drivers_intel_dptf_ops = {
647 	.name = "Intel DPTF",
648 	.enable_dev = dptf_enable_dev,
649 };
650