iPXE
spcr.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26#include <errno.h>
27#include <ipxe/serial.h>
28#include <ipxe/pci.h>
29#include <ipxe/ns16550.h>
30#include <ipxe/spcr.h>
31
32/** @file
33 *
34 * ACPI Serial Port Console Redirection (SPCR)
35 *
36 */
37
38#ifdef SERIAL_SPCR
39#define SERIAL_PREFIX_spcr
40#else
41#define SERIAL_PREFIX_spcr __spcr_
42#endif
43
44/** SPCR-defined UART */
45static struct uart spcr_uart = {
46 .refcnt = REF_INIT ( ref_no_free ),
47 .name = "SPCR",
48};
49
50/** SPCR-defined 16550 UART */
51static struct ns16550_uart spcr_ns16550 = {
52 .clock = NS16550_CLK_DEFAULT,
53};
54
55/** Base baud rate for SPCR divisors */
56#define SPCR_BAUD_BASE 115200
57
58/** SPCR baud rate divisors */
60 [SPCR_BAUD_2400] = ( SPCR_BAUD_BASE / 2400 ),
61 [SPCR_BAUD_4800] = ( SPCR_BAUD_BASE / 4800 ),
62 [SPCR_BAUD_9600] = ( SPCR_BAUD_BASE / 9600 ),
63 [SPCR_BAUD_19200] = ( SPCR_BAUD_BASE / 19200 ),
64 [SPCR_BAUD_38400] = ( SPCR_BAUD_BASE / 38400 ),
65 [SPCR_BAUD_57600] = ( SPCR_BAUD_BASE / 57600 ),
66 [SPCR_BAUD_115200] = ( SPCR_BAUD_BASE / 115200 ),
67};
68
69/**
70 * Configure 16550-based serial console
71 *
72 * @v spcr SPCR table
73 * @v uart UART to configure
74 * @ret rc Return status code
75 */
76static int spcr_16550 ( struct spcr_table *spcr, struct uart *uart ) {
77 struct ns16550_uart *ns16550 = &spcr_ns16550;
78
79 /* Set base address */
80 ns16550->base = acpi_ioremap ( &spcr->base, NS16550_LEN );
81 if ( ! ns16550->base ) {
82 DBGC ( uart, "SPCR could not map registers\n" );
83 return -ENODEV;
84 }
85
86 /* Set clock frequency, if specified */
87 if ( spcr->clock )
88 ns16550->clock = le32_to_cpu ( spcr->clock );
89
90 /* Configure UART as a 16550 */
92 uart->priv = ns16550;
93
94 return 0;
95}
96
97/**
98 * Identify default serial console
99 *
100 * @ret uart Default serial console UART, or NULL
101 */
102static struct uart * spcr_console ( void ) {
103 struct uart *uart = &spcr_uart;
104 struct spcr_table *spcr;
105 unsigned int baud;
106 int rc;
107
108 /* Locate SPCR table */
109 spcr = container_of ( acpi_table ( SPCR_SIGNATURE, 0 ),
110 struct spcr_table, acpi );
111 if ( ! spcr ) {
112 DBGC ( uart, "SPCR found no table\n" );
113 goto err_table;
114 }
115 DBGC2 ( uart, "SPCR found table:\n" );
116 DBGC2_HDA ( uart, 0, spcr, sizeof ( *spcr ) );
117 DBGC ( uart, "SPCR is type %d at %02x:%08llx\n",
118 spcr->type, spcr->base.type,
119 ( ( unsigned long long ) le64_to_cpu ( spcr->base.address ) ) );
120 if ( spcr->pci_vendor_id != cpu_to_le16 ( PCI_ANY_ID ) ) {
121 DBGC ( uart, "SPCR is PCI " PCI_FMT " (%04x:%04x)\n",
122 spcr->pci_segment, spcr->pci_bus, spcr->pci_dev,
123 spcr->pci_func, le16_to_cpu ( spcr->pci_vendor_id ),
124 le16_to_cpu ( spcr->pci_device_id ) );
125 }
126
127 /* Get baud rate */
128 baud = 0;
129 if ( le32_to_cpu ( spcr->acpi.length ) >=
130 ( offsetof ( typeof ( *spcr ), precise ) +
131 sizeof ( spcr->precise ) ) ) {
132 baud = le32_to_cpu ( spcr->precise );
133 if ( baud )
134 DBGC ( uart, "SPCR has precise baud rate %d\n", baud );
135 }
136 if ( ( ! baud ) && spcr->baud && ( spcr->baud < SPCR_BAUD_MAX ) ) {
138 DBGC ( uart, "SPCR has baud rate %d\n", baud );
139 }
140 uart->baud = baud;
141
142 /* Initialise according to type */
143 switch ( spcr->type ) {
144 case SPCR_TYPE_16550:
145 case SPCR_TYPE_16450:
147 if ( ( rc = spcr_16550 ( spcr, uart ) ) != 0 )
148 goto err_type;
149 break;
150 default:
151 DBGC ( uart, "SPCR unsupported type %d\n", spcr->type );
152 goto err_type;
153 }
154
155 return uart;
156
157 err_type:
158 err_table:
159 /* Fall back to using fixed serial console */
160 return fixed_serial_console();
161}
162
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition acpi.c:93
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
void * acpi_ioremap(struct acpi_address *address, size_t len)
Map an ACPI generic address.
Definition acpi.c:270
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition efi_block.c:67
Error codes.
#define DBGC2(...)
Definition compiler.h:522
#define DBGC2_HDA(...)
Definition compiler.h:523
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENODEV
No such device.
Definition errno.h:510
#define le16_to_cpu(value)
Definition byteswap.h:113
#define le64_to_cpu(value)
Definition byteswap.h:115
#define le32_to_cpu(value)
Definition byteswap.h:114
#define cpu_to_le16(value)
Definition byteswap.h:107
16550-compatible UART
#define NS16550_CLK_DEFAULT
Default input clock rate (1.8432 MHz)
Definition ns16550.h:95
#define NS16550_LEN
Length of register region.
Definition ns16550.h:15
Serial console.
struct uart * default_serial_console(void)
Get serial console UART.
#define PROVIDE_SERIAL(_subsys, _api_func, _func)
Provide a serial API implementation.
Definition serial.h:39
struct uart_operations ns16550_operations
16550 UART operations
Definition ns16550.c:171
PCI bus.
#define PCI_ANY_ID
Match-anything ID.
Definition pci.h:187
#define PCI_FMT
PCI device debug message format.
Definition pci.h:312
void ref_no_free(struct refcnt *refcnt __unused)
Do not free reference-counted object.
Definition refcnt.c:102
#define REF_INIT(free_fn)
Initialise a static reference counter.
Definition refcnt.h:78
struct uart * fixed_serial_console(void)
Get fixed serial console UART.
Definition serial.c:76
static int spcr_16550(struct spcr_table *spcr, struct uart *uart)
Configure 16550-based serial console.
Definition spcr.c:76
#define SPCR_BAUD_BASE
Base baud rate for SPCR divisors.
Definition spcr.c:56
static struct ns16550_uart spcr_ns16550
SPCR-defined 16550 UART.
Definition spcr.c:51
static const uint8_t spcr_baud_divisor[SPCR_BAUD_MAX]
SPCR baud rate divisors.
Definition spcr.c:59
static struct uart * spcr_console(void)
Identify default serial console.
Definition spcr.c:102
static struct uart spcr_uart
SPCR-defined UART.
Definition spcr.c:45
ACPI Serial Port Console Redirection (SPCR)
#define SPCR_TYPE_16550
16550-compatible
Definition spcr.h:75
#define SPCR_TYPE_16450
16450-compatible
Definition spcr.h:76
#define SPCR_SIGNATURE
Serial Port Console Redirection table signature.
Definition spcr.h:16
#define SPCR_TYPE_16550_GAS
16550-compatible
Definition spcr.h:77
@ SPCR_BAUD_4800
Definition spcr.h:82
@ SPCR_BAUD_115200
Definition spcr.h:87
@ SPCR_BAUD_MAX
Definition spcr.h:88
@ SPCR_BAUD_38400
Definition spcr.h:85
@ SPCR_BAUD_57600
Definition spcr.h:86
@ SPCR_BAUD_2400
Definition spcr.h:81
@ SPCR_BAUD_9600
Definition spcr.h:83
@ SPCR_BAUD_19200
Definition spcr.h:84
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
uint8_t type
Address space type.
Definition acpi.h:25
uint64_t address
Address.
Definition acpi.h:33
uint32_t length
Length of table, in bytes, including header.
Definition acpi.h:184
A 16550-compatible UART.
Definition ns16550.h:80
unsigned int clock
Input clock frequency.
Definition ns16550.h:86
void * base
Register base address.
Definition ns16550.h:82
A Serial Port Console Redirection table.
Definition spcr.h:19
uint8_t pci_segment
PCI segment.
Definition spcr.h:65
struct acpi_header acpi
ACPI header.
Definition spcr.h:21
uint32_t clock
Clock frequency.
Definition spcr.h:67
uint8_t pci_func
PCI function number.
Definition spcr.h:61
uint8_t pci_dev
PCI device number.
Definition spcr.h:59
uint8_t type
Interface type.
Definition spcr.h:23
uint8_t baud
Baud rate.
Definition spcr.h:41
uint32_t precise
Precise baud rate.
Definition spcr.h:69
uint16_t pci_device_id
PCI device ID.
Definition spcr.h:53
uint8_t pci_bus
PCI bus number.
Definition spcr.h:57
struct acpi_address base
Base address.
Definition spcr.h:27
uint16_t pci_vendor_id
PCI vendor ID.
Definition spcr.h:55
A generic UART.
Definition uart.h:17
unsigned int baud
Baud rate (if specified)
Definition uart.h:26
struct uart_operations * op
UART operations.
Definition uart.h:29
void * priv
Driver-private data.
Definition uart.h:31