diff options
author | Thor Thayer <tthayer@opensource.altera.com> | 2016-09-22 14:56:16 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-09-27 12:55:50 +0200 |
commit | 8e5470c9839caff94fe334e67ff7e7ace587282a (patch) | |
tree | d96d839061310f9c2e94f7fc24fc906d338f4d01 /drivers/tty | |
parent | ffea043965e4634617485b4d313d6c0099d817f0 (diff) | |
download | linux-8e5470c9839caff94fe334e67ff7e7ace587282a.tar.bz2 |
serial: 8250: Set Altera 16550 TX FIFO Threshold
The Altera 16550 soft IP UART requires 2 additional registers for
TX FIFO threshold support. These 2 registers enable the TX FIFO
Low Watermark and set the TX FIFO Low Watermark.
Set the TX FIFO threshold to the FIFO size - tx_loadsz.
Signed-off-by: Thor Thayer <tthayer@opensource.altera.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 28d29fac1973..1bfb6fdbaa20 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1870,6 +1870,30 @@ static int exar_handle_irq(struct uart_port *port) return ret; } +/* + * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP + * have a programmable TX threshold that triggers the THRE interrupt in + * the IIR register. In this case, the THRE interrupt indicates the FIFO + * has space available. Load it up with tx_loadsz bytes. + */ +static int serial8250_tx_threshold_handle_irq(struct uart_port *port) +{ + unsigned long flags; + unsigned int iir = serial_port_in(port, UART_IIR); + + /* TX Threshold IRQ triggered so load up FIFO */ + if ((iir & UART_IIR_ID) == UART_IIR_THRI) { + struct uart_8250_port *up = up_to_u8250p(port); + + spin_lock_irqsave(&port->lock, flags); + serial8250_tx_chars(up); + spin_unlock_irqrestore(&port->lock, flags); + } + + iir = serial_port_in(port, UART_IIR); + return serial8250_handle_irq(port, iir); +} + static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -2159,6 +2183,25 @@ int serial8250_do_startup(struct uart_port *port) serial_port_out(port, UART_LCR, 0); } + /* + * For the Altera 16550 variants, set TX threshold trigger level. + */ + if (((port->type == PORT_ALTR_16550_F32) || + (port->type == PORT_ALTR_16550_F64) || + (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { + /* Bounds checking of TX threshold (valid 0 to fifosize-2) */ + if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { + pr_err("ttyS%d TX FIFO Threshold errors, skipping\n", + serial_index(port)); + } else { + serial_port_out(port, UART_ALTR_AFR, + UART_ALTR_EN_TXFIFO_LW); + serial_port_out(port, UART_ALTR_TX_LOW, + port->fifosize - up->tx_loadsz); + port->handle_irq = serial8250_tx_threshold_handle_irq; + } + } + if (port->irq) { unsigned char iir1; /* |