diff options
| -rw-r--r-- | drivers/tty/serial/8250/8250_mxpcie.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c index 9f4374d75fcc..e1d607b607e8 100644 --- a/drivers/tty/serial/8250/8250_mxpcie.c +++ b/drivers/tty/serial/8250/8250_mxpcie.c @@ -46,6 +46,23 @@ /* UART */ #define MOXA_PUART_BASE_BAUD 921600 #define MOXA_PUART_OFFSET 0x200 +#define MOXA_PUART_TX_TRIG_DEFAULT 0 +#define MOXA_PUART_RX_TRIG_DEFAULT 96 +#define MOXA_PUART_RX_FLOW_LOW_DEFAULT 16 +#define MOXA_PUART_RX_FLOW_HIGH_DEFAULT 110 + +/* Special Function Register (SFR) */ +#define MOXA_PUART_SFR 0x07 +#define MOXA_PUART_SFR_950 BIT(5) + +/* Enhanced Function Register (EFR) */ +#define MOXA_PUART_EFR 0x0A +#define MOXA_PUART_EFR_ENHANCED BIT(4) + +#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 */ +#define MOXA_PUART_FCH 0x13 /* Flow Control High Trigger Level */ #define MOXA_GPIO_DIRECTION 0x09 #define MOXA_GPIO_OUTPUT 0x0A @@ -131,6 +148,49 @@ static void mxpcie8250_set_interface(struct mxpcie8250 *priv, iowrite8(cval, uir_addr); } +static int mxpcie8250_startup(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + ret = serial8250_do_startup(port); + if (ret) + return ret; + + /* + * The TX FIFO write pointer (w_ptr) and read pointer (r_ptr) + * are driven by different clocks: w_ptr uses the PCIe clock + * and r_ptr uses the UART clock. When TX FIFO flush is requested, + * w_ptr may be cleared before r_ptr, so the UART can still observe + * pending TX data. + * + * It is recommended to clear the FIFOs at least 5 times to ensure + * both pointers are reset. + */ + for (unsigned int i = 0; i < 5; ++i) + serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + + serial_out(up, MOXA_PUART_EFR, MOXA_PUART_EFR_ENHANCED); + serial_out(up, MOXA_PUART_SFR, MOXA_PUART_SFR_950); + + serial_out(up, MOXA_PUART_TTL, MOXA_PUART_TX_TRIG_DEFAULT); + serial_out(up, MOXA_PUART_RTL, MOXA_PUART_RX_TRIG_DEFAULT); + serial_out(up, MOXA_PUART_FCL, MOXA_PUART_RX_FLOW_LOW_DEFAULT); + serial_out(up, MOXA_PUART_FCH, MOXA_PUART_RX_FLOW_HIGH_DEFAULT); + + return 0; +} + +static void mxpcie8250_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial_out(up, MOXA_PUART_EFR, 0); + serial_out(up, MOXA_PUART_SFR, 0); + + serial8250_do_shutdown(port); +} + static void mxpcie8250_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv) { void __iomem *bar2_base = priv->bar2_base; @@ -225,6 +285,9 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id up.port.iobase = 0; up.port.regshift = 0; + up.port.startup = mxpcie8250_startup; + up.port.shutdown = mxpcie8250_shutdown; + for (unsigned int i = 0; i < num_ports; i++) { mxpcie8250_setup_port(pdev, priv, &up, i); |
