Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | // SPDX-License-Identifier: GPL-2.0-only /* * Parse the EFI PCDP table to locate the console device. * * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P. * Khalid Aziz <khalid.aziz@hp.com> * Alex Williamson <alex.williamson@hp.com> * Bjorn Helgaas <bjorn.helgaas@hp.com> */ #include <linux/acpi.h> #include <linux/console.h> #include <linux/efi.h> #include <linux/serial.h> #include <linux/serial_core.h> #include <asm/vga.h> #include "pcdp.h" static int __init setup_serial_console(struct pcdp_uart *uart) { #ifdef CONFIG_SERIAL_8250_CONSOLE int mmio; static char options[64], *p = options; char parity; mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); p += sprintf(p, "uart8250,%s,0x%llx", mmio ? "mmio" : "io", uart->addr.address); if (uart->baud) { p += sprintf(p, ",%llu", uart->baud); if (uart->bits) { switch (uart->parity) { case 0x2: parity = 'e'; break; case 0x3: parity = 'o'; break; default: parity = 'n'; } p += sprintf(p, "%c%d", parity, uart->bits); } } add_preferred_console("uart", 8250, &options[9]); return setup_earlycon(options); #else return -ENODEV; #endif } static int __init setup_vga_console(struct pcdp_device *dev) { #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) u8 *if_ptr; if_ptr = ((u8 *)dev + sizeof(struct pcdp_device)); if (if_ptr[0] == PCDP_IF_PCI) { struct pcdp_if_pci if_pci; /* struct copy since ifptr might not be correctly aligned */ memcpy(&if_pci, if_ptr, sizeof(if_pci)); if (if_pci.trans & PCDP_PCI_TRANS_IOPORT) vga_console_iobase = if_pci.ioport_tra; if (if_pci.trans & PCDP_PCI_TRANS_MMIO) vga_console_membase = if_pci.mmio_tra; } if (efi_mem_type(vga_console_membase + 0xA0000) == EFI_CONVENTIONAL_MEMORY) { printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n"); return -ENODEV; } conswitchp = &vga_con; printk(KERN_INFO "PCDP: VGA console\n"); return 0; #else return -ENODEV; #endif } int __init efi_setup_pcdp_console(char *cmdline) { struct pcdp *pcdp; struct pcdp_uart *uart; struct pcdp_device *dev, *end; int i, serial = 0; int rc = -ENODEV; if (efi.hcdp == EFI_INVALID_TABLE_ADDR) return -ENODEV; pcdp = early_memremap(efi.hcdp, 4096); printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp); if (strstr(cmdline, "console=hcdp")) { if (pcdp->rev < 3) serial = 1; } else if (strstr(cmdline, "console=")) { printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n"); goto out; } if (pcdp->rev < 3 && efi_uart_console_only()) serial = 1; for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) { if (uart->type == PCDP_CONSOLE_UART) { rc = setup_serial_console(uart); goto out; } } } end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length); for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts); dev < end; dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) { if (dev->flags & PCDP_PRIMARY_CONSOLE) { if (dev->type == PCDP_CONSOLE_VGA) { rc = setup_vga_console(dev); goto out; } } } out: early_memunmap(pcdp, 4096); return rc; } |