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