]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/serial/8250.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / drivers / serial / 8250.c
index 5f383d8d248ba8364e434f5a2393b12b89a1d4d9..acea5623b2281159ee59003d82ac8e286489622c 100644 (file)
@@ -279,6 +279,13 @@ static const struct serial8250_config uart_config[] = {
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
                .flags          = UART_CAP_FIFO,
        },
+       [PORT_OCTEON] = {
+               .name           = "OCTEON",
+               .fifo_size      = 64,
+               .tx_loadsz      = 64,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .flags          = UART_CAP_FIFO,
+       },
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -303,16 +310,16 @@ static const u8 au_io_out_map[] = {
 };
 
 /* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_AU)
+       if (p->iotype != UPIO_AU)
                return offset;
        return au_io_in_map[offset];
 }
 
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_AU)
+       if (p->iotype != UPIO_AU)
                return offset;
        return au_io_out_map[offset];
 }
@@ -341,16 +348,16 @@ static const u8
                [UART_SCR]      = 0x2c
        };
 
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_RM9000)
+       if (p->iotype != UPIO_RM9000)
                return offset;
        return regmap_in[offset];
 }
 
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
 {
-       if (up->port.iotype != UPIO_RM9000)
+       if (p->iotype != UPIO_RM9000)
                return offset;
        return regmap_out[offset];
 }
@@ -363,108 +370,170 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
 
 #endif
 
-static unsigned int serial_in(struct uart_8250_port *up, int offset)
+static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 {
-       unsigned int tmp;
-       offset = map_8250_in_reg(up, offset) << up->port.regshift;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       return inb(p->iobase + 1);
+}
 
-       switch (up->port.iotype) {
-       case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               return inb(up->port.iobase + 1);
+static void hub6_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(p->hub6 - 1 + offset, p->iobase);
+       outb(value, p->iobase + 1);
+}
 
-       case UPIO_MEM:
-       case UPIO_DWAPB:
-               return readb(up->port.membase + offset);
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readb(p->membase + offset);
+}
 
-       case UPIO_RM9000:
-       case UPIO_MEM32:
-               return readl(up->port.membase + offset);
+static void mem_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static void mem32_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       writel(value, p->membase + offset);
+}
+
+static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return readl(p->membase + offset);
+}
 
 #ifdef CONFIG_SERIAL_8250_AU1X00
-       case UPIO_AU:
-               return __raw_readl(up->port.membase + offset);
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       __raw_writel(value, p->membase + offset);
+}
 #endif
 
-       case UPIO_TSI:
-               if (offset == UART_IIR) {
-                       tmp = readl(up->port.membase + (UART_IIR & ~3));
-                       return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
-               } else
-                       return readb(up->port.membase + offset);
+static unsigned int tsi_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int tmp;
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       if (offset == UART_IIR) {
+               tmp = readl(p->membase + (UART_IIR & ~3));
+               return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+       } else
+               return readb(p->membase + offset);
+}
 
-       default:
-               return inb(up->port.iobase + offset);
-       }
+static void tsi_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+               writeb(value, p->membase + offset);
 }
 
-static void
-serial_out(struct uart_8250_port *up, int offset, int value)
+static void dwapb_serial_out(struct uart_port *p, int offset, int value)
 {
-       /* Save the offset before it's remapped */
        int save_offset = offset;
-       offset = map_8250_out_reg(up, offset) << up->port.regshift;
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       /* Save the LCR value so it can be re-written when a
+        * Busy Detect interrupt occurs. */
+       if (save_offset == UART_LCR) {
+               struct uart_8250_port *up = (struct uart_8250_port *)p;
+               up->lcr = value;
+       }
+       writeb(value, p->membase + offset);
+       /* Read the IER to ensure any interrupt is cleared before
+        * returning from ISR. */
+       if (save_offset == UART_TX || save_offset == UART_IER)
+               value = p->serial_in(p, UART_IER);
+}
 
