Martin Roth has uploaded this change for review. ( https://review.coreboot.org/25344
Change subject: ACPI: Add SPCR table ......................................................................
ACPI: Add SPCR table
The SPCR ACPI table is used to indicate whether a serial port or a non-legacy UART interface is available for use with Microsoft Windows Emergency Management Services (EMS).
It is also used by Linux and BITS to determine the serial port configuration.
For more information, see the Reference Serial Port Console Redirection Table - SPCR_Tbl-v102-CP.docx
BUG=b:74392237 TEST=After following commit, Build Grunt, verify SPCR table
Change-Id: I2ff31da061c88a6f3e3cf76285f8ab78ee35509c Signed-off-by: Martin Roth martinroth@google.com --- M src/arch/x86/include/arch/acpi.h M src/superio/Makefile.inc A src/superio/acpi/Makefile.inc A src/superio/acpi/spcr.c 4 files changed, 239 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/44/25344/1
diff --git a/src/arch/x86/include/arch/acpi.h b/src/arch/x86/include/arch/acpi.h index 5418420..3be5c9e 100644 --- a/src/arch/x86/include/arch/acpi.h +++ b/src/arch/x86/include/arch/acpi.h @@ -4,6 +4,7 @@ * Copyright (C) 2004 SUSE LINUX AG * Copyright (C) 2004 Nick Barker * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2013 Sage Electronic Engineering, LLC. * Copyright (C) 2015 Timothy Pearson tpearson@raptorengineeringinc.com, * Raptor Engineering * Copyright (C) 2016 Siemens AG @@ -63,6 +64,7 @@ #define ACPI_TABLE_CREATOR "COREBOOT" /* Must be exactly 8 bytes long! */ #define OEM_ID "CORE " /* Must be exactly 6 bytes long! */ #define ASLC "CORE" /* Must be exactly 4 bytes long! */ +#define SPCR_SIG "SPCR" /* Must be exactly 4 bytes long! */
/* * The assigned ACPI ID for the coreboot project is 'BOOT' @@ -636,6 +638,77 @@ u32 status; } __packed acpi_tstate_t;
+/* SPCR (Serial Port Console Redirection) */ +typedef struct acpi_spcr { + struct acpi_table_header header; + u8 interface_type; + u8 reserved_1; + u8 reserved_2; + u8 reserved_3; + struct acpi_gen_regaddr base_address; + u8 interrupt_type; + u8 irq; + u32 global_system_interrupt; + u8 baud_rate; + u8 parity; + u8 stop_bits; + u8 flow_control; + u8 terminal_type; + u8 reserved_4; + u16 pci_device_id; + u16 pci_vendor_id; + u8 pci_bus_number; + u8 pci_device_number; + u8 pci_function_number; + u32 pci_flags; + u8 pci_segment; + u32 reserved_5; +} __packed acpi_spcr_t; + +#define ACPI_SPCR_REV 1 /* 1.0 */ + +#define SPCR_16550_INTERFACE 0 +#define SPCR_16450_INTERFACE 1 + +#define SPCR_RESERVED_MUST_BE_ZERO 0 + +#define SPCR_NO_INTERRUPT_SUPPORTED 0 +#define SPCR_PIC_INTERRUPT_SUPPORTED (1 << 0) +#define SPCR_APIC_INTERRUPT_SUPPORTED (1 << 1) +#define SPCR_SAPIC_INTERRUPT_SUPPORTED (1 << 2) + +#define SPCR_NO_IRQ 0 +#define SPCR_NO_GSI 0 + +#define SPCR_9600_BAUD 3 +#define SPCR_19200_BAUD 4 +#define SPCR_57600_BAUD 6 +#define SPCR_115200_BAUD 7 + +#define SPCR_NO_PARITY 0 + +#define SPCR_1_STOP_BIT 1 + +#define SPCR_NO_FLOW_CONTROL 0 +#define SPCR_DCD_FLOW_CONTROL (1 << 0) +#define SPCR_RTS_CTS_FLOW_CONTROL (1 << 1) +#define SPCR_XON_XOFF_FLOW_CONTROL (1 << 2) + +#define SPCR_TERM_VT100 0 +#define SPCR_TERM_VT100_PLUS 1 +#define SPCR_TERM_VT_UTF8 2 +#define SPCR_TERM_ANSI 3 + +#define SPCR_DID_NOT_A_PCI_DEVICE 0xffff +#define SPCR_VID_NOT_A_PCI_DEVICE 0xffff +#define SPCR_BUS_NOT_A_PCI_DEVICE 0x00 +#define SPCR_DEV_NOT_A_PCI_DEVICE 0x00 +#define SPCR_FUNC_NOT_A_PCI_DEVICE 0x00 +#define SPCR_PCI_FLAG_NOT_A_PCI_DEVICE 0x00 +#define SPCR_PCI_FLAG_NONE 0x00 +#define SPCR_PCI_FLAG_DO_NOT_SUPRESS_PNP_ENUM (1 << 0) +#define SPCR_PCI_SEGMENT_0 0x00 + unsigned long fw_cfg_acpi_tables(unsigned long start);
/* These are implemented by the target port or north/southbridge. */ @@ -732,6 +805,8 @@ void acpi_write_hest(acpi_hest_t *hest, unsigned long (*acpi_fill_hest)(acpi_hest_t *hest));
+unsigned long acpi_create_spcr(unsigned long current); + unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, acpi_hest_esd_t *esd, u16 type, void *data, u16 len);
diff --git a/src/superio/Makefile.inc b/src/superio/Makefile.inc index 5fc0ecd..630aa77 100644 --- a/src/superio/Makefile.inc +++ b/src/superio/Makefile.inc @@ -13,6 +13,7 @@ ## GNU General Public License for more details. ##
+subdirs-y += acpi subdirs-y += fintek subdirs-y += intel subdirs-y += ite diff --git a/src/superio/acpi/Makefile.inc b/src/superio/acpi/Makefile.inc new file mode 100644 index 0000000..7c12d3c --- /dev/null +++ b/src/superio/acpi/Makefile.inc @@ -0,0 +1,14 @@ +## +## This file is part of the coreboot project. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + +ramstage-y += spcr.c diff --git a/src/superio/acpi/spcr.c b/src/superio/acpi/spcr.c new file mode 100644 index 0000000..b64d786 --- /dev/null +++ b/src/superio/acpi/spcr.c @@ -0,0 +1,149 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * Copyright (C) 2018 Google, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * ACPI - Create the Serial Port Console Redirection Table (SPCR) + */ + + +#include <string.h> +#include <console/console.h> +#include <console/uart.h> +#include <arch/acpi.h> +#include <arch/io.h> +#include <device/device.h> + +static uint8_t get_spcr_baudrate(void) +{ + switch (get_uart_baudrate()) { + case 115200: + return SPCR_115200_BAUD; + case 57600: + return SPCR_57600_BAUD; + case 119200: + return SPCR_19200_BAUD; + case 9600: + return SPCR_9600_BAUD; + default: + printk(BIOS_WARNING, "SPCR Error: Unsupported baud rate.\n" + "SPCR table supports 115200, 57600, 19200, or 9600.\n"); + return 0; + } +} +/* + * Serial Port Console Redirection Table (SPCR) + */ +unsigned long acpi_create_spcr(unsigned long current) +{ + acpi_spcr_t *spcr = (void *)current; + if (!current) + return current; + + acpi_header_t *header = &(spcr->header); + uint8_t baud, acpi_space_type, address_width; + uint8_t irq = SPCR_NO_IRQ; + uint8_t interupt_type = SPCR_NO_INTERRUPT_SUPPORTED; + uint32_t address; + + printk(BIOS_DEBUG, "ACPI: * SPCR\n"); + + baud = get_spcr_baudrate(); + if (baud == 0) + return current; + + if (IS_ENABLED(CONFIG_DRIVERS_UART_8250MEM) || IS_ENABLED(CONFIG_DRIVERS_UART_8250MEM_32)) { + + /* Memory Mapped serial port. */ + acpi_space_type=ACPI_ADDRESS_SPACE_MEMORY; + address = CONFIG_TTYS0_BASE; + + if (IS_ENABLED(CONFIG_DRIVERS_UART_8250MEM_32)) + address_width = 32; + else + address_width = 8; + + } else if (IS_ENABLED(CONFIG_DRIVERS_UART_8250IO)) { + + /* IO Mapped 8250/16450/16550 UART configuration */ + acpi_space_type=ACPI_ADDRESS_SPACE_IO; + address = CONFIG_TTYS0_BASE; + address_width = 8; + + /* TODO - Add a better way than just assuming standard IRQs */ + if ((CONFIG_UART_FOR_CONSOLE == 0) || + (CONFIG_UART_FOR_CONSOLE == 2)) { + irq = 4; + interupt_type = SPCR_PIC_INTERRUPT_SUPPORTED; + } else if ((CONFIG_UART_FOR_CONSOLE == 1) || + (CONFIG_UART_FOR_CONSOLE == 3)) { + irq = 3; + interupt_type = SPCR_PIC_INTERRUPT_SUPPORTED; + } else { + printk(BIOS_WARNING, "SPCR Warning: IRQ is not known." + "Defaulting to NONE.\n"); + } + + } else { + printk( BIOS_ERR, "SPCR Error: unknown UART type\n"); + return current; + } + + /* Prepare the header */ + memset((void *)spcr, 0, sizeof(acpi_spcr_t)); + memcpy(header->signature, SPCR_SIG, 4); + header->length = sizeof(acpi_spcr_t); + header->revision = ACPI_SPCR_REV; + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + header->asl_compiler_revision = 0; + + spcr->interface_type = SPCR_16550_INTERFACE; + spcr->reserved_1 = SPCR_RESERVED_MUST_BE_ZERO; + spcr->reserved_2 = SPCR_RESERVED_MUST_BE_ZERO; + spcr->reserved_3 = SPCR_RESERVED_MUST_BE_ZERO; + + spcr->base_address.space_id = acpi_space_type; + spcr->base_address.bit_width = address_width; + spcr->base_address.bit_offset = 0; + spcr->base_address.access_size = ACPI_ACCESS_SIZE_UNDEFINED; + spcr->base_address.addrl = address; + spcr->base_address.addrh = 0x0; + + spcr->interrupt_type = interupt_type; + spcr->irq = irq; + spcr->global_system_interrupt = SPCR_NO_GSI; + spcr->baud_rate = baud; + spcr->parity = SPCR_NO_PARITY; + spcr->stop_bits = SPCR_1_STOP_BIT; + spcr->flow_control = SPCR_NO_FLOW_CONTROL; + spcr->terminal_type = SPCR_TERM_VT100; + + spcr->reserved_4 = SPCR_RESERVED_MUST_BE_ZERO; + spcr->pci_device_id = SPCR_DID_NOT_A_PCI_DEVICE; + spcr->pci_vendor_id = SPCR_VID_NOT_A_PCI_DEVICE; + spcr->pci_bus_number = SPCR_BUS_NOT_A_PCI_DEVICE; + spcr->pci_device_number = SPCR_DEV_NOT_A_PCI_DEVICE; + spcr->pci_function_number = SPCR_FUNC_NOT_A_PCI_DEVICE; + spcr->pci_flags = SPCR_PCI_FLAG_NOT_A_PCI_DEVICE; + spcr->pci_segment = SPCR_PCI_SEGMENT_0; + spcr->reserved_5 = SPCR_RESERVED_MUST_BE_ZERO; + + header->checksum = acpi_checksum((void *)spcr, spcr->header.length); + + return current + sizeof(acpi_spcr_t); +}