18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Parse the EFI PCDP table to locate the console device. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P. 68c2ecf20Sopenharmony_ci * Khalid Aziz <khalid.aziz@hp.com> 78c2ecf20Sopenharmony_ci * Alex Williamson <alex.williamson@hp.com> 88c2ecf20Sopenharmony_ci * Bjorn Helgaas <bjorn.helgaas@hp.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/acpi.h> 128c2ecf20Sopenharmony_ci#include <linux/console.h> 138c2ecf20Sopenharmony_ci#include <linux/efi.h> 148c2ecf20Sopenharmony_ci#include <linux/serial.h> 158c2ecf20Sopenharmony_ci#include <linux/serial_core.h> 168c2ecf20Sopenharmony_ci#include <asm/vga.h> 178c2ecf20Sopenharmony_ci#include "pcdp.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int __init 208c2ecf20Sopenharmony_cisetup_serial_console(struct pcdp_uart *uart) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_CONSOLE 238c2ecf20Sopenharmony_ci int mmio; 248c2ecf20Sopenharmony_ci static char options[64], *p = options; 258c2ecf20Sopenharmony_ci char parity; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); 288c2ecf20Sopenharmony_ci p += sprintf(p, "uart8250,%s,0x%llx", 298c2ecf20Sopenharmony_ci mmio ? "mmio" : "io", uart->addr.address); 308c2ecf20Sopenharmony_ci if (uart->baud) { 318c2ecf20Sopenharmony_ci p += sprintf(p, ",%llu", uart->baud); 328c2ecf20Sopenharmony_ci if (uart->bits) { 338c2ecf20Sopenharmony_ci switch (uart->parity) { 348c2ecf20Sopenharmony_ci case 0x2: parity = 'e'; break; 358c2ecf20Sopenharmony_ci case 0x3: parity = 'o'; break; 368c2ecf20Sopenharmony_ci default: parity = 'n'; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci p += sprintf(p, "%c%d", parity, uart->bits); 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci add_preferred_console("uart", 8250, &options[9]); 438c2ecf20Sopenharmony_ci return setup_earlycon(options); 448c2ecf20Sopenharmony_ci#else 458c2ecf20Sopenharmony_ci return -ENODEV; 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int __init 508c2ecf20Sopenharmony_cisetup_vga_console(struct pcdp_device *dev) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) 538c2ecf20Sopenharmony_ci u8 *if_ptr; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if_ptr = ((u8 *)dev + sizeof(struct pcdp_device)); 568c2ecf20Sopenharmony_ci if (if_ptr[0] == PCDP_IF_PCI) { 578c2ecf20Sopenharmony_ci struct pcdp_if_pci if_pci; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* struct copy since ifptr might not be correctly aligned */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci memcpy(&if_pci, if_ptr, sizeof(if_pci)); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (if_pci.trans & PCDP_PCI_TRANS_IOPORT) 648c2ecf20Sopenharmony_ci vga_console_iobase = if_pci.ioport_tra; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (if_pci.trans & PCDP_PCI_TRANS_MMIO) 678c2ecf20Sopenharmony_ci vga_console_membase = if_pci.mmio_tra; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (efi_mem_type(vga_console_membase + 0xA0000) == EFI_CONVENTIONAL_MEMORY) { 718c2ecf20Sopenharmony_ci printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n"); 728c2ecf20Sopenharmony_ci return -ENODEV; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci conswitchp = &vga_con; 768c2ecf20Sopenharmony_ci printk(KERN_INFO "PCDP: VGA console\n"); 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci#else 798c2ecf20Sopenharmony_ci return -ENODEV; 808c2ecf20Sopenharmony_ci#endif 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciextern unsigned long hcdp_phys; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ciint __init 868c2ecf20Sopenharmony_ciefi_setup_pcdp_console(char *cmdline) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct pcdp *pcdp; 898c2ecf20Sopenharmony_ci struct pcdp_uart *uart; 908c2ecf20Sopenharmony_ci struct pcdp_device *dev, *end; 918c2ecf20Sopenharmony_ci int i, serial = 0; 928c2ecf20Sopenharmony_ci int rc = -ENODEV; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (hcdp_phys == EFI_INVALID_TABLE_ADDR) 958c2ecf20Sopenharmony_ci return -ENODEV; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci pcdp = early_memremap(hcdp_phys, 4096); 988c2ecf20Sopenharmony_ci printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, hcdp_phys); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (strstr(cmdline, "console=hcdp")) { 1018c2ecf20Sopenharmony_ci if (pcdp->rev < 3) 1028c2ecf20Sopenharmony_ci serial = 1; 1038c2ecf20Sopenharmony_ci } else if (strstr(cmdline, "console=")) { 1048c2ecf20Sopenharmony_ci printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n"); 1058c2ecf20Sopenharmony_ci goto out; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (pcdp->rev < 3 && efi_uart_console_only()) 1098c2ecf20Sopenharmony_ci serial = 1; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { 1128c2ecf20Sopenharmony_ci if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) { 1138c2ecf20Sopenharmony_ci if (uart->type == PCDP_CONSOLE_UART) { 1148c2ecf20Sopenharmony_ci rc = setup_serial_console(uart); 1158c2ecf20Sopenharmony_ci goto out; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length); 1218c2ecf20Sopenharmony_ci for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts); 1228c2ecf20Sopenharmony_ci dev < end; 1238c2ecf20Sopenharmony_ci dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) { 1248c2ecf20Sopenharmony_ci if (dev->flags & PCDP_PRIMARY_CONSOLE) { 1258c2ecf20Sopenharmony_ci if (dev->type == PCDP_CONSOLE_VGA) { 1268c2ecf20Sopenharmony_ci rc = setup_vga_console(dev); 1278c2ecf20Sopenharmony_ci goto out; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciout: 1338c2ecf20Sopenharmony_ci early_memunmap(pcdp, 4096); 1348c2ecf20Sopenharmony_ci return rc; 1358c2ecf20Sopenharmony_ci} 136