linux/drivers/tty/serial/8250/8250_hp300.c
<<
>>
Prefs
   1/*
   2 * Driver for the 98626/98644/internal serial interface on hp300/hp400
   3 * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
   4 *
   5 * Ported from 2.2 and modified to use the normal 8250 driver
   6 * by Kars de Jong <jongk@linux-m68k.org>, May 2004.
   7 */
   8#include <linux/module.h>
   9#include <linux/init.h>
  10#include <linux/string.h>
  11#include <linux/kernel.h>
  12#include <linux/serial.h>
  13#include <linux/serial_core.h>
  14#include <linux/serial_8250.h>
  15#include <linux/delay.h>
  16#include <linux/dio.h>
  17#include <linux/console.h>
  18#include <linux/slab.h>
  19#include <asm/io.h>
  20
  21#include "8250.h"
  22
  23#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
  24#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
  25#endif
  26
  27#ifdef CONFIG_HPAPCI
  28struct hp300_port
  29{
  30        struct hp300_port *next;        /* next port */
  31        int line;                       /* line (tty) number */
  32};
  33
  34static struct hp300_port *hp300_ports;
  35#endif
  36
  37#ifdef CONFIG_HPDCA
  38
  39static int hpdca_init_one(struct dio_dev *d,
  40                                        const struct dio_device_id *ent);
  41static void hpdca_remove_one(struct dio_dev *d);
  42
  43static struct dio_device_id hpdca_dio_tbl[] = {
  44        { DIO_ID_DCA0 },
  45        { DIO_ID_DCA0REM },
  46        { DIO_ID_DCA1 },
  47        { DIO_ID_DCA1REM },
  48        { 0 }
  49};
  50
  51static struct dio_driver hpdca_driver = {
  52        .name      = "hpdca",
  53        .id_table  = hpdca_dio_tbl,
  54        .probe     = hpdca_init_one,
  55        .remove    = hpdca_remove_one,
  56};
  57
  58#endif
  59
  60static unsigned int num_ports;
  61
  62extern int hp300_uart_scode;
  63
  64/* Offset to UART registers from base of DCA */
  65#define UART_OFFSET     17
  66
  67#define DCA_ID          0x01    /* ID (read), reset (write) */
  68#define DCA_IC          0x03    /* Interrupt control        */
  69
  70/* Interrupt control */
  71#define DCA_IC_IE       0x80    /* Master interrupt enable  */
  72
  73#define HPDCA_BAUD_BASE 153600
  74
  75/* Base address of the Frodo part */
  76#define FRODO_BASE      (0x41c000)
  77
  78/*
  79 * Where we find the 8250-like APCI ports, and how far apart they are.
  80 */
  81#define FRODO_APCIBASE          0x0
  82#define FRODO_APCISPACE         0x20
  83#define FRODO_APCI_OFFSET(x)    (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
  84
  85#define HPAPCI_BAUD_BASE 500400
  86
  87#ifdef CONFIG_SERIAL_8250_CONSOLE
  88/*
  89 * Parse the bootinfo to find descriptions for headless console and
  90 * debug serial ports and register them with the 8250 driver.
  91 * This function should be called before serial_console_init() is called
  92 * to make sure the serial console will be available for use. IA-64 kernel
  93 * calls this function from setup_arch() after the EFI and ACPI tables have
  94 * been parsed.
  95 */
  96int __init hp300_setup_serial_console(void)
  97{
  98        int scode;
  99        struct uart_port port;
 100
 101        memset(&port, 0, sizeof(port));
 102
 103        if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
 104                return 0;
 105
 106        if (DIO_SCINHOLE(hp300_uart_scode))
 107                return 0;
 108
 109        scode = hp300_uart_scode;
 110
 111        /* Memory mapped I/O */
 112        port.iotype = UPIO_MEM;
 113        port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
 114        port.type = PORT_UNKNOWN;
 115
 116        /* Check for APCI console */
 117        if (scode == 256) {
 118#ifdef CONFIG_HPAPCI
 119                printk(KERN_INFO "Serial console is HP APCI 1\n");
 120
 121                port.uartclk = HPAPCI_BAUD_BASE * 16;
 122                port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
 123                port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
 124                port.regshift = 2;
 125                add_preferred_console("ttyS", port.line, "9600n8");
 126#else
 127                printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
 128                return 0;
 129#endif
 130        } else {
 131#ifdef CONFIG_HPDCA
 132                unsigned long pa = dio_scodetophysaddr(scode);
 133                if (!pa)
 134                        return 0;
 135
 136                printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
 137
 138                port.uartclk = HPDCA_BAUD_BASE * 16;
 139                port.mapbase = (pa + UART_OFFSET);
 140                port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
 141                port.regshift = 1;
 142                port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
 143
 144                /* Enable board-interrupts */
 145                out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
 146
 147                if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
 148                        add_preferred_console("ttyS", port.line, "9600n8");
 149#else
 150                printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
 151                return 0;
 152#endif
 153        }
 154
 155        if (early_serial_setup(&port) < 0)
 156                printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
 157        return 0;
 158}
 159#endif /* CONFIG_SERIAL_8250_CONSOLE */
 160
 161#ifdef CONFIG_HPDCA
 162static int hpdca_init_one(struct dio_dev *d,
 163                                const struct dio_device_id *ent)
 164{
 165        struct uart_8250_port uart;
 166        int line;
 167
 168#ifdef CONFIG_SERIAL_8250_CONSOLE
 169        if (hp300_uart_scode == d->scode) {
 170                /* Already got it. */
 171                return 0;
 172        }
 173#endif
 174        memset(&uart, 0, sizeof(uart));
 175
 176        /* Memory mapped I/O */
 177        uart.port.iotype = UPIO_MEM;
 178        uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
 179        uart.port.irq = d->ipl;
 180        uart.port.uartclk = HPDCA_BAUD_BASE * 16;
 181        uart.port.mapbase = (d->resource.start + UART_OFFSET);
 182        uart.port.membase = (char *)(uart.port.mapbase + DIO_VIRADDRBASE);
 183        uart.port.regshift = 1;
 184        uart.port.dev = &d->dev;
 185        line = serial8250_register_8250_port(&uart);
 186
 187        if (line < 0) {
 188                printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
 189                       " irq %d failed\n", d->scode, uart.port.irq);
 190                return -ENOMEM;
 191        }
 192
 193        /* Enable board-interrupts */
 194        out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
 195        dio_set_drvdata(d, (void *)line);
 196
 197        /* Reset the DCA */
 198        out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
 199        udelay(100);
 200
 201        num_ports++;
 202
 203        return 0;
 204}
 205#endif
 206
 207static int __init hp300_8250_init(void)
 208{
 209        static int called;
 210#ifdef CONFIG_HPAPCI
 211        int line;
 212        unsigned long base;
 213        struct uart_8250_port uart;
 214        struct hp300_port *port;
 215        int i;
 216#endif
 217        if (called)
 218                return -ENODEV;
 219        called = 1;
 220
 221        if (!MACH_IS_HP300)
 222                return -ENODEV;
 223
 224#ifdef CONFIG_HPDCA
 225        dio_register_driver(&hpdca_driver);
 226#endif
 227#ifdef CONFIG_HPAPCI
 228        if (hp300_model < HP_400) {
 229                if (!num_ports)
 230                        return -ENODEV;
 231                return 0;
 232        }
 233        /* These models have the Frodo chip.
 234         * Port 0 is reserved for the Apollo Domain keyboard.
 235         * Port 1 is either the console or the DCA.
 236         */
 237        for (i = 1; i < 4; i++) {
 238                /* Port 1 is the console on a 425e, on other machines it's
 239                 * mapped to DCA.
 240                 */
 241#ifdef CONFIG_SERIAL_8250_CONSOLE
 242                if (i == 1)
 243                        continue;
 244#endif
 245
 246                /* Create new serial device */
 247                port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
 248                if (!port)
 249                        return -ENOMEM;
 250
 251                memset(&uart, 0, sizeof(uart));
 252
 253                base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
 254
 255                /* Memory mapped I/O */
 256                uart.port.iotype = UPIO_MEM;
 257                uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
 258                              | UPF_BOOT_AUTOCONF;
 259                /* XXX - no interrupt support yet */
 260                uart.port.irq = 0;
 261                uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
 262                uart.port.mapbase = base;
 263                uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
 264                uart.port.regshift = 2;
 265
 266                line = serial8250_register_8250_port(&uart);
 267
 268                if (line < 0) {
 269                        printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
 270                               " %d irq %d failed\n", i, uart.port.irq);
 271                        kfree(port);
 272                        continue;
 273                }
 274
 275                port->line = line;
 276                port->next = hp300_ports;
 277                hp300_ports = port;
 278
 279                num_ports++;
 280        }
 281#endif
 282
 283        /* Any boards found? */
 284        if (!num_ports)
 285                return -ENODEV;
 286
 287        return 0;
 288}
 289
 290#ifdef CONFIG_HPDCA
 291static void hpdca_remove_one(struct dio_dev *d)
 292{
 293        int line;
 294
 295        line = (int) dio_get_drvdata(d);
 296        if (d->resource.start) {
 297                /* Disable board-interrupts */
 298                out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
 299        }
 300        serial8250_unregister_port(line);
 301}
 302#endif
 303
 304static void __exit hp300_8250_exit(void)
 305{
 306#ifdef CONFIG_HPAPCI
 307        struct hp300_port *port, *to_free;
 308
 309        for (port = hp300_ports; port; ) {
 310                serial8250_unregister_port(port->line);
 311                to_free = port;
 312                port = port->next;
 313                kfree(to_free);
 314        }
 315
 316        hp300_ports = NULL;
 317#endif
 318#ifdef CONFIG_HPDCA
 319        dio_unregister_driver(&hpdca_driver);
 320#endif
 321}
 322
 323module_init(hp300_8250_init);
 324module_exit(hp300_8250_exit);
 325MODULE_DESCRIPTION("HP DCA/APCI serial driver");
 326MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
 327MODULE_LICENSE("GPL");
 328