x86: acpi: Generate SPCR table

Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
Let's provide it in U-Boot.

[1]: https://docs.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Andy Shevchenko 2018-11-20 23:52:38 +02:00 committed by Simon Glass
parent f3275aa4a1
commit b288cd9600
2 changed files with 120 additions and 0 deletions

View file

@ -327,6 +327,8 @@ struct acpi_global_nvs;
#define ACPI_DBG2_USB_XHCI 0x0000
#define ACPI_DBG2_USB_EHCI 0x0001
#define ACPI_DBG2_UNKNOWN 0x00FF
/* SPCR (Serial Port Console Redirection table) */
struct __packed acpi_spcr {
struct acpi_table_header header;

View file

@ -10,6 +10,7 @@
#include <cpu.h>
#include <dm.h>
#include <dm/uclass-internal.h>
#include <serial.h>
#include <version.h>
#include <asm/acpi/global_nvs.h>
#include <asm/acpi_table.h>
@ -336,6 +337,115 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
header->checksum = table_compute_checksum((void *)mcfg, header->length);
}
static void acpi_create_spcr(struct acpi_spcr *spcr)
{
struct acpi_table_header *header = &(spcr->header);
struct serial_device_info serial_info = {0};
ulong serial_address, serial_offset;
uint serial_config;
uint serial_width;
int access_size;
int space_id;
int ret;
/* Fill out header fields */
acpi_fill_header(header, "SPCR");
header->length = sizeof(struct acpi_spcr);
header->revision = 2;
ret = serial_getinfo(&serial_info);
if (ret)
serial_info.type = SERIAL_CHIP_UNKNOWN;
/* Encode chip type */
switch (serial_info.type) {
case SERIAL_CHIP_16550_COMPATIBLE:
spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
break;
case SERIAL_CHIP_UNKNOWN:
default:
spcr->interface_type = ACPI_DBG2_UNKNOWN;
break;
}
/* Encode address space */
switch (serial_info.addr_space) {
case SERIAL_ADDRESS_SPACE_MEMORY:
space_id = ACPI_ADDRESS_SPACE_MEMORY;
break;
case SERIAL_ADDRESS_SPACE_IO:
default:
space_id = ACPI_ADDRESS_SPACE_IO;
break;
}
serial_width = serial_info.reg_width * 8;
serial_offset = serial_info.reg_offset << serial_info.reg_shift;
serial_address = serial_info.addr + serial_offset;
/* Encode register access size */
switch (serial_info.reg_shift) {
case 0:
access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
break;
case 1:
access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
break;
case 2:
access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
break;
case 3:
access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
break;
default:
access_size = ACPI_ACCESS_SIZE_UNDEFINED;
break;
}
debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
/* Fill GAS */
spcr->serial_port.space_id = space_id;
spcr->serial_port.bit_width = serial_width;
spcr->serial_port.bit_offset = 0;
spcr->serial_port.access_size = access_size;
spcr->serial_port.addrl = lower_32_bits(serial_address);
spcr->serial_port.addrh = upper_32_bits(serial_address);
/* Encode baud rate */
switch (serial_info.baudrate) {
case 9600:
spcr->baud_rate = 3;
break;
case 19200:
spcr->baud_rate = 4;
break;
case 57600:
spcr->baud_rate = 6;
break;
case 115200:
spcr->baud_rate = 7;
break;
default:
spcr->baud_rate = 0;
break;
}
ret = serial_getconfig(&serial_config);
if (ret)
serial_config = SERIAL_DEFAULT_CONFIG;
spcr->parity = SERIAL_GET_PARITY(serial_config);
spcr->stop_bits = SERIAL_GET_STOP(serial_config);
/* No PCI devices for now */
spcr->pci_device_id = 0xffff;
spcr->pci_vendor_id = 0xffff;
/* Fix checksum */
header->checksum = table_compute_checksum((void *)spcr, header->length);
}
/*
* QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
*/
@ -350,6 +460,7 @@ ulong write_acpi_tables(ulong start)
struct acpi_fadt *fadt;
struct acpi_mcfg *mcfg;
struct acpi_madt *madt;
struct acpi_spcr *spcr;
int i;
current = start;
@ -438,6 +549,13 @@ ulong write_acpi_tables(ulong start)
acpi_add_table(rsdp, mcfg);
current = ALIGN(current, 16);
debug("ACPI: * SPCR\n");
spcr = (struct acpi_spcr *)current;
acpi_create_spcr(spcr);
current += spcr->header.length;
acpi_add_table(rsdp, spcr);
current = ALIGN(current, 16);
debug("current = %x\n", current);
acpi_rsdp_addr = (unsigned long)rsdp;