aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/acpi_table.h11
-rw-r--r--arch/x86/lib/acpi_table.c41
-rw-r--r--include/acpi/acpi_table.h40
-rw-r--r--lib/acpi/acpi_table.c64
4 files changed, 156 insertions, 0 deletions
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 7047ee6..1b7ff50 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -47,6 +47,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
*
* @gnvs: Table to fill in
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 0080c96..e257c78 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -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;
+}
diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h
index f814044..c826a79 100644
--- a/include/acpi/acpi_table.h
+++ b/include/acpi/acpi_table.h
@@ -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;
@@ -523,6 +546,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
*
* This sets all fields except length, revision, checksum and aslc_revision
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index acc55e7..908d890 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -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);
+}