blob: 1713e7230930f278f0e652ed972c3d5bfb59c82d [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"
8
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -06009/* Generic DPTF participants have a PTYP field to distinguish them */
10enum dptf_generic_participant_type {
11 DPTF_GENERIC_PARTICIPANT_TYPE_TSR = 0x3,
12 DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER = 0xB,
13};
14
15#define DEFAULT_CHARGER_STR "Battery Charger"
16
17#define DPTF_DEVICE_HID_EISAID "INT3400"
18#define GENERIC_HID_EISAID "INT3403"
19#define FAN_HID_EISAID "INT3404"
20
21#define DPTF_DEVICE_HID "INTC1040"
22#define GENERIC_HID "INTC1043"
23#define FAN_HID "INTC1044"
24
25/*
26 * Helper method to determine if a device is "used" (called out anywhere as a source or a target
27 * of any policies, and therefore should be included in the ACPI tables.
28 */
29static bool is_participant_used(const struct drivers_intel_dptf_config *config,
30 enum dptf_participant participant)
31{
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060032 int i;
33
34 /* Active? */
35 for (i = 0; i < DPTF_MAX_ACTIVE_POLICIES; ++i)
36 if (config->policies.active[i].target == participant)
37 return true;
38
Tim Wawrzynczak7eb11362020-05-29 14:10:53 -060039 /* Passive? */
40 for (i = 0; i < DPTF_MAX_PASSIVE_POLICIES; ++i)
41 if (config->policies.passive[i].source == participant ||
42 config->policies.passive[i].target == participant)
43 return true;
44
Tim Wawrzynczak3a9cde92020-05-29 14:19:15 -060045 /* Critical? */
46 for (i = 0; i < DPTF_MAX_CRITICAL_POLICIES; ++i)
47 if (config->policies.critical[i].source == participant)
48 return true;
49
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060050 /* Check fan as well (its use is implicit in the Active policy) */
51 if (participant == DPTF_FAN && config->policies.active[0].target != DPTF_NONE)
52 return true;
53
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060054 return false;
55}
56
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060057static const char *dptf_acpi_name(const struct device *dev)
58{
59 return "DPTF";
60}
61
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060062static int get_STA_value(const struct drivers_intel_dptf_config *config,
63 enum dptf_participant participant)
64{
65 return is_participant_used(config, participant) ?
66 ACPI_STATUS_DEVICE_ALL_ON :
67 ACPI_STATUS_DEVICE_ALL_OFF;
68}
69
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060070/* Devices with GENERIC _HID (distinguished by PTYP) */
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060071static void dptf_write_generic_participant(const char *name,
72 enum dptf_generic_participant_type ptype,
73 const char *str, int sta_val)
74{
75 /* Auto-incrementing UID for generic participants */
76 static int generic_uid = 0;
77
78 acpigen_write_device(name);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060079 acpigen_write_name("_HID");
80 if (CONFIG(DPTF_USE_EISA_HID))
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060081 acpigen_emit_eisaid(GENERIC_HID_EISAID);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060082 else
83 acpigen_write_string(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 */
110static void write_fan(const struct drivers_intel_dptf_config *config)
111{
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600112 acpigen_write_device("TFN1");
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600113 acpigen_write_name("_HID");
114 if (CONFIG(DPTF_USE_EISA_HID))
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600115 acpigen_emit_eisaid(FAN_HID_EISAID);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600116 else
117 acpigen_write_string(FAN_HID);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600118
119 acpigen_write_name_integer("_UID", 0);
120 acpigen_write_STA(get_STA_value(config, DPTF_FAN));
121 acpigen_pop_len(); /* Device */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600122}
123
124/* \_SB.DPTF.xxxx */
125static void write_generic_devices(const struct drivers_intel_dptf_config *config)
126{
127 enum dptf_participant participant;
128 char name[ACPI_NAME_BUFFER_SIZE];
129 int i;
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600130
131 dptf_write_generic_participant("TCHG", DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER,
132 DEFAULT_CHARGER_STR, get_STA_value(config,
133 DPTF_CHARGER));
134
135 for (i = 0, participant = DPTF_TEMP_SENSOR_0; i < 4; ++i, ++participant) {
136 snprintf(name, sizeof(name), "TSR%1d", i);
137 dptf_write_generic_participant(name, DPTF_GENERIC_PARTICIPANT_TYPE_TSR,
138 NULL, get_STA_value(config, participant));
139 }
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600140}
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600141
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600142/* \_SB.DPTF - note: leaves the Scope open for child devices*/
143static void write_open_dptf_device(const struct device *dev)
144{
145 acpigen_write_scope("\\_SB");
146 acpigen_write_device(acpi_device_name(dev));
147 acpigen_write_name("_HID");
148 if (CONFIG(DPTF_USE_EISA_HID))
149 acpigen_emit_eisaid(DPTF_DEVICE_HID_EISAID);
150 else
151 acpigen_write_string(DPTF_DEVICE_HID);
152
153 acpigen_write_name_integer("_UID", 0);
154 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
155}
156
157/* Add minimal definitions of DPTF devices into the SSDT */
158static void write_device_definitions(const struct device *dev)
159{
160 const struct drivers_intel_dptf_config *config;
161 struct device *parent;
162
163 /* The CPU device gets an _ADR that matches the ACPI PCI address for 00:04.00 */
164 parent = dev && dev->bus ? dev->bus->dev : NULL;
165 if (!parent || parent->path.type != DEVICE_PATH_PCI) {
166 printk(BIOS_ERR, "%s: DPTF objects must live under 00:04.0 PCI device\n",
167 __func__);
168 return;
169 }
170
171 config = config_of(dev);
172 write_tcpu(parent, config);
173 write_open_dptf_device(dev);
174 write_fan(config);
175 write_generic_devices(config);
176
177 acpigen_pop_len(); /* DPTF Device (write_open_dptf_device) */
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600178 acpigen_pop_len(); /* Scope */
179}
180
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600181/* Emites policy definitions for each policy type */
182static void write_policies(const struct drivers_intel_dptf_config *config)
183{
184 dptf_write_enabled_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES,
185 config->policies.passive, DPTF_MAX_PASSIVE_POLICIES,
186 config->policies.critical, DPTF_MAX_CRITICAL_POLICIES);
187
188 dptf_write_active_policies(config->policies.active,
189 DPTF_MAX_ACTIVE_POLICIES);
190
191 dptf_write_passive_policies(config->policies.passive,
192 DPTF_MAX_PASSIVE_POLICIES);
193
194 dptf_write_critical_policies(config->policies.critical,
195 DPTF_MAX_CRITICAL_POLICIES);
196}
197
198/* Writes other static tables that are used by DPTF */
199static void write_controls(const struct drivers_intel_dptf_config *config)
200{
201 dptf_write_charger_perf(config->controls.charger_perf, DPTF_MAX_CHARGER_PERF_STATES);
202 dptf_write_fan_perf(config->controls.fan_perf, DPTF_MAX_FAN_PERF_STATES);
203 dptf_write_power_limits(&config->controls.power_limits);
204}
205
206/* Options to control the behavior of devices */
207static void write_options(const struct drivers_intel_dptf_config *config)
208{
209 enum dptf_participant p;
210 int i;
211
212 /* Fan options */
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600213 dptf_write_scope(DPTF_FAN);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600214 dptf_write_fan_options(config->options.fan.fine_grained_control,
215 config->options.fan.step_size,
216 config->options.fan.low_speed_notify);
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600217 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600218
219 /* TSR options */
220 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_3; ++p, ++i) {
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600221 if (is_participant_used(config, p) && (config->options.tsr[i].hysteresis ||
222 config->options.tsr[i].desc)) {
223 dptf_write_scope(p);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600224 dptf_write_tsr_hysteresis(config->options.tsr[i].hysteresis);
225 dptf_write_STR(config->options.tsr[i].desc);
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600226 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600227 }
228 }
229}
230
231/* Add custom tables and methods to SSDT */
232static void dptf_fill_ssdt(const struct device *dev)
233{
234 struct drivers_intel_dptf_config *config = config_of(dev);
235
236 write_device_definitions(dev);
237 write_policies(config);
238 write_controls(config);
239 write_options(config);
240
241 printk(BIOS_INFO, DPTF_DEVICE_PATH ": %s at %s\n", dev->chip_ops->name, dev_path(dev));
242}
243
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600244static struct device_operations dptf_ops = {
245 .read_resources = noop_read_resources,
246 .set_resources = noop_set_resources,
247 .acpi_name = dptf_acpi_name,
248 .acpi_fill_ssdt = dptf_fill_ssdt,
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600249};
250
251static void dptf_enable_dev(struct device *dev)
252{
253 dev->ops = &dptf_ops;
254}
255
256struct chip_operations drivers_intel_dptf_ops = {
257 CHIP_NAME("Intel DPTF")
258 .enable_dev = dptf_enable_dev,
259};