1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Parse the EFI PCDP table to locate the console device.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P.
61da177e4SLinus Torvalds * Khalid Aziz <khalid.aziz@hp.com>
71da177e4SLinus Torvalds * Alex Williamson <alex.williamson@hp.com>
81da177e4SLinus Torvalds * Bjorn Helgaas <bjorn.helgaas@hp.com>
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/acpi.h>
121da177e4SLinus Torvalds #include <linux/console.h>
131da177e4SLinus Torvalds #include <linux/efi.h>
141da177e4SLinus Torvalds #include <linux/serial.h>
15df519e7bSPeter Hurley #include <linux/serial_core.h>
1666b7f8a3SMark Maule #include <asm/vga.h>
171da177e4SLinus Torvalds #include "pcdp.h"
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds static int __init
setup_serial_console(struct pcdp_uart * uart)201da177e4SLinus Torvalds setup_serial_console(struct pcdp_uart *uart)
211da177e4SLinus Torvalds {
221da177e4SLinus Torvalds #ifdef CONFIG_SERIAL_8250_CONSOLE
231da177e4SLinus Torvalds int mmio;
24280dedb8SBjorn Helgaas static char options[64], *p = options;
2511be00cbSBjorn Helgaas char parity;
261da177e4SLinus Torvalds
2715a58ed1SAlexey Starikovskiy mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
28e088a4adSMatthew Wilcox p += sprintf(p, "uart8250,%s,0x%llx",
29280dedb8SBjorn Helgaas mmio ? "mmio" : "io", uart->addr.address);
3011be00cbSBjorn Helgaas if (uart->baud) {
31e088a4adSMatthew Wilcox p += sprintf(p, ",%llu", uart->baud);
3211be00cbSBjorn Helgaas if (uart->bits) {
3311be00cbSBjorn Helgaas switch (uart->parity) {
3411be00cbSBjorn Helgaas case 0x2: parity = 'e'; break;
3511be00cbSBjorn Helgaas case 0x3: parity = 'o'; break;
3611be00cbSBjorn Helgaas default: parity = 'n';
3711be00cbSBjorn Helgaas }
3811be00cbSBjorn Helgaas p += sprintf(p, "%c%d", parity, uart->bits);
3911be00cbSBjorn Helgaas }
4011be00cbSBjorn Helgaas }
411da177e4SLinus Torvalds
4218a8bd94SYinghai Lu add_preferred_console("uart", 8250, &options[9]);
43df519e7bSPeter Hurley return setup_earlycon(options);
441da177e4SLinus Torvalds #else
451da177e4SLinus Torvalds return -ENODEV;
461da177e4SLinus Torvalds #endif
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds static int __init
setup_vga_console(struct pcdp_device * dev)5066b7f8a3SMark Maule setup_vga_console(struct pcdp_device *dev)
511da177e4SLinus Torvalds {
521da177e4SLinus Torvalds #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
5366b7f8a3SMark Maule u8 *if_ptr;
5466b7f8a3SMark Maule
5566b7f8a3SMark Maule if_ptr = ((u8 *)dev + sizeof(struct pcdp_device));
5666b7f8a3SMark Maule if (if_ptr[0] == PCDP_IF_PCI) {
5766b7f8a3SMark Maule struct pcdp_if_pci if_pci;
5866b7f8a3SMark Maule
5966b7f8a3SMark Maule /* struct copy since ifptr might not be correctly aligned */
6066b7f8a3SMark Maule
6166b7f8a3SMark Maule memcpy(&if_pci, if_ptr, sizeof(if_pci));
6266b7f8a3SMark Maule
6366b7f8a3SMark Maule if (if_pci.trans & PCDP_PCI_TRANS_IOPORT)
6466b7f8a3SMark Maule vga_console_iobase = if_pci.ioport_tra;
6566b7f8a3SMark Maule
6666b7f8a3SMark Maule if (if_pci.trans & PCDP_PCI_TRANS_MMIO)
6766b7f8a3SMark Maule vga_console_membase = if_pci.mmio_tra;
6866b7f8a3SMark Maule }
6966b7f8a3SMark Maule
7066b7f8a3SMark Maule if (efi_mem_type(vga_console_membase + 0xA0000) == EFI_CONVENTIONAL_MEMORY) {
711da177e4SLinus Torvalds printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
721da177e4SLinus Torvalds return -ENODEV;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds conswitchp = &vga_con;
761da177e4SLinus Torvalds printk(KERN_INFO "PCDP: VGA console\n");
771da177e4SLinus Torvalds return 0;
781da177e4SLinus Torvalds #else
791da177e4SLinus Torvalds return -ENODEV;
801da177e4SLinus Torvalds #endif
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds
83*120540f2SArd Biesheuvel extern unsigned long hcdp_phys;
84*120540f2SArd Biesheuvel
851da177e4SLinus Torvalds int __init
efi_setup_pcdp_console(char * cmdline)861da177e4SLinus Torvalds efi_setup_pcdp_console(char *cmdline)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds struct pcdp *pcdp;
891da177e4SLinus Torvalds struct pcdp_uart *uart;
901da177e4SLinus Torvalds struct pcdp_device *dev, *end;
911da177e4SLinus Torvalds int i, serial = 0;
92b2c99e3cSBjorn Helgaas int rc = -ENODEV;
931da177e4SLinus Torvalds
94*120540f2SArd Biesheuvel if (hcdp_phys == EFI_INVALID_TABLE_ADDR)
951da177e4SLinus Torvalds return -ENODEV;
961da177e4SLinus Torvalds
97*120540f2SArd Biesheuvel pcdp = early_memremap(hcdp_phys, 4096);
98*120540f2SArd Biesheuvel printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, hcdp_phys);
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds if (strstr(cmdline, "console=hcdp")) {
1011da177e4SLinus Torvalds if (pcdp->rev < 3)
1021da177e4SLinus Torvalds serial = 1;
1031da177e4SLinus Torvalds } else if (strstr(cmdline, "console=")) {
1041da177e4SLinus Torvalds printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
105b2c99e3cSBjorn Helgaas goto out;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds if (pcdp->rev < 3 && efi_uart_console_only())
1091da177e4SLinus Torvalds serial = 1;
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
1121da177e4SLinus Torvalds if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
1131da177e4SLinus Torvalds if (uart->type == PCDP_CONSOLE_UART) {
114b2c99e3cSBjorn Helgaas rc = setup_serial_console(uart);
115b2c99e3cSBjorn Helgaas goto out;
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
1211da177e4SLinus Torvalds for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
1221da177e4SLinus Torvalds dev < end;
1231da177e4SLinus Torvalds dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
1241da177e4SLinus Torvalds if (dev->flags & PCDP_PRIMARY_CONSOLE) {
1251da177e4SLinus Torvalds if (dev->type == PCDP_CONSOLE_VGA) {
126b2c99e3cSBjorn Helgaas rc = setup_vga_console(dev);
127b2c99e3cSBjorn Helgaas goto out;
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds
132b2c99e3cSBjorn Helgaas out:
133f7750a79STom Lendacky early_memunmap(pcdp, 4096);
134b2c99e3cSBjorn Helgaas return rc;
1351da177e4SLinus Torvalds }
136