*
* Copyright (C) 2001 Russell King.
*
+ * 2005/09/16: Enabled higher baud rates for 16C95x.
+ * (Mathias Adam <a2@adamis.de>)
+ *
* 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
* mapbase is the physical address of the IO port.
* membase is an 'ioremapped' cookie.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
/*
* Configuration:
- * share_irqs - whether we pass SA_SHIRQ to request_irq(). This option
+ * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
* is unsafe when used on edge-triggered interrupts.
*/
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
static unsigned int serial_in(struct uart_8250_port *up, int offset)
{
+ unsigned int tmp;
offset = map_8250_in_reg(up, offset) << up->port.regshift;
switch (up->port.iotype) {
return __raw_readl(up->port.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);
+
default:
return inb(up->port.iobase + offset);
}
__raw_writel(value, up->port.membase + offset);
break;
#endif
+ case UPIO_TSI:
+ if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+ writeb(value, up->port.membase + offset);
+ break;
default:
outb(value, up->port.iobase + offset);
#define serial_inp(up, offset) serial_in(up, offset)
#define serial_outp(up, offset, value) serial_out(up, offset, value)
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_outp(up, UART_DLL, value & 0xff);
+ serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+ if (up->port.iotype == UPIO_AU)
+ return __raw_readl(up->port.membase + 0x28);
+ else
+ return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+ if (up->port.iotype == UPIO_AU)
+ __raw_writel(value, up->port.membase + 0x28);
+ else
+ _serial_dl_write(up, value);
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
/*
* For the 16C950
*/
static int size_fifo(struct uart_8250_port *up)
{
- unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr;
+ unsigned char old_fcr, old_mcr, old_lcr;
+ unsigned short old_dl;
int count;
old_lcr = serial_inp(up, UART_LCR);
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_outp(up, UART_MCR, UART_MCR_LOOP);
serial_outp(up, UART_LCR, UART_LCR_DLAB);
- old_dll = serial_inp(up, UART_DLL);
- old_dlm = serial_inp(up, UART_DLM);
- serial_outp(up, UART_DLL, 0x01);
- serial_outp(up, UART_DLM, 0x00);
+ old_dl = serial_dl_read(up);
+ serial_dl_write(up, 0x0001);
serial_outp(up, UART_LCR, 0x03);
for (count = 0; count < 256; count++)
serial_outp(up, UART_TX, count);
serial_outp(up, UART_FCR, old_fcr);
serial_outp(up, UART_MCR, old_mcr);
serial_outp(up, UART_LCR, UART_LCR_DLAB);
- serial_outp(up, UART_DLL, old_dll);
- serial_outp(up, UART_DLM, old_dlm);
+ serial_dl_write(up, old_dl);
serial_outp(up, UART_LCR, old_lcr);
return count;
serial_outp(up, UART_LCR, 0xE0);
- quot = serial_inp(up, UART_DLM) << 8;
- quot += serial_inp(up, UART_DLL);
+ quot = serial_dl_read(up);
quot <<= 3;
status1 = serial_in(up, 0x04); /* EXCR1 */
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
- serial_outp(up, UART_DLL, quot & 0xff);
- serial_outp(up, UART_DLM, quot >> 8);
+ serial_dl_write(up, quot);
serial_outp(up, UART_LCR, 0);
}
static void
-receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
+receive_chars(struct uart_8250_port *up, int *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch, lsr = *status;
else if (lsr & UART_LSR_FE)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto ignore_char;
uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
{
unsigned int status = serial_in(up, UART_MSR);
- if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+ if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+ up->port.info != NULL) {
if (status & UART_MSR_TERI)
up->port.icount.rng++;
if (status & UART_MSR_DDSR)
* This handles the interrupt from one port.
*/
static inline void
-serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
+serial8250_handle_port(struct uart_8250_port *up)
{
unsigned int status;
DEBUG_INTR("status = %x...", status);
if (status & UART_LSR_DR)
- receive_chars(up, &status, regs);
+ receive_chars(up, &status);
check_modem_status(up);
if (status & UART_LSR_THRE)
transmit_chars(up);
* 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)
+static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
{
struct irq_info *i = dev_id;
struct list_head *l, *end = NULL;
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT)) {
- serial8250_handle_port(up, regs);
+ serial8250_handle_port(up);
handled = 1;
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;
+ int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
spin_lock_irq(&i->lock);
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT))
- serial8250_handle_port(up, NULL);
+ serial8250_handle_port(up);
timeout = up->port.timeout;
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
/*
* Clear the FIFO buffers and disable them.
- * (they will be reeanbled in set_termios())
+ * (they will be reenabled in set_termios())
*/
serial8250_clear_fifos(up);
else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/8))
quot = 0x8002;
+ /*
+ * For 16C950s UART_TCR is used in combination with divisor==1
+ * to achieve baud rates up to baud_base*4.
+ */
+ else if ((port->type == PORT_16C950) &&
+ baud > (port->uartclk/16))
+ quot = 1;
+
else
quot = uart_get_divisor(port, baud);
}
static void
-serial8250_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
- unsigned int baud, quot;
+ unsigned int baud, quot, max_baud;
switch (termios->c_cflag & CSIZE) {
case CS5:
/*
* Ask the core to calculate the divisor for us.
*/
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ max_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16);
+ baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
quot = serial8250_get_divisor(port, baud);
/*
*/
spin_lock_irqsave(&up->port.lock, flags);
+ /*
+ * 16C950 supports additional prescaler ratios between 1:16 and 1:4
+ * thus increasing max baud rate to uartclk/4.
+ */
+ if (up->port.type == PORT_16C950) {
+ if (baud == port->uartclk/4)
+ serial_icr_write(up, UART_TCR, 0x4);
+ else if (baud == port->uartclk/8)
+ serial_icr_write(up, UART_TCR, 0x8);
+ else
+ serial_icr_write(up, UART_TCR, 0);
+ }
+
/*
* Update the per-port timeout.
*/
serial_outp(up, UART_EFR, efr);
}
+#ifdef CONFIG_ARCH_OMAP15XX
+ /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+ if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+ if (baud == 115200) {
+ quot = 1;
+ serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+ } else
+ serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+ }
+#endif
+
if (up->capabilities & UART_NATSEMI) {
/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
serial_outp(up, UART_LCR, 0xe0);
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
}
- serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_dl_write(up, quot);
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
int ret = 0;
switch (up->port.iotype) {
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
+ case UPIO_TSI:
+ case UPIO_MEM32:
case UPIO_MEM:
if (!up->port.mapbase)
break;
unsigned int size = 8 << up->port.regshift;
switch (up->port.iotype) {
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
+ case UPIO_TSI:
+ case UPIO_MEM32:
case UPIO_MEM:
if (!up->port.mapbase)
break;
{
unsigned long start = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
- int ret = 0;
+ int ret = -EINVAL;
switch (up->port.iotype) {
- case UPIO_MEM:
- ret = -EINVAL;
- break;
-
case UPIO_HUB6:
case UPIO_PORT:
start += up->port.iobase;
- if (!request_region(start, size, "serial-rsa"))
+ if (request_region(start, size, "serial-rsa"))
+ ret = 0;
+ else
ret = -EBUSY;
break;
}
unsigned int size = 8 << up->port.regshift;
switch (up->port.iotype) {
- case UPIO_MEM:
- break;
-
case UPIO_HUB6:
case UPIO_PORT:
release_region(up->port.iobase + offset, size);
/* 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))
+ while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
udelay(1);
+ touch_nmi_watchdog();
+ }
}
}
+static void serial8250_console_putchar(struct uart_port *port, int ch)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+ wait_for_xmitr(up, UART_LSR_THRE);
+ serial_out(up, UART_TX, ch);
+}
+
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
serial8250_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_8250_port *up = &serial8250_ports[co->index];
+ unsigned long flags;
unsigned int ier;
- int i;
+ int locked = 1;
touch_nmi_watchdog();
+ local_irq_save(flags);
+ if (up->port.sysrq) {
+ /* serial8250_handle_port() already took the lock */
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&up->port.lock);
+ } else
+ spin_lock(&up->port.lock);
+
/*
* First save the IER then disable the interrupts
*/
else
serial_out(up, UART_IER, 0);
- /*
- * Now, do each character
- */
- for (i = 0; i < count; i++, s++) {
- wait_for_xmitr(up, UART_LSR_THRE);
-
- /*
- * Send the character out.
- * If a LF, also do CR...
- */
- serial_out(up, UART_TX, *s);
- if (*s == 10) {
- wait_for_xmitr(up, UART_LSR_THRE);
- serial_out(up, UART_TX, 13);
- }
- }
+ uart_console_write(&up->port, s, count, serial8250_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(up, BOTH_EMPTY);
- up->ier |= UART_IER_THRI;
- serial_out(up, UART_IER, ier | UART_IER_THRI);
+ serial_out(up, UART_IER, ier);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
}
-static int serial8250_console_setup(struct console *co, char *options)
+static int __init serial8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
static struct uart_driver serial8250_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
/**
* 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.
*/
/**
* 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.
*/