blob: 0f1cc9c400c88a67986547e941d55de87d251c16 [file] [log] [blame]
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpigen.h>
4#include <console/console.h>
5#include <device/device.h>
6#include "chip.h"
7
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -06008/* Generic DPTF participants have a PTYP field to distinguish them */
9enum dptf_generic_participant_type {
10 DPTF_GENERIC_PARTICIPANT_TYPE_TSR = 0x3,
11 DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER = 0xB,
12};
13
14#define DEFAULT_CHARGER_STR "Battery Charger"
15
16#define DPTF_DEVICE_HID_EISAID "INT3400"
17#define GENERIC_HID_EISAID "INT3403"
18#define FAN_HID_EISAID "INT3404"
19
20#define DPTF_DEVICE_HID "INTC1040"
21#define GENERIC_HID "INTC1043"
22#define FAN_HID "INTC1044"
23
24/*
25 * Helper method to determine if a device is "used" (called out anywhere as a source or a target
26 * of any policies, and therefore should be included in the ACPI tables.
27 */
28static bool is_participant_used(const struct drivers_intel_dptf_config *config,
29 enum dptf_participant participant)
30{
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060031 int i;
32
33 /* Active? */
34 for (i = 0; i < DPTF_MAX_ACTIVE_POLICIES; ++i)
35 if (config->policies.active[i].target == participant)
36 return true;
37
Tim Wawrzynczak7eb11362020-05-29 14:10:53 -060038 /* Passive? */
39 for (i = 0; i < DPTF_MAX_PASSIVE_POLICIES; ++i)
40 if (config->policies.passive[i].source == participant ||
41 config->policies.passive[i].target == participant)
42 return true;
43
Tim Wawrzynczak3a9cde92020-05-29 14:19:15 -060044 /* Critical? */
45 for (i = 0; i < DPTF_MAX_CRITICAL_POLICIES; ++i)
46 if (config->policies.critical[i].source == participant)
47 return true;
48
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060049 /* Check fan as well (its use is implicit in the Active policy) */
50 if (participant == DPTF_FAN && config->policies.active[0].target != DPTF_NONE)
51 return true;
52
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060053 return false;
54}
55
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060056static const char *dptf_acpi_name(const struct device *dev)
57{
58 return "DPTF";
59}
60
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060061static int get_STA_value(const struct drivers_intel_dptf_config *config,
62 enum dptf_participant participant)
63{
64 return is_participant_used(config, participant) ?
65 ACPI_STATUS_DEVICE_ALL_ON :
66 ACPI_STATUS_DEVICE_ALL_OFF;
67}
68
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060069/* Devices with GENERIC _HID (distinguished by PTYP) */
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060070static void dptf_write_generic_participant(const char *name,
71 enum dptf_generic_participant_type ptype,
72 const char *str, int sta_val)
73{
74 /* Auto-incrementing UID for generic participants */
75 static int generic_uid = 0;
76
77 acpigen_write_device(name);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060078 acpigen_write_name("_HID");
79 if (CONFIG(DPTF_USE_EISA_HID))
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060080 acpigen_emit_eisaid(GENERIC_HID_EISAID);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -060081 else
82 acpigen_write_string(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 */
109static void write_fan(const struct drivers_intel_dptf_config *config)
110{
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600111 acpigen_write_device("TFN1");
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600112 acpigen_write_name("_HID");
113 if (CONFIG(DPTF_USE_EISA_HID))
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600114 acpigen_emit_eisaid(FAN_HID_EISAID);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600115 else
116 acpigen_write_string(FAN_HID);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600117
118 acpigen_write_name_integer("_UID", 0);
119 acpigen_write_STA(get_STA_value(config, DPTF_FAN));
120 acpigen_pop_len(); /* Device */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600121}
122
123/* \_SB.DPTF.xxxx */
124static void write_generic_devices(const struct drivers_intel_dptf_config *config)
125{
126 enum dptf_participant participant;
127 char name[ACPI_NAME_BUFFER_SIZE];
128 int i;
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600129
130 dptf_write_generic_participant("TCHG", DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER,
131 DEFAULT_CHARGER_STR, get_STA_value(config,
132 DPTF_CHARGER));
133
134 for (i = 0, participant = DPTF_TEMP_SENSOR_0; i < 4; ++i, ++participant) {
135 snprintf(name, sizeof(name), "TSR%1d", i);
136 dptf_write_generic_participant(name, DPTF_GENERIC_PARTICIPANT_TYPE_TSR,
137 NULL, get_STA_value(config, participant));
138 }
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600139}
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600140
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600141/* \_SB.DPTF - note: leaves the Scope open for child devices*/
142static void write_open_dptf_device(const struct device *dev)
143{
144 acpigen_write_scope("\\_SB");
145 acpigen_write_device(acpi_device_name(dev));
146 acpigen_write_name("_HID");
147 if (CONFIG(DPTF_USE_EISA_HID))
148 acpigen_emit_eisaid(DPTF_DEVICE_HID_EISAID);
149 else
150 acpigen_write_string(DPTF_DEVICE_HID);
151
152 acpigen_write_name_integer("_UID", 0);
153 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
154}
155
156/* Add minimal definitions of DPTF devices into the SSDT */
157static void write_device_definitions(const struct device *dev)
158{
159 const struct drivers_intel_dptf_config *config;
160 struct device *parent;
161
162 /* The CPU device gets an _ADR that matches the ACPI PCI address for 00:04.00 */
163 parent = dev && dev->bus ? dev->bus->dev : NULL;
164 if (!parent || parent->path.type != DEVICE_PATH_PCI) {
165 printk(BIOS_ERR, "%s: DPTF objects must live under 00:04.0 PCI device\n",
166 __func__);
167 return;
168 }
169
170 config = config_of(dev);
171 write_tcpu(parent, config);
172 write_open_dptf_device(dev);
173 write_fan(config);
174 write_generic_devices(config);
175
176 acpigen_pop_len(); /* DPTF Device (write_open_dptf_device) */
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600177 acpigen_pop_len(); /* Scope */
178}
179
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600180/* Emites policy definitions for each policy type */
181static void write_policies(const struct drivers_intel_dptf_config *config)
182{
183 dptf_write_enabled_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES,
184 config->policies.passive, DPTF_MAX_PASSIVE_POLICIES,
185 config->policies.critical, DPTF_MAX_CRITICAL_POLICIES);
186
187 dptf_write_active_policies(config->policies.active,
188 DPTF_MAX_ACTIVE_POLICIES);
189
190 dptf_write_passive_policies(config->policies.passive,
191 DPTF_MAX_PASSIVE_POLICIES);
192
193 dptf_write_critical_policies(config->policies.critical,
194 DPTF_MAX_CRITICAL_POLICIES);
195}
196
197/* Writes other static tables that are used by DPTF */
198static void write_controls(const struct drivers_intel_dptf_config *config)
199{
200 dptf_write_charger_perf(config->controls.charger_perf, DPTF_MAX_CHARGER_PERF_STATES);
201 dptf_write_fan_perf(config->controls.fan_perf, DPTF_MAX_FAN_PERF_STATES);
202 dptf_write_power_limits(&config->controls.power_limits);
203}
204
205/* Options to control the behavior of devices */
206static void write_options(const struct drivers_intel_dptf_config *config)
207{
208 enum dptf_participant p;
209 int i;
210
211 /* Fan options */
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600212 dptf_write_scope(DPTF_FAN);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600213 dptf_write_fan_options(config->options.fan.fine_grained_control,
214 config->options.fan.step_size,
215 config->options.fan.low_speed_notify);
Tim Wawrzynczak3a658ad2020-07-24 18:58:24 -0600216 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600217
218 /* TSR options */
219 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_3; ++p, ++i) {
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600220 if (is_participant_used(config, p) && (config->options.tsr[i].hysteresis ||
221 config->options.tsr[i].desc)) {
222 dptf_write_scope(p);
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600223 dptf_write_tsr_hysteresis(config->options.tsr[i].hysteresis);
224 dptf_write_STR(config->options.tsr[i].desc);
Tim Wawrzynczakc6a593b2020-07-14 13:19:03 -0600225 acpigen_pop_len(); /* Scope */
Tim Wawrzynczak5212ece62020-07-16 11:54:04 -0600226 }
227 }
228}
229
230/* Add custom tables and methods to SSDT */
231static void dptf_fill_ssdt(const struct device *dev)
232{
233 struct drivers_intel_dptf_config *config = config_of(dev);
234
235 write_device_definitions(dev);
236 write_policies(config);
237 write_controls(config);
238 write_options(config);
239
240 printk(BIOS_INFO, DPTF_DEVICE_PATH ": %s at %s\n", dev->chip_ops->name, dev_path(dev));
241}
242
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600243static struct device_operations dptf_ops = {
244 .read_resources = noop_read_resources,
245 .set_resources = noop_set_resources,
246 .acpi_name = dptf_acpi_name,
247 .acpi_fill_ssdt = dptf_fill_ssdt,
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600248};
249
250static void dptf_enable_dev(struct device *dev)
251{
252 dev->ops = &dptf_ops;
253}
254
255struct chip_operations drivers_intel_dptf_ops = {
256 CHIP_NAME("Intel DPTF")
257 .enable_dev = dptf_enable_dev,
258};