Brandon Breitenstein has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/48253 )
Change subject: drivers/intel/usb4: Add Mux Ack driver ......................................................................
drivers/intel/usb4: Add Mux Ack driver
There are some syncronization issues between EC and Kernel that can cause unwanted side effects in the USB4/TCSS flows if left alone. This driver adds ACPI methods to set a gpio so that EC and Kernel can remain in sync on PMC requests.
Change-Id: Ib584150a0c12bae34ebe8d297288425635873919 Signed-off-by: Brandon Breitenstein brandon.breitenstein@intel.com --- A src/drivers/intel/usb4/mux_ack/Kconfig A src/drivers/intel/usb4/mux_ack/Makefile.inc A src/drivers/intel/usb4/mux_ack/ack.c A src/drivers/intel/usb4/mux_ack/chip.h 4 files changed, 160 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/53/48253/1
diff --git a/src/drivers/intel/usb4/mux_ack/Kconfig b/src/drivers/intel/usb4/mux_ack/Kconfig new file mode 100644 index 0000000..3528a9f --- /dev/null +++ b/src/drivers/intel/usb4/mux_ack/Kconfig @@ -0,0 +1,8 @@ +config DRIVERS_INTEL_USB4_MUX_ACK + bool + depends on HAVE_ACPI_TABLES + help + The mux ack driver is required when syncronization is needed + between the EC and the Kernel on the state transitions of the + Type-C muxes. If your mainboard is utilizing TCSS controlled + muxes select this driver. diff --git a/src/drivers/intel/usb4/mux_ack/Makefile.inc b/src/drivers/intel/usb4/mux_ack/Makefile.inc new file mode 100644 index 0000000..86c43ee --- /dev/null +++ b/src/drivers/intel/usb4/mux_ack/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_INTEL_USB4_MUX_ACK) += ack.c diff --git a/src/drivers/intel/usb4/mux_ack/ack.c b/src/drivers/intel/usb4/mux_ack/ack.c new file mode 100644 index 0000000..0dc186a --- /dev/null +++ b/src/drivers/intel/usb4/mux_ack/ack.c @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <acpi/acpigen.h> +#include <acpi/acpi_device.h> +#include <console/console.h> +#include <device/device.h> +#include <device/path.h> +#include <gpio.h> +#include <string.h> +#include "chip.h" + +/* Unique ID for the ACK _DSM. */ +#define INTEL_USB4_MUX_ACK_DSM_UUID "5e7fb958-b2c5-49dc-90b9-f95b1275e824" + +/* + * Arg0: UUID + * Arg1: Revision ID (set to 1) + * Arg2: Function Index + * 0: Query command implemented + * 1: Query current ACK state + * 2: Set ACK state + * Arg3: A package containing parameters for the function specified by the UUID + * revision ID and function index. + * Function 2: Value to set ACK GPIO + */ + +static void usb4_mux_ack_cb_standard_query(void *arg) +{ + /* + * ToInteger (Arg1, Local2) + * If (Local2 == 1) { + * Return(Buffer() {0x07}) + * } + * Return (Buffer() {0x01}) + */ +acpigen_write_to_integer(ARG1_OP, LOCAL2_OP); + + /* Revision 1 supports 2 Functions beyond the standard query */ + acpigen_write_if_lequal_op_int(LOCAL2_OP, 1); + acpigen_write_return_singleton_buffer(0x07); + acpigen_pop_len(); /* If */ + + /* Other revisions support no additional functions */ + acpigen_write_return_singleton_buffer(0); +} + +static void usb4_mux_ack_cb_get_ack_state(void *arg) +{ + struct acpi_gpio *ack_gpio = arg; + + /* + * // Read ack gpio into Local0 + * Store (_SB.PCI0.GTXS (ack_gpio), Local0) + * Return (Local0) + */ + acpigen_get_tx_gpio(ack_gpio); + acpigen_write_return_op(LOCAL0_OP); +} + +static void usb4_mux_ack_cb_set_ack_state(void *arg) +{ + struct acpi_gpio *ack_gpio = arg; + + /* + * // Get argument for on/off from Arg3[0] + * Local0 = DeRefOf (Arg3[0]) + */ + acpigen_get_package_op_element(ARG3_OP, 0, LOCAL0_OP); + + /* + * If (Local0 == 0) { + * // Turn ACK Off + * _SB.PCI0.CTXS (ack_gpio) + * } + */ + acpigen_write_if_lequal_op_int(LOCAL0_OP, 0); + acpigen_disable_tx_gpio(ack_gpio); + acpigen_pop_len(); /* If */ + + /* + * Else { + * // Turn ACK on + * _SB.PCI0.STXS (ack_gpio) + * } + */ + acpigen_write_else(); + acpigen_enable_tx_gpio(ack_gpio); + acpigen_pop_len(); + + /* Return (Zero) */ + acpigen_write_return_integer(0); +} + +static void (*usb4_mux_ack_callbacks[3])(void *) = { + usb4_mux_ack_cb_standard_query, /* Function 0 */ + usb4_mux_ack_cb_get_ack_state, /* Function 1 */ + usb4_mux_ack_cb_set_ack_state, /* Function 2 */ +}; + +static void usb4_mux_ack_fill_ssdt(const struct device *dev) +{ + const struct drivers_intel_usb4_mux_ack_config *config = dev->chip_info; + const char *scope = acpi_device_scope(dev); + + if (!scope || !config) + return; + + if (!config->ack_gpio.pin_count) { + printk(BIOS_ERR, "%s: Power GPIO required for %s\n", __func__, dev_path(dev)); + return; + } + + /* Write the _DSM that toggles ack with provided GPIO. */ + acpigen_write_scope(scope); + acpigen_write_dsm(INTEL_USB4_MUX_ACK_DSM_UUID, usb4_mux_ack_callbacks, + ARRAY_SIZE(usb4_mux_ack_callbacks), (void *)&config->ack_gpio); + acpigen_pop_len(); /* Scope */ + + printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name, + dev_path(dev)); +} + +static struct device_operations usb4_mux_ack_dev_ops = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .acpi_fill_ssdt = usb4_mux_ack_fill_ssdt, +}; + +static void usb4_mux_ack_enable(struct device *dev) +{ + dev->ops = &usb4_mux_ack_dev_ops; +} + +struct chip_operations drivers_intel_usb4_mux_ack_ops = { + CHIP_NAME("Intel USB4 Mux Ack") + .enable_dev = usb4_mux_ack_enable +}; diff --git a/src/drivers/intel/usb4/mux_ack/chip.h b/src/drivers/intel/usb4/mux_ack/chip.h new file mode 100644 index 0000000..c74df6a --- /dev/null +++ b/src/drivers/intel/usb4/mux_ack/chip.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __DRIVERS_INTEL_USB4_ACK_H__ +#define __DRIVERS_INTEL_USB4_ACK_H__ + +#include <acpi/acpi_device.h> + +struct drivers_intel_usb4_mux_ack_config { + /* GPIO used to tell EC that a mux mode request has been completed. */ + struct acpi_gpio ack_gpio; +}; + +#endif /* __DRIVERS_INTEL_USB4_ACK_H__ */ +