blob: f9b4dee5c5687edc4dc420c5c58cb8d0826b9771 [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>
7#include "chip.h"
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -06008#include "dptf.h"
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -06009
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060010/* Generic DPTF participants have a PTYP field to distinguish them */
11enum dptf_generic_participant_type {
12 DPTF_GENERIC_PARTICIPANT_TYPE_TSR = 0x3,
13 DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER = 0xB,
14};
15
16#define DEFAULT_CHARGER_STR "Battery Charger"
17
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060018/*
19 * Helper method to determine if a device is "used" (called out anywhere as a source or a target
20 * of any policies, and therefore should be included in the ACPI tables.
21 */
22static bool is_participant_used(const struct drivers_intel_dptf_config *config,
23 enum dptf_participant participant)
24{
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060025 int i;
26
27 /* Active? */
28 for (i = 0; i < DPTF_MAX_ACTIVE_POLICIES; ++i)
29 if (config->policies.active[i].target == participant)
30 return true;
31
Tim Wawrzynczak7eb11362020-05-29 14:10:53 -060032 /* Passive? */
33 for (i = 0; i < DPTF_MAX_PASSIVE_POLICIES; ++i)
34 if (config->policies.passive[i].source == participant ||
35 config->policies.passive[i].target == participant)
36 return true;
37
Tim Wawrzynczak3a9cde92020-05-29 14:19:15 -060038 /* Critical? */
39 for (i = 0; i < DPTF_MAX_CRITICAL_POLICIES; ++i)
40 if (config->policies.critical[i].source == participant)
41 return true;
42
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060043 /* Check fan as well (its use is implicit in the Active policy) */
44 if (participant == DPTF_FAN && config->policies.active[0].target != DPTF_NONE)
45 return true;
46
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060047 return false;
48}
49
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060050static const char *dptf_acpi_name(const struct device *dev)
51{
52 return "DPTF";
53}
54
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060055static int get_STA_value(const struct drivers_intel_dptf_config *config,
56 enum dptf_participant participant)
57{
58 return is_participant_used(config, participant) ?
59 ACPI_STATUS_DEVICE_ALL_ON :
60 ACPI_STATUS_DEVICE_ALL_OFF;
61}
62
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -060063static void dptf_write_hid(bool is_eisa, const char *hid)
64{
65 if (is_eisa)
66 acpigen_emit_eisaid(hid);
67 else
68 acpigen_write_string(hid);
69}
70
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060071/* Devices with GENERIC _HID (distinguished by PTYP) */
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060072static void dptf_write_generic_participant(const char *name,
73 enum dptf_generic_participant_type ptype,
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -060074 const char *str, int sta_val,
75 const struct dptf_platform_info *platform_info)
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060076{
77 /* Auto-incrementing UID for generic participants */
78 static int generic_uid = 0;
79
80 acpigen_write_device(name);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060081 acpigen_write_name("_HID");
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -060082 dptf_write_hid(platform_info->use_eisa_hids, platform_info->generic_hid);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060083
84 acpigen_write_name_integer("_UID", generic_uid++);
85 acpigen_write_STA(sta_val);
86
87 if (str)
88 acpigen_write_name_string("_STR", str);
89
90 acpigen_write_name_integer("PTYP", ptype);
91
92 acpigen_pop_len(); /* Device */
93}
94
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060095/* \_SB.PCI0.TCPU */
96static void write_tcpu(const struct device *pci_dev,
97 const struct drivers_intel_dptf_config *config)
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060098{
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060099 /* DPTF CPU device - \_SB.PCI0.TCPU */
100 acpigen_write_scope(TCPU_SCOPE);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600101 acpigen_write_device("TCPU");
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600102 acpigen_write_ADR_pci_device(pci_dev);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600103 acpigen_write_STA(get_STA_value(config, DPTF_CPU));
104 acpigen_pop_len(); /* Device */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600105 acpigen_pop_len(); /* TCPU Scope */
106}
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600107
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600108/* \_SB.DPTF.TFN1 */
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600109static void write_fan(const struct drivers_intel_dptf_config *config,
110 const struct dptf_platform_info *platform_info)
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600111{
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600112 acpigen_write_device("TFN1");
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600113 acpigen_write_name("_HID");
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600114 dptf_write_hid(platform_info->use_eisa_hids, platform_info->fan_hid);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600115 acpigen_write_name_integer("_UID", 0);
116 acpigen_write_STA(get_STA_value(config, DPTF_FAN));
117 acpigen_pop_len(); /* Device */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600118}
119
Sumeet R Pawnikar36571872021-05-11 20:05:20 +0530120/* \_SB.DPTF */
121static void write_oem_variables(const struct drivers_intel_dptf_config *config)
122{
123 int i;
124
125 acpigen_write_name("ODVX");
126 acpigen_write_package(DPTF_OEM_VARIABLE_COUNT);
127 for (i = 0; i < DPTF_OEM_VARIABLE_COUNT; i++)
128 acpigen_write_dword(config->oem_data.oem_variables[i]);
129 acpigen_write_package_end();
130
131 /*
132 * Method (ODUP, 2)
133 * Arg0 = Index of ODVX to update
134 * Arg1 = Value to place in ODVX[Arg0]
135 */
136 acpigen_write_method_serialized("ODUP", 2);
137 /* ODVX[Arg0] = Arg1 */
138 acpigen_write_store();
139 acpigen_emit_byte(ARG1_OP);
140 acpigen_emit_byte(INDEX_OP);
141 acpigen_emit_namestring("ODVX");
142 acpigen_emit_byte(ARG0_OP);
143 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
144 acpigen_write_method_end();
145
146 /*
147 * Method (ODGT, 1)
148 * Arg0 = Index of ODVX to get
149 */
150 acpigen_write_method_serialized("ODGT", 1);
151 /* Return (ODVX[Arg0]) */
152 acpigen_emit_byte(RETURN_OP);
153 acpigen_emit_byte(DEREF_OP);
154 acpigen_emit_byte(INDEX_OP);
155 acpigen_emit_namestring("ODVX");
156 acpigen_emit_byte(ARG0_OP);
157 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
158 acpigen_write_method_end();
159
160 /* Method (ODVP) { Return (ODVX) } */
161 acpigen_write_method_serialized("ODVP", 0);
162 acpigen_emit_byte(RETURN_OP);
163 acpigen_emit_namestring("ODVX");
164 acpigen_write_method_end();
165}
166
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600167/* \_SB.DPTF.xxxx */
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600168static void write_generic_devices(const struct drivers_intel_dptf_config *config,
169 const struct dptf_platform_info *platform_info)
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600170{
171 enum dptf_participant participant;
172 char name[ACPI_NAME_BUFFER_SIZE];
173 int i;
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600174
175 dptf_write_generic_participant("TCHG", DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER,
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600176 DEFAULT_CHARGER_STR,
177 get_STA_value(config, DPTF_CHARGER),
178 platform_info);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600179
180 for (i = 0, participant = DPTF_TEMP_SENSOR_0; i < 4; ++i, ++participant) {
181 snprintf(name, sizeof(name), "TSR%1d", i);
182 dptf_write_generic_participant(name, DPTF_GENERIC_PARTICIPANT_TYPE_TSR,
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600183 NULL, get_STA_value(config, participant),
184 platform_info);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600185 }
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600186}
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600187
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600188/* \_SB.DPTF - note: leaves the Scope open for child devices*/
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600189static void write_open_dptf_device(const struct device *dev,
190 const struct dptf_platform_info *platform_info)
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600191{
192 acpigen_write_scope("\\_SB");
193 acpigen_write_device(acpi_device_name(dev));
194 acpigen_write_name("_HID");
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600195 dptf_write_hid(platform_info->use_eisa_hids, platform_info->dptf_device_hid);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600196 acpigen_write_name_integer("_UID", 0);
197 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
198}
199
200/* Add minimal definitions of DPTF devices into the SSDT */
201static void write_device_definitions(const struct device *dev)
202{
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600203 const struct dptf_platform_info *platform_info = get_dptf_platform_info();
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600204 const struct drivers_intel_dptf_config *config;
205 struct device *parent;
206
207 /* The CPU device gets an _ADR that matches the ACPI PCI address for 00:04.00 */
208 parent = dev && dev->bus ? dev->bus->dev : NULL;
209 if (!parent || parent->path.type != DEVICE_PATH_PCI) {
210 printk(BIOS_ERR, "%s: DPTF objects must live under 00:04.0 PCI device\n",
211 __func__);
212 return;
213 }
214
215 config = config_of(dev);
216 write_tcpu(parent, config);
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600217 write_open_dptf_device(dev, platform_info);
218 write_fan(config, platform_info);
Sumeet R Pawnikar36571872021-05-11 20:05:20 +0530219 write_oem_variables(config);
Tim Wawrzynczak7f7c3882021-04-09 12:15:21 -0600220 write_generic_devices(config, platform_info);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600221
222 acpigen_pop_len(); /* DPTF Device (write_open_dptf_device) */
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600223 acpigen_pop_len(); /* Scope */
224}
225
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600226/* Emites policy definitions for each policy type */
227static void write_policies(const struct drivers_intel_dptf_config *config)
228{
229 dptf_write_enabled_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES,
230 config->policies.passive, DPTF_MAX_PASSIVE_POLICIES,
231 config->policies.critical, DPTF_MAX_CRITICAL_POLICIES);
232
233 dptf_write_active_policies(config->policies.active,
234 DPTF_MAX_ACTIVE_POLICIES);
235
236 dptf_write_passive_policies(config->policies.passive,
237 DPTF_MAX_PASSIVE_POLICIES);
238
239 dptf_write_critical_policies(config->policies.critical,
240 DPTF_MAX_CRITICAL_POLICIES);
241}
242
243/* Writes other static tables that are used by DPTF */
244static void write_controls(const struct drivers_intel_dptf_config *config)
245{
246 dptf_write_charger_perf(config->controls.charger_perf, DPTF_MAX_CHARGER_PERF_STATES);
247 dptf_write_fan_perf(config->controls.fan_perf, DPTF_MAX_FAN_PERF_STATES);
248 dptf_write_power_limits(&config->controls.power_limits);
249}
250
251/* Options to control the behavior of devices */
252static void write_options(const struct drivers_intel_dptf_config *config)
253{
254 enum dptf_participant p;
255 int i;
256
257 /* Fan options */
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600258 dptf_write_scope(DPTF_FAN);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600259 dptf_write_fan_options(config->options.fan.fine_grained_control,
260 config->options.fan.step_size,
261 config->options.fan.low_speed_notify);
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600262 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600263
264 /* TSR options */
265 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_3; ++p, ++i) {
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600266 if (is_participant_used(config, p) && (config->options.tsr[i].hysteresis ||
267 config->options.tsr[i].desc)) {
268 dptf_write_scope(p);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600269 dptf_write_tsr_hysteresis(config->options.tsr[i].hysteresis);
270 dptf_write_STR(config->options.tsr[i].desc);
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600271 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600272 }
273 }
274}
275
276/* Add custom tables and methods to SSDT */
277static void dptf_fill_ssdt(const struct device *dev)
278{
279 struct drivers_intel_dptf_config *config = config_of(dev);
280
281 write_device_definitions(dev);
282 write_policies(config);
283 write_controls(config);
284 write_options(config);
285
286 printk(BIOS_INFO, DPTF_DEVICE_PATH ": %s at %s\n", dev->chip_ops->name, dev_path(dev));
287}
288
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600289static struct device_operations dptf_ops = {
290 .read_resources = noop_read_resources,
291 .set_resources = noop_set_resources,
292 .acpi_name = dptf_acpi_name,
293 .acpi_fill_ssdt = dptf_fill_ssdt,
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600294};
295
296static void dptf_enable_dev(struct device *dev)
297{
298 dev->ops = &dptf_ops;
299}
300
301struct chip_operations drivers_intel_dptf_ops = {
302 CHIP_NAME("Intel DPTF")
303 .enable_dev = dptf_enable_dev,
304};