This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / firmware / pcdp.c
index ca751f5..09e4f68 100644 (file)
 #include <linux/acpi.h>
 #include <linux/console.h>
 #include <linux/efi.h>
+#include <linux/tty.h>
 #include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <asm/io.h>
+#include <asm/serial.h>
 #include "pcdp.h"
 
-static int __init
-setup_serial_console(struct pcdp_uart *uart)
+static inline int
+uart_irq_supported(int rev, struct pcdp_uart *uart)
+{
+       if (rev < 3)
+               return uart->pci_func & PCDP_UART_IRQ;
+       return uart->flags & PCDP_UART_IRQ;
+}
+
+static inline int
+uart_pci(int rev, struct pcdp_uart *uart)
+{
+       if (rev < 3)
+               return uart->pci_func & PCDP_UART_PCI;
+       return uart->flags & PCDP_UART_PCI;
+}
+
+static inline int
+uart_active_high_low(int rev, struct pcdp_uart *uart)
+{
+       if (uart_pci(rev, uart) || uart->flags & PCDP_UART_ACTIVE_LOW)
+               return ACPI_ACTIVE_LOW;
+       return ACPI_ACTIVE_HIGH;
+}
+
+static inline int
+uart_edge_level(int rev, struct pcdp_uart *uart)
+{
+       if (uart_pci(rev, uart))
+               return ACPI_LEVEL_SENSITIVE;
+       if (rev < 3 || uart->flags & PCDP_UART_EDGE_SENSITIVE)
+               return ACPI_EDGE_SENSITIVE;
+       return ACPI_LEVEL_SENSITIVE;
+}
+
+static void __init
+setup_serial_console(int rev, struct pcdp_uart *uart)
 {
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-       int mmio;
-       static char options[64];
+       struct uart_port port;
+       static char options[16];
+       int mapsize = 64;
+
+       memset(&port, 0, sizeof(port));
+       port.uartclk = uart->clock_rate;
+       if (!port.uartclk)      /* some FW doesn't supply this */
+               port.uartclk = BASE_BAUD * 16;
+
+       if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+               port.mapbase = uart->addr.address;
+               port.membase = ioremap(port.mapbase, mapsize);
+               if (!port.membase) {
+                       printk(KERN_ERR "%s: couldn't ioremap 0x%lx-0x%lx\n",
+                               __FUNCTION__, port.mapbase, port.mapbase + mapsize);
+                       return;
+               }
+               port.iotype = UPIO_MEM;
+       } else if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+               port.iobase = uart->addr.address;
+               port.iotype = UPIO_PORT;
+       } else
+               return;
+
+       switch (uart->pci_prog_intfc) {
+               case 0x0: port.type = PORT_8250;    break;
+               case 0x1: port.type = PORT_16450;   break;
+               case 0x2: port.type = PORT_16550;   break;
+               case 0x3: port.type = PORT_16650;   break;
+               case 0x4: port.type = PORT_16750;   break;
+               case 0x5: port.type = PORT_16850;   break;
+               case 0x6: port.type = PORT_16C950;  break;
+               default:  port.type = PORT_UNKNOWN; break;
+       }
+
+       port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+
+       if (uart_irq_supported(rev, uart)) {
+               port.irq = acpi_register_gsi(uart->gsi,
+                       uart_active_high_low(rev, uart),
+                       uart_edge_level(rev, uart));
+               port.flags |= UPF_AUTO_IRQ;  /* some FW reported wrong GSI */
+               if (uart_pci(rev, uart))
+                       port.flags |= UPF_SHARE_IRQ;
+       }
+
+       if (early_serial_setup(&port) < 0)
+               return;
 
-       mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
-       snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d",
-               mmio ? "mmio" : "io", uart->addr.address, uart->baud,
+       snprintf(options, sizeof(options), "%lun%d", uart->baud,
                uart->bits ? uart->bits : 8);
+       add_preferred_console("ttyS", port.line, options);
 
-       return early_serial_console_init(options);
-#else
-       return -ENODEV;
+       printk(KERN_INFO "PCDP: serial console at %s 0x%lx (ttyS%d, options %s)\n",
+               port.iotype == UPIO_MEM ? "MMIO" : "I/O",
+               uart->addr.address, port.line, options);
 #endif
 }
 
-static int __init
+static void __init
 setup_vga_console(struct pcdp_vga *vga)
 {
-#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
+#ifdef CONFIG_VT
+#ifdef CONFIG_VGA_CONSOLE
        if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
                printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
-               return -ENODEV;
+               return;
        }
 
        conswitchp = &vga_con;
        printk(KERN_INFO "PCDP: VGA console\n");
-       return 0;
-#else
-       return -ENODEV;
+#endif
 #endif
 }
 
-int __init
+void __init
 efi_setup_pcdp_console(char *cmdline)
 {
        struct pcdp *pcdp;
@@ -62,25 +144,20 @@ efi_setup_pcdp_console(char *cmdline)
 
        pcdp = efi.hcdp;
        if (!pcdp)
-               return -ENODEV;
+               return;
 
-       printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
+       printk(KERN_INFO "PCDP: v%d at 0x%p\n", pcdp->rev, pcdp);
 
-       if (strstr(cmdline, "console=hcdp")) {
-               if (pcdp->rev < 3)
+       if (pcdp->rev < 3) {
+               if (strstr(cmdline, "console=ttyS0") || efi_uart_console_only())
                        serial = 1;
-       } else if (strstr(cmdline, "console=")) {
-               printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
-               return -ENODEV;
        }
 
-       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) {
-                               return setup_serial_console(uart);
+                               setup_serial_console(pcdp->rev, uart);
+                               return;
                        }
                }
        }
@@ -91,12 +168,11 @@ efi_setup_pcdp_console(char *cmdline)
             dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
                if (dev->flags & PCDP_PRIMARY_CONSOLE) {
                        if (dev->type == PCDP_CONSOLE_VGA) {
-                               return setup_vga_console((struct pcdp_vga *) dev);
+                               setup_vga_console((struct pcdp_vga *) dev);
+                               return;
                        }
                }
        }
-
-       return -ENODEV;
 }
 
 #ifdef CONFIG_IA64_EARLY_PRINTK_UART