acpi: Add IORT helper functions
[coreboot2.git] / src / drivers / usb / acpi / usb_acpi.c
blob3a9db30dbf7a7447ea58e15edd6d31d351e06863
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <acpi/acpi_device.h>
4 #include <acpi/acpi_pld.h>
5 #include <acpi/acpigen.h>
6 #include <acpi/acpigen_dsm.h>
7 #include <console/console.h>
8 #include <device/device.h>
9 #include "chip.h"
12 * Intel Bluetooth DSM
14 * Check Tile Activation (2d19d3e1-5708-4696-bd5b-2c3dbae2d6a9)
16 * Arg2 == 0: Return a package with the following bits set
17 * BIT(0) Indicates whether the device supports other functions
18 * BIT(1) Check Tile Activation
20 * Check/Set Reset Delay (aa10f4e0-81ac-4233-abf6-3b2ac50e28d9)
21 * Arg2 == 0: Return a package with the following bit set
22 * BIT(0) Indicates whether the device supports other functions
23 * BIT(1) Check Bluetooth reset timing
24 * Arg2 == 1: Set the reset delay based on Arg3
27 static void check_reset_delay(void *arg)
29 acpigen_write_if_lequal_op_int(ARG1_OP, 0);
31 acpigen_write_return_singleton_buffer(0x03);
33 acpigen_write_else();
35 acpigen_write_return_singleton_buffer(0x00);
37 acpigen_pop_len();
40 static void set_reset_delay(void *arg)
42 acpigen_write_store_op_to_namestr(ARG3_OP, "RDLY");
45 static void get_feature_flag(void *arg)
47 acpigen_write_if_lequal_op_int(ARG1_OP, 0);
49 acpigen_write_return_singleton_buffer(0x03);
51 acpigen_write_else();
53 acpigen_write_return_singleton_buffer(0x00);
55 acpigen_pop_len();
58 void (*uuid_callbacks1[])(void *) = { check_reset_delay, set_reset_delay };
59 void (*uuid_callbacks2[])(void *) = { get_feature_flag };
61 static void acpi_device_intel_bt(void)
64 * Name (RDLY, 0x69)
66 acpigen_write_name_integer("RDLY", 0x69);
69 * Method (_DSM, 4, Serialized)
70 * {
71 * If ((Arg0 == ToUUID ("aa10f4e0-81ac-4233-abf6-3b2ac50e28d9")))
72 * {
73 * If ((Arg2 == Zero))
74 * {
75 * If ((Arg1 == Zero))
76 * {
77 * Return (Buffer (One)
78 * {
79 * 0x03
80 * })
81 * }
82 * Else
83 * {
84 * Return (Buffer (One)
85 * {
86 * 0x00
87 * })
88 * }
89 * }
90 * If ((Arg2 == One))
91 * {
92 * RDLY = Arg3
93 * }
94 * Return (Zero)
95 * }
96 * ElseIf ((Arg0 == ToUUID ("2d19d3e1-5708-4696-bd5b-2c3dbae2d6a9")))
97 * {
98 * If ((Arg2 == Zero))
99 * {
100 * If ((Arg1 == Zero))
102 * Return (Buffer (One)
104 * 0x00
105 * })
107 * Else
109 * Return (Buffer (One)
111 * 0x00
112 * })
115 * Return (Zero)
117 * Else
119 * Return (Buffer (One)
121 * 0x00
122 * })
126 struct dsm_uuid uuid_callbacks[] = {
127 DSM_UUID("aa10f4e0-81ac-4233-abf6-3b2ac50e28d9", uuid_callbacks1, 2, NULL),
128 DSM_UUID("2d19d3e1-5708-4696-bd5b-2c3dbae2d6a9", uuid_callbacks2, 1, NULL),
131 acpigen_write_dsm_uuid_arr(uuid_callbacks, ARRAY_SIZE(uuid_callbacks));
133 * PowerResource (BTRT, 0x05, 0x0000)
135 * Method (_STA, 0, NotSerialized)
137 * Return (One)
139 * Method (_ON, 0, NotSerialized)
142 * Method (_OFF, 0, NotSerialized)
145 * Method (_RST, 0, NotSerialized)
147 * Local0 = Acquire (CNMT, 0x03E8)
148 * If ((Local0 == Zero))
150 * BTRK (Zero)
151 * Sleep (RDLY)
152 * BTRK (One)
153 * Sleep (RDLY)
155 * Release (CNMT)
159 acpigen_write_power_res("BTRT", 5, 0, NULL, 0);
161 acpigen_write_method("_STA", 0);
163 acpigen_write_return_integer(1);
165 acpigen_pop_len();
167 acpigen_write_method("_ON", 0);
168 acpigen_pop_len();
170 acpigen_write_method("_OFF", 0);
171 acpigen_pop_len();
173 acpigen_write_method("_RST", 0);
175 acpigen_write_store();
176 acpigen_write_acquire("CNMT", 0x03e8);
177 acpigen_emit_byte(LOCAL0_OP);
179 acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
181 acpigen_emit_namestring("BTRK");
182 acpigen_emit_byte(0);
184 acpigen_emit_ext_op(SLEEP_OP);
185 acpigen_emit_namestring("RDLY");
187 acpigen_emit_namestring("BTRK");
188 acpigen_emit_byte(1);
190 acpigen_emit_ext_op(SLEEP_OP);
191 acpigen_emit_namestring("RDLY");
193 acpigen_pop_len();
194 acpigen_write_release("CNMT");
196 acpigen_pop_len();
198 acpigen_write_power_res_end();
201 static bool usb_acpi_add_gpios_to_crs(struct drivers_usb_acpi_config *cfg)
203 if (cfg->privacy_gpio.pin_count)
204 return true;
206 if (cfg->reset_gpio.pin_count && !cfg->has_power_resource)
207 return true;
209 return false;
212 static int usb_acpi_write_gpio(struct acpi_gpio *gpio, int *curr_index)
214 int ret = -1;
216 if (gpio->pin_count == 0)
217 return ret;
219 acpi_device_write_gpio(gpio);
220 ret = *curr_index;
221 (*curr_index)++;
223 return ret;
226 static void usb_acpi_fill_ssdt_generator(const struct device *dev)
228 struct drivers_usb_acpi_config *config = dev->chip_info;
229 const char *path = acpi_device_path(dev);
230 struct acpi_pld pld;
231 struct dsm_usb_config usb_cfg;
233 if (!path || !config)
234 return;
236 /* Don't generate output for hubs, only ports */
237 if (config->type == UPC_TYPE_HUB)
238 return;
240 acpigen_write_scope(path);
241 if (config->desc)
242 acpigen_write_name_string("_DDN", config->desc);
243 acpigen_write_upc(config->type);
245 if (usb_acpi_get_pld(dev, &pld))
246 acpigen_write_pld(&pld);
247 else
248 printk(BIOS_ERR, "Error retrieving PLD for %s\n", path);
250 if (config->usb_lpm_incapable) {
251 usb_cfg.usb_lpm_incapable = 1;
252 acpigen_write_dsm_usb(&usb_cfg);
255 /* Resources */
256 if (usb_acpi_add_gpios_to_crs(config) == true) {
257 struct acpi_dp *dsd;
258 int idx = 0;
259 int reset_gpio_index = -1;
260 int privacy_gpio_index;
262 acpigen_write_name("_CRS");
263 acpigen_write_resourcetemplate_header();
264 if (!config->has_power_resource) {
265 reset_gpio_index = usb_acpi_write_gpio(
266 &config->reset_gpio, &idx);
268 privacy_gpio_index = usb_acpi_write_gpio(&config->privacy_gpio,
269 &idx);
270 acpigen_write_resourcetemplate_footer();
272 dsd = acpi_dp_new_table("_DSD");
273 if (reset_gpio_index >= 0)
274 acpi_dp_add_gpio(dsd, "reset-gpio", path,
275 reset_gpio_index, 0,
276 config->reset_gpio.active_low);
277 if (privacy_gpio_index >= 0)
278 acpi_dp_add_gpio(dsd, "privacy-gpio", path,
279 privacy_gpio_index, 0,
280 config->privacy_gpio.active_low);
281 acpi_dp_write(dsd);
284 if (config->has_power_resource) {
285 const struct acpi_power_res_params power_res_params = {
286 &config->reset_gpio,
287 config->reset_delay_ms,
288 config->reset_off_delay_ms,
289 &config->enable_gpio,
290 config->enable_delay_ms,
291 config->enable_off_delay_ms,
292 NULL,
295 config->use_gpio_for_status
297 acpi_device_add_power_res(&power_res_params);
300 if (config->is_intel_bluetooth)
301 acpi_device_intel_bt();
303 acpigen_pop_len();
305 printk(BIOS_INFO, "%s: %s at %s\n", path,
306 config->desc ? : dev->chip_ops->name, dev_path(dev));
309 static struct device_operations usb_acpi_ops = {
310 .read_resources = noop_read_resources,
311 .set_resources = noop_set_resources,
312 .scan_bus = scan_static_bus,
313 .acpi_fill_ssdt = usb_acpi_fill_ssdt_generator,
316 static void usb_acpi_enable(struct device *dev)
318 dev->ops = &usb_acpi_ops;
321 struct chip_operations drivers_usb_acpi_ops = {
322 .name = "USB ACPI Device",
323 .enable_dev = usb_acpi_enable
326 bool usb_acpi_get_pld(const struct device *usb_device, struct acpi_pld *pld)
328 struct drivers_usb_acpi_config *config;
330 if (!usb_device || !usb_device->chip_info ||
331 usb_device->chip_ops != &drivers_usb_acpi_ops)
332 return false;
334 config = usb_device->chip_info;
335 if (config->use_custom_pld)
336 *pld = config->custom_pld;
337 else
338 acpi_pld_fill_usb(pld, config->type, &config->group);
340 return true;