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 
24 FILE_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 */
45 static struct uart spcr_uart = {
47  .name = "SPCR",
48 };
49 
50 /** SPCR-defined 16550 UART */
51 static struct ns16550_uart spcr_ns16550 = {
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  */
76 static 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  */
102 static 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 ) ) {
137  baud = ( SPCR_BAUD_BASE / spcr_baud_divisor[spcr->baud] );
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:
146  case SPCR_TYPE_16550_GAS:
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 
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define le32_to_cpu(value)
Definition: byteswap.h:113
static struct uart spcr_uart
SPCR-defined UART.
Definition: spcr.c:45
#define NS16550_LEN
Length of register region.
Definition: ns16550.h:15
Error codes.
A generic UART.
Definition: uart.h:17
#define SPCR_TYPE_16550
16550-compatible
Definition: spcr.h:75
void * base
Register base address.
Definition: ns16550.h:82
struct uart * fixed_serial_console(void)
Get fixed serial console UART.
Definition: serial.c:76
uint16_t pci_device_id
PCI device ID.
Definition: spcr.h:53
uint16_t pci_vendor_id
PCI vendor ID.
Definition: spcr.h:55
#define DBGC(...)
Definition: compiler.h:505
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
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:92
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:24
Serial console.
A Serial Port Console Redirection table.
Definition: spcr.h:19
struct uart * default_serial_console(void)
Get serial console UART.
PROVIDE_SERIAL(spcr, default_serial_console, spcr_console)
16550-compatible UART
#define SPCR_TYPE_16550_GAS
16550-compatible
Definition: spcr.h:77
#define NS16550_CLK_DEFAULT
Default input clock rate (1.8432 MHz)
Definition: ns16550.h:95
uint32_t precise
Precise baud rate.
Definition: spcr.h:69
#define SPCR_BAUD_BASE
Base baud rate for SPCR divisors.
Definition: spcr.c:56
uint8_t pci_segment
PCI segment.
Definition: spcr.h:65
unsigned int baud
Baud rate (if specified)
Definition: uart.h:26
static struct uart * spcr_console(void)
Identify default serial console.
Definition: spcr.c:102
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
uint32_t length
Length of table, in bytes, including header.
Definition: acpi.h:183
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition: efi_block.c:66
#define SPCR_SIGNATURE
Serial Port Console Redirection table signature.
Definition: spcr.h:16
#define DBGC2_HDA(...)
Definition: compiler.h:523
unsigned int clock
Input clock frequency.
Definition: ns16550.h:86
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:311
PCI bus.
void * priv
Driver-private data.
Definition: uart.h:31
A 16550-compatible UART.
Definition: ns16550.h:80
uint32_t clock
Clock frequency.
Definition: spcr.h:67
#define ENODEV
No such device.
Definition: errno.h:509
uint8_t type
Interface type.
Definition: spcr.h:23
struct acpi_header acpi
ACPI header.
Definition: spcr.h:21
unsigned char uint8_t
Definition: stdint.h:10
struct uart_operations ns16550_operations
16550 UART operations
Definition: ns16550.c:171
struct acpi_address base
Base address.
Definition: spcr.h:27
uint8_t pci_func
PCI function number.
Definition: spcr.h:61
#define le16_to_cpu(value)
Definition: byteswap.h:112
static int spcr_16550(struct spcr_table *spcr, struct uart *uart)
Configure 16550-based serial console.
Definition: spcr.c:76
uint8_t pci_bus
PCI bus number.
Definition: spcr.h:57
uint8_t type
Address space type.
Definition: acpi.h:24
uint8_t pci_dev
PCI device number.
Definition: spcr.h:59
void * acpi_ioremap(struct acpi_address *address, size_t len)
Map an ACPI generic address.
Definition: acpi.c:269
uint64_t address
Address.
Definition: acpi.h:32
#define DBGC2(...)
Definition: compiler.h:522
uint8_t baud
Baud rate.
Definition: spcr.h:41
struct uart_operations * op
UART operations.
Definition: uart.h:29
#define cpu_to_le16(value)
Definition: byteswap.h:106
#define REF_INIT(free_fn)
Initialise a static reference counter.
Definition: refcnt.h:77
#define SPCR_TYPE_16450
16450-compatible
Definition: spcr.h:76
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:47
struct refcnt refcnt
Reference count.
Definition: uart.h:19
#define le64_to_cpu(value)
Definition: byteswap.h:114
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void ref_no_free(struct refcnt *refcnt __unused)
Do not free reference-counted object.
Definition: refcnt.c:101
ACPI Serial Port Console Redirection (SPCR)
#define PCI_ANY_ID
Match-anything ID.
Definition: pci.h:186