blob: e84d29b6c68cab07f37741ee38c32ccde7239b7f [file] [log] [blame]
Duncan Laurie2cc126b2020-08-28 19:46:35 +00001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include <acpi/acpigen.h>
4#include <acpi/acpi_device.h>
John Zhao0b3f15c2021-04-27 10:47:25 -07005#include <acpi/acpi_pld.h>
Duncan Laurie2cc126b2020-08-28 19:46:35 +00006#include <console/console.h>
7#include <device/device.h>
8#include <device/path.h>
9#include <gpio.h>
John Zhao0b3f15c2021-04-27 10:47:25 -070010#include <string.h>
Duncan Laurie2cc126b2020-08-28 19:46:35 +000011#include "chip.h"
Brandon Breitenstein297d27b2020-12-14 13:52:24 -080012#include "retimer.h"
Duncan Laurie2cc126b2020-08-28 19:46:35 +000013
14/* Unique ID for the retimer _DSM. */
John Zhao0b3f15c2021-04-27 10:47:25 -070015#define INTEL_USB4_RETIMER_DSM_UUID "E0053122-795B-4122-8A5E-57BE1D26ACB3"
16
17static const char *usb4_retimer_scope;
18static const char *usb4_retimer_path_arg(const char *arg)
19{
20 /* \\_SB.PCI0.TDMx.ARG */
21 static char name[DEVICE_PATH_MAX];
22 snprintf(name, sizeof(name), "%s%c%s", usb4_retimer_scope, '.', arg);
23 return name;
24}
25
26/* Each polling cycle takes up to 25 ms with a total of 12 of these iterations */
27#define USB4_RETIMER_ITERATION_NUM 12
28#define USB4_RETIMER_POLL_CYCLE_MS 25
29static void usb4_retimer_execute_ec_cmd(uint8_t port, uint8_t cmd, uint8_t expected_value)
30{
31 const char *RFWU = ec_retimer_fw_update_path();
32 const uint8_t data = cmd << USB_RETIMER_FW_UPDATE_OP_SHIFT | port;
33
34 /* Invoke EC Retimer firmware update command execution */
35 ec_retimer_fw_update(data);
36 /* If RFWU has return value 0xfe, return error -1 */
37 acpigen_write_if_lequal_namestr_int(RFWU, USB_RETIMER_FW_UPDATE_ERROR);
38 acpigen_write_return_integer(-1);
39 acpigen_pop_len(); /* If */
40
41 acpigen_write_store_int_to_op(USB4_RETIMER_ITERATION_NUM, LOCAL2_OP);
42 acpigen_emit_byte(WHILE_OP);
43 acpigen_write_len_f();
44 acpigen_emit_byte(LGREATER_OP);
45 acpigen_emit_byte(LOCAL2_OP);
46 acpigen_emit_byte(ZERO_OP);
47 acpigen_write_if_lequal_namestr_int(RFWU, expected_value);
48 acpigen_emit_byte(BREAK_OP);
49 acpigen_pop_len(); /* If */
50
51 if (cmd == USB_RETIMER_FW_UPDATE_SET_TBT) {
52 /*
53 * EC return either USB_PD_MUX_USB4_ENABLED or USB_PD_MUX_TBT_COMPAT_ENABLED
54 * to RFWU after the USB_RETIMER_FW_UPDATE_SET_TBT command execution. It is
55 * needed to add additional check for USB_PD_MUX_TBT_COMPAT_ENABLED.
56 */
57 acpigen_write_if_lequal_namestr_int(RFWU, USB_PD_MUX_TBT_COMPAT_ENABLED);
58 acpigen_emit_byte(BREAK_OP);
59 acpigen_pop_len(); /* If */
60 }
61
62 acpigen_write_sleep(USB4_RETIMER_POLL_CYCLE_MS);
63 acpigen_emit_byte(DECREMENT_OP);
64 acpigen_emit_byte(LOCAL2_OP);
65 acpigen_pop_len(); /* While */
66
67 /*
68 * Check whether there is timeout error
69 * Return: -1 if timeout error occurring
70 */
71 acpigen_write_if_lequal_op_int(LOCAL2_OP, 0);
72 acpigen_write_return_integer(-1);
73 acpigen_pop_len(); /* If */
74}
75
76static void enable_retimer_online_state(uint8_t port, struct acpi_gpio *power_gpio)
77{
78 uint8_t expected_value;
79
80 /*
81 * Enable_retimer_online_state under NDA
82 * 1. Force power on
83 * 2. Check if there is a device connected
84 * 3. Suspend PD
85 * 4. Set Mux to USB mode
86 * 5. Set Mux to Safe mode
87 * 6. Set Mux to TBT mode
88 */
89
90 /* Force power on for the retimer on the port */
91 acpigen_enable_tx_gpio(power_gpio);
92
93 /*
94 * Get MUX mode state
95 * Return -1 if there is a device connected on the port.
96 * Otherwise proceed Retimer firmware upgrade operation.
97 */
98 expected_value = USB_PD_MUX_NONE;
99 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_GET_MUX, expected_value);
100
101 /*
102 * Suspend PD
103 * Command: USB_RETIMER_FW_UPDATE_SUSPEND_PD
104 * Expect return value: 0
105 */
106 expected_value = 0;
107 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_SUSPEND_PD, expected_value);
108
109 /*
110 * Set MUX USB Mode
111 * Command: USB_RETIMER_FW_UPDATE_SUSPEND_PD
112 * Expect return value: USB_PD_MUX_USB_ENABLED
113 */
114 expected_value = USB_PD_MUX_USB_ENABLED;
115 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_SET_USB, expected_value);
116
117 /*
118 * Set MUX Safe Mode
119 * Command: USB_RETIMER_FW_UPDATE_SET_SAFE
120 * Expect return value: USB_PD_MUX_SAFE_MODE
121 */
122 expected_value = USB_PD_MUX_SAFE_MODE;
123 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_SET_SAFE, expected_value);
124
125 /*
126 * Set MUX TBT Mode
127 * Command: USB_RETIMER_FW_UPDATE_SET_TBT
128 * Expect return value: USB_PD_MUX_USB4_ENABLED or USB_PD_MUX_TBT_COMPAT_ENABLED
129 */
130 expected_value = USB_PD_MUX_USB4_ENABLED;
131 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_SET_TBT, expected_value);
132}
133
134static void disable_retimer_online_state(uint8_t port, struct acpi_gpio *power_gpio)
135{
136 uint8_t expected_value;
137
138 /*
139 * Disable_retimer_online_state
140 * 1. Set Mux to disconnect mode
141 * 2. Resume PD
142 * 3. Force power off
143 */
144
145 /*
146 * Set MUX Disconnect Mode
147 * Command: USB_RETIMER_FW_UPDATE_DISCONNECT
148 * Expect return value: 0
149 */
150 expected_value = 0;
151 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_DISCONNECT, expected_value);
152
153 /*
154 * Resume PD
155 * Command: USB_RETIMER_FW_UPDATE_RESUME_PD
156 * Expect return value: 1
157 */
158 expected_value = 1;
159 usb4_retimer_execute_ec_cmd(port, USB_RETIMER_FW_UPDATE_RESUME_PD, expected_value);
160
161 /* Force power off */
162 acpigen_disable_tx_gpio(power_gpio);
163}
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000164
165/*
John Zhao0b3f15c2021-04-27 10:47:25 -0700166 * Arg0: UUID e0053122-795b-4122-8a5e-57be1d26acb3
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000167 * Arg1: Revision ID (set to 1)
168 * Arg2: Function Index
169 * 0: Query command implemented
John Zhao0b3f15c2021-04-27 10:47:25 -0700170 * 1: Get power state
171 * 2: Set power state
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000172 * Arg3: A package containing parameters for the function specified
John Zhao0b3f15c2021-04-27 10:47:25 -0700173 * by the UUID, revision ID, function index and port index.
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000174 */
John Zhao0b3f15c2021-04-27 10:47:25 -0700175static void usb4_retimer_cb_standard_query(uint8_t port, void *arg)
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000176{
177 /*
John Zhao0b3f15c2021-04-27 10:47:25 -0700178 * ToInteger (Arg1, Local1)
179 * If (Local1 == 1) {
180 * Return(Buffer() {0x7})
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000181 * }
182 * Return (Buffer() {0x01})
183 */
John Zhao0b3f15c2021-04-27 10:47:25 -0700184 acpigen_write_to_integer(ARG1_OP, LOCAL1_OP);
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000185
John Zhao0b3f15c2021-04-27 10:47:25 -0700186 /* Revision 1 supports 2 Functions beyond the standard query */
187 acpigen_write_if_lequal_op_int(LOCAL1_OP, 1);
188 acpigen_write_return_singleton_buffer(0x7);
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000189 acpigen_pop_len(); /* If */
190
191 /* Other revisions support no additional functions */
John Zhao0b3f15c2021-04-27 10:47:25 -0700192 acpigen_write_return_singleton_buffer(0x1);
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000193}
194
John Zhao0b3f15c2021-04-27 10:47:25 -0700195static void usb4_retimer_cb_get_power_state(uint8_t port, void *arg)
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000196{
John Zhao0b3f15c2021-04-27 10:47:25 -0700197 const char *PWR;
198 char pwr[DEVICE_PATH_MAX];
199
200 snprintf(pwr, sizeof(pwr), "HR.DFP%1d.PWR", port);
201 PWR = usb4_retimer_path_arg(pwr);
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000202
203 /*
John Zhao0b3f15c2021-04-27 10:47:25 -0700204 * If (PWR > 0) {
205 * Return (1)
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000206 * }
207 */
John Zhao0b3f15c2021-04-27 10:47:25 -0700208 acpigen_write_if();
209 acpigen_emit_byte(LGREATER_OP);
210 acpigen_emit_namestring(PWR);
211 acpigen_emit_byte(0);
212 acpigen_write_return_integer(1);
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000213
214 /*
215 * Else {
John Zhao0b3f15c2021-04-27 10:47:25 -0700216 * Return (0)
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000217 * }
218 */
219 acpigen_write_else();
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000220 acpigen_write_return_integer(0);
John Zhao0b3f15c2021-04-27 10:47:25 -0700221 acpigen_pop_len();
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000222}
223
John Zhao0b3f15c2021-04-27 10:47:25 -0700224static void usb4_retimer_cb_set_power_state(uint8_t port, void *arg)
Brandon Breitenstein297d27b2020-12-14 13:52:24 -0800225{
John Zhao0b3f15c2021-04-27 10:47:25 -0700226 struct acpi_gpio *power_gpio = arg;
227 const char *PWR;
228 char pwr[DEVICE_PATH_MAX];
229
230 snprintf(pwr, sizeof(pwr), "HR.DFP%1d.PWR", port);
231 PWR = usb4_retimer_path_arg(pwr);
Brandon Breitenstein297d27b2020-12-14 13:52:24 -0800232
233 /*
John Zhao0b3f15c2021-04-27 10:47:25 -0700234 * Get information to set retimer power state from Arg3[0]
235 * Local1 = DeRefOf (Arg3[0])
Brandon Breitenstein297d27b2020-12-14 13:52:24 -0800236 */
John Zhao0b3f15c2021-04-27 10:47:25 -0700237 acpigen_get_package_op_element(ARG3_OP, 0, LOCAL1_OP);
238
239 /*
240 * If ((Local1 == 0) && (PWR > 0)) {
241 * PWR--
242 * If (PWR == 0) {
243 * // Disable retimer online state
244 * }
245 * }
246 */
247 acpigen_write_if();
248 acpigen_emit_byte(LAND_OP);
249 acpigen_emit_byte(LEQUAL_OP);
250 acpigen_emit_byte(LOCAL1_OP);
251 acpigen_emit_byte(0);
252 acpigen_emit_byte(LGREATER_OP);
253 acpigen_emit_namestring(PWR);
254 acpigen_emit_byte(0);
255 /* PWR-- */
256 acpigen_emit_byte(DECREMENT_OP);
257 acpigen_emit_namestring(PWR);
258 acpigen_write_if_lequal_namestr_int(PWR, 0); /* If (PWR == 0) */
259 disable_retimer_online_state(port, power_gpio);
260 acpigen_pop_len(); /* If (PWR == 0) */
261
262 /*
263 * Else If ((Local1 == 1) && (PWR == 0)) {
264 * // Enable retimer online state
265 * PWR++
266 * }
267 */
268 acpigen_write_else();
269 acpigen_write_if();
270 acpigen_emit_byte(LAND_OP);
271 acpigen_emit_byte(LEQUAL_OP);
272 acpigen_emit_byte(LOCAL1_OP);
273 acpigen_emit_byte(1);
274 acpigen_emit_byte(LEQUAL_OP);
275 acpigen_emit_namestring(PWR);
276 acpigen_emit_byte(0);
277 enable_retimer_online_state(port, power_gpio);
278 /* PWR++ */
279 acpigen_emit_byte(INCREMENT_OP);
280 acpigen_emit_namestring(PWR);
281
282 /*
283 * Else {
284 * Return (0)
285 * }
286 */
287 acpigen_write_else();
288 acpigen_write_return_integer(0);
289 acpigen_pop_len(); /* Else */
290 acpigen_pop_len(); /* If */
291
292 /*
293 * If (PWR == 1) {
294 * Return (1)
295 * }
296 */
297 acpigen_write_if_lequal_namestr_int(PWR, 1);
298 acpigen_write_return_integer(1);
299
300 /*
301 * Else {
302 * Return (0)
303 * }
304 */
305 acpigen_write_else();
306 acpigen_write_return_integer(0);
307 acpigen_pop_len();
Brandon Breitenstein297d27b2020-12-14 13:52:24 -0800308}
309
John Zhao0b3f15c2021-04-27 10:47:25 -0700310static void (*usb4_retimer_callbacks[3])(uint8_t port, void *) = {
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000311 usb4_retimer_cb_standard_query, /* Function 0 */
312 usb4_retimer_cb_get_power_state, /* Function 1 */
313 usb4_retimer_cb_set_power_state, /* Function 2 */
314};
315
John Zhao0b3f15c2021-04-27 10:47:25 -0700316static void usb4_retimer_write_dsm(uint8_t port, const char *uuid,
317 void (**callbacks)(uint8_t port, void *), size_t count, void *arg)
318{
319 struct usb4_retimer_dsm_uuid id = DSM_UUID(uuid, callbacks, count, arg);
320 size_t i;
321
322 acpigen_write_to_integer(ARG2_OP, LOCAL0_OP);
323
324 for (i = 0; i < id.count; i++) {
325 /* If (LEqual (Local0, i)) */
326 acpigen_write_if_lequal_op_int(LOCAL0_OP, i);
327
328 /* Callback to write if handler. */
329 if (id.callbacks[i])
330 id.callbacks[i](port, id.arg);
331
332 acpigen_pop_len(); /* If */
333 }
334}
335
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000336static void usb4_retimer_fill_ssdt(const struct device *dev)
337{
John Zhao0b3f15c2021-04-27 10:47:25 -0700338 struct drivers_intel_usb4_retimer_config *config = dev->chip_info;
339 static char dfp[DEVICE_PATH_MAX];
340 struct acpi_pld pld;
341 uint8_t port;
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000342
John Zhao0b3f15c2021-04-27 10:47:25 -0700343 usb4_retimer_scope = acpi_device_scope(dev);
344 if (!usb4_retimer_scope || !config)
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000345 return;
346
John Zhao0b3f15c2021-04-27 10:47:25 -0700347 /* Scope */
348 acpigen_write_scope(usb4_retimer_scope);
349
350 /* Host router */
351 acpigen_write_device("HR");
352 acpigen_write_ADR(0);
353 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
354
355 for (port = 0; port < DFP_NUM_MAX; port++) {
356 if (!config->dfp[port].power_gpio.pin_count) {
357 printk(BIOS_ERR, "%s: No DFP%1d power GPIO for %s\n", __func__,
358 port, dev_path(dev));
359 continue;
360 }
361
362 /* DFPx */
363 snprintf(dfp, sizeof(dfp), "DFP%1d", port);
364 acpigen_write_device(dfp);
365 /* _ADR part is for the lane adapter */
366 acpigen_write_ADR(port*2 + 1);
367
368 /* Fill _PLD with the same USB 3.x object on the Type-C connector */
369 acpi_pld_fill_usb(&pld, UPC_TYPE_PROPRIETARY, &config->dfp[port].group);
370 pld.shape = PLD_SHAPE_OVAL;
371 pld.visible = 1;
372 acpigen_write_pld(&pld);
373
374 /* Power online reference counter(_PWR) */
375 acpigen_write_name("PWR");
376 acpigen_write_zero();
377
378 /* Method (_DSM, 4, Serialized) */
379 acpigen_write_method_serialized("_DSM", 0x4);
380 /* ToBuffer (Arg0, Local0) */
381 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
382 acpigen_write_if(); /* If (UUID != INTEL_USB4_RETIMER_DSM_UUID) */
383 acpigen_emit_byte(LNOT_OP);
384 acpigen_emit_byte(LEQUAL_OP);
385 acpigen_emit_byte(LOCAL0_OP);
386 acpigen_write_uuid(INTEL_USB4_RETIMER_DSM_UUID);
387 /* Return (Buffer (One) { 0x0 }) */
388 acpigen_write_return_singleton_buffer(0x0);
389 acpigen_pop_len();
390 usb4_retimer_write_dsm(port, INTEL_USB4_RETIMER_DSM_UUID,
391 usb4_retimer_callbacks, ARRAY_SIZE(usb4_retimer_callbacks),
392 (void *)&config->dfp[port].power_gpio);
393 /* Default case: Return (Buffer (One) { 0x0 }) */
394 acpigen_write_return_singleton_buffer(0x0);
395
396 acpigen_pop_len(); /* Method _DSM */
397 acpigen_pop_len(); /* DFP */
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000398 }
John Zhao0b3f15c2021-04-27 10:47:25 -0700399 acpigen_pop_len(); /* Host Router */
Duncan Laurie2cc126b2020-08-28 19:46:35 +0000400 acpigen_pop_len(); /* Scope */
401
402 printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
403 dev_path(dev));
404}
405
406static struct device_operations usb4_retimer_dev_ops = {
407 .read_resources = noop_read_resources,
408 .set_resources = noop_set_resources,
409 .acpi_fill_ssdt = usb4_retimer_fill_ssdt,
410};
411
412static void usb4_retimer_enable(struct device *dev)
413{
414 dev->ops = &usb4_retimer_dev_ops;
415}
416
417struct chip_operations drivers_intel_usb4_retimer_ops = {
418 CHIP_NAME("Intel USB4 Retimer")
419 .enable_dev = usb4_retimer_enable
420};
Brandon Breitenstein297d27b2020-12-14 13:52:24 -0800421
422__weak const char *ec_retimer_fw_update_path(void)
423{
424 return NULL;
425}
426
John Zhao0b3f15c2021-04-27 10:47:25 -0700427__weak void ec_retimer_fw_update(uint8_t data)
Brandon Breitenstein297d27b2020-12-14 13:52:24 -0800428{
429}