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