Commit d4965b3e authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/rmk/linux-2.6-serial

* master.kernel.org:/home/rmk/linux-2.6-serial:
  [SERIAL] Provide Cirrus EP93xx AMBA PL010 serial support.
  [SERIAL] amba-pl010: allow platforms to specify modem control method
  [SERIAL] Remove obsoleted au1x00_uart driver
  [SERIAL] Small time UART configuration fix for AU1100 processor
parents 9561b03d aee85fe8
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/termios.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/serial.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -360,6 +362,68 @@ void __init ep93xx_init_irq(void) ...@@ -360,6 +362,68 @@ void __init ep93xx_init_irq(void)
/************************************************************************* /*************************************************************************
* EP93xx peripheral handling * EP93xx peripheral handling
*************************************************************************/ *************************************************************************/
#define EP93XX_UART_MCR_OFFSET (0x0100)
static void ep93xx_uart_set_mctrl(struct amba_device *dev,
void __iomem *base, unsigned int mctrl)
{
unsigned int mcr;
mcr = 0;
if (!(mctrl & TIOCM_RTS))
mcr |= 2;
if (!(mctrl & TIOCM_DTR))
mcr |= 1;
__raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET);
}
static struct amba_pl010_data ep93xx_uart_data = {
.set_mctrl = ep93xx_uart_set_mctrl,
};
static struct amba_device uart1_device = {
.dev = {
.bus_id = "apb:uart1",
.platform_data = &ep93xx_uart_data,
},
.res = {
.start = EP93XX_UART1_PHYS_BASE,
.end = EP93XX_UART1_PHYS_BASE + 0x0fff,
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_EP93XX_UART1, NO_IRQ },
.periphid = 0x00041010,
};
static struct amba_device uart2_device = {
.dev = {
.bus_id = "apb:uart2",
.platform_data = &ep93xx_uart_data,
},
.res = {
.start = EP93XX_UART2_PHYS_BASE,
.end = EP93XX_UART2_PHYS_BASE + 0x0fff,
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_EP93XX_UART2, NO_IRQ },
.periphid = 0x00041010,
};
static struct amba_device uart3_device = {
.dev = {
.bus_id = "apb:uart3",
.platform_data = &ep93xx_uart_data,
},
.res = {
.start = EP93XX_UART3_PHYS_BASE,
.end = EP93XX_UART3_PHYS_BASE + 0x0fff,
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_EP93XX_UART3, NO_IRQ },
.periphid = 0x00041010,
};
void __init ep93xx_init_devices(void) void __init ep93xx_init_devices(void)
{ {
unsigned int v; unsigned int v;
...@@ -371,4 +435,8 @@ void __init ep93xx_init_devices(void) ...@@ -371,4 +435,8 @@ void __init ep93xx_init_devices(void)
v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE; v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG); __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
amba_device_register(&uart1_device, &iomem_resource);
amba_device_register(&uart2_device, &iomem_resource);
amba_device_register(&uart3_device, &iomem_resource);
} }
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/termios.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/serial.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -28,6 +30,8 @@ ...@@ -28,6 +30,8 @@
#include "common.h" #include "common.h"
static struct amba_pl010_data integrator_uart_data;
static struct amba_device rtc_device = { static struct amba_device rtc_device = {
.dev = { .dev = {
.bus_id = "mb:15", .bus_id = "mb:15",
...@@ -44,6 +48,7 @@ static struct amba_device rtc_device = { ...@@ -44,6 +48,7 @@ static struct amba_device rtc_device = {
static struct amba_device uart0_device = { static struct amba_device uart0_device = {
.dev = { .dev = {
.bus_id = "mb:16", .bus_id = "mb:16",
.platform_data = &integrator_uart_data,
}, },
.res = { .res = {
.start = INTEGRATOR_UART0_BASE, .start = INTEGRATOR_UART0_BASE,
...@@ -57,6 +62,7 @@ static struct amba_device uart0_device = { ...@@ -57,6 +62,7 @@ static struct amba_device uart0_device = {
static struct amba_device uart1_device = { static struct amba_device uart1_device = {
.dev = { .dev = {
.bus_id = "mb:17", .bus_id = "mb:17",
.platform_data = &integrator_uart_data,
}, },
.res = { .res = {
.start = INTEGRATOR_UART1_BASE, .start = INTEGRATOR_UART1_BASE,
...@@ -115,6 +121,46 @@ static int __init integrator_init(void) ...@@ -115,6 +121,46 @@ static int __init integrator_init(void)
arch_initcall(integrator_init); arch_initcall(integrator_init);
/*
* On the Integrator platform, the port RTS and DTR are provided by
* bits in the following SC_CTRLS register bits:
* RTS DTR
* UART0 7 6
* UART1 5 4
*/
#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
{
unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
if (dev == &uart0_device) {
rts_mask = 1 << 4;
dtr_mask = 1 << 5;
} else {
rts_mask = 1 << 6;
dtr_mask = 1 << 7;
}
if (mctrl & TIOCM_RTS)
ctrlc |= rts_mask;
else
ctrls |= rts_mask;
if (mctrl & TIOCM_DTR)
ctrlc |= dtr_mask;
else
ctrls |= dtr_mask;
__raw_writel(ctrls, SC_CTRLS);
__raw_writel(ctrlc, SC_CTRLC);
}
static struct amba_pl010_data integrator_uart_data = {
.set_mctrl = integrator_uart_set_mctrl,
};
#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET #define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
static DEFINE_SPINLOCK(cm_lock); static DEFINE_SPINLOCK(cm_lock);
......
...@@ -94,7 +94,7 @@ void __init plat_setup(void) ...@@ -94,7 +94,7 @@ void __init plat_setup(void)
argptr = prom_getcmdline(); argptr = prom_getcmdline();
#if defined(CONFIG_SERIAL_AU1X00_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) #ifdef CONFIG_SERIAL_8250_CONSOLE
if ((argptr = strstr(argptr, "console=")) == NULL) { if ((argptr = strstr(argptr, "console=")) == NULL) {
argptr = prom_getcmdline(); argptr = prom_getcmdline();
strcat(argptr, " console=ttyS0,115200"); strcat(argptr, " console=ttyS0,115200");
......
...@@ -51,7 +51,7 @@ static struct plat_serial8250_port au1x00_data[] = { ...@@ -51,7 +51,7 @@ static struct plat_serial8250_port au1x00_data[] = {
#elif defined(CONFIG_SOC_AU1100) #elif defined(CONFIG_SOC_AU1100)
PORT(UART0_ADDR, AU1100_UART0_INT), PORT(UART0_ADDR, AU1100_UART0_INT),
PORT(UART1_ADDR, AU1100_UART1_INT), PORT(UART1_ADDR, AU1100_UART1_INT),
PORT(UART2_ADDR, AU1100_UART2_INT), /* The internal UART2 does not exist on the AU1100 processor. */
PORT(UART3_ADDR, AU1100_UART3_INT), PORT(UART3_ADDR, AU1100_UART3_INT),
#elif defined(CONFIG_SOC_AU1550) #elif defined(CONFIG_SOC_AU1550)
PORT(UART0_ADDR, AU1550_UART0_INT), PORT(UART0_ADDR, AU1550_UART0_INT),
......
...@@ -620,22 +620,6 @@ config SERIAL_SH_SCI_CONSOLE ...@@ -620,22 +620,6 @@ config SERIAL_SH_SCI_CONSOLE
depends on SERIAL_SH_SCI=y depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE select SERIAL_CORE_CONSOLE
config SERIAL_AU1X00
bool "Enable Au1x00 UART Support"
depends on MIPS && SOC_AU1X00
select SERIAL_CORE
help
If you have an Alchemy AU1X00 processor (MIPS based) and you want
to use serial ports, say Y. Otherwise, say N.
config SERIAL_AU1X00_CONSOLE
bool "Enable Au1x00 serial console"
depends on SERIAL_AU1X00
select SERIAL_CORE_CONSOLE
help
If you have an Alchemy AU1X00 processor (MIPS based) and you want
to use a console on a serial port, say Y. Otherwise, say N.
config SERIAL_CORE config SERIAL_CORE
tristate tristate
......
...@@ -41,7 +41,6 @@ obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o ...@@ -41,7 +41,6 @@ obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_V850E_UART) += v850e_uart.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
......
...@@ -51,8 +51,6 @@ ...@@ -51,8 +51,6 @@
#include <linux/amba/serial.h> #include <linux/amba/serial.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#define UART_NR 2 #define UART_NR 2
...@@ -65,26 +63,16 @@ ...@@ -65,26 +63,16 @@
#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) #define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0)
#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) #define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0)
#define UART_DUMMY_RSR_RX /*256*/0 #define UART_DUMMY_RSR_RX 256
#define UART_PORT_SIZE 64 #define UART_PORT_SIZE 64
/*
* On the Integrator platform, the port RTS and DTR are provided by
* bits in the following SC_CTRLS register bits:
* RTS DTR
* UART0 7 6
* UART1 5 4
*/
#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
/* /*
* We wrap our port structure around the generic uart_port. * We wrap our port structure around the generic uart_port.
*/ */
struct uart_amba_port { struct uart_amba_port {
struct uart_port port; struct uart_port port;
unsigned int dtr_mask; struct amba_device *dev;
unsigned int rts_mask; struct amba_pl010_data *data;
unsigned int old_status; unsigned int old_status;
}; };
...@@ -300,20 +288,9 @@ static unsigned int pl010_get_mctrl(struct uart_port *port) ...@@ -300,20 +288,9 @@ static unsigned int pl010_get_mctrl(struct uart_port *port)
static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct uart_amba_port *uap = (struct uart_amba_port *)port; struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int ctrls = 0, ctrlc = 0;
if (mctrl & TIOCM_RTS) if (uap->data)
ctrlc |= uap->rts_mask; uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
else
ctrls |= uap->rts_mask;
if (mctrl & TIOCM_DTR)
ctrlc |= uap->dtr_mask;
else
ctrls |= uap->dtr_mask;
__raw_writel(ctrls, SC_CTRLS);
__raw_writel(ctrlc, SC_CTRLC);
} }
static void pl010_break_ctl(struct uart_port *port, int break_state) static void pl010_break_ctl(struct uart_port *port, int break_state)
...@@ -539,38 +516,7 @@ static struct uart_ops amba_pl010_pops = { ...@@ -539,38 +516,7 @@ static struct uart_ops amba_pl010_pops = {
.verify_port = pl010_verify_port, .verify_port = pl010_verify_port,
}; };
static struct uart_amba_port amba_ports[UART_NR] = { static struct uart_amba_port *amba_ports[UART_NR];
{
.port = {
.membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
.mapbase = INTEGRATOR_UART0_BASE,
.iotype = UPIO_MEM,
.irq = IRQ_UARTINT0,
.uartclk = 14745600,
.fifosize = 16,
.ops = &amba_pl010_pops,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
},
.dtr_mask = 1 << 5,
.rts_mask = 1 << 4,
},
{
.port = {
.membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
.mapbase = INTEGRATOR_UART1_BASE,
.iotype = UPIO_MEM,
.irq = IRQ_UARTINT1,
.uartclk = 14745600,
.fifosize = 16,
.ops = &amba_pl010_pops,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
},
.dtr_mask = 1 << 7,
.rts_mask = 1 << 6,
}
};
#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE #ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
...@@ -588,7 +534,7 @@ static void pl010_console_putchar(struct uart_port *port, int ch) ...@@ -588,7 +534,7 @@ static void pl010_console_putchar(struct uart_port *port, int ch)
static void static void
pl010_console_write(struct console *co, const char *s, unsigned int count) pl010_console_write(struct console *co, const char *s, unsigned int count)
{ {
struct uart_port *port = &amba_ports[co->index].port; struct uart_port *port = &amba_ports[co->index]->port;
unsigned int status, old_cr; unsigned int status, old_cr;
/* /*
...@@ -651,7 +597,7 @@ static int __init pl010_console_setup(struct console *co, char *options) ...@@ -651,7 +597,7 @@ static int __init pl010_console_setup(struct console *co, char *options)
*/ */
if (co->index >= UART_NR) if (co->index >= UART_NR)
co->index = 0; co->index = 0;
port = &amba_ports[co->index].port; port = &amba_ports[co->index]->port;
if (options) if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow); uart_parse_options(options, &baud, &parity, &bits, &flow);
...@@ -672,24 +618,6 @@ static struct console amba_console = { ...@@ -672,24 +618,6 @@ static struct console amba_console = {
.data = &amba_reg, .data = &amba_reg,
}; };
static int __init amba_console_init(void)
{
/*
* All port initializations are done statically
*/
register_console(&amba_console);
return 0;
}
console_initcall(amba_console_init);
static int __init amba_late_console_init(void)
{
if (!(amba_console.flags & CON_ENABLED))
register_console(&amba_console);
return 0;
}
late_initcall(amba_late_console_init);
#define AMBA_CONSOLE &amba_console #define AMBA_CONSOLE &amba_console
#else #else
#define AMBA_CONSOLE NULL #define AMBA_CONSOLE NULL
...@@ -707,30 +635,76 @@ static struct uart_driver amba_reg = { ...@@ -707,30 +635,76 @@ static struct uart_driver amba_reg = {
static int pl010_probe(struct amba_device *dev, void *id) static int pl010_probe(struct amba_device *dev, void *id)
{ {
int i; struct uart_amba_port *port;
void __iomem *base;
int i, ret;
for (i = 0; i < UART_NR; i++) { for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i].port.mapbase != dev->res.start) if (amba_ports[i] == NULL)
continue;
amba_ports[i].port.dev = &dev->dev;
uart_add_one_port(&amba_reg, &amba_ports[i].port);
amba_set_drvdata(dev, &amba_ports[i]);
break; break;
if (i == ARRAY_SIZE(amba_ports)) {
ret = -EBUSY;
goto out;
} }
return 0; port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
if (!port) {
ret = -ENOMEM;
goto out;
}
base = ioremap(dev->res.start, PAGE_SIZE);
if (!base) {
ret = -ENOMEM;
goto free;
}
port->port.dev = &dev->dev;
port->port.mapbase = dev->res.start;
port->port.membase = base;
port->port.iotype = UPIO_MEM;
port->port.irq = dev->irq[0];
port->port.uartclk = 14745600;
port->port.fifosize = 16;
port->port.ops = &amba_pl010_pops;
port->port.flags = UPF_BOOT_AUTOCONF;
port->port.line = i;
port->dev = dev;
port->data = dev->dev.platform_data;
amba_ports[i] = port;
amba_set_drvdata(dev, port);
ret = uart_add_one_port(&amba_reg, &port->port);
if (ret) {
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
iounmap(base);
free:
kfree(port);
}
out:
return ret;
} }
static int pl010_remove(struct amba_device *dev) static int pl010_remove(struct amba_device *dev)
{ {
struct uart_amba_port *uap = amba_get_drvdata(dev); struct uart_amba_port *port = amba_get_drvdata(dev);
int i;
if (uap)
uart_remove_one_port(&amba_reg, &uap->port);
amba_set_drvdata(dev, NULL); amba_set_drvdata(dev, NULL);
uart_remove_one_port(&amba_reg, &port->port);
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == port)
amba_ports[i] = NULL;
iounmap(port->port.membase);
kfree(port);
return 0; return 0;
} }
......
/*
* Driver for 8250/16550-type serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright (C) 2001 Russell King.
*
* 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.
*
* A note about mapbase / membase
*
* mapbase is the physical address of the IO port. Currently, we don't
* support this very well, and it may well be dropped from this driver
* in future. As such, mapbase should be NULL.
*
* membase is an 'ioremapped' cookie. This is compatible with the old
* serial.c driver, and is currently the preferred form.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/delay.h>
#include <asm/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-au1x00/au1000.h>
#if defined(CONFIG_SERIAL_AU1X00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#include "8250.h"
/*
* Debugging.
*/
#if 0
#define DEBUG_AUTOCONF(fmt...) printk(fmt)
#else
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
#endif
#if 0
#define DEBUG_INTR(fmt...) printk(fmt)
#else
#define DEBUG_INTR(fmt...) do { } while (0)
#endif
#define PASS_LIMIT 256
/*
* We default to IRQ0 for the "no irq" hack. Some
* machine types want others as well - they're free
* to redefine this in their header file.
*/
#define is_real_interrupt(irq) ((irq) != 0)
static struct old_serial_port old_serial_port[] = {
{ .baud_base = 0,
.iomem_base = (u8 *)UART0_ADDR,
.irq = AU1000_UART0_INT,
.flags = STD_COM_FLAGS,
.iomem_reg_shift = 2,
}, {
.baud_base = 0,
.iomem_base = (u8 *)UART1_ADDR,
.irq = AU1000_UART1_INT,
.flags = STD_COM_FLAGS,
.iomem_reg_shift = 2
}, {
.baud_base = 0,
.iomem_base = (u8 *)UART2_ADDR,
.irq = AU1000_UART2_INT,
.flags = STD_COM_FLAGS,
.iomem_reg_shift = 2
}, {
.baud_base = 0,
.iomem_base = (u8 *)UART3_ADDR,
.irq = AU1000_UART3_INT,
.flags = STD_COM_FLAGS,
.iomem_reg_shift = 2
}
};
#define UART_NR ARRAY_SIZE(old_serial_port)
struct uart_8250_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
unsigned short rev;
unsigned char acr;
unsigned char ier;
unsigned char lcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
unsigned char lsr_break_flag;
/*
* We provide a per-port pm hook.
*/
void (*pm)(struct uart_port *port,
unsigned int state, unsigned int old);
};
struct irq_info {
spinlock_t lock;
struct list_head *head;
};
static struct irq_info irq_lists[NR_IRQS];
/*
* Here we define the default xmit fifo size used for each type of UART.
*/
static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
{ "unknown", 1, 0 },
{ "8250", 1, 0 },
{ "16450", 1, 0 },
{ "16550", 1, 0 },
/* PORT_16550A */
{ "AU1X00_UART",16, UART_CLEAR_FIFO | UART_USE_FIFO },
};
static unsigned int serial_in(struct uart_8250_port *up, int offset)
{
return au_readl((unsigned long)up->port.membase + offset);
}
static void serial_out(struct uart_8250_port *up, int offset, int value)
{
au_writel(value, (unsigned long)up->port.membase + offset);
}
#define serial_inp(up, offset) serial_in(up, offset)
#define serial_outp(up, offset, value) serial_out(up, offset, value)
/*
* This routine is called by rs_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
* whether or not this UART is a 16550A or not, since this will
* determine whether or not we can use its FIFO features or not.
*/
static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
{
unsigned char save_lcr, save_mcr;
unsigned long flags;
if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
return;
DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%08lx): ",
up->port.line, up->port.iobase, up->port.membase);
/*
* We really do need global IRQs disabled here - we're going to
* be frobbing the chips IRQ enable register to see if it exists.
*/
spin_lock_irqsave(&up->port.lock, flags);
// save_flags(flags); cli();
save_mcr = serial_in(up, UART_MCR);
save_lcr = serial_in(up, UART_LCR);
up->port.type = PORT_16550A;
serial_outp(up, UART_LCR, save_lcr);
up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
if (up->port.type == PORT_UNKNOWN)
goto out;
/*
* Reset the UART.
*/
serial_outp(up, UART_MCR, save_mcr);
serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
serial_outp(up, UART_FCR, 0);
(void)serial_in(up, UART_RX);
serial_outp(up, UART_IER, 0);
out:
spin_unlock_irqrestore(&up->port.lock, flags);
// restore_flags(flags);
DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
}
static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
if (up->ier & UART_IER_THRI) {
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
}
static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
}
static void serial8250_stop_rx(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
}
static void serial8250_enable_ms(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
}
static void
receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch, flag;
int max_count = 256;
do {
ch = serial_inp(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE))) {
/*
* For statistics only
*/
if (*status & UART_LSR_BI) {
*status &= ~(UART_LSR_FE | UART_LSR_PE);
up->port.icount.brk++;
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
* or read_status_mask.
*/
if (uart_handle_break(&up->port))
goto ignore_char;
} else if (*status & UART_LSR_PE)
up->port.icount.parity++;
else if (*status & UART_LSR_FE)
up->port.icount.frame++;
if (*status & UART_LSR_OE)
up->port.icount.overrun++;
/*
* Mask off conditions which should be ingored.
*/
*status &= up->port.read_status_mask;
#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
if (up->port.line == up->port.cons->index) {
/* Recover the break flag from console xmit */
*status |= up->lsr_break_flag;
up->lsr_break_flag = 0;
}
#endif
if (*status & UART_LSR_BI) {
DEBUG_INTR("handling break....");
flag = TTY_BREAK;
} else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
else if (*status & UART_LSR_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0)
tty_insert_flip_char(tty, ch, flag);
if (*status & UART_LSR_OE)
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char:
*status = serial_inp(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
spin_unlock(&up->port.lock);
tty_flip_buffer_push(tty);
spin_lock(&up->port.lock);
}
static void transmit_chars(struct uart_8250_port *up)
{
struct circ_buf *xmit = &up->port.info->xmit;
int count;
if (up->port.x_char) {
serial_outp(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
up->port.x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
serial8250_stop_tx(&up->port);
return;
}
count = up->port.fifosize;
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
up->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
DEBUG_INTR("THRE...");
if (uart_circ_empty(xmit))
serial8250_stop_tx(&up->port);
}
static void check_modem_status(struct uart_8250_port *up)
{
int status;
status = serial_in(up, UART_MSR);
if ((status & UART_MSR_ANY_DELTA) == 0)
return;
if (status & UART_MSR_TERI)
up->port.icount.rng++;
if (status & UART_MSR_DDSR)
up->port.icount.dsr++;
if (status & UART_MSR_DDCD)
uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
if (status & UART_MSR_DCTS)
uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
wake_up_interruptible(&up->port.info->delta_msr_wait);
}
/*
* This handles the interrupt from one port.
*/
static inline void
serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
{
unsigned int status = serial_inp(up, UART_LSR);
DEBUG_INTR("status = %x...", status);
if (status & UART_LSR_DR)
receive_chars(up, &status, regs);
check_modem_status(up);
if (status & UART_LSR_THRE)
transmit_chars(up);
}
/*
* This is the serial driver's interrupt routine.
*
* Arjan thinks the old way was overly complex, so it got simplified.
* Alan disagrees, saying that need the complexity to handle the weird
* nature of ISA shared interrupts. (This is a special exception.)
*
* In order to handle ISA shared interrupts properly, we need to check
* that all ports have been serviced, and therefore the ISA interrupt
* line has been de-asserted.
*
* This means we need to loop through all ports. checking that they
* don't have an interrupt pending.
*/
static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct irq_info *i = dev_id;
struct list_head *l, *end = NULL;
int pass_counter = 0;
DEBUG_INTR("serial8250_interrupt(%d)...", irq);
spin_lock(&i->lock);
l = i->head;
do {
struct uart_8250_port *up;
unsigned int iir;
up = list_entry(l, struct uart_8250_port, list);
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT)) {
spin_lock(&up->port.lock);
serial8250_handle_port(up, regs);
spin_unlock(&up->port.lock);
end = NULL;
} else if (end == NULL)
end = l;
l = l->next;
if (l == i->head && pass_counter++ > PASS_LIMIT) {
/* If we hit this, we're dead. */
printk(KERN_ERR "serial8250: too much work for "
"irq%d\n", irq);
break;
}
} while (l != end);
spin_unlock(&i->lock);
DEBUG_INTR("end.\n");
/* FIXME! Was it really ours? */
return IRQ_HANDLED;
}
/*
* To support ISA shared interrupts, we need to have one interrupt
* handler that ensures that the IRQ line has been deasserted
* before returning. Failing to do this will result in the IRQ
* line being stuck active, and, since ISA irqs are edge triggered,
* no more IRQs will be seen.
*/
static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
{
spin_lock_irq(&i->lock);
if (!list_empty(i->head)) {
if (i->head == &up->list)
i->head = i->head->next;
list_del(&up->list);
} else {
BUG_ON(i->head != &up->list);
i->head = NULL;
}
spin_unlock_irq(&i->lock);
}
static int serial_link_irq_chain(struct uart_8250_port *up)
{
struct irq_info *i = irq_lists + up->port.irq;
int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
spin_lock_irq(&i->lock);
if (i->head) {
list_add(&up->list, i->head);
spin_unlock_irq(&i->lock);
ret = 0;
} else {
INIT_LIST_HEAD(&up->list);
i->head = &up->list;
spin_unlock_irq(&i->lock);
ret = request_irq(up->port.irq, serial8250_interrupt,
irq_flags, "serial", i);
if (ret < 0)
serial_do_unlink(i, up);
}
return ret;
}
static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
struct irq_info *i = irq_lists + up->port.irq;
BUG_ON(i->head == NULL);
if (list_empty(i->head))
free_irq(up->port.irq, i);
serial_do_unlink(i, up);
}
/*
* This function is used to handle ports that do not have an
* interrupt. This doesn't work very well for 16450's, but gives
* barely passable results for a 16550A. (Although at the expense
* of much CPU overhead).
*/
static void serial8250_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
unsigned int timeout;
unsigned int iir;
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT)) {
spin_lock(&up->port.lock);
serial8250_handle_port(up, NULL);
spin_unlock(&up->port.lock);
}
timeout = up->port.timeout;
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
mod_timer(&up->timer, jiffies + timeout);
}
static unsigned int serial8250_tx_empty(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
unsigned int ret;
spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
return ret;
}
static unsigned int serial8250_get_mctrl(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char status;
unsigned int ret;
status = serial_in(up, UART_MSR);
ret = 0;
if (status & UART_MSR_DCD)
ret |= TIOCM_CAR;
if (status & UART_MSR_RI)
ret |= TIOCM_RNG;
if (status & UART_MSR_DSR)
ret |= TIOCM_DSR;
if (status & UART_MSR_CTS)
ret |= TIOCM_CTS;
return ret;
}
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char mcr = 0;
if (mctrl & TIOCM_RTS)
mcr |= UART_MCR_RTS;
if (mctrl & TIOCM_DTR)
mcr |= UART_MCR_DTR;
if (mctrl & TIOCM_OUT1)
mcr |= UART_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
mcr |= UART_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
mcr = (mcr & up->mcr_mask) | up->mcr_force;
serial_out(up, UART_MCR, mcr);
}
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
else
up->lcr &= ~UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
}
static int serial8250_startup(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
int retval;
/*
* Clear the FIFO buffers and disable them.
* (they will be reeanbled in set_termios())
*/
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_outp(up, UART_FCR, 0);
}
/*
* Clear the interrupt registers.
*/
(void) serial_inp(up, UART_LSR);
(void) serial_inp(up, UART_RX);
(void) serial_inp(up, UART_IIR);
(void) serial_inp(up, UART_MSR);
/*
* At this point, there's no way the LSR could still be 0xff;
* if it is, then bail out, because there's likely no UART
* here.
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
(serial_inp(up, UART_LSR) == 0xff)) {
printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
return -ENODEV;
}
retval = serial_link_irq_chain(up);
if (retval)
return retval;
/*
* Now, initialize the UART
*/
serial_outp(up, UART_LCR, UART_LCR_WLEN8);
spin_lock_irqsave(&up->port.lock, flags);
if (up->port.flags & UPF_FOURPORT) {
if (!is_real_interrupt(up->port.irq))
up->port.mctrl |= TIOCM_OUT1;
} else
/*
* Most PC uarts need OUT2 raised to enable interrupts.
*/
if (is_real_interrupt(up->port.irq))
up->port.mctrl |= TIOCM_OUT2;
serial8250_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
serial_outp(up, UART_IER, up->ier);
if (up->port.flags & UPF_FOURPORT) {
unsigned int icp;
/*
* Enable interrupts on the AST Fourport board
*/
icp = (up->port.iobase & 0xfe0) | 0x01f;
outb_p(0x80, icp);
(void) inb_p(icp);
}
/*
* And clear the interrupt registers again for luck.
*/
(void) serial_inp(up, UART_LSR);
(void) serial_inp(up, UART_RX);
(void) serial_inp(up, UART_IIR);
(void) serial_inp(up, UART_MSR);
return 0;
}
static void serial8250_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
/*
* Disable interrupts from this port
*/
up->ier = 0;
serial_outp(up, UART_IER, 0);
spin_lock_irqsave(&up->port.lock, flags);
if (up->port.flags & UPF_FOURPORT) {
/* reset interrupts on the AST Fourport board */
inb((up->port.iobase & 0xfe0) | 0x1f);
up->port.mctrl |= TIOCM_OUT1;
} else
up->port.mctrl &= ~TIOCM_OUT2;
serial8250_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
/*
* Disable break condition and FIFOs
*/
serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
serial_outp(up, UART_FCR, 0);
/*
* Read data port to reset things, and then unlink from
* the IRQ chain.
*/
(void) serial_in(up, UART_RX);
if (!is_real_interrupt(up->port.irq))
del_timer_sync(&up->timer);
else
serial_unlink_irq_chain(up);
}
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
{
unsigned int quot;
/*
* Handle magic divisors for baud rates above baud_base on
* SMSC SuperIO chips.
*/
if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/4))
quot = 0x8001;
else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/8))
quot = 0x8002;
else
quot = uart_get_divisor(port, baud);
return quot;
}
static void
serial8250_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
case CS5:
cval = UART_LCR_WLEN5;
break;
case CS6:
cval = UART_LCR_WLEN6;
break;
case CS7:
cval = UART_LCR_WLEN7;
break;
default:
case CS8:
cval = UART_LCR_WLEN8;
break;
}
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (termios->c_cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = serial8250_get_divisor(port, baud);
quot = 0x35; /* FIXME */
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
* chip which causes it to seriously miscalculate baud rates
* when DLL is 0.
*/
if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
up->rev == 0x5201)
quot ++;
if (uart_config[up->port.type].flags & UART_USE_FIFO) {
if (baud < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;
}
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
spin_lock_irqsave(&up->port.lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/*
* Characteres to ignore
*/
up->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (termios->c_iflag & IGNBRK) {
up->port.ignore_status_mask |= UART_LSR_BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_OE;
}
/*
* ignore all characters if CREAD is not set
*/
if ((termios->c_cflag & CREAD) == 0)
up->port.ignore_status_mask |= UART_LSR_DR;
/*
* CTS flow control flag and modem status interrupts
*/
up->ier &= ~UART_IER_MSI;
if (UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
serial_outp(up, 0x28, quot & 0xffff);
up->lcr = cval; /* Save LCR */
if (up->port.type != PORT_16750) {
if (fcr & UART_FCR_ENABLE_FIFO) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
serial_outp(up, UART_FCR, fcr); /* set fcr */
}
spin_unlock_irqrestore(&up->port.lock, flags);
}
static void
serial8250_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
if (state) {
/* sleep */
if (up->pm)
up->pm(port, state, oldstate);
} else {
/* wake */
if (up->pm)
up->pm(port, state, oldstate);
}
}
/*
* Resource handling. This is complicated by the fact that resources
* depend on the port type. Maybe we should be claiming the standard
* 8250 ports, and then trying to get other resources as necessary?
*/
static int
serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
{
unsigned int size = 8 << up->port.regshift;
int ret = 0;
switch (up->port.iotype) {
case UPIO_MEM:
if (up->port.mapbase) {
*res = request_mem_region(up->port.mapbase, size, "serial");
if (!*res)
ret = -EBUSY;
}
break;
case UPIO_HUB6:
case UPIO_PORT:
*res = request_region(up->port.iobase, size, "serial");
if (!*res)
ret = -EBUSY;
break;
}
return ret;
}
static void serial8250_release_port(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long start, offset = 0, size = 0;
size <<= up->port.regshift;
switch (up->port.iotype) {
case UPIO_MEM:
if (up->port.mapbase) {
/*
* Unmap the area.
*/
iounmap(up->port.membase);
up->port.membase = NULL;
start = up->port.mapbase;
if (size)
release_mem_region(start + offset, size);
release_mem_region(start, 8 << up->port.regshift);
}
break;
case UPIO_HUB6:
case UPIO_PORT:
start = up->port.iobase;
if (size)
release_region(start + offset, size);
release_region(start + offset, 8 << up->port.regshift);
break;
default:
break;
}
}
static int serial8250_request_port(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
struct resource *res = NULL, *res_rsa = NULL;
int ret = 0;
ret = serial8250_request_std_resource(up, &res);
/*
* If we have a mapbase, then request that as well.
*/
if (ret == 0 && up->port.flags & UPF_IOREMAP) {
int size = res->end - res->start + 1;
up->port.membase = ioremap(up->port.mapbase, size);
if (!up->port.membase)
ret = -ENOMEM;
}
if (ret < 0) {
if (res_rsa)
release_resource(res_rsa);
if (res)
release_resource(res);
}
return ret;
}
static void serial8250_config_port(struct uart_port *port, int flags)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
struct resource *res_std = NULL, *res_rsa = NULL;
int probeflags = PROBE_ANY;
probeflags &= ~PROBE_RSA;
if (flags & UART_CONFIG_TYPE)
autoconfig(up, probeflags);
/*
* If the port wasn't an RSA port, release the resource.
*/
if (up->port.type != PORT_RSA && res_rsa)
release_resource(res_rsa);
if (up->port.type == PORT_UNKNOWN && res_std)
release_resource(res_std);
}
static int
serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->irq >= NR_IRQS || ser->irq < 0 ||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS ||
ser->type == PORT_STARTECH)
return -EINVAL;
return 0;
}
static const char *
serial8250_type(struct uart_port *port)
{
int type = port->type;
if (type >= ARRAY_SIZE(uart_config))
type = 0;
return uart_config[type].name;
}
static struct uart_ops serial8250_pops = {
.tx_empty = serial8250_tx_empty,
.set_mctrl = serial8250_set_mctrl,
.get_mctrl = serial8250_get_mctrl,
.stop_tx = serial8250_stop_tx,
.start_tx = serial8250_start_tx,
.stop_rx = serial8250_stop_rx,
.enable_ms = serial8250_enable_ms,
.break_ctl = serial8250_break_ctl,
.startup = serial8250_startup,
.shutdown = serial8250_shutdown,
.set_termios = serial8250_set_termios,
.pm = serial8250_pm,
.type = serial8250_type,
.release_port = serial8250_release_port,
.request_port = serial8250_request_port,
.config_port = serial8250_config_port,
.verify_port = serial8250_verify_port,
};
static struct uart_8250_port serial8250_ports[UART_NR];
static void __init serial8250_isa_init_ports(void)
{
struct uart_8250_port *up;
static int first = 1;
int i;
if (!first)
return;
first = 0;
for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = old_serial_port[i].irq;
up->port.uartclk = get_au1x00_uart_baud_base();
up->port.flags = old_serial_port[i].flags;
up->port.hub6 = old_serial_port[i].hub6;
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;
up->port.ops = &serial8250_pops;
}
}
static void __init serial8250_register_ports(struct uart_driver *drv)
{
int i;
serial8250_isa_init_ports();
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
up->port.line = i;
up->port.ops = &serial8250_pops;
init_timer(&up->timer);
up->timer.function = serial8250_timeout;
/*
* ALPHA_KLUDGE_MCR needs to be killed.
*/
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR;
uart_add_one_port(drv, &up->port);
}
}
#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Wait for transmitter & holding register to empty
*/
static inline void wait_for_xmitr(struct uart_8250_port *up)
{
unsigned int status, tmout = 10000;
/* Wait up to 10ms for the character(s) to be sent. */
do {
status = serial_in(up, UART_LSR);
if (status & UART_LSR_BI)
up->lsr_break_flag = UART_LSR_BI;
if (--tmout == 0)
break;
udelay(1);
} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
tmout = 1000000;
while (--tmout &&
((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
udelay(1);
}
}
static void au1x00_console_putchar(struct uart_port *port, int ch)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* The console_lock must be held when we get here.
*/
static void
serial8250_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_8250_port *up = &serial8250_ports[co->index];
unsigned int ier;
/*
* First save the UER then disable the interrupts
*/
ier = serial_in(up, UART_IER);
serial_out(up, UART_IER, 0);
uart_console_write(&up->port, s, count, au1x00_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(up);
serial_out(up, UART_IER, ier);
}
static int __init serial8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index >= UART_NR)
co->index = 0;
port = &serial8250_ports[co->index].port;
/*
* Temporary fix.
*/
spin_lock_init(&port->lock);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
extern struct uart_driver serial8250_reg;
static struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
.setup = serial8250_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial8250_reg,
};
static int __init serial8250_console_init(void)
{
serial8250_isa_init_ports();
register_console(&serial8250_console);
return 0;
}
console_initcall(serial8250_console_init);
#define SERIAL8250_CONSOLE &serial8250_console
#else
#define SERIAL8250_CONSOLE NULL
#endif
static struct uart_driver serial8250_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
.devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = UART_NR,
.cons = SERIAL8250_CONSOLE,
};
int __init early_serial_setup(struct uart_port *port)
{
serial8250_isa_init_ports();
serial8250_ports[port->line].port = *port;
serial8250_ports[port->line].port.ops = &serial8250_pops;
return 0;
}
/**
* serial8250_suspend_port - suspend one serial port
* @line: serial line number
* @level: the level of port suspension, as per uart_suspend_port
*
* Suspend one serial port.
*/
void serial8250_suspend_port(int line)
{
uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
}
/**
* serial8250_resume_port - resume one serial port
* @line: serial line number
* @level: the level of port resumption, as per uart_resume_port
*
* Resume one serial port.
*/
void serial8250_resume_port(int line)
{
uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
}
static int __init serial8250_init(void)
{
int ret, i;
printk(KERN_INFO "Serial: Au1x00 driver\n");
for (i = 0; i < NR_IRQS; i++)
spin_lock_init(&irq_lists[i].lock);
ret = uart_register_driver(&serial8250_reg);
if (ret >= 0)
serial8250_register_ports(&serial8250_reg);
return ret;
}
static void __exit serial8250_exit(void)
{
int i;
for (i = 0; i < UART_NR; i++)
uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
uart_unregister_driver(&serial8250_reg);
}
module_init(serial8250_init);
module_exit(serial8250_exit);
EXPORT_SYMBOL(serial8250_suspend_port);
EXPORT_SYMBOL(serial8250_resume_port);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au1x00 serial driver\n");
...@@ -103,88 +103,6 @@ ...@@ -103,88 +103,6 @@
#define IVR_SERIAL_PORT_DEFNS #define IVR_SERIAL_PORT_DEFNS
#endif #endif
#ifdef CONFIG_SERIAL_AU1X00
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_SOC_AU1000
#define AU1000_SERIAL_PORT_DEFNS \
{ .baud_base = 0, .port = UART0_ADDR, \
.iomem_base = (unsigned char *)UART0_ADDR, \
.irq = AU1000_UART0_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART1_ADDR, \
.iomem_base = (unsigned char *)UART1_ADDR, \
.irq = AU1000_UART1_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART2_ADDR, \
.iomem_base = (unsigned char *)UART2_ADDR, \
.irq = AU1000_UART2_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART3_ADDR, \
.iomem_base = (unsigned char *)UART3_ADDR, \
.irq = AU1000_UART3_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 },
#endif
#ifdef CONFIG_SOC_AU1500
#define AU1000_SERIAL_PORT_DEFNS \
{ .baud_base = 0, .port = UART0_ADDR, \
.iomem_base = (unsigned char *)UART0_ADDR, \
.irq = AU1500_UART0_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART3_ADDR, \
.iomem_base = (unsigned char *)UART3_ADDR, \
.irq = AU1500_UART3_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 },
#endif
#ifdef CONFIG_SOC_AU1100
#define AU1000_SERIAL_PORT_DEFNS \
{ .baud_base = 0, .port = UART0_ADDR, \
.iomem_base = (unsigned char *)UART0_ADDR, \
.irq = AU1100_UART0_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART1_ADDR, \
.iomem_base = (unsigned char *)UART1_ADDR, \
.irq = AU1100_UART1_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART3_ADDR, \
.iomem_base = (unsigned char *)UART3_ADDR, \
.irq = AU1100_UART3_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 },
#endif
#ifdef CONFIG_SOC_AU1550
#define AU1000_SERIAL_PORT_DEFNS \
{ .baud_base = 0, .port = UART0_ADDR, \
.iomem_base = (unsigned char *)UART0_ADDR, \
.irq = AU1550_UART0_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART1_ADDR, \
.iomem_base = (unsigned char *)UART1_ADDR, \
.irq = AU1550_UART1_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART3_ADDR, \
.iomem_base = (unsigned char *)UART3_ADDR, \
.irq = AU1550_UART3_INT, .flags = STD_COM_FLAGS,\
.iomem_reg_shift = 2 },
#endif
#ifdef CONFIG_SOC_AU1200
#define AU1000_SERIAL_PORT_DEFNS \
{ .baud_base = 0, .port = UART0_ADDR, \
.iomem_base = (unsigned char *)UART0_ADDR, \
.irq = AU1200_UART0_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 }, \
{ .baud_base = 0, .port = UART1_ADDR, \
.iomem_base = (unsigned char *)UART1_ADDR, \
.irq = AU1200_UART1_INT, .flags = STD_COM_FLAGS, \
.iomem_reg_shift = 2 },
#endif
#else
#define AU1000_SERIAL_PORT_DEFNS
#endif
#ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT #ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT
#define STD_SERIAL_PORT_DEFNS \ #define STD_SERIAL_PORT_DEFNS \
/* UART CLK PORT IRQ FLAGS */ \ /* UART CLK PORT IRQ FLAGS */ \
...@@ -331,7 +249,6 @@ ...@@ -331,7 +249,6 @@
MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \ MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS \ MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_SERIAL_PORT_DEFNS \ MOMENCO_OCELOT_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS \ MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS
AU1000_SERIAL_PORT_DEFNS
#endif /* _ASM_SERIAL_H */ #endif /* _ASM_SERIAL_H */
...@@ -158,4 +158,10 @@ ...@@ -158,4 +158,10 @@
#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE) #define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE)
#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS) #define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS)
#ifndef __ASSEMBLY__
struct amba_pl010_data {
void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl);
};
#endif
#endif #endif
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