summaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block/xhci
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@chromium.org>2019-06-06 15:35:11 -0600
committerPatrick Georgi <pgeorgi@google.com>2019-07-19 17:14:35 +0000
commitef0c2265d73004860a7b18ae5e0f9cb1accfb869 (patch)
tree30a46e55b35a4531adfc43e6b91f9064a1a2ec33 /src/soc/intel/common/block/xhci
parent0f718312f1b57ec300b7486c95e53562be5a2325 (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.c85
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 */ }