blob: be9ec35230e93867d09c796091e32de29fc13035 [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>
5#include <console/console.h>
6#include <device/device.h>
7#include <device/path.h>
8#include <gpio.h>
9#include <string.h>
10#include "chip.h"
11
12/* Unique ID for the retimer _DSM. */
13#define INTEL_USB4_RETIMER_DSM_UUID "61788900-C470-42BB-80F0-23A313864593"
14
15/*
16 * Arg0: UUID
17 * Arg1: Revision ID (set to 1)
18 * Arg2: Function Index
19 * 0: Query command implemented
20 * 1: Query force power enable state
21 * 2: Set force power state
22 * Arg3: A package containing parameters for the function specified
23 * by the UUID, revision ID and function index.
24 */
25
26static void usb4_retimer_cb_standard_query(void *arg)
27{
28 /*
29 * ToInteger (Arg1, Local2)
30 * If (Local2 == 1) {
31 * Return(Buffer() {0x07})
32 * }
33 * Return (Buffer() {0x01})
34 */
35 acpigen_write_to_integer(ARG1_OP, LOCAL2_OP);
36
37 /* Revision 1 supports 2 Functions beyond the standard query */
38 acpigen_write_if_lequal_op_int(LOCAL2_OP, 1);
39 acpigen_write_return_singleton_buffer(0x07);
40 acpigen_pop_len(); /* If */
41
42 /* Other revisions support no additional functions */
43 acpigen_write_return_singleton_buffer(0);
44}
45
46static void usb4_retimer_cb_get_power_state(void *arg)
47{
48 struct acpi_gpio *power_gpio = arg;
49
50 /*
51 * // Read power gpio into Local0
52 * Store (\_SB.PCI0.GTXS (power_gpio), Local0)
53 * Return (Local0)
54 */
55 acpigen_get_tx_gpio(power_gpio);
56 acpigen_write_return_op(LOCAL0_OP);
57}
58
59static void usb4_retimer_cb_set_power_state(void *arg)
60{
61 struct acpi_gpio *power_gpio = arg;
62
63 /*
64 * // Get argument for on/off from Arg3[0]
65 * Local0 = DeRefOf (Arg3[0])
66 */
67 acpigen_get_package_op_element(ARG3_OP, 0, LOCAL0_OP);
68
69 /*
70 * If (Local0 == 0) {
71 * // Turn power off
72 * \_SB.PCI0.CTXS (power_gpio)
73 * }
74 */
75 acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
76 acpigen_disable_tx_gpio(power_gpio);
77 acpigen_pop_len(); /* If */
78
79 /*
80 * Else {
81 * // Turn power on
82 * \_SB.PCI0.STXS (power_gpio)
83 * }
84 */
85 acpigen_write_else();
86 acpigen_enable_tx_gpio(power_gpio);
87 acpigen_pop_len();
88
89 /* Return (Zero) */
90 acpigen_write_return_integer(0);
91}
92
93static void (*usb4_retimer_callbacks[3])(void *) = {
94 usb4_retimer_cb_standard_query, /* Function 0 */
95 usb4_retimer_cb_get_power_state, /* Function 1 */
96 usb4_retimer_cb_set_power_state, /* Function 2 */
97};
98
99static void usb4_retimer_fill_ssdt(const struct device *dev)
100{
101 const struct drivers_intel_usb4_retimer_config *config = dev->chip_info;
102 const char *scope = acpi_device_scope(dev);
103
104 if (!dev->enabled || !scope || !config)
105 return;
106
107 if (!config->power_gpio.pin_count) {
108 printk(BIOS_ERR, "%s: Power GPIO required for %s\n", __func__, dev_path(dev));
109 return;
110 }
111
112 /* Write the _DSM that toggles power with provided GPIO. */
113 acpigen_write_scope(scope);
114 acpigen_write_dsm(INTEL_USB4_RETIMER_DSM_UUID, usb4_retimer_callbacks,
115 ARRAY_SIZE(usb4_retimer_callbacks), (void *)&config->power_gpio);
116 acpigen_pop_len(); /* Scope */
117
118 printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
119 dev_path(dev));
120}
121
122static struct device_operations usb4_retimer_dev_ops = {
123 .read_resources = noop_read_resources,
124 .set_resources = noop_set_resources,
125 .acpi_fill_ssdt = usb4_retimer_fill_ssdt,
126};
127
128static void usb4_retimer_enable(struct device *dev)
129{
130 dev->ops = &usb4_retimer_dev_ops;
131}
132
133struct chip_operations drivers_intel_usb4_retimer_ops = {
134 CHIP_NAME("Intel USB4 Retimer")
135 .enable_dev = usb4_retimer_enable
136};