diff options
-rw-r--r-- | arch/x86/include/asm/acpi_table.h | 11 | ||||
-rw-r--r-- | arch/x86/lib/acpi_table.c | 41 | ||||
-rw-r--r-- | include/acpi/acpi_table.h | 40 | ||||
-rw-r--r-- | lib/acpi/acpi_table.c | 64 |
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); +} |