diff options
author | Karthikeyan Ramasubramanian <kramasub@chromium.org> | 2019-06-06 15:35:11 -0600 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-07-19 17:14:35 +0000 |
commit | ef0c2265d73004860a7b18ae5e0f9cb1accfb869 (patch) | |
tree | 30a46e55b35a4531adfc43e6b91f9064a1a2ec33 /src/soc/intel/common/block/xhci | |
parent | 0f718312f1b57ec300b7486c95e53562be5a2325 (diff) |
soc/intel/common/block/xhci: Add API to disable USB devices
Add API to disable USB devices that are not present but are configured
in the device tree either after probing the concerned port status or as
explicitly configured by the variants.
BUG=None
BRANCH=octopus
TEST=Boot to ChromeOS.
Change-Id: Ied12faabee1b8c096f2b27de89ab42ee8be5d94d
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/33377
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/intel/common/block/xhci')
-rw-r--r-- | src/soc/intel/common/block/xhci/xhci.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/xhci/xhci.c b/src/soc/intel/common/block/xhci/xhci.c index c429e7dd58..0bdf1d97ba 100644 --- a/src/soc/intel/common/block/xhci/xhci.c +++ b/src/soc/intel/common/block/xhci/xhci.c @@ -14,11 +14,96 @@ * GNU General Public License for more details. */ +#include <arch/acpi_device.h> +#include <console/console.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <drivers/usb/acpi/chip.h> #include <intelblocks/acpi.h> #include <intelblocks/xhci.h> +#include <soc/pci_devs.h> + +#define XHCI_USB2 2 +#define XHCI_USB3 3 + +/* Current Connect Status */ +#define XHCI_STATUS_CCS (1 << 0) + +static bool is_usb_port_connected(const struct xhci_usb_info *info, + unsigned int port_type, unsigned int port_id) +{ + uintptr_t port_sts_reg; + uint32_t port_status; + const struct resource *res; + + /* Support only USB2 or USB3 ports */ + if (!(port_type == XHCI_USB2 || port_type == XHCI_USB3)) + return false; + + /* Mark out of bound port id as not connected */ + if ((port_type == XHCI_USB2 && port_id >= info->num_usb2_ports) || + (port_type == XHCI_USB3 && port_id >= info->num_usb3_ports)) + return false; + + /* Calculate port status register address and read the status */ + res = find_resource(PCH_DEV_XHCI, PCI_BASE_ADDRESS_0); + /* If the memory BAR is not allocated for XHCI, leave the devices enabled */ + if (!res) + return true; + + if (port_type == XHCI_USB2) + port_sts_reg = (uintptr_t)res->base + + info->usb2_port_status_reg + port_id * 0x10; + else + port_sts_reg = (uintptr_t)res->base + + info->usb3_port_status_reg + port_id * 0x10; + port_status = read32((void *)port_sts_reg); + + /* Ensure that the status is not all 1s */ + if (port_status == 0xffffffff) + return false; + + return !!(port_status & XHCI_STATUS_CCS); +} + +void usb_xhci_disable_unused(bool (*ext_usb_xhci_en_cb)(unsigned int port_type, + unsigned int port_id)) +{ + struct device *xhci, *hub = NULL, *port = NULL; + const struct xhci_usb_info *info = soc_get_xhci_usb_info(); + struct drivers_usb_acpi_config *config; + bool enable; + + xhci = pcidev_path_on_root(PCH_DEVFN_XHCI); + if (!xhci) { + printk(BIOS_ERR, "%s: Could not locate XHCI device in DT\n", __func__); + return; + } + + while ((hub = dev_bus_each_child(xhci->link_list, hub)) != NULL) { + while ((port = dev_bus_each_child(hub->link_list, port)) != NULL) { + enable = true; + config = config_of(port); + if (config->type == UPC_TYPE_INTERNAL) { + /* Probe the connect status of internal ports */ + enable = is_usb_port_connected(info, port->path.usb.port_type, + port->path.usb.port_id); + } else if (ext_usb_xhci_en_cb) { + /* Check the mainboard for the status of external ports */ + enable = ext_usb_xhci_en_cb(port->path.usb.port_type, + port->path.usb.port_id); + } + + if (!enable) { + printk(BIOS_INFO, "%s: Disabling USB Type%d Id%d\n", + __func__, port->path.usb.port_type, + port->path.usb.port_id); + port->enabled = 0; + } + } + } +} __weak void soc_xhci_init(struct device *dev) { /* no-op */ } |