blob: 1e4063e40f8bb20d83c38218e0d5a885b236507b [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
61/* Add custom tables and methods to SSDT */
62static void dptf_fill_ssdt(const struct device *dev)
63{
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -060064 struct drivers_intel_dptf_config *config = config_of(dev);
Tim Wawrzynczake4d8ebc2020-05-29 14:58:16 -060065 enum dptf_participant p;
66 bool tsr_en[DPTF_MAX_TSR] = {false};
67 int i;
68
69 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_3; ++p, ++i)
70 tsr_en[i] = is_participant_used(config, p);
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -060071
Tim Wawrzynczak03465f42020-06-03 16:27:30 -060072 /* Policies */
73 dptf_write_enabled_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES,
74 config->policies.passive, DPTF_MAX_PASSIVE_POLICIES,
75 config->policies.critical, DPTF_MAX_CRITICAL_POLICIES);
76
Tim Wawrzynczakc41f7f12020-05-29 13:56:37 -060077 dptf_write_active_policies(config->policies.active,
78 DPTF_MAX_ACTIVE_POLICIES);
79
Tim Wawrzynczak7eb11362020-05-29 14:10:53 -060080 dptf_write_passive_policies(config->policies.passive,
81 DPTF_MAX_PASSIVE_POLICIES);
82
Tim Wawrzynczak3a9cde92020-05-29 14:19:15 -060083 dptf_write_critical_policies(config->policies.critical,
84 DPTF_MAX_CRITICAL_POLICIES);
85
Tim Wawrzynczak46f6fcf2020-05-29 14:29:53 -060086 /* Controls */
87 dptf_write_charger_perf(config->controls.charger_perf, DPTF_MAX_CHARGER_PERF_STATES);
Tim Wawrzynczak2ad8ffe2020-05-29 14:39:02 -060088 dptf_write_fan_perf(config->controls.fan_perf, DPTF_MAX_FAN_PERF_STATES);
Tim Wawrzynczakbb5c2552020-05-29 14:46:19 -060089 dptf_write_power_limits(&config->controls.power_limits);
Tim Wawrzynczak46f6fcf2020-05-29 14:29:53 -060090
Tim Wawrzynczake4d8ebc2020-05-29 14:58:16 -060091 /* Fan options */
92 dptf_write_fan_options(config->options.fan.fine_grained_control,
93 config->options.fan.step_size,
94 config->options.fan.low_speed_notify);
95
96 /* TSR options */
97 for (p = DPTF_TEMP_SENSOR_0, i = 0; p <= DPTF_TEMP_SENSOR_3; ++p, ++i) {
98 if (tsr_en[i]) {
99 dptf_write_tsr_hysteresis(config->options.tsr[i].hysteresis);
100 dptf_write_STR(config->options.tsr[i].desc);
101 }
102 }
103
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600104 printk(BIOS_INFO, "\\_SB.DPTF: %s at %s\n", dev->chip_ops->name, dev_path(dev));
105}
106
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600107static int get_STA_value(const struct drivers_intel_dptf_config *config,
108 enum dptf_participant participant)
109{
110 return is_participant_used(config, participant) ?
111 ACPI_STATUS_DEVICE_ALL_ON :
112 ACPI_STATUS_DEVICE_ALL_OFF;
113}
114
115static void dptf_write_generic_participant(const char *name,
116 enum dptf_generic_participant_type ptype,
117 const char *str, int sta_val)
118{
119 /* Auto-incrementing UID for generic participants */
120 static int generic_uid = 0;
121
122 acpigen_write_device(name);
123
124 if (CONFIG(DPTF_USE_EISA_HID)) {
125 acpigen_write_name("_HID");
126 acpigen_emit_eisaid(GENERIC_HID_EISAID);
127 } else {
128 acpigen_write_name_string("_HID", GENERIC_HID);
129 }
130
131 acpigen_write_name_integer("_UID", generic_uid++);
132 acpigen_write_STA(sta_val);
133
134 if (str)
135 acpigen_write_name_string("_STR", str);
136
137 acpigen_write_name_integer("PTYP", ptype);
138
139 acpigen_pop_len(); /* Device */
140}
141
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600142/* Add static definitions of DPTF devices into the DSDT */
143static void dptf_inject_dsdt(const struct device *dev)
144{
145 const struct drivers_intel_dptf_config *config;
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600146 enum dptf_participant participant;
147 struct device *parent;
148 char name[5];
149 int i;
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600150
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600151 /* The CPU device gets an _ADR that matches the ACPI PCI address for 00:04.00 */
152 parent = dev && dev->bus ? dev->bus->dev : NULL;
153 if (!parent || parent->path.type != DEVICE_PATH_PCI) {
154 printk(BIOS_ERR, "%s: DPTF objects must live under 00:04.0 PCI device\n",
155 __func__);
156 return;
157 }
158
159 config = config_of(dev);
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600160 acpigen_write_scope("\\_SB");
161
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600162 /* DPTF CPU device - \_SB.TCPU */
163 acpigen_write_device("TCPU");
164 acpigen_write_ADR_pci_device(parent);
165 acpigen_write_STA(get_STA_value(config, DPTF_CPU));
166 acpigen_pop_len(); /* Device */
167
168 /* Toplevel DPTF device - \_SB.DPTF*/
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600169 acpigen_write_device(acpi_device_name(dev));
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600170 if (CONFIG(DPTF_USE_EISA_HID)) {
171 acpigen_write_name("_HID");
172 acpigen_emit_eisaid(DPTF_DEVICE_HID_EISAID);
173 } else {
174 acpigen_write_name_string("_HID", DPTF_DEVICE_HID);
175 }
176
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600177 acpigen_write_name_integer("_UID", 0);
Tim Wawrzynczakff2f6b22020-05-29 13:24:03 -0600178 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
179
180 /*
181 * The following devices live underneath \_SB.DPTF:
182 * - Fan, \_SB.DPTF.TFN1
183 * - Charger, \_SB.DPTF.TCHG
184 * - Temperature Sensors, \_SB.DPTF.TSRn
185 */
186
187 acpigen_write_device("TFN1");
188 if (CONFIG(DPTF_USE_EISA_HID)) {
189 acpigen_write_name("_HID");
190 acpigen_emit_eisaid(FAN_HID_EISAID);
191 } else {
192 acpigen_write_name_string("_HID", FAN_HID);
193 }
194
195 acpigen_write_name_integer("_UID", 0);
196 acpigen_write_STA(get_STA_value(config, DPTF_FAN));
197 acpigen_pop_len(); /* Device */
198
199 dptf_write_generic_participant("TCHG", DPTF_GENERIC_PARTICIPANT_TYPE_CHARGER,
200 DEFAULT_CHARGER_STR, get_STA_value(config,
201 DPTF_CHARGER));
202
203 for (i = 0, participant = DPTF_TEMP_SENSOR_0; i < 4; ++i, ++participant) {
204 snprintf(name, sizeof(name), "TSR%1d", i);
205 dptf_write_generic_participant(name, DPTF_GENERIC_PARTICIPANT_TYPE_TSR,
206 NULL, get_STA_value(config, participant));
207 }
Tim Wawrzynczak103bd5e2020-05-29 13:11:00 -0600208
209 acpigen_pop_len(); /* DPTF Device */
210 acpigen_pop_len(); /* Scope */
211}
212
213static struct device_operations dptf_ops = {
214 .read_resources = noop_read_resources,
215 .set_resources = noop_set_resources,
216 .acpi_name = dptf_acpi_name,
217 .acpi_fill_ssdt = dptf_fill_ssdt,
218 .acpi_inject_dsdt = dptf_inject_dsdt,
219};
220
221static void dptf_enable_dev(struct device *dev)
222{
223 dev->ops = &dptf_ops;
224}
225
226struct chip_operations drivers_intel_dptf_ops = {
227 CHIP_NAME("Intel DPTF")
228 .enable_dev = dptf_enable_dev,
229};