summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/serial/8250/8250_mxpcie.c53
1 files changed, 50 insertions, 3 deletions
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 25ca43225e7a..39eee8a9b82d 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -61,8 +61,20 @@
#define MOXA_PUART_EFR_AUTO_RTS BIT(6)
#define MOXA_PUART_EFR_AUTO_CTS BIT(7)
#define MOXA_PUART_EFR_RX_FLOW_MASK GENMASK(1, 0)
+#define MOXA_PUART_EFR_RX_FLOW_DISABLED 0x0
+#define MOXA_PUART_EFR_RX_FLOW_XON2_XOFF2 0x1
+#define MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 0x2
+#define MOXA_PUART_EFR_RX_FLOW_COPY_TX 0x3
#define MOXA_PUART_EFR_TX_FLOW_MASK GENMASK(3, 2)
-
+#define MOXA_PUART_EFR_TX_FLOW_DISABLED 0x0
+#define MOXA_PUART_EFR_TX_FLOW_XON2_XOFF2 0x1
+#define MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 0x2
+#define MOXA_PUART_EFR_TX_FLOW_RESERVED 0x3
+
+#define MOXA_PUART_XON1 0x0B
+#define MOXA_PUART_XON2 0x0C
+#define MOXA_PUART_XOFF1 0x0D
+#define MOXA_PUART_XOFF2 0x0E
#define MOXA_PUART_TTL 0x10 /* Tx Interrupt Trigger Level */
#define MOXA_PUART_RTL 0x11 /* Rx Interrupt Trigger Level */
#define MOXA_PUART_FCL 0x12 /* Flow Control Low Trigger Level */
@@ -159,11 +171,11 @@ static void mxpcie8250_set_termios(struct uart_port *port,
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_struct *tty = port->state->port.tty;
unsigned int cflag = tty->termios.c_cflag;
- u8 efr;
+ u8 efr, val;
serial8250_do_set_termios(port, new, old);
- up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
+ up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS | UPSTAT_AUTOXOFF);
efr = serial_in(up, MOXA_PUART_EFR);
efr &= ~(MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
@@ -172,6 +184,21 @@ static void mxpcie8250_set_termios(struct uart_port *port,
efr |= (MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
}
+ /* Set on-chip software flow control character */
+ serial_out(up, MOXA_PUART_XON1, START_CHAR(tty));
+ serial_out(up, MOXA_PUART_XON2, START_CHAR(tty));
+ serial_out(up, MOXA_PUART_XOFF1, STOP_CHAR(tty));
+ serial_out(up, MOXA_PUART_XOFF2, STOP_CHAR(tty));
+
+ val = I_IXON(tty) ? MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_RX_FLOW_DISABLED;
+ FIELD_MODIFY(MOXA_PUART_EFR_RX_FLOW_MASK, &efr, val);
+
+ val = I_IXOFF(tty) ? MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_TX_FLOW_DISABLED;
+ FIELD_MODIFY(MOXA_PUART_EFR_TX_FLOW_MASK, &efr, val);
+
+ if (I_IXOFF(tty))
+ up->port.status |= UPSTAT_AUTOXOFF;
+
serial_out(up, MOXA_PUART_EFR, efr);
}
@@ -218,6 +245,24 @@ static void mxpcie8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port);
}
+static void mxpcie8250_throttle(struct uart_port *port)
+{
+ guard(uart_port_lock_irqsave)(port);
+
+ port->ops->stop_rx(port);
+}
+
+static void mxpcie8250_unthrottle(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ guard(uart_port_lock_irqsave)(port);
+
+ up->ier |= UART_IER_RLSI | UART_IER_RDI;
+ port->read_status_mask |= UART_LSR_DR;
+ serial_out(up, UART_IER, up->ier);
+}
+
static void mxpcie8250_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv)
{
void __iomem *bar2_base = priv->bar2_base;
@@ -315,6 +360,8 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
up.port.set_termios = mxpcie8250_set_termios;
up.port.startup = mxpcie8250_startup;
up.port.shutdown = mxpcie8250_shutdown;
+ up.port.throttle = mxpcie8250_throttle;
+ up.port.unthrottle = mxpcie8250_unthrottle;
for (unsigned int i = 0; i < num_ports; i++) {
mxpcie8250_setup_port(pdev, priv, &up, i);