coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
retimer.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
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 <device/path.h>
10 #include <gpio.h>
11 #include <string.h>
12 #include "chip.h"
13 #include "retimer.h"
14 
15 /* Unique ID for the retimer _DSM. */
16 #define INTEL_USB4_RETIMER_DSM_UUID "E0053122-795B-4122-8A5E-57BE1D26ACB3"
17 
18 static const char *usb4_retimer_scope;
19 static const char *usb4_retimer_path_arg(const char *arg)
20 {
21  /* \\_SB.PCI0.TDMx.ARG */
22  static char name[DEVICE_PATH_MAX];
23  snprintf(name, sizeof(name), "%s%c%s", usb4_retimer_scope, '.', arg);
24  return name;
25 }
26 
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 {
32  const char *RFWU = ec_retimer_fw_update_path();
33  const uint8_t data = cmd << USB_RETIMER_FW_UPDATE_OP_SHIFT | port;
34 
35  /* Invoke EC Retimer firmware update command execution */
37  /* If RFWU has return value 0xfe, return error -1 */
40  acpigen_pop_len(); /* If */
41 
48  acpigen_write_if_lequal_namestr_int(RFWU, expected_value);
50  acpigen_pop_len(); /* If */
51 
52  if (cmd == USB_RETIMER_FW_UPDATE_SET_TBT) {
53  /*
54  * EC return either USB_PD_MUX_USB4_ENABLED or USB_PD_MUX_TBT_COMPAT_ENABLED
55  * to RFWU after the USB_RETIMER_FW_UPDATE_SET_TBT command execution. It is
56  * needed to add additional check for USB_PD_MUX_TBT_COMPAT_ENABLED.
57  */
60  acpigen_pop_len(); /* If */
61  }
62 
66  acpigen_pop_len(); /* While */
67 
68  /*
69  * Check whether there is timeout error
70  * Return: -1 if timeout error occurring
71  */
74  acpigen_pop_len(); /* If */
75 }
76 
77 static void enable_retimer_online_state(uint8_t port, struct acpi_gpio *power_gpio)
78 {
79  uint8_t expected_value;
80 
81  /*
82  * Enable_retimer_online_state under NDA
83  * 1. Force power on
84  * 2. Check if there is a device connected
85  * 3. Suspend PD
86  * 4. Set Mux to USB mode
87  * 5. Set Mux to Safe mode
88  * 6. Set Mux to TBT mode
89  */
90 
91  /* Force power on for the retimer on the port */
92  acpigen_enable_tx_gpio(power_gpio);
93 
94  /*
95  * Get MUX mode state
96  * Return -1 if there is a device connected on the port.
97  * Otherwise proceed Retimer firmware upgrade operation.
98  */
99  expected_value = USB_PD_MUX_NONE;
101 
102  /*
103  * Suspend PD
104  * Command: USB_RETIMER_FW_UPDATE_SUSPEND_PD
105  * Expect return value: 0
106  */
107  expected_value = 0;
109 
110  /*
111  * Set MUX USB Mode
112  * Command: USB_RETIMER_FW_UPDATE_SUSPEND_PD
113  * Expect return value: USB_PD_MUX_USB_ENABLED
114  */
115  expected_value = USB_PD_MUX_USB_ENABLED;
117 
118  /*
119  * Set MUX Safe Mode
120  * Command: USB_RETIMER_FW_UPDATE_SET_SAFE
121  * Expect return value: USB_PD_MUX_SAFE_MODE
122  */
123  expected_value = USB_PD_MUX_SAFE_MODE;
125 
126  /*
127  * Set MUX TBT Mode
128  * Command: USB_RETIMER_FW_UPDATE_SET_TBT
129  * Expect return value: USB_PD_MUX_USB4_ENABLED or USB_PD_MUX_TBT_COMPAT_ENABLED
130  */
131  expected_value = USB_PD_MUX_USB4_ENABLED;
133 }
134 
135 static void disable_retimer_online_state(uint8_t port, struct acpi_gpio *power_gpio)
136 {
137  uint8_t expected_value;
138 
139  /*
140  * Disable_retimer_online_state
141  * 1. Set Mux to disconnect mode
142  * 2. Resume PD
143  * 3. Force power off
144  */
145 
146  /*
147  * Set MUX Disconnect Mode
148  * Command: USB_RETIMER_FW_UPDATE_DISCONNECT
149  * Expect return value: 0
150  */
151  expected_value = 0;
153 
154  /*
155  * Resume PD
156  * Command: USB_RETIMER_FW_UPDATE_RESUME_PD
157  * Expect return value: 1
158  */
159  expected_value = 1;
161 
162  /* Force power off */
163  acpigen_disable_tx_gpio(power_gpio);
164 }
165 
166 /*
167  * Arg0: UUID e0053122-795b-4122-8a5e-57be1d26acb3
168  * Arg1: Revision ID (set to 1)
169  * Arg2: Function Index
170  * 0: Query command implemented
171  * 1: Get power state
172  * 2: Set power state
173  * Arg3: A package containing parameters for the function specified
174  * by the UUID, revision ID, function index and port index.
175  */
177 {
178  /*
179  * ToInteger (Arg1, Local1)
180  * If (Local1 == 1) {
181  * Return(Buffer() {0x7})
182  * }
183  * Return (Buffer() {0x01})
184  */
186 
187  /* Revision 1 supports 2 Functions beyond the standard query */
190  acpigen_pop_len(); /* If */
191 
192  /* Other revisions support no additional functions */
194 }
195 
197 {
198  const char *PWR;
199  char pwr[DEVICE_PATH_MAX];
200 
201  snprintf(pwr, sizeof(pwr), "HR.DFP%1d.PWR", port);
202  PWR = usb4_retimer_path_arg(pwr);
203 
204  /*
205  * If (PWR > 0) {
206  * Return (1)
207  * }
208  */
214 
215  /*
216  * Else {
217  * Return (0)
218  * }
219  */
222  acpigen_pop_len();
223 }
224 
226 {
227  struct acpi_gpio *power_gpio = arg;
228  const char *PWR;
229  char pwr[DEVICE_PATH_MAX];
230 
231  snprintf(pwr, sizeof(pwr), "HR.DFP%1d.PWR", port);
232  PWR = usb4_retimer_path_arg(pwr);
233 
234  /*
235  * Get information to set retimer power state from Arg3[0]
236  * Local1 = DeRefOf (Arg3[0])
237  */
239 
240  /*
241  * If ((Local1 == 0) && (PWR > 0)) {
242  * PWR--
243  * If (PWR == 0) {
244  * // Disable retimer online state
245  * }
246  * }
247  */
256  /* PWR-- */
259  acpigen_write_if_lequal_namestr_int(PWR, 0); /* If (PWR == 0) */
260  disable_retimer_online_state(port, power_gpio);
261  acpigen_pop_len(); /* If (PWR == 0) */
262 
263  /*
264  * Else If ((Local1 == 1) && (PWR == 0)) {
265  * // Enable retimer online state
266  * PWR++
267  * }
268  */
278  enable_retimer_online_state(port, power_gpio);
279  /* PWR++ */
282 
283  /*
284  * Else {
285  * Return (0)
286  * }
287  */
290  acpigen_pop_len(); /* Else */
291  acpigen_pop_len(); /* If */
292 
293  /*
294  * If (PWR == 1) {
295  * Return (1)
296  * }
297  */
300 
301  /*
302  * Else {
303  * Return (0)
304  * }
305  */
308  acpigen_pop_len();
309 }
310 
311 static void (*usb4_retimer_callbacks[3])(uint8_t port, void *) = {
312  usb4_retimer_cb_standard_query, /* Function 0 */
313  usb4_retimer_cb_get_power_state, /* Function 1 */
314  usb4_retimer_cb_set_power_state, /* Function 2 */
315 };
316 
317 static void usb4_retimer_write_dsm(uint8_t port, const char *uuid,
318  void (**callbacks)(uint8_t port, void *), size_t count, void *arg)
319 {
321  size_t i;
322 
324 
325  for (i = 0; i < id.count; i++) {
326  /* If (LEqual (Local0, i)) */
328 
329  /* Callback to write if handler. */
330  if (id.callbacks[i])
331  id.callbacks[i](port, id.arg);
332 
333  acpigen_pop_len(); /* If */
334  }
335 }
336 
337 static void usb4_retimer_fill_ssdt(const struct device *dev)
338 {
340  const struct device *usb_device;
341  static char dfp[DEVICE_PATH_MAX];
342  struct acpi_pld pld;
343  uint8_t dfp_port, usb_port;
344  int ec_port = 0;
345 
347  if (!usb4_retimer_scope || !config)
348  return;
349 
350  /* Scope */
352 
353  /* Host router */
354  acpigen_write_device("HR");
357 
358  for (dfp_port = 0; dfp_port < DFP_NUM_MAX; dfp_port++) {
359 
360  if (!config->dfp[dfp_port].power_gpio.pin_count) {
361  printk(BIOS_WARNING, "%s: No DFP%1d power GPIO for %s\n",
362  __func__, dfp_port, dev_path(dev));
363  continue;
364  }
365 
366  usb_device = config->dfp[dfp_port].typec_port;
367  usb_port = usb_device->path.usb.port_id;
368 
370  if (ec_port == -1) {
371  printk(BIOS_ERR, "%s: No relative EC port found for TC port %d\n",
372  __func__, usb_port);
373  continue;
374  }
375  /* DFPx */
376  snprintf(dfp, sizeof(dfp), "DFP%1d", ec_port);
378  /* _ADR part is for the lane adapter */
379  acpigen_write_ADR(dfp_port*2 + 1);
380 
381  /* Fill _PLD with the same USB 3.x object on the Type-C connector */
382  if (CONFIG(DRIVERS_USB_ACPI)) {
383  if (usb_acpi_get_pld(usb_device, &pld))
384  acpigen_write_pld(&pld);
385  else
386  printk(BIOS_ERR, "Error retrieving PLD for USB Type-C %d\n",
387  usb_port);
388  }
389 
390  /* Power online reference counter(_PWR) */
391  acpigen_write_name("PWR");
393 
394  /* Method (_DSM, 4, Serialized) */
395  acpigen_write_method_serialized("_DSM", 0x4);
396  /* ToBuffer (Arg0, Local0) */
398  acpigen_write_if(); /* If (UUID != INTEL_USB4_RETIMER_DSM_UUID) */
403  /* Return (Buffer (One) { 0x0 }) */
405  acpigen_pop_len();
408  (void *)&config->dfp[dfp_port].power_gpio);
409  /* Default case: Return (Buffer (One) { 0x0 }) */
411 
412  acpigen_pop_len(); /* Method _DSM */
413  acpigen_pop_len(); /* DFP */
414  }
415  acpigen_pop_len(); /* Host Router */
416  acpigen_pop_len(); /* Scope */
417 
418  printk(BIOS_INFO, "%s.HR: %s at %s\n", usb4_retimer_scope, dev->chip_ops->name,
419  dev_path(dev));
420 }
421 
422 static struct device_operations usb4_retimer_dev_ops = {
424  .set_resources = noop_set_resources,
425  .acpi_fill_ssdt = usb4_retimer_fill_ssdt,
426 };
427 
428 static void usb4_retimer_enable(struct device *dev)
429 {
430  dev->ops = &usb4_retimer_dev_ops;
431 }
432 
434  CHIP_NAME("Intel USB4 Retimer")
435  .enable_dev = usb4_retimer_enable
436 };
437 
439 {
440  return NULL;
441 }
442 
444 {
445 }
446 
447 /*
448  * This function will convert CPU physical port mapping to abstract
449  * EC port mapping.
450  * For example, board might have enabled TCSS port 1 and 3 as per physical
451  * port mapping. Since only 2 TCSS ports are enabled EC will index it as port 0
452  * and port 1. So there will be an issue when coreboot sends command to EC for
453  * port 3 (with coreboot index of 2). EC will produce an error due to wrong index.
454  *
455  * Note: Each SoC code using retimer driver needs to implement this function
456  * since SoC will have physical port details.
457  */
459 {
460  /* By default assume that retimer port index = Type C port */
461  return (int)typec_port;
462 }
const char * acpi_device_scope(const struct device *dev)
Definition: device.c:158
void acpigen_write_len_f(void)
Definition: acpigen.c:28
void acpigen_write_if(void)
Definition: acpigen.c:1437
void acpigen_write_ADR(uint64_t adr)
Definition: acpigen.c:2122
void acpigen_emit_namestring(const char *namepath)
Definition: acpigen.c:275
void acpigen_write_return_integer(uint64_t arg)
Definition: acpigen.c:1583
void acpigen_write_uuid(const char *uuid)
Definition: acpigen.c:1277
void acpigen_pop_len(void)
Definition: acpigen.c:37
void acpigen_write_scope(const char *name)
Definition: acpigen.c:326
void acpigen_write_zero(void)
Definition: acpigen.c:121
int acpigen_disable_tx_gpio(const struct acpi_gpio *gpio)
Definition: acpigen.c:2023
void acpigen_write_if_lequal_op_int(uint8_t op, uint64_t val)
Definition: acpigen.c:1472
void acpigen_write_sleep(uint64_t sleep_ms)
Definition: acpigen.c:1327
void acpigen_write_method_serialized(const char *name, int nargs)
Definition: acpigen.c:764
void acpigen_write_STA(uint8_t status)
Definition: acpigen.c:783
void acpigen_get_package_op_element(uint8_t package_op, unsigned int element, uint8_t dest_op)
Definition: acpigen.c:333
void acpigen_emit_byte(unsigned char b)
Definition: acpigen.c:61
void acpigen_write_to_integer(uint8_t src, uint8_t dst)
Definition: acpigen.c:1532
void acpigen_write_device(const char *name)
Definition: acpigen.c:769
int acpigen_enable_tx_gpio(const struct acpi_gpio *gpio)
Definition: acpigen.c:2015
void acpigen_write_to_buffer(uint8_t src, uint8_t dst)
Definition: acpigen.c:1525
void acpigen_write_return_singleton_buffer(uint8_t arg)
Definition: acpigen.c:1566
void acpigen_write_else(void)
Definition: acpigen.c:1510
void acpigen_write_name(const char *name)
Definition: acpigen.c:320
void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst)
Definition: acpigen.c:1363
void acpigen_write_pld(const struct acpi_pld *pld)
Definition: acpigen.c:1616
void acpigen_write_if_lequal_namestr_int(const char *namestr, uint64_t val)
Definition: acpigen.c:1486
const char * name
Definition: mmu.c:92
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define printk(level,...)
Definition: stdlib.h:16
const char * dev_path(const struct device *dev)
Definition: device_util.c:149
#define DFP_NUM_MAX
Definition: chip.h:10
static void usb4_retimer_cb_get_power_state(uint8_t port, void *arg)
Definition: retimer.c:196
static void(* usb4_retimer_callbacks[3])(uint8_t port, void *)
Definition: retimer.c:311
static struct device_operations usb4_retimer_dev_ops
Definition: retimer.c:422
__weak void ec_retimer_fw_update(uint8_t data)
Definition: retimer.c:443
static void usb4_retimer_fill_ssdt(const struct device *dev)
Definition: retimer.c:337
#define INTEL_USB4_RETIMER_DSM_UUID
Definition: retimer.c:16
#define USB4_RETIMER_POLL_CYCLE_MS
Definition: retimer.c:29
static void usb4_retimer_cb_set_power_state(uint8_t port, void *arg)
Definition: retimer.c:225
__weak int retimer_get_index_for_typec(uint8_t typec_port)
Definition: retimer.c:458
static void disable_retimer_online_state(uint8_t port, struct acpi_gpio *power_gpio)
Definition: retimer.c:135
struct chip_operations drivers_intel_usb4_retimer_ops
Definition: retimer.c:433
static void enable_retimer_online_state(uint8_t port, struct acpi_gpio *power_gpio)
Definition: retimer.c:77
static void usb4_retimer_cb_standard_query(uint8_t port, void *arg)
Definition: retimer.c:176
static const char * usb4_retimer_scope
Definition: retimer.c:18
static void usb4_retimer_write_dsm(uint8_t port, const char *uuid, void(**callbacks)(uint8_t port, void *), size_t count, void *arg)
Definition: retimer.c:317
__weak const char * ec_retimer_fw_update_path(void)
Definition: retimer.c:438
static void usb4_retimer_execute_ec_cmd(uint8_t port, uint8_t cmd, uint8_t expected_value)
Definition: retimer.c:30
static void usb4_retimer_enable(struct device *dev)
Definition: retimer.c:428
static const char * usb4_retimer_path_arg(const char *arg)
Definition: retimer.c:19
#define USB4_RETIMER_ITERATION_NUM
Definition: retimer.c:28
bool usb_acpi_get_pld(const struct device *usb_device, struct acpi_pld *pld)
Definition: usb_acpi.c:127
@ CONFIG
Definition: dsi_common.h:201
port
Definition: i915.h:29
#define ACPI_STATUS_DEVICE_ALL_ON
Definition: acpigen.h:20
@ ARG0_OP
Definition: acpigen.h:89
@ ARG1_OP
Definition: acpigen.h:90
@ LOCAL1_OP
Definition: acpigen.h:82
@ BREAK_OP
Definition: acpigen.h:147
@ ARG3_OP
Definition: acpigen.h:92
@ LOCAL0_OP
Definition: acpigen.h:81
@ WHILE_OP
Definition: acpigen.h:144
@ LOCAL2_OP
Definition: acpigen.h:83
@ DECREMENT_OP
Definition: acpigen.h:102
@ LNOT_OP
Definition: acpigen.h:130
@ ZERO_OP
Definition: acpigen.h:30
@ LGREATER_OP
Definition: acpigen.h:132
@ ARG2_OP
Definition: acpigen.h:91
@ LEQUAL_OP
Definition: acpigen.h:131
@ INCREMENT_OP
Definition: acpigen.h:101
@ LAND_OP
Definition: acpigen.h:128
#define DSM_UUID(DSM_UUID, DSM_CALLBACKS, DSM_COUNT, DSM_ARG)
Definition: acpigen.h:220
#define CHIP_NAME(X)
Definition: device.h:32
static void noop_read_resources(struct device *dev)
Standard device operations function pointers shims.
Definition: device.h:73
static void noop_set_resources(struct device *dev)
Definition: device.h:74
struct bootblock_arg arg
Definition: decompressor.c:22
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
enum board_config config
Definition: memory.c:448
#define DEVICE_PATH_MAX
Definition: path.h:133
#define USB_PD_MUX_NONE
Definition: retimer.h:7
#define USB_PD_MUX_USB4_ENABLED
Definition: retimer.h:11
#define USB_RETIMER_FW_UPDATE_SET_SAFE
Definition: retimer.h:20
#define USB_PD_MUX_TBT_COMPAT_ENABLED
Definition: retimer.h:10
#define USB_PD_MUX_USB_ENABLED
Definition: retimer.h:8
#define USB_RETIMER_FW_UPDATE_DISCONNECT
Definition: retimer.h:22
#define USB_RETIMER_FW_UPDATE_GET_MUX
Definition: retimer.h:18
#define USB_RETIMER_FW_UPDATE_OP_SHIFT
Definition: retimer.h:13
#define USB_RETIMER_FW_UPDATE_RESUME_PD
Definition: retimer.h:17
#define USB_RETIMER_FW_UPDATE_SUSPEND_PD
Definition: retimer.h:16
#define USB_RETIMER_FW_UPDATE_SET_TBT
Definition: retimer.h:21
#define USB_RETIMER_FW_UPDATE_ERROR
Definition: retimer.h:14
#define USB_PD_MUX_SAFE_MODE
Definition: retimer.h:9
#define USB_RETIMER_FW_UPDATE_SET_USB
Definition: retimer.h:19
const struct smm_save_state_ops *legacy_ops __weak
Definition: save_state.c:8
usb_port
Definition: usb.h:56
#define NULL
Definition: stddef.h:19
unsigned char uint8_t
Definition: stdint.h:8
const char * name
Definition: device.h:29
void(* read_resources)(struct device *dev)
Definition: device.h:39
struct usb_path usb
Definition: path.h:127
Definition: device.h:107
struct chip_operations * chip_ops
Definition: device.h:144
struct device_path path
Definition: device.h:115
struct device_operations * ops
Definition: device.h:143
DEVTREE_CONST void * chip_info
Definition: device.h:164
const char * uuid
Definition: retimer.h:25
void(** callbacks)(uint8_t port, void *)
Definition: retimer.h:26
unsigned int port_id
Definition: path.h:102
#define count
int snprintf(char *buf, size_t size, const char *fmt,...)
Note: This file is only for POSIX compatibility, and is meant to be chain-included via string....
Definition: vsprintf.c:35
typedef void(X86APIP X86EMU_intrFuncs)(int num)