drivers/usb: Add chip driver for external USB hub

Add chip driver for soldered down external USB hub. This driver adds
ACPI objects for the hub and any downstream facing ports.

BUG=b:227761300
TEST=Build and boot to OS in Skyrim. Ensure that the hub and any
configured ports have ACPI devices defined in SSDT.

Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com>
Change-Id: I11d7ccc42d3dce8e136eb771f120825980e5c027
Reviewed-on: https://review.coreboot.org/c/coreboot/+/63968
Reviewed-by: Raul Rangel <rrangel@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Karthikeyan Ramasubramanian 2022-05-02 13:16:15 -06:00 committed by Tim Wawrzynczak
parent bcec2904c8
commit 0bb5b1c58a
4 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,8 @@
config DRIVERS_USB_HUB
bool
default n
depends on HAVE_ACPI_TABLES
help
This driver is for soldered down USB Hub in the mainboard. When enabled,
this driver will add ACPI support for the USB hub and any devices on the
downstream facing ports.

View File

@ -0,0 +1 @@
ramstage-$(CONFIG_DRIVERS_USB_HUB) += acpi.c

View File

@ -0,0 +1,88 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
#include <stdlib.h>
#include "chip.h"
static const char *usb_hub_acpi_name(const struct device *dev)
{
char *name;
const char *pattern;
/* USB ACPI driver does not have acpi_name operation defined. Hence return
the ACPI name for both the hub and any downstream facing ports. */
switch (dev->path.usb.port_type) {
case 0:
return "EHUB";
case 2:
pattern = "HS%02d";
break;
case 3:
pattern = "SS%02d";
break;
default:
return NULL;
}
name = malloc(ACPI_NAME_BUFFER_SIZE);
snprintf(name, ACPI_NAME_BUFFER_SIZE, pattern, dev->path.usb.port_id + 1);
name[4] = '\0';
return name;
}
static void usb_hub_add_ports(const struct device *dev)
{
const struct drivers_usb_hub_config *config = config_of(dev);
struct device *port = NULL;
unsigned int child_count = 0;
while ((port = dev_bus_each_child(dev->link_list, port)) != NULL) {
if (child_count++ >= config->port_count) {
printk(BIOS_WARNING, "%s cannot be added. Port Count limit reached.\n",
dev_name(port));
continue;
}
acpigen_write_device(usb_hub_acpi_name(port));
acpigen_write_name_byte("_ADR", port->path.usb.port_id + 1);
acpigen_write_device_end();
}
}
static void usb_hub_acpi_fill_ssdt(const struct device *dev)
{
const struct drivers_usb_hub_config *config = config_of(dev);
const char *scope = acpi_device_scope(dev);
const char *name = acpi_device_name(dev);
acpigen_write_scope(scope);
acpigen_write_device(name);
acpigen_write_ADR(0);
if (config->name)
acpigen_write_name_string("_DDN", config->name);
if (config->desc)
acpigen_write_name_unicode("_STR", config->desc);
usb_hub_add_ports(dev);
acpigen_write_device_end();
acpigen_write_scope_end();
}
static struct device_operations usb_hub_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.scan_bus = scan_static_bus,
.acpi_fill_ssdt = usb_hub_acpi_fill_ssdt,
.acpi_name = usb_hub_acpi_name
};
static void usb_hub_acpi_enable(struct device *dev)
{
dev->ops = &usb_hub_ops;
}
struct chip_operations drivers_usb_hub_ops = {
CHIP_NAME("USB Hub")
.enable_dev = usb_hub_acpi_enable
};

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __DRIVERS_USB_HUB_CHIP_H__
#define __DRIVERS_USB_HUB_CHIP_H__
struct drivers_usb_hub_config {
const char *name;
const char *desc;
unsigned int port_count; /* Number of Super-speed or High-speed ports */
};
#endif /* __DRIVERS_USB_HUB_CHIP_H__ */