]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
x86: acpi: Support generation of the DBG2 table
authorSimon Glass <sjg@chromium.org>
Tue, 22 Sep 2020 18:45:10 +0000 (12:45 -0600)
committerBin Meng <bmeng.cn@gmail.com>
Fri, 25 Sep 2020 03:27:17 +0000 (11:27 +0800)
Add an implementation of the DBG2 (Debug Port Table 2) ACPI table.
Adjust one of the header includes to be in the correct order, before
adding more.

Note that the DBG2 table is generic but the PCI UART is x86-specific at
present since it assumes an ns16550 UART. It can be generalised later
if necessary.

Signed-off-by: Simon Glass <sjg@chromium.org>
arch/x86/include/asm/acpi_table.h
arch/x86/lib/acpi_table.c
include/acpi/acpi_table.h
lib/acpi/acpi_table.c

index 7047ee6c7724ce850767461ecb96ca8c48167683..1b7ff509516498b06c3fe82a838b14fe2d4644cd 100644 (file)
@@ -46,6 +46,17 @@ u32 acpi_fill_csrt(u32 current);
  */
 int acpi_write_hpet(struct acpi_ctx *ctx);
 
+/**
+ * acpi_write_dbg2_pci_uart() - Write out a DBG2 table
+ *
+ * @ctx: Current ACPI context
+ * @dev: Debug UART device to describe
+ * @access_size: Access size for UART (e.g. ACPI_ACCESS_SIZE_DWORD_ACCESS)
+ * @return 0 if OK, -ve on error
+ */
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+                            uint access_size);
+
 /**
  * acpi_create_gnvs() - Create a GNVS (Global Non Volatile Storage) table
  *
index 0080c96cfe7768b2de2385d5c9a53c644b7bdddf..e257c7898383b1606d48e7521ddbdd088b595107 100644 (file)
@@ -15,6 +15,7 @@
 #include <serial.h>
 #include <version.h>
 #include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
 #include <acpi/acpi_table.h>
 #include <asm/acpi/global_nvs.h>
 #include <asm/ioapic.h>
@@ -588,3 +589,43 @@ int acpi_write_hpet(struct acpi_ctx *ctx)
 
        return 0;
 }
+
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+                            uint access_size)
+{
+       struct acpi_dbg2_header *dbg2 = ctx->current;
+       char path[ACPI_PATH_MAX];
+       struct acpi_gen_regaddr address;
+       phys_addr_t addr;
+       int ret;
+
+       if (!device_active(dev)) {
+               log_info("Device not enabled\n");
+               return -EACCES;
+       }
+       /*
+        * PCI devices don't remember their resource allocation information in
+        * U-Boot at present. We assume that MMIO is used for the UART and that
+        * the address space is 32 bytes: ns16550 uses 8 registers of up to
+        * 32-bits each. This is only for debugging so it is not a big deal.
+        */
+       addr = dm_pci_read_bar32(dev, 0);
+       printf("UART addr %lx\n", (ulong)addr);
+
+       memset(&address, '\0', sizeof(address));
+       address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+       address.addrl = (uint32_t)addr;
+       address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
+       address.access_size = access_size;
+
+       ret = acpi_device_path(dev, path, sizeof(path));
+       if (ret)
+               return log_msg_ret("path", ret);
+       acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
+                        ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
+
+       acpi_inc_align(ctx, dbg2->header.length);
+       acpi_add_table(ctx, dbg2);
+
+       return 0;
+}
index f8140446a599c4929882c2bae036c45fe7a6a2b5..c826a797f5b88e0fa598d974b111b617da1e70b3 100644 (file)
@@ -448,6 +448,29 @@ struct __packed acpi_dmar {
 
 #define ACPI_DBG2_UNKNOWN              0x00FF
 
+/* DBG2: Microsoft Debug Port Table 2 header */
+struct __packed acpi_dbg2_header {
+       struct acpi_table_header header;
+       u32 devices_offset;
+       u32 devices_count;
+};
+
+/* DBG2: Microsoft Debug Port Table 2 device entry */
+struct __packed acpi_dbg2_device {
+       u8  revision;
+       u16 length;
+       u8 address_count;
+       u16 namespace_string_length;
+       u16 namespace_string_offset;
+       u16 oem_data_length;
+       u16 oem_data_offset;
+       u16 port_type;
+       u16 port_subtype;
+       u8  reserved[2];
+       u16 base_address_offset;
+       u16 address_size_offset;
+};
+
 /* SPCR (Serial Port Console Redirection table) */
 struct __packed acpi_spcr {
        struct acpi_table_header header;
@@ -522,6 +545,23 @@ int acpi_get_table_revision(enum acpi_tables table);
  */
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
 
+/**
+ * acpi_create_dbg2() - Create a DBG2 table
+ *
+ * This table describes how to access the debug UART
+ *
+ * @dbg2: Place to put information
+ * @port_type: Serial port type (see ACPI_DBG2_...)
+ * @port_subtype: Serial port sub-type (see ACPI_DBG2_...)
+ * @address: ACPI address of port
+ * @address_size: Size of address space
+ * @device_path: Path of device (created using acpi_device_path())
+ */
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+                     int port_type, int port_subtype,
+                     struct acpi_gen_regaddr *address, uint32_t address_size,
+                     const char *device_path);
+
 /**
  * acpi_fill_header() - Set up a new table header
  *
index acc55e7fad69e6e476e4e870b6a44ec7366063bd..908d8903893568c963817969407645e92dad7411 100644 (file)
@@ -264,3 +264,67 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
         */
        acpi_align64(ctx);
 }
