Tim Wawrzynczak has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/47411 )
Change subject: soc/intel/common: Add North XHCI block driver ......................................................................
soc/intel/common: Add North XHCI block driver
Add a driver for the North XHCI block, which is part of the Type-C Subsystem. This driver only adds support for logging wake events from USB2 and USB3 ports associated with the North XHCI.
Change-Id: I9f28354e031e3eda587f4faf8ef7595dce8b33ea Signed-off-by: Tim Wawrzynczak twawrzynczak@chromium.org --- A src/soc/intel/common/block/include/intelblocks/north_xhci.h A src/soc/intel/common/block/north_xhci/Kconfig A src/soc/intel/common/block/north_xhci/Makefile.inc A src/soc/intel/common/block/north_xhci/elog.c 4 files changed, 138 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/11/47411/1
diff --git a/src/soc/intel/common/block/include/intelblocks/north_xhci.h b/src/soc/intel/common/block/include/intelblocks/north_xhci.h new file mode 100644 index 0000000..a561847 --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/north_xhci.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SOC_INTEL_COMMON_BLOCK_NORTH_XHCI_H +#define SOC_INTEL_COMMON_BLOCK_NORTH_XHCI_H + +#include <stdint.h> +#include <types.h> + +struct north_xhci_usb_info { + uint32_t usb2_port_status_reg; + uint32_t num_usb2_ports; + uint32_t usb3_port_status_reg; + uint32_t num_usb3_ports; +}; + +/* + * soc_get_north_xhci_usb_info() - Get the information about North USB2 & USB3 ports. + * + * This function is used to get USB ports and status register offset information within a North + * XHCI controller. + * + * Return: North USB ports and status register offset info for the SoC. + */ +const struct north_xhci_usb_info *soc_get_north_xhci_usb_info(void); + +/* + * pch_xhci_update_wake_event() - Identify and log North XHCI wake events. + * @info: Information about number of North USB ports and their status reg offset. + * + * This function goes through individual USB port status registers within the North XHCI block + * and identifies if any of those USB ports triggered a wake-up and logs information about those + * ports to the event log. + * + * Returns true if a North XHCI USB port was the source of a wake. + */ +bool north_xhci_update_wake_event(const struct north_xhci_usb_info *info); + +#endif /* SOC_INTEL_COMMON_BLOCK_NORTH_XHCI_H */ diff --git a/src/soc/intel/common/block/north_xhci/Kconfig b/src/soc/intel/common/block/north_xhci/Kconfig new file mode 100644 index 0000000..0517d25 --- /dev/null +++ b/src/soc/intel/common/block/north_xhci/Kconfig @@ -0,0 +1,6 @@ +config SOC_INTEL_COMMON_BLOCK_NORTH_XHCI_ELOG + bool + default n + help + Set this option to identify if the North XHCI caused a wake and log + that information to the event log. diff --git a/src/soc/intel/common/block/north_xhci/Makefile.inc b/src/soc/intel/common/block/north_xhci/Makefile.inc new file mode 100644 index 0000000..9ac3048 --- /dev/null +++ b/src/soc/intel/common/block/north_xhci/Makefile.inc @@ -0,0 +1,2 @@ +#ramstage-$(SOC_INTEL_COMMON_BLOCK_NORTH_XHCI_ELOG) += elog.c +ramstage-y += elog.c diff --git a/src/soc/intel/common/block/north_xhci/elog.c b/src/soc/intel/common/block/north_xhci/elog.c new file mode 100644 index 0000000..5006318 --- /dev/null +++ b/src/soc/intel/common/block/north_xhci/elog.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/io.h> +#include <device/pci_ops.h> +#include <elog.h> +#include <intelblocks/north_xhci.h> +#include <soc/pci_devs.h> +#include <stdint.h> +#include <types.h> + +/* Port Link State */ +#define PORTSC_PLS_MASK 0xf0 +#define PORTSC_PLS_RESUME 0xf0 +/* Connect Status Change */ +#define PORTSC_CSC BIT(17) +/* Port Link State Change */ +#define PORTSC_PLC BIT(22) +/* Wake On Connect Enable */ +#define PORTSC_WCE BIT(25) +/* Wake On Disconnect Enable */ +#define PORTSC_WDE BIT(26) + +/* MMIO space between PORTSC registers */ +#define NEXT_PORT_OFFSET 0x10 + +static bool is_connect_wake_capable(uint32_t portsc) +{ + return !!(portsc & (PORTSC_WDE | PORTSC_WCE)); +} + +static bool connect_status_changed(uint32_t portsc) +{ + return !!(portsc & PORTSC_CSC); +} + +static bool is_link_state_changed(uint32_t portsc) +{ + return !!(portsc & PORTSC_PLC); +} + +static bool link_status_is_resume(uint32_t portsc) +{ + return (portsc & PORTSC_PLS_MASK) == PORTSC_PLS_RESUME; +} + +static bool log_port_wakes(uintptr_t base, uint8_t num, uint8_t event) +{ + uint32_t portsc; + unsigned int i; + bool found = false; + + /* For each port, if it is: + * 1) Capable of wakes on connect/disconnect and connect status changed, or: + * 2) Link state changed and its new state is a resume (indicating USB activity), + * then add a wake event to the elog. + */ + for (i = 0; i < num; i++, base += NEXT_PORT_OFFSET) { + portsc = read32((void *)base); + if (portsc == 0xffffffff) + continue; + + if ((is_connect_wake_capable(portsc) && connect_status_changed(portsc)) || + (is_link_state_changed(portsc) && link_status_is_resume(portsc))) { + elog_add_event_wake(event, i + 1); + found = true; + } + } + + return found; +} + +bool north_xhci_update_wake_event(const struct north_xhci_usb_info *info) +{ + const struct device *tcss_xhci = pcidev_path_on_root(SA_DEV_TCSS_XHCI); + bool found = false; + + if (!tcss_xhci) + return false; + + const uintptr_t mmio_base = pci_read_config32(tcss_xhci, PCI_BASE_ADDRESS_0) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + + found |= log_port_wakes(mmio_base + info->usb2_port_status_reg, + info->num_usb2_ports, + ELOG_WAKE_SOURCE_PME_TCSS_XHCI_USB_2); + + found |= log_port_wakes(mmio_base + info->usb3_port_status_reg, + info->num_usb3_ports, + ELOG_WAKE_SOURCE_PME_TCSS_XHCI_USB_3); + + return found; +}