Brandon Breitenstein has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/37473 )
Change subject: driver/intel/usb4: Add new driver for USB4 Root Port and Resource Allocation ......................................................................
driver/intel/usb4: Add new driver for USB4 Root Port and Resource Allocation
USB4 requires several changes to the typical PCI logic of devices since it allows for several new devices to be hot plugged by the user. To allow for this there is BUS allocation and resource allocation needed for each root port that is active for USB4 with PCI tunneling. This patch creates a new driver that will take care of the busses and resources necessary for USB4 to be used with PCI Tunneling.
Allocations are as follows: 42 Busses per Root Port 194 MB of Memory per Root Port 448 MB of Prefetch Memory per Root Port
Change-Id: I326c6ba3258463d8cb461d9507abb8d7e12dfc42 Signed-off-by: Brandon Breitenstein brandon.breitenstein@intel.com --- M src/device/pci_device.c A src/drivers/intel/usb4/Kconfig A src/drivers/intel/usb4/Makefile.inc A src/drivers/intel/usb4/usb4.c A src/drivers/intel/usb4/usb4.h M src/include/device/device.h M src/include/device/pci_ids.h 7 files changed, 327 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/73/37473/1
diff --git a/src/device/pci_device.c b/src/device/pci_device.c index 36b7c82..9298152 100644 --- a/src/device/pci_device.c +++ b/src/device/pci_device.c @@ -1259,7 +1259,7 @@
if (state == PCI_ROUTE_SCAN) { link->secondary = parent->subordinate + 1; - link->subordinate = link->secondary; + link->subordinate = link->secondary + dev->usb4_buses; }
if (state == PCI_ROUTE_CLOSE) { diff --git a/src/drivers/intel/usb4/Kconfig b/src/drivers/intel/usb4/Kconfig new file mode 100644 index 0000000..1cabcdf --- /dev/null +++ b/src/drivers/intel/usb4/Kconfig @@ -0,0 +1,5 @@ +config DRIVERS_INTEL_USB4 + bool + help + When enabled, driver/intel/usb4 will enable PCI resources and root + ports to allow for PCI tunnelling for USB4 diff --git a/src/drivers/intel/usb4/Makefile.inc b/src/drivers/intel/usb4/Makefile.inc new file mode 100644 index 0000000..d65b6ae --- /dev/null +++ b/src/drivers/intel/usb4/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_INTEL_USB4) += usb4.c diff --git a/src/drivers/intel/usb4/usb4.c b/src/drivers/intel/usb4/usb4.c new file mode 100644 index 0000000..6c73bdd --- /dev/null +++ b/src/drivers/intel/usb4/usb4.c @@ -0,0 +1,250 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <console/console.h> +#include <device/pci.h> +#include <device/pciexp.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <soc/systemagent.h> +#include <soc/pci_devs.h> +#include "usb4.h" + +static void print_device_info(struct device *dev) +{ + u16 reg16; + + reg16 = pci_read_config16(dev, PCI_DEVICE_ID); + printk(BIOS_SPEW, "USB4: Device id = 0x%08x\n", reg16); + printk(BIOS_SPEW, "class: 0x%02x %s\n" + "subclass: 0x%02x %s\n" + "prog: 0x%02x\n" + "revision: 0x%02x\n", + pci_read_config16(dev, PCI_CLASS_DEVICE) >> 8, + get_pci_class_name(dev), + pci_read_config16(dev, PCI_CLASS_DEVICE) & 0xff, + get_pci_subclass_name(dev), + pci_read_config8(dev, PCI_CLASS_PROG), + pci_read_config8(dev, PCI_REVISION_ID)); + + printk(BIOS_SPEW, "USB4: bus=0x%8x\n", dev->bus->secondary); + printk(BIOS_SPEW, "USB4: dev=0x%08x fun=0x%08x\n****\n", PCI_SLOT(dev->path.pci.devfn), + PCI_FUNC(dev->path.pci.devfn)); +} + +static bool is_usb4_rp_bridge(struct device *dev) +{ + + return PCI_SLOT(dev->path.pci.devfn) == PCH_DEV_SLOT_USB4; +} + +static void usb4_pci_scan_bridge(struct device *dev) +{ + + printk(BIOS_DEBUG, "Scanning for USB4 bridge\n"); + + bool is_usb4_rp = is_usb4_rp_bridge(dev); + if (is_usb4_rp) { + printk(BIOS_DEBUG, "USB4 bridge found adding buses\n"); + dev->usb4_buses = TCSS_MAX_BUS; + } + + pciexp_scan_bridge(dev); + + if (is_usb4_rp) { + printk(BIOS_DEBUG, "Add dummy USB4 device to reserve resources\n"); + struct device *slot; + struct device_path slot_path = { .type = DEVICE_PATH_NONE }; + slot = alloc_dev(dev->link_list, &slot_path); + } +} + +static int check_usb4_switch_port_type(struct device *dev) +{ + u16 device_id; + device_id = pci_read_config16(dev, PCI_DEVICE_ID); + + switch (device_id) { + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP0: + return TCSS_USB4_RP_0; + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP1: + return TCSS_USB4_RP_1; + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP2: + return TCSS_USB4_RP_2; + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP3: + return TCSS_USB4_RP_3; + case PCI_DEVICE_ID_INTEL_TCSS_DMA1_EMEP: + return TCSS_DMA1_EMEP; + case PCI_DEVICE_ID_INTEL_TCSS_DMA2_EMEP: + return TCSS_DMA2_EMEP; + case PCI_DEVICE_ID_INTEL_TCSS_XHCI_EMEP: + return TCSS_XHCI_EMEP; + } + + return -1; +} + +static void usb4_set_resource(struct device *dev, struct usb4_resources *usb4) +{ + pci_write_config16(dev, PCI_MEMORY_BASE, usb4->base); + pci_write_config16(dev, PCI_MEMORY_LIMIT, usb4->limit); + if (usb4->pref_base) { + pci_write_config16(dev, PCI_PREF_MEMORY_BASE, usb4->pref_base & 0xFFFF); + pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, usb4->pref_limit & 0xFFFF); + pci_write_config32(dev, PCI_PREF_BASE_UPPER32, usb4->pref_base >> 16); + pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, usb4->pref_limit >> 16); + } +} + +static void usb4_configure_resource(struct device *dev, struct usb4_resources *usb4) +{ + if (dev && dev->enabled) { + + switch (check_usb4_switch_port_type(dev)) { + case TCSS_USB4_RP_0: + usb4_set_resource(dev, usb4); + break; + + case TCSS_USB4_RP_1: + usb4_set_resource(dev, usb4); + break; + + case TCSS_USB4_RP_2: + usb4_set_resource(dev, usb4); + break; + + case TCSS_USB4_RP_3: + usb4_set_resource(dev, usb4); + break; + + default: + break; + } + + } + + print_device_info(dev); +} + +static void usb4_assign_port_resources(struct device *dev, int num_port) +{ + u16 device_id; + struct usb4_resources usb4; + + device_id = pci_read_config16(dev, PCI_DEVICE_ID); + /* TODO: add checks for any foot ports being found */ + switch (device_id) { + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP0: + break; + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP1: + break; + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP2: + break; + case PCI_DEVICE_ID_INTEL_TCSS_USB4_RP3: + break; + default: + printk(BIOS_SPEW, "Not a USB4 Root Port do not assign resources\n"); + return; + } + + usb4.base = (ALIGN_UP(sa_get_tolud_base(), 32*MiB) + (TCSS_MEM_SIZE * num_port)) >> 16; + usb4.limit = usb4.base + (TCSS_MEM_SIZE >> 16) - 0x10; + /* Allocate prefetch base above 4GB */ + usb4.pref_base = USB4_PREF_MEM_BASE_ADDR + (TCSS_PMEM_SIZE * num_port >> 16); + usb4.pref_limit = usb4.pref_base + (TCSS_PMEM_SIZE >> 16) - 0x10; + usb4_configure_resource(dev, &usb4); + + /* Update root complex subordinate */ + dev->bus->subordinate = usb4.max_bus; + +} + +static void usb4_allocate_resources(struct device *dev, int num_port) +{ + if (!dev) { + printk(BIOS_SPEW, "Failed to find USB4 device, exiting\n"); + return; + } + + printk(BIOS_SPEW, "USB43 root port found assigning resources\n"); + usb4_assign_port_resources(dev, num_port); + +} + +void assign_usb4_resources(struct device *dev) +{ + printk(BIOS_SPEW, "Entered USB4 resource allocation"); + int num_port = -1; + + /* Assign RP 0 */ + dev = dev_find_slot(0, PCH_DEVFN_USB40); + if (dev != NULL) { + num_port++; + print_device_info(dev); + usb4_allocate_resources(dev, num_port); + } + + /* Assign RP 1 */ + dev = dev_find_slot(0, PCH_DEVFN_USB41); + if (dev != NULL) { + num_port++; + print_device_info(dev); + usb4_allocate_resources(dev, num_port); + } + + /* Assign RP 2 */ + dev = dev_find_slot(0, PCH_DEVFN_USB42); + if (dev != NULL) { + num_port++; + print_device_info(dev); + usb4_allocate_resources(dev, num_port); + } + + /* Assign RP 3 */ + dev = dev_find_slot(0, PCH_DEVFN_USB43); + if (dev != NULL) { + num_port++; + print_device_info(dev); + usb4_allocate_resources(dev, num_port); + } +} + +static struct pci_operations pci_ops = { + .set_subsystem = pci_dev_set_subsystem, +}; + +static struct device_operations device_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .scan_bus = usb4_pci_scan_bridge, + .reset_bus = pci_bus_reset, + .ops_pci = &pci_ops, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_USB4_RP0, + PCI_DEVICE_ID_USB4_RP1, + PCI_DEVICE_ID_USB4_RP2, + PCI_DEVICE_ID_USB4_RP3, + 0 +}; + +static const struct pci_driver usb4_pcie __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids, +}; diff --git a/src/drivers/intel/usb4/usb4.h b/src/drivers/intel/usb4/usb4.h new file mode 100644 index 0000000..942ea86 --- /dev/null +++ b/src/drivers/intel/usb4/usb4.h @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef DEVICE_USB4_H +#define DEVICE_USB4_H + +/* + * PCIE ISs for USB4 host router and + * its xHCI, DMA, and xDCI endpoints + * TCSS has 4 USB4 enabled ports + */ +#define PCI_DEVICE_ID_INTEL_TCSS_USB4_RP0 0x9a23 +#define PCI_DEVICE_ID_INTEL_TCSS_USB4_RP1 0x9a25 +#define PCI_DEVICE_ID_INTEL_TCSS_USB4_RP2 0x9a27 +#define PCI_DEVICE_ID_INTEL_TCSS_USB4_RP3 0x9a29 +#define PCI_DEVICE_ID_INTEL_TCSS_XHCI_EMEP 0x9a13 +#define PCI_DEVICE_ID_INTEL_TCSS_XDCI_EMEP 0x9a15 +#define PCI_DEVICE_ID_INTEL_TCSS_DMA1_EMEP 0x9a1b +#define PCI_DEVICE_ID_INTEL_TCSS_DMA2_EMEP 0x9a1d + +#define USB4_PREF_MEM_BASE_ADDR 0x80000 /* This is temp till */ + +/* TCSS port types in order of enumeration */ +#define TCSS_USB4_RP_0 0/* Bx:07.0*/ +#define TCSS_USB4_RP_1 1/* Bx:07.1*/ +#define TCSS_USB4_RP_2 2/* Bx:07.2*/ +#define TCSS_USB4_RP_3 3/* Bx:07.3*/ +#define TCSS_XHCI_EMEP 4/* 0:0:0xD:0*/ +#define TCSS_XDCI_EMEP 5/* 0:0:0xD:1*/ +#define TCSS_DMA1_EMEP 6/* 0:0:0xD:2*/ +#define TCSS_DMA2_EMEP 7/* 0:0:0xD:3*/ + + + + +/* Resources */ +#define TCSS_MAX_BUS 0x2a +#define TCSS_MEM_SIZE (194*MiB) /* 194 MB */ +#define TCSS_PMEM_SIZE (448*MiB) /* 448 MB */ + +struct usb4_resources { + u8 max_bus; + u8 secondary_bus; + u16 base; + u16 limit; + u64 pref_base; + u64 pref_limit; +}; + +void assign_usb4_resources(struct device *dev); +#endif diff --git a/src/include/device/device.h b/src/include/device/device.h index abcd0a4..c719b56 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -129,6 +129,7 @@ unsigned int disable_pcie_aspm : 1; unsigned int hidden : 1; /* set if we should hide from UI */ u8 command; + unsigned int usb4_buses; /* reserved for usb4 ports */
/* Base registers for this device. I/O, MEM and Expansion ROM */ DEVTREE_CONST struct resource *resource_list; diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index b75e596..31e4f8b 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -3616,6 +3616,12 @@ #define PCI_DEVICE_ID_SIS_SIS968_PCIE 0x000a /* D6F0,D7F0 */ #define PCI_DEVICE_ID_SIS_SIS968_HD_AUDIO 0x7502 /* DfF0 */
+/* USB4 */ +#define PCI_DEVICE_ID_USB4_RP0 0x9a23 +#define PCI_DEVICE_ID_USB4_RP1 0x9a25 +#define PCI_DEVICE_ID_USB4_RP2 0x9a27 +#define PCI_DEVICE_ID_USB4_RP3 0x9a29 + /* OLD USAGE FOR COREBOOT */ #define PCI_VENDOR_ID_ACER 0x10b9 #define PCI_DEVICE_ID_ACER_M1535D 0x1533