blob: a202a2712993ddbedf8424b1c9a3b57e5683ca95 [file] [log] [blame]
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpigen.h>
Tim Wawrzynczakd40a4c22021-02-25 13:14:49 -07004#include <acpi/acpigen_pci.h>
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -06005#include <console/console.h>
6#include <device/device.h>
Sumeet Pawnikara91d9312021-08-30 23:19:38 +05307#include <intelblocks/pmc_ipc.h>
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -06008#include "chip.h"
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -06009#include "dptf.h"
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060010
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060011/* Generic DPTF participants have a PTYP field to distinguish them */
12enum dptf_generic_participant_type {
13 DPTF_GENERIC_PARTICIPANT_TYPE_TSR = 0x3,
14 DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER = 0xB,
15};
16
17#define DEFAULT_CHARGER_STR "Battery Charger"
18
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060019/*
20 * Helper method to determine if a device is "used" (called out anywhere as a source or a target
21 * of any policies, and therefore should be included in the ACPI tables.
22 */
23static bool is_participant_used(const struct drivers_intel_dptf_config *config,
24 enum dptf_participant participant)
25{
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060026 int i;
27
28 /* Active? */
29 for (i = 0; i < DPTF_MAX_ACTIVE_POLICIES; ++i)
30 if (config->policies.active[i].target == participant)
31 return true;
32
Tim Wawrzynczak7eb11362020-05-29 14:10:53 -060033 /* Passive? */
34 for (i = 0; i < DPTF_MAX_PASSIVE_POLICIES; ++i)
35 if (config->policies.passive[i].source == participant ||
36 config->policies.passive[i].target == participant)
37 return true;
38
Tim Wawrzynczak3a9cde92020-05-29 14:19:15 -060039 /* Critical? */
40 for (i = 0; i < DPTF_MAX_CRITICAL_POLICIES; ++i)
41 if (config->policies.critical[i].source == participant)
42 return true;
43
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060044 /* Check fan as well (its use is implicit in the Active policy) */
45 if (participant == DPTF_FAN && config->policies.active[0].target != DPTF_NONE)
46 return true;
47
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060048 return false;
49}
50
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060051static const char *dptf_acpi_name(const struct device *dev)
52{
53 return "DPTF";
54}
55
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060056static int get_STA_value(const struct drivers_intel_dptf_config *config,
57 enum dptf_participant participant)
58{
59 return is_participant_used(config, participant) ?
60 ACPI_STATUS_DEVICE_ALL_ON :
61 ACPI_STATUS_DEVICE_ALL_OFF;
62}
63
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -060064static void dptf_write_hid(bool is_eisa, const char *hid)
65{
66 if (is_eisa)
67 acpigen_emit_eisaid(hid);
68 else
69 acpigen_write_string(hid);
70}
71
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060072/* Devices with GENERIC _HID (distinguished by PTYP) */
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060073static void dptf_write_generic_participant(const char *name,
74 enum dptf_generic_participant_type ptype,
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -060075 const char *str, int sta_val,
76 const struct dptf_platform_info *platform_info)
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060077{
78 /* Auto-incrementing UID for generic participants */
79 static int generic_uid = 0;
80
81 acpigen_write_device(name);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060082 acpigen_write_name("_HID");
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -060083 dptf_write_hid(platform_info->use_eisa_hids, platform_info->generic_hid);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060084
85 acpigen_write_name_integer("_UID", generic_uid++);
86 acpigen_write_STA(sta_val);
87
88 if (str)
89 acpigen_write_name_string("_STR", str);
90
91 acpigen_write_name_integer("PTYP", ptype);
92
93 acpigen_pop_len(); /* Device */
94}
95
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060096/* \_SB.PCI0.TCPU */
97static void write_tcpu(const struct device *pci_dev,
98 const struct drivers_intel_dptf_config *config)
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060099{
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600100 /* DPTF CPU device - \_SB.PCI0.TCPU */
101 acpigen_write_scope(TCPU_SCOPE);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600102 acpigen_write_device("TCPU");
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600103 acpigen_write_ADR_pci_device(pci_dev);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600104 acpigen_write_STA(get_STA_value(config, DPTF_CPU));
105 acpigen_pop_len(); /* Device */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600106 acpigen_pop_len(); /* TCPU Scope */
107}
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600108
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600109/* \_SB.DPTF.TFN1 */
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600110static void write_fan(const struct drivers_intel_dptf_config *config,
111 const struct dptf_platform_info *platform_info)
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600112{
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600113 acpigen_write_device("TFN1");
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600114 acpigen_write_name("_HID");
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600115 dptf_write_hid(platform_info->use_eisa_hids, platform_info->fan_hid);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600116 acpigen_write_name_integer("_UID", 0);
117 acpigen_write_STA(get_STA_value(config, DPTF_FAN));
118 acpigen_pop_len(); /* Device */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600119}
120
Sumeet R Pawnikar36571872021-05-11 20:05:20 +0530121/* \_SB.DPTF */
Sumeet Pawnikarf96aa7a2021-07-05 21:09:53 +0530122static void write_imok(void)
123{
124 acpigen_write_method("IMOK", 1);
125 /* Return (Arg0) */
126 acpigen_emit_byte(RETURN_OP);
127 acpigen_emit_byte(ARG0_OP);
128 acpigen_write_method_end();
129}
130/* \_SB.DPTF */
Sumeet R Pawnikar36571872021-05-11 20:05:20 +0530131static void write_oem_variables(const struct drivers_intel_dptf_config *config)
132{
133 int i;
134
135 acpigen_write_name("ODVX");
136 acpigen_write_package(DPTF_OEM_VARIABLE_COUNT);
137 for (i = 0; i < DPTF_OEM_VARIABLE_COUNT; i++)
138 acpigen_write_dword(config->oem_data.oem_variables[i]);
139 acpigen_write_package_end();
140
141 /*
142 * Method (ODUP, 2)
143 * Arg0 = Index of ODVX to update
144 * Arg1 = Value to place in ODVX[Arg0]
145 */
146 acpigen_write_method_serialized("ODUP", 2);
147 /* ODVX[Arg0] = Arg1 */
148 acpigen_write_store();
149 acpigen_emit_byte(ARG1_OP);
150 acpigen_emit_byte(INDEX_OP);
151 acpigen_emit_namestring("ODVX");
152 acpigen_emit_byte(ARG0_OP);
153 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
154 acpigen_write_method_end();
155
156 /*
157 * Method (ODGT, 1)
158 * Arg0 = Index of ODVX to get
159 */
160 acpigen_write_method_serialized("ODGT", 1);
161 /* Return (ODVX[Arg0]) */
162 acpigen_emit_byte(RETURN_OP);
163 acpigen_emit_byte(DEREF_OP);
164 acpigen_emit_byte(INDEX_OP);
165 acpigen_emit_namestring("ODVX");
166 acpigen_emit_byte(ARG0_OP);
167 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
168 acpigen_write_method_end();
169
170 /* Method (ODVP) { Return (ODVX) } */
171 acpigen_write_method_serialized("ODVP", 0);
172 acpigen_emit_byte(RETURN_OP);
173 acpigen_emit_namestring("ODVX");
174 acpigen_write_method_end();
175}
176
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600177/* \_SB.DPTF.xxxx */
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600178static void write_generic_devices(const struct drivers_intel_dptf_config *config,
179 const struct dptf_platform_info *platform_info)
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600180{
181 enum dptf_participant participant;
182 char name[ACPI_NAME_BUFFER_SIZE];
183 int i;
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600184
185 dptf_write_generic_participant("TCHG", DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER,
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600186 DEFAULT_CHARGER_STR,
187 get_STA_value(config, DPTF_CHARGER),
188 platform_info);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600189
190 for (i = 0, participant = DPTF_TEMP_SENSOR_0; i < 4; ++i, ++participant) {
191 snprintf(name, sizeof(name), "TSR%1d", i);
192 dptf_write_generic_participant(name, DPTF_GENERIC_PARTICIPANT_TYPE_TSR,
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600193 NULL, get_STA_value(config, participant),
194 platform_info);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600195 }
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600196}
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600197
Sumeet Pawnikara91d9312021-08-30 23:19:38 +0530198/* \_SB.DPTF.TPCH.RFC methods */
199static void write_tpch_rfc_methods(const char *tpch_rfc_method_name,
200 unsigned int ipc_subcmd_ctrl_value)
201{
202 acpigen_write_method_serialized(tpch_rfc_method_name, 1);
203 acpigen_emit_namestring("IPCS");
204 acpigen_write_integer(PMC_IPC_CMD_COMMAND_FIVR);
205 acpigen_write_integer(PMC_IPC_CMD_CMD_ID_FIVR_WRITE);
206 acpigen_write_integer(0x8);
207 acpigen_write_integer(ipc_subcmd_ctrl_value);
208 acpigen_emit_byte(ARG0_OP);
209 acpigen_write_dword(0);
210 acpigen_write_dword(0);
211 /* The reason for returning a value here is a W/A for the ESIF shell */
212 acpigen_emit_byte(RETURN_OP);
213 acpigen_write_package(0);
214 acpigen_write_package_end();
215 acpigen_write_method_end();
216}
217
218static void write_create_tpch(const struct dptf_platform_info *platform_info)
219{
220 acpigen_write_device("TPCH");
221 acpigen_write_name("_HID");
222 dptf_write_hid(platform_info->use_eisa_hids, platform_info->tpch_device_hid);
223 acpigen_write_name_integer("_UID", 0);
224 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
225}
226
227static void write_tpch_methods(const struct dptf_platform_info *platform_info)
228{
229 write_create_tpch(platform_info);
230
231 /* Create RFC0 method */
232 write_tpch_rfc_methods(platform_info->tpch_rfc0_method,
233 PMC_IPC_SUBCMD_RFI_CTRL0_LOGIC);
234 /* Create RFC1 method */
235 write_tpch_rfc_methods(platform_info->tpch_rfc1_method,
236 PMC_IPC_SUBCMD_RFI_CTRL4_LOGIC);
237
238 acpigen_write_device_end(); /* TPCH Device */
239}
240
241/* \_SB.DPTF - note: leaves the Scope open for child devices */
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600242static void write_open_dptf_device(const struct device *dev,
243 const struct dptf_platform_info *platform_info)
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600244{
245 acpigen_write_scope("\\_SB");
246 acpigen_write_device(acpi_device_name(dev));
247 acpigen_write_name("_HID");
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600248 dptf_write_hid(platform_info->use_eisa_hids, platform_info->dptf_device_hid);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600249 acpigen_write_name_integer("_UID", 0);
250 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
251}
252
253/* Add minimal definitions of DPTF devices into the SSDT */
254static void write_device_definitions(const struct device *dev)
255{
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600256 const struct dptf_platform_info *platform_info = get_dptf_platform_info();
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600257 const struct drivers_intel_dptf_config *config;
258 struct device *parent;
259
260 /* The CPU device gets an _ADR that matches the ACPI PCI address for 00:04.00 */
261 parent = dev && dev->bus ? dev->bus->dev : NULL;
262 if (!parent || parent->path.type != DEVICE_PATH_PCI) {
263 printk(BIOS_ERR, "%s: DPTF objects must live under 00:04.0 PCI device\n",
264 __func__);
265 return;
266 }
267
268 config = config_of(dev);
269 write_tcpu(parent, config);
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600270 write_open_dptf_device(dev, platform_info);
271 write_fan(config, platform_info);
Sumeet R Pawnikar36571872021-05-11 20:05:20 +0530272 write_oem_variables(config);
Sumeet Pawnikarf96aa7a2021-07-05 21:09:53 +0530273 write_imok();
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600274 write_generic_devices(config, platform_info);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600275
Sumeet Pawnikara91d9312021-08-30 23:19:38 +0530276 if (CONFIG(DRIVERS_INTEL_DPTF_SUPPORTS_TPCH))
277 write_tpch_methods(platform_info);
278
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600279 acpigen_pop_len(); /* DPTF Device (write_open_dptf_device) */
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600280 acpigen_pop_len(); /* Scope */
281}
282
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600283/* Emites policy definitions for each policy type */
284static void write_policies(const struct drivers_intel_dptf_config *config)
285{
286 dptf_write_enabled_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES,
287 config->policies.passive, DPTF_MAX_PASSIVE_POLICIES,
288 config->policies.critical, DPTF_MAX_CRITICAL_POLICIES);
289
290 dptf_write_active_policies(config->policies.active,
291 DPTF_MAX_ACTIVE_POLICIES);
292
293 dptf_write_passive_policies(config->policies.passive,
294 DPTF_MAX_PASSIVE_POLICIES);
295
296 dptf_write_critical_policies(config->policies.critical,
297 DPTF_MAX_CRITICAL_POLICIES);
298}
299
300/* Writes other static tables that are used by DPTF */
301static void write_controls(const struct drivers_intel_dptf_config *config)
302{
303 dptf_write_charger_perf(config->controls.charger_perf, DPTF_MAX_CHARGER_PERF_STATES);
304 dptf_write_fan_perf(config->controls.fan_perf, DPTF_MAX_FAN_PERF_STATES);
305 dptf_write_power_limits(&config->controls.power_limits);
306}
307
308/* Options to control the behavior of devices */
309static void write_options(const struct drivers_intel_dptf_config *config)
310{
311 enum dptf_participant p;
312 int i;
313
314 /* Fan options */
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600315 dptf_write_scope(DPTF_FAN);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600316 dptf_write_fan_options(config->options.fan.fine_grained_control,
317 config->options.fan.step_size,
318 config->options.fan.low_speed_notify);
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600319 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600320
321 /* TSR options */
322 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_3; ++p, ++i) {
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600323 if (is_participant_used(config, p) && (config->options.tsr[i].hysteresis ||
324 config->options.tsr[i].desc)) {
325 dptf_write_scope(p);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600326 dptf_write_tsr_hysteresis(config->options.tsr[i].hysteresis);
327 dptf_write_STR(config->options.tsr[i].desc);
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600328 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600329 }
330 }
331}
332
333/* Add custom tables and methods to SSDT */
334static void dptf_fill_ssdt(const struct device *dev)
335{
336 struct drivers_intel_dptf_config *config = config_of(dev);
337
338 write_device_definitions(dev);
339 write_policies(config);
340 write_controls(config);
341 write_options(config);
342
343 printk(BIOS_INFO, DPTF_DEVICE_PATH ": %s at %s\n", dev->chip_ops->name, dev_path(dev));
344}
345
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600346static struct device_operations dptf_ops = {
347 .read_resources = noop_read_resources,
348 .set_resources = noop_set_resources,
349 .acpi_name = dptf_acpi_name,
350 .acpi_fill_ssdt = dptf_fill_ssdt,
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600351};
352
353static void dptf_enable_dev(struct device *dev)
354{
355 dev->ops = &dptf_ops;
356}
357
358struct chip_operations drivers_intel_dptf_ops = {
359 CHIP_NAME("Intel DPTF")
360 .enable_dev = dptf_enable_dev,
361};