aboutsummaryrefslogtreecommitdiff
path: root/lib/acpi
diff options
context:
space:
mode:
authorSimon Glass2020-07-07 13:12:11 -0600
committerBin Meng2020-07-17 14:32:24 +0800
commitfefac0b0643b14e72c356cf05dabcbe7512c4709 (patch)
treec3651cb15214fa2f99b31f5bc94a0e9a9aebe638 /lib/acpi
parent20349781a3ca833c67126888ddfce7c1517c772e (diff)
dm: acpi: Enhance acpi_get_name()
For many device types it is possible to figure out the name just by looking at its uclass or parent. Add a function to handle this, since it allows us to cover the vast majority of cases automatically. However it is sometimes impossible to figure out an ACPI name for a device just by looking at its uclass. For example a touch device may have a vendor-specific name. Add a new "acpi,name" property to allow a custom name to be created. With this new feature we can drop the get_name() methods in the sandbox I2C and SPI drivers. They were only added for testing purposes. Update the tests to use the new values. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'lib/acpi')
-rw-r--r--lib/acpi/acpi_device.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index c66cafcfee8..3c75b6d9629 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -10,6 +10,8 @@
#include <dm.h>
#include <irq.h>
#include <log.h>
+#include <usb.h>
+#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
#include <acpi/acpigen.h>
#include <asm-generic/gpio.h>
@@ -715,3 +717,107 @@ int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev)
return 0;
}
#endif /* CONFIG_SPI */
+
+static const char *acpi_name_from_id(enum uclass_id id)
+{
+ switch (id) {
+ case UCLASS_USB_HUB:
+ /* Root Hub */
+ return "RHUB";
+ /* DSDT: acpi/northbridge.asl */
+ case UCLASS_NORTHBRIDGE:
+ return "MCHC";
+ /* DSDT: acpi/lpc.asl */
+ case UCLASS_LPC:
+ return "LPCB";
+ /* DSDT: acpi/xhci.asl */
+ case UCLASS_USB:
+ /* This only supports USB3.0 controllers at present */
+ return "XHCI";
+ case UCLASS_PWM:
+ return "PWM";
+ default:
+ return NULL;
+ }
+}
+
+static int acpi_check_seq(const struct udevice *dev)
+{
+ if (dev->req_seq == -1) {
+ log_warning("Device '%s' has no seq\n", dev->name);
+ return log_msg_ret("no seq", -ENXIO);
+ }
+
+ return dev->req_seq;
+}
+
+/* If you change this function, add test cases to dm_test_acpi_get_name() */
+int acpi_device_infer_name(const struct udevice *dev, char *out_name)
+{
+ enum uclass_id parent_id = UCLASS_INVALID;
+ enum uclass_id id;
+ const char *name = NULL;
+
+ id = device_get_uclass_id(dev);
+ if (dev_get_parent(dev))
+ parent_id = device_get_uclass_id(dev_get_parent(dev));
+
+ if (id == UCLASS_SOUND)
+ name = "HDAS";
+ else if (id == UCLASS_PCI)
+ name = "PCI0";
+ else if (device_is_on_pci_bus(dev))
+ name = acpi_name_from_id(id);
+ if (!name) {
+ switch (parent_id) {
+ case UCLASS_USB: {
+ struct usb_device *udev = dev_get_parent_priv(dev);
+
+ sprintf(out_name, udev->speed >= USB_SPEED_SUPER ?
+ "HS%02d" : "FS%02d", udev->portnr);
+ name = out_name;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (!name) {
+ int num;
+
+ switch (id) {
+ /* DSDT: acpi/lpss.asl */
+ case UCLASS_SERIAL:
+ num = acpi_check_seq(dev);
+ if (num < 0)
+ return num;
+ sprintf(out_name, "URT%d", num);
+ name = out_name;
+ break;
+ case UCLASS_I2C:
+ num = acpi_check_seq(dev);
+ if (num < 0)
+ return num;
+ sprintf(out_name, "I2C%d", num);
+ name = out_name;
+ break;
+ case UCLASS_SPI:
+ num = acpi_check_seq(dev);
+ if (num < 0)
+ return num;
+ sprintf(out_name, "SPI%d", num);
+ name = out_name;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!name) {
+ log_warning("No name for device '%s'\n", dev->name);
+ return -ENOENT;
+ }
+ if (name != out_name)
+ acpi_copy_name(out_name, name);
+
+ return 0;
+}