Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e5470c9 authored by Thor Thayer's avatar Thor Thayer Committed by Greg Kroah-Hartman
Browse files

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: default avatarThor Thayer <tthayer@opensource.altera.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ffea0439
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -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;
		/*
+8 −0
Original line number Diff line number Diff line
@@ -376,5 +376,13 @@
#define UART_EXAR_TXTRG		0x0a	/* Tx FIFO trigger level write-only */
#define UART_EXAR_RXTRG		0x0b	/* Rx FIFO trigger level write-only */

/*
 * These are definitions for the Altera ALTR_16550_F32/F64/F128
 * Normalized from 0x100 to 0x40 because of shift by 2 (32 bit regs).
 */
#define UART_ALTR_AFR		0x40	/* Additional Features Register */
#define UART_ALTR_EN_TXFIFO_LW	0x01	/* Enable the TX FIFO Low Watermark */
#define UART_ALTR_TX_LOW	0x41	/* Tx FIFO Low Watermark */

#endif /* _LINUX_SERIAL_REG_H */