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