1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <acpi/acpigen.h>
4 #include <acpi/acpi_device.h>
5 #include <acpi/acpi_pld.h>
6 #include <console/console.h>
7 #include <device/device.h>
8 #include <drivers/usb/acpi/chip.h>
15 /* Unique ID for the retimer _DSM. */
16 #define INTEL_USB4_RETIMER_DSM_UUID "E0053122-795B-4122-8A5E-57BE1D26ACB3"
18 static const char *usb4_retimer_scope
;
19 static const char *usb4_retimer_path_arg(const char *arg
)
21 /* \\_SB.PCI0.TDMx.ARG */
22 static char name
[DEVICE_PATH_MAX
];
23 snprintf(name
, sizeof(name
), "%s%c%s", usb4_retimer_scope
, '.', arg
);
27 /* Each polling cycle takes up to 25 ms with a total of 12 of these iterations */
28 #define USB4_RETIMER_ITERATION_NUM 12
29 #define USB4_RETIMER_POLL_CYCLE_MS 25
30 static void usb4_retimer_execute_ec_cmd(uint8_t port
, uint8_t cmd
, uint8_t expected_value
,
31 struct acpi_gpio
*power_gpio
)
33 const char *RFWU
= ec_retimer_fw_update_path();
34 const uint8_t data
= cmd
<< USB_RETIMER_FW_UPDATE_OP_SHIFT
| port
;
36 /* Invoke EC Retimer firmware update command execution */
37 ec_retimer_fw_update(data
);
38 /* If RFWU has return value 0xfe, return error -1 */
39 acpigen_write_if_lequal_namestr_int(RFWU
, USB_RETIMER_FW_UPDATE_ERROR
);
40 acpigen_disable_tx_gpio(power_gpio
);
41 acpigen_write_return_integer(-1);
42 acpigen_pop_len(); /* If */
44 acpigen_write_store_int_to_op(USB4_RETIMER_ITERATION_NUM
, LOCAL2_OP
);
45 acpigen_emit_byte(WHILE_OP
);
46 acpigen_write_len_f();
47 acpigen_emit_byte(LGREATER_OP
);
48 acpigen_emit_byte(LOCAL2_OP
);
49 acpigen_emit_byte(ZERO_OP
);
50 acpigen_write_if_lequal_namestr_int(RFWU
, expected_value
);
51 acpigen_emit_byte(BREAK_OP
);
52 acpigen_pop_len(); /* If */
54 if (cmd
== USB_RETIMER_FW_UPDATE_GET_MUX
) {
55 acpigen_write_if_lequal_namestr_int(RFWU
, USB_RETIMER_FW_UPDATE_INVALID_MUX
);
56 acpigen_write_sleep(USB4_RETIMER_POLL_CYCLE_MS
);
57 acpigen_emit_byte(DECREMENT_OP
);
58 acpigen_emit_byte(LOCAL2_OP
);
59 acpigen_emit_byte(CONTINUE_OP
);
60 acpigen_pop_len(); /* If */
62 acpigen_emit_byte(AND_OP
);
63 acpigen_emit_namestring(RFWU
);
64 acpigen_write_integer(USB_RETIMER_FW_UPDATE_MUX_MASK
);
65 acpigen_emit_byte(LOCAL3_OP
);
67 acpigen_emit_byte(LNOT_OP
);
68 acpigen_emit_byte(LEQUAL_OP
);
69 acpigen_emit_byte(LOCAL3_OP
);
71 acpigen_disable_tx_gpio(power_gpio
);
72 acpigen_write_return_integer(-1);
73 acpigen_pop_len(); /* If */
74 } else if (cmd
== USB_RETIMER_FW_UPDATE_SET_TBT
) {
76 * EC return either USB_PD_MUX_USB4_ENABLED or USB_PD_MUX_TBT_COMPAT_ENABLED
77 * to RFWU after the USB_RETIMER_FW_UPDATE_SET_TBT command execution. It is
78 * needed to add additional check for USB_PD_MUX_TBT_COMPAT_ENABLED.
80 acpigen_write_if_lequal_namestr_int(RFWU
, USB_PD_MUX_TBT_COMPAT_ENABLED
);
81 acpigen_emit_byte(BREAK_OP
);
82 acpigen_pop_len(); /* If */
85 acpigen_write_sleep(USB4_RETIMER_POLL_CYCLE_MS
);
86 acpigen_emit_byte(DECREMENT_OP
);
87 acpigen_emit_byte(LOCAL2_OP
);
88 acpigen_pop_len(); /* While */
91 * Check whether there is timeout error
92 * Return: -1 if timeout error occurring
94 acpigen_write_if_lequal_op_int(LOCAL2_OP
, 0);
95 acpigen_disable_tx_gpio(power_gpio
);
96 acpigen_write_return_integer(-1);
97 acpigen_pop_len(); /* If */
100 static void enable_retimer_online_state(uint8_t port
, struct acpi_gpio
*power_gpio
)
102 uint8_t expected_value
;
105 * Enable_retimer_online_state under NDA
107 * 2. Check if there is a device connected
109 * 4. Set Mux to USB mode
110 * 5. Set Mux to Safe mode
111 * 6. Set Mux to TBT mode
114 /* Force power on for the retimer on the port */
115 acpigen_enable_tx_gpio(power_gpio
);
119 * Return -1 if there is a device connected on the port.
120 * Otherwise proceed Retimer firmware upgrade operation.
122 expected_value
= USB_PD_MUX_NONE
;
123 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_GET_MUX
, expected_value
,
128 * Command: USB_RETIMER_FW_UPDATE_SUSPEND_PD
129 * Expect return value: 0
132 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_SUSPEND_PD
, expected_value
,
137 * Command: USB_RETIMER_FW_UPDATE_SUSPEND_PD
138 * Expect return value: USB_PD_MUX_USB_ENABLED
140 expected_value
= USB_PD_MUX_USB_ENABLED
;
141 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_SET_USB
, expected_value
,
146 * Command: USB_RETIMER_FW_UPDATE_SET_SAFE
147 * Expect return value: USB_PD_MUX_SAFE_MODE
149 expected_value
= USB_PD_MUX_SAFE_MODE
;
150 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_SET_SAFE
, expected_value
,
155 * Command: USB_RETIMER_FW_UPDATE_SET_TBT
156 * Expect return value: USB_PD_MUX_USB4_ENABLED or USB_PD_MUX_TBT_COMPAT_ENABLED
158 expected_value
= USB_PD_MUX_USB4_ENABLED
;
159 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_SET_TBT
, expected_value
,
163 static void disable_retimer_online_state(uint8_t port
, struct acpi_gpio
*power_gpio
)
165 uint8_t expected_value
;
168 * Disable_retimer_online_state
169 * 1. Set Mux to disconnect mode
175 * Set MUX Disconnect Mode
176 * Command: USB_RETIMER_FW_UPDATE_DISCONNECT
177 * Expect return value: 0
180 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_DISCONNECT
, expected_value
,
185 * Command: USB_RETIMER_FW_UPDATE_RESUME_PD
186 * Expect return value: 1
189 usb4_retimer_execute_ec_cmd(port
, USB_RETIMER_FW_UPDATE_RESUME_PD
, expected_value
,
192 /* Force power off */
193 acpigen_disable_tx_gpio(power_gpio
);
197 * Arg0: UUID e0053122-795b-4122-8a5e-57be1d26acb3
198 * Arg1: Revision ID (set to 1)
199 * Arg2: Function Index
200 * 0: Query command implemented
203 * Arg3: A package containing parameters for the function specified
204 * by the UUID, revision ID, function index and port index.
206 static void usb4_retimer_cb_standard_query(uint8_t port
, void *arg
)
209 * ToInteger (Arg1, Local1)
211 * Return(Buffer() {0x7})
213 * Return (Buffer() {0x01})
215 acpigen_write_to_integer(ARG1_OP
, LOCAL1_OP
);
217 /* Revision 1 supports 2 Functions beyond the standard query */
218 acpigen_write_if_lequal_op_int(LOCAL1_OP
, 1);
219 acpigen_write_return_singleton_buffer(0x7);
220 acpigen_pop_len(); /* If */
222 /* Other revisions support no additional functions */
223 acpigen_write_return_singleton_buffer(0x1);
226 static void usb4_retimer_cb_get_power_state(uint8_t port
, void *arg
)
229 char pwr
[DEVICE_PATH_MAX
];
231 snprintf(pwr
, sizeof(pwr
), "HR.DFP%1d.PWR", port
);
232 PWR
= usb4_retimer_path_arg(pwr
);
240 acpigen_emit_byte(LGREATER_OP
);
241 acpigen_emit_namestring(PWR
);
242 acpigen_emit_byte(0);
243 acpigen_write_return_integer(1);
250 acpigen_write_else();
251 acpigen_write_return_integer(0);
255 static void usb4_retimer_cb_set_power_state(uint8_t port
, void *arg
)
257 struct acpi_gpio
*power_gpio
= arg
;
259 char pwr
[DEVICE_PATH_MAX
];
261 snprintf(pwr
, sizeof(pwr
), "HR.DFP%1d.PWR", port
);
262 PWR
= usb4_retimer_path_arg(pwr
);
265 * Get information to set retimer power state from Arg3[0]
266 * Local1 = DeRefOf (Arg3[0])
268 acpigen_get_package_op_element(ARG3_OP
, 0, LOCAL1_OP
);
271 * If ((Local1 == 0) && (PWR > 0)) {
274 * // Disable retimer online state
279 acpigen_emit_byte(LAND_OP
);
280 acpigen_emit_byte(LEQUAL_OP
);
281 acpigen_emit_byte(LOCAL1_OP
);
282 acpigen_emit_byte(0);
283 acpigen_emit_byte(LGREATER_OP
);
284 acpigen_emit_namestring(PWR
);
285 acpigen_emit_byte(0);
287 acpigen_emit_byte(DECREMENT_OP
);
288 acpigen_emit_namestring(PWR
);
289 acpigen_write_if_lequal_namestr_int(PWR
, 0); /* If (PWR == 0) */
290 disable_retimer_online_state(port
, power_gpio
);
291 acpigen_pop_len(); /* If (PWR == 0) */
294 * Else If ((Local1 == 1) && (PWR == 0)) {
295 * // Enable retimer online state
299 acpigen_write_else();
301 acpigen_emit_byte(LAND_OP
);
302 acpigen_emit_byte(LEQUAL_OP
);
303 acpigen_emit_byte(LOCAL1_OP
);
304 acpigen_emit_byte(1);
305 acpigen_emit_byte(LEQUAL_OP
);
306 acpigen_emit_namestring(PWR
);
307 acpigen_emit_byte(0);
308 enable_retimer_online_state(port
, power_gpio
);
310 acpigen_emit_byte(INCREMENT_OP
);
311 acpigen_emit_namestring(PWR
);
318 acpigen_write_else();
319 acpigen_write_return_integer(0);
320 acpigen_pop_len(); /* Else */
321 acpigen_pop_len(); /* If */
328 acpigen_write_if_lequal_namestr_int(PWR
, 1);
329 acpigen_write_return_integer(1);
336 acpigen_write_else();
337 acpigen_write_return_integer(0);
341 static void (*usb4_retimer_callbacks
[3])(uint8_t port
, void *) = {
342 usb4_retimer_cb_standard_query
, /* Function 0 */
343 usb4_retimer_cb_get_power_state
, /* Function 1 */
344 usb4_retimer_cb_set_power_state
, /* Function 2 */
347 static void usb4_retimer_write_dsm(uint8_t port
, const char *uuid
,
348 void (**callbacks
)(uint8_t port
, void *), size_t count
, void *arg
)
350 struct usb4_retimer_dsm_uuid id
= DSM_UUID(uuid
, callbacks
, count
, arg
);
353 acpigen_write_to_integer(ARG2_OP
, LOCAL0_OP
);
355 for (i
= 0; i
< id
.count
; i
++) {
356 /* If (LEqual (Local0, i)) */
357 acpigen_write_if_lequal_op_int(LOCAL0_OP
, i
);
359 /* Callback to write if handler. */
361 id
.callbacks
[i
](port
, id
.arg
);
363 acpigen_pop_len(); /* If */
367 static void usb4_retimer_fill_ssdt(const struct device
*dev
)
369 struct drivers_intel_usb4_retimer_config
*config
= dev
->chip_info
;
370 const struct device
*usb_device
;
371 static char dfp
[DEVICE_PATH_MAX
];
373 uint8_t dfp_port
, usb_port
;
376 usb4_retimer_scope
= acpi_device_scope(dev
);
377 if (!usb4_retimer_scope
|| !config
)
381 acpigen_write_scope(usb4_retimer_scope
);
384 acpigen_write_device("HR");
385 acpigen_write_ADR(0);
386 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON
);
388 for (dfp_port
= 0; dfp_port
< DFP_NUM_MAX
; dfp_port
++) {
389 if (!config
->dfp
[dfp_port
].power_gpio
.pin_count
) {
390 printk(BIOS_WARNING
, "%s: No DFP%1d power GPIO for %s\n",
391 __func__
, dfp_port
, dev_path(dev
));
395 usb_device
= config
->dfp
[dfp_port
].typec_port
;
396 usb_port
= usb_device
->path
.usb
.port_id
;
398 ec_port
= retimer_get_index_for_typec(usb_port
);
400 printk(BIOS_ERR
, "%s: No relative EC port found for TC port %d\n",
405 snprintf(dfp
, sizeof(dfp
), "DFP%1d", ec_port
);
406 acpigen_write_device(dfp
);
407 /* _ADR part is for the lane adapter */
408 acpigen_write_ADR(dfp_port
*2 + 1);
410 /* Fill _PLD with the same USB 3.x object on the Type-C connector */
411 if (CONFIG(DRIVERS_USB_ACPI
)) {
412 if (usb_acpi_get_pld(usb_device
, &pld
))
413 acpigen_write_pld(&pld
);
415 printk(BIOS_ERR
, "Error retrieving PLD for USB Type-C %d\n",
419 /* Power online reference counter(_PWR) */
420 acpigen_write_name("PWR");
421 acpigen_write_zero();
423 /* Method (_DSM, 4, Serialized) */
424 acpigen_write_method_serialized("_DSM", 0x4);
425 /* ToBuffer (Arg0, Local0) */
426 acpigen_write_to_buffer(ARG0_OP
, LOCAL0_OP
);
427 acpigen_write_if(); /* If (UUID != INTEL_USB4_RETIMER_DSM_UUID) */
428 acpigen_emit_byte(LNOT_OP
);
429 acpigen_emit_byte(LEQUAL_OP
);
430 acpigen_emit_byte(LOCAL0_OP
);
431 acpigen_write_uuid(INTEL_USB4_RETIMER_DSM_UUID
);
432 /* Return (Buffer (One) { 0x0 }) */
433 acpigen_write_return_singleton_buffer(0x0);
435 usb4_retimer_write_dsm(ec_port
, INTEL_USB4_RETIMER_DSM_UUID
,
436 usb4_retimer_callbacks
, ARRAY_SIZE(usb4_retimer_callbacks
),
437 (void *)&config
->dfp
[dfp_port
].power_gpio
);
438 /* Default case: Return (Buffer (One) { 0x0 }) */
439 acpigen_write_return_singleton_buffer(0x0);
441 acpigen_pop_len(); /* Method _DSM */
442 acpigen_pop_len(); /* DFP */
444 acpigen_pop_len(); /* Host Router */
445 acpigen_pop_len(); /* Scope */
447 printk(BIOS_INFO
, "%s.HR: %s at %s\n", usb4_retimer_scope
, dev
->chip_ops
->name
,
451 static struct device_operations usb4_retimer_dev_ops
= {
452 .read_resources
= noop_read_resources
,
453 .set_resources
= noop_set_resources
,
454 .acpi_fill_ssdt
= usb4_retimer_fill_ssdt
,
457 static void usb4_retimer_enable(struct device
*dev
)
459 dev
->ops
= &usb4_retimer_dev_ops
;
462 struct chip_operations drivers_intel_usb4_retimer_ops
= {
463 .name
= "Intel USB4 Retimer",
464 .enable_dev
= usb4_retimer_enable
467 __weak
const char *ec_retimer_fw_update_path(void)
472 __weak
void ec_retimer_fw_update(uint8_t data
)
477 * This function will convert CPU physical port mapping to abstract
479 * For example, board might have enabled TCSS port 1 and 3 as per physical
480 * port mapping. Since only 2 TCSS ports are enabled EC will index it as port 0
481 * and port 1. So there will be an issue when coreboot sends command to EC for
482 * port 3 (with coreboot index of 2). EC will produce an error due to wrong index.
484 * Note: Each SoC code using retimer driver needs to implement this function
485 * since SoC will have physical port details.
487 __weak
int retimer_get_index_for_typec(uint8_t typec_port
)
489 /* By default assume that retimer port index = Type C port */
490 return (int)typec_port
;