diff options
-rw-r--r-- | src/drivers/usb/hub/Kconfig | 8 | ||||
-rw-r--r-- | src/drivers/usb/hub/Makefile.inc | 1 | ||||
-rw-r--r-- | src/drivers/usb/hub/acpi.c | 88 | ||||
-rw-r--r-- | src/drivers/usb/hub/chip.h | 12 |
4 files changed, 109 insertions, 0 deletions
diff --git a/src/drivers/usb/hub/Kconfig b/src/drivers/usb/hub/Kconfig new file mode 100644 index 0000000000..32eb7c5fa4 --- /dev/null +++ b/src/drivers/usb/hub/Kconfig @@ -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. diff --git a/src/drivers/usb/hub/Makefile.inc b/src/drivers/usb/hub/Makefile.inc new file mode 100644 index 0000000000..a64d622a03 --- /dev/null +++ b/src/drivers/usb/hub/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_USB_HUB) += acpi.c diff --git a/src/drivers/usb/hub/acpi.c b/src/drivers/usb/hub/acpi.c new file mode 100644 index 0000000000..347e25e5c3 --- /dev/null +++ b/src/drivers/usb/hub/acpi.c @@ -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 +}; diff --git a/src/drivers/usb/hub/chip.h b/src/drivers/usb/hub/chip.h new file mode 100644 index 0000000000..d735f112f9 --- /dev/null +++ b/src/drivers/usb/hub/chip.h @@ -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__ */ |