xref: /openbmc/linux/drivers/firmware/pcdp.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
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