Commit 8ec5a566 authored by Christoph Hellwig's avatar Christoph Hellwig

acpi serial stuff

parent 29b25594
...@@ -2064,9 +2064,11 @@ int register_serial(struct serial_struct *req) ...@@ -2064,9 +2064,11 @@ int register_serial(struct serial_struct *req)
return __register_serial(req, -1); return __register_serial(req, -1);
} }
int __init early_serial_setup(struct serial_struct *req) int __init early_serial_setup(struct uart_port *port)
{ {
__register_serial(req, req->line); serial8250_isa_init_ports();
serial8250_ports[port->line].port = *port;
serial8250_ports[port->line].port.ops = &serial8250_pops;
return 0; return 0;
} }
......
/*
* serial/acpi.c
* Copyright (c) 2002-2003 Matthew Wilcox for Hewlett-Packard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/serial.h>
#include <acpi/acpi_bus.h>
#include <asm/io.h>
#include <asm/serial.h>
static void acpi_serial_address(struct serial_struct *req,
struct acpi_resource_address32 *addr32)
{
unsigned long size;
size = addr32->max_address_range - addr32->min_address_range + 1;
req->iomap_base = addr32->min_address_range;
req->iomem_base = ioremap(req->iomap_base, size);
req->io_type = SERIAL_IO_MEM;
}
static void acpi_serial_irq(struct serial_struct *req,
struct acpi_resource_ext_irq *ext_irq)
{
if (ext_irq->number_of_interrupts > 0) {
#ifdef CONFIG_IA64
req->irq = acpi_register_irq(ext_irq->interrupts[0],
ext_irq->active_high_low, ext_irq->edge_level);
#else
req->irq = ext_irq->interrupts[0];
#endif
}
}
static int acpi_serial_add(struct acpi_device *device)
{
acpi_status result;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct serial_struct serial_req;
int line, offset = 0;
memset(&serial_req, 0, sizeof(serial_req));
result = acpi_get_current_resources(device->handle, &buffer);
if (ACPI_FAILURE(result)) {
result = -ENODEV;
goto out;
}
while (offset <= buffer.length) {
struct acpi_resource *res = buffer.pointer + offset;
if (res->length == 0)
break;
offset += res->length;
if (res->id == ACPI_RSTYPE_ADDRESS32) {
acpi_serial_address(&serial_req, &res->data.address32);
} else if (res->id == ACPI_RSTYPE_EXT_IRQ) {
acpi_serial_irq(&serial_req, &res->data.extended_irq);
}
}
serial_req.baud_base = BASE_BAUD;
serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ;
result = 0;
line = register_serial(&serial_req);
if (line < 0)
result = -ENODEV;
out:
acpi_os_free(buffer.pointer);
return result;
}
static int acpi_serial_remove(struct acpi_device *device, int type)
{
return 0;
}
static struct acpi_driver acpi_serial_driver = {
.name = "serial",
.class = "",
.ids = "PNP0501",
.ops = {
.add = acpi_serial_add,
.remove = acpi_serial_remove,
},
};
static int __init acpi_serial_init(void)
{
return acpi_bus_register_driver(&acpi_serial_driver);
}
static void __exit acpi_serial_exit(void)
{
acpi_bus_unregister_driver(&acpi_serial_driver);
}
module_init(acpi_serial_init);
module_exit(acpi_serial_exit);
/*
* linux/drivers/char/hcdp_serial.c
*
* Copyright (C) 2002 Hewlett-Packard Co.
* Khalid Aziz <khalid_aziz@hp.com>
*
* Parse the EFI HCDP table to locate serial console and debug ports and
* initialize them.
*
* 2002/08/29 davidm Adjust it to new 2.5 serial driver infrastructure.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/serial.h>
#include <asm/acpi.h>
#include "8250_hcdp.h"
#undef SERIAL_DEBUG_HCDP
/*
* Parse the HCDP table to find descriptions for headless console and debug
* serial ports and add them to rs_table[]. A pointer to HCDP table is
* passed as parameter. This function should be called before
* serial_console_init() is called to make sure the HCDP serial console will
* be available for use. IA-64 kernel calls this function from setup_arch()
* after the EFI and ACPI tables have been parsed.
*/
void __init
setup_serial_hcdp(void *tablep)
{
hcdp_dev_t *hcdp_dev;
struct uart_port port;
unsigned long iobase;
hcdp_t hcdp;
int gsi, nr;
#if 0
static int shift_once = 1;
#endif
#ifdef SERIAL_DEBUG_HCDP
printk("Entering setup_serial_hcdp()\n");
#endif
/* Verify we have a valid table pointer */
if (!tablep)
return;
memset(&port, 0, sizeof(port));
/*
* Don't trust firmware to give us a table starting at an aligned
* address. Make a local copy of the HCDP table with aligned
* structures.
*/
memcpy(&hcdp, tablep, sizeof(hcdp));
/*
* Perform a sanity check on the table. Table should have a signature
* of "HCDP" and it should be atleast 82 bytes long to have any
* useful information.
*/
if ((strncmp(hcdp.signature, HCDP_SIGNATURE, HCDP_SIG_LEN) != 0))
return;
if (hcdp.len < 82)
return;
#ifdef SERIAL_DEBUG_HCDP
printk("setup_serial_hcdp(): table pointer = 0x%p, sig = '%.4s'\n",
tablep, hcdp.signature);
printk(" length = %d, rev = %d, ", hcdp.len, hcdp.rev);
printk("OEM ID = %.6s, # of entries = %d\n", hcdp.oemid,
hcdp.num_entries);
#endif
/*
* Parse each device entry
*/
for (nr = 0; nr < hcdp.num_entries; nr++) {
hcdp_dev = hcdp.hcdp_dev + nr;
/*
* We will parse only the primary console device which is
* the first entry for these devices. We will ignore rest
* of the entries for the same type device that has already
* been parsed and initialized
*/
if (hcdp_dev->type != HCDP_DEV_CONSOLE)
continue;
iobase = ((u64) hcdp_dev->base_addr.addrhi << 32) |
hcdp_dev->base_addr.addrlo;
gsi = hcdp_dev->global_int;
/* See PCI spec v2.2, Appendix D (Class Codes): */
switch (hcdp_dev->pci_prog_intfc) {
case 0x00:
port.type = PORT_8250;
break;
case 0x01:
port.type = PORT_16450;
break;
case 0x02:
port.type = PORT_16550;
break;
case 0x03:
port.type = PORT_16650;
break;
case 0x04:
port.type = PORT_16750;
break;
case 0x05:
port.type = PORT_16850;
break;
case 0x06:
port.type = PORT_16C950;
break;
default:
printk(KERN_WARNING "warning: EFI HCDP table reports "
"unknown serial programming interface 0x%02x; "
"will autoprobe.\n", hcdp_dev->pci_prog_intfc);
port.type = PORT_UNKNOWN;
break;
}
#ifdef SERIAL_DEBUG_HCDP
printk(" type = %s, uart = %d\n",
((hcdp_dev->type == HCDP_DEV_CONSOLE) ?
"Headless Console" :
((hcdp_dev->type == HCDP_DEV_DEBUG) ?
"Debug port" : "Huh????")), port.type);
printk(" base address space = %s, base address = 0x%lx\n",
((hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE) ?
"Memory Space" :
((hcdp_dev->base_addr.space_id == ACPI_IO_SPACE) ?
"I/O space" : "PCI space")),
iobase);
printk(" gsi = %d, baud rate = %lu, bits = %d, clock = %d\n",
gsi, (unsigned long) hcdp_dev->baud, hcdp_dev->bits,
hcdp_dev->clock_rate);
if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE)
printk(" PCI id: %02x:%02x:%02x, vendor ID=0x%x, "
"dev ID=0x%x\n", hcdp_dev->pci_seg,
hcdp_dev->pci_bus, hcdp_dev->pci_dev,
hcdp_dev->pci_vendor_id, hcdp_dev->pci_dev_id);
#endif
/*
* Now fill in a port structure to update the 8250 port table..
*/
if (hcdp_dev->clock_rate)
port.uartclk = hcdp_dev->clock_rate;
else
port.uartclk = BASE_BAUD * 16;
/*
* Check if this is an I/O mapped address or a memory mapped
* address
*/
if (hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE) {
port.iobase = 0;
port.mapbase = iobase;
port.membase = ioremap(iobase, 64);
port.iotype = SERIAL_IO_MEM;
} else if (hcdp_dev->base_addr.space_id == ACPI_IO_SPACE) {
port.iobase = iobase;
port.mapbase = 0;
port.membase = NULL;
port.iotype = SERIAL_IO_PORT;
} else if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) {
printk(KERN_WARNING"warning: No support for PCI serial console\n");
return;
}
#ifdef CONFIG_IA64
port.irq = acpi_register_irq(gsi, ACPI_ACTIVE_HIGH,
ACPI_EDGE_SENSITIVE);
#else
port.irq = gsi;
#endif
port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
if (gsi)
port.flags |= ASYNC_AUTO_IRQ;
/*
* Note: the above memset() initializes port.line to 0,
* so we register this port as ttyS0.
*/
if (early_serial_setup(&port) < 0) {
printk("setup_serial_hcdp(): early_serial_setup() "
"for HCDP serial console port failed. "
"Will try any additional consoles in HCDP.\n");
continue;
}
break;
}
#ifdef SERIAL_DEBUG_HCDP
printk("Leaving setup_serial_hcdp()\n");
#endif
}
#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;
hcdp_t *hcdp = 0;
hcdp_dev_t *dev;
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) {
hcdp = (hcdp_t *) config_tables[i].table;
break;
}
}
if (!hcdp)
return 0;
hcdp = __va(hcdp);
for (i = 0, dev = hcdp->hcdp_dev; i < hcdp->num_entries; i++, dev++) {
if (dev->type == HCDP_DEV_CONSOLE) {
addr = (u64) dev->base_addr.addrhi << 32 | dev->base_addr.addrlo;
break;
}
}
return addr;
}
#endif /* CONFIG_IA64_EARLY_PRINTK_UART */
/*
* drivers/serial/8250_hcdp.h
*
* Copyright (C) 2002 Hewlett-Packard Co.
* Khalid Aziz <khalid_aziz@hp.com>
*
* Definitions for HCDP defined serial ports (Serial console and debug
* ports)
*/
/* ACPI table signatures */
#define HCDP_SIG_LEN 4
#define HCDP_SIGNATURE "HCDP"
/* Space ID as defined in ACPI generic address structure */
#define ACPI_MEM_SPACE 0
#define ACPI_IO_SPACE 1
#define ACPI_PCICONF_SPACE 2
/*
* Maximum number of HCDP devices we want to read in
*/
#define MAX_HCDP_DEVICES 6
/*
* Default UART clock rate if clock rate is 0 in HCDP table.
*/
#define DEFAULT_UARTCLK 115200
/*
* ACPI Generic Address Structure
*/
typedef struct {
u8 space_id;
u8 bit_width;
u8 bit_offset;
u8 resv;
u32 addrlo;
u32 addrhi;
} acpi_gen_addr;
/* HCDP Device descriptor entry types */
#define HCDP_DEV_CONSOLE 0
#define HCDP_DEV_DEBUG 1
/* HCDP Device descriptor type */
typedef struct {
u8 type;
u8 bits;
u8 parity;
u8 stop_bits;
u8 pci_seg;
u8 pci_bus;
u8 pci_dev;
u8 pci_func;
u64 baud;
acpi_gen_addr base_addr;
u16 pci_dev_id;
u16 pci_vendor_id;
u32 global_int;
u32 clock_rate;
u8 pci_prog_intfc;
u8 resv;
} hcdp_dev_t;
/* HCDP Table format */
typedef struct {
u8 signature[4];
u32 len;
u8 rev;
u8 chksum;
u8 oemid[6];
u8 oem_tabid[8];
u32 oem_rev;
u8 creator_id[4];
u32 creator_rev;
u32 num_entries;
hcdp_dev_t hcdp_dev[MAX_HCDP_DEVICES];
} hcdp_t;
...@@ -77,6 +77,15 @@ config SERIAL_8250_CS ...@@ -77,6 +77,15 @@ config SERIAL_8250_CS
a module, say M here and read <file:Documentation/modules.txt>. a module, say M here and read <file:Documentation/modules.txt>.
If unsure, say N. If unsure, say N.
config SERIAL_HCDP
bool "8250/16550 device discovery support via EFI HCDP table"
depends on IA64
---help---
If you wish to make the serial console port described by the EFI
HCDP table available for use as serial console or general
purpose port, say Y here. See
<http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf>.
config SERIAL_8250_EXTENDED config SERIAL_8250_EXTENDED
bool "Extended 8250/16550 serial driver options" bool "Extended 8250/16550 serial driver options"
depends on SERIAL_8250 depends on SERIAL_8250
......
...@@ -8,6 +8,9 @@ serial-8250-y := ...@@ -8,6 +8,9 @@ serial-8250-y :=
serial-8250-$(CONFIG_GSC) += 8250_gsc.o serial-8250-$(CONFIG_GSC) += 8250_gsc.o
serial-8250-$(CONFIG_PCI) += 8250_pci.o serial-8250-$(CONFIG_PCI) += 8250_pci.o
serial-8250-$(CONFIG_PNP) += 8250_pnp.o serial-8250-$(CONFIG_PNP) += 8250_pnp.o
serial-8250-$(CONFIG_ACPI) += acpi.o
serial-8250-$(CONFIG_SERIAL_HCDP) += 8250_hcdp.o
obj-$(CONFIG_SERIAL_CORE) += core.o obj-$(CONFIG_SERIAL_CORE) += core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o obj-$(CONFIG_SERIAL_21285) += 21285.o
obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* *
*/ */
#include <linux/serial.h>
extern void setup_serial_acpi(void *); extern void setup_serial_acpi(void *);
#define ACPI_SIG_LEN 4 #define ACPI_SIG_LEN 4
......
...@@ -180,14 +180,9 @@ struct serial_icounter_struct { ...@@ -180,14 +180,9 @@ struct serial_icounter_struct {
extern int register_serial(struct serial_struct *req); extern int register_serial(struct serial_struct *req);
extern void unregister_serial(int line); extern void unregister_serial(int line);
/* Allow complicated architectures to specify rs_table[] at run time */ /* Allow architectures to override entries in serial8250_ports[] at run time: */
extern int early_serial_setup(struct serial_struct *req); struct uart_port; /* forward declaration */
extern int early_serial_setup(struct uart_port *port);
#ifdef CONFIG_ACPI
/* tty ports reserved for the ACPI serial console port and debug port */
#define ACPI_SERIAL_CONSOLE_PORT 4
#define ACPI_SERIAL_DEBUG_PORT 5
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_SERIAL_H */ #endif /* _LINUX_SERIAL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment