/* * Copyright (C) 2002, 2003, 2004 Hewlett-Packard Co. * Khalid Aziz * Alex Williamson * Bjorn Helgaas * * Parse the EFI PCDP table to locate the console device. */ #include #include #include #include #include #include #include #include #include "pcdp.h" 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 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; snprintf(options, sizeof(options), "%lun%d", uart->baud, uart->bits ? uart->bits : 8); add_preferred_console("ttyS", port.line, options); 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 void __init setup_vga_console(struct pcdp_vga *vga) { #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; } conswitchp = &vga_con; printk(KERN_INFO "PCDP: VGA console\n"); #endif #endif } void __init efi_setup_pcdp_console(char *cmdline) { struct pcdp *pcdp; struct pcdp_uart *uart; struct pcdp_device *dev, *end; int i, serial = 0; pcdp = efi.hcdp; if (!pcdp) return; printk(KERN_INFO "PCDP: v%d at 0x%p\n", pcdp->rev, pcdp); if (pcdp->rev < 3) { if (strstr(cmdline, "console=ttyS0") || 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) { setup_serial_console(pcdp->rev, uart); return; } } } end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length); for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts); dev < end; dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) { if (dev->flags & PCDP_PRIMARY_CONSOLE) { if (dev->type == PCDP_CONSOLE_VGA) { setup_vga_console((struct pcdp_vga *) dev); return; } } } } #ifdef CONFIG_IA64_EARLY_PRINTK_UART unsigned long hcdp_early_uart (void) { efi_system_table_t *systab; efi_config_table_t *config_tables; unsigned long addr = 0; struct pcdp *pcdp = 0; struct pcdp_uart *uart; int i; systab = (efi_system_table_t *) ia64_boot_param->efi_systab; if (!systab) return 0; systab = __va(systab); config_tables = (efi_config_table_t *) systab->tables; if (!config_tables) return 0; config_tables = __va(config_tables); for (i = 0; i < systab->nr_tables; i++) { if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { pcdp = (struct pcdp *) config_tables[i].table; break; } } if (!pcdp) return 0; pcdp = __va(pcdp); for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { if (uart->type == PCDP_CONSOLE_UART) { addr = uart->addr.address; break; } } return addr; } #endif /* CONFIG_IA64_EARLY_PRINTK_UART */