VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / firmware / pcdp.c
1 /*
2  * Parse the EFI PCDP table to locate the console device.
3  *
4  * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P.
5  *      Khalid Aziz <khalid.aziz@hp.com>
6  *      Alex Williamson <alex.williamson@hp.com>
7  *      Bjorn Helgaas <bjorn.helgaas@hp.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/acpi.h>
15 #include <linux/console.h>
16 #include <linux/efi.h>
17 #include <linux/tty.h>
18 #include <linux/serial.h>
19 #include <linux/serial_core.h>
20 #include <asm/io.h>
21 #include <asm/serial.h>
22 #include "pcdp.h"
23
24 static inline int
25 uart_irq_supported(int rev, struct pcdp_uart *uart)
26 {
27         if (rev < 3)
28                 return uart->pci_func & PCDP_UART_IRQ;
29         return uart->flags & PCDP_UART_IRQ;
30 }
31
32 static inline int
33 uart_pci(int rev, struct pcdp_uart *uart)
34 {
35         if (rev < 3)
36                 return uart->pci_func & PCDP_UART_PCI;
37         return uart->flags & PCDP_UART_PCI;
38 }
39
40 static inline int
41 uart_active_high_low(int rev, struct pcdp_uart *uart)
42 {
43         if (uart_pci(rev, uart) || uart->flags & PCDP_UART_ACTIVE_LOW)
44                 return ACPI_ACTIVE_LOW;
45         return ACPI_ACTIVE_HIGH;
46 }
47
48 static inline int
49 uart_edge_level(int rev, struct pcdp_uart *uart)
50 {
51         if (uart_pci(rev, uart))
52                 return ACPI_LEVEL_SENSITIVE;
53         if (rev < 3 || uart->flags & PCDP_UART_EDGE_SENSITIVE)
54                 return ACPI_EDGE_SENSITIVE;
55         return ACPI_LEVEL_SENSITIVE;
56 }
57
58 static void __init
59 setup_serial_console(int rev, struct pcdp_uart *uart)
60 {
61 #ifdef CONFIG_SERIAL_8250_CONSOLE
62         struct uart_port port;
63         static char options[16];
64         int mapsize = 64;
65
66         memset(&port, 0, sizeof(port));
67         port.uartclk = uart->clock_rate;
68         if (!port.uartclk)      /* some FW doesn't supply this */
69                 port.uartclk = BASE_BAUD * 16;
70
71         if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
72                 port.mapbase = uart->addr.address;
73                 port.membase = ioremap(port.mapbase, mapsize);
74                 if (!port.membase) {
75                         printk(KERN_ERR "%s: couldn't ioremap 0x%lx-0x%lx\n",
76                                 __FUNCTION__, port.mapbase, port.mapbase + mapsize);
77                         return;
78                 }
79                 port.iotype = UPIO_MEM;
80         } else if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
81                 port.iobase = uart->addr.address;
82                 port.iotype = UPIO_PORT;
83         } else
84                 return;
85
86         switch (uart->pci_prog_intfc) {
87                 case 0x0: port.type = PORT_8250;    break;
88                 case 0x1: port.type = PORT_16450;   break;
89                 case 0x2: port.type = PORT_16550;   break;
90                 case 0x3: port.type = PORT_16650;   break;
91                 case 0x4: port.type = PORT_16750;   break;
92                 case 0x5: port.type = PORT_16850;   break;
93                 case 0x6: port.type = PORT_16C950;  break;
94                 default:  port.type = PORT_UNKNOWN; break;
95         }
96
97         port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
98
99         if (uart_irq_supported(rev, uart)) {
100                 port.irq = acpi_register_gsi(uart->gsi,
101                         uart_active_high_low(rev, uart),
102                         uart_edge_level(rev, uart));
103                 port.flags |= UPF_AUTO_IRQ;  /* some FW reported wrong GSI */
104                 if (uart_pci(rev, uart))
105                         port.flags |= UPF_SHARE_IRQ;
106         }
107
108         if (early_serial_setup(&port) < 0)
109                 return;
110
111         snprintf(options, sizeof(options), "%lun%d", uart->baud,
112                 uart->bits ? uart->bits : 8);
113         add_preferred_console("ttyS", port.line, options);
114
115         printk(KERN_INFO "PCDP: serial console at %s 0x%lx (ttyS%d, options %s)\n",
116                 port.iotype == UPIO_MEM ? "MMIO" : "I/O",
117                 uart->addr.address, port.line, options);
118 #endif
119 }
120
121 static void __init
122 setup_vga_console(struct pcdp_vga *vga)
123 {
124 #ifdef CONFIG_VT
125 #ifdef CONFIG_VGA_CONSOLE
126         if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
127                 printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
128                 return;
129         }
130
131         conswitchp = &vga_con;
132         printk(KERN_INFO "PCDP: VGA console\n");
133 #endif
134 #endif
135 }
136
137 void __init
138 efi_setup_pcdp_console(char *cmdline)
139 {
140         struct pcdp *pcdp;
141         struct pcdp_uart *uart;
142         struct pcdp_device *dev, *end;
143         int i, serial = 0;
144
145         pcdp = efi.hcdp;
146         if (!pcdp)
147                 return;
148
149         printk(KERN_INFO "PCDP: v%d at 0x%p\n", pcdp->rev, pcdp);
150
151         if (pcdp->rev < 3) {
152                 if (strstr(cmdline, "console=ttyS0") || efi_uart_console_only())
153                         serial = 1;
154         }
155
156         for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
157                 if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
158                         if (uart->type == PCDP_CONSOLE_UART) {
159                                 setup_serial_console(pcdp->rev, uart);
160                                 return;
161                         }
162                 }
163         }
164
165         end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
166         for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
167              dev < end;
168              dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
169                 if (dev->flags & PCDP_PRIMARY_CONSOLE) {
170                         if (dev->type == PCDP_CONSOLE_VGA) {
171                                 setup_vga_console((struct pcdp_vga *) dev);
172                                 return;
173                         }
174                 }
175         }
176 }
177
178 #ifdef CONFIG_IA64_EARLY_PRINTK_UART
179 unsigned long
180 hcdp_early_uart (void)
181 {
182         efi_system_table_t *systab;
183         efi_config_table_t *config_tables;
184         unsigned long addr = 0;
185         struct pcdp *pcdp = 0;
186         struct pcdp_uart *uart;
187         int i;
188
189         systab = (efi_system_table_t *) ia64_boot_param->efi_systab;
190         if (!systab)
191                 return 0;
192         systab = __va(systab);
193
194         config_tables = (efi_config_table_t *) systab->tables;
195         if (!config_tables)
196                 return 0;
197         config_tables = __va(config_tables);
198
199         for (i = 0; i < systab->nr_tables; i++) {
200                 if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
201                         pcdp = (struct pcdp *) config_tables[i].table;
202                         break;
203                 }
204         }
205         if (!pcdp)
206                 return 0;
207         pcdp = __va(pcdp);
208
209         for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
210                 if (uart->type == PCDP_CONSOLE_UART) {
211                         addr = uart->addr.address;
212                         break;
213                 }
214         }
215         return addr;
216 }
217 #endif /* CONFIG_IA64_EARLY_PRINTK_UART */