source: trunk/packages/xen-common/xen-common/xen/arch/ia64/xen/pcdp.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 6.5 KB
Line 
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/serial.h>
18#ifdef XEN
19#include <linux/efi.h>
20#include <linux/errno.h>
21#include <asm/io.h>
22#include <asm/iosapic.h>
23#include <asm/system.h>
24#include <acpi/acpi.h>
25#endif
26#include "pcdp.h"
27
28#ifdef XEN
29extern struct ns16550_defaults ns16550_com1;
30extern unsigned int ns16550_com1_gsi;
31extern unsigned int ns16550_com1_polarity;
32extern unsigned int ns16550_com1_trigger;
33
34/*
35 * This is kind of ugly, but older rev HCDP tables don't provide interrupt
36 * polarity and trigger information.  Linux/ia64 discovers these properties
37 * later via ACPI names, but we don't have that luxury in Xen/ia64.  Since
38 * all future platforms should have newer PCDP tables, this should be a
39 * fixed list of boxes in the field, so we can hardcode based on the model.
40 */
41static void __init
42pcdp_hp_irq_fixup(struct pcdp *pcdp, struct pcdp_uart *uart)
43{
44        efi_system_table_t *systab;
45        efi_config_table_t *tables;
46        struct acpi20_table_rsdp *rsdp = NULL;
47        struct acpi_table_xsdt *xsdt;
48        struct acpi_table_header *hdr;
49        int i;
50
51        if (pcdp->rev >= 3 || strcmp((char *)pcdp->oemid, "HP"))
52                return;
53
54        /*
55         * Manually walk firmware provided tables to get to the XSDT.
56         * The OEM table ID on the XSDT is the platform model string.
57         * We only care about ACPI 2.0 tables as that's all HP provides.
58         */
59        systab = __va(ia64_boot_param->efi_systab);
60
61        if (!systab || systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
62                return;
63
64        tables = __va(systab->tables);
65
66        for (i = 0 ; i < (int)systab->nr_tables && !rsdp ; i++) {
67                if (efi_guidcmp(tables[i].guid, ACPI_20_TABLE_GUID) == 0)
68                        rsdp =
69                             (struct acpi20_table_rsdp *)__va(tables[i].table);
70        }
71
72        if (!rsdp || strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1))
73                return;
74
75        xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address);
76        hdr = &xsdt->header;
77
78        if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1))
79                return;
80
81        /* Sanity check; are we still looking at HP firmware tables? */
82        if (strcmp(hdr->oem_id, "HP"))
83                return;
84
85        if (!strcmp(hdr->oem_table_id, "zx2000") ||
86            !strcmp(hdr->oem_table_id, "zx6000") ||
87            !strcmp(hdr->oem_table_id, "rx2600") ||
88            !strcmp(hdr->oem_table_id, "cx2600")) {
89
90                ns16550_com1.irq = ns16550_com1_gsi = uart->gsi;
91                ns16550_com1_polarity = IOSAPIC_POL_HIGH;
92                ns16550_com1_trigger = IOSAPIC_EDGE;
93
94        } else if (!strcmp(hdr->oem_table_id, "rx2620") ||
95                   !strcmp(hdr->oem_table_id, "cx2620") ||
96                   !strcmp(hdr->oem_table_id, "rx1600") ||
97                   !strcmp(hdr->oem_table_id, "rx1620")) {
98
99                ns16550_com1.irq = ns16550_com1_gsi = uart->gsi;
100                ns16550_com1_polarity = IOSAPIC_POL_LOW;
101                ns16550_com1_trigger = IOSAPIC_LEVEL;
102        }
103}
104
105static void __init
106setup_pcdp_irq(struct pcdp *pcdp, struct pcdp_uart *uart)
107{
108        /* PCDP provides full interrupt info */
109        if (pcdp->rev >= 3) {
110                if (uart->flags & PCDP_UART_IRQ) {
111                        ns16550_com1.irq = ns16550_com1_gsi = uart->gsi,
112                        ns16550_com1_polarity =
113                                       uart->flags & PCDP_UART_ACTIVE_LOW ?
114                                       IOSAPIC_POL_LOW : IOSAPIC_POL_HIGH;
115                        ns16550_com1_trigger =
116                                       uart->flags & PCDP_UART_EDGE_SENSITIVE ?
117                                       IOSAPIC_EDGE : IOSAPIC_LEVEL;
118                }
119                return;
120        }
121
122        /* HCDP support */
123        if (uart->pci_func & PCDP_UART_IRQ) {
124                /*
125                 * HCDP tables don't provide interrupt polarity/trigger
126                 * info.  If the UART is a PCI device, we know to program
127                 * it as low/level.  Otherwise rely on platform hacks or
128                 * default to polling (irq = 0).
129                 */
130                if (uart->pci_func & PCDP_UART_PCI) {
131                        ns16550_com1.irq = ns16550_com1_gsi = uart->gsi;
132                        ns16550_com1_polarity = IOSAPIC_POL_LOW;
133                        ns16550_com1_trigger = IOSAPIC_LEVEL;
134                } else if (!strcmp((char *)pcdp->oemid, "HP"))
135                        pcdp_hp_irq_fixup(pcdp, uart);
136        }
137}
138
139static int __init
140setup_serial_console(struct pcdp *pcdp, struct pcdp_uart *uart)
141{
142
143        ns16550_com1.baud = uart->baud ? uart->baud : BAUD_AUTO;
144        ns16550_com1.io_base = uart->addr.address;
145        if (uart->bits)
146                ns16550_com1.data_bits = uart->bits;
147
148        setup_pcdp_irq(pcdp, uart);
149
150        return 0;
151}
152#else
153static int __init
154setup_serial_console(struct pcdp_uart *uart)
155{
156#ifdef CONFIG_SERIAL_8250_CONSOLE
157        int mmio;
158        static char options[64];
159
160        mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
161        snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d",
162                mmio ? "mmio" : "io", uart->addr.address, uart->baud,
163                uart->bits ? uart->bits : 8);
164
165        return early_serial_console_init(options);
166#else
167        return -ENODEV;
168#endif
169}
170
171static int __init
172setup_vga_console(struct pcdp_vga *vga)
173{
174#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
175        if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
176                printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
177                return -ENODEV;
178        }
179
180        conswitchp = &vga_con;
181        printk(KERN_INFO "PCDP: VGA console\n");
182        return 0;
183#else
184        return -ENODEV;
185#endif
186}
187#endif
188
189int __init
190efi_setup_pcdp_console(char *cmdline)
191{
192        struct pcdp *pcdp;
193        struct pcdp_uart *uart;
194#ifndef XEN
195        struct pcdp_device *dev, *end;
196#endif
197        int i, serial = 0;
198
199        pcdp = efi.hcdp;
200        if (!pcdp)
201                return -ENODEV;
202
203#ifndef XEN
204        printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
205#endif
206
207        if (strstr(cmdline, "console=hcdp")) {
208                if (pcdp->rev < 3)
209                        serial = 1;
210        } else if (strstr(cmdline, "console=")) {
211#ifndef XEN
212                printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
213#endif
214                return -ENODEV;
215        }
216
217        if (pcdp->rev < 3 && efi_uart_console_only())
218                serial = 1;
219
220        for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
221                if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
222                        if (uart->type == PCDP_CONSOLE_UART) {
223#ifndef XEN
224                                return setup_serial_console(uart);
225#else
226                                return setup_serial_console(pcdp, uart);
227#endif
228                               
229                        }
230                }
231        }
232
233#ifndef XEN
234        end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
235        for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
236             dev < end;
237             dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
238                if (dev->flags & PCDP_PRIMARY_CONSOLE) {
239                        if (dev->type == PCDP_CONSOLE_VGA) {
240                                return setup_vga_console((struct pcdp_vga *) dev);
241                        }
242                }
243        }
244#endif
245
246        return -ENODEV;
247}
Note: See TracBrowser for help on using the repository browser.