Commit 4d2c5599 authored by David Woodhouse's avatar David Woodhouse

Merge baythorne.infradead.org:/inst/bk/hsserial-2.5

into hera.kernel.org:/home/dwmw2/BK/uart-2.5
parents 0a785252 d836691b
......@@ -237,7 +237,7 @@ serial21285_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned long flags;
unsigned int quot, h_lcr;
unsigned int baud, quot, h_lcr;
/*
* We don't support modem control lines.
......@@ -253,7 +253,8 @@ serial21285_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -286,7 +287,7 @@ serial21285_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
/*
* Which character status flags are we interested in?
......
......@@ -159,7 +159,8 @@ static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }
{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }
};
static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
......@@ -481,6 +482,40 @@ static void autoconfig_16550a(struct uart_8250_port *up)
return;
}
/*
* Check for a National Semiconductor SuperIO chip.
* Attempt to switch to bank 2, read the value of the LOOP bit
* from EXCR1. Switch back to bank 0, change it in MCR. Then
* switch back to bank 2, read it from EXCR1 again and check
* it's changed. If so, set baud_base in EXCR2 to 921600.
*/
serial_outp(up, UART_LCR, 0);
status1 = serial_in(up, UART_MCR);
serial_outp(up, UART_LCR, 0xE0);
status2 = serial_in(up, 0x02); /* EXCR1 */
if (!((status2 ^ status1) & UART_MCR_LOOP)) {
serial_outp(up, UART_LCR, 0);
serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
serial_outp(up, UART_LCR, 0xE0);
status2 = serial_in(up, 0x02); /* EXCR1 */
serial_outp(up, UART_LCR, 0);
serial_outp(up, UART_MCR, status1);
if ((status2 ^ status1) & UART_MCR_LOOP) {
serial_outp(up, UART_LCR, 0xE0);
status1 = serial_in(up, 0x04); /* EXCR1 */
status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
serial_outp(up, UART_LCR, 0);
up->port.type = PORT_NS16550A;
up->port.uartclk = 921600*16;
return;
}
}
/*
* No EFR. Try to detect a TI16750, which only sets bit 5 of
* the IIR when 64 byte FIFO mode is enabled when DLAB is set.
......@@ -1318,6 +1353,26 @@ static void serial8250_shutdown(struct uart_port *port)
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)
......@@ -1325,7 +1380,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int quot;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -1357,7 +1412,8 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = serial8250_get_divisor(port, baud);
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
......@@ -1369,7 +1425,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
quot ++;
if (uart_config[up->port.type].flags & UART_USE_FIFO) {
if ((up->port.uartclk / quot) < (2400 * 16))
if (baud < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
#ifdef CONFIG_SERIAL_8250_RSA
else if (up->port.type == PORT_RSA)
......@@ -1390,7 +1446,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
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)
......@@ -1434,7 +1490,13 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_outp(up, UART_EFR,
termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
}
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
if (uart_config[up->port.type].flags & UART_NATSEMI) {
/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
serial_outp(up, UART_LCR, 0xe0);
} else {
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 */
if (up->port.type == PORT_16750)
......
......@@ -408,12 +408,13 @@ ambauart_set_termios(struct uart_port *port, struct termios *termios,
{
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int quot;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -444,7 +445,7 @@ ambauart_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = AMBA_UARTRSR_OE;
if (termios->c_iflag & INPCK)
......
......@@ -287,7 +287,7 @@ anakin_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned long flags;
unsigned int quot;
unsigned int baud, quot;
/*
* We don't support parity, stop bits, or anything other
......@@ -304,11 +304,12 @@ anakin_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&port->lock, flags);
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
while (!(anakin_in(port, 0x10) & TXEMPTY))
barrier();
......
......@@ -320,7 +320,7 @@ static void
clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int ubrlcr, quot;
unsigned int ubrlcr, baud, quot;
unsigned long flags;
/*
......@@ -331,7 +331,8 @@ clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
......@@ -362,7 +363,7 @@ clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UARTDR_OVERR;
if (termios->c_iflag & INPCK)
......
......@@ -271,7 +271,7 @@ static void uart_shutdown(struct uart_info *info)
*/
void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int quot)
unsigned int baud)
{
unsigned int bits;
......@@ -305,7 +305,7 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag,
* Figure the timeout to send the above number of bits.
* Add .02 seconds of slop
*/
port->timeout = (HZ * bits) / (port->uartclk / (16 * quot)) + HZ/50;
port->timeout = (HZ * bits) / baud + HZ/50;
}
EXPORT_SYMBOL(uart_update_timeout);
......@@ -321,6 +321,12 @@ EXPORT_SYMBOL(uart_update_timeout);
* Decode the termios structure into a numeric baud rate,
* taking account of the magic 38400 baud rate (with spd_*
* flags), and mapping the %B0 rate to 9600 baud.
*
* If the new baud rate is invalid, try the old termios setting.
* If it's still invalid, we try 9600 baud.
*
* Update the @termios structure to reflect the baud rate
* we're actually going to be using.
*/
unsigned int
uart_get_baud_rate(struct uart_port *port, struct termios *termios,
......@@ -383,26 +389,14 @@ EXPORT_SYMBOL(uart_get_baud_rate);
/**
* uart_get_divisor - return uart clock divisor
* @port: uart_port structure describing the port.
* @termios: desired termios settings
* @old_termios: the original port settings, or NULL
*
* Calculate the uart clock divisor for the port. If the
* divisor is invalid, try the old termios setting. If
* the divisor is still invalid, we try 9600 baud.
* @baud: desired baud rate
*
* Update the @termios structure to reflect the baud rate
* we're actually going to be using.
*
* If 9600 baud fails, we return a zero divisor.
* Calculate the uart clock divisor for the port.
*/
unsigned int
uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios)
uart_get_divisor(struct uart_port *port, unsigned int baud)
{
unsigned int quot, baud, max = port->uartclk / 16;
/* Determine divisor based on baud rate */
baud = uart_get_baud_rate(port, termios, old_termios, 0, max);
unsigned int quot;
/*
* Old custom speed handling.
......@@ -832,8 +826,17 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
goto exit;
if (info->flags & UIF_INITIALIZED) {
if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
old_custom_divisor != port->custom_divisor)
old_custom_divisor != port->custom_divisor) {
/* If they're setting up a custom divisor or speed,
* instead of clearing it, then bitch about it. No
* need to rate-limit; it's CAP_SYS_ADMIN only. */
if (port->flags & UPF_SPD_MASK) {
printk(KERN_NOTICE "%s sets custom speed on %s%d. This is deprecated.\n",
current->comm, info->tty->driver.name,
info->port->line);
}
uart_change_speed(info, NULL);
}
} else
retval = uart_startup(info, 1);
exit:
......
......@@ -441,7 +441,7 @@ sa1100_set_termios(struct uart_port *port, struct termios *termios,
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
unsigned int utcr0, old_utcr3, quot;
unsigned int utcr0, old_utcr3, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
/*
......@@ -470,7 +470,8 @@ sa1100_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&sport->port.lock, flags);
......@@ -507,7 +508,7 @@ sa1100_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
/*
* disable interrupts and drain transmitter
......
......@@ -853,7 +853,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, cflag, quot);
uart_update_timeout(port, cflag, (port->uartclk / (16 * quot)));
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (iflag & INPCK)
......@@ -920,12 +920,13 @@ static void
sunsu_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int quot;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot);
}
......
......@@ -317,7 +317,7 @@ static void
uart00_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int uart_mc, old_ies, quot;
unsigned int uart_mc, old_ies, baud, quot;
unsigned long flags;
/*
......@@ -328,7 +328,8 @@ uart00_set_termios(struct uart_port *port, struct termios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
quot = uart_get_divisor(port, termios, old);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
/* byte size and parity */
switch (termios->c_cflag & CSIZE) {
......@@ -358,7 +359,7 @@ uart00_set_termios(struct uart_port *port, struct termios *termios,
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UART_RDS_OE_MSK;
if (termios->c_iflag & INPCK)
......
......@@ -91,6 +91,7 @@ struct serial_uart_config {
#define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02
#define UART_STARTECH 0x04
#define UART_NATSEMI 0x08
/*
* Definitions for async_struct (and serial_struct) flags field
......
......@@ -37,7 +37,8 @@
#define PORT_16654 11
#define PORT_16850 12
#define PORT_RSA 13
#define PORT_MAX_8250 13 /* max port ID */
#define PORT_NS16550A 14
#define PORT_MAX_8250 14 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
......@@ -172,6 +173,7 @@ struct uart_port {
#define UPF_LOW_LATENCY (1 << 13)
#define UPF_BUGGY_UART (1 << 14)
#define UPF_AUTOPROBE (1 << 15)
#define UPF_MAGIC_MULTIPLIER (1 << 16)
#define UPF_BOOT_ONLYMCA (1 << 22)
#define UPF_CONS_FLOW (1 << 23)
#define UPF_SHARE_IRQ (1 << 24)
......@@ -179,7 +181,7 @@ struct uart_port {
#define UPF_RESOURCES (1 << 30)
#define UPF_IOREMAP (1 << 31)
#define UPF_CHANGE_MASK (0x7fff)
#define UPF_CHANGE_MASK (0x17fff)
#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY)
unsigned int mctrl; /* current modem ctrl settings */
......@@ -279,12 +281,11 @@ void uart_write_wakeup(struct uart_port *port);
* Baud rate helpers.
*/
void uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int quot);
unsigned int baud);
unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios,
struct termios *old, unsigned int min,
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, struct termios *termios,
struct termios *old_termios);
unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
/*
* Console helpers.
......
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