-       switch (up->port.iotype) {
+static unsigned int io_serial_in(struct uart_port *p, int offset)
+{
+       offset = map_8250_in_reg(p, offset) << p->regshift;
+       return inb(p->iobase + offset);
+}
+
+static void io_serial_out(struct uart_port *p, int offset, int value)
+{
+       offset = map_8250_out_reg(p, offset) << p->regshift;
+       outb(value, p->iobase + offset);
+}
+
+static void set_io_from_upio(struct uart_port *p)
+{
+       switch (p->iotype) {
        case UPIO_HUB6:
-               outb(up->port.hub6 - 1 + offset, up->port.iobase);
-               outb(value, up->port.iobase + 1);
+               p->serial_in = hub6_serial_in;
+               p->serial_out = hub6_serial_out;
                break;
 
        case UPIO_MEM:
-               writeb(value, up->port.membase + offset);
+               p->serial_in = mem_serial_in;
+               p->serial_out = mem_serial_out;
                break;
 
        case UPIO_RM9000:
        case UPIO_MEM32:
-               writel(value, up->port.membase + offset);
+               p->serial_in = mem32_serial_in;
+               p->serial_out = mem32_serial_out;
                break;
 
 #ifdef CONFIG_SERIAL_8250_AU1X00
        case UPIO_AU:
-               __raw_writel(value, up->port.membase + offset);
+               p->serial_in = au_serial_in;
+               p->serial_out = au_serial_out;
                break;
 #endif
        case UPIO_TSI:
-               if (!((offset == UART_IER) && (value & UART_IER_UUE)))
-                       writeb(value, up->port.membase + offset);
+               p->serial_in = tsi_serial_in;
+               p->serial_out = tsi_serial_out;
                break;
 
        case UPIO_DWAPB:
-               /* Save the LCR value so it can be re-written when a
-                * Busy Detect interrupt occurs. */
-               if (save_offset == UART_LCR)
-                       up->lcr = value;
-               writeb(value, up->port.membase + offset);
-               /* Read the IER to ensure any interrupt is cleared before
-                * returning from ISR. */
-               if (save_offset == UART_TX || save_offset == UART_IER)
-                       value = serial_in(up, UART_IER);
+               p->serial_in = mem_serial_in;
+               p->serial_out = dwapb_serial_out;
                break;
 
        default:
-               outb(value, up->port.iobase + offset);
+               p->serial_in = io_serial_in;
+               p->serial_out = io_serial_out;
+               break;
        }
 }
 
 static void
 serial_out_sync(struct uart_8250_port *up, int offset, int value)
 {
-       switch (up->port.iotype) {
+       struct uart_port *p = &up->port;
+       switch (p->iotype) {
        case UPIO_MEM:
        case UPIO_MEM32:
 #ifdef CONFIG_SERIAL_8250_AU1X00
        case UPIO_AU:
 #endif
        case UPIO_DWAPB:
-               serial_out(up, offset, value);
-               serial_in(up, UART_LCR);        /* safe, no side-effects */
+               p->serial_out(p, offset, value);
+               p->serial_in(p, UART_LCR);      /* safe, no side-effects */
                break;
        default:
-               serial_out(up, offset, value);
+               p->serial_out(p, offset, value);
        }
 }
 
+#define serial_in(up, offset)          \
+       (up->port.serial_in(&(up)->port, (offset)))
+#define serial_out(up, offset, value)  \
+       (up->port.serial_out(&(up)->port, (offset), (value)))
 /*
  * We used to support using pause I/O for certain machines.  We
  * haven't supported this for a while, but just in case it's badly
@@ -2593,6 +2662,7 @@ static void __init serial8250_isa_init_ports(void)
                up->port.membase  = old_serial_port[i].iomem_base;
                up->port.iotype   = old_serial_port[i].io_type;
                up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               set_io_from_upio(&up->port);
                if (share_irqs)
                        up->port.flags |= UPF_SHARE_IRQ;
        }
@@ -2769,12 +2839,30 @@ static struct uart_driver serial8250_reg = {
  */
 int __init early_serial_setup(struct uart_port *port)
 {
+       struct uart_port *p;
+
        if (port->line >= ARRAY_SIZE(serial8250_ports))
                return -ENODEV;
 
        serial8250_isa_init_ports();
-       serial8250_ports[port->line].port       = *port;
-       serial8250_ports[port->line].port.ops   = &serial8250_pops;
+       p = &serial8250_ports[port->line].port;
+       p->iobase       = port->iobase;
+       p->membase      = port->membase;
+       p->irq          = port->irq;
+       p->uartclk      = port->uartclk;
+       p->fifosize     = port->fifosize;
+       p->regshift     = port->regshift;
+       p->iotype       = port->iotype;
+       p->flags        = port->flags;
+       p->mapbase      = port->mapbase;
+       p->private_data = port->private_data;
+
+       set_io_from_upio(p);
+       if (port->serial_in)
+               p->serial_in = port->serial_in;
+       if (port->serial_out)
+               p->serial_out = port->serial_out;
+
        return 0;
 }
 
@@ -2839,6 +2927,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.mapbase            = p->mapbase;
                port.hub6               = p->hub6;
                port.private_data       = p->private_data;
+               port.type               = p->type;
+               port.serial_in          = p->serial_in;
+               port.serial_out         = p->serial_out;
                port.dev                = &dev->dev;
                if (share_irqs)
                        port.flags |= UPF_SHARE_IRQ;
@@ -2993,6 +3084,20 @@ int serial8250_register_port(struct uart_port *port)
                if (port->dev)
                        uart->port.dev = port->dev;
 
+               if (port->flags & UPF_FIXED_TYPE) {
+                       uart->port.type = port->type;
+                       uart->port.fifosize = uart_config[port->type].fifo_size;
+                       uart->capabilities = uart_config[port->type].flags;
+                       uart->tx_loadsz = uart_config[port->type].tx_loadsz;
+               }
+
+               set_io_from_upio(&uart->port);
+               /* Possibly override default I/O functions.  */
+               if (port->serial_in)
+                       uart->port.serial_in = port->serial_in;
+               if (port->serial_out)
+                       uart->port.serial_out = port->serial_out;
+
                ret = uart_add_one_port(&serial8250_reg, &uart->port);
                if (ret == 0)
                        ret = uart->port.line;
@@ -3035,7 +3140,7 @@ static int __init serial8250_init(void)
        if (nr_uarts > UART_NR)
                nr_uarts = UART_NR;
 
-       printk(KERN_INFO "Serial: 8250/16550 driver"
+       printk(KERN_INFO "Serial: 8250/16550 driver"
                "%d ports, IRQ sharing %sabled\n", nr_uarts,
                share_irqs ? "en" : "dis");