+
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+                     int port_type, int port_subtype,
+                     struct acpi_gen_regaddr *address, u32 address_size,
+                     const char *device_path)
+{
+       uintptr_t current;
+       struct acpi_dbg2_device *device;
+       u32 *dbg2_addr_size;
+       struct acpi_table_header *header;
+       size_t path_len;
+       const char *path;
+       char *namespace;
+
+       /* Fill out header fields. */
+       current = (uintptr_t)dbg2;
+       memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
+       header = &dbg2->header;
+
+       header->revision = acpi_get_table_revision(ACPITAB_DBG2);
+       acpi_fill_header(header, "DBG2");
+       header->aslc_revision = ASL_REVISION;
+
+       /* One debug device defined */
+       dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
+       dbg2->devices_count = 1;
+       current += sizeof(struct acpi_dbg2_header);
+
+       /* Device comes after the header */
+       device = (struct acpi_dbg2_device *)current;
+       memset(device, 0, sizeof(struct acpi_dbg2_device));
+       current += sizeof(struct acpi_dbg2_device);
+
+       device->revision = 0;
+       device->address_count = 1;
+       device->port_type = port_type;
+       device->port_subtype = port_subtype;
+
+       /* Base Address comes after device structure */
+       memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
+       device->base_address_offset = current - (uintptr_t)device;
+       current += sizeof(struct acpi_gen_regaddr);
+
+       /* Address Size comes after address structure */
+       dbg2_addr_size = (uint32_t *)current;
+       device->address_size_offset = current - (uintptr_t)device;
+       *dbg2_addr_size = address_size;
+       current += sizeof(uint32_t);
+
+       /* Namespace string comes last, use '.' if not provided */
+       path = device_path ? : ".";
+       /* Namespace string length includes NULL terminator */
+       path_len = strlen(path) + 1;
+       namespace = (char *)current;
+       device->namespace_string_length = path_len;
+       device->namespace_string_offset = current - (uintptr_t)device;
+       strncpy(namespace, path, path_len);
+       current += path_len;
+
+       /* Update structure lengths and checksum */
+       device->length = current - (uintptr_t)device;
+       header->length = current - (uintptr_t)dbg2;
+       header->checksum = table_compute_checksum(dbg2, header->length);
+}