diff options
Diffstat (limited to 'drivers/tty/serial')
162 files changed, 32352 insertions, 23472 deletions
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 718e010fcb04..4de0c975ebdc 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -50,25 +50,25 @@ static const char serial21285_name[] = "Footbridge UART"; static bool is_enabled(struct uart_port *port, int bit) { - unsigned long private_data = (unsigned long)port->private_data; + unsigned long *private_data = (unsigned long *)&port->private_data; - if (test_bit(bit, &private_data)) + if (test_bit(bit, private_data)) return true; return false; } static void enable(struct uart_port *port, int bit) { - unsigned long private_data = (unsigned long)port->private_data; + unsigned long *private_data = (unsigned long *)&port->private_data; - set_bit(bit, &private_data); + set_bit(bit, private_data); } static void disable(struct uart_port *port, int bit) { - unsigned long private_data = (unsigned long)port->private_data; + unsigned long *private_data = (unsigned long *)&port->private_data; - clear_bit(bit, &private_data); + clear_bit(bit, private_data); } #define is_tx_enabled(port) is_enabled(port, tx_enabled_bit) @@ -117,7 +117,8 @@ static void serial21285_stop_rx(struct uart_port *port) static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - unsigned int status, ch, flag, rxs, max_count = 256; + unsigned int status, rxs, max_count = 256; + u8 ch, flag; status = *CSR_UARTFLG; while (!(status & 0x10) && max_count--) { @@ -154,35 +155,13 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) static irqreturn_t serial21285_tx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; - int count = 256; - - if (port->x_char) { - *CSR_UARTDR = port->x_char; - port->icount.tx++; - port->x_char = 0; - goto out; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - serial21285_stop_tx(port); - goto out; - } - - do { - *CSR_UARTDR = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + u8 ch; - if (uart_circ_empty(xmit)) - serial21285_stop_tx(port); + uart_port_tx_limited(port, ch, 256, + !(*CSR_UARTFLG & 0x20), + *CSR_UARTDR = ch, + ({})); - out: return IRQ_HANDLED; } @@ -206,14 +185,14 @@ static void serial21285_break_ctl(struct uart_port *port, int break_state) unsigned long flags; unsigned int h_lcr; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); h_lcr = *CSR_H_UBRLCR; if (break_state) h_lcr |= H_UBRLCR_BREAK; else h_lcr &= ~H_UBRLCR_BREAK; *CSR_H_UBRLCR = h_lcr; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int serial21285_startup(struct uart_port *port) @@ -243,7 +222,7 @@ static void serial21285_shutdown(struct uart_port *port) static void serial21285_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, quot, h_lcr, b; @@ -293,7 +272,7 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, if (port->fifosize) h_lcr |= H_UBRLCR_FIFO; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* * Update the per-port timeout. @@ -330,7 +309,7 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, *CSR_H_UBRLCR = h_lcr; *CSR_UARTCON = 1; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *serial21285_type(struct uart_port *port) @@ -403,7 +382,7 @@ static void serial21285_setup_ports(void) } #ifdef CONFIG_SERIAL_21285_CONSOLE -static void serial21285_console_putchar(struct uart_port *port, int ch) +static void serial21285_console_putchar(struct uart_port *port, unsigned char ch) { while (*CSR_UARTFLG & 0x20) barrier(); @@ -461,9 +440,6 @@ static int __init serial21285_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if (machine_is_personal_server()) - baud = 57600; - /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 52bb21205bb6..8caecfc85d93 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -7,8 +7,9 @@ * Copyright (C) 2001 Russell King. */ +#include <linux/bits.h> #include <linux/serial_8250.h> -#include <linux/serial_reg.h> +#include <linux/serial_core.h> #include <linux/dmaengine.h> #include "../serial_mctrl_gpio.h" @@ -16,6 +17,8 @@ struct uart_8250_dma { int (*tx_dma)(struct uart_8250_port *p); int (*rx_dma)(struct uart_8250_port *p); + void (*prepare_tx_dma)(struct uart_8250_port *p); + void (*prepare_rx_dma)(struct uart_8250_port *p); /* Filter function */ dma_filter_fn fn; @@ -70,31 +73,30 @@ struct serial8250_config { unsigned int flags; }; -#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */ -#define UART_CAP_EFR (1 << 9) /* UART has EFR */ -#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */ -#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */ -#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ -#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */ -#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */ -#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */ -#define UART_CAP_IRDA (1 << 16) /* UART supports IrDA line discipline */ -#define UART_CAP_MINI (1 << 17) /* Mini UART on BCM283X family lacks: +#define UART_CAP_FIFO BIT(8) /* UART has FIFO */ +#define UART_CAP_EFR BIT(9) /* UART has EFR */ +#define UART_CAP_SLEEP BIT(10) /* UART has IER sleep */ +#define UART_CAP_AFE BIT(11) /* MCR-based hw flow control */ +#define UART_CAP_UUE BIT(12) /* UART needs IER bit 6 set (Xscale) */ +#define UART_CAP_RTOIE BIT(13) /* UART needs IER bit 4 set (Xscale, Tegra) */ +#define UART_CAP_HFIFO BIT(14) /* UART has a "hidden" FIFO */ +#define UART_CAP_RPM BIT(15) /* Runtime PM is active while idle */ +#define UART_CAP_IRDA BIT(16) /* UART supports IrDA line discipline */ +#define UART_CAP_MINI BIT(17) /* Mini UART on BCM283X family lacks: * STOP PARITY EPAR SPAR WLEN5 WLEN6 */ +#define UART_CAP_NOTEMT BIT(18) /* UART without interrupt on TEMT available */ -#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ -#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ -#define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ -#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ -#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ +#define UART_BUG_QUOT BIT(0) /* UART has buggy quot LSB */ +#define UART_BUG_TXEN BIT(1) /* UART has buggy TX IIR status */ +#define UART_BUG_NOMSR BIT(2) /* UART has buggy MSR status bits (Au1x00) */ +#define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */ +#define UART_BUG_TXRACE BIT(5) /* UART Tx fails to set remote DR */ +/* Module parameters */ +#define UART_NR CONFIG_SERIAL_8250_NR_UARTS -#ifdef CONFIG_SERIAL_8250_SHARE_IRQ -#define SERIAL8250_SHARE_IRQS 1 -#else -#define SERIAL8250_SHARE_IRQS 0 -#endif +extern unsigned int nr_uarts; #define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \ { \ @@ -107,6 +109,19 @@ struct serial8250_config { #define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0) +extern struct uart_driver serial8250_reg; +void serial8250_register_ports(struct uart_driver *drv, struct device *dev); + +/* Legacy ISA bus related APIs */ +typedef void (*serial8250_isa_config_fn)(int, struct uart_port *, u32 *); +extern serial8250_isa_config_fn serial8250_isa_config; + +void serial8250_isa_init_ports(void); + +extern struct platform_device *serial8250_isa_devs; + +extern const struct uart_ops *univ8250_port_base_ops; +extern struct uart_ops univ8250_port_ops; static inline int serial_in(struct uart_8250_port *up, int offset) { @@ -118,20 +133,70 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +/** + * serial_lsr_in - Read LSR register and preserve flags across reads + * @up: uart 8250 port + * + * Read LSR register and handle saving non-preserved flags across reads. + * The flags that are not preserved across reads are stored into + * up->lsr_saved_flags. + * + * Returns LSR value or'ed with the preserved flags (if any). + */ +static inline u16 serial_lsr_in(struct uart_8250_port *up) +{ + u16 lsr = up->lsr_saved_flags; + + lsr |= serial_in(up, UART_LSR); + up->lsr_saved_flags = lsr & up->lsr_save_mask; + + return lsr; +} + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up, + int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} + void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); -static inline int serial_dl_read(struct uart_8250_port *up) +void serial8250_rpm_get(struct uart_8250_port *p); +void serial8250_rpm_put(struct uart_8250_port *p); +DEFINE_GUARD(serial8250_rpm, struct uart_8250_port *, + serial8250_rpm_get(_T), serial8250_rpm_put(_T)); + +static inline u32 serial_dl_read(struct uart_8250_port *up) { return up->dl_read(up); } -static inline void serial_dl_write(struct uart_8250_port *up, int value) +static inline void serial_dl_write(struct uart_8250_port *up, u32 value) { up->dl_write(up, value); } static inline bool serial8250_set_THRI(struct uart_8250_port *up) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + if (up->ier & UART_IER_THRI) return false; up->ier |= UART_IER_THRI; @@ -141,6 +206,9 @@ static inline bool serial8250_set_THRI(struct uart_8250_port *up) static inline bool serial8250_clear_THRI(struct uart_8250_port *up) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + if (!(up->ier & UART_IER_THRI)) return false; up->ier &= ~UART_IER_THRI; @@ -148,18 +216,15 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up) return true; } +struct uart_8250_port *serial8250_setup_port(int index); struct uart_8250_port *serial8250_get_port(int line); -void serial8250_rpm_get(struct uart_8250_port *p); -void serial8250_rpm_put(struct uart_8250_port *p); - -void serial8250_rpm_get_tx(struct uart_8250_port *p); -void serial8250_rpm_put_tx(struct uart_8250_port *p); - -int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485); -void serial8250_em485_start_tx(struct uart_8250_port *p); -void serial8250_em485_stop_tx(struct uart_8250_port *p); +int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485); +void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier); +void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier); void serial8250_em485_destroy(struct uart_8250_port *p); +extern struct serial_rs485 serial8250_em485_supported; /* MCR <-> TIOCM conversion */ static inline int serial8250_TIOCM_to_MCR(int tiocm) @@ -239,17 +304,6 @@ static inline int serial8250_in_MCR(struct uart_8250_port *up) return mctrl; } -#if defined(__alpha__) && !defined(CONFIG_PCI) -/* - * Digital did something really horribly wrong with the OUT1 and OUT2 - * lines on at least some ALPHA's. The failure mode is that if either - * is cleared, the machine locks up with endless interrupts. - */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) -#else -#define ALPHA_KLUDGE_MCR 0 -#endif - #ifdef CONFIG_SERIAL_8250_PNP int serial8250_pnp_init(void); void serial8250_pnp_exit(void); @@ -258,6 +312,20 @@ static inline int serial8250_pnp_init(void) { return 0; } static inline void serial8250_pnp_exit(void) { } #endif +#ifdef CONFIG_SERIAL_8250_RSA +void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops); +void rsa_enable(struct uart_8250_port *up); +void rsa_disable(struct uart_8250_port *up); +void rsa_autoconfig(struct uart_8250_port *up); +void rsa_reset(struct uart_8250_port *up); +#else +static inline void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops) { } +static inline void rsa_enable(struct uart_8250_port *up) {} +static inline void rsa_disable(struct uart_8250_port *up) {} +static inline void rsa_autoconfig(struct uart_8250_port *up) {} +static inline void rsa_reset(struct uart_8250_port *up) {} +#endif + #ifdef CONFIG_SERIAL_8250_FINTEK int fintek_8250_probe(struct uart_8250_port *uart); #else @@ -265,6 +333,7 @@ static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; } #endif #ifdef CONFIG_ARCH_OMAP1 +#include <linux/soc/ti/omap1-soc.h> static inline int is_omap1_8250(struct uart_8250_port *pt) { int res; @@ -303,15 +372,40 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt) #ifdef CONFIG_SERIAL_8250_DMA extern int serial8250_tx_dma(struct uart_8250_port *); +extern void serial8250_tx_dma_flush(struct uart_8250_port *); extern int serial8250_rx_dma(struct uart_8250_port *); extern void serial8250_rx_dma_flush(struct uart_8250_port *); extern int serial8250_request_dma(struct uart_8250_port *); extern void serial8250_release_dma(struct uart_8250_port *); + +static inline void serial8250_do_prepare_tx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (dma->prepare_tx_dma) + dma->prepare_tx_dma(p); +} + +static inline void serial8250_do_prepare_rx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (dma->prepare_rx_dma) + dma->prepare_rx_dma(p); +} + +static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + return dma && dma->tx_running; +} #else static inline int serial8250_tx_dma(struct uart_8250_port *p) { return -1; } +static inline void serial8250_tx_dma_flush(struct uart_8250_port *p) { } static inline int serial8250_rx_dma(struct uart_8250_port *p) { return -1; @@ -322,6 +416,11 @@ static inline int serial8250_request_dma(struct uart_8250_port *p) return -1; } static inline void serial8250_release_dma(struct uart_8250_port *p) { } + +static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) +{ + return false; +} #endif static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index c33e02cbde93..26fc0464f1cc 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -28,10 +28,12 @@ #define ASPEED_VUART_ADDRL 0x28 #define ASPEED_VUART_ADDRH 0x2c +#define ASPEED_VUART_DEFAULT_LPC_ADDR 0x3f8 +#define ASPEED_VUART_DEFAULT_SIRQ 4 +#define ASPEED_VUART_DEFAULT_SIRQ_POLARITY IRQ_TYPE_LEVEL_LOW + struct aspeed_vuart { struct device *dev; - void __iomem *regs; - struct clk *clk; int line; struct timer_list unthrottle_timer; struct uart_8250_port *port; @@ -60,16 +62,37 @@ static const int unthrottle_timeout = HZ/10; * different system (though most of them use 3f8/4). */ +static inline u8 aspeed_vuart_readb(struct aspeed_vuart *vuart, u8 reg) +{ + return readb(vuart->port->port.membase + reg); +} + +static inline void aspeed_vuart_writeb(struct aspeed_vuart *vuart, u8 val, u8 reg) +{ + writeb(val, vuart->port->port.membase + reg); +} + static ssize_t lpc_address_show(struct device *dev, struct device_attribute *attr, char *buf) { struct aspeed_vuart *vuart = dev_get_drvdata(dev); u16 addr; - addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) | - (readb(vuart->regs + ASPEED_VUART_ADDRL)); + addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) | + (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL)); + + return sysfs_emit(buf, "0x%x\n", addr); +} + +static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr) +{ + if (addr > U16_MAX) + return -EINVAL; + + aspeed_vuart_writeb(vuart, addr >> 8, ASPEED_VUART_ADDRH); + aspeed_vuart_writeb(vuart, addr >> 0, ASPEED_VUART_ADDRL); - return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr); + return 0; } static ssize_t lpc_address_store(struct device *dev, @@ -77,17 +100,15 @@ static ssize_t lpc_address_store(struct device *dev, const char *buf, size_t count) { struct aspeed_vuart *vuart = dev_get_drvdata(dev); - unsigned long val; + u32 val; int err; - err = kstrtoul(buf, 0, &val); + err = kstrtou32(buf, 0, &val); if (err) return err; - writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH); - writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL); - - return count; + err = aspeed_vuart_set_lpc_address(vuart, val); + return err ? : count; } static DEVICE_ATTR_RW(lpc_address); @@ -98,11 +119,29 @@ static ssize_t sirq_show(struct device *dev, struct aspeed_vuart *vuart = dev_get_drvdata(dev); u8 reg; - reg = readb(vuart->regs + ASPEED_VUART_GCRB); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB); reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; - return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg); + return sysfs_emit(buf, "%u\n", reg); +} + +static int aspeed_vuart_set_sirq(struct aspeed_vuart *vuart, u32 sirq) +{ + u8 reg; + + if (sirq > (ASPEED_VUART_GCRB_HOST_SIRQ_MASK >> ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT)) + return -EINVAL; + + sirq <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; + sirq &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; + + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB); + reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK; + reg |= sirq; + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRB); + + return 0; } static ssize_t sirq_store(struct device *dev, struct device_attribute *attr, @@ -111,21 +150,13 @@ static ssize_t sirq_store(struct device *dev, struct device_attribute *attr, struct aspeed_vuart *vuart = dev_get_drvdata(dev); unsigned long val; int err; - u8 reg; err = kstrtoul(buf, 0, &val); if (err) return err; - val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; - val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; - - reg = readb(vuart->regs + ASPEED_VUART_GCRB); - reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK; - reg |= val; - writeb(reg, vuart->regs + ASPEED_VUART_GCRB); - - return count; + err = aspeed_vuart_set_sirq(vuart, val); + return err ? : count; } static DEVICE_ATTR_RW(sirq); @@ -136,23 +167,23 @@ static ssize_t sirq_polarity_show(struct device *dev, struct aspeed_vuart *vuart = dev_get_drvdata(dev); u8 reg; - reg = readb(vuart->regs + ASPEED_VUART_GCRA); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; - return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0); + return sysfs_emit(buf, "%u\n", reg ? 1 : 0); } static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart, bool polarity) { - u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA); + u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); if (polarity) reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; else reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; - writeb(reg, vuart->regs + ASPEED_VUART_GCRA); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA); } static ssize_t sirq_polarity_store(struct device *dev, @@ -187,14 +218,14 @@ static const struct attribute_group aspeed_vuart_attr_group = { static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled) { - u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA); + u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); if (enabled) reg |= ASPEED_VUART_GCRA_VUART_EN; else reg &= ~ASPEED_VUART_GCRA_VUART_EN; - writeb(reg, vuart->regs + ASPEED_VUART_GCRA); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA); } static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart, @@ -202,7 +233,7 @@ static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart, { u8 reg; - reg = readb(vuart->regs + ASPEED_VUART_GCRA); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); /* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */ if (!discard) @@ -210,7 +241,7 @@ static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart, else reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD; - writeb(reg, vuart->regs + ASPEED_VUART_GCRA); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA); } static int aspeed_vuart_startup(struct uart_port *uart_port) @@ -243,6 +274,9 @@ static void __aspeed_vuart_set_throttle(struct uart_8250_port *up, { unsigned char irqs = UART_IER_RLSI | UART_IER_RDI; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + up->ier &= ~irqs; if (!throttle) up->ier |= irqs; @@ -253,9 +287,9 @@ static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle) struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); __aspeed_vuart_set_throttle(up, throttle); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void aspeed_vuart_throttle(struct uart_port *port) @@ -270,7 +304,8 @@ static void aspeed_vuart_unthrottle(struct uart_port *port) static void aspeed_vuart_unthrottle_exp(struct timer_list *timer) { - struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer); + struct aspeed_vuart *vuart = timer_container_of(vuart, timer, + unthrottle_timer); struct uart_8250_port *up = vuart->port; if (!tty_buffer_space_avail(&up->port.state->port)) { @@ -298,14 +333,14 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir, lsr; unsigned long flags; - int space, count; + unsigned int space, count; iir = serial_port_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) return 0; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); lsr = serial_port_in(port, UART_LSR); @@ -317,14 +352,12 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) struct aspeed_vuart *vuart = port->private_data; __aspeed_vuart_set_throttle(up, true); - if (!timer_pending(&vuart->unthrottle_timer)) { - vuart->port = up; + if (!timer_pending(&vuart->unthrottle_timer)) mod_timer(&vuart->unthrottle_timer, jiffies + unthrottle_timeout); - } } else { - count = min(space, 256); + count = min(space, 256U); do { serial8250_read_char(up, lsr); @@ -341,7 +374,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); - uart_unlock_and_check_sysrq(port, flags); + uart_unlock_and_check_sysrq_irqrestore(port, flags); return 1; } @@ -367,15 +400,29 @@ static void aspeed_vuart_auto_configure_sirq_polarity( aspeed_vuart_set_sirq_polarity(vuart, (value & reg_mask) == 0); } +static int aspeed_vuart_map_irq_polarity(u32 dt) +{ + switch (dt) { + case IRQ_TYPE_LEVEL_LOW: + return 0; + case IRQ_TYPE_LEVEL_HIGH: + return 1; + default: + return -EINVAL; + } +} + static int aspeed_vuart_probe(struct platform_device *pdev) { struct of_phandle_args sirq_polarity_sense_args; + struct device *dev = &pdev->dev; struct uart_8250_port port; struct aspeed_vuart *vuart; struct device_node *np; struct resource *res; - u32 clk, prop; - int rc; + int rc, sirq_polarity; + u32 prop, sirq[2]; + struct clk *vclk; np = pdev->dev.of_node; @@ -387,13 +434,11 @@ static int aspeed_vuart_probe(struct platform_device *pdev) timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vuart->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(vuart->regs)) - return PTR_ERR(vuart->regs); + if (!res) + return -EINVAL; memset(&port, 0, sizeof(port)); port.port.private_data = vuart; - port.port.membase = vuart->regs; port.port.mapbase = res->start; port.port.mapsize = resource_size(res); port.port.startup = aspeed_vuart_startup; @@ -403,58 +448,35 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.status = UPSTAT_SYNC_FIFO; port.port.dev = &pdev->dev; port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); + port.port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE | + UPF_NO_THRE_TEST; + port.bugs |= UART_BUG_TXRACE; rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); if (rc < 0) return rc; - if (of_property_read_u32(np, "clock-frequency", &clk)) { - vuart->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(vuart->clk)) { - dev_warn(&pdev->dev, - "clk or clock-frequency not defined\n"); - rc = PTR_ERR(vuart->clk); - goto err_sysfs_remove; - } + rc = uart_read_port_properties(&port.port); + if (rc) + goto err_sysfs_remove; - rc = clk_prepare_enable(vuart->clk); - if (rc < 0) + /* Get clk rate through clk driver if present */ + if (!port.port.uartclk) { + vclk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(vclk)) { + rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n"); goto err_sysfs_remove; + } - clk = clk_get_rate(vuart->clk); + port.port.uartclk = clk_get_rate(vclk); } /* If current-speed was set, then try not to change it. */ if (of_property_read_u32(np, "current-speed", &prop) == 0) - port.port.custom_divisor = clk / (16 * prop); - - /* Check for shifted address mapping */ - if (of_property_read_u32(np, "reg-offset", &prop) == 0) - port.port.mapbase += prop; + port.port.custom_divisor = port.port.uartclk / (16 * prop); - /* Check for registers offset within the devices address range */ - if (of_property_read_u32(np, "reg-shift", &prop) == 0) - port.port.regshift = prop; - - /* Check for fifo size */ - if (of_property_read_u32(np, "fifo-size", &prop) == 0) - port.port.fifosize = prop; - - /* Check for a fixed line number */ - rc = of_alias_get_id(np, "serial"); - if (rc >= 0) - port.port.line = rc; - - port.port.irq = irq_of_parse_and_map(np, 0); port.port.handle_irq = aspeed_vuart_handle_irq; - port.port.iotype = UPIO_MEM; - port.port.type = PORT_16550A; - port.port.uartclk = clk; - port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF - | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST; - - if (of_property_read_bool(np, "no-loopback-test")) - port.port.flags |= UPF_SKIP_TEST; + port.port.type = PORT_ASPEED_VUART; if (port.port.fifosize) port.capabilities = UART_CAP_FIFO; @@ -464,9 +486,10 @@ static int aspeed_vuart_probe(struct platform_device *pdev) rc = serial8250_register_8250_port(&port); if (rc < 0) - goto err_clk_disable; + goto err_sysfs_remove; vuart->line = rc; + vuart->port = serial8250_get_port(vuart->line); rc = of_parse_phandle_with_fixed_args( np, "aspeed,sirq-polarity-sense", 2, 0, @@ -482,31 +505,56 @@ static int aspeed_vuart_probe(struct platform_device *pdev) of_node_put(sirq_polarity_sense_args.np); } + rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &prop); + if (rc < 0) + prop = ASPEED_VUART_DEFAULT_LPC_ADDR; + + rc = aspeed_vuart_set_lpc_address(vuart, prop); + if (rc < 0) { + dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n"); + goto err_sysfs_remove; + } + + rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2); + if (rc < 0) { + sirq[0] = ASPEED_VUART_DEFAULT_SIRQ; + sirq[1] = ASPEED_VUART_DEFAULT_SIRQ_POLARITY; + } + + rc = aspeed_vuart_set_sirq(vuart, sirq[0]); + if (rc < 0) { + dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n"); + goto err_sysfs_remove; + } + + sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]); + if (sirq_polarity < 0) { + rc = dev_err_probe(dev, sirq_polarity, + "invalid sirq polarity in aspeed,lpc-interrupts property\n"); + goto err_sysfs_remove; + } + + aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity); + aspeed_vuart_set_enabled(vuart, true); aspeed_vuart_set_host_tx_discard(vuart, true); platform_set_drvdata(pdev, vuart); return 0; -err_clk_disable: - clk_disable_unprepare(vuart->clk); - irq_dispose_mapping(port.port.irq); err_sysfs_remove: sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); return rc; } -static int aspeed_vuart_remove(struct platform_device *pdev) +static void aspeed_vuart_remove(struct platform_device *pdev) { struct aspeed_vuart *vuart = platform_get_drvdata(pdev); - del_timer_sync(&vuart->unthrottle_timer); + timer_delete_sync(&vuart->unthrottle_timer); aspeed_vuart_set_enabled(vuart, false); serial8250_unregister_port(vuart->line); sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); - clk_disable_unprepare(vuart->clk); - - return 0; } static const struct of_device_id aspeed_vuart_table[] = { @@ -514,6 +562,7 @@ static const struct of_device_id aspeed_vuart_table[] = { { .compatible = "aspeed,ast2500-vuart" }, { }, }; +MODULE_DEVICE_TABLE(of, aspeed_vuart_table); static struct platform_driver aspeed_vuart_driver = { .driver = { diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index 12d03e678295..0609582a62f7 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -13,10 +13,12 @@ */ #include <linux/clk.h> +#include <linux/console.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> #include "8250.h" @@ -44,7 +46,7 @@ struct bcm2835aux_data { u32 cntl; }; -static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) +static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier) { if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev); @@ -63,7 +65,7 @@ static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) serial8250_out_MCR(up, UART_MCR_RTS); } -static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) +static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up, bool toggle_ier) { if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) serial8250_out_MCR(up, 0); @@ -80,9 +82,11 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) static int bcm2835aux_serial_probe(struct platform_device *pdev) { + const struct software_node *bcm2835_swnode; struct uart_8250_port up = { }; struct bcm2835aux_data *data; struct resource *res; + unsigned int uartclk; int ret; /* allocate the custom structure */ @@ -93,13 +97,10 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) /* initialize data */ up.capabilities = UART_CAP_FIFO | UART_CAP_MINI; up.port.dev = &pdev->dev; - up.port.regshift = 2; up.port.type = PORT_16550; - up.port.iotype = UPIO_MEM; - up.port.fifosize = 8; - up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | - UPF_SKIP_TEST | UPF_IOREMAP; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP; up.port.rs485_config = serial8250_em485_config; + up.port.rs485_supported = serial8250_em485_supported; up.rs485_start_tx = bcm2835aux_rs485_start_tx; up.rs485_stop_tx = bcm2835aux_rs485_stop_tx; @@ -109,19 +110,9 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); /* get the clock - this also enables the HW */ - data->clk = devm_clk_get(&pdev->dev, NULL); - ret = PTR_ERR_OR_ZERO(data->clk); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "could not get clk: %d\n", ret); - return ret; - } - - /* get the interrupt */ - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - up.port.irq = ret; + data->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(data->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); /* map the main registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -129,35 +120,46 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) dev_err(&pdev->dev, "memory resource not found"); return -EINVAL; } + up.port.mapbase = res->start; up.port.mapsize = resource_size(res); - /* Check for a fixed line number */ - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - up.port.line = ret; + bcm2835_swnode = device_get_match_data(&pdev->dev); + if (bcm2835_swnode) { + ret = device_add_software_node(&pdev->dev, bcm2835_swnode); + if (ret) + return ret; + } + + ret = uart_read_port_properties(&up.port); + if (ret) + goto rm_swnode; + + up.port.regshift = 2; + up.port.fifosize = 8; /* enable the clock as a last step */ ret = clk_prepare_enable(data->clk); if (ret) { - dev_err(&pdev->dev, "unable to enable uart clock - %d\n", - ret); - return ret; + dev_err_probe(&pdev->dev, ret, "unable to enable uart clock\n"); + goto rm_swnode; } + uartclk = clk_get_rate(data->clk); + if (uartclk) + up.port.uartclk = uartclk; + /* the HW-clock divider for bcm2835aux is 8, * but 8250 expects a divider of 16, * so we have to multiply the actual clock by 2 * to get identical baudrates. */ - up.port.uartclk = clk_get_rate(data->clk) * 2; + up.port.uartclk *= 2; /* register the port */ ret = serial8250_register_8250_port(&up); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "unable to register 8250 port - %d\n", ret); + dev_err_probe(&pdev->dev, ret, "unable to register 8250 port\n"); goto dis_clk; } data->line = ret; @@ -166,29 +168,103 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) dis_clk: clk_disable_unprepare(data->clk); +rm_swnode: + device_remove_software_node(&pdev->dev); return ret; } -static int bcm2835aux_serial_remove(struct platform_device *pdev) +static void bcm2835aux_serial_remove(struct platform_device *pdev) { struct bcm2835aux_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk); - - return 0; + device_remove_software_node(&pdev->dev); } +/* + * Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi) + * describe the miniuart with a base address that encompasses the auxiliary + * registers shared between the miniuart and spi. + * + * This is due to historical reasons, see discussion here: + * https://edk2.groups.io/g/devel/topic/87501357#84349 + * + * We need to add the offset between the miniuart and auxiliary registers + * to get the real miniuart base address. + */ +static const struct property_entry bcm2835_acpi_properties[] = { + PROPERTY_ENTRY_U32("reg-offset", 0x40), + { } +}; + +static const struct software_node bcm2835_acpi_node = { + .properties = bcm2835_acpi_properties, +}; + static const struct of_device_id bcm2835aux_serial_match[] = { { .compatible = "brcm,bcm2835-aux-uart" }, { }, }; MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); +static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = { + { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_node }, + { } +}; +MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match); + +static bool bcm2835aux_can_disable_clock(struct device *dev) +{ + struct bcm2835aux_data *data = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(data->line); + + if (device_may_wakeup(dev)) + return false; + + if (uart_console(&up->port) && !console_suspend_enabled) + return false; + + return true; +} + +static int bcm2835aux_suspend(struct device *dev) +{ + struct bcm2835aux_data *data = dev_get_drvdata(dev); + + serial8250_suspend_port(data->line); + + if (!bcm2835aux_can_disable_clock(dev)) + return 0; + + clk_disable_unprepare(data->clk); + return 0; +} + +static int bcm2835aux_resume(struct device *dev) +{ + struct bcm2835aux_data *data = dev_get_drvdata(dev); + int ret; + + if (bcm2835aux_can_disable_clock(dev)) { + ret = clk_prepare_enable(data->clk); + if (ret) + return ret; + } + + serial8250_resume_port(data->line); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(bcm2835aux_dev_pm_ops, bcm2835aux_suspend, bcm2835aux_resume); + static struct platform_driver bcm2835aux_serial_driver = { .driver = { .name = "bcm2835-aux-uart", .of_match_table = bcm2835aux_serial_match, + .acpi_match_table = bcm2835aux_serial_acpi_match, + .pm = pm_ptr(&bcm2835aux_dev_pm_ops), }, .probe = bcm2835aux_serial_probe, .remove = bcm2835aux_serial_remove, diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c new file mode 100644 index 000000000000..742004d63c6f --- /dev/null +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -0,0 +1,1234 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2020, Broadcom */ +/* + * 8250-core based driver for Broadcom ns16550a UARTs + * + * This driver uses the standard 8250 driver core but adds additional + * optional features including the ability to use a baud rate clock + * mux for more accurate high speed baud rate selection and also + * an optional DMA engine. + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/dma-mapping.h> +#include <linux/tty_flip.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/units.h> + +#include "8250.h" + +/* Register definitions for UART DMA block. Version 1.1 or later. */ +#define UDMA_ARB_RX 0x00 +#define UDMA_ARB_TX 0x04 +#define UDMA_ARB_REQ 0x00000001 +#define UDMA_ARB_GRANT 0x00000002 + +#define UDMA_RX_REVISION 0x00 +#define UDMA_RX_REVISION_REQUIRED 0x00000101 +#define UDMA_RX_CTRL 0x04 +#define UDMA_RX_CTRL_BUF_CLOSE_MODE 0x00010000 +#define UDMA_RX_CTRL_MASK_WR_DONE 0x00008000 +#define UDMA_RX_CTRL_ENDIAN_OVERRIDE 0x00004000 +#define UDMA_RX_CTRL_ENDIAN 0x00002000 +#define UDMA_RX_CTRL_OE_IS_ERR 0x00001000 +#define UDMA_RX_CTRL_PE_IS_ERR 0x00000800 +#define UDMA_RX_CTRL_FE_IS_ERR 0x00000400 +#define UDMA_RX_CTRL_NUM_BUF_USED_MASK 0x000003c0 +#define UDMA_RX_CTRL_NUM_BUF_USED_SHIFT 6 +#define UDMA_RX_CTRL_BUF_CLOSE_CLK_SEL_SYS 0x00000020 +#define UDMA_RX_CTRL_BUF_CLOSE_ENA 0x00000010 +#define UDMA_RX_CTRL_TIMEOUT_CLK_SEL_SYS 0x00000008 +#define UDMA_RX_CTRL_TIMEOUT_ENA 0x00000004 +#define UDMA_RX_CTRL_ABORT 0x00000002 +#define UDMA_RX_CTRL_ENA 0x00000001 +#define UDMA_RX_STATUS 0x08 +#define UDMA_RX_STATUS_ACTIVE_BUF_MASK 0x0000000f +#define UDMA_RX_TRANSFER_LEN 0x0c +#define UDMA_RX_TRANSFER_TOTAL 0x10 +#define UDMA_RX_BUFFER_SIZE 0x14 +#define UDMA_RX_SRC_ADDR 0x18 +#define UDMA_RX_TIMEOUT 0x1c +#define UDMA_RX_BUFFER_CLOSE 0x20 +#define UDMA_RX_BLOCKOUT_COUNTER 0x24 +#define UDMA_RX_BUF0_PTR_LO 0x28 +#define UDMA_RX_BUF0_PTR_HI 0x2c +#define UDMA_RX_BUF0_STATUS 0x30 +#define UDMA_RX_BUFX_STATUS_OVERRUN_ERR 0x00000010 +#define UDMA_RX_BUFX_STATUS_FRAME_ERR 0x00000008 +#define UDMA_RX_BUFX_STATUS_PARITY_ERR 0x00000004 +#define UDMA_RX_BUFX_STATUS_CLOSE_EXPIRED 0x00000002 +#define UDMA_RX_BUFX_STATUS_DATA_RDY 0x00000001 +#define UDMA_RX_BUF0_DATA_LEN 0x34 +#define UDMA_RX_BUF1_PTR_LO 0x38 +#define UDMA_RX_BUF1_PTR_HI 0x3c +#define UDMA_RX_BUF1_STATUS 0x40 +#define UDMA_RX_BUF1_DATA_LEN 0x44 + +#define UDMA_TX_REVISION 0x00 +#define UDMA_TX_REVISION_REQUIRED 0x00000101 +#define UDMA_TX_CTRL 0x04 +#define UDMA_TX_CTRL_ENDIAN_OVERRIDE 0x00000080 +#define UDMA_TX_CTRL_ENDIAN 0x00000040 +#define UDMA_TX_CTRL_NUM_BUF_USED_MASK 0x00000030 +#define UDMA_TX_CTRL_NUM_BUF_USED_1 0x00000010 +#define UDMA_TX_CTRL_ABORT 0x00000002 +#define UDMA_TX_CTRL_ENA 0x00000001 +#define UDMA_TX_DST_ADDR 0x08 +#define UDMA_TX_BLOCKOUT_COUNTER 0x10 +#define UDMA_TX_TRANSFER_LEN 0x14 +#define UDMA_TX_TRANSFER_TOTAL 0x18 +#define UDMA_TX_STATUS 0x20 +#define UDMA_TX_BUF0_PTR_LO 0x24 +#define UDMA_TX_BUF0_PTR_HI 0x28 +#define UDMA_TX_BUF0_STATUS 0x2c +#define UDMA_TX_BUFX_LAST 0x00000002 +#define UDMA_TX_BUFX_EMPTY 0x00000001 +#define UDMA_TX_BUF0_DATA_LEN 0x30 +#define UDMA_TX_BUF0_DATA_SENT 0x34 +#define UDMA_TX_BUF1_PTR_LO 0x38 + +#define UDMA_INTR_STATUS 0x00 +#define UDMA_INTR_ARB_TX_GRANT 0x00040000 +#define UDMA_INTR_ARB_RX_GRANT 0x00020000 +#define UDMA_INTR_TX_ALL_EMPTY 0x00010000 +#define UDMA_INTR_TX_EMPTY_BUF1 0x00008000 +#define UDMA_INTR_TX_EMPTY_BUF0 0x00004000 +#define UDMA_INTR_TX_ABORT 0x00002000 +#define UDMA_INTR_TX_DONE 0x00001000 +#define UDMA_INTR_RX_ERROR 0x00000800 +#define UDMA_INTR_RX_TIMEOUT 0x00000400 +#define UDMA_INTR_RX_READY_BUF7 0x00000200 +#define UDMA_INTR_RX_READY_BUF6 0x00000100 +#define UDMA_INTR_RX_READY_BUF5 0x00000080 +#define UDMA_INTR_RX_READY_BUF4 0x00000040 +#define UDMA_INTR_RX_READY_BUF3 0x00000020 +#define UDMA_INTR_RX_READY_BUF2 0x00000010 +#define UDMA_INTR_RX_READY_BUF1 0x00000008 +#define UDMA_INTR_RX_READY_BUF0 0x00000004 +#define UDMA_INTR_RX_READY_MASK 0x000003fc +#define UDMA_INTR_RX_READY_SHIFT 2 +#define UDMA_INTR_RX_ABORT 0x00000002 +#define UDMA_INTR_RX_DONE 0x00000001 +#define UDMA_INTR_SET 0x04 +#define UDMA_INTR_CLEAR 0x08 +#define UDMA_INTR_MASK_STATUS 0x0c +#define UDMA_INTR_MASK_SET 0x10 +#define UDMA_INTR_MASK_CLEAR 0x14 + + +#define UDMA_RX_INTERRUPTS ( \ + UDMA_INTR_RX_ERROR | \ + UDMA_INTR_RX_TIMEOUT | \ + UDMA_INTR_RX_READY_BUF0 | \ + UDMA_INTR_RX_READY_BUF1 | \ + UDMA_INTR_RX_READY_BUF2 | \ + UDMA_INTR_RX_READY_BUF3 | \ + UDMA_INTR_RX_READY_BUF4 | \ + UDMA_INTR_RX_READY_BUF5 | \ + UDMA_INTR_RX_READY_BUF6 | \ + UDMA_INTR_RX_READY_BUF7 | \ + UDMA_INTR_RX_ABORT | \ + UDMA_INTR_RX_DONE) + +#define UDMA_RX_ERR_INTERRUPTS ( \ + UDMA_INTR_RX_ERROR | \ + UDMA_INTR_RX_TIMEOUT | \ + UDMA_INTR_RX_ABORT | \ + UDMA_INTR_RX_DONE) + +#define UDMA_TX_INTERRUPTS ( \ + UDMA_INTR_TX_ABORT | \ + UDMA_INTR_TX_DONE) + +#define UDMA_IS_RX_INTERRUPT(status) ((status) & UDMA_RX_INTERRUPTS) +#define UDMA_IS_TX_INTERRUPT(status) ((status) & UDMA_TX_INTERRUPTS) + + +/* Current devices have 8 sets of RX buffer registers */ +#define UDMA_RX_BUFS_COUNT 8 +#define UDMA_RX_BUFS_REG_OFFSET (UDMA_RX_BUF1_PTR_LO - UDMA_RX_BUF0_PTR_LO) +#define UDMA_RX_BUFx_PTR_LO(x) (UDMA_RX_BUF0_PTR_LO + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_PTR_HI(x) (UDMA_RX_BUF0_PTR_HI + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_STATUS(x) (UDMA_RX_BUF0_STATUS + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_DATA_LEN(x) (UDMA_RX_BUF0_DATA_LEN + \ + ((x) * UDMA_RX_BUFS_REG_OFFSET)) + +/* Current devices have 2 sets of TX buffer registers */ +#define UDMA_TX_BUFS_COUNT 2 +#define UDMA_TX_BUFS_REG_OFFSET (UDMA_TX_BUF1_PTR_LO - UDMA_TX_BUF0_PTR_LO) +#define UDMA_TX_BUFx_PTR_LO(x) (UDMA_TX_BUF0_PTR_LO + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_PTR_HI(x) (UDMA_TX_BUF0_PTR_HI + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_STATUS(x) (UDMA_TX_BUF0_STATUS + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_DATA_LEN(x) (UDMA_TX_BUF0_DATA_LEN + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_DATA_SENT(x) (UDMA_TX_BUF0_DATA_SENT + \ + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define REGS_8250 0 +#define REGS_DMA_RX 1 +#define REGS_DMA_TX 2 +#define REGS_DMA_ISR 3 +#define REGS_DMA_ARB 4 +#define REGS_MAX 5 + +#define TX_BUF_SIZE 4096 +#define RX_BUF_SIZE 4096 +#define RX_BUFS_COUNT 2 + +static const u32 brcmstb_rate_table[] = { + 81 * HZ_PER_MHZ, + 108 * HZ_PER_MHZ, + 64 * HZ_PER_MHZ, /* Actually 64285715 for some chips */ + 48 * HZ_PER_MHZ, +}; + +static const u32 brcmstb_rate_table_7278[] = { + 81 * HZ_PER_MHZ, + 108 * HZ_PER_MHZ, + 0, + 48 * HZ_PER_MHZ, +}; + +struct brcmuart_priv { + int line; + struct clk *baud_mux_clk; + unsigned long default_mux_rate; + u32 real_rates[ARRAY_SIZE(brcmstb_rate_table)]; + const u32 *rate_table; + ktime_t char_wait; + struct uart_port *up; + struct hrtimer hrt; + bool shutdown; + bool dma_enabled; + struct uart_8250_dma dma; + void __iomem *regs[REGS_MAX]; + dma_addr_t rx_addr; + void *rx_bufs; + size_t rx_size; + int rx_next_buf; + dma_addr_t tx_addr; + void *tx_buf; + size_t tx_size; + bool tx_running; + bool rx_running; + struct dentry *debugfs_dir; + + /* stats exposed through debugfs */ + u64 dma_rx_partial_buf; + u64 dma_rx_full_buf; + u32 rx_bad_timeout_late_char; + u32 rx_bad_timeout_no_char; + u32 rx_missing_close_timeout; + u32 rx_err; + u32 rx_timeout; + u32 rx_abort; + u32 saved_mctrl; +}; + +static struct dentry *brcmuart_debugfs_root; + +/* + * Register access routines + */ +static u32 udma_readl(struct brcmuart_priv *priv, + int reg_type, int offset) +{ + return readl(priv->regs[reg_type] + offset); +} + +static void udma_writel(struct brcmuart_priv *priv, + int reg_type, int offset, u32 value) +{ + writel(value, priv->regs[reg_type] + offset); +} + +static void udma_set(struct brcmuart_priv *priv, + int reg_type, int offset, u32 bits) +{ + void __iomem *reg = priv->regs[reg_type] + offset; + u32 value; + + value = readl(reg); + value |= bits; + writel(value, reg); +} + +static void udma_unset(struct brcmuart_priv *priv, + int reg_type, int offset, u32 bits) +{ + void __iomem *reg = priv->regs[reg_type] + offset; + u32 value; + + value = readl(reg); + value &= ~bits; + writel(value, reg); +} + +/* + * The UART DMA engine hardware can be used by multiple UARTS, but + * only one at a time. Sharing is not currently supported so + * the first UART to request the DMA engine will get it and any + * subsequent requests by other UARTS will fail. + */ +static int brcmuart_arbitration(struct brcmuart_priv *priv, bool acquire) +{ + u32 rx_grant; + u32 tx_grant; + int waits; + int ret = 0; + + if (acquire) { + udma_set(priv, REGS_DMA_ARB, UDMA_ARB_RX, UDMA_ARB_REQ); + udma_set(priv, REGS_DMA_ARB, UDMA_ARB_TX, UDMA_ARB_REQ); + + waits = 1; + while (1) { + rx_grant = udma_readl(priv, REGS_DMA_ARB, UDMA_ARB_RX); + tx_grant = udma_readl(priv, REGS_DMA_ARB, UDMA_ARB_TX); + if (rx_grant & tx_grant & UDMA_ARB_GRANT) + return 0; + if (waits-- == 0) + break; + msleep(1); + } + ret = 1; + } + + udma_unset(priv, REGS_DMA_ARB, UDMA_ARB_RX, UDMA_ARB_REQ); + udma_unset(priv, REGS_DMA_ARB, UDMA_ARB_TX, UDMA_ARB_REQ); + return ret; +} + +static void brcmuart_init_dma_hardware(struct brcmuart_priv *priv) +{ + u32 daddr; + u32 value; + int x; + + /* Start with all interrupts disabled */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_SET, 0xffffffff); + + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFFER_SIZE, RX_BUF_SIZE); + + /* + * Setup buffer close to happen when 32 character times have + * elapsed since the last character was received. + */ + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFFER_CLOSE, 16*10*32); + value = (RX_BUFS_COUNT << UDMA_RX_CTRL_NUM_BUF_USED_SHIFT) + | UDMA_RX_CTRL_BUF_CLOSE_MODE + | UDMA_RX_CTRL_BUF_CLOSE_ENA; + udma_writel(priv, REGS_DMA_RX, UDMA_RX_CTRL, value); + + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BLOCKOUT_COUNTER, 0); + daddr = priv->rx_addr; + for (x = 0; x < RX_BUFS_COUNT; x++) { + + /* Set RX transfer length to 0 for unknown */ + udma_writel(priv, REGS_DMA_RX, UDMA_RX_TRANSFER_LEN, 0); + + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFx_PTR_LO(x), + lower_32_bits(daddr)); + udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFx_PTR_HI(x), + upper_32_bits(daddr)); + daddr += RX_BUF_SIZE; + } + + daddr = priv->tx_addr; + udma_writel(priv, REGS_DMA_TX, UDMA_TX_BUFx_PTR_LO(0), + lower_32_bits(daddr)); + udma_writel(priv, REGS_DMA_TX, UDMA_TX_BUFx_PTR_HI(0), + upper_32_bits(daddr)); + udma_writel(priv, REGS_DMA_TX, UDMA_TX_CTRL, + UDMA_TX_CTRL_NUM_BUF_USED_1); + + /* clear all interrupts then enable them */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_CLEAR, 0xffffffff); + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_CLEAR, + UDMA_RX_INTERRUPTS | UDMA_TX_INTERRUPTS); + +} + +static void start_rx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + int x; + + udma_unset(priv, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ENA); + + /* Clear the RX ready bit for all buffers */ + for (x = 0; x < RX_BUFS_COUNT; x++) + udma_unset(priv, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(x), + UDMA_RX_BUFX_STATUS_DATA_RDY); + + /* always start with buffer 0 */ + udma_unset(priv, REGS_DMA_RX, UDMA_RX_STATUS, + UDMA_RX_STATUS_ACTIVE_BUF_MASK); + priv->rx_next_buf = 0; + + udma_set(priv, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ENA); + priv->rx_running = true; +} + +static void stop_rx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + + /* If RX is running, set the RX ABORT */ + if (priv->rx_running) + udma_set(priv, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ABORT); +} + +static int stop_tx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + u32 value; + + /* If TX is running, set the TX ABORT */ + value = udma_readl(priv, REGS_DMA_TX, UDMA_TX_CTRL); + if (value & UDMA_TX_CTRL_ENA) + udma_set(priv, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ABORT); + priv->tx_running = false; + return 0; +} + +/* + * NOTE: printk's in this routine will hang the system if this is + * the console tty + */ +static int brcmuart_tx_dma(struct uart_8250_port *p) +{ + struct brcmuart_priv *priv = p->port.private_data; + struct tty_port *tport = &p->port.state->port; + u32 tx_size; + + if (uart_tx_stopped(&p->port) || priv->tx_running || + kfifo_is_empty(&tport->xmit_fifo)) { + return 0; + } + + priv->dma.tx_err = 0; + tx_size = uart_fifo_out(&p->port, priv->tx_buf, UART_XMIT_SIZE); + + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(&p->port); + + udma_writel(priv, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, tx_size); + udma_writel(priv, REGS_DMA_TX, UDMA_TX_BUF0_DATA_LEN, tx_size); + udma_unset(priv, REGS_DMA_TX, UDMA_TX_BUF0_STATUS, UDMA_TX_BUFX_EMPTY); + udma_set(priv, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ENA); + priv->tx_running = true; + + return 0; +} + +static void brcmuart_rx_buf_done_isr(struct uart_port *up, int index) +{ + struct brcmuart_priv *priv = up->private_data; + struct tty_port *tty_port = &up->state->port; + u32 status; + u32 length; + u32 copied; + + /* Make sure we're still in sync with the hardware */ + status = udma_readl(priv, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(index)); + length = udma_readl(priv, REGS_DMA_RX, UDMA_RX_BUFx_DATA_LEN(index)); + + if ((status & UDMA_RX_BUFX_STATUS_DATA_RDY) == 0) { + dev_err(up->dev, "RX done interrupt but DATA_RDY not found\n"); + return; + } + if (status & (UDMA_RX_BUFX_STATUS_OVERRUN_ERR | + UDMA_RX_BUFX_STATUS_FRAME_ERR | + UDMA_RX_BUFX_STATUS_PARITY_ERR)) { + if (status & UDMA_RX_BUFX_STATUS_OVERRUN_ERR) { + up->icount.overrun++; + dev_warn(up->dev, "RX OVERRUN Error\n"); + } + if (status & UDMA_RX_BUFX_STATUS_FRAME_ERR) { + up->icount.frame++; + dev_warn(up->dev, "RX FRAMING Error\n"); + } + if (status & UDMA_RX_BUFX_STATUS_PARITY_ERR) { + up->icount.parity++; + dev_warn(up->dev, "RX PARITY Error\n"); + } + } + copied = (u32)tty_insert_flip_string( + tty_port, + priv->rx_bufs + (index * RX_BUF_SIZE), + length); + if (copied != length) { + dev_warn(up->dev, "Flip buffer overrun of %d bytes\n", + length - copied); + up->icount.overrun += length - copied; + } + up->icount.rx += length; + if (status & UDMA_RX_BUFX_STATUS_CLOSE_EXPIRED) + priv->dma_rx_partial_buf++; + else if (length != RX_BUF_SIZE) + /* + * This is a bug in the controller that doesn't cause + * any problems but will be fixed in the future. + */ + priv->rx_missing_close_timeout++; + else + priv->dma_rx_full_buf++; + + tty_flip_buffer_push(tty_port); +} + +static void brcmuart_rx_isr(struct uart_port *up, u32 rx_isr) +{ + struct brcmuart_priv *priv = up->private_data; + struct device *dev = up->dev; + u32 rx_done_isr; + u32 check_isr; + + rx_done_isr = (rx_isr & UDMA_INTR_RX_READY_MASK); + while (rx_done_isr) { + check_isr = UDMA_INTR_RX_READY_BUF0 << priv->rx_next_buf; + if (check_isr & rx_done_isr) { + brcmuart_rx_buf_done_isr(up, priv->rx_next_buf); + } else { + dev_err(dev, + "RX buffer ready out of sequence, restarting RX DMA\n"); + start_rx_dma(up_to_u8250p(up)); + break; + } + if (rx_isr & UDMA_RX_ERR_INTERRUPTS) { + if (rx_isr & UDMA_INTR_RX_ERROR) + priv->rx_err++; + if (rx_isr & UDMA_INTR_RX_TIMEOUT) { + priv->rx_timeout++; + dev_err(dev, "RX TIMEOUT Error\n"); + } + if (rx_isr & UDMA_INTR_RX_ABORT) + priv->rx_abort++; + priv->rx_running = false; + } + /* If not ABORT, re-enable RX buffer */ + if (!(rx_isr & UDMA_INTR_RX_ABORT)) + udma_unset(priv, REGS_DMA_RX, + UDMA_RX_BUFx_STATUS(priv->rx_next_buf), + UDMA_RX_BUFX_STATUS_DATA_RDY); + rx_done_isr &= ~check_isr; + priv->rx_next_buf++; + if (priv->rx_next_buf == RX_BUFS_COUNT) + priv->rx_next_buf = 0; + } +} + +static void brcmuart_tx_isr(struct uart_port *up, u32 isr) +{ + struct brcmuart_priv *priv = up->private_data; + struct device *dev = up->dev; + struct uart_8250_port *port_8250 = up_to_u8250p(up); + struct tty_port *tport = &port_8250->port.state->port; + + if (isr & UDMA_INTR_TX_ABORT) { + if (priv->tx_running) + dev_err(dev, "Unexpected TX_ABORT interrupt\n"); + return; + } + priv->tx_running = false; + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(up)) + brcmuart_tx_dma(port_8250); +} + +static irqreturn_t brcmuart_isr(int irq, void *dev_id) +{ + struct uart_port *up = dev_id; + struct device *dev = up->dev; + struct brcmuart_priv *priv = up->private_data; + unsigned long flags; + u32 interrupts; + u32 rval; + u32 tval; + + interrupts = udma_readl(priv, REGS_DMA_ISR, UDMA_INTR_STATUS); + if (interrupts == 0) + return IRQ_NONE; + + uart_port_lock_irqsave(up, &flags); + + /* Clear all interrupts */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_CLEAR, interrupts); + + rval = UDMA_IS_RX_INTERRUPT(interrupts); + if (rval) + brcmuart_rx_isr(up, rval); + tval = UDMA_IS_TX_INTERRUPT(interrupts); + if (tval) + brcmuart_tx_isr(up, tval); + if ((rval | tval) == 0) + dev_warn(dev, "Spurious interrupt: 0x%x\n", interrupts); + + uart_port_unlock_irqrestore(up, flags); + return IRQ_HANDLED; +} + +static int brcmuart_startup(struct uart_port *port) +{ + int res; + struct uart_8250_port *up = up_to_u8250p(port); + struct brcmuart_priv *priv = up->port.private_data; + + priv->shutdown = false; + + /* + * prevent serial8250_do_startup() from allocating non-existent + * DMA resources + */ + up->dma = NULL; + + res = serial8250_do_startup(port); + if (!priv->dma_enabled) + return res; + /* + * Disable the Receive Data Interrupt because the DMA engine + * will handle this. + * + * Synchronize UART_IER access against the console. + */ + uart_port_lock_irq(port); + up->ier &= ~UART_IER_RDI; + serial_port_out(port, UART_IER, up->ier); + uart_port_unlock_irq(port); + + priv->tx_running = false; + priv->dma.rx_dma = NULL; + priv->dma.tx_dma = brcmuart_tx_dma; + up->dma = &priv->dma; + + brcmuart_init_dma_hardware(priv); + start_rx_dma(up); + return res; +} + +static void brcmuart_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + struct brcmuart_priv *priv = up->port.private_data; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + priv->shutdown = true; + if (priv->dma_enabled) { + stop_rx_dma(up); + stop_tx_dma(up); + /* disable all interrupts */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_SET, + UDMA_RX_INTERRUPTS | UDMA_TX_INTERRUPTS); + } + + /* + * prevent serial8250_do_shutdown() from trying to free + * DMA resources that we never alloc'd for this driver. + */ + up->dma = NULL; + + uart_port_unlock_irqrestore(port, flags); + serial8250_do_shutdown(port); +} + +/* + * Not all clocks run at the exact specified rate, so set each requested + * rate and then get the actual rate. + */ +static void init_real_clk_rates(struct device *dev, struct brcmuart_priv *priv) +{ + int x; + int rc; + + priv->default_mux_rate = clk_get_rate(priv->baud_mux_clk); + for (x = 0; x < ARRAY_SIZE(priv->real_rates); x++) { + if (priv->rate_table[x] == 0) { + priv->real_rates[x] = 0; + continue; + } + rc = clk_set_rate(priv->baud_mux_clk, priv->rate_table[x]); + if (rc) { + dev_err(dev, "Error selecting BAUD MUX clock for %u\n", + priv->rate_table[x]); + priv->real_rates[x] = priv->rate_table[x]; + } else { + priv->real_rates[x] = clk_get_rate(priv->baud_mux_clk); + } + } + clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate); +} + +static u32 find_quot(struct device *dev, u32 freq, u32 baud, u32 *percent) +{ + u32 quot; + u32 rate; + u64 hires_rate; + u64 hires_baud; + u64 hires_err; + + rate = freq / 16; + quot = DIV_ROUND_CLOSEST(rate, baud); + if (!quot) + return 0; + + /* increase resolution to get xx.xx percent */ + hires_rate = div_u64((u64)rate * 10000, (u64)quot); + hires_baud = (u64)baud * 10000; + + /* get the delta */ + if (hires_rate > hires_baud) + hires_err = (hires_rate - hires_baud); + else + hires_err = (hires_baud - hires_rate); + + *percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud); + + dev_dbg(dev, "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n", + baud, freq, *percent / 100, *percent % 100); + + return quot; +} + +static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, + u32 baud) +{ + u32 percent; + u32 best_percent = UINT_MAX; + u32 quot; + u32 freq; + u32 best_quot = 1; + u32 best_freq = 0; + int rc; + int i; + int real_baud; + + /* If the Baud Mux Clock was not specified, just return */ + if (priv->baud_mux_clk == NULL) + return; + + /* Try default_mux_rate first */ + quot = find_quot(up->dev, priv->default_mux_rate, baud, &percent); + if (quot) { + best_percent = percent; + best_freq = priv->default_mux_rate; + best_quot = quot; + } + /* If more than 1% error, find the closest match for specified baud */ + if (best_percent > 100) { + for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) { + freq = priv->real_rates[i]; + if (freq == 0 || freq == priv->default_mux_rate) + continue; + quot = find_quot(up->dev, freq, baud, &percent); + if (!quot) + continue; + + if (percent < best_percent) { + best_percent = percent; + best_freq = freq; + best_quot = quot; + } + } + } + if (!best_freq) { + dev_err(up->dev, "Error, %d BAUD rate is too fast.\n", baud); + return; + } + rc = clk_set_rate(priv->baud_mux_clk, best_freq); + if (rc) + dev_err(up->dev, "Error selecting BAUD MUX clock\n"); + + /* Error over 3 percent will cause data errors */ + if (best_percent > 300) + dev_err(up->dev, "Error, baud: %d has %u.%u%% error\n", + baud, percent / 100, percent % 100); + + real_baud = best_freq / 16 / best_quot; + dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", best_freq); + dev_dbg(up->dev, "Requested baud: %u, Actual baud: %u\n", + baud, real_baud); + + /* calc nanoseconds for 1.5 characters time at the given baud rate */ + i = NSEC_PER_SEC / real_baud / 10; + i += (i / 2); + priv->char_wait = ns_to_ktime(i); + + up->uartclk = best_freq; +} + +static void brcmstb_set_termios(struct uart_port *up, + struct ktermios *termios, + const struct ktermios *old) +{ + struct uart_8250_port *p8250 = up_to_u8250p(up); + struct brcmuart_priv *priv = up->private_data; + + if (priv->dma_enabled) + stop_rx_dma(p8250); + set_clock_mux(up, priv, tty_termios_baud_rate(termios)); + serial8250_do_set_termios(up, termios, old); + if (p8250->mcr & UART_MCR_AFE) + p8250->port.status |= UPSTAT_AUTOCTS; + if (priv->dma_enabled) + start_rx_dma(p8250); +} + +static int brcmuart_handle_irq(struct uart_port *p) +{ + unsigned int iir = serial_port_in(p, UART_IIR); + struct brcmuart_priv *priv = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); + unsigned int status; + unsigned long flags; + unsigned int ier; + unsigned int mcr; + int handled = 0; + + /* + * There's a bug in some 8250 cores where we get a timeout + * interrupt but there is no data ready. + */ + if (((iir & UART_IIR_ID) == UART_IIR_RX_TIMEOUT) && !(priv->shutdown)) { + uart_port_lock_irqsave(p, &flags); + status = serial_port_in(p, UART_LSR); + if ((status & UART_LSR_DR) == 0) { + + ier = serial_port_in(p, UART_IER); + /* + * if Receive Data Interrupt is enabled and + * we're uing hardware flow control, deassert + * RTS and wait for any chars in the pipeline to + * arrive and then check for DR again. + */ + if ((ier & UART_IER_RDI) && (up->mcr & UART_MCR_AFE)) { + ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_port_out(p, UART_IER, ier); + mcr = serial_port_in(p, UART_MCR); + mcr &= ~UART_MCR_RTS; + serial_port_out(p, UART_MCR, mcr); + hrtimer_start(&priv->hrt, priv->char_wait, + HRTIMER_MODE_REL); + } else { + serial_port_in(p, UART_RX); + } + + handled = 1; + } + uart_port_unlock_irqrestore(p, flags); + if (handled) + return 1; + } + return serial8250_handle_irq(p, iir); +} + +static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) +{ + struct brcmuart_priv *priv = container_of(t, struct brcmuart_priv, hrt); + struct uart_port *p = priv->up; + struct uart_8250_port *up = up_to_u8250p(p); + unsigned int status; + unsigned long flags; + + if (priv->shutdown) + return HRTIMER_NORESTART; + + uart_port_lock_irqsave(p, &flags); + status = serial_port_in(p, UART_LSR); + + /* + * If a character did not arrive after the timeout, clear the false + * receive timeout. + */ + if ((status & UART_LSR_DR) == 0) { + serial_port_in(p, UART_RX); + priv->rx_bad_timeout_no_char++; + } else { + priv->rx_bad_timeout_late_char++; + } + + /* re-enable receive unless upper layer has disabled it */ + if ((up->ier & (UART_IER_RLSI | UART_IER_RDI)) == + (UART_IER_RLSI | UART_IER_RDI)) { + status = serial_port_in(p, UART_IER); + status |= (UART_IER_RLSI | UART_IER_RDI); + serial_port_out(p, UART_IER, status); + status = serial_port_in(p, UART_MCR); + status |= UART_MCR_RTS; + serial_port_out(p, UART_MCR, status); + } + uart_port_unlock_irqrestore(p, flags); + return HRTIMER_NORESTART; +} + +static const struct of_device_id brcmuart_dt_ids[] = { + { + .compatible = "brcm,bcm7278-uart", + .data = brcmstb_rate_table_7278, + }, + { + .compatible = "brcm,bcm7271-uart", + .data = brcmstb_rate_table, + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, brcmuart_dt_ids); + +static void brcmuart_free_bufs(struct device *dev, struct brcmuart_priv *priv) +{ + if (priv->rx_bufs) + dma_free_coherent(dev, priv->rx_size, priv->rx_bufs, + priv->rx_addr); + if (priv->tx_buf) + dma_free_coherent(dev, priv->tx_size, priv->tx_buf, + priv->tx_addr); +} + +static void brcmuart_throttle(struct uart_port *port) +{ + struct brcmuart_priv *priv = port->private_data; + + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_SET, UDMA_RX_INTERRUPTS); +} + +static void brcmuart_unthrottle(struct uart_port *port) +{ + struct brcmuart_priv *priv = port->private_data; + + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_MASK_CLEAR, + UDMA_RX_INTERRUPTS); +} + +static int debugfs_stats_show(struct seq_file *s, void *unused) +{ + struct brcmuart_priv *priv = s->private; + + seq_printf(s, "rx_err:\t\t\t\t%u\n", + priv->rx_err); + seq_printf(s, "rx_timeout:\t\t\t%u\n", + priv->rx_timeout); + seq_printf(s, "rx_abort:\t\t\t%u\n", + priv->rx_abort); + seq_printf(s, "rx_bad_timeout_late_char:\t%u\n", + priv->rx_bad_timeout_late_char); + seq_printf(s, "rx_bad_timeout_no_char:\t\t%u\n", + priv->rx_bad_timeout_no_char); + seq_printf(s, "rx_missing_close_timeout:\t%u\n", + priv->rx_missing_close_timeout); + if (priv->dma_enabled) { + seq_printf(s, "dma_rx_partial_buf:\t\t%llu\n", + priv->dma_rx_partial_buf); + seq_printf(s, "dma_rx_full_buf:\t\t%llu\n", + priv->dma_rx_full_buf); + } + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_stats); + +static void brcmuart_init_debugfs(struct brcmuart_priv *priv, + const char *device) +{ + priv->debugfs_dir = debugfs_create_dir(device, brcmuart_debugfs_root); + debugfs_create_file("stats", 0444, priv->debugfs_dir, priv, + &debugfs_stats_fops); +} + + +static int brcmuart_probe(struct platform_device *pdev) +{ + struct resource *regs; + const struct of_device_id *of_id = NULL; + struct uart_8250_port *new_port; + struct device *dev = &pdev->dev; + struct brcmuart_priv *priv; + struct clk *baud_mux_clk; + struct uart_8250_port up; + void __iomem *membase = NULL; + resource_size_t mapbase = 0; + int ret; + int x; + int dma_irq; + static const char * const reg_names[REGS_MAX] = { + "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb" + }; + + priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + of_id = of_match_node(brcmuart_dt_ids, dev->of_node); + if (!of_id || !of_id->data) + priv->rate_table = brcmstb_rate_table; + else + priv->rate_table = of_id->data; + + for (x = 0; x < REGS_MAX; x++) { + regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, + reg_names[x]); + if (!regs) + break; + priv->regs[x] = devm_ioremap(dev, regs->start, + resource_size(regs)); + if (!priv->regs[x]) + return -ENOMEM; + if (x == REGS_8250) { + mapbase = regs->start; + membase = priv->regs[x]; + } + } + + /* We should have just the uart base registers or all the registers */ + if (x != 1 && x != REGS_MAX) + return dev_err_probe(dev, -EINVAL, "%s registers not specified\n", + reg_names[x]); + + /* if the DMA registers were specified, try to enable DMA */ + if (x > REGS_DMA_RX) { + if (brcmuart_arbitration(priv, 1) == 0) { + u32 txrev = 0; + u32 rxrev = 0; + + txrev = udma_readl(priv, REGS_DMA_RX, UDMA_RX_REVISION); + rxrev = udma_readl(priv, REGS_DMA_TX, UDMA_TX_REVISION); + if ((txrev >= UDMA_TX_REVISION_REQUIRED) && + (rxrev >= UDMA_RX_REVISION_REQUIRED)) { + + /* Enable the use of the DMA hardware */ + priv->dma_enabled = true; + } else { + brcmuart_arbitration(priv, 0); + dev_err(dev, + "Unsupported DMA Hardware Revision\n"); + } + } else { + dev_err(dev, + "Timeout arbitrating for UART DMA hardware\n"); + } + } + + dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not "); + + memset(&up, 0, sizeof(up)); + up.port.type = PORT_BCM7271; + up.port.dev = dev; + up.port.mapbase = mapbase; + up.port.membase = membase; + up.port.handle_irq = brcmuart_handle_irq; + up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; + up.port.private_data = priv; + + ret = uart_read_port_properties(&up.port); + if (ret) + goto release_dma; + + up.port.regshift = 2; + up.port.iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32; + + /* See if a Baud clock has been specified */ + baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud"); + ret = PTR_ERR_OR_ZERO(baud_mux_clk); + if (ret) + goto release_dma; + if (baud_mux_clk) { + dev_dbg(dev, "BAUD MUX clock found\n"); + + priv->baud_mux_clk = baud_mux_clk; + init_real_clk_rates(dev, priv); + up.port.uartclk = priv->default_mux_rate; + } else { + dev_dbg(dev, "BAUD MUX clock not specified\n"); + } + + /* setup HR timer */ + hrtimer_setup(&priv->hrt, brcmuart_hrtimer_func, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + + up.port.shutdown = brcmuart_shutdown; + up.port.startup = brcmuart_startup; + up.port.throttle = brcmuart_throttle; + up.port.unthrottle = brcmuart_unthrottle; + up.port.set_termios = brcmstb_set_termios; + + if (priv->dma_enabled) { + priv->rx_size = RX_BUF_SIZE * RX_BUFS_COUNT; + priv->rx_bufs = dma_alloc_coherent(dev, + priv->rx_size, + &priv->rx_addr, GFP_KERNEL); + if (!priv->rx_bufs) { + ret = -ENOMEM; + goto err; + } + priv->tx_size = UART_XMIT_SIZE; + priv->tx_buf = dma_alloc_coherent(dev, + priv->tx_size, + &priv->tx_addr, GFP_KERNEL); + if (!priv->tx_buf) { + ret = -ENOMEM; + goto err; + } + } + + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err_probe(dev, ret, "unable to register 8250 port\n"); + goto err; + } + priv->line = ret; + new_port = serial8250_get_port(ret); + priv->up = &new_port->port; + if (priv->dma_enabled) { + dma_irq = platform_get_irq_byname(pdev, "dma"); + if (dma_irq < 0) { + ret = dev_err_probe(dev, dma_irq, "no IRQ resource info\n"); + goto err1; + } + ret = devm_request_irq(dev, dma_irq, brcmuart_isr, + IRQF_SHARED, "uart DMA irq", &new_port->port); + if (ret) { + dev_err_probe(dev, ret, "unable to register IRQ handler\n"); + goto err1; + } + } + platform_set_drvdata(pdev, priv); + brcmuart_init_debugfs(priv, dev_name(&pdev->dev)); + return 0; + +err1: + serial8250_unregister_port(priv->line); +err: + brcmuart_free_bufs(dev, priv); +release_dma: + if (priv->dma_enabled) + brcmuart_arbitration(priv, 0); + return ret; +} + +static void brcmuart_remove(struct platform_device *pdev) +{ + struct brcmuart_priv *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debugfs_dir); + hrtimer_cancel(&priv->hrt); + serial8250_unregister_port(priv->line); + brcmuart_free_bufs(&pdev->dev, priv); + if (priv->dma_enabled) + brcmuart_arbitration(priv, 0); +} + +static int __maybe_unused brcmuart_suspend(struct device *dev) +{ + struct brcmuart_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + struct uart_port *port = &up->port; + unsigned long flags; + + /* + * This will prevent resume from enabling RTS before the + * baud rate has been restored. + */ + uart_port_lock_irqsave(port, &flags); + priv->saved_mctrl = port->mctrl; + port->mctrl &= ~TIOCM_RTS; + uart_port_unlock_irqrestore(port, flags); + + serial8250_suspend_port(priv->line); + clk_disable_unprepare(priv->baud_mux_clk); + + return 0; +} + +static int __maybe_unused brcmuart_resume(struct device *dev) +{ + struct brcmuart_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + struct uart_port *port = &up->port; + unsigned long flags; + int ret; + + ret = clk_prepare_enable(priv->baud_mux_clk); + if (ret) + dev_err(dev, "Error enabling BAUD MUX clock\n"); + + /* + * The hardware goes back to it's default after suspend + * so get the "clk" back in sync. + */ + ret = clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate); + if (ret) + dev_err(dev, "Error restoring default BAUD MUX clock\n"); + if (priv->dma_enabled) { + if (brcmuart_arbitration(priv, 1)) { + dev_err(dev, "Timeout arbitrating for DMA hardware on resume\n"); + return(-EBUSY); + } + brcmuart_init_dma_hardware(priv); + start_rx_dma(serial8250_get_port(priv->line)); + } + serial8250_resume_port(priv->line); + + if (priv->saved_mctrl & TIOCM_RTS) { + /* Restore RTS */ + uart_port_lock_irqsave(port, &flags); + port->mctrl |= TIOCM_RTS; + port->ops->set_mctrl(port, port->mctrl); + uart_port_unlock_irqrestore(port, flags); + } + + return 0; +} + +static const struct dev_pm_ops brcmuart_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(brcmuart_suspend, brcmuart_resume) +}; + +static struct platform_driver brcmuart_platform_driver = { + .driver = { + .name = "bcm7271-uart", + .pm = &brcmuart_dev_pm_ops, + .of_match_table = brcmuart_dt_ids, + }, + .probe = brcmuart_probe, + .remove = brcmuart_remove, +}; + +static int __init brcmuart_init(void) +{ + int ret; + + brcmuart_debugfs_root = debugfs_create_dir( + brcmuart_platform_driver.driver.name, NULL); + ret = platform_driver_register(&brcmuart_platform_driver); + if (ret) { + debugfs_remove_recursive(brcmuart_debugfs_root); + return ret; + } + + return 0; +} +module_init(brcmuart_init); + +static void __exit brcmuart_deinit(void) +{ + platform_driver_unregister(&brcmuart_platform_driver); + debugfs_remove_recursive(brcmuart_debugfs_root); +} +module_exit(brcmuart_deinit); + +MODULE_AUTHOR("Al Cooper"); +MODULE_DESCRIPTION("Broadcom NS16550A compatible serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_ce4100.c b/drivers/tty/serial/8250/8250_ce4100.c new file mode 100644 index 000000000000..81dfb2adbabd --- /dev/null +++ b/drivers/tty/serial/8250/8250_ce4100.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel CE4100 platform specific setup code + * + * (C) Copyright 2010 Intel Corporation + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/types.h> + +#include <asm/ce4100.h> +#include <asm/fixmap.h> +#include <asm/page.h> + +#include <linux/serial_reg.h> +#include <linux/serial_8250.h> + +static unsigned int mem_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readl(p->membase + offset); +} + +/* + * The UART Tx interrupts are not set under some conditions and therefore serial + * transmission hangs. This is a silicon issue and has not been root caused. The + * workaround for this silicon issue checks UART_LSR_THRE bit and UART_LSR_TEMT + * bit of LSR register in interrupt handler to see whether at least one of these + * two bits is set, if so then process the transmit request. If this workaround + * is not applied, then the serial transmission may hang. This workaround is for + * errata number 9 in Errata - B step. +*/ +static u32 ce4100_mem_serial_in(struct uart_port *p, unsigned int offset) +{ + u32 ret, ier, lsr; + + ret = mem_serial_in(p, offset); + if (offset != UART_IIR || !(ret & UART_IIR_NO_INT)) + return ret; + + /* see if the TX interrupt should have really set */ + ier = mem_serial_in(p, UART_IER); + /* see if the UART's XMIT interrupt is enabled */ + if (!(ier & UART_IER_THRI)) + return ret; + + lsr = mem_serial_in(p, UART_LSR); + /* now check to see if the UART should be generating an interrupt (but isn't) */ + if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) + ret &= ~UART_IIR_NO_INT; + + return ret; +} + +static void ce4100_mem_serial_out(struct uart_port *p, unsigned int offset, u32 value) +{ + offset <<= p->regshift; + writel(value, p->membase + offset); +} + +static void ce4100_serial_fixup(int port, struct uart_port *up, u32 *capabilities) +{ +#ifdef CONFIG_EARLY_PRINTK + /* + * Override the legacy port configuration that comes from + * asm/serial.h. Using the ioport driver then switching to the + * PCI memmaped driver hangs the IOAPIC. + */ + if (up->iotype != UPIO_MEM32) { + up->uartclk = 14745600; + up->mapbase = 0xdffe0200; + set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, up->mapbase & PAGE_MASK); + up->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + up->membase += up->mapbase & ~PAGE_MASK; + up->mapbase += port * 0x100; + up->membase += port * 0x100; + up->iotype = UPIO_MEM32; + up->regshift = 2; + up->irq = 4; + } +#endif + up->iobase = 0; + up->serial_in = ce4100_mem_serial_in; + up->serial_out = ce4100_mem_serial_out; + + *capabilities |= (1 << 12); +} + +void __init sdv_serial_fixup(void) +{ + serial8250_set_isa_configurator(ce4100_serial_fixup); +} diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index fc118f649887..0e81f78c6063 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -6,15 +6,14 @@ * * Copyright (C) 2001 Russell King. * - * Supports: ISA-compatible 8250/16550 ports - * PNP 8250/16550 ports + * Supports: * early_serial_setup() ports * userspace-configurable "phantom" ports - * "serial8250" platform devices * serial8250_register_8250_port() ports */ #include <linux/acpi.h> +#include <linux/hashtable.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ioport.h> @@ -23,6 +22,7 @@ #include <linux/sysrq.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/tty.h> #include <linux/ratelimit.h> #include <linux/tty_flip.h> @@ -31,55 +31,16 @@ #include <linux/nmi.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/string_helpers.h> #include <linux/uaccess.h> -#include <linux/pm_runtime.h> #include <linux/io.h> -#ifdef CONFIG_SPARC -#include <linux/sunserialcore.h> -#endif #include <asm/irq.h> #include "8250.h" -/* - * Configuration: - * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option - * is unsafe when used on edge-triggered interrupts. - */ -static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; - -static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; - -static struct uart_driver serial8250_reg; - -static unsigned int skip_txen_test; /* force skip of txen test at init time */ - #define PASS_LIMIT 512 -#include <asm/serial.h> -/* - * SERIAL_PORT_DFNS tells us about built-in ports that have no - * standard enumeration mechanism. Platforms that can find all - * serial ports via mechanisms like ACPI or PCI need not supply it. - */ -#ifndef SERIAL_PORT_DFNS -#define SERIAL_PORT_DFNS -#endif - -static const struct old_serial_port old_serial_port[] = { - SERIAL_PORT_DFNS /* defined in asm/serial.h */ -}; - -#define UART_NR CONFIG_SERIAL_8250_NR_UARTS - -#ifdef CONFIG_SERIAL_8250_RSA - -#define PORT_RSA_MAX 4 -static unsigned long probe_rsa[PORT_RSA_MAX]; -static unsigned int probe_rsa_count; -#endif /* CONFIG_SERIAL_8250_RSA */ - struct irq_info { struct hlist_node node; int irq; @@ -87,10 +48,14 @@ struct irq_info { struct list_head *head; }; -#define NR_IRQ_HASH 32 /* Can be adjusted later */ -static struct hlist_head irq_lists[NR_IRQ_HASH]; +#define IRQ_HASH_BITS 5 /* Can be adjusted later */ +static DEFINE_HASHTABLE(irq_lists, IRQ_HASH_BITS); static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ +static bool skip_txen_test; +module_param(skip_txen_test, bool, 0644); +MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); + /* * This is the serial driver's interrupt routine. * @@ -111,17 +76,12 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) struct list_head *l, *end = NULL; int pass_counter = 0, handled = 0; - pr_debug("%s(%d): start\n", __func__, irq); - - spin_lock(&i->lock); + guard(spinlock)(&i->lock); l = i->head; do { - struct uart_8250_port *up; - struct uart_port *port; - - up = list_entry(l, struct uart_8250_port, list); - port = &up->port; + struct uart_8250_port *up = list_entry(l, struct uart_8250_port, list); + struct uart_port *port = &up->port; if (port->handle_irq(port)) { handled = 1; @@ -135,10 +95,6 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) break; } while (l != end); - spin_unlock(&i->lock); - - pr_debug("%s(%d): end\n", __func__, irq); - return IRQ_RETVAL(handled); } @@ -169,83 +125,79 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) } } -static int serial_link_irq_chain(struct uart_8250_port *up) +/* + * Either: + * - find the corresponding info in the hashtable and return it, or + * - allocate a new one, add it to the hashtable and return it. + */ +static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_port *up) { - struct hlist_head *h; - struct hlist_node *n; struct irq_info *i; - int ret; - - mutex_lock(&hash_mutex); - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; + guard(mutex)(&hash_mutex); - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); + hash_for_each_possible(irq_lists, i, node, up->port.irq) if (i->irq == up->port.irq) - break; - } + return i; - if (n == NULL) { - i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); - if (i == NULL) { - mutex_unlock(&hash_mutex); - return -ENOMEM; - } - spin_lock_init(&i->lock); - i->irq = up->port.irq; - hlist_add_head(&i->node, h); - } - mutex_unlock(&hash_mutex); + i = kzalloc(sizeof(*i), GFP_KERNEL); + if (i == NULL) + return ERR_PTR(-ENOMEM); - spin_lock_irq(&i->lock); + spin_lock_init(&i->lock); + i->irq = up->port.irq; + hash_add(irq_lists, &i->node, i->irq); - if (i->head) { - list_add(&up->list, i->head); - spin_unlock_irq(&i->lock); + return i; +} + +static int serial_link_irq_chain(struct uart_8250_port *up) +{ + struct irq_info *i; + int ret; + + i = serial_get_or_create_irq_info(up); + if (IS_ERR(i)) + return PTR_ERR(i); + + scoped_guard(spinlock_irq, &i->lock) { + if (i->head) { + list_add(&up->list, i->head); + + return 0; + } - ret = 0; - } else { INIT_LIST_HEAD(&up->list); i->head = &up->list; - spin_unlock_irq(&i->lock); - ret = request_irq(up->port.irq, serial8250_interrupt, - up->port.irqflags, up->port.name, i); - if (ret < 0) - serial_do_unlink(i, up); } + ret = request_irq(up->port.irq, serial8250_interrupt, up->port.irqflags, up->port.name, i); + if (ret < 0) + serial_do_unlink(i, up); + return ret; } static void serial_unlink_irq_chain(struct uart_8250_port *up) { - /* - * yes, some broken gcc emit "warning: 'i' may be used uninitialized" - * but no, we are not going to take a patch that assigns NULL below. - */ struct irq_info *i; - struct hlist_node *n; - struct hlist_head *h; - mutex_lock(&hash_mutex); + guard(mutex)(&hash_mutex); - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; + hash_for_each_possible(irq_lists, i, node, up->port.irq) + if (i->irq == up->port.irq) { + if (WARN_ON(i->head == NULL)) + return; - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } + if (list_empty(i->head)) + free_irq(up->port.irq, i); - BUG_ON(n == NULL); - BUG_ON(i->head == NULL); + serial_do_unlink(i, up); - if (list_empty(i->head)) - free_irq(up->port.irq, i); + return; + } - serial_do_unlink(i, up); - mutex_unlock(&hash_mutex); + WARN_ON(1); } /* @@ -256,7 +208,7 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) */ static void serial8250_timeout(struct timer_list *t) { - struct uart_8250_port *up = from_timer(up, t, timer); + struct uart_8250_port *up = timer_container_of(up, t, timer); up->port.handle_irq(&up->port); mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); @@ -264,11 +216,11 @@ static void serial8250_timeout(struct timer_list *t) static void serial8250_backup_timeout(struct timer_list *t) { - struct uart_8250_port *up = from_timer(up, t, timer); + struct uart_8250_port *up = timer_container_of(up, t, timer); unsigned int iir, ier = 0, lsr; unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Must disable interrupts or else we risk racing with the interrupt @@ -287,10 +239,10 @@ static void serial8250_backup_timeout(struct timer_list *t) * the "Diva" UART used on the management processor on many HP * ia64 and parisc boxes. */ - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + lsr = serial_lsr_in(up); if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && + (!kfifo_is_empty(&up->port.state->port.xmit_fifo) || + up->port.x_char) && (lsr & UART_LSR_THRE)) { iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); iir |= UART_IIR_THRI; @@ -302,17 +254,16 @@ static void serial8250_backup_timeout(struct timer_list *t) if (up->port.irq) serial_out(up, UART_IER, ier); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* Standard timer interval plus 0.2s to keep the port running */ mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port) + HZ / 5); } -static int univ8250_setup_irq(struct uart_8250_port *up) +static void univ8250_setup_timer(struct uart_8250_port *up) { struct uart_port *port = &up->port; - int retval = 0; /* * The above check will only give an accurate result the first time @@ -331,67 +282,37 @@ static int univ8250_setup_irq(struct uart_8250_port *up) * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ - if (!port->irq) { + if (!port->irq) mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else - retval = serial_link_irq_chain(up); - - return retval; } -static void univ8250_release_irq(struct uart_8250_port *up) +static int univ8250_setup_irq(struct uart_8250_port *up) { struct uart_port *port = &up->port; - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; if (port->irq) - serial_unlink_irq_chain(up); -} - -#ifdef CONFIG_SERIAL_8250_RSA -static int serial8250_request_rsa_resource(struct uart_8250_port *up) -{ - unsigned long start = UART_RSA_BASE << up->port.regshift; - unsigned int size = 8 << up->port.regshift; - struct uart_port *port = &up->port; - int ret = -EINVAL; - - switch (port->iotype) { - case UPIO_HUB6: - case UPIO_PORT: - start += port->iobase; - if (request_region(start, size, "serial-rsa")) - ret = 0; - else - ret = -EBUSY; - break; - } + return serial_link_irq_chain(up); - return ret; + return 0; } -static void serial8250_release_rsa_resource(struct uart_8250_port *up) +static void univ8250_release_irq(struct uart_8250_port *up) { - unsigned long offset = UART_RSA_BASE << up->port.regshift; - unsigned int size = 8 << up->port.regshift; struct uart_port *port = &up->port; - switch (port->iotype) { - case UPIO_HUB6: - case UPIO_PORT: - release_region(port->iobase + offset, size); - break; - } + timer_delete_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (port->irq) + serial_unlink_irq_chain(up); } -#endif -static const struct uart_ops *base_ops; -static struct uart_ops univ8250_port_ops; +const struct uart_ops *univ8250_port_base_ops; +struct uart_ops univ8250_port_ops; static const struct uart_8250_ops univ8250_driver_ops = { .setup_irq = univ8250_setup_irq, .release_irq = univ8250_release_irq, + .setup_timer = univ8250_setup_timer, }; static struct uart_8250_port serial8250_ports[UART_NR]; @@ -414,149 +335,37 @@ struct uart_8250_port *serial8250_get_port(int line) } EXPORT_SYMBOL_GPL(serial8250_get_port); -static void (*serial8250_isa_config)(int port, struct uart_port *up, - u32 *capabilities); - -void serial8250_set_isa_configurator( - void (*v)(int port, struct uart_port *up, u32 *capabilities)) -{ - serial8250_isa_config = v; -} -EXPORT_SYMBOL(serial8250_set_isa_configurator); - -#ifdef CONFIG_SERIAL_8250_RSA - -static void univ8250_config_port(struct uart_port *port, int flags) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - up->probe &= ~UART_PROBE_RSA; - if (port->type == PORT_RSA) { - if (serial8250_request_rsa_resource(up) == 0) - up->probe |= UART_PROBE_RSA; - } else if (flags & UART_CONFIG_TYPE) { - int i; - - for (i = 0; i < probe_rsa_count; i++) { - if (probe_rsa[i] == up->port.iobase) { - if (serial8250_request_rsa_resource(up) == 0) - up->probe |= UART_PROBE_RSA; - break; - } - } - } - - base_ops->config_port(port, flags); - - if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA) - serial8250_release_rsa_resource(up); -} - -static int univ8250_request_port(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - int ret; - - ret = base_ops->request_port(port); - if (ret == 0 && port->type == PORT_RSA) { - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - base_ops->release_port(port); - } - - return ret; -} - -static void univ8250_release_port(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - if (port->type == PORT_RSA) - serial8250_release_rsa_resource(up); - base_ops->release_port(port); -} - -static void univ8250_rsa_support(struct uart_ops *ops) -{ - ops->config_port = univ8250_config_port; - ops->request_port = univ8250_request_port; - ops->release_port = univ8250_release_port; -} - -#else -#define univ8250_rsa_support(x) do { } while (0) -#endif /* CONFIG_SERIAL_8250_RSA */ - static inline void serial8250_apply_quirks(struct uart_8250_port *up) { up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0; } -static void __init serial8250_isa_init_ports(void) +struct uart_8250_port *serial8250_setup_port(int index) { struct uart_8250_port *up; - static int first = 1; - int i, irqflag = 0; - if (!first) - return; - first = 0; + if (index >= UART_NR) + return NULL; - if (nr_uarts > UART_NR) - nr_uarts = UART_NR; + up = &serial8250_ports[index]; + up->port.line = index; + up->port.port_id = index; - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - struct uart_port *port = &up->port; + serial8250_init_port(up); + if (!univ8250_port_base_ops) + univ8250_port_base_ops = up->port.ops; + up->port.ops = &univ8250_port_ops; - port->line = i; - serial8250_init_port(up); - if (!base_ops) - base_ops = port->ops; - port->ops = &univ8250_port_ops; + timer_setup(&up->timer, serial8250_timeout, 0); - timer_setup(&up->timer, serial8250_timeout, 0); + up->ops = &univ8250_driver_ops; - up->ops = &univ8250_driver_ops; + serial8250_set_defaults(up); - /* - * ALPHA_KLUDGE_MCR needs to be killed. - */ - up->mcr_mask = ~ALPHA_KLUDGE_MCR; - up->mcr_force = ALPHA_KLUDGE_MCR; - } - - /* chain base port ops to support Remote Supervisor Adapter */ - univ8250_port_ops = *base_ops; - univ8250_rsa_support(&univ8250_port_ops); - - if (share_irqs) - irqflag = IRQF_SHARED; - - for (i = 0, up = serial8250_ports; - i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; - i++, up++) { - struct uart_port *port = &up->port; - - port->iobase = old_serial_port[i].port; - port->irq = irq_canonicalize(old_serial_port[i].irq); - port->irqflags = 0; - port->uartclk = old_serial_port[i].baud_base * 16; - port->flags = old_serial_port[i].flags; - port->hub6 = 0; - port->membase = old_serial_port[i].iomem_base; - port->iotype = old_serial_port[i].io_type; - port->regshift = old_serial_port[i].iomem_reg_shift; - serial8250_set_defaults(up); - - port->irqflags |= irqflag; - if (serial8250_isa_config != NULL) - serial8250_isa_config(i, &up->port, &up->capabilities); - } + return up; } -static void __init -serial8250_register_ports(struct uart_driver *drv, struct device *dev) +void __init serial8250_register_ports(struct uart_driver *drv, struct device *dev) { int i; @@ -571,6 +380,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) up->port.dev = dev; + if (uart_console_registered(&up->port)) + pm_runtime_get_sync(up->port.dev); + serial8250_apply_quirks(up); uart_add_one_port(drv, &up->port); } @@ -588,23 +400,36 @@ static void univ8250_console_write(struct console *co, const char *s, static int univ8250_console_setup(struct console *co, char *options) { + struct uart_8250_port *up; struct uart_port *port; - int retval; + int retval, i; /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support. */ - if (co->index >= nr_uarts) + if (co->index < 0 || co->index >= UART_NR) co->index = 0; + + /* + * If the console is past the initial isa ports, init more ports up to + * co->index as needed and increment nr_uarts accordingly. + */ + for (i = nr_uarts; i <= co->index; i++) { + up = serial8250_setup_port(i); + if (!up) + return -ENODEV; + nr_uarts++; + } + port = &serial8250_ports[co->index].port; /* link port to console */ - port->cons = co; + uart_port_set_cons(port, co); retval = serial8250_console_setup(port, options, false); if (retval != 0) - port->cons = NULL; + uart_port_set_cons(port, NULL); return retval; } @@ -638,7 +463,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, char *options) { char match[] = "uart"; /* 8250-specific earlycon name */ - unsigned char iotype; + enum uart_iotype iotype; resource_size_t addr; int i; @@ -662,7 +487,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, continue; co->index = i; - port->cons = co; + uart_port_set_cons(port, co); return serial8250_console_setup(port, options, true); } @@ -697,7 +522,7 @@ console_initcall(univ8250_console_init); #define SERIAL8250_CONSOLE NULL #endif -static struct uart_driver serial8250_reg = { +struct uart_driver serial8250_reg = { .owner = THIS_MODULE, .driver_name = "serial", .dev_name = "ttyS", @@ -762,6 +587,7 @@ void serial8250_suspend_port(int line) if (!console_suspend_enabled && uart_console(port) && port->type != PORT_8250) { unsigned char canary = 0xa5; + serial_out(up, UART_SCR, canary); if (serial_in(up, UART_SCR) == canary) up->canary = canary; @@ -798,124 +624,13 @@ void serial8250_resume_port(int line) EXPORT_SYMBOL(serial8250_resume_port); /* - * Register a set of serial devices attached to a platform device. The - * list is terminated with a zero flags entry, which means we expect - * all entries to have at least UPF_BOOT_AUTOCONF set. - */ -static int serial8250_probe(struct platform_device *dev) -{ - struct plat_serial8250_port *p = dev_get_platdata(&dev->dev); - struct uart_8250_port uart; - int ret, i, irqflag = 0; - - memset(&uart, 0, sizeof(uart)); - - if (share_irqs) - irqflag = IRQF_SHARED; - - for (i = 0; p && p->flags != 0; p++, i++) { - uart.port.iobase = p->iobase; - uart.port.membase = p->membase; - uart.port.irq = p->irq; - uart.port.irqflags = p->irqflags; - uart.port.uartclk = p->uartclk; - uart.port.regshift = p->regshift; - uart.port.iotype = p->iotype; - uart.port.flags = p->flags; - uart.port.mapbase = p->mapbase; - uart.port.hub6 = p->hub6; - uart.port.has_sysrq = p->has_sysrq; - uart.port.private_data = p->private_data; - uart.port.type = p->type; - uart.port.serial_in = p->serial_in; - uart.port.serial_out = p->serial_out; - uart.port.handle_irq = p->handle_irq; - uart.port.handle_break = p->handle_break; - uart.port.set_termios = p->set_termios; - uart.port.set_ldisc = p->set_ldisc; - uart.port.get_mctrl = p->get_mctrl; - uart.port.pm = p->pm; - uart.port.dev = &dev->dev; - uart.port.irqflags |= irqflag; - ret = serial8250_register_8250_port(&uart); - if (ret < 0) { - dev_err(&dev->dev, "unable to register port at index %d " - "(IO%lx MEM%llx IRQ%d): %d\n", i, - p->iobase, (unsigned long long)p->mapbase, - p->irq, ret); - } - } - return 0; -} - -/* - * Remove serial ports registered against a platform device. - */ -static int serial8250_remove(struct platform_device *dev) -{ - int i; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.dev == &dev->dev) - serial8250_unregister_port(i); - } - return 0; -} - -static int serial8250_suspend(struct platform_device *dev, pm_message_t state) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_suspend_port(&serial8250_reg, &up->port); - } - - return 0; -} - -static int serial8250_resume(struct platform_device *dev) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - serial8250_resume_port(i); - } - - return 0; -} - -static struct platform_driver serial8250_isa_driver = { - .probe = serial8250_probe, - .remove = serial8250_remove, - .suspend = serial8250_suspend, - .resume = serial8250_resume, - .driver = { - .name = "serial8250", - }, -}; - -/* - * This "device" covers _all_ ISA 8250-compatible serial devices listed - * in the table in include/asm/serial.h - */ -static struct platform_device *serial8250_isa_devs; - -/* * serial8250_register_8250_port and serial8250_unregister_port allows for * 16x50 serial ports to be configured at run-time, to support PCMCIA * modems and PCI multiport cards. */ static DEFINE_MUTEX(serial_mutex); -static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) +static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_port *port) { int i; @@ -954,17 +669,12 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * static void serial_8250_overrun_backoff_work(struct work_struct *work) { - struct uart_8250_port *up = - container_of(to_delayed_work(work), struct uart_8250_port, - overrun_backoff); - struct uart_port *port = &up->port; - unsigned long flags; + struct uart_8250_port *up = container_of(to_delayed_work(work), struct uart_8250_port, + overrun_backoff); - spin_lock_irqsave(&port->lock, flags); + guard(uart_port_lock_irqsave)(&up->port); up->ier |= UART_IER_RLSI | UART_IER_RDI; - up->port.read_status_mask |= UART_LSR_DR; serial_out(up, UART_IER, up->ier); - spin_unlock_irqrestore(&port->lock, flags); } /** @@ -980,149 +690,168 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) * * On success the port is ready to use and the line number is returned. */ -int serial8250_register_8250_port(struct uart_8250_port *up) +int serial8250_register_8250_port(const struct uart_8250_port *up) { struct uart_8250_port *uart; - int ret = -ENOSPC; + int ret; if (up->port.uartclk == 0) return -EINVAL; - mutex_lock(&serial_mutex); + guard(mutex)(&serial_mutex); uart = serial8250_find_match_or_unused(&up->port); - if (uart && uart->port.type != PORT_8250_CIR) { - struct mctrl_gpios *gpios; - - if (uart->port.dev) - uart_remove_one_port(&serial8250_reg, &uart->port); - - uart->port.iobase = up->port.iobase; - uart->port.membase = up->port.membase; - uart->port.irq = up->port.irq; - uart->port.irqflags = up->port.irqflags; - uart->port.uartclk = up->port.uartclk; - uart->port.fifosize = up->port.fifosize; - uart->port.regshift = up->port.regshift; - uart->port.iotype = up->port.iotype; - uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; - uart->bugs = up->bugs; - uart->port.mapbase = up->port.mapbase; - uart->port.mapsize = up->port.mapsize; - uart->port.private_data = up->port.private_data; - uart->tx_loadsz = up->tx_loadsz; - uart->capabilities = up->capabilities; - uart->port.throttle = up->port.throttle; - uart->port.unthrottle = up->port.unthrottle; - uart->port.rs485_config = up->port.rs485_config; - uart->port.rs485 = up->port.rs485; - uart->rs485_start_tx = up->rs485_start_tx; - uart->rs485_stop_tx = up->rs485_stop_tx; - uart->dma = up->dma; - - /* Take tx_loadsz from fifosize if it wasn't set separately */ - if (uart->port.fifosize && !uart->tx_loadsz) - uart->tx_loadsz = uart->port.fifosize; - - if (up->port.dev) { - uart->port.dev = up->port.dev; - ret = uart_get_rs485_mode(&uart->port); - if (ret) - goto err; - } - - if (up->port.flags & UPF_FIXED_TYPE) - uart->port.type = up->port.type; - + if (!uart) { /* - * Only call mctrl_gpio_init(), if the device has no ACPI - * companion device + * If the port is past the initial isa ports, initialize a new + * port and increment nr_uarts accordingly. */ - if (!has_acpi_companion(uart->port.dev)) { - gpios = mctrl_gpio_init(&uart->port, 0); - if (IS_ERR(gpios)) { - ret = PTR_ERR(gpios); - goto err; - } else { - uart->gpios = gpios; - } - } + uart = serial8250_setup_port(nr_uarts); + if (!uart) + return -ENOSPC; + nr_uarts++; + } - serial8250_set_defaults(uart); - - /* Possibly override default I/O functions. */ - if (up->port.serial_in) - uart->port.serial_in = up->port.serial_in; - if (up->port.serial_out) - uart->port.serial_out = up->port.serial_out; - if (up->port.handle_irq) - uart->port.handle_irq = up->port.handle_irq; - /* Possibly override set_termios call */ - if (up->port.set_termios) - uart->port.set_termios = up->port.set_termios; - if (up->port.set_ldisc) - uart->port.set_ldisc = up->port.set_ldisc; - if (up->port.get_mctrl) - uart->port.get_mctrl = up->port.get_mctrl; - if (up->port.set_mctrl) - uart->port.set_mctrl = up->port.set_mctrl; - if (up->port.get_divisor) - uart->port.get_divisor = up->port.get_divisor; - if (up->port.set_divisor) - uart->port.set_divisor = up->port.set_divisor; - if (up->port.startup) - uart->port.startup = up->port.startup; - if (up->port.shutdown) - uart->port.shutdown = up->port.shutdown; - if (up->port.pm) - uart->port.pm = up->port.pm; - if (up->port.handle_break) - uart->port.handle_break = up->port.handle_break; - if (up->dl_read) - uart->dl_read = up->dl_read; - if (up->dl_write) - uart->dl_write = up->dl_write; - - if (uart->port.type != PORT_8250_CIR) { - if (serial8250_isa_config != NULL) - serial8250_isa_config(0, &uart->port, - &uart->capabilities); - - serial8250_apply_quirks(uart); - ret = uart_add_one_port(&serial8250_reg, - &uart->port); - if (ret) - goto err; - - ret = uart->port.line; - } else { - dev_info(uart->port.dev, - "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n", - uart->port.iobase, - (unsigned long long)uart->port.mapbase, - uart->port.irq); + /* Check if it is CIR already. We check this below again, see there why. */ + if (uart->port.type == PORT_8250_CIR) + return -ENODEV; - ret = 0; - } + if (uart->port.dev) + uart_remove_one_port(&serial8250_reg, &uart->port); + + uart->port.ctrl_id = up->port.ctrl_id; + uart->port.port_id = up->port.port_id; + uart->port.iobase = up->port.iobase; + uart->port.membase = up->port.membase; + uart->port.irq = up->port.irq; + uart->port.irqflags = up->port.irqflags; + uart->port.uartclk = up->port.uartclk; + uart->port.fifosize = up->port.fifosize; + uart->port.regshift = up->port.regshift; + uart->port.iotype = up->port.iotype; + uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; + uart->bugs = up->bugs; + uart->port.mapbase = up->port.mapbase; + uart->port.mapsize = up->port.mapsize; + uart->port.private_data = up->port.private_data; + uart->tx_loadsz = up->tx_loadsz; + uart->capabilities = up->capabilities; + uart->port.throttle = up->port.throttle; + uart->port.unthrottle = up->port.unthrottle; + uart->port.rs485_config = up->port.rs485_config; + uart->port.rs485_supported = up->port.rs485_supported; + uart->port.rs485 = up->port.rs485; + uart->rs485_start_tx = up->rs485_start_tx; + uart->rs485_stop_tx = up->rs485_stop_tx; + uart->lsr_save_mask = up->lsr_save_mask; + uart->dma = up->dma; + + /* Take tx_loadsz from fifosize if it wasn't set separately */ + if (uart->port.fifosize && !uart->tx_loadsz) + uart->tx_loadsz = uart->port.fifosize; + + if (up->port.dev) { + uart->port.dev = up->port.dev; + ret = uart_get_rs485_mode(&uart->port); + if (ret) + goto err; + } - /* Initialise interrupt backoff work if required */ - if (up->overrun_backoff_time_ms > 0) { - uart->overrun_backoff_time_ms = - up->overrun_backoff_time_ms; - INIT_DELAYED_WORK(&uart->overrun_backoff, - serial_8250_overrun_backoff_work); + if (up->port.flags & UPF_FIXED_TYPE) + uart->port.type = up->port.type; + + /* + * Only call mctrl_gpio_init(), if the device has no ACPI + * companion device + */ + if (!has_acpi_companion(uart->port.dev)) { + struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0); + if (IS_ERR(gpios)) { + ret = PTR_ERR(gpios); + goto err; } else { - uart->overrun_backoff_time_ms = 0; + uart->gpios = gpios; } } - mutex_unlock(&serial_mutex); + serial8250_set_defaults(uart); + + /* Possibly override default I/O functions. */ + if (up->port.serial_in) + uart->port.serial_in = up->port.serial_in; + if (up->port.serial_out) + uart->port.serial_out = up->port.serial_out; + if (up->port.handle_irq) + uart->port.handle_irq = up->port.handle_irq; + /* Possibly override set_termios call */ + if (up->port.set_termios) + uart->port.set_termios = up->port.set_termios; + if (up->port.set_ldisc) + uart->port.set_ldisc = up->port.set_ldisc; + if (up->port.get_mctrl) + uart->port.get_mctrl = up->port.get_mctrl; + if (up->port.set_mctrl) + uart->port.set_mctrl = up->port.set_mctrl; + if (up->port.get_divisor) + uart->port.get_divisor = up->port.get_divisor; + if (up->port.set_divisor) + uart->port.set_divisor = up->port.set_divisor; + if (up->port.startup) + uart->port.startup = up->port.startup; + if (up->port.shutdown) + uart->port.shutdown = up->port.shutdown; + if (up->port.pm) + uart->port.pm = up->port.pm; + if (up->port.handle_break) + uart->port.handle_break = up->port.handle_break; + if (up->dl_read) + uart->dl_read = up->dl_read; + if (up->dl_write) + uart->dl_write = up->dl_write; + + /* Check the type (again)! It might have changed by the port.type assignment above. */ + if (uart->port.type != PORT_8250_CIR) { + if (uart_console_registered(&uart->port)) + pm_runtime_get_sync(uart->port.dev); + + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, + &uart->capabilities); + + serial8250_apply_quirks(uart); + ret = uart_add_one_port(&serial8250_reg, + &uart->port); + if (ret) + goto err; + + ret = uart->port.line; + } else { + dev_info(uart->port.dev, + "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n", + uart->port.iobase, + (unsigned long long)uart->port.mapbase, + uart->port.irq); + + ret = 0; + } + + if (!uart->lsr_save_mask) + uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */ + + /* Initialise interrupt backoff work if required */ + if (up->overrun_backoff_time_ms > 0) { + uart->overrun_backoff_time_ms = + up->overrun_backoff_time_ms; + INIT_DELAYED_WORK(&uart->overrun_backoff, + serial_8250_overrun_backoff_work); + } else { + uart->overrun_backoff_time_ms = 0; + } return ret; err: uart->port.dev = NULL; - mutex_unlock(&serial_mutex); return ret; } EXPORT_SYMBOL(serial8250_register_8250_port); @@ -1138,14 +867,11 @@ void serial8250_unregister_port(int line) { struct uart_8250_port *uart = &serial8250_ports[line]; - mutex_lock(&serial_mutex); + guard(mutex)(&serial_mutex); if (uart->em485) { - unsigned long flags; - - spin_lock_irqsave(&uart->port.lock, flags); + guard(uart_port_lock_irqsave)(&uart->port); serial8250_em485_destroy(uart); - spin_unlock_irqrestore(&uart->port.lock, flags); } uart_remove_one_port(&serial8250_reg, &uart->port); @@ -1153,144 +879,16 @@ void serial8250_unregister_port(int line) uart->port.flags &= ~UPF_BOOT_AUTOCONF; uart->port.type = PORT_UNKNOWN; uart->port.dev = &serial8250_isa_devs->dev; + uart->port.port_id = line; uart->capabilities = 0; + serial8250_init_port(uart); serial8250_apply_quirks(uart); uart_add_one_port(&serial8250_reg, &uart->port); } else { uart->port.dev = NULL; } - mutex_unlock(&serial_mutex); } EXPORT_SYMBOL(serial8250_unregister_port); -static int __init serial8250_init(void) -{ - int ret; - - if (nr_uarts == 0) - return -ENODEV; - - serial8250_isa_init_ports(); - - pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n", - nr_uarts, share_irqs ? "en" : "dis"); - -#ifdef CONFIG_SPARC - ret = sunserial_register_minors(&serial8250_reg, UART_NR); -#else - serial8250_reg.nr = UART_NR; - ret = uart_register_driver(&serial8250_reg); -#endif - if (ret) - goto out; - - ret = serial8250_pnp_init(); - if (ret) - goto unreg_uart_drv; - - serial8250_isa_devs = platform_device_alloc("serial8250", - PLAT8250_DEV_LEGACY); - if (!serial8250_isa_devs) { - ret = -ENOMEM; - goto unreg_pnp; - } - - ret = platform_device_add(serial8250_isa_devs); - if (ret) - goto put_dev; - - serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); - - ret = platform_driver_register(&serial8250_isa_driver); - if (ret == 0) - goto out; - - platform_device_del(serial8250_isa_devs); -put_dev: - platform_device_put(serial8250_isa_devs); -unreg_pnp: - serial8250_pnp_exit(); -unreg_uart_drv: -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else - uart_unregister_driver(&serial8250_reg); -#endif -out: - return ret; -} - -static void __exit serial8250_exit(void) -{ - struct platform_device *isa_dev = serial8250_isa_devs; - - /* - * This tells serial8250_unregister_port() not to re-register - * the ports (thereby making serial8250_isa_driver permanently - * in use.) - */ - serial8250_isa_devs = NULL; - - platform_driver_unregister(&serial8250_isa_driver); - platform_device_unregister(isa_dev); - - serial8250_pnp_exit(); - -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else - uart_unregister_driver(&serial8250_reg); -#endif -} - -module_init(serial8250_init); -module_exit(serial8250_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); - -module_param_hw(share_irqs, uint, other, 0644); -MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)"); - -module_param(nr_uarts, uint, 0644); -MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); - -module_param(skip_txen_test, uint, 0644); -MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); - -#ifdef CONFIG_SERIAL_8250_RSA -module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444); -MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); -#endif -MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); - -#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS -#ifndef MODULE -/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name - * working as well for the module options so we don't break people. We - * need to keep the names identical and the convenient macros will happily - * refuse to let us do that by failing the build with redefinition errors - * of global variables. So we stick them inside a dummy function to avoid - * those conflicts. The options still get parsed, and the redefined - * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive. - * - * This is hacky. I'm sorry. - */ -static void __used s8250_options(void) -{ -#undef MODULE_PARAM_PREFIX -#define MODULE_PARAM_PREFIX "8250_core." - - module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644); - module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644); - module_param_cb(skip_txen_test, ¶m_ops_uint, &skip_txen_test, 0644); -#ifdef CONFIG_SERIAL_8250_RSA - __module_param_call(MODULE_PARAM_PREFIX, probe_rsa, - ¶m_array_ops, .arr = &__param_arr_probe_rsa, - 0444, -1, 0); -#endif -} -#else -MODULE_ALIAS("8250_core"); -#endif -#endif diff --git a/drivers/tty/serial/8250/8250_dfl.c b/drivers/tty/serial/8250/8250_dfl.c new file mode 100644 index 000000000000..6c5ff019df4b --- /dev/null +++ b/drivers/tty/serial/8250/8250_dfl.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA UART + * + * Copyright (C) 2022 Intel Corporation. + * + * Authors: + * Ananda Ravuri <ananda.ravuri@intel.com> + * Matthew Gerlach <matthew.gerlach@linux.intel.com> + */ + +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/dfl.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/types.h> + +#include <linux/serial.h> +#include <linux/serial_8250.h> + +#define DFHv1_PARAM_ID_CLK_FRQ 0x2 +#define DFHv1_PARAM_ID_FIFO_LEN 0x3 + +#define DFHv1_PARAM_ID_REG_LAYOUT 0x4 +#define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32) +#define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0) + +struct dfl_uart { + int line; +}; + +static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval) +{ + size_t psize; + u64 *p; + + p = dfh_find_param(dfl_dev, param_id, &psize); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (psize != sizeof(*pval)) + return -EINVAL; + + *pval = *p; + + return 0; +} + +static int dfl_uart_get_params(struct dfl_device *dfl_dev, struct uart_8250_port *uart) +{ + struct device *dev = &dfl_dev->dev; + u64 fifo_len, clk_freq, reg_layout; + u32 reg_width; + int ret; + + ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_CLK_FRQ, &clk_freq); + if (ret) + return dev_err_probe(dev, ret, "missing CLK_FRQ param\n"); + + uart->port.uartclk = clk_freq; + + ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_FIFO_LEN, &fifo_len); + if (ret) + return dev_err_probe(dev, ret, "missing FIFO_LEN param\n"); + + switch (fifo_len) { + case 32: + uart->port.type = PORT_ALTR_16550_F32; + break; + + case 64: + uart->port.type = PORT_ALTR_16550_F64; + break; + + case 128: + uart->port.type = PORT_ALTR_16550_F128; + break; + + default: + return dev_err_probe(dev, -EINVAL, "unsupported FIFO_LEN %llu\n", fifo_len); + } + + ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_REG_LAYOUT, ®_layout); + if (ret) + return dev_err_probe(dev, ret, "missing REG_LAYOUT param\n"); + + uart->port.regshift = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_SHIFT, reg_layout); + reg_width = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_WIDTH, reg_layout); + switch (reg_width) { + case 4: + uart->port.iotype = UPIO_MEM32; + break; + + case 2: + uart->port.iotype = UPIO_MEM16; + break; + + default: + return dev_err_probe(dev, -EINVAL, "unsupported reg-width %u\n", reg_width); + + } + + return 0; +} + +static int dfl_uart_probe(struct dfl_device *dfl_dev) +{ + struct device *dev = &dfl_dev->dev; + struct uart_8250_port uart = { }; + struct dfl_uart *dfluart; + int ret; + + uart.port.flags = UPF_IOREMAP; + uart.port.mapbase = dfl_dev->mmio_res.start; + uart.port.mapsize = resource_size(&dfl_dev->mmio_res); + + ret = dfl_uart_get_params(dfl_dev, &uart); + if (ret < 0) + return dev_err_probe(dev, ret, "failed uart feature walk\n"); + + if (dfl_dev->num_irqs == 1) + uart.port.irq = dfl_dev->irqs[0]; + + dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL); + if (!dfluart) + return -ENOMEM; + + dfluart->line = serial8250_register_8250_port(&uart); + if (dfluart->line < 0) + return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n"); + + dev_set_drvdata(dev, dfluart); + + return 0; +} + +static void dfl_uart_remove(struct dfl_device *dfl_dev) +{ + struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev); + + serial8250_unregister_port(dfluart->line); +} + +#define FME_FEATURE_ID_UART 0x24 + +static const struct dfl_device_id dfl_uart_ids[] = { + { FME_ID, FME_FEATURE_ID_UART }, + { } +}; +MODULE_DEVICE_TABLE(dfl, dfl_uart_ids); + +static struct dfl_driver dfl_uart_driver = { + .drv = { + .name = "dfl-uart", + }, + .id_table = dfl_uart_ids, + .probe = dfl_uart_probe, + .remove = dfl_uart_remove, +}; +module_dfl_driver(dfl_uart_driver); + +MODULE_DESCRIPTION("DFL Intel UART driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 890fa7ddaa7f..bdd26c9f34bd 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -15,72 +15,116 @@ static void __dma_tx_complete(void *param) { struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; unsigned long flags; int ret; dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); - spin_lock_irqsave(&p->port.lock, flags); + uart_port_lock_irqsave(&p->port, &flags); dma->tx_running = 0; - xmit->tail += dma->tx_size; - xmit->tail &= UART_XMIT_SIZE - 1; - p->port.icount.tx += dma->tx_size; + uart_xmit_advance(&p->port, dma->tx_size); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&p->port); ret = serial8250_tx_dma(p); - if (ret) + if (ret || !dma->tx_running) serial8250_set_THRI(p); - spin_unlock_irqrestore(&p->port.lock, flags); + uart_port_unlock_irqrestore(&p->port, flags); } -static void __dma_rx_complete(void *param) +static void __dma_rx_complete(struct uart_8250_port *p) { - struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_tx_state state; + enum dma_status dma_status; int count; - dma->rx_running = 0; - dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + /* + * New DMA Rx can be started during the completion handler before it + * could acquire port's lock and it might still be ongoing. Don't to + * anything in such case. + */ + dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + if (dma_status == DMA_IN_PROGRESS) + return; count = dma->rx_size - state.residue; tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += count; + dma->rx_running = 0; tty_flip_buffer_push(tty_port); } +static void dma_rx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + unsigned long flags; + + uart_port_lock_irqsave(&p->port, &flags); + if (dma->rx_running) + __dma_rx_complete(p); + + /* + * Cannot be combined with the previous check because __dma_rx_complete() + * changes dma->rx_running. + */ + if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR)) + p->dma->rx_dma(p); + uart_port_unlock_irqrestore(&p->port, flags); +} + int serial8250_tx_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; struct dma_async_tx_descriptor *desc; + struct uart_port *up = &p->port; + struct scatterlist *sg; + struct scatterlist sgl[2]; + int i; int ret; - if (dma->tx_running) + if (dma->tx_running) { + if (up->x_char) { + dmaengine_pause(dma->txchan); + uart_xchar_out(up, UART_TX); + dmaengine_resume(dma->txchan); + } return 0; + } else if (up->x_char) { + uart_xchar_out(up, UART_TX); + } - if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { + if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) { /* We have been called from __dma_tx_complete() */ - serial8250_rpm_put_tx(p); return 0; } - dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + serial8250_do_prepare_tx_dma(p); - desc = dmaengine_prep_slave_single(dma->txchan, - dma->tx_addr + xmit->tail, - dma->tx_size, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + sg_init_table(sgl, ARRAY_SIZE(sgl)); + + ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, sgl, ARRAY_SIZE(sgl), + UART_XMIT_SIZE, dma->tx_addr); + + dma->tx_size = 0; + + for_each_sg(sgl, sg, ret, i) + dma->tx_size += sg_dma_len(sg); + + desc = dmaengine_prep_slave_sg(dma->txchan, sgl, ret, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { ret = -EBUSY; goto err; @@ -96,16 +140,31 @@ int serial8250_tx_dma(struct uart_8250_port *p) UART_XMIT_SIZE, DMA_TO_DEVICE); dma_async_issue_pending(dma->txchan); - if (dma->tx_err) { - dma->tx_err = 0; - serial8250_clear_THRI(p); - } + serial8250_clear_THRI(p); + dma->tx_err = 0; + return 0; err: dma->tx_err = 1; return ret; } +void serial8250_tx_dma_flush(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (!dma->tx_running) + return; + + /* + * kfifo_reset() has been called by the serial core, avoid + * advancing and underflowing in __dma_tx_complete(). + */ + dma->tx_size = 0; + + dmaengine_terminate_async(dma->txchan); +} + int serial8250_rx_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; @@ -114,6 +173,8 @@ int serial8250_rx_dma(struct uart_8250_port *p) if (dma->rx_running) return 0; + serial8250_do_prepare_rx_dma(p); + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -121,7 +182,7 @@ int serial8250_rx_dma(struct uart_8250_port *p) return -EBUSY; dma->rx_running = 1; - desc->callback = __dma_rx_complete; + desc->callback = dma_rx_complete; desc->callback_param = p; dma->rx_cookie = dmaengine_submit(desc); @@ -218,7 +279,7 @@ int serial8250_request_dma(struct uart_8250_port *p) /* TX buffer */ dma->tx_addr = dma_map_single(dma->txchan->device->dev, - p->port.state->xmit.buf, + p->port.state->port.xmit_buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index aab3cccc6789..27af83f0ff46 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -9,40 +9,70 @@ * LCR is written whilst busy. If it is, then a busy detect interrupt is * raised, the LCR needs to be rewritten and the uart status register read. */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/io.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/serial_8250.h> -#include <linux/serial_reg.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> +#include <linux/notifier.h> #include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/acpi.h> -#include <linux/clk.h> -#include <linux/reset.h> #include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/reset.h> +#include <linux/slab.h> +#include <linux/workqueue.h> #include <asm/byteorder.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> + #include "8250_dwlib.h" /* Offsets for the DesignWare specific registers */ #define DW_UART_USR 0x1f /* UART Status Register */ +#define DW_UART_DMASA 0xa8 /* DMA Software Ack */ + +#define OCTEON_UART_USR 0x27 /* UART Status Register */ + +#define RZN1_UART_TDMACR 0x10c /* DMA Control Register Transmit Mode */ +#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */ /* DesignWare specific register fields */ #define DW_UART_MCR_SIRE BIT(6) +/* Renesas specific register fields */ +#define RZN1_UART_xDMACR_DMA_EN BIT(0) +#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1) +#define RZN1_UART_xDMACR_4_WORD_BURST (1 << 1) +#define RZN1_UART_xDMACR_8_WORD_BURST (2 << 1) +#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3) + +/* Quirks */ +#define DW_UART_QUIRK_OCTEON BIT(0) +#define DW_UART_QUIRK_ARMADA_38X BIT(1) +#define DW_UART_QUIRK_SKIP_SET_RATE BIT(2) +#define DW_UART_QUIRK_IS_DMA_FC BIT(3) +#define DW_UART_QUIRK_APMC0D08 BIT(4) +#define DW_UART_QUIRK_CPR_VALUE BIT(5) + +struct dw8250_platform_data { + u8 usr_reg; + u32 cpr_value; + unsigned int quirks; +}; + struct dw8250_data { struct dw8250_port_data data; + const struct dw8250_platform_data *pdata; - u8 usr_reg; - int msr_mask_on; - int msr_mask_off; + u32 msr_mask_on; + u32 msr_mask_off; struct clk *clk; struct clk *pclk; + struct notifier_block clk_notifier; + struct work_struct clk_work; struct reset_control *rst; unsigned int skip_autocfg:1; @@ -54,7 +84,17 @@ static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) return container_of(data, struct dw8250_data, data); } -static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) +static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) +{ + return container_of(nb, struct dw8250_data, clk_notifier); +} + +static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work) +{ + return container_of(work, struct dw8250_data, clk_work); +} + +static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u32 value) { struct dw8250_data *d = to_dw8250_data(p->private_data); @@ -67,22 +107,56 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) return value; } +/* + * This function is being called as part of the uart_port::serial_out() + * routine. Hence, it must not call serial_port_out() or serial_out() + * against the modified registers here, i.e. LCR. + */ static void dw8250_force_idle(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); + unsigned int lsr; + /* + * The following call currently performs serial_out() + * against the FCR register. Because it differs to LCR + * there will be no infinite loop, but if it ever gets + * modified, we might need a new custom version of it + * that avoids infinite recursion. + */ serial8250_clear_and_reinit_fifos(up); - (void)p->serial_in(p, UART_RX); + + /* + * With PSLVERR_RESP_EN parameter set to 1, the device generates an + * error response when an attempt to read an empty RBR with FIFO + * enabled. + */ + if (up->fcr & UART_FCR_ENABLE_FIFO) { + lsr = serial_port_in(p, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return; + } + + serial_port_in(p, UART_RX); } -static void dw8250_check_lcr(struct uart_port *p, int value) +/* + * This function is being called as part of the uart_port::serial_out() + * routine. Hence, it must not call serial_port_out() or serial_out() + * against the modified registers here, i.e. LCR. + */ +static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value) { - void __iomem *offset = p->membase + (UART_LCR << p->regshift); + struct dw8250_data *d = to_dw8250_data(p->private_data); + void __iomem *addr = p->membase + (offset << p->regshift); int tries = 1000; + if (offset != UART_LCR || d->uart_16550_compatible) + return; + /* Make sure LCR write wasn't ignored */ while (tries--) { - unsigned int lcr = p->serial_in(p, UART_LCR); + u32 lcr = serial_port_in(p, offset); if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) return; @@ -91,15 +165,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value) #ifdef CONFIG_64BIT if (p->type == PORT_OCTEON) - __raw_writeq(value & 0xff, offset); + __raw_writeq(value & 0xff, addr); else #endif if (p->iotype == UPIO_MEM32) - writel(value, offset); + writel(value, addr); else if (p->iotype == UPIO_MEM32BE) - iowrite32be(value, offset); + iowrite32be(value, addr); else - writeb(value, offset); + writeb(value, addr); } /* * FIXME: this deadlocks if port->lock is already held @@ -110,12 +184,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value) /* Returns once the transmitter is empty or we run out of retries */ static void dw8250_tx_wait_empty(struct uart_port *p) { + struct uart_8250_port *up = up_to_u8250p(p); unsigned int tries = 20000; unsigned int delay_threshold = tries - 1000; unsigned int lsr; while (tries--) { lsr = readb (p->membase + (UART_LSR << p->regshift)); + up->lsr_saved_flags |= lsr & up->lsr_save_mask; + if (lsr & UART_LSR_TEMT) break; @@ -128,92 +205,69 @@ static void dw8250_tx_wait_empty(struct uart_port *p) } } -static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) +static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - - /* Allow the TX to drain before we reconfigure */ - if (offset == UART_LCR) - dw8250_tx_wait_empty(p); - writeb(value, p->membase + (offset << p->regshift)); - - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } - -static void dw8250_serial_out(struct uart_port *p, int offset, int value) +static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - - writeb(value, p->membase + (offset << p->regshift)); + /* Allow the TX to drain before we reconfigure */ + if (offset == UART_LCR) + dw8250_tx_wait_empty(p); - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_serial_out(p, offset, value); } -static unsigned int dw8250_serial_in(struct uart_port *p, int offset) +static u32 dw8250_serial_in(struct uart_port *p, unsigned int offset) { - unsigned int value = readb(p->membase + (offset << p->regshift)); + u32 value = readb(p->membase + (offset << p->regshift)); return dw8250_modify_msr(p, offset, value); } #ifdef CONFIG_64BIT -static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) +static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset) { - unsigned int value; - - value = (u8)__raw_readq(p->membase + (offset << p->regshift)); + u8 value = __raw_readq(p->membase + (offset << p->regshift)); return dw8250_modify_msr(p, offset, value); } -static void dw8250_serial_outq(struct uart_port *p, int offset, int value) +static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - value &= 0xff; __raw_writeq(value, p->membase + (offset << p->regshift)); /* Read back to ensure register write ordering. */ __raw_readq(p->membase + (UART_LCR << p->regshift)); - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } #endif /* CONFIG_64BIT */ -static void dw8250_serial_out32(struct uart_port *p, int offset, int value) +static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - writel(value, p->membase + (offset << p->regshift)); - - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } -static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) +static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset) { - unsigned int value = readl(p->membase + (offset << p->regshift)); + u32 value = readl(p->membase + (offset << p->regshift)); return dw8250_modify_msr(p, offset, value); } -static void dw8250_serial_out32be(struct uart_port *p, int offset, int value) +static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - iowrite32be(value, p->membase + (offset << p->regshift)); - - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } -static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset) +static u32 dw8250_serial_in32be(struct uart_port *p, unsigned int offset) { - unsigned int value = ioread32be(p->membase + (offset << p->regshift)); + u32 value = ioread32be(p->membase + (offset << p->regshift)); return dw8250_modify_msr(p, offset, value); } @@ -223,7 +277,9 @@ static int dw8250_handle_irq(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); struct dw8250_data *d = to_dw8250_data(p->private_data); - unsigned int iir = p->serial_in(p, UART_IIR); + unsigned int iir = serial_port_in(p, UART_IIR); + bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT; + unsigned int quirks = d->pdata->quirks; unsigned int status; unsigned long flags; @@ -237,14 +293,26 @@ static int dw8250_handle_irq(struct uart_port *p) * This problem has only been observed so far when not in DMA mode * so we limit the workaround only to non-DMA mode. */ - if (!up->dma && ((iir & 0x3f) == UART_IIR_RX_TIMEOUT)) { - spin_lock_irqsave(&p->lock, flags); - status = p->serial_in(p, UART_LSR); + if (!up->dma && rx_timeout) { + uart_port_lock_irqsave(p, &flags); + status = serial_lsr_in(up); if (!(status & (UART_LSR_DR | UART_LSR_BI))) - (void) p->serial_in(p, UART_RX); + serial_port_in(p, UART_RX); + + uart_port_unlock_irqrestore(p, flags); + } + + /* Manually stop the Rx DMA transfer when acting as flow controller */ + if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) { + uart_port_lock_irqsave(p, &flags); + status = serial_lsr_in(up); + uart_port_unlock_irqrestore(p, flags); - spin_unlock_irqrestore(&p->lock, flags); + if (status & (UART_LSR_DR | UART_LSR_BI)) { + dw8250_writel_ext(p, RZN1_UART_RDMACR, 0); + dw8250_writel_ext(p, DW_UART_DMASA, 1); + } } if (serial8250_handle_irq(p, iir)) @@ -252,7 +320,7 @@ static int dw8250_handle_irq(struct uart_port *p) if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { /* Clear the USR */ - (void)p->serial_in(p, d->usr_reg); + serial_port_in(p, d->pdata->usr_reg); return 1; } @@ -260,6 +328,46 @@ static int dw8250_handle_irq(struct uart_port *p) return 0; } +static void dw8250_clk_work_cb(struct work_struct *work) +{ + struct dw8250_data *d = work_to_dw8250_data(work); + struct uart_8250_port *up; + unsigned long rate; + + rate = clk_get_rate(d->clk); + if (rate <= 0) + return; + + up = serial8250_get_port(d->data.line); + + serial8250_update_uartclk(&up->port, rate); +} + +static int dw8250_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct dw8250_data *d = clk_to_dw8250_data(nb); + + /* + * We have no choice but to defer the uartclk update due to two + * deadlocks. First one is caused by a recursive mutex lock which + * happens when clk_set_rate() is called from dw8250_set_termios(). + * Second deadlock is more tricky and is caused by an inverted order of + * the clk and tty-port mutexes lock. It happens if clock rate change + * is requested asynchronously while set_termios() is executed between + * tty-port mutex lock and clk_set_rate() function invocation and + * vise-versa. Anyway if we didn't have the reference clock alteration + * in the dw8250_set_termios() method we wouldn't have needed this + * deferred event handling complication. + */ + if (event == POST_RATE_CHANGE) { + queue_work(system_dfl_wq, &d->clk_work); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + static void dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { @@ -273,40 +381,33 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) } static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - unsigned int baud = tty_termios_baud_rate(termios); + unsigned long newrate = tty_termios_baud_rate(termios) * 16; struct dw8250_data *d = to_dw8250_data(p->private_data); long rate; int ret; clk_disable_unprepare(d->clk); - rate = clk_round_rate(d->clk, baud * 16); - if (rate < 0) - ret = rate; - else if (rate == 0) - ret = -ENOENT; - else - ret = clk_set_rate(d->clk, rate); + rate = clk_round_rate(d->clk, newrate); + if (rate > 0) { + /* + * Note that any clock-notifier worker will block in + * serial8250_update_uartclk() until we are done. + */ + ret = clk_set_rate(d->clk, newrate); + if (!ret) + p->uartclk = rate; + } clk_prepare_enable(d->clk); - if (ret) - goto out; - - p->uartclk = rate; - -out: - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); + dw8250_do_set_termios(p, termios, old); } static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) { struct uart_8250_port *up = up_to_u8250p(p); - unsigned int mcr = p->serial_in(p, UART_MCR); + unsigned int mcr = serial_port_in(p, UART_MCR); if (up->capabilities & UART_CAP_IRDA) { if (termios->c_line == N_IRDA) @@ -314,7 +415,7 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) else mcr &= ~DW_UART_MCR_SIRE; - p->serial_out(p, UART_MCR, mcr); + serial_port_out(p, UART_MCR, mcr); } serial8250_do_set_ldisc(p, termios); } @@ -337,108 +438,151 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) return param == chan->device->dev; } +static void dw8250_setup_dma_filter(struct uart_port *p, struct dw8250_data *data) +{ + /* Platforms with iDMA 64-bit */ + if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) { + data->data.dma.rx_param = p->dev->parent; + data->data.dma.tx_param = p->dev->parent; + data->data.dma.fn = dw8250_idma_filter; + } else { + data->data.dma.fn = dw8250_fallback_dma_filter; + } +} + +static u32 dw8250_rzn1_get_dmacr_burst(int max_burst) +{ + if (max_burst >= 8) + return RZN1_UART_xDMACR_8_WORD_BURST; + else if (max_burst >= 4) + return RZN1_UART_xDMACR_4_WORD_BURST; + else + return RZN1_UART_xDMACR_1_WORD_BURST; +} + +static void dw8250_prepare_tx_dma(struct uart_8250_port *p) +{ + struct uart_port *up = &p->port; + struct uart_8250_dma *dma = p->dma; + u32 val; + + dw8250_writel_ext(up, RZN1_UART_TDMACR, 0); + val = dw8250_rzn1_get_dmacr_burst(dma->txconf.dst_maxburst) | + RZN1_UART_xDMACR_BLK_SZ(dma->tx_size) | + RZN1_UART_xDMACR_DMA_EN; + dw8250_writel_ext(up, RZN1_UART_TDMACR, val); +} + +static void dw8250_prepare_rx_dma(struct uart_8250_port *p) +{ + struct uart_port *up = &p->port; + struct uart_8250_dma *dma = p->dma; + u32 val; + + dw8250_writel_ext(up, RZN1_UART_RDMACR, 0); + val = dw8250_rzn1_get_dmacr_burst(dma->rxconf.src_maxburst) | + RZN1_UART_xDMACR_BLK_SZ(dma->rx_size) | + RZN1_UART_xDMACR_DMA_EN; + dw8250_writel_ext(up, RZN1_UART_RDMACR, val); +} + static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { - if (p->dev->of_node) { - struct device_node *np = p->dev->of_node; - int id; + unsigned int quirks = data->pdata->quirks; + u32 cpr_value = data->pdata->cpr_value; + + if (quirks & DW_UART_QUIRK_CPR_VALUE) + data->data.cpr_value = cpr_value; - /* get index of serial line, if found in DT aliases */ - id = of_alias_get_id(np, "serial"); - if (id >= 0) - p->line = id; #ifdef CONFIG_64BIT - if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { - p->serial_in = dw8250_serial_inq; - p->serial_out = dw8250_serial_outq; - p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - p->type = PORT_OCTEON; - data->usr_reg = 0x27; - data->skip_autocfg = true; - } + if (quirks & DW_UART_QUIRK_OCTEON) { + p->serial_in = dw8250_serial_inq; + p->serial_out = dw8250_serial_outq; + p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + p->type = PORT_OCTEON; + data->skip_autocfg = true; + } #endif - if (of_device_is_big_endian(p->dev->of_node)) { - p->iotype = UPIO_MEM32BE; - p->serial_in = dw8250_serial_in32be; - p->serial_out = dw8250_serial_out32be; - } - if (of_device_is_compatible(np, "marvell,armada-38x-uart")) - p->serial_out = dw8250_serial_out38x; - } else if (acpi_dev_present("APMC0D08", NULL, -1)) { + if (quirks & DW_UART_QUIRK_ARMADA_38X) + p->serial_out = dw8250_serial_out38x; + if (quirks & DW_UART_QUIRK_SKIP_SET_RATE) + p->set_termios = dw8250_do_set_termios; + if (quirks & DW_UART_QUIRK_IS_DMA_FC) { + data->data.dma.txconf.device_fc = 1; + data->data.dma.rxconf.device_fc = 1; + data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma; + data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma; + } + if (quirks & DW_UART_QUIRK_APMC0D08) { p->iotype = UPIO_MEM32; p->regshift = 2; p->serial_in = dw8250_serial_in32; data->uart_16550_compatible = true; } +} - /* Platforms with iDMA 64-bit */ - if (platform_get_resource_byname(to_platform_device(p->dev), - IORESOURCE_MEM, "lpss_priv")) { - data->data.dma.rx_param = p->dev->parent; - data->data.dma.tx_param = p->dev->parent; - data->data.dma.fn = dw8250_idma_filter; - } +static void dw8250_reset_control_assert(void *data) +{ + reset_control_assert(data); } static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}, *up = &uart; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct uart_port *p = &up->port; struct device *dev = &pdev->dev; struct dw8250_data *data; - int irq; + struct resource *regs; int err; - u32 val; - if (!regs) { - dev_err(dev, "no registers defined\n"); - return -EINVAL; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return dev_err_probe(dev, -EINVAL, "no registers defined\n"); spin_lock_init(&p->lock); - p->mapbase = regs->start; - p->irq = irq; - p->handle_irq = dw8250_handle_irq; p->pm = dw8250_do_pm; p->type = PORT_8250; - p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; + p->flags = UPF_FIXED_PORT; p->dev = dev; - p->iotype = UPIO_MEM; - p->serial_in = dw8250_serial_in; - p->serial_out = dw8250_serial_out; p->set_ldisc = dw8250_set_ldisc; p->set_termios = dw8250_set_termios; - p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); - if (!p->membase) - return -ENOMEM; - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->data.dma.fn = dw8250_fallback_dma_filter; - data->usr_reg = DW_UART_USR; p->private_data = &data->data; - data->uart_16550_compatible = device_property_read_bool(dev, - "snps,uart-16550-compatible"); + p->mapbase = regs->start; + p->mapsize = resource_size(regs); - err = device_property_read_u32(dev, "reg-shift", &val); - if (!err) - p->regshift = val; + p->membase = devm_ioremap(dev, p->mapbase, p->mapsize); + if (!p->membase) + return -ENOMEM; - err = device_property_read_u32(dev, "reg-io-width", &val); - if (!err && val == 4) { - p->iotype = UPIO_MEM32; + err = uart_read_port_properties(p); + /* no interrupt -> fall back to polling */ + if (err == -ENXIO) + err = 0; + if (err) + return err; + + switch (p->iotype) { + case UPIO_MEM: + p->serial_in = dw8250_serial_in; + p->serial_out = dw8250_serial_out; + break; + case UPIO_MEM32: p->serial_in = dw8250_serial_in32; p->serial_out = dw8250_serial_out32; + break; + case UPIO_MEM32BE: + p->serial_in = dw8250_serial_in32be; + p->serial_out = dw8250_serial_out32be; + break; + default: + return -ENODEV; } if (device_property_read_bool(dev, "dcd-override")) { @@ -465,54 +609,53 @@ static int dw8250_probe(struct platform_device *pdev) data->msr_mask_off |= UART_MSR_TERI; } - /* Always ask for fixed clock rate from a property. */ - device_property_read_u32(dev, "clock-frequency", &p->uartclk); - /* If there is separate baudclk, get the rate from it. */ - data->clk = devm_clk_get_optional(dev, "baudclk"); + data->clk = devm_clk_get_optional_enabled(dev, "baudclk"); if (data->clk == NULL) - data->clk = devm_clk_get_optional(dev, NULL); + data->clk = devm_clk_get_optional_enabled(dev, NULL); if (IS_ERR(data->clk)) - return PTR_ERR(data->clk); + return dev_err_probe(dev, PTR_ERR(data->clk), + "failed to get baudclk\n"); - err = clk_prepare_enable(data->clk); - if (err) - dev_warn(dev, "could not enable optional baudclk: %d\n", err); + INIT_WORK(&data->clk_work, dw8250_clk_work_cb); + data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; if (data->clk) p->uartclk = clk_get_rate(data->clk); /* If no clock rate is defined, fail. */ - if (!p->uartclk) { - dev_err(dev, "clock rate not defined\n"); - err = -EINVAL; - goto err_clk; - } + if (!p->uartclk) + return dev_err_probe(dev, -EINVAL, "clock rate not defined\n"); - data->pclk = devm_clk_get_optional(dev, "apb_pclk"); - if (IS_ERR(data->pclk)) { - err = PTR_ERR(data->pclk); - goto err_clk; - } + data->pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); + if (IS_ERR(data->pclk)) + return PTR_ERR(data->pclk); - err = clk_prepare_enable(data->pclk); - if (err) { - dev_err(dev, "could not enable apb_pclk\n"); - goto err_clk; - } + data->rst = devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(data->rst)) + return PTR_ERR(data->rst); - data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(data->rst)) { - err = PTR_ERR(data->rst); - goto err_pclk; - } - reset_control_deassert(data->rst); + err = reset_control_deassert(data->rst); + if (err) + return dev_err_probe(dev, err, "failed to deassert resets\n"); + + err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst); + if (err) + return err; + + data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible"); - dw8250_quirks(p, data); + data->pdata = device_get_match_data(p->dev); + if (data->pdata) + dw8250_quirks(p, data); /* If the Busy Functionality is not implemented, don't handle it */ if (data->uart_16550_compatible) p->handle_irq = NULL; + else if (data->pdata) + p->handle_irq = dw8250_handle_irq; + + dw8250_setup_dma_filter(p, data); if (!data->skip_autocfg) dw8250_setup_port(p); @@ -525,9 +668,19 @@ static int dw8250_probe(struct platform_device *pdev) } data->data.line = serial8250_register_8250_port(up); - if (data->data.line < 0) { - err = data->data.line; - goto err_reset; + if (data->data.line < 0) + return data->data.line; + + /* + * Some platforms may provide a reference clock shared between several + * devices. In this case any clock state change must be known to the + * UART port at least post factum. + */ + if (data->clk) { + err = clk_notifier_register(data->clk, &data->clk_notifier); + if (err) + return dev_err_probe(dev, err, "Failed to set the clock notifier\n"); + queue_work(system_dfl_wq, &data->clk_work); } platform_set_drvdata(pdev, data); @@ -536,41 +689,27 @@ static int dw8250_probe(struct platform_device *pdev) pm_runtime_enable(dev); return 0; - -err_reset: - reset_control_assert(data->rst); - -err_pclk: - clk_disable_unprepare(data->pclk); - -err_clk: - clk_disable_unprepare(data->clk); - - return err; } -static int dw8250_remove(struct platform_device *pdev) +static void dw8250_remove(struct platform_device *pdev) { struct dw8250_data *data = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; pm_runtime_get_sync(dev); - serial8250_unregister_port(data->data.line); - - reset_control_assert(data->rst); + if (data->clk) { + clk_notifier_unregister(data->clk, &data->clk_notifier); - clk_disable_unprepare(data->pclk); + flush_work(&data->clk_work); + } - clk_disable_unprepare(data->clk); + serial8250_unregister_port(data->data.line); pm_runtime_disable(dev); pm_runtime_put_noidle(dev); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int dw8250_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -588,9 +727,7 @@ static int dw8250_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM static int dw8250_runtime_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -612,34 +749,67 @@ static int dw8250_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops dw8250_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume) - SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume) + RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL) +}; + +static const struct dw8250_platform_data dw8250_dw_apb = { + .usr_reg = DW_UART_USR, +}; + +static const struct dw8250_platform_data dw8250_octeon_3860_data = { + .usr_reg = OCTEON_UART_USR, + .quirks = DW_UART_QUIRK_OCTEON, +}; + +static const struct dw8250_platform_data dw8250_armada_38x_data = { + .usr_reg = DW_UART_USR, + .quirks = DW_UART_QUIRK_ARMADA_38X, +}; + +static const struct dw8250_platform_data dw8250_renesas_rzn1_data = { + .usr_reg = DW_UART_USR, + .cpr_value = 0x00012f32, + .quirks = DW_UART_QUIRK_CPR_VALUE | DW_UART_QUIRK_IS_DMA_FC, +}; + +static const struct dw8250_platform_data dw8250_skip_set_rate_data = { + .usr_reg = DW_UART_USR, + .quirks = DW_UART_QUIRK_SKIP_SET_RATE, }; static const struct of_device_id dw8250_of_match[] = { - { .compatible = "snps,dw-apb-uart" }, - { .compatible = "cavium,octeon-3860-uart" }, - { .compatible = "marvell,armada-38x-uart" }, - { .compatible = "renesas,rzn1-uart" }, + { .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb }, + { .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data }, + { .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data }, + { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data }, + { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data }, + { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dw8250_of_match); +static const struct dw8250_platform_data dw8250_apmc0d08 = { + .usr_reg = DW_UART_USR, + .quirks = DW_UART_QUIRK_APMC0D08, +}; + static const struct acpi_device_id dw8250_acpi_match[] = { - { "INT33C4", 0 }, - { "INT33C5", 0 }, - { "INT3434", 0 }, - { "INT3435", 0 }, - { "80860F0A", 0 }, - { "8086228A", 0 }, - { "APMC0D08", 0}, - { "AMD0020", 0 }, - { "AMDI0020", 0 }, - { "BRCM2032", 0 }, - { "HISI0031", 0 }, + { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb }, + { "8086228A", (kernel_ulong_t)&dw8250_dw_apb }, + { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb }, + { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb }, + { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb }, + { "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 }, + { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb }, + { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb }, + { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb }, + { "INT33C5", (kernel_ulong_t)&dw8250_dw_apb }, + { "INT3434", (kernel_ulong_t)&dw8250_dw_apb }, + { "INT3435", (kernel_ulong_t)&dw8250_dw_apb }, + { "INTC10EE", (kernel_ulong_t)&dw8250_dw_apb }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); @@ -647,9 +817,9 @@ MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); static struct platform_driver dw8250_platform_driver = { .driver = { .name = "dw-apb-uart", - .pm = &dw8250_pm_ops, + .pm = pm_ptr(&dw8250_pm_ops), .of_match_table = dw8250_of_match, - .acpi_match_table = ACPI_PTR(dw8250_acpi_match), + .acpi_match_table = dw8250_acpi_match, }, .probe = dw8250_probe, .remove = dw8250_remove, diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 6d6a78eead3e..b055d89cfb39 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -2,50 +2,65 @@ /* Synopsys DesignWare 8250 library. */ #include <linux/bitops.h> +#include <linux/bitfield.h> +#include <linux/delay.h> #include <linux/device.h> -#include <linux/io.h> #include <linux/kernel.h> +#include <linux/math.h> +#include <linux/property.h> #include <linux/serial_8250.h> #include <linux/serial_core.h> #include "8250_dwlib.h" /* Offsets for the DesignWare specific registers */ +#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */ +#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ +#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ #define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ +#define DW_UART_RAR 0xc4 /* Receive Address Register */ +#define DW_UART_TAR 0xc8 /* Transmit Address Register */ +#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_UCV 0xf8 /* UART Component Version */ -/* Component Parameter Register bits */ -#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) -#define DW_UART_CPR_AFCE_MODE (1 << 4) -#define DW_UART_CPR_THRE_MODE (1 << 5) -#define DW_UART_CPR_SIR_MODE (1 << 6) -#define DW_UART_CPR_SIR_LP_MODE (1 << 7) -#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) -#define DW_UART_CPR_FIFO_ACCESS (1 << 9) -#define DW_UART_CPR_FIFO_STAT (1 << 10) -#define DW_UART_CPR_SHADOW (1 << 11) -#define DW_UART_CPR_ENCODED_PARMS (1 << 12) -#define DW_UART_CPR_DMA_EXTRA (1 << 13) -#define DW_UART_CPR_FIFO_MODE (0xff << 16) +/* Receive / Transmit Address Register bits */ +#define DW_UART_ADDR_MASK GENMASK(7, 0) -/* Helper for FIFO size calculation */ -#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) +/* Line Status Register bits */ +#define DW_UART_LSR_ADDR_RCVD BIT(8) -static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) -{ - if (p->iotype == UPIO_MEM32BE) - return ioread32be(p->membase + offset); - return readl(p->membase + offset); -} +/* Transceiver Control Register bits */ +#define DW_UART_TCR_RS485_EN BIT(0) +#define DW_UART_TCR_RE_POL BIT(1) +#define DW_UART_TCR_DE_POL BIT(2) +#define DW_UART_TCR_XFER_MODE GENMASK(4, 3) +#define DW_UART_TCR_XFER_MODE_DE_DURING_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 0) +#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1) +#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2) -static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) -{ - if (p->iotype == UPIO_MEM32BE) - iowrite32be(reg, p->membase + offset); - else - writel(reg, p->membase + offset); -} +/* Line Extended Control Register bits */ +#define DW_UART_LCR_EXT_DLS_E BIT(0) +#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1) +#define DW_UART_LCR_EXT_SEND_ADDR BIT(2) +#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) + +/* Component Parameter Register bits */ +#define DW_UART_CPR_ABP_DATA_WIDTH GENMASK(1, 0) +#define DW_UART_CPR_AFCE_MODE BIT(4) +#define DW_UART_CPR_THRE_MODE BIT(5) +#define DW_UART_CPR_SIR_MODE BIT(6) +#define DW_UART_CPR_SIR_LP_MODE BIT(7) +#define DW_UART_CPR_ADDITIONAL_FEATURES BIT(8) +#define DW_UART_CPR_FIFO_ACCESS BIT(9) +#define DW_UART_CPR_FIFO_STAT BIT(10) +#define DW_UART_CPR_SHADOW BIT(11) +#define DW_UART_CPR_ENCODED_PARMS BIT(12) +#define DW_UART_CPR_DMA_EXTRA BIT(13) +#define DW_UART_CPR_FIFO_MODE GENMASK(23, 16) + +/* Helper for FIFO size calculation */ +#define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16) /* * divisor = div(I) + div(F) @@ -74,38 +89,197 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, unsigned int quot, unsigned int quot_frac) { dw8250_writel_ext(p, DW_UART_DLF, quot_frac); - serial8250_do_set_divisor(p, baud, quot, quot_frac); + serial8250_do_set_divisor(p, baud, quot); } -void dw8250_setup_port(struct uart_port *p) +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, + const struct ktermios *old) { - struct uart_8250_port *up = up_to_u8250p(p); - u32 reg; + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + + serial8250_do_set_termios(p, termios, old); + + /* Filter addresses which have 9th bit set */ + p->ignore_status_mask |= DW_UART_LSR_ADDR_RCVD; + p->read_status_mask |= DW_UART_LSR_ADDR_RCVD; +} +EXPORT_SYMBOL_GPL(dw8250_do_set_termios); + +/* + * Wait until re is de-asserted for sure. An ongoing receive will keep + * re asserted until end of frame. Without BUSY indication available, + * only available course of action is to wait for the time it takes to + * receive one frame (there might nothing to receive but w/o BUSY the + * driver cannot know). + */ +static void dw8250_wait_re_deassert(struct uart_port *p) +{ + ndelay(p->frame_time); +} + +static void dw8250_update_rar(struct uart_port *p, u32 addr) +{ + u32 re_en = dw8250_readl_ext(p, DW_UART_RE_EN); /* - * If the Component Version Register returns zero, we know that - * ADDITIONAL_FEATURES are not enabled. No need to go any further. + * RAR shouldn't be changed while receiving. Thus, de-assert RE_EN + * if asserted and wait. */ - reg = dw8250_readl_ext(p, DW_UART_UCV); - if (!reg) - return; + if (re_en) + dw8250_writel_ext(p, DW_UART_RE_EN, 0); + dw8250_wait_re_deassert(p); + dw8250_writel_ext(p, DW_UART_RAR, addr); + if (re_en) + dw8250_writel_ext(p, DW_UART_RE_EN, re_en); +} + +static void dw8250_rs485_set_addr(struct uart_port *p, struct serial_rs485 *rs485, + struct ktermios *termios) +{ + u32 lcr = dw8250_readl_ext(p, DW_UART_LCR_EXT); - dev_dbg(p->dev, "Designware UART version %c.%c%c\n", - (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + if (rs485->flags & SER_RS485_ADDRB) { + lcr |= DW_UART_LCR_EXT_DLS_E; + if (termios) + termios->c_cflag |= ADDRB; + if (rs485->flags & SER_RS485_ADDR_RECV) { + u32 delta = p->rs485.flags ^ rs485->flags; + + /* + * rs485 (param) is equal to uart_port's rs485 only during init + * (during init, delta is not yet applicable). + */ + if (unlikely(&p->rs485 == rs485)) + delta = rs485->flags; + + if ((delta & SER_RS485_ADDR_RECV) || + (p->rs485.addr_recv != rs485->addr_recv)) + dw8250_update_rar(p, rs485->addr_recv); + lcr |= DW_UART_LCR_EXT_ADDR_MATCH; + } else { + lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH; + } + if (rs485->flags & SER_RS485_ADDR_DEST) { + /* + * Don't skip writes here as another endpoint could + * have changed communication line's destination + * address in between. + */ + dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest); + lcr |= DW_UART_LCR_EXT_SEND_ADDR; + } + } else { + lcr = 0; + } + dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr); +} + +static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + u32 tcr; + + tcr = dw8250_readl_ext(p, DW_UART_TCR); + tcr &= ~DW_UART_TCR_XFER_MODE; + + if (rs485->flags & SER_RS485_ENABLED) { + tcr |= DW_UART_TCR_RS485_EN; + + if (rs485->flags & SER_RS485_RX_DURING_TX) + tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE; + else + tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE; + dw8250_writel_ext(p, DW_UART_DE_EN, 1); + dw8250_writel_ext(p, DW_UART_RE_EN, 1); + } else { + if (termios) + termios->c_cflag &= ~ADDRB; + + tcr &= ~DW_UART_TCR_RS485_EN; + } + + /* Reset to default polarity */ + tcr |= DW_UART_TCR_DE_POL; + tcr &= ~DW_UART_TCR_RE_POL; + + if (!(rs485->flags & SER_RS485_RTS_ON_SEND)) + tcr &= ~DW_UART_TCR_DE_POL; + if (device_property_read_bool(p->dev, "rs485-rx-active-high")) + tcr |= DW_UART_TCR_RE_POL; + + dw8250_writel_ext(p, DW_UART_TCR, tcr); + + /* Addressing mode can only be set up after TCR */ + if (rs485->flags & SER_RS485_ENABLED) + dw8250_rs485_set_addr(p, rs485, termios); + + return 0; +} + +/* + * Tests if RE_EN register can have non-zero value to see if RS-485 HW support + * is present. + */ +static bool dw8250_detect_rs485_hw(struct uart_port *p) +{ + u32 reg; + + dw8250_writel_ext(p, DW_UART_RE_EN, 1); + reg = dw8250_readl_ext(p, DW_UART_RE_EN); + dw8250_writel_ext(p, DW_UART_RE_EN, 0); + return reg; +} + +static const struct serial_rs485 dw8250_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND | SER_RS485_ADDRB | SER_RS485_ADDR_RECV | + SER_RS485_ADDR_DEST, +}; + +void dw8250_setup_port(struct uart_port *p) +{ + struct dw8250_port_data *pd = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); + u32 reg, old_dlf; + + pd->hw_rs485_support = dw8250_detect_rs485_hw(p); + if (pd->hw_rs485_support) { + p->rs485_config = dw8250_rs485_config; + up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD; + p->rs485_supported = dw8250_rs485_supported; + } else { + p->rs485_config = serial8250_em485_config; + p->rs485_supported = serial8250_em485_supported; + up->rs485_start_tx = serial8250_em485_start_tx; + up->rs485_stop_tx = serial8250_em485_stop_tx; + } + up->capabilities |= UART_CAP_NOTEMT; + + /* Preserve value written by firmware or bootloader */ + old_dlf = dw8250_readl_ext(p, DW_UART_DLF); dw8250_writel_ext(p, DW_UART_DLF, ~0U); reg = dw8250_readl_ext(p, DW_UART_DLF); - dw8250_writel_ext(p, DW_UART_DLF, 0); + dw8250_writel_ext(p, DW_UART_DLF, old_dlf); if (reg) { - struct dw8250_port_data *d = p->private_data; - - d->dlf_size = fls(reg); + pd->dlf_size = fls(reg); p->get_divisor = dw8250_get_divisor; p->set_divisor = dw8250_set_divisor; } + reg = dw8250_readl_ext(p, DW_UART_UCV); + if (reg) + dev_dbg(p->dev, "Designware UART version %c.%c%c\n", + (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + reg = dw8250_readl_ext(p, DW_UART_CPR); + if (!reg) { + reg = pd->cpr_value; + dev_dbg(p->dev, "CPR is not available, using 0x%08x instead\n", reg); + } if (!reg) return; @@ -114,7 +288,7 @@ void dw8250_setup_port(struct uart_port *p) p->type = PORT_16550A; p->flags |= UPF_FIXED_TYPE; p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); - up->capabilities = UART_CAP_FIFO; + up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT; } if (reg & DW_UART_CPR_AFCE_MODE) diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 9a12953832d3..7dd2a8e7b780 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* Synopsys DesignWare 8250 library header file. */ +#include <linux/io.h> #include <linux/types.h> #include "8250.h" @@ -13,7 +14,27 @@ struct dw8250_port_data { struct uart_8250_dma dma; /* Hardware configuration */ + u32 cpr_value; u8 dlf_size; + + /* RS485 variables */ + bool hw_rs485_support; }; +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old); void dw8250_setup_port(struct uart_port *p); + +static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) +{ + if (p->iotype == UPIO_MEM32BE) + return ioread32be(p->membase + offset); + return readl(p->membase + offset); +} + +static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) +{ + if (p->iotype == UPIO_MEM32BE) + iowrite32be(reg, p->membase + offset); + else + writel(reg, p->membase + offset); +} diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 70d7826788f5..dc0371857ecb 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -27,7 +27,6 @@ #include <linux/init.h> #include <linux/console.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/serial_8250.h> @@ -36,7 +35,6 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset) { - int reg_offset = offset; offset <<= port->regshift; switch (port->iotype) { @@ -48,10 +46,10 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset) return readl(port->membase + offset); case UPIO_MEM32BE: return ioread32be(port->membase + offset); +#ifdef CONFIG_HAS_IOPORT case UPIO_PORT: return inb(port->iobase + offset); - case UPIO_AU: - return port->serial_in(port, reg_offset); +#endif default: return 0; } @@ -59,7 +57,6 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset) static void serial8250_early_out(struct uart_port *port, int offset, int value) { - int reg_offset = offset; offset <<= port->regshift; switch (port->iotype) { @@ -75,18 +72,17 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value) case UPIO_MEM32BE: iowrite32be(value, port->membase + offset); break; +#ifdef CONFIG_HAS_IOPORT case UPIO_PORT: outb(value, port->iobase + offset); break; - case UPIO_AU: - port->serial_out(port, reg_offset, value); +#endif + default: break; } } -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static void serial_putc(struct uart_port *port, int c) +static void serial_putc(struct uart_port *port, unsigned char c) { unsigned int status; @@ -94,7 +90,7 @@ static void serial_putc(struct uart_port *port, int c) for (;;) { status = serial8250_early_in(port, UART_LSR); - if ((status & BOTH_EMPTY) == BOTH_EMPTY) + if (uart_lsr_tx_empty(status)) break; cpu_relax(); } @@ -138,11 +134,11 @@ static void __init init_port(struct earlycon_device *device) unsigned char c; unsigned int ier; - serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */ + serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */ ier = serial8250_early_in(port, UART_IER); serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */ serial8250_early_out(port, UART_FCR, 0); /* no fifo */ - serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */ + serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); if (port->uartclk) { divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); @@ -181,6 +177,17 @@ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); +static int __init early_serial8250_rs2_setup(struct earlycon_device *device, + const char *options) +{ + device->port.regshift = 2; + + return early_serial8250_setup(device, options); +} +OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup); +OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup); +OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup); + #ifdef CONFIG_SERIAL_8250_OMAP static int __init early_omap8250_setup(struct earlycon_device *device, @@ -199,22 +206,6 @@ static int __init early_omap8250_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup); OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup); OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup); - -#endif - -#ifdef CONFIG_SERIAL_8250_RT288X - -unsigned int au_serial_in(struct uart_port *p, int offset); -void au_serial_out(struct uart_port *p, int offset, int value); - -static int __init early_au_setup(struct earlycon_device *dev, const char *opt) -{ - dev->port.serial_in = au_serial_in; - dev->port.serial_out = au_serial_out; - dev->port.iotype = UPIO_AU; - dev->con->write = early_serial8250_write; - return 0; -} -OF_EARLYCON_DECLARE(palmchip, "ralink,rt2880-uart", early_au_setup); +OF_EARLYCON_DECLARE(omap8250, "ti,am654-uart", early_omap8250_setup); #endif diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 2a76e22d2ec0..e90c71494944 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -13,64 +13,138 @@ #include <linux/serial_reg.h> #include <linux/platform_device.h> #include <linux/clk.h> -#include <linux/slab.h> #include "8250.h" #define UART_DLL_EM 9 #define UART_DLM_EM 10 +#define UART_HCR0_EM 11 + +/* + * A high value for UART_FCR_EM avoids overlapping with existing UART_* + * register defines. UART_FCR_EM_HW is the real HW register offset. + */ +#define UART_FCR_EM 0x10003 +#define UART_FCR_EM_HW 3 + +#define UART_HCR0_EM_SW_RESET BIT(7) /* SW Reset */ struct serial8250_em_priv { - struct clk *sclk; int line; }; -static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) +static void serial8250_em_serial_out_helper(struct uart_port *p, int offset, + int value) { switch (offset) { case UART_TX: /* TX @ 0x00 */ writeb(value, p->membase); break; - case UART_FCR: /* FCR @ 0x0c (+1) */ case UART_LCR: /* LCR @ 0x10 (+1) */ case UART_MCR: /* MCR @ 0x14 (+1) */ case UART_SCR: /* SCR @ 0x20 (+1) */ writel(value, p->membase + ((offset + 1) << 2)); break; + case UART_FCR_EM: + writel(value, p->membase + (UART_FCR_EM_HW << 2)); + break; case UART_IER: /* IER @ 0x04 */ value &= 0x0f; /* only 4 valid bits - not Xscale */ - /* fall-through */ + fallthrough; case UART_DLL_EM: /* DLL @ 0x24 (+9) */ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ + case UART_HCR0_EM: /* HCR0 @ 0x2c */ writel(value, p->membase + (offset << 2)); + break; } } -static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset) +static u32 serial8250_em_serial_in(struct uart_port *p, unsigned int offset) { switch (offset) { case UART_RX: /* RX @ 0x00 */ return readb(p->membase); + case UART_LCR: /* LCR @ 0x10 (+1) */ case UART_MCR: /* MCR @ 0x14 (+1) */ case UART_LSR: /* LSR @ 0x18 (+1) */ case UART_MSR: /* MSR @ 0x1c (+1) */ case UART_SCR: /* SCR @ 0x20 (+1) */ return readl(p->membase + ((offset + 1) << 2)); + case UART_FCR_EM: + return readl(p->membase + (UART_FCR_EM_HW << 2)); case UART_IER: /* IER @ 0x04 */ case UART_IIR: /* IIR @ 0x08 */ case UART_DLL_EM: /* DLL @ 0x24 (+9) */ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ + case UART_HCR0_EM: /* HCR0 @ 0x2c */ return readl(p->membase + (offset << 2)); } return 0; } -static int serial8250_em_serial_dl_read(struct uart_8250_port *up) +static void serial8250_em_reg_update(struct uart_port *p, int off, int value) +{ + unsigned int ier, fcr, lcr, mcr, hcr0; + + ier = serial8250_em_serial_in(p, UART_IER); + fcr = serial8250_em_serial_in(p, UART_FCR_EM); + lcr = serial8250_em_serial_in(p, UART_LCR); + mcr = serial8250_em_serial_in(p, UART_MCR); + hcr0 = serial8250_em_serial_in(p, UART_HCR0_EM); + + serial8250_em_serial_out_helper(p, UART_FCR_EM, fcr | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0 | + UART_HCR0_EM_SW_RESET); + serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0 & + ~UART_HCR0_EM_SW_RESET); + + switch (off) { + case UART_FCR_EM: + fcr = value; + break; + case UART_LCR: + lcr = value; + break; + case UART_MCR: + mcr = value; + break; + } + + serial8250_em_serial_out_helper(p, UART_IER, ier); + serial8250_em_serial_out_helper(p, UART_FCR_EM, fcr); + serial8250_em_serial_out_helper(p, UART_MCR, mcr); + serial8250_em_serial_out_helper(p, UART_LCR, lcr); + serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0); +} + +static void serial8250_em_serial_out(struct uart_port *p, unsigned int offset, u32 value) +{ + switch (offset) { + case UART_TX: + case UART_SCR: + case UART_IER: + case UART_DLL_EM: + case UART_DLM_EM: + serial8250_em_serial_out_helper(p, offset, value); + break; + case UART_FCR: + serial8250_em_reg_update(p, UART_FCR_EM, value); + break; + case UART_LCR: + case UART_MCR: + serial8250_em_reg_update(p, offset, value); + break; + } +} + +static u32 serial8250_em_serial_dl_read(struct uart_8250_port *up) { return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8; } -static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) +static void serial8250_em_serial_dl_write(struct uart_8250_port *up, u32 value) { serial_out(up, UART_DLL_EM, value & 0xff); serial_out(up, UART_DLM_EM, value >> 8 & 0xff); @@ -78,37 +152,38 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) static int serial8250_em_probe(struct platform_device *pdev) { - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct serial8250_em_priv *priv; + struct device *dev = &pdev->dev; struct uart_8250_port up; - int ret; + struct resource *regs; + struct clk *sclk; + int irq, ret; - if (!regs || !irq) { - dev_err(&pdev->dev, "missing registers or irq\n"); - return -EINVAL; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return dev_err_probe(dev, -EINVAL, "missing registers\n"); - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->sclk = devm_clk_get(&pdev->dev, "sclk"); - if (IS_ERR(priv->sclk)) { - dev_err(&pdev->dev, "unable to get clock\n"); - return PTR_ERR(priv->sclk); - } + sclk = devm_clk_get_enabled(dev, "sclk"); + if (IS_ERR(sclk)) + return dev_err_probe(dev, PTR_ERR(sclk), "unable to get clock\n"); memset(&up, 0, sizeof(up)); up.port.mapbase = regs->start; - up.port.irq = irq->start; - up.port.type = PORT_UNKNOWN; - up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; - up.port.dev = &pdev->dev; + up.port.irq = irq; + up.port.type = PORT_16750; + up.port.flags = UPF_FIXED_PORT | UPF_IOREMAP | UPF_FIXED_TYPE; + up.port.dev = dev; up.port.private_data = priv; - clk_prepare_enable(priv->sclk); - up.port.uartclk = clk_get_rate(priv->sclk); + up.port.uartclk = clk_get_rate(sclk); up.port.iotype = UPIO_MEM32; up.port.serial_in = serial8250_em_serial_in; @@ -117,24 +192,19 @@ static int serial8250_em_probe(struct platform_device *pdev) up.dl_write = serial8250_em_serial_dl_write; ret = serial8250_register_8250_port(&up); - if (ret < 0) { - dev_err(&pdev->dev, "unable to register 8250 port\n"); - clk_disable_unprepare(priv->sclk); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "unable to register 8250 port\n"); priv->line = ret; platform_set_drvdata(pdev, priv); return 0; } -static int serial8250_em_remove(struct platform_device *pdev) +static void serial8250_em_remove(struct platform_device *pdev) { struct serial8250_em_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); - clk_disable_unprepare(priv->sclk); - return 0; } static const struct of_device_id serial8250_em_dt_ids[] = { diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index ddb6aeb76dc5..c682c0d0dffa 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -6,24 +6,31 @@ * * Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved. */ -#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/device.h> #include <linux/dmi.h> +#include <linux/eeprom_93cx6.h> +#include <linux/interrupt.h> #include <linux/io.h> -#include <linux/kernel.h> +#include <linux/math.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/property.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <linux/serial_8250.h> #include <linux/serial_core.h> #include <linux/serial_reg.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/tty.h> -#include <linux/8250_pci.h> -#include <linux/delay.h> #include <asm/byteorder.h> #include "8250.h" +#include "8250_pcilib.h" #define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052 #define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d @@ -33,6 +40,8 @@ #define PCI_DEVICE_ID_ACCESSIO_COM_4SM 0x10db #define PCI_DEVICE_ID_ACCESSIO_COM_8SM 0x10ea +#define PCI_DEVICE_ID_ADVANTECH_XR17V352 0x0018 + #define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002 #define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004 #define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a @@ -40,8 +49,54 @@ #define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020 #define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 + +#define PCI_VENDOR_ID_CONNECT_TECH 0x12c4 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_SP_OPTO 0x0340 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_A 0x0341 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_B 0x0342 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS 0x0350 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A 0x0351 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B 0x0352 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS 0x0353 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A 0x0354 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B 0x0355 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO 0x0360 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A 0x0361 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B 0x0362 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP 0x0370 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232 0x0371 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485 0x0372 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP 0x0373 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP 0x0374 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP 0x0375 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232_NS 0x0376 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT 0x0380 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT 0x0381 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO 0x0382 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO 0x0392 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP 0x03A0 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232 0x03A1 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485 0x03A2 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232_NS 0x03A3 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XEG001 0x0602 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_BASE 0x1000 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_2 0x1002 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_4 0x1004 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_8 0x1008 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_12 0x100C +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_16 0x1010 +#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X 0x110c +#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X 0x110d +#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16 0x1110 + #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define PCI_DEVICE_ID_EXAR_XR17V252 0x0252 +#define PCI_DEVICE_ID_EXAR_XR17V254 0x0254 +#define PCI_DEVICE_ID_EXAR_XR17V258 0x0258 + +#define PCI_SUBDEVICE_ID_USR_2980 0x0128 +#define PCI_SUBDEVICE_ID_USR_2981 0x0129 #define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ @@ -74,12 +129,26 @@ #define UART_EXAR_RS485_DLY(x) ((x) << 4) +#define UART_EXAR_DLD 0x02 /* Divisor Fractional */ +#define UART_EXAR_DLD_485_POLARITY 0x80 /* RS-485 Enable Signal Polarity */ + +/* EEPROM registers */ +#define UART_EXAR_REGB 0x8e +#define UART_EXAR_REGB_EECK BIT(4) +#define UART_EXAR_REGB_EECS BIT(5) +#define UART_EXAR_REGB_EEDI BIT(6) +#define UART_EXAR_REGB_EEDO BIT(7) + +#define UART_EXAR_XR17C15X_PORT_OFFSET 0x200 +#define UART_EXAR_XR17V25X_PORT_OFFSET 0x200 +#define UART_EXAR_XR17V35X_PORT_OFFSET 0x400 + /* * IOT2040 MPIO wiring semantics: * * MPIO Port Function * ---- ---- -------- - * 0 2 Mode bit 0 + * 0 2 Mode bit 0 * 1 2 Mode bit 1 * 2 2 Terminate bus * 3 - <reserved> @@ -109,35 +178,247 @@ #define IOT2040_UARTS_ENABLE 0x03 #define IOT2040_UARTS_GPIO_HI_MODE 0xF8 /* enable & LED as outputs */ +/* CTI EEPROM offsets */ +#define CTI_EE_OFF_XR17C15X_OSC_FREQ 0x04 /* 2 words */ +#define CTI_EE_OFF_XR17C15X_PART_NUM 0x0A /* 4 words */ +#define CTI_EE_OFF_XR17C15X_SERIAL_NUM 0x0E /* 1 word */ + +#define CTI_EE_OFF_XR17V25X_OSC_FREQ 0x08 /* 2 words */ +#define CTI_EE_OFF_XR17V25X_PART_NUM 0x0E /* 4 words */ +#define CTI_EE_OFF_XR17V25X_SERIAL_NUM 0x12 /* 1 word */ + +#define CTI_EE_OFF_XR17V35X_SERIAL_NUM 0x11 /* 2 word */ +#define CTI_EE_OFF_XR17V35X_BRD_FLAGS 0x13 /* 1 word */ +#define CTI_EE_OFF_XR17V35X_PORT_FLAGS 0x14 /* 1 word */ + +#define CTI_EE_MASK_PORT_FLAGS_TYPE GENMASK(7, 0) +#define CTI_EE_MASK_OSC_FREQ GENMASK(31, 0) + +#define CTI_FPGA_RS485_IO_REG 0x2008 +#define CTI_FPGA_CFG_INT_EN_REG 0x48 +#define CTI_FPGA_CFG_INT_EN_EXT_BIT BIT(15) /* External int enable bit */ + +#define CTI_DEFAULT_PCI_OSC_FREQ 29491200 +#define CTI_DEFAULT_PCIE_OSC_FREQ 125000000 +#define CTI_DEFAULT_FPGA_OSC_FREQ 33333333 + +/* + * CTI Serial port line types. These match the values stored in the first + * nibble of the CTI EEPROM port_flags word. + */ +enum cti_port_type { + CTI_PORT_TYPE_NONE = 0, + CTI_PORT_TYPE_RS232, // RS232 ONLY + CTI_PORT_TYPE_RS422_485, // RS422/RS485 ONLY + CTI_PORT_TYPE_RS232_422_485_HW, // RS232/422/485 HW ONLY Switchable + CTI_PORT_TYPE_RS232_422_485_SW, // RS232/422/485 SW ONLY Switchable + CTI_PORT_TYPE_RS232_422_485_4B, // RS232/422/485 HW/SW (4bit ex. BCG004) + CTI_PORT_TYPE_RS232_422_485_2B, // RS232/422/485 HW/SW (2bit ex. BBG008) + CTI_PORT_TYPE_MAX, +}; + +#define CTI_PORT_TYPE_VALID(_port_type) \ + (((_port_type) > CTI_PORT_TYPE_NONE) && \ + ((_port_type) < CTI_PORT_TYPE_MAX)) + +#define CTI_PORT_TYPE_RS485(_port_type) \ + (((_port_type) > CTI_PORT_TYPE_RS232) && \ + ((_port_type) < CTI_PORT_TYPE_MAX)) + struct exar8250; struct exar8250_platform { - int (*rs485_config)(struct uart_port *, struct serial_rs485 *); - int (*register_gpio)(struct pci_dev *, struct uart_8250_port *); + int (*rs485_config)(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485); + const struct serial_rs485 *rs485_supported; + int (*register_gpio)(struct pci_dev *pcidev, struct uart_8250_port *port); + void (*unregister_gpio)(struct uart_8250_port *port); }; /** * struct exar8250_board - board information * @num_ports: number of serial ports * @reg_shift: describes UART register mapping in PCI memory - * @setup: quirk run at ->probe() stage + * @setup: quirk run at ->probe() stage for each port * @exit: quirk run at ->remove() stage */ struct exar8250_board { unsigned int num_ports; unsigned int reg_shift; - int (*setup)(struct exar8250 *, struct pci_dev *, - struct uart_8250_port *, int); + int (*setup)(struct exar8250 *priv, struct pci_dev *pcidev, + struct uart_8250_port *port, int idx); void (*exit)(struct pci_dev *pcidev); }; struct exar8250 { unsigned int nr; + unsigned int osc_freq; struct exar8250_board *board; + struct eeprom_93cx6 eeprom; void __iomem *virt; int line[]; }; +static inline void exar_write_reg(struct exar8250 *priv, + unsigned int reg, u8 value) +{ + writeb(value, priv->virt + reg); +} + +static inline u8 exar_read_reg(struct exar8250 *priv, unsigned int reg) +{ + return readb(priv->virt + reg); +} + +static void exar_eeprom_93cx6_reg_read(struct eeprom_93cx6 *eeprom) +{ + struct exar8250 *priv = eeprom->data; + u8 regb = exar_read_reg(priv, UART_EXAR_REGB); + + /* EECK and EECS always read 0 from REGB so only set EEDO */ + eeprom->reg_data_out = regb & UART_EXAR_REGB_EEDO; +} + +static void exar_eeprom_93cx6_reg_write(struct eeprom_93cx6 *eeprom) +{ + struct exar8250 *priv = eeprom->data; + u8 regb = 0; + + if (eeprom->reg_data_in) + regb |= UART_EXAR_REGB_EEDI; + if (eeprom->reg_data_clock) + regb |= UART_EXAR_REGB_EECK; + if (eeprom->reg_chip_select) + regb |= UART_EXAR_REGB_EECS; + + exar_write_reg(priv, UART_EXAR_REGB, regb); +} + +static void exar_eeprom_init(struct exar8250 *priv) +{ + priv->eeprom.data = priv; + priv->eeprom.register_read = exar_eeprom_93cx6_reg_read; + priv->eeprom.register_write = exar_eeprom_93cx6_reg_write; + priv->eeprom.width = PCI_EEPROM_WIDTH_93C46; + priv->eeprom.quirks |= PCI_EEPROM_QUIRK_EXTRA_READ_CYCLE; +} + +/** + * exar_mpio_config_output() - Configure an Exar MPIO as an output + * @priv: Device's private structure + * @mpio_num: MPIO number/offset to configure + * + * Configure a single MPIO as an output and disable tristate. It is recommended + * to set the level with exar_mpio_set_high()/exar_mpio_set_low() prior to + * calling this function to ensure default MPIO pin state. + * + * Return: 0 on success, negative error code on failure + */ +static int exar_mpio_config_output(struct exar8250 *priv, + unsigned int mpio_num) +{ + unsigned int mpio_offset; + u8 sel_reg; // MPIO Select register (input/output) + u8 tri_reg; // MPIO Tristate register + u8 value; + + if (mpio_num < 8) { + sel_reg = UART_EXAR_MPIOSEL_7_0; + tri_reg = UART_EXAR_MPIO3T_7_0; + mpio_offset = mpio_num; + } else if (mpio_num >= 8 && mpio_num < 16) { + sel_reg = UART_EXAR_MPIOSEL_15_8; + tri_reg = UART_EXAR_MPIO3T_15_8; + mpio_offset = mpio_num - 8; + } else { + return -EINVAL; + } + + // Disable MPIO pin tri-state + value = exar_read_reg(priv, tri_reg); + value &= ~BIT(mpio_offset); + exar_write_reg(priv, tri_reg, value); + + value = exar_read_reg(priv, sel_reg); + value &= ~BIT(mpio_offset); + exar_write_reg(priv, sel_reg, value); + + return 0; +} + +/** + * _exar_mpio_set() - Set an Exar MPIO output high or low + * @priv: Device's private structure + * @mpio_num: MPIO number/offset to set + * @high: Set MPIO high if true, low if false + * + * Set a single MPIO high or low. exar_mpio_config_output() must also be called + * to configure the pin as an output. + * + * Return: 0 on success, negative error code on failure + */ +static int _exar_mpio_set(struct exar8250 *priv, + unsigned int mpio_num, bool high) +{ + unsigned int mpio_offset; + u8 lvl_reg; + u8 value; + + if (mpio_num < 8) { + lvl_reg = UART_EXAR_MPIOLVL_7_0; + mpio_offset = mpio_num; + } else if (mpio_num >= 8 && mpio_num < 16) { + lvl_reg = UART_EXAR_MPIOLVL_15_8; + mpio_offset = mpio_num - 8; + } else { + return -EINVAL; + } + + value = exar_read_reg(priv, lvl_reg); + if (high) + value |= BIT(mpio_offset); + else + value &= ~BIT(mpio_offset); + exar_write_reg(priv, lvl_reg, value); + + return 0; +} + +static int exar_mpio_set_low(struct exar8250 *priv, unsigned int mpio_num) +{ + return _exar_mpio_set(priv, mpio_num, false); +} + +static int exar_mpio_set_high(struct exar8250 *priv, unsigned int mpio_num) +{ + return _exar_mpio_set(priv, mpio_num, true); +} + +static int generic_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); + u8 __iomem *p = port->membase; + u8 value; + + value = readb(p + UART_EXAR_FCTR); + if (is_rs485) + value |= UART_FCTR_EXAR_485; + else + value &= ~UART_FCTR_EXAR_485; + + writeb(value, p + UART_EXAR_FCTR); + + if (is_rs485) + writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); + + return 0; +} + +static const struct serial_rs485 generic_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, +}; + static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old) { /* @@ -167,7 +448,7 @@ static unsigned int xr17v35x_get_divisor(struct uart_port *p, unsigned int baud, static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud, unsigned int quot, unsigned int quot_frac) { - serial8250_do_set_divisor(p, baud, quot, quot_frac); + serial8250_do_set_divisor(p, baud, quot); /* Preserve bits not related to baudrate; DLD[7:4]. */ quot_frac |= serial_port_in(p, 0x2) & 0xf0; @@ -183,21 +464,25 @@ static int xr17v35x_startup(struct uart_port *port) serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); /* - * Make sure all interrups are masked until initialization is + * Make sure all interrupts are masked until initialization is * complete and the FIFOs are cleared + * + * Synchronize UART_IER access against the console. */ + uart_port_lock_irq(port); serial_port_out(port, UART_IER, 0); + uart_port_unlock_irq(port); return serial8250_do_startup(port); } static void exar_shutdown(struct uart_port *port) { - unsigned char lsr; bool tx_complete = false; struct uart_8250_port *up = up_to_u8250p(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int i = 0; + u16 lsr; do { lsr = serial_in(up, UART_LSR); @@ -206,7 +491,8 @@ static void exar_shutdown(struct uart_port *port) else tx_complete = false; usleep_range(1000, 1100); - } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000); + } while (!kfifo_is_empty(&tport->xmit_fifo) && + !tx_complete && i++ < 1000); serial8250_do_shutdown(port); } @@ -216,13 +502,12 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port) { const struct exar8250_board *board = priv->board; - unsigned int bar = 0; unsigned char status; + int err; - port->port.iotype = UPIO_MEM; - port->port.mapbase = pci_resource_start(pcidev, bar) + offset; - port->port.membase = priv->virt + offset; - port->port.regshift = board->reg_shift; + err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift, priv->virt); + if (err) + return err; /* * XR17V35x UARTs have an extra divisor register, DLD that gets enabled @@ -271,41 +556,542 @@ pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev, writeb(32, p + UART_EXAR_TXTRG); writeb(32, p + UART_EXAR_RXTRG); + /* Skip the initial (per device) setup */ + if (idx) + return 0; + /* * Setup Multipurpose Input/Output pins. */ + switch (pcidev->device) { + case PCI_DEVICE_ID_COMMTECH_4222PCI335: + case PCI_DEVICE_ID_COMMTECH_4224PCI335: + writeb(0x78, p + UART_EXAR_MPIOLVL_7_0); + writeb(0x00, p + UART_EXAR_MPIOINV_7_0); + writeb(0x00, p + UART_EXAR_MPIOSEL_7_0); + break; + case PCI_DEVICE_ID_COMMTECH_2324PCI335: + case PCI_DEVICE_ID_COMMTECH_2328PCI335: + writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); + writeb(0xc0, p + UART_EXAR_MPIOINV_7_0); + writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0); + break; + default: + break; + } + writeb(0x00, p + UART_EXAR_MPIOINT_7_0); + writeb(0x00, p + UART_EXAR_MPIO3T_7_0); + writeb(0x00, p + UART_EXAR_MPIOOD_7_0); + + return 0; +} + +/** + * cti_tristate_disable() - Disable RS485 transciever tristate + * @priv: Device's private structure + * @port_num: Port number to set tristate off + * + * Most RS485 capable cards have a power on tristate jumper/switch that ensures + * the RS422/RS485 transceiver does not drive a multi-drop RS485 bus when it is + * not the master. When this jumper is installed the user must set the RS485 + * mode to Full or Half duplex to disable tristate prior to using the port. + * + * Some Exar UARTs have an auto-tristate feature while others require setting + * an MPIO to disable the tristate. + * + * Return: 0 on success, negative error code on failure + */ +static int cti_tristate_disable(struct exar8250 *priv, unsigned int port_num) +{ + int ret; + + ret = exar_mpio_set_high(priv, port_num); + if (ret) + return ret; + + return exar_mpio_config_output(priv, port_num); +} + +/** + * cti_plx_int_enable() - Enable UART interrupts to PLX bridge + * @priv: Device's private structure + * + * Some older CTI cards require MPIO_0 to be set low to enable the + * interrupts from the UART to the PLX PCI->PCIe bridge. + * + * Return: 0 on success, negative error code on failure + */ +static int cti_plx_int_enable(struct exar8250 *priv) +{ + int ret; + + ret = exar_mpio_set_low(priv, 0); + if (ret) + return ret; + + return exar_mpio_config_output(priv, 0); +} + +/** + * cti_read_osc_freq() - Read the UART oscillator frequency from EEPROM + * @priv: Device's private structure + * @eeprom_offset: Offset where the oscillator frequency is stored + * + * CTI XR17x15X and XR17V25X cards have the serial boards oscillator frequency + * stored in the EEPROM. FPGA and XR17V35X based cards use the PCI/PCIe clock. + * + * Return: frequency on success, negative error code on failure + */ +static int cti_read_osc_freq(struct exar8250 *priv, u8 eeprom_offset) +{ + __le16 ee_words[2]; + u32 osc_freq; + + eeprom_93cx6_multiread(&priv->eeprom, eeprom_offset, ee_words, ARRAY_SIZE(ee_words)); + + osc_freq = le16_to_cpu(ee_words[0]) | (le16_to_cpu(ee_words[1]) << 16); + if (osc_freq == CTI_EE_MASK_OSC_FREQ) + return -EIO; + + return osc_freq; +} + +/** + * cti_get_port_type_xr17c15x_xr17v25x() - Get port type of xr17c15x/xr17v25x + * @priv: Device's private structure + * @pcidev: Pointer to the PCI device for this port + * @port_num: Port to get type of + * + * CTI xr17c15x and xr17v25x based cards port types are based on PCI IDs. + * + * Return: port type on success, CTI_PORT_TYPE_NONE on failure + */ +static enum cti_port_type cti_get_port_type_xr17c15x_xr17v25x(struct exar8250 *priv, + struct pci_dev *pcidev, + unsigned int port_num) +{ + switch (pcidev->subsystem_device) { + // RS232 only cards + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232_NS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232_NS: + return CTI_PORT_TYPE_RS232; + // 1x RS232, 1x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1: + return (port_num == 0) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + // 2x RS232, 2x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2: + return (port_num < 2) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + // 4x RS232, 4x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP: + return (port_num < 4) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + // RS232/RS422/RS485 HW (jumper) selectable + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_SP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP: + return CTI_PORT_TYPE_RS232_422_485_HW; + // RS422/RS485 HW (jumper) selectable + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485: + return CTI_PORT_TYPE_RS422_485; + // 6x RS232, 2x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP: + return (port_num < 6) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + // 2x RS232, 6x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP: + return (port_num < 2) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + default: + dev_err(&pcidev->dev, "unknown/unsupported device\n"); + return CTI_PORT_TYPE_NONE; + } +} + +/** + * cti_get_port_type_fpga() - Get the port type of a CTI FPGA card + * @priv: Device's private structure + * @pcidev: Pointer to the PCI device for this port + * @port_num: Port to get type of + * + * FPGA based cards port types are based on PCI IDs. + * + * Return: port type on success, CTI_PORT_TYPE_NONE on failure + */ +static enum cti_port_type cti_get_port_type_fpga(struct exar8250 *priv, + struct pci_dev *pcidev, + unsigned int port_num) +{ + switch (pcidev->device) { + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X: + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X: + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16: + return CTI_PORT_TYPE_RS232_422_485_HW; + default: + dev_err(&pcidev->dev, "unknown/unsupported device\n"); + return CTI_PORT_TYPE_NONE; + } +} + +/** + * cti_get_port_type_xr17v35x() - Read port type from the EEPROM + * @priv: Device's private structure + * @pcidev: Pointer to the PCI device for this port + * @port_num: port offset + * + * CTI XR17V35X based cards have the port types stored in the EEPROM. + * This function reads the port type for a single port. + * + * Return: port type on success, CTI_PORT_TYPE_NONE on failure + */ +static enum cti_port_type cti_get_port_type_xr17v35x(struct exar8250 *priv, + struct pci_dev *pcidev, + unsigned int port_num) +{ + enum cti_port_type port_type; + u16 port_flags; + u8 offset; + + offset = CTI_EE_OFF_XR17V35X_PORT_FLAGS + port_num; + eeprom_93cx6_read(&priv->eeprom, offset, &port_flags); + + port_type = FIELD_GET(CTI_EE_MASK_PORT_FLAGS_TYPE, port_flags); + if (CTI_PORT_TYPE_VALID(port_type)) + return port_type; + + /* + * If the port type is missing the card assume it is a + * RS232/RS422/RS485 card to be safe. + * + * There is one known board (BEG013) that only has 3 of 4 port types + * written to the EEPROM so this acts as a work around. + */ + dev_warn(&pcidev->dev, "failed to get port %d type from EEPROM\n", port_num); + + return CTI_PORT_TYPE_RS232_422_485_HW; +} + +static int cti_rs485_config_mpio_tristate(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct exar8250 *priv = (struct exar8250 *)port->private_data; + int ret; + + ret = generic_rs485_config(port, termios, rs485); + if (ret) + return ret; + + // Disable power-on RS485 tri-state via MPIO + return cti_tristate_disable(priv, port->port_id); +} + +static void cti_board_init_osc_freq(struct exar8250 *priv, struct pci_dev *pcidev, u8 eeprom_offset) +{ + int osc_freq; + + osc_freq = cti_read_osc_freq(priv, eeprom_offset); + if (osc_freq <= 0) { + dev_warn(&pcidev->dev, "failed to read OSC freq from EEPROM, using default\n"); + osc_freq = CTI_DEFAULT_PCI_OSC_FREQ; + } + + priv->osc_freq = osc_freq; +} + +static int cti_port_setup_common(struct exar8250 *priv, + struct pci_dev *pcidev, + int idx, unsigned int offset, + struct uart_8250_port *port) +{ + int ret; + + port->port.port_id = idx; + port->port.uartclk = priv->osc_freq; + + ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0, priv->virt); + if (ret) + return ret; + + port->port.private_data = (void *)priv; + port->port.pm = exar_pm; + port->port.shutdown = exar_shutdown; + + return 0; +} + +static int cti_board_init_fpga(struct exar8250 *priv, struct pci_dev *pcidev) +{ + int ret; + u16 cfg_val; + + // FPGA OSC is fixed to the 33MHz PCI clock + priv->osc_freq = CTI_DEFAULT_FPGA_OSC_FREQ; + + // Enable external interrupts in special cfg space register + ret = pci_read_config_word(pcidev, CTI_FPGA_CFG_INT_EN_REG, &cfg_val); + if (ret) + return pcibios_err_to_errno(ret); + + cfg_val |= CTI_FPGA_CFG_INT_EN_EXT_BIT; + ret = pci_write_config_word(pcidev, CTI_FPGA_CFG_INT_EN_REG, cfg_val); + if (ret) + return pcibios_err_to_errno(ret); + + // RS485 gate needs to be enabled; otherwise RTS/CTS will not work + exar_write_reg(priv, CTI_FPGA_RS485_IO_REG, 0x01); + + return 0; +} + +static int cti_port_setup_fpga(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + int ret; + if (idx == 0) { - switch (pcidev->device) { - case PCI_DEVICE_ID_COMMTECH_4222PCI335: - case PCI_DEVICE_ID_COMMTECH_4224PCI335: - writeb(0x78, p + UART_EXAR_MPIOLVL_7_0); - writeb(0x00, p + UART_EXAR_MPIOINV_7_0); - writeb(0x00, p + UART_EXAR_MPIOSEL_7_0); + ret = cti_board_init_fpga(priv, pcidev); + if (ret) + return ret; + } + + port_type = cti_get_port_type_fpga(priv, pcidev, idx); + + // FPGA shares port offsets with XR17C15X + offset = idx * UART_EXAR_XR17C15X_PORT_OFFSET; + port->port.type = PORT_XR17D15X; + + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + port->port.startup = xr17v35x_startup; + + if (CTI_PORT_TYPE_RS485(port_type)) { + port->port.rs485_config = generic_rs485_config; + port->port.rs485_supported = generic_rs485_supported; + } + + return cti_port_setup_common(priv, pcidev, idx, offset, port); +} + +static void cti_board_init_xr17v35x(struct exar8250 *priv, struct pci_dev *pcidev) +{ + // XR17V35X uses the PCIe clock rather than an oscillator + priv->osc_freq = CTI_DEFAULT_PCIE_OSC_FREQ; +} + +static int cti_port_setup_xr17v35x(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + int ret; + + if (idx == 0) + cti_board_init_xr17v35x(priv, pcidev); + + port_type = cti_get_port_type_xr17v35x(priv, pcidev, idx); + + offset = idx * UART_EXAR_XR17V35X_PORT_OFFSET; + port->port.type = PORT_XR17V35X; + + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + port->port.startup = xr17v35x_startup; + + switch (port_type) { + case CTI_PORT_TYPE_RS422_485: + case CTI_PORT_TYPE_RS232_422_485_HW: + port->port.rs485_config = cti_rs485_config_mpio_tristate; + port->port.rs485_supported = generic_rs485_supported; + break; + case CTI_PORT_TYPE_RS232_422_485_SW: + case CTI_PORT_TYPE_RS232_422_485_4B: + case CTI_PORT_TYPE_RS232_422_485_2B: + port->port.rs485_config = generic_rs485_config; + port->port.rs485_supported = generic_rs485_supported; + break; + default: + break; + } + + ret = cti_port_setup_common(priv, pcidev, idx, offset, port); + if (ret) + return ret; + + exar_write_reg(priv, (offset + UART_EXAR_8XMODE), 0x00); + exar_write_reg(priv, (offset + UART_EXAR_FCTR), UART_FCTR_EXAR_TRGD); + exar_write_reg(priv, (offset + UART_EXAR_TXTRG), 128); + exar_write_reg(priv, (offset + UART_EXAR_RXTRG), 128); + + return 0; +} + +static void cti_board_init_xr17v25x(struct exar8250 *priv, struct pci_dev *pcidev) +{ + cti_board_init_osc_freq(priv, pcidev, CTI_EE_OFF_XR17V25X_OSC_FREQ); + + /* enable interrupts on cards that need the "PLX fix" */ + switch (pcidev->subsystem_device) { + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B: + cti_plx_int_enable(priv); + break; + default: + break; + } +} + +static int cti_port_setup_xr17v25x(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + int ret; + + if (idx == 0) + cti_board_init_xr17v25x(priv, pcidev); + + port_type = cti_get_port_type_xr17c15x_xr17v25x(priv, pcidev, idx); + + offset = idx * UART_EXAR_XR17V25X_PORT_OFFSET; + port->port.type = PORT_XR17D15X; + + // XR17V25X supports fractional baudrates + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + port->port.startup = xr17v35x_startup; + + if (CTI_PORT_TYPE_RS485(port_type)) { + switch (pcidev->subsystem_device) { + // These cards support power on 485 tri-state via MPIO + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485: + port->port.rs485_config = cti_rs485_config_mpio_tristate; break; - case PCI_DEVICE_ID_COMMTECH_2324PCI335: - case PCI_DEVICE_ID_COMMTECH_2328PCI335: - writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); - writeb(0xc0, p + UART_EXAR_MPIOINV_7_0); - writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0); + // Otherwise auto or no power on 485 tri-state support + default: + port->port.rs485_config = generic_rs485_config; break; } - writeb(0x00, p + UART_EXAR_MPIOINT_7_0); - writeb(0x00, p + UART_EXAR_MPIO3T_7_0); - writeb(0x00, p + UART_EXAR_MPIOOD_7_0); + + port->port.rs485_supported = generic_rs485_supported; } + ret = cti_port_setup_common(priv, pcidev, idx, offset, port); + if (ret) + return ret; + + exar_write_reg(priv, (offset + UART_EXAR_8XMODE), 0x00); + exar_write_reg(priv, (offset + UART_EXAR_FCTR), UART_FCTR_EXAR_TRGD); + exar_write_reg(priv, (offset + UART_EXAR_TXTRG), 32); + exar_write_reg(priv, (offset + UART_EXAR_RXTRG), 32); + return 0; } -static int -pci_connect_tech_setup(struct exar8250 *priv, struct pci_dev *pcidev, - struct uart_8250_port *port, int idx) +static void cti_board_init_xr17c15x(struct exar8250 *priv, struct pci_dev *pcidev) { - unsigned int offset = idx * 0x200; - unsigned int baud = 1843200; + cti_board_init_osc_freq(priv, pcidev, CTI_EE_OFF_XR17C15X_OSC_FREQ); + + /* enable interrupts on cards that need the "PLX fix" */ + switch (pcidev->subsystem_device) { + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B: + cti_plx_int_enable(priv); + break; + default: + break; + } +} - port->port.uartclk = baud * 16; - return default_setup(priv, pcidev, idx, offset, port); +static int cti_port_setup_xr17c15x(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + + if (idx == 0) + cti_board_init_xr17c15x(priv, pcidev); + + port_type = cti_get_port_type_xr17c15x_xr17v25x(priv, pcidev, idx); + + offset = idx * UART_EXAR_XR17C15X_PORT_OFFSET; + port->port.type = PORT_XR17D15X; + + if (CTI_PORT_TYPE_RS485(port_type)) { + switch (pcidev->subsystem_device) { + // These cards support power on 485 tri-state via MPIO + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485: + port->port.rs485_config = cti_rs485_config_mpio_tristate; + break; + // Otherwise auto or no power on 485 tri-state support + default: + port->port.rs485_config = generic_rs485_config; + break; + } + + port->port.rs485_supported = generic_rs485_supported; + } + + return cti_port_setup_common(priv, pcidev, idx, offset, port); } static int @@ -326,7 +1112,16 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p) * devices will export them as GPIOs, so we pre-configure them safely * as inputs. */ - u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00; + u8 dir = 0x00; + + if ((pcidev->vendor == PCI_VENDOR_ID_EXAR) && + (pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) { + // Configure GPIO as inputs for Commtech adapters + dir = 0xff; + } else { + // Configure GPIO as outputs for SeaLevel adapters + dir = 0x00; + } writeb(0x00, p + UART_EXAR_MPIOINT_7_0); writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); @@ -342,9 +1137,8 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p) writeb(0x00, p + UART_EXAR_MPIOOD_15_8); } -static void * -__xr17v35x_register_gpio(struct pci_dev *pcidev, - const struct property_entry *properties) +static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev, + const struct software_node *node) { struct platform_device *pdev; @@ -353,9 +1147,9 @@ __xr17v35x_register_gpio(struct pci_dev *pcidev, return NULL; pdev->dev.parent = &pcidev->dev; - ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev)); + device_set_node(&pdev->dev, dev_fwnode(&pcidev->dev)); - if (platform_device_add_properties(pdev, properties) < 0 || + if (device_add_software_node(&pdev->dev, node) < 0 || platform_device_add(pdev) < 0) { platform_device_put(pdev); return NULL; @@ -364,51 +1158,87 @@ __xr17v35x_register_gpio(struct pci_dev *pcidev, return pdev; } +static void __xr17v35x_unregister_gpio(struct platform_device *pdev) +{ + device_remove_software_node(&pdev->dev); + platform_device_unregister(pdev); +} + static const struct property_entry exar_gpio_properties[] = { PROPERTY_ENTRY_U32("exar,first-pin", 0), PROPERTY_ENTRY_U32("ngpios", 16), { } }; -static int xr17v35x_register_gpio(struct pci_dev *pcidev, - struct uart_8250_port *port) +static const struct software_node exar_gpio_node = { + .properties = exar_gpio_properties, +}; + +static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { if (pcidev->vendor == PCI_VENDOR_ID_EXAR) port->port.private_data = - __xr17v35x_register_gpio(pcidev, exar_gpio_properties); + __xr17v35x_register_gpio(pcidev, &exar_gpio_node); return 0; } -static int generic_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) +static void xr17v35x_unregister_gpio(struct uart_8250_port *port) +{ + if (!port->port.private_data) + return; + + __xr17v35x_unregister_gpio(port->port.private_data); + port->port.private_data = NULL; +} + +static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { - bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); u8 __iomem *p = port->membase; - u8 value; + u8 old_lcr; + u8 efr; + u8 dld; + int ret; - value = readb(p + UART_EXAR_FCTR); - if (is_rs485) - value |= UART_FCTR_EXAR_485; - else - value &= ~UART_FCTR_EXAR_485; + ret = generic_rs485_config(port, termios, rs485); + if (ret) + return ret; - writeb(value, p + UART_EXAR_FCTR); + if (!(rs485->flags & SER_RS485_ENABLED)) + return 0; - if (is_rs485) - writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); + old_lcr = readb(p + UART_LCR); + + /* Set EFR[4]=1 to enable enhanced feature registers */ + efr = readb(p + UART_XR_EFR); + efr |= UART_EFR_ECB; + writeb(efr, p + UART_XR_EFR); + + /* Set MCR to use DTR as Auto-RS485 Enable signal */ + writeb(UART_MCR_OUT1, p + UART_MCR); + + /* Set LCR[7]=1 to enable access to DLD register */ + writeb(old_lcr | UART_LCR_DLAB, p + UART_LCR); + + /* Set DLD[7]=1 for inverted RS485 Enable logic */ + dld = readb(p + UART_EXAR_DLD); + dld |= UART_EXAR_DLD_485_POLARITY; + writeb(dld, p + UART_EXAR_DLD); - port->rs485 = *rs485; + writeb(old_lcr, p + UART_LCR); return 0; } static const struct exar8250_platform exar8250_default_platform = { .register_gpio = xr17v35x_register_gpio, + .unregister_gpio = xr17v35x_unregister_gpio, .rs485_config = generic_rs485_config, + .rs485_supported = &generic_rs485_supported, }; -static int iot2040_rs485_config(struct uart_port *port, +static int iot2040_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); @@ -438,15 +1268,24 @@ static int iot2040_rs485_config(struct uart_port *port, value |= mode; writeb(value, p + UART_EXAR_MPIOLVL_7_0); - return generic_rs485_config(port, rs485); + return generic_rs485_config(port, termios, rs485); } +static const struct serial_rs485 iot2040_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS, +}; + static const struct property_entry iot2040_gpio_properties[] = { PROPERTY_ENTRY_U32("exar,first-pin", 10), PROPERTY_ENTRY_U32("ngpios", 1), { } }; +static const struct software_node iot2040_gpio_node = { + .properties = iot2040_gpio_properties, +}; + static int iot2040_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { @@ -458,14 +1297,16 @@ static int iot2040_register_gpio(struct pci_dev *pcidev, writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8); port->port.private_data = - __xr17v35x_register_gpio(pcidev, iot2040_gpio_properties); + __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node); return 0; } static const struct exar8250_platform iot2040_platform = { .rs485_config = iot2040_rs485_config, + .rs485_supported = &iot2040_rs485_supported, .register_gpio = iot2040_register_gpio, + .unregister_gpio = xr17v35x_unregister_gpio, }; /* @@ -483,25 +1324,33 @@ static const struct dmi_system_id exar_platforms[] = { {} }; +static const struct exar8250_platform *exar_get_platform(void) +{ + const struct dmi_system_id *dmi_match; + + dmi_match = dmi_first_match(exar_platforms); + if (dmi_match) + return dmi_match->driver_data; + + return &exar8250_default_platform; +} + static int pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port, int idx) { - const struct exar8250_platform *platform; - const struct dmi_system_id *dmi_match; + const struct exar8250_platform *platform = exar_get_platform(); unsigned int offset = idx * 0x400; unsigned int baud = 7812500; u8 __iomem *p; int ret; - dmi_match = dmi_first_match(exar_platforms); - if (dmi_match) - platform = dmi_match->driver_data; - else - platform = &exar8250_default_platform; - port->port.uartclk = baud * 16; port->port.rs485_config = platform->rs485_config; + port->port.rs485_supported = *(platform->rs485_supported); + + if (pcidev->subsystem_vendor == PCI_VENDOR_ID_SEALEVEL) + port->port.rs485_config = sealevel_rs485_config; /* * Setup the UART clock for the devices on expansion slot to @@ -533,12 +1382,11 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, static void pci_xr17v35x_exit(struct pci_dev *pcidev) { + const struct exar8250_platform *platform = exar_get_platform(); struct exar8250 *priv = pci_get_drvdata(pcidev); struct uart_8250_port *port = serial8250_get_port(priv->line[0]); - struct platform_device *pdev = port->port.private_data; - platform_device_unregister(pdev); - port->port.private_data = NULL; + platform->unregister_gpio(port); } static inline void exar_misc_clear(struct exar8250 *priv) @@ -567,6 +1415,35 @@ static irqreturn_t exar_misc_handler(int irq, void *data) return IRQ_HANDLED; } +static unsigned int exar_get_nr_ports(struct exar8250_board *board, struct pci_dev *pcidev) +{ + if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) + return BIT(((pcidev->device & 0x38) >> 3) - 1); + + // Check if board struct overrides number of ports + if (board->num_ports > 0) + return board->num_ports; + + // Exar encodes # ports in last nibble of PCI Device ID ex. 0358 + if (pcidev->vendor == PCI_VENDOR_ID_EXAR) + return pcidev->device & 0x0f; + + // Handle CTI FPGA cards + if (pcidev->vendor == PCI_VENDOR_ID_CONNECT_TECH) { + switch (pcidev->device) { + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X: + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X: + return 12; + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16: + return 16; + default: + return 0; + } + } + + return 0; +} + static int exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) { @@ -586,7 +1463,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3); - nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f; + nr_ports = exar_get_nr_ports(board, pcidev); + if (nr_ports == 0) + return dev_err_probe(&pcidev->dev, -ENODEV, "failed to get number of ports\n"); priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) @@ -608,18 +1487,20 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; + /* Clear interrupts */ + exar_misc_clear(priv); + rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler, IRQF_SHARED, "exar_uart", priv); if (rc) return rc; - /* Clear interrupts */ - exar_misc_clear(priv); + exar_eeprom_init(priv); for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { - dev_err(&pcidev->dev, "Failed to setup port %u\n", i); + dev_err_probe(&pcidev->dev, rc, "Failed to setup port %u\n", i); break; } @@ -628,10 +1509,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { - dev_err(&pcidev->dev, - "Couldn't register serial port %lx, irq %d, type %d, error %d\n", - uart.port.iobase, uart.port.irq, - uart.port.iotype, priv->line[i]); + dev_err_probe(&pcidev->dev, priv->line[i], + "Couldn't register serial port %lx, type %d, irq %d\n", + uart.port.iobase, uart.port.iotype, uart.port.irq); break; } } @@ -648,28 +1528,24 @@ static void exar_pci_remove(struct pci_dev *pcidev) for (i = 0; i < priv->nr; i++) serial8250_unregister_port(priv->line[i]); + /* Ensure that every init quirk is properly torn down */ if (priv->board->exit) priv->board->exit(pcidev); } -static int __maybe_unused exar_suspend(struct device *dev) +static int exar_suspend(struct device *dev) { - struct pci_dev *pcidev = to_pci_dev(dev); - struct exar8250 *priv = pci_get_drvdata(pcidev); + struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; for (i = 0; i < priv->nr; i++) if (priv->line[i] >= 0) serial8250_suspend_port(priv->line[i]); - /* Ensure that every init quirk is properly torn down */ - if (priv->board->exit) - priv->board->exit(pcidev); - return 0; } -static int __maybe_unused exar_resume(struct device *dev) +static int exar_resume(struct device *dev) { struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; @@ -683,23 +1559,7 @@ static int __maybe_unused exar_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); - -static const struct exar8250_board acces_com_2x = { - .num_ports = 2, - .setup = pci_xr17c154_setup, -}; - -static const struct exar8250_board acces_com_4x = { - .num_ports = 4, - .setup = pci_xr17c154_setup, -}; - -static const struct exar8250_board acces_com_8x = { - .num_ports = 8, - .setup = pci_xr17c154_setup, -}; - +static DEFINE_SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); static const struct exar8250_board pbn_fastcom335_2 = { .num_ports = 2, @@ -716,8 +1576,20 @@ static const struct exar8250_board pbn_fastcom335_8 = { .setup = pci_fastcom335_setup, }; -static const struct exar8250_board pbn_connect = { - .setup = pci_connect_tech_setup, +static const struct exar8250_board pbn_cti_xr17c15x = { + .setup = cti_port_setup_xr17c15x, +}; + +static const struct exar8250_board pbn_cti_xr17v25x = { + .setup = cti_port_setup_xr17v25x, +}; + +static const struct exar8250_board pbn_cti_xr17v35x = { + .setup = cti_port_setup_xr17v35x, +}; + +static const struct exar8250_board pbn_cti_fpga = { + .setup = cti_port_setup_fpga, }; static const struct exar8250_board pbn_exar_ibm_saturn = { @@ -734,6 +1606,30 @@ static const struct exar8250_board pbn_exar_XR17V35x = { .exit = pci_xr17v35x_exit, }; +static const struct exar8250_board pbn_fastcom35x_2 = { + .num_ports = 2, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + +static const struct exar8250_board pbn_fastcom35x_4 = { + .num_ports = 4, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + +static const struct exar8250_board pbn_fastcom35x_8 = { + .num_ports = 8, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + +static const struct exar8250_board pbn_adv_XR17V352 = { + .num_ports = 2, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + static const struct exar8250_board pbn_exar_XR17V4358 = { .num_ports = 12, .setup = pci_xr17v35x_setup, @@ -746,13 +1642,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { .exit = pci_xr17v35x_exit, }; -#define CONNECT_DEVICE(devid, sdevid, bd) { \ - PCI_DEVICE_SUB( \ - PCI_VENDOR_ID_EXAR, \ - PCI_DEVICE_ID_EXAR_##devid, \ - PCI_SUBVENDOR_ID_CONNECT_TECH, \ - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_##sdevid), 0, 0, \ - (kernel_ulong_t)&bd \ +#define CTI_EXAR_DEVICE(devid, bd) { \ + PCI_DEVICE_SUB( \ + PCI_VENDOR_ID_EXAR, \ + PCI_DEVICE_ID_EXAR_##devid, \ + PCI_SUBVENDOR_ID_CONNECT_TECH, \ + PCI_ANY_ID), 0, 0, \ + (kernel_ulong_t)&bd \ } #define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } @@ -761,35 +1657,56 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { PCI_DEVICE_SUB( \ PCI_VENDOR_ID_EXAR, \ PCI_DEVICE_ID_EXAR_##devid, \ - PCI_VENDOR_ID_IBM, \ + PCI_SUBVENDOR_ID_IBM, \ PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \ (kernel_ulong_t)&bd \ } +#define USR_DEVICE(devid, sdevid, bd) { \ + PCI_DEVICE_SUB( \ + PCI_VENDOR_ID_USR, \ + PCI_DEVICE_ID_EXAR_##devid, \ + PCI_VENDOR_ID_EXAR, \ + PCI_SUBDEVICE_ID_USR_##sdevid), 0, 0, \ + (kernel_ulong_t)&bd \ + } + static const struct pci_device_id exar_pci_tbl[] = { - EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x), - EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x), - EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x), - EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x), - EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x), - EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x), - EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x), - - CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect), - CONNECT_DEVICE(XR17C152, UART_1_1, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_2_2, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_4_4, pbn_connect), - CONNECT_DEVICE(XR17C152, UART_2, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_4, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_8, pbn_connect), - CONNECT_DEVICE(XR17C152, UART_2_485, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_4_485, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_8_485, pbn_connect), + EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_4S, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_8S, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM232_8, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_2SM, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_4SM, pbn_exar_XR17C15x), + EXAR_DEVICE(ACCESSIO, COM_8SM, pbn_exar_XR17C15x), + + /* Connect Tech cards with Exar vendor/device PCI IDs */ + CTI_EXAR_DEVICE(XR17C152, pbn_cti_xr17c15x), + CTI_EXAR_DEVICE(XR17C154, pbn_cti_xr17c15x), + CTI_EXAR_DEVICE(XR17C158, pbn_cti_xr17c15x), + + CTI_EXAR_DEVICE(XR17V252, pbn_cti_xr17v25x), + CTI_EXAR_DEVICE(XR17V254, pbn_cti_xr17v25x), + CTI_EXAR_DEVICE(XR17V258, pbn_cti_xr17v25x), + + CTI_EXAR_DEVICE(XR17V352, pbn_cti_xr17v35x), + CTI_EXAR_DEVICE(XR17V354, pbn_cti_xr17v35x), + CTI_EXAR_DEVICE(XR17V358, pbn_cti_xr17v35x), + + /* Connect Tech cards with Connect Tech vendor/device PCI IDs (FPGA based) */ + EXAR_DEVICE(CONNECT_TECH, PCI_XR79X_12_XIG00X, pbn_cti_fpga), + EXAR_DEVICE(CONNECT_TECH, PCI_XR79X_12_XIG01X, pbn_cti_fpga), + EXAR_DEVICE(CONNECT_TECH, PCI_XR79X_16, pbn_cti_fpga), IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), + /* USRobotics USR298x-OEM PCI Modems */ + USR_DEVICE(XR17C152, 2980, pbn_exar_XR17C15x), + USR_DEVICE(XR17C152, 2981, pbn_exar_XR17C15x), + + /* ADVANTECH devices */ + EXAR_DEVICE(ADVANTECH, XR17V352, pbn_adv_XR17V352), + /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */ EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x), EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x), @@ -801,9 +1718,9 @@ static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x), EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358), EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358), - EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x), + EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_fastcom35x_2), + EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_fastcom35x_4), + EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_fastcom35x_8), EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2), EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), @@ -818,12 +1735,13 @@ static struct pci_driver exar_pci_driver = { .probe = exar_pci_probe, .remove = exar_pci_remove, .driver = { - .pm = &exar_pci_pm, + .pm = pm_sleep_ptr(&exar_pci_pm), }, .id_table = exar_pci_tbl, }; module_pci_driver(exar_pci_driver); +MODULE_IMPORT_NS("SERIAL_8250_PCI"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Exar Serial Driver"); MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index d1d253c4b518..b4461a89b8d0 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -21,6 +21,7 @@ #define CHIP_ID_F81866 0x1010 #define CHIP_ID_F81966 0x0215 #define CHIP_ID_F81216AD 0x1602 +#define CHIP_ID_F81216E 0x1617 #define CHIP_ID_F81216H 0x0501 #define CHIP_ID_F81216 0x0802 #define VENDOR_ID1 0x23 @@ -125,7 +126,7 @@ static int fintek_8250_enter_key(u16 base_port, u8 key) if (!request_muxed_region(base_port, 2, "8250_fintek")) return -EBUSY; - /* Force to deactive all SuperIO in this base_port */ + /* Force to deactivate all SuperIO in this base_port */ outb(EXIT_KEY, base_port + ADDR_PORT); outb(key, base_port + ADDR_PORT); @@ -158,6 +159,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata) case CHIP_ID_F81866: case CHIP_ID_F81966: case CHIP_ID_F81216AD: + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81216: break; @@ -181,6 +183,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, return 0; case CHIP_ID_F81216AD: + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81216: *min = F81216_LDN_LOW; @@ -191,7 +194,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, return -ENODEV; } -static int fintek_8250_rs485_config(struct uart_port *port, +static int fintek_8250_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { uint8_t config = 0; @@ -200,25 +203,13 @@ static int fintek_8250_rs485_config(struct uart_port *port, if (!pdata) return -EINVAL; - /* Hardware do not support same RTS level on send and receive */ - if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == - !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) - return -EINVAL; if (rs485->flags & SER_RS485_ENABLED) { - memset(rs485->padding, 0, sizeof(rs485->padding)); + /* Hardware do not support same RTS level on send and receive */ + if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == + !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) + return -EINVAL; config |= RS485_URA; - } else { - memset(rs485, 0, sizeof(*rs485)); - } - - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND; - - /* Only the first port supports delays */ - if (pdata->index) { - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; } if (rs485->delay_rts_before_send) { @@ -241,8 +232,6 @@ static int fintek_8250_rs485_config(struct uart_port *port, sio_write_reg(pdata, RS485, config); fintek_8250_exit_key(pdata->base_port); - port->rs485 = *rs485; - return 0; } @@ -255,7 +244,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) case CHIP_ID_F81866: sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1, 0); - /* fall through */ + fallthrough; case CHIP_ID_F81865: sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE, F81866_IRQ_SHARE); @@ -264,6 +253,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) break; case CHIP_ID_F81216AD: + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81216: sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE, @@ -277,7 +267,8 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) { switch (pdata->pid) { - case CHIP_ID_F81216H: /* 128Bytes FIFO */ + case CHIP_ID_F81216E: /* 128Bytes FIFO */ + case CHIP_ID_F81216H: case CHIP_ID_F81966: case CHIP_ID_F81866: sio_write_mask_reg(pdata, FIFO_CTRL, @@ -290,28 +281,9 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) } } -static void fintek_8250_goto_highspeed(struct uart_8250_port *uart, - struct fintek_8250 *pdata) -{ - sio_write_reg(pdata, LDN, pdata->index); - - switch (pdata->pid) { - case CHIP_ID_F81966: - case CHIP_ID_F81866: /* set uart clock for high speed serial mode */ - sio_write_mask_reg(pdata, F81866_UART_CLK, - F81866_UART_CLK_MASK, - F81866_UART_CLK_14_769MHZ); - - uart->port.uartclk = 921600 * 16; - break; - default: /* leave clock speed untouched */ - break; - } -} - static void fintek_8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct fintek_8250 *pdata = port->private_data; unsigned int baud = tty_termios_baud_rate(termios); @@ -330,6 +302,7 @@ static void fintek_8250_set_termios(struct uart_port *port, goto exit; switch (pdata->pid) { + case CHIP_ID_F81216E: case CHIP_ID_F81216H: reg = RS485; break; @@ -379,6 +352,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart) struct fintek_8250 *pdata = uart->port.private_data; switch (pdata->pid) { + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81966: case CHIP_ID_F81866: @@ -430,7 +404,6 @@ static int probe_setup_port(struct fintek_8250 *pdata, fintek_8250_set_irq_mode(pdata, level_mode); fintek_8250_set_max_fifo(pdata); - fintek_8250_goto_highspeed(uart, pdata); fintek_8250_exit_key(addr[i]); @@ -444,6 +417,17 @@ static int probe_setup_port(struct fintek_8250 *pdata, return -ENODEV; } +/* Only the first port supports delays */ +static const struct serial_rs485 fintek_8250_rs485_supported_port0 = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + +static const struct serial_rs485 fintek_8250_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, +}; + static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) { struct fintek_8250 *pdata = uart->port.private_data; @@ -455,6 +439,15 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) case CHIP_ID_F81866: case CHIP_ID_F81865: uart->port.rs485_config = fintek_8250_rs485_config; + if (!pdata->index) + uart->port.rs485_supported = fintek_8250_rs485_supported_port0; + else + uart->port.rs485_supported = fintek_8250_rs485_supported; + break; + + case CHIP_ID_F81216E: /* F81216E does not support RS485 delays */ + uart->port.rs485_config = fintek_8250_rs485_config; + uart->port.rs485_supported = fintek_8250_rs485_supported; break; default: /* No RS485 Auto direction functional */ diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index 0d0c80905c58..649ae5c8304d 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -1,15 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/serial_reg.h> -#include <linux/serial_8250.h> - -#include "8250.h" - /* * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker. + * Copyright 2020 NXP + * Copyright 2020 Puresoftware Ltd. * * This isn't a full driver; it just provides an alternate IRQ - * handler to deal with an errata. Everything else is just - * using the bog standard 8250 support. + * handler to deal with an errata and provide ACPI wrapper. + * Everything else is just using the bog standard 8250 support. * * We follow code flow of serial8250_default_handle_irq() but add * a check for a break and insert a dummy read on the Rx for the @@ -20,30 +17,49 @@ * IRQ event to the next one. */ +#include <linux/acpi.h> +#include <linux/serial_reg.h> +#include <linux/serial_8250.h> + +#include "8250.h" + int fsl8250_handle_irq(struct uart_port *port) { - unsigned char lsr, orig_lsr; unsigned long flags; + u16 lsr, orig_lsr; unsigned int iir; struct uart_8250_port *up = up_to_u8250p(port); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); - iir = port->serial_in(port, UART_IIR); + iir = serial_port_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return 0; } - /* This is the WAR; if last event was BRK, then read and return */ - if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) { + /* + * For a single break the hardware reports LSR.BI for each character + * time. This is described in the MPC8313E chip errata as "General17". + * A typical break has a duration of 0.3s, with a 115200n8 configuration + * that (theoretically) corresponds to ~3500 interrupts in these 0.3s. + * In practise it's less (around 500) because of hardware + * and software latencies. The workaround recommended by the vendor is + * to read the RX register (to clear LSR.DR and thus prevent a FIFO + * aging interrupt). To prevent the irq from retriggering LSR must not be + * read. (This would clear LSR.BI, hardware would reassert the BI event + * immediately and interrupt the CPU again. The hardware clears LSR.BI + * when the next valid char is read.) + */ + if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI && + (up->lsr_saved_flags & UART_LSR_BI))) { up->lsr_saved_flags &= ~UART_LSR_BI; - port->serial_in(port, UART_RX); - spin_unlock_irqrestore(&up->port.lock, flags); + serial_port_in(port, UART_RX); + uart_port_unlock_irqrestore(&up->port, flags); return 1; } - lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR); + lsr = orig_lsr = serial_port_in(port, UART_LSR); /* Process incoming characters first */ if ((lsr & (UART_LSR_DR | UART_LSR_BI)) && @@ -55,7 +71,7 @@ int fsl8250_handle_irq(struct uart_port *port) if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) { unsigned long delay; - up->ier = port->serial_in(port, UART_IER); + up->ier = serial_port_in(port, UART_IER); if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { port->ops->stop_rx(port); } else { @@ -71,11 +87,103 @@ int fsl8250_handle_irq(struct uart_port *port) serial8250_modem_status(up); - if (lsr & UART_LSR_THRE) + if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) serial8250_tx_chars(up); - up->lsr_saved_flags = orig_lsr; - uart_unlock_and_check_sysrq(&up->port, flags); + up->lsr_saved_flags |= orig_lsr & UART_LSR_BI; + + uart_unlock_and_check_sysrq_irqrestore(&up->port, flags); + return 1; } EXPORT_SYMBOL_GPL(fsl8250_handle_irq); + +#ifdef CONFIG_ACPI +struct fsl8250_data { + int line; +}; + +static int fsl8250_acpi_probe(struct platform_device *pdev) +{ + struct fsl8250_data *data; + struct uart_8250_port port8250; + struct device *dev = &pdev->dev; + struct resource *regs; + + int ret, irq; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(dev, "no registers defined\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + memset(&port8250, 0, sizeof(port8250)); + + ret = device_property_read_u32(dev, "clock-frequency", + &port8250.port.uartclk); + if (ret) + return ret; + + spin_lock_init(&port8250.port.lock); + + port8250.port.mapbase = regs->start; + port8250.port.irq = irq; + port8250.port.handle_irq = fsl8250_handle_irq; + port8250.port.type = PORT_16550A; + port8250.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF + | UPF_FIXED_PORT | UPF_IOREMAP + | UPF_FIXED_TYPE; + port8250.port.dev = dev; + port8250.port.mapsize = resource_size(regs); + port8250.port.iotype = UPIO_MEM; + port8250.port.irqflags = IRQF_SHARED; + + port8250.port.membase = devm_ioremap(dev, port8250.port.mapbase, + port8250.port.mapsize); + if (!port8250.port.membase) + return -ENOMEM; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->line = serial8250_register_8250_port(&port8250); + if (data->line < 0) + return data->line; + + platform_set_drvdata(pdev, data); + return 0; +} + +static void fsl8250_acpi_remove(struct platform_device *pdev) +{ + struct fsl8250_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); +} + +static const struct acpi_device_id fsl_8250_acpi_id[] = { + { "NXP0018", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, fsl_8250_acpi_id); + +static struct platform_driver fsl8250_platform_driver = { + .driver = { + .name = "fsl-16550-uart", + .acpi_match_table = ACPI_PTR(fsl_8250_acpi_id), + }, + .probe = fsl8250_acpi_probe, + .remove = fsl8250_acpi_remove, +}; + +module_platform_driver(fsl8250_platform_driver); +#endif + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Handling of Freescale specific 8250 variants"); diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 424c07c5f629..94542fc143c2 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_fdt.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/serial_8250.h> #include <linux/serial_core.h> @@ -52,9 +51,9 @@ static void early_out(struct uart_port *port, int offset, uint8_t value) writel(value, port->membase + (offset << 2)); } -static void ingenic_early_console_putc(struct uart_port *port, int c) +static void ingenic_early_console_putc(struct uart_port *port, unsigned char c) { - uint8_t lsr; + u16 lsr; do { lsr = early_in(port, UART_LSR); @@ -87,7 +86,7 @@ static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev dev->port.uartclk = be32_to_cpup(prop); } -static int __init ingenic_early_console_setup(struct earlycon_device *dev, +static int __init ingenic_earlycon_setup_tail(struct earlycon_device *dev, const char *opt) { struct uart_port *port = &dev->port; @@ -103,8 +102,6 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev, uart_parse_options(opt, &baud, &parity, &bits, &flow); } - ingenic_early_console_setup_clock(dev); - if (dev->baud) baud = dev->baud; divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); @@ -129,9 +126,36 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev, return 0; } +static int __init ingenic_early_console_setup(struct earlycon_device *dev, + const char *opt) +{ + ingenic_early_console_setup_clock(dev); + + return ingenic_earlycon_setup_tail(dev, opt); +} + +static int __init jz4750_early_console_setup(struct earlycon_device *dev, + const char *opt) +{ + /* + * JZ4750/55/60 have an optional /2 divider between the EXT + * oscillator and some peripherals including UART, which will + * be enabled if using a 24 MHz oscillator, and disabled when + * using a 12 MHz oscillator. + */ + ingenic_early_console_setup_clock(dev); + if (dev->port.uartclk >= 16000000) + dev->port.uartclk /= 2; + + return ingenic_earlycon_setup_tail(dev, opt); +} + OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4750_uart, "ingenic,jz4750-uart", + jz4750_early_console_setup); + OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart", ingenic_early_console_setup); @@ -144,9 +168,9 @@ OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart", ingenic_early_console_setup); -static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) +static void ingenic_uart_serial_out(struct uart_port *p, unsigned int offset, u32 value) { - int ier; + u32 ier; switch (offset) { case UART_FCR: @@ -182,9 +206,9 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) writeb(value, p->membase + (offset << p->regshift)); } -static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset) +static u32 ingenic_uart_serial_in(struct uart_port *p, unsigned int offset) { - unsigned int value; + u8 value; value = readb(p->membase + (offset << p->regshift)); @@ -207,22 +231,20 @@ static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset) static int ingenic_uart_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct ingenic_uart_data *data; const struct ingenic_uart_config *cdata; - const struct of_device_id *match; - int err, line; + struct resource *regs; + int err; - match = of_match_device(of_match, &pdev->dev); - if (!match) { + cdata = of_device_get_match_data(&pdev->dev); + if (!cdata) { dev_err(&pdev->dev, "Error: No device match found\n"); return -ENODEV; } - cdata = match->data; - if (!regs || !irq) { - dev_err(&pdev->dev, "no registers/irq defined\n"); + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); return -EINVAL; } @@ -233,21 +255,19 @@ static int ingenic_uart_probe(struct platform_device *pdev) spin_lock_init(&uart.port.lock); uart.port.type = PORT_16550A; uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; - uart.port.iotype = UPIO_MEM; uart.port.mapbase = regs->start; - uart.port.regshift = 2; uart.port.serial_out = ingenic_uart_serial_out; uart.port.serial_in = ingenic_uart_serial_in; - uart.port.irq = irq->start; uart.port.dev = &pdev->dev; - uart.port.fifosize = cdata->fifosize; uart.tx_loadsz = cdata->tx_loadsz; uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; - /* Check for a fixed line number */ - line = of_alias_get_id(pdev->dev.of_node, "serial"); - if (line >= 0) - uart.port.line = line; + err = uart_read_port_properties(&uart.port); + if (err) + return err; + + uart.port.regshift = 2; + uart.port.fifosize = cdata->fifosize; uart.port.membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); @@ -255,22 +275,14 @@ static int ingenic_uart_probe(struct platform_device *pdev) return -ENOMEM; data->clk_module = devm_clk_get(&pdev->dev, "module"); - if (IS_ERR(data->clk_module)) { - err = PTR_ERR(data->clk_module); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, - "unable to get module clock: %d\n", err); - return err; - } + if (IS_ERR(data->clk_module)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk_module), + "unable to get module clock\n"); data->clk_baud = devm_clk_get(&pdev->dev, "baud"); - if (IS_ERR(data->clk_baud)) { - err = PTR_ERR(data->clk_baud); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, - "unable to get baud clock: %d\n", err); - return err; - } + if (IS_ERR(data->clk_baud)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk_baud), + "unable to get baud clock\n"); err = clk_prepare_enable(data->clk_module); if (err) { @@ -302,14 +314,13 @@ out: return err; } -static int ingenic_uart_remove(struct platform_device *pdev) +static void ingenic_uart_remove(struct platform_device *pdev) { struct ingenic_uart_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk_module); clk_disable_unprepare(data->clk_baud); - return 0; } static const struct ingenic_uart_config jz4740_uart_config = { @@ -334,6 +345,7 @@ static const struct ingenic_uart_config x1000_uart_config = { static const struct of_device_id of_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, + { .compatible = "ingenic,jz4750-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c index d5a39e105a76..28e28076782b 100644 --- a/drivers/tty/serial/8250/8250_ioc3.c +++ b/drivers/tty/serial/8250/8250_ioc3.c @@ -5,7 +5,7 @@ * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de> * * based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org> - * Copyright (C) 2014 Joshua Kinard <kumba@gentoo.org> + * Copyright (C) 2014 Joshua Kinard <linux@kumba.dev> */ #include <linux/module.h> @@ -21,12 +21,12 @@ struct ioc3_8250_data { int line; }; -static unsigned int ioc3_serial_in(struct uart_port *p, int offset) +static u32 ioc3_serial_in(struct uart_port *p, unsigned int offset) { return readb(p->membase + (offset ^ 3)); } -static void ioc3_serial_out(struct uart_port *p, int offset, int value) +static void ioc3_serial_out(struct uart_port *p, unsigned int offset, u32 value) { writeb(value, p->membase + (offset ^ 3)); } @@ -75,12 +75,11 @@ static int serial8250_ioc3_probe(struct platform_device *pdev) return 0; } -static int serial8250_ioc3_remove(struct platform_device *pdev) +static void serial8250_ioc3_remove(struct platform_device *pdev) { struct ioc3_8250_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); - return 0; } static struct platform_driver serial8250_ioc3_driver = { diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c new file mode 100644 index 000000000000..c05b89551b12 --- /dev/null +++ b/drivers/tty/serial/8250/8250_keba.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 KEBA Industrial Automation GmbH + * + * Driver for KEBA UART FPGA IP core + */ + +#include <linux/auxiliary_bus.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/misc/keba.h> +#include <linux/module.h> + +#include "8250.h" + +#define KUART "kuart" + +/* flags */ +#define KUART_RS485 BIT(0) +#define KUART_USE_CAPABILITY BIT(1) + +/* registers */ +#define KUART_VERSION 0x0000 +#define KUART_REVISION 0x0001 +#define KUART_CAPABILITY 0x0002 +#define KUART_CONTROL 0x0004 +#define KUART_BASE 0x000C +#define KUART_REGSHIFT 2 +#define KUART_CLK 1843200 + +/* mode flags */ +enum kuart_mode { + KUART_MODE_NONE = 0, + KUART_MODE_RS485, + KUART_MODE_RS422, + KUART_MODE_RS232 +}; + +/* capability flags */ +#define KUART_CAPABILITY_NONE BIT(KUART_MODE_NONE) +#define KUART_CAPABILITY_RS485 BIT(KUART_MODE_RS485) +#define KUART_CAPABILITY_RS422 BIT(KUART_MODE_RS422) +#define KUART_CAPABILITY_RS232 BIT(KUART_MODE_RS232) +#define KUART_CAPABILITY_MASK GENMASK(3, 0) + +/* Additional Control Register DTR line configuration */ +#define UART_ACR_DTRLC_MASK 0x18 +#define UART_ACR_DTRLC_COMPAT 0x00 +#define UART_ACR_DTRLC_ENABLE_LOW 0x10 + +struct kuart { + struct keba_uart_auxdev *auxdev; + void __iomem *base; + unsigned int line; + + unsigned int flags; + u8 capability; + enum kuart_mode mode; +}; + +static void kuart_set_phy_mode(struct kuart *kuart, enum kuart_mode mode) +{ + iowrite8(mode, kuart->base + KUART_CONTROL); +} + +static void kuart_enhanced_mode(struct uart_8250_port *up, bool enable) +{ + u8 lcr, efr; + + /* backup LCR register */ + lcr = serial_in(up, UART_LCR); + + /* enable 650 compatible register set (EFR, ...) */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + /* enable/disable enhanced mode with indexed control registers */ + efr = serial_in(up, UART_EFR); + if (enable) + efr |= UART_EFR_ECB; + else + efr &= ~UART_EFR_ECB; + serial_out(up, UART_EFR, efr); + + /* disable 650 compatible register set, restore LCR */ + serial_out(up, UART_LCR, lcr); +} + +static void kuart_dtr_line_config(struct uart_8250_port *up, u8 dtrlc) +{ + u8 acr; + + /* set index register to 0 to access ACR register */ + serial_out(up, UART_SCR, UART_ACR); + + /* set value register to 0x10 writing DTR mode (1,0) */ + acr = serial_in(up, UART_LSR); + acr &= ~UART_ACR_DTRLC_MASK; + acr |= dtrlc; + serial_out(up, UART_LSR, acr); +} + +static int kuart_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = up_to_u8250p(port); + struct kuart *kuart = port->private_data; + enum kuart_mode mode; + u8 dtrlc; + + if (rs485->flags & SER_RS485_ENABLED) { + if (rs485->flags & SER_RS485_MODE_RS422) + mode = KUART_MODE_RS422; + else + mode = KUART_MODE_RS485; + } else { + mode = KUART_MODE_RS232; + } + + if (mode == kuart->mode) + return 0; + + if (kuart->flags & KUART_USE_CAPABILITY) { + /* deactivate physical interface, break before make */ + kuart_set_phy_mode(kuart, KUART_MODE_NONE); + } + + if (mode == KUART_MODE_RS485) { + /* + * Set DTR line configuration of 95x UART to DTR mode (1,0). + * In this mode the DTR pin drives the active-low enable pin of + * an external RS485 buffer. The DTR pin will be forced low + * whenever the transmitter is not empty, otherwise DTR pin is + * high. + */ + dtrlc = UART_ACR_DTRLC_ENABLE_LOW; + } else { + /* + * Set DTR line configuration of 95x UART to DTR mode (0,0). + * In this mode the DTR pin is compatible with 16C450, 16C550, + * 16C650 and 16c670 (i.e. normal). + */ + dtrlc = UART_ACR_DTRLC_COMPAT; + } + + kuart_enhanced_mode(up, true); + kuart_dtr_line_config(up, dtrlc); + kuart_enhanced_mode(up, false); + + if (kuart->flags & KUART_USE_CAPABILITY) { + /* activate selected physical interface */ + kuart_set_phy_mode(kuart, mode); + } + + kuart->mode = mode; + + return 0; +} + +static int kuart_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct device *dev = &auxdev->dev; + struct uart_8250_port uart = {}; + struct resource res; + struct kuart *kuart; + int retval; + + kuart = devm_kzalloc(dev, sizeof(*kuart), GFP_KERNEL); + if (!kuart) + return -ENOMEM; + kuart->auxdev = container_of(auxdev, struct keba_uart_auxdev, auxdev); + kuart->flags = id->driver_data; + auxiliary_set_drvdata(auxdev, kuart); + + /* + * map only memory in front of UART registers, UART registers will be + * mapped by serial port + */ + res = kuart->auxdev->io; + res.end = res.start + KUART_BASE - 1; + kuart->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(kuart->base)) + return PTR_ERR(kuart->base); + + if (kuart->flags & KUART_USE_CAPABILITY) { + /* + * supported modes are read from capability register, at least + * one mode other than none must be supported + */ + kuart->capability = ioread8(kuart->base + KUART_CAPABILITY) & + KUART_CAPABILITY_MASK; + if ((kuart->capability & ~KUART_CAPABILITY_NONE) == 0) + return -EIO; + } + + spin_lock_init(&uart.port.lock); + uart.port.dev = dev; + uart.port.mapbase = kuart->auxdev->io.start + KUART_BASE; + uart.port.irq = kuart->auxdev->irq; + uart.port.uartclk = KUART_CLK; + uart.port.private_data = kuart; + + /* 8 bit registers are 32 bit aligned => shift register offset */ + uart.port.iotype = UPIO_MEM32; + uart.port.regshift = KUART_REGSHIFT; + + /* + * UART mixes 16550, 16750 and 16C950 (for RS485) standard => auto + * configuration works best + */ + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_IOREMAP; + + /* + * UART supports RS485, RS422 and RS232 with switching of physical + * interface + */ + uart.port.rs485_config = kuart_rs485_config; + if (kuart->flags & KUART_RS485) { + uart.port.rs485_supported.flags = SER_RS485_ENABLED | + SER_RS485_RTS_ON_SEND; + uart.port.rs485.flags = SER_RS485_ENABLED | + SER_RS485_RTS_ON_SEND; + } + if (kuart->flags & KUART_USE_CAPABILITY) { + /* default mode priority is RS485 > RS422 > RS232 */ + if (kuart->capability & KUART_CAPABILITY_RS422) { + uart.port.rs485_supported.flags |= SER_RS485_ENABLED | + SER_RS485_RTS_ON_SEND | + SER_RS485_MODE_RS422; + uart.port.rs485.flags = SER_RS485_ENABLED | + SER_RS485_RTS_ON_SEND | + SER_RS485_MODE_RS422; + } + if (kuart->capability & KUART_CAPABILITY_RS485) { + uart.port.rs485_supported.flags |= SER_RS485_ENABLED | + SER_RS485_RTS_ON_SEND; + uart.port.rs485.flags = SER_RS485_ENABLED | + SER_RS485_RTS_ON_SEND; + } + } + + retval = serial8250_register_8250_port(&uart); + if (retval < 0) { + dev_err(&auxdev->dev, "UART registration failed!\n"); + return retval; + } + kuart->line = retval; + + return 0; +} + +static void kuart_remove(struct auxiliary_device *auxdev) +{ + struct kuart *kuart = auxiliary_get_drvdata(auxdev); + + if (kuart->flags & KUART_USE_CAPABILITY) + kuart_set_phy_mode(kuart, KUART_MODE_NONE); + + serial8250_unregister_port(kuart->line); +} + +static const struct auxiliary_device_id kuart_devtype_aux[] = { + { .name = "keba.rs485-uart", .driver_data = KUART_RS485 }, + { .name = "keba.rs232-uart", .driver_data = 0 }, + { .name = "keba.uart", .driver_data = KUART_USE_CAPABILITY }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, kuart_devtype_aux); + +static struct auxiliary_driver kuart_driver_aux = { + .name = KUART, + .id_table = kuart_devtype_aux, + .probe = kuart_probe, + .remove = kuart_remove, +}; +module_auxiliary_driver(kuart_driver_aux); + +MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>"); +MODULE_DESCRIPTION("KEBA 8250 serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c new file mode 100644 index 000000000000..53153a116c01 --- /dev/null +++ b/drivers/tty/serial/8250/8250_loongson.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Serial Port driver for Loongson family chips + * + * Copyright (C) 2020-2025 Loongson Technology Corporation Limited + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/property.h> +#include <linux/math.h> +#include <linux/mod_devicetable.h> +#include <linux/pm.h> +#include <linux/reset.h> + +#include "8250.h" + +/* Divisor Latch Fraction Register */ +#define LOONGSON_UART_DLF 0x2 + +#define LOONGSON_QUOT_FRAC_MASK GENMASK(7, 0) +#define LOONGSON_QUOT_DIV_MASK GENMASK(15, 8) + +struct loongson_uart_ddata { + bool has_frac; + u8 mcr_invert; + u8 msr_invert; +}; + +static const struct loongson_uart_ddata ls2k0500_uart_data = { + .has_frac = false, + .mcr_invert = UART_MCR_RTS | UART_MCR_DTR, + .msr_invert = UART_MSR_CTS | UART_MSR_DSR, +}; + +static const struct loongson_uart_ddata ls2k1500_uart_data = { + .has_frac = true, + .mcr_invert = UART_MCR_RTS | UART_MCR_DTR, + .msr_invert = 0, +}; + +struct loongson_uart_priv { + int line; + struct clk *clk; + struct resource *res; + struct reset_control *rst; + const struct loongson_uart_ddata *ddata; +}; + +static u8 serial_fixup(struct uart_port *p, unsigned int offset, u8 val) +{ + struct loongson_uart_priv *priv = p->private_data; + + switch (offset) { + case UART_MCR: + return val ^ priv->ddata->mcr_invert; + case UART_MSR: + return val ^ priv->ddata->msr_invert; + default: + return val; + } +} + +static u32 loongson_serial_in(struct uart_port *p, unsigned int offset) +{ + u8 val; + + val = readb(p->membase + (offset << p->regshift)); + + return serial_fixup(p, offset, val); +} + +static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value) +{ + u8 val; + + offset <<= p->regshift; + val = serial_fixup(p, offset, value); + writeb(val, p->membase + offset); +} + +static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud, + unsigned int *frac) +{ + unsigned int quot; + + quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud); + *frac = FIELD_GET(LOONGSON_QUOT_FRAC_MASK, quot); + + return FIELD_GET(LOONGSON_QUOT_DIV_MASK, quot); +} + +static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); + serial_dl_write(up, quot); + serial_port_out(port, LOONGSON_UART_DLF, quot_frac); +} + +static int loongson_uart_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uart_8250_port uart = {}; + struct loongson_uart_priv *priv; + struct uart_port *port; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ddata = device_get_match_data(dev); + + port = &uart.port; + spin_lock_init(&port->lock); + port->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP; + port->iotype = UPIO_MEM; + port->regshift = 0; + port->dev = dev; + port->type = PORT_16550A; + port->private_data = priv; + + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res); + if (!port->membase) + return -ENOMEM; + + port->mapbase = priv->res->start; + port->mapsize = resource_size(priv->res); + port->serial_in = loongson_serial_in; + port->serial_out = loongson_serial_out; + + if (priv->ddata->has_frac) { + port->get_divisor = loongson_frac_get_divisor; + port->set_divisor = loongson_frac_set_divisor; + } + + ret = uart_read_port_properties(port); + if (ret) + return ret; + + if (!port->uartclk) { + priv->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "Unable to determine clock frequency!\n"); + port->uartclk = clk_get_rate(priv->clk); + } + + priv->rst = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(priv->rst)) + return PTR_ERR(priv->rst); + + ret = reset_control_deassert(priv->rst); + if (ret) + return ret; + + ret = serial8250_register_8250_port(&uart); + if (ret < 0) { + reset_control_assert(priv->rst); + return ret; + } + + priv->line = ret; + platform_set_drvdata(pdev, priv); + + return 0; +} + +static void loongson_uart_remove(struct platform_device *pdev) +{ + struct loongson_uart_priv *priv = platform_get_drvdata(pdev); + + serial8250_unregister_port(priv->line); + reset_control_assert(priv->rst); +} + +static int loongson_uart_suspend(struct device *dev) +{ + struct loongson_uart_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + + serial8250_suspend_port(priv->line); + + if (!uart_console(&up->port) || console_suspend_enabled) + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int loongson_uart_resume(struct device *dev) +{ + struct loongson_uart_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + int ret; + + if (!uart_console(&up->port) || console_suspend_enabled) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + serial8250_resume_port(priv->line); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(loongson_uart_pm_ops, loongson_uart_suspend, + loongson_uart_resume); + +static const struct of_device_id loongson_uart_of_ids[] = { + { .compatible = "loongson,ls2k0500-uart", .data = &ls2k0500_uart_data }, + { .compatible = "loongson,ls2k1500-uart", .data = &ls2k1500_uart_data }, + { }, +}; +MODULE_DEVICE_TABLE(of, loongson_uart_of_ids); + +static struct platform_driver loongson_uart_driver = { + .probe = loongson_uart_probe, + .remove = loongson_uart_remove, + .driver = { + .name = "loongson-uart", + .pm = pm_ptr(&loongson_uart_pm_ops), + .of_match_table = loongson_uart_of_ids, + }, +}; + +module_platform_driver(loongson_uart_driver); + +MODULE_DESCRIPTION("Loongson UART driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited."); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 570e25d6f37e..6c0489c9c253 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -32,7 +32,7 @@ struct lpc18xx_uart_data { int line; }; -static int lpc18xx_rs485_config(struct uart_port *port, +static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct uart_8250_port *up = up_to_u8250p(port); @@ -40,24 +40,12 @@ static int lpc18xx_rs485_config(struct uart_port *port, u32 rs485_dly_reg = 0; unsigned baud_clk; - if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND; - if (rs485->flags & SER_RS485_ENABLED) { rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN | LPC18XX_UART_RS485CTRL_DCTRL; - if (rs485->flags & SER_RS485_RTS_ON_SEND) { + if (rs485->flags & SER_RS485_RTS_ON_SEND) rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV; - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - } else { - rs485->flags |= SER_RS485_RTS_AFTER_SEND; - } } if (rs485->delay_rts_after_send) { @@ -73,18 +61,13 @@ static int lpc18xx_rs485_config(struct uart_port *port, / baud_clk; } - /* Delay RTS before send not supported */ - rs485->delay_rts_before_send = 0; - serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg); serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg); - port->rs485 = *rs485; - return 0; } -static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value) +static void lpc18xx_uart_serial_out(struct uart_port *p, unsigned int offset, u32 value) { /* * For DMA mode one must ensure that the UART_FCR_DMA_SELECT @@ -98,16 +81,18 @@ static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value) writel(value, p->membase + offset); } +static const struct serial_rs485 lpc18xx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + .delay_rts_after_send = 1, + /* Delay RTS before send is not supported */ +}; + static int lpc18xx_serial_probe(struct platform_device *pdev) { struct lpc18xx_uart_data *data; struct uart_8250_port uart; struct resource *res; - int irq, ret; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -150,26 +135,27 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) goto dis_clk_reg; } - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - uart.port.line = ret; - data->dma.rx_param = data; data->dma.tx_param = data; spin_lock_init(&uart.port.lock); uart.port.dev = &pdev->dev; - uart.port.irq = irq; - uart.port.iotype = UPIO_MEM32; uart.port.mapbase = res->start; - uart.port.regshift = 2; uart.port.type = PORT_16550A; uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; uart.port.uartclk = clk_get_rate(data->clk_uart); uart.port.private_data = data; uart.port.rs485_config = lpc18xx_rs485_config; + uart.port.rs485_supported = lpc18xx_rs485_supported; uart.port.serial_out = lpc18xx_uart_serial_out; + ret = uart_read_port_properties(&uart.port); + if (ret) + goto dis_uart_clk; + + uart.port.iotype = UPIO_MEM32; + uart.port.regshift = 2; + uart.dma = &data->dma; uart.dma->rxconf.src_maxburst = 1; uart.dma->txconf.dst_maxburst = 1; @@ -192,15 +178,13 @@ dis_clk_reg: return ret; } -static int lpc18xx_serial_remove(struct platform_device *pdev) +static void lpc18xx_serial_remove(struct platform_device *pdev) { struct lpc18xx_uart_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk_uart); clk_disable_unprepare(data->clk_reg); - - return 0; } static const struct of_device_id lpc18xx_serial_match[] = { diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 4dee8a9e0c95..776ec1ef29d6 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -70,7 +70,7 @@ static inline struct lpss8250 *to_lpss8250(struct dw8250_port_data *data) } static void byt_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); struct lpss8250 *lpss = to_lpss8250(p->private_data); @@ -100,11 +100,7 @@ static void byt_set_termios(struct uart_port *p, struct ktermios *termios, reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; writel(reg, p->membase + BYT_PRV_CLK); - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); + dw8250_do_set_termios(p, termios, old); } static unsigned int byt_get_mctrl(struct uart_port *port) @@ -121,8 +117,7 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { struct dw_dma_slave *param = &lpss->dma_param; struct pci_dev *pdev = to_pci_dev(port->dev); - unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); - struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn); + struct pci_dev *dma_dev; switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: @@ -141,6 +136,8 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return -EINVAL; } + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); + param->dma_dev = &dma_dev->dev; param->m_master = 0; param->p_master = 1; @@ -156,11 +153,41 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return 0; } +static void byt_serial_exit(struct lpss8250 *lpss) +{ + struct dw_dma_slave *param = &lpss->dma_param; + + /* Paired with pci_get_slot() in the byt_serial_setup() above */ + put_device(param->dma_dev); +} + static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { + struct uart_8250_dma *dma = &lpss->data.dma; + struct uart_8250_port *up = up_to_u8250p(port); + + /* + * This simply makes the checks in the 8250_port to try the DMA + * channel request which in turn uses the magic of ACPI tables + * parsing (see drivers/dma/acpi-dma.c for the details) and + * matching with the registered General Purpose DMA controllers. + */ + up->dma = dma; + + lpss->dma_maxburst = 16; + + port->set_termios = dw8250_do_set_termios; + return 0; } +static void ehl_serial_exit(struct lpss8250 *lpss) +{ + struct uart_8250_port *up = serial8250_get_port(lpss->data.line); + + up->dma = NULL; +} + #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, @@ -252,28 +279,32 @@ static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port struct dw_dma_slave *rx_param, *tx_param; struct device *dev = port->port.dev; - if (!lpss->dma_param.dma_dev) + if (!lpss->dma_param.dma_dev) { + dma = port->dma; + if (dma) + goto out_configuration_only; + return 0; + } - rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + rx_param = devm_kmemdup(dev, &lpss->dma_param, sizeof(*rx_param), GFP_KERNEL); if (!rx_param) return -ENOMEM; - tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + tx_param = devm_kmemdup(dev, &lpss->dma_param, sizeof(*tx_param), GFP_KERNEL); if (!tx_param) return -ENOMEM; - *rx_param = lpss->dma_param; - dma->rxconf.src_maxburst = lpss->dma_maxburst; - - *tx_param = lpss->dma_param; - dma->txconf.dst_maxburst = lpss->dma_maxburst; - dma->fn = lpss8250_dma_filter; dma->rx_param = rx_param; dma->tx_param = tx_param; port->dma = dma; + +out_configuration_only: + dma->rxconf.src_maxburst = lpss->dma_maxburst; + dma->txconf.dst_maxburst = lpss->dma_maxburst; + return 0; } @@ -305,7 +336,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) uart.port.irq = pci_irq_vector(pdev, 0); uart.port.private_data = &lpss->data; uart.port.type = PORT_16550A; - uart.port.iotype = UPIO_MEM; + uart.port.iotype = UPIO_MEM32; uart.port.regshift = 2; uart.port.uartclk = lpss->board->base_baud * 16; uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE; @@ -335,8 +366,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_exit: - if (lpss->board->exit) - lpss->board->exit(lpss); + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); return ret; } @@ -347,8 +377,7 @@ static void lpss8250_remove(struct pci_dev *pdev) serial8250_unregister_port(lpss->data.line); - if (lpss->board->exit) - lpss->board->exit(lpss); + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); } @@ -356,12 +385,14 @@ static const struct lpss8250_board byt_board = { .freq = 100000000, .base_baud = 2764800, .setup = byt_serial_setup, + .exit = byt_serial_exit, }; static const struct lpss8250_board ehl_board = { .freq = 200000000, .base_baud = 12500000, .setup = ehl_serial_setup, + .exit = ehl_serial_exit, }; static const struct lpss8250_board qrk_board = { diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index e985f344b2dd..a78ef35c8187 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -7,17 +7,47 @@ #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/serial_8250.h> -#include <uapi/linux/serial_core.h> #define MEN_UART_ID_Z025 0x19 #define MEN_UART_ID_Z057 0x39 #define MEN_UART_ID_Z125 0x7d -#define MEN_UART_MEM_SIZE 0x10 +/* + * IP Cores Z025 and Z057 can have up to 4 UART + * The UARTs available are stored in a global + * register saved in physical address + 0x40 + * Is saved as follows: + * + * 7 0 + * +------+-------+-------+-------+-------+-------+-------+-------+ + * |UART4 | UART3 | UART2 | UART1 | U4irq | U3irq | U2irq | U1irq | + * +------+-------+-------+-------+-------+-------+-------+-------+ + */ +#define MEN_UART1_MASK 0x01 +#define MEN_UART2_MASK 0x02 +#define MEN_UART3_MASK 0x04 +#define MEN_UART4_MASK 0x08 + +#define MEN_Z125_UARTS_AVAILABLE 0x01 + +#define MEN_Z025_MAX_UARTS 4 +#define MEN_UART_MEM_SIZE 0x10 +#define MEM_UART_REGISTER_SIZE 0x01 +#define MEN_Z025_REGISTER_OFFSET 0x40 + +#define MEN_UART1_OFFSET 0 +#define MEN_UART2_OFFSET (MEN_UART1_OFFSET + MEN_UART_MEM_SIZE) +#define MEN_UART3_OFFSET (MEN_UART2_OFFSET + MEN_UART_MEM_SIZE) +#define MEN_UART4_OFFSET (MEN_UART3_OFFSET + MEN_UART_MEM_SIZE) + +#define MEN_READ_REGISTER(addr) readb(addr) + +#define MAX_PORTS 4 struct serial_8250_men_mcb_data { - struct uart_8250_port uart; - int line; + int num_ports; + int line[MAX_PORTS]; + unsigned int offset[MAX_PORTS]; }; /* @@ -38,10 +68,10 @@ static u32 men_lookup_uartclk(struct mcb_device *mdev) clkval = 1041666; else if (strncmp(mdev->bus->name, "F216", 4) == 0) clkval = 1843200; - else if (strncmp(mdev->bus->name, "G215", 4) == 0) - clkval = 1843200; else if (strncmp(mdev->bus->name, "F210", 4) == 0) clkval = 115200; + else if (strstr(mdev->bus->name, "215")) + clkval = 1843200; else dev_info(&mdev->dev, "board not detected, using default uartclk\n"); @@ -51,16 +81,98 @@ static u32 men_lookup_uartclk(struct mcb_device *mdev) return clkval; } -static unsigned int get_num_ports(struct mcb_device *mdev, - void __iomem *membase) +static int read_uarts_available_from_register(struct resource *mem_res, + u8 *uarts_available) +{ + void __iomem *mem; + int reg_value; + + if (!request_mem_region(mem_res->start + MEN_Z025_REGISTER_OFFSET, + MEM_UART_REGISTER_SIZE, KBUILD_MODNAME)) { + return -EBUSY; + } + + mem = ioremap(mem_res->start + MEN_Z025_REGISTER_OFFSET, + MEM_UART_REGISTER_SIZE); + if (!mem) { + release_mem_region(mem_res->start + MEN_Z025_REGISTER_OFFSET, + MEM_UART_REGISTER_SIZE); + return -ENOMEM; + } + + reg_value = MEN_READ_REGISTER(mem); + + iounmap(mem); + + release_mem_region(mem_res->start + MEN_Z025_REGISTER_OFFSET, + MEM_UART_REGISTER_SIZE); + + *uarts_available = reg_value >> 4; + + return 0; +} + +static int read_serial_data(struct mcb_device *mdev, + struct resource *mem_res, + struct serial_8250_men_mcb_data *serial_data) +{ + u8 uarts_available; + int count = 0; + int mask; + int res; + int i; + + res = read_uarts_available_from_register(mem_res, &uarts_available); + if (res < 0) + return res; + + for (i = 0; i < MAX_PORTS; i++) { + mask = 0x1 << i; + switch (uarts_available & mask) { + case MEN_UART1_MASK: + serial_data->offset[count] = MEN_UART1_OFFSET; + count++; + break; + case MEN_UART2_MASK: + serial_data->offset[count] = MEN_UART2_OFFSET; + count++; + break; + case MEN_UART3_MASK: + serial_data->offset[count] = MEN_UART3_OFFSET; + count++; + break; + case MEN_UART4_MASK: + serial_data->offset[count] = MEN_UART4_OFFSET; + count++; + break; + default: + return -EINVAL; + } + } + + if (count <= 0 || count > MAX_PORTS) { + dev_err(&mdev->dev, "unexpected number of ports: %u\n", + count); + return -ENODEV; + } + + serial_data->num_ports = count; + + return 0; +} + +static int init_serial_data(struct mcb_device *mdev, + struct resource *mem_res, + struct serial_8250_men_mcb_data *serial_data) { switch (mdev->id) { case MEN_UART_ID_Z125: - return 1U; + serial_data->num_ports = 1; + serial_data->offset[0] = 0; + return 0; case MEN_UART_ID_Z025: - return readb(membase) >> 4; case MEN_UART_ID_Z057: - return 4U; + return read_serial_data(mdev, mem_res, serial_data); default: dev_err(&mdev->dev, "no supported device!\n"); return -ENODEV; @@ -70,62 +182,54 @@ static unsigned int get_num_ports(struct mcb_device *mdev, static int serial_8250_men_mcb_probe(struct mcb_device *mdev, const struct mcb_device_id *id) { + struct uart_8250_port uart; struct serial_8250_men_mcb_data *data; struct resource *mem; - int num_ports; int i; - void __iomem *membase; + int res; mem = mcb_get_resource(mdev, IORESOURCE_MEM); if (mem == NULL) return -ENXIO; - membase = devm_ioremap_resource(&mdev->dev, mem); - if (IS_ERR(membase)) - return PTR_ERR_OR_ZERO(membase); - - num_ports = get_num_ports(mdev, membase); - dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n", - mdev->id, num_ports); - - if (num_ports <= 0 || num_ports > 4) { - dev_err(&mdev->dev, "unexpected number of ports: %u\n", - num_ports); - return -ENODEV; - } - - data = devm_kcalloc(&mdev->dev, num_ports, + data = devm_kzalloc(&mdev->dev, sizeof(struct serial_8250_men_mcb_data), GFP_KERNEL); if (!data) return -ENOMEM; + res = init_serial_data(mdev, mem, data); + if (res < 0) + return res; + + dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n", + mdev->id, data->num_ports); + mcb_set_drvdata(mdev, data); - for (i = 0; i < num_ports; i++) { - data[i].uart.port.dev = mdev->dma_dev; - spin_lock_init(&data[i].uart.port.lock); - - data[i].uart.port.type = PORT_16550; - data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ - | UPF_FIXED_TYPE; - data[i].uart.port.iotype = UPIO_MEM; - data[i].uart.port.uartclk = men_lookup_uartclk(mdev); - data[i].uart.port.regshift = 0; - data[i].uart.port.irq = mcb_get_irq(mdev); - data[i].uart.port.membase = membase; - data[i].uart.port.fifosize = 60; - data[i].uart.port.mapbase = (unsigned long) mem->start - + i * MEN_UART_MEM_SIZE; - data[i].uart.port.iobase = data[i].uart.port.mapbase; + for (i = 0; i < data->num_ports; i++) { + memset(&uart, 0, sizeof(struct uart_8250_port)); + spin_lock_init(&uart.port.lock); + + uart.port.flags = UPF_SKIP_TEST | + UPF_SHARE_IRQ | + UPF_BOOT_AUTOCONF | + UPF_IOREMAP; + uart.port.iotype = UPIO_MEM; + uart.port.uartclk = men_lookup_uartclk(mdev); + uart.port.irq = mcb_get_irq(mdev); + uart.port.mapbase = (unsigned long) mem->start + + data->offset[i]; /* ok, register the port */ - data[i].line = serial8250_register_8250_port(&data[i].uart); - if (data[i].line < 0) { + res = serial8250_register_8250_port(&uart); + if (res < 0) { dev_err(&mdev->dev, "unable to register UART port\n"); - return data[i].line; + return res; } - dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line); + + data->line[i] = res; + dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data->line[i]); } return 0; @@ -133,20 +237,14 @@ static int serial_8250_men_mcb_probe(struct mcb_device *mdev, static void serial_8250_men_mcb_remove(struct mcb_device *mdev) { - int num_ports, i; + int i; struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev); if (!data) return; - num_ports = get_num_ports(mdev, data[0].uart.port.membase); - if (num_ports < 0 || num_ports > 4) { - dev_err(&mdev->dev, "error retrieving number of ports!\n"); - return; - } - - for (i = 0; i < num_ports; i++) - serial8250_unregister_port(data[i].line); + for (i = 0; i < data->num_ports; i++) + serial8250_unregister_port(data->line[i]); } static const struct mcb_device_id serial_8250_men_mcb_ids[] = { @@ -160,7 +258,6 @@ MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids); static struct mcb_driver mcb_driver = { .driver = { .name = "8250_men_mcb", - .owner = THIS_MODULE, }, .probe = serial_8250_men_mcb_probe, .remove = serial_8250_men_mcb_remove, @@ -174,4 +271,4 @@ MODULE_AUTHOR("Michael Moese <michael.moese@men.de"); MODULE_ALIAS("mcb:16z125"); MODULE_ALIAS("mcb:16z025"); MODULE_ALIAS("mcb:16z057"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index efa0515139f8..8ec03863606e 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -12,7 +12,6 @@ #include <linux/rational.h> #include <linux/dma/hsu.h> -#include <linux/8250_pci.h> #include "8250.h" @@ -32,9 +31,9 @@ struct mid8250; struct mid8250_board { - unsigned int flags; unsigned long freq; unsigned int base_baud; + unsigned int bar; int (*setup)(struct mid8250 *, struct uart_port *p); void (*exit)(struct mid8250 *); }; @@ -73,6 +72,11 @@ static int pnw_setup(struct mid8250 *mid, struct uart_port *p) return 0; } +static void pnw_exit(struct mid8250 *mid) +{ + pci_dev_put(mid->dma_dev); +} + static int tng_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; @@ -124,6 +128,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) return 0; } +static void tng_exit(struct mid8250 *mid) +{ + pci_dev_put(mid->dma_dev); +} + static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; @@ -159,7 +168,6 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p) { struct hsu_dma_chip *chip = &mid->dma_chip; struct pci_dev *pdev = to_pci_dev(p->dev); - unsigned int bar = FL_GET_BASE(mid->board->flags); int ret; pci_set_master(pdev); @@ -173,7 +181,7 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p) chip->dev = &pdev->dev; chip->irq = pci_irq_vector(pdev, 0); chip->regs = p->membase; - chip->length = pci_resource_len(pdev, bar); + chip->length = pci_resource_len(pdev, mid->board->bar); chip->offset = DNV_DMA_CHAN_OFFSET; /* Falling back to PIO mode if DMA probing fails */ @@ -196,9 +204,8 @@ static void dnv_exit(struct mid8250 *mid) /*****************************************************************************/ -static void mid8250_set_termios(struct uart_port *p, - struct ktermios *termios, - struct ktermios *old) +static void mid8250_set_termios(struct uart_port *p, struct ktermios *termios, + const struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); struct mid8250 *mid = p->private_data; @@ -282,7 +289,6 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct uart_8250_port uart; struct mid8250 *mid; - unsigned int bar; int ret; ret = pcim_enable_device(pdev); @@ -294,7 +300,6 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; mid->board = (struct mid8250_board *)id->driver_data; - bar = FL_GET_BASE(mid->board->flags); memset(&uart, 0, sizeof(struct uart_8250_port)); @@ -307,16 +312,14 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE; uart.port.set_termios = mid8250_set_termios; - uart.port.mapbase = pci_resource_start(pdev, bar); - uart.port.membase = pcim_iomap(pdev, bar, 0); + uart.port.mapbase = pci_resource_start(pdev, mid->board->bar); + uart.port.membase = pcim_iomap(pdev, mid->board->bar, 0); if (!uart.port.membase) return -ENOMEM; - if (mid->board->setup) { - ret = mid->board->setup(mid, &uart.port); - if (ret) - return ret; - } + ret = mid->board->setup(mid, &uart.port); + if (ret) + return ret; ret = mid8250_dma_setup(mid, &uart); if (ret) @@ -330,9 +333,9 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, mid); return 0; + err: - if (mid->board->exit) - mid->board->exit(mid); + mid->board->exit(mid); return ret; } @@ -342,42 +345,41 @@ static void mid8250_remove(struct pci_dev *pdev) serial8250_unregister_port(mid->line); - if (mid->board->exit) - mid->board->exit(mid); + mid->board->exit(mid); } static const struct mid8250_board pnw_board = { - .flags = FL_BASE0, .freq = 50000000, .base_baud = 115200, + .bar = 0, .setup = pnw_setup, + .exit = pnw_exit, }; static const struct mid8250_board tng_board = { - .flags = FL_BASE0, .freq = 38400000, .base_baud = 1843200, + .bar = 0, .setup = tng_setup, + .exit = tng_exit, }; static const struct mid8250_board dnv_board = { - .flags = FL_BASE1, .freq = 133333333, .base_baud = 115200, + .bar = 1, .setup = dnv_setup, .exit = dnv_exit, }; -#define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board } - static const struct pci_device_id pci_ids[] = { - MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART1, pnw_board), - MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART2, pnw_board), - MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART3, pnw_board), - MID_DEVICE(PCI_DEVICE_ID_INTEL_TNG_UART, tng_board), - MID_DEVICE(PCI_DEVICE_ID_INTEL_CDF_UART, dnv_board), - MID_DEVICE(PCI_DEVICE_ID_INTEL_DNV_UART, dnv_board), - { }, + { PCI_DEVICE_DATA(INTEL, PNW_UART1, &pnw_board) }, + { PCI_DEVICE_DATA(INTEL, PNW_UART2, &pnw_board) }, + { PCI_DEVICE_DATA(INTEL, PNW_UART3, &pnw_board) }, + { PCI_DEVICE_DATA(INTEL, TNG_UART, &tng_board) }, + { PCI_DEVICE_DATA(INTEL, CDF_UART, &dnv_board) }, + { PCI_DEVICE_DATA(INTEL, DNV_UART, &dnv_board) }, + { } }; MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index f839380c2f4c..5875a7b9b4b1 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -37,6 +37,7 @@ #define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */ #define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */ +#define MTK_UART_EFR 38 /* I/O: Extended Features Register */ #define MTK_UART_EFR_EN 0x10 /* Enable enhancement feature */ #define MTK_UART_EFR_RTS 0x40 /* Enable hardware rx flow control */ #define MTK_UART_EFR_CTS 0x80 /* Enable hardware tx flow control */ @@ -53,6 +54,9 @@ #define MTK_UART_TX_TRIGGER 1 #define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE +#define MTK_UART_XON1 40 /* I/O: Xon character 1 */ +#define MTK_UART_XOFF1 42 /* I/O: Xoff character 1 */ + #ifdef CONFIG_SERIAL_8250_DMA enum dma_rx_status { DMA_RX_START = 0, @@ -93,10 +97,13 @@ static void mtk8250_dma_rx_complete(void *param) struct dma_tx_state state; int copied, total, cnt; unsigned char *ptr; + unsigned long flags; if (data->rx_status == DMA_RX_SHUTDOWN) return; + uart_port_lock_irqsave(&up->port, &flags); + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); total = dma->rx_size - state.residue; cnt = total; @@ -120,6 +127,8 @@ static void mtk8250_dma_rx_complete(void *param) tty_flip_buffer_push(tty_port); mtk8250_rx_dma(up); + + uart_port_unlock_irqrestore(&up->port, flags); } static void mtk8250_rx_dma(struct uart_8250_port *up) @@ -164,7 +173,7 @@ static void mtk8250_dma_enable(struct uart_8250_port *up) MTK_UART_DMA_EN_RX | MTK_UART_DMA_EN_TX); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, MTK_UART_EFR, UART_EFR_ECB); serial_out(up, UART_LCR, lcr); if (dmaengine_slave_config(dma->rxchan, &dma->rxconf) != 0) @@ -190,7 +199,7 @@ static int mtk8250_startup(struct uart_port *port) if (up->dma) { data->rx_status = DMA_RX_START; - uart_circ_clear(&port->state->xmit); + kfifo_reset(&port->state->port.xmit_fifo); } #endif memset(&port->icount, 0, sizeof(port->icount)); @@ -200,24 +209,34 @@ static int mtk8250_startup(struct uart_port *port) static void mtk8250_shutdown(struct uart_port *port) { -#ifdef CONFIG_SERIAL_8250_DMA struct uart_8250_port *up = up_to_u8250p(port); struct mtk8250_data *data = port->private_data; + int irq = data->rx_wakeup_irq; +#ifdef CONFIG_SERIAL_8250_DMA if (up->dma) data->rx_status = DMA_RX_SHUTDOWN; #endif - return serial8250_do_shutdown(port); + serial8250_do_shutdown(port); + + if (irq >= 0) + serial8250_do_set_mctrl(&up->port, TIOCM_RTS); } static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); } static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); } @@ -226,8 +245,11 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) struct uart_port *port = &up->port; int lcr = serial_in(up, UART_LCR); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, MTK_UART_EFR, UART_EFR_ECB); serial_out(up, UART_LCR, lcr); lcr = serial_in(up, UART_LCR); @@ -236,7 +258,7 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); serial_out(up, MTK_UART_ESCAPE_EN, 0x00); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, serial_in(up, UART_EFR) & + serial_out(up, MTK_UART_EFR, serial_in(up, MTK_UART_EFR) & (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK))); serial_out(up, UART_LCR, lcr); mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI | @@ -250,8 +272,8 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /*enable hw flow control*/ - serial_out(up, UART_EFR, MTK_UART_EFR_HW_FC | - (serial_in(up, UART_EFR) & + serial_out(up, MTK_UART_EFR, MTK_UART_EFR_HW_FC | + (serial_in(up, MTK_UART_EFR) & (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)))); serial_out(up, UART_LCR, lcr); @@ -265,12 +287,12 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /*enable sw flow control */ - serial_out(up, UART_EFR, MTK_UART_EFR_XON1_XOFF1 | - (serial_in(up, UART_EFR) & + serial_out(up, MTK_UART_EFR, MTK_UART_EFR_XON1_XOFF1 | + (serial_in(up, MTK_UART_EFR) & (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)))); - serial_out(up, UART_XON1, START_CHAR(port->state->port.tty)); - serial_out(up, UART_XOFF1, STOP_CHAR(port->state->port.tty)); + serial_out(up, MTK_UART_XON1, START_CHAR(port->state->port.tty)); + serial_out(up, MTK_UART_XOFF1, STOP_CHAR(port->state->port.tty)); serial_out(up, UART_LCR, lcr); mtk8250_disable_intrs(up, MTK_UART_IER_CTSI|MTK_UART_IER_RTSI); mtk8250_enable_intrs(up, MTK_UART_IER_XOFFI); @@ -282,12 +304,12 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) static void mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - unsigned short fraction_L_mapping[] = { + static const unsigned short fraction_L_mapping[] = { 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF }; - unsigned short fraction_M_mapping[] = { + static const unsigned short fraction_M_mapping[] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 }; struct uart_8250_port *up = up_to_u8250p(port); @@ -306,13 +328,26 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, } #endif - serial8250_do_set_termios(port, termios, old); + /* + * Store the requested baud rate before calling the generic 8250 + * set_termios method. Standard 8250 port expects bauds to be + * no higher than (uartclk / 16) so the baud will be clamped if it + * gets out of that bound. Mediatek 8250 port supports speed + * higher than that, therefore we'll get original baud rate back + * after calling the generic set_termios method and recalculate + * the speed later in this method. + */ + baud = tty_termios_baud_rate(termios); + + serial8250_do_set_termios(port, termios, NULL); + + tty_termios_encode_baud_rate(termios, baud, baud); /* * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) * - * We need to recalcualte the quot register, as the claculation depends - * on the vaule in the highspeed register. + * We need to recalculate the quot register, as the calculation depends + * on the value in the highspeed register. * * Some baudrates are not supported by the chip, so we use the next * lower rate supported and update termios c_flag. @@ -337,7 +372,12 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); /* set DLAB we have cval saved in up->lcr from the call to the core */ serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); @@ -380,7 +420,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, if (uart_console(port)) up->port.cons->cflag = termios->c_cflag; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -395,12 +435,8 @@ static int __maybe_unused mtk8250_runtime_suspend(struct device *dev) while (serial_in(up, MTK_UART_DEBUG0)); - if (data->clk_count == 0U) { - dev_dbg(dev, "%s clock count is 0\n", __func__); - } else { - clk_disable_unprepare(data->bus_clk); - data->clk_count--; - } + clk_disable_unprepare(data->uart_clk); + clk_disable_unprepare(data->bus_clk); return 0; } @@ -408,19 +444,9 @@ static int __maybe_unused mtk8250_runtime_suspend(struct device *dev) static int __maybe_unused mtk8250_runtime_resume(struct device *dev) { struct mtk8250_data *data = dev_get_drvdata(dev); - int err; - if (data->clk_count > 0U) { - dev_dbg(dev, "%s clock count is %d\n", __func__, - data->clk_count); - } else { - err = clk_prepare_enable(data->bus_clk); - if (err) { - dev_warn(dev, "Can't enable bus clock\n"); - return err; - } - data->clk_count++; - } + clk_prepare_enable(data->bus_clk); + clk_prepare_enable(data->uart_clk); return 0; } @@ -429,14 +455,12 @@ static void mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { if (!state) - if (!mtk8250_runtime_resume(port->dev)) - pm_runtime_get_sync(port->dev); + pm_runtime_get_sync(port->dev); serial8250_do_pm(port, state, old); if (state) - if (!pm_runtime_put_sync_suspend(port->dev)) - mtk8250_runtime_suspend(port->dev); + pm_runtime_put_sync_suspend(port->dev); } #ifdef CONFIG_SERIAL_8250_DMA @@ -453,13 +477,13 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, int dmacnt; #endif - data->uart_clk = devm_clk_get(&pdev->dev, "baud"); + data->uart_clk = devm_clk_get_enabled(&pdev->dev, "baud"); if (IS_ERR(data->uart_clk)) { /* * For compatibility with older device trees try unnamed * clk when no baud clk can be found. */ - data->uart_clk = devm_clk_get(&pdev->dev, NULL); + data->uart_clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(data->uart_clk)) { dev_warn(&pdev->dev, "Can't get uart clock\n"); return PTR_ERR(data->uart_clk); @@ -468,7 +492,7 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, return 0; } - data->bus_clk = devm_clk_get(&pdev->dev, "bus"); + data->bus_clk = devm_clk_get_enabled(&pdev->dev, "bus"); if (IS_ERR(data->bus_clk)) return PTR_ERR(data->bus_clk); @@ -494,13 +518,17 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, static int mtk8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct mtk8250_data *data; - int err; + struct resource *regs; + int irq, err; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - if (!regs || !irq) { - dev_err(&pdev->dev, "no registers/irq defined\n"); + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); return -EINVAL; } @@ -524,7 +552,7 @@ static int mtk8250_probe(struct platform_device *pdev) spin_lock_init(&uart.port.lock); uart.port.mapbase = regs->start; - uart.port.irq = irq->start; + uart.port.irq = irq; uart.port.pm = mtk8250_do_pm; uart.port.type = PORT_16550; uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; @@ -547,21 +575,19 @@ static int mtk8250_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - pm_runtime_enable(&pdev->dev); - err = mtk8250_runtime_resume(&pdev->dev); - if (err) - return err; - data->line = serial8250_register_8250_port(&uart); if (data->line < 0) return data->line; data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0; } -static int mtk8250_remove(struct platform_device *pdev) +static void mtk8250_remove(struct platform_device *pdev) { struct mtk8250_data *data = platform_get_drvdata(pdev); @@ -571,11 +597,6 @@ static int mtk8250_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - if (!pm_runtime_status_suspended(&pdev->dev)) - mtk8250_runtime_suspend(&pdev->dev); - - return 0; } static int __maybe_unused mtk8250_suspend(struct device *dev) @@ -647,6 +668,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device, return -ENODEV; device->port.iotype = UPIO_MEM32; + device->port.regshift = 2; return early_serial8250_setup(device, NULL); } diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c new file mode 100644 index 000000000000..cb5b42b3609c --- /dev/null +++ b/drivers/tty/serial/8250/8250_ni.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NI 16550 UART Driver + * + * The National Instruments (NI) 16550 is a UART that is compatible with the + * TL16C550C and OX16C950B register interfaces, but has additional functions + * for RS-485 transceiver control. This driver implements support for the + * additional functionality on top of the standard serial8250 core. + * + * Copyright 2012-2023 National Instruments Corporation + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/serial_core.h> +#include <linux/types.h> + +#include "8250.h" + +/* Extra bits in UART_ACR */ +#define NI16550_ACR_AUTO_DTR_EN BIT(4) + +/* TFS - TX FIFO Size */ +#define NI16550_TFS_OFFSET 0x0C +/* RFS - RX FIFO Size */ +#define NI16550_RFS_OFFSET 0x0D + +/* PMR - Port Mode Register */ +#define NI16550_PMR_OFFSET 0x0E +/* PMR[1:0] - Port Capabilities */ +#define NI16550_PMR_CAP_MASK GENMASK(1, 0) +#define NI16550_PMR_NOT_IMPL FIELD_PREP(NI16550_PMR_CAP_MASK, 0) /* not implemented */ +#define NI16550_PMR_CAP_RS232 FIELD_PREP(NI16550_PMR_CAP_MASK, 1) /* RS-232 capable */ +#define NI16550_PMR_CAP_RS485 FIELD_PREP(NI16550_PMR_CAP_MASK, 2) /* RS-485 capable */ +#define NI16550_PMR_CAP_DUAL FIELD_PREP(NI16550_PMR_CAP_MASK, 3) /* dual-port */ +/* PMR[4] - Interface Mode */ +#define NI16550_PMR_MODE_MASK GENMASK(4, 4) +#define NI16550_PMR_MODE_RS232 FIELD_PREP(NI16550_PMR_MODE_MASK, 0) /* currently 232 */ +#define NI16550_PMR_MODE_RS485 FIELD_PREP(NI16550_PMR_MODE_MASK, 1) /* currently 485 */ + +/* PCR - Port Control Register */ +/* + * Wire Mode | Tx enabled? | Rx enabled? + * ---------------|----------------------|-------------------------- + * PCR_RS422 | Always | Always + * PCR_ECHO_RS485 | When DTR asserted | Always + * PCR_DTR_RS485 | When DTR asserted | Disabled when TX enabled + * PCR_AUTO_RS485 | When data in TX FIFO | Disabled when TX enabled + */ +#define NI16550_PCR_OFFSET 0x0F +#define NI16550_PCR_WIRE_MODE_MASK GENMASK(1, 0) +#define NI16550_PCR_RS422 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 0) +#define NI16550_PCR_ECHO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 1) +#define NI16550_PCR_DTR_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 2) +#define NI16550_PCR_AUTO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 3) +#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3) +#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6) + +/* flags for ni16550_device_info */ +#define NI_HAS_PMR BIT(0) + +struct ni16550_device_info { + u32 uartclk; + u8 prescaler; + u8 flags; +}; + +struct ni16550_data { + int line; + struct clk *clk; +}; + +static int ni16550_enable_transceivers(struct uart_port *port) +{ + u8 pcr; + + pcr = port->serial_in(port, NI16550_PCR_OFFSET); + pcr |= NI16550_PCR_TXVR_ENABLE_BIT; + dev_dbg(port->dev, "enable transceivers: write pcr: 0x%02x\n", pcr); + port->serial_out(port, NI16550_PCR_OFFSET, pcr); + + return 0; +} + +static int ni16550_disable_transceivers(struct uart_port *port) +{ + u8 pcr; + + pcr = serial_port_in(port, NI16550_PCR_OFFSET); + pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT; + dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr); + serial_port_out(port, NI16550_PCR_OFFSET, pcr); + + return 0; +} + +static int ni16550_rs485_config(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); + u8 pcr; + + pcr = serial_port_in(port, NI16550_PCR_OFFSET); + pcr &= ~NI16550_PCR_WIRE_MODE_MASK; + + if ((rs485->flags & SER_RS485_MODE_RS422) || + !(rs485->flags & SER_RS485_ENABLED)) { + /* RS-422 */ + pcr |= NI16550_PCR_RS422; + up->acr &= ~NI16550_ACR_AUTO_DTR_EN; + } else { + /* RS-485 2-wire Auto */ + pcr |= NI16550_PCR_AUTO_RS485; + up->acr |= NI16550_ACR_AUTO_DTR_EN; + } + + dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr); + serial_port_out(port, NI16550_PCR_OFFSET, pcr); + serial_icr_write(up, UART_ACR, up->acr); + + return 0; +} + +static bool is_pmr_rs232_mode(struct uart_8250_port *up) +{ + u8 pmr = serial_in(up, NI16550_PMR_OFFSET); + u8 pmr_mode = pmr & NI16550_PMR_MODE_MASK; + u8 pmr_cap = pmr & NI16550_PMR_CAP_MASK; + + /* + * If the PMR is not implemented, then by default NI UARTs are + * connected to RS-485 transceivers + */ + if (pmr_cap == NI16550_PMR_NOT_IMPL) + return false; + + if (pmr_cap == NI16550_PMR_CAP_DUAL) + /* + * If the port is dual-mode capable, then read the mode bit + * to know the current mode + */ + return pmr_mode == NI16550_PMR_MODE_RS232; + /* + * If it is not dual-mode capable, then decide based on the + * capability + */ + return pmr_cap == NI16550_PMR_CAP_RS232; +} + +static void ni16550_config_prescaler(struct uart_8250_port *up, + u8 prescaler) +{ + /* + * Page in the Enhanced Mode Registers + * Sets EFR[4] for Enhanced Mode. + */ + u8 lcr_value; + u8 efr_value; + + lcr_value = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + efr_value = serial_in(up, UART_EFR); + efr_value |= UART_EFR_ECB; + + serial_out(up, UART_EFR, efr_value); + + /* Page out the Enhanced Mode Registers */ + serial_out(up, UART_LCR, lcr_value); + + /* Set prescaler to CPR register. */ + serial_out(up, UART_SCR, UART_CPR); + serial_out(up, UART_ICR, prescaler); +} + +static const struct serial_rs485 ni16550_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, + /* + * delay_rts_* and RX_DURING_TX are not supported. + * + * RTS_{ON,AFTER}_SEND are supported, but ignored; the transceiver + * is connected in only one way and we don't need userspace to tell + * us, but want to retain compatibility with applications that do. + */ +}; + +static void ni16550_rs485_setup(struct uart_port *port) +{ + port->rs485_config = ni16550_rs485_config; + port->rs485_supported = ni16550_rs485_supported; + /* + * The hardware comes up by default in 2-wire auto mode and we + * set the flags to represent that + */ + port->rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; +} + +static int ni16550_port_startup(struct uart_port *port) +{ + int ret; + + ret = serial8250_do_startup(port); + if (ret) + return ret; + + return ni16550_enable_transceivers(port); +} + +static void ni16550_port_shutdown(struct uart_port *port) +{ + ni16550_disable_transceivers(port); + + serial8250_do_shutdown(port); +} + +static int ni16550_get_regs(struct platform_device *pdev, + struct uart_port *port) +{ + struct resource *regs; + + regs = platform_get_mem_or_io(pdev, 0); + if (!regs) + return dev_err_probe(&pdev->dev, -EINVAL, "no registers defined\n"); + + switch (resource_type(regs)) { + case IORESOURCE_IO: + port->iotype = UPIO_PORT; + port->iobase = regs->start; + + return 0; + case IORESOURCE_MEM: + port->iotype = UPIO_MEM; + port->mapbase = regs->start; + port->mapsize = resource_size(regs); + port->flags |= UPF_IOREMAP; + + return 0; + default: + return -EINVAL; + } +} + +/* + * Very old implementations don't have the TFS or RFS registers + * defined, so we may read all-0s or all-1s. For such devices, + * assume a FIFO size of 128. + */ +static u8 ni16550_read_fifo_size(struct uart_8250_port *uart, int reg) +{ + u8 value = serial_in(uart, reg); + + if (value == 0x00 || value == 0xFF) + return 128; + + return value; +} + +static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->mcr |= UART_MCR_CLKSEL; + serial8250_do_set_mctrl(port, mctrl); +} + +static int ni16550_probe(struct platform_device *pdev) +{ + struct uart_8250_port *uart __free(kfree) = NULL; + const struct ni16550_device_info *info; + struct device *dev = &pdev->dev; + unsigned int txfifosz, rxfifosz; + struct ni16550_data *data; + unsigned int prescaler; + const char *portmode; + bool rs232_property; + int ret; + + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&uart->port.lock); + + ret = ni16550_get_regs(pdev, &uart->port); + if (ret < 0) + return ret; + + /* early setup so that serial_in()/serial_out() work */ + serial8250_set_defaults(uart); + + info = device_get_match_data(dev); + + uart->port.dev = dev; + uart->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart->port.startup = ni16550_port_startup; + uart->port.shutdown = ni16550_port_shutdown; + + /* + * Hardware instantiation of FIFO sizes are held in registers. + */ + txfifosz = ni16550_read_fifo_size(uart, NI16550_TFS_OFFSET); + rxfifosz = ni16550_read_fifo_size(uart, NI16550_RFS_OFFSET); + + dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n", + txfifosz, rxfifosz); + + uart->port.type = PORT_16550A; + uart->port.fifosize = txfifosz; + uart->tx_loadsz = txfifosz; + uart->fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; + uart->capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR; + + /* + * Declaration of the base clock frequency can come from one of: + * - static declaration in this driver (for older ACPI IDs) + * - a "clock-frequency" ACPI + */ + uart->port.uartclk = info->uartclk; + + ret = uart_read_port_properties(&uart->port); + if (ret) + return ret; + + if (!uart->port.uartclk) { + data->clk = devm_clk_get_enabled(dev, NULL); + if (!IS_ERR(data->clk)) + uart->port.uartclk = clk_get_rate(data->clk); + } + + if (!uart->port.uartclk) + return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n"); + + prescaler = info->prescaler; + device_property_read_u32(dev, "clock-prescaler", &prescaler); + if (prescaler) { + uart->port.set_mctrl = ni16550_set_mctrl; + ni16550_config_prescaler(uart, (u8)prescaler); + } + + /* + * The determination of whether or not this is an RS-485 or RS-232 port + * can come from the PMR (if present), otherwise we're solely an RS-485 + * port. + * + * This is a device-specific property, and there are old devices in the + * field using "transceiver" as an ACPI property, so we have to check + * for that as well. + */ + if (!device_property_read_string(dev, "transceiver", &portmode)) { + rs232_property = strncmp(portmode, "RS-232", 6) == 0; + + dev_dbg(dev, "port is in %s mode (via device property)\n", + rs232_property ? "RS-232" : "RS-485"); + } else if (info->flags & NI_HAS_PMR) { + rs232_property = is_pmr_rs232_mode(uart); + + dev_dbg(dev, "port is in %s mode (via PMR)\n", + rs232_property ? "RS-232" : "RS-485"); + } else { + rs232_property = 0; + + dev_dbg(dev, "port is fixed as RS-485\n"); + } + + if (!rs232_property) { + /* + * Neither the 'transceiver' property nor the PMR indicate + * that this is an RS-232 port, so it must be an RS-485 one. + */ + ni16550_rs485_setup(&uart->port); + } + + ret = serial8250_register_8250_port(uart); + if (ret < 0) + return ret; + data->line = ret; + + platform_set_drvdata(pdev, data); + return 0; +} + +static void ni16550_remove(struct platform_device *pdev) +{ + struct ni16550_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); +} + +/* NI 16550 RS-485 Interface */ +static const struct ni16550_device_info nic7750 = { + .uartclk = 33333333, +}; + +/* NI CVS-145x RS-485 Interface */ +static const struct ni16550_device_info nic7772 = { + .uartclk = 1843200, + .flags = NI_HAS_PMR, +}; + +/* NI cRIO-904x RS-485 Interface */ +static const struct ni16550_device_info nic792b = { + /* Sets UART clock rate to 22.222 MHz with 1.125 prescale */ + .uartclk = 22222222, + .prescaler = 0x09, +}; + +/* NI sbRIO 96x8 RS-232/485 Interfaces */ +static const struct ni16550_device_info nic7a69 = { + /* Set UART clock rate to 29.629 MHz with 1.125 prescale */ + .uartclk = 29629629, + .prescaler = 0x09, +}; + +static const struct acpi_device_id ni16550_acpi_match[] = { + { "NIC7750", (kernel_ulong_t)&nic7750 }, + { "NIC7772", (kernel_ulong_t)&nic7772 }, + { "NIC792B", (kernel_ulong_t)&nic792b }, + { "NIC7A69", (kernel_ulong_t)&nic7a69 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match); + +static struct platform_driver ni16550_driver = { + .driver = { + .name = "ni16550", + .acpi_match_table = ni16550_acpi_match, + }, + .probe = ni16550_probe, + .remove = ni16550_remove, +}; + +module_platform_driver(ni16550_driver); + +MODULE_AUTHOR("Emerson Electric Co."); +MODULE_DESCRIPTION("NI 16550 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 65e9045dafe6..9799356b65f7 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -4,7 +4,10 @@ * * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp. */ + +#include <linux/bits.h> #include <linux/console.h> +#include <linux/math.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/serial_core.h> @@ -15,16 +18,69 @@ #include <linux/pm_runtime.h> #include <linux/clk.h> #include <linux/reset.h> +#include <linux/notifier.h> #include "8250.h" struct of_serial_info { struct clk *clk; + struct clk *bus_clk; struct reset_control *rst; int type; int line; + struct notifier_block clk_notifier; }; +/* Nuvoton NPCM timeout register */ +#define UART_NPCM_TOR 7 +#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ + +static int npcm_startup(struct uart_port *port) +{ + /* + * Nuvoton calls the scratch register 'UART_TOR' (timeout + * register). Enable it, and set TIOC (timeout interrupt + * comparator) to be 0x20 for correct operation. + */ + serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); + + return serial8250_do_startup(port); +} + +/* Nuvoton NPCM UARTs have a custom divisor calculation */ +static unsigned int npcm_get_divisor(struct uart_port *port, unsigned int baud, + unsigned int *frac) +{ + return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; +} + +static int npcm_setup(struct uart_port *port) +{ + port->get_divisor = npcm_get_divisor; + port->startup = npcm_startup; + return 0; +} + +static inline struct of_serial_info *clk_nb_to_info(struct notifier_block *nb) +{ + return container_of(nb, struct of_serial_info, clk_notifier); +} + +static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct of_serial_info *info = clk_nb_to_info(nb); + struct uart_8250_port *port8250 = serial8250_get_port(info->line); + struct clk_notifier_data *ndata = data; + + if (event == POST_RATE_CHANGE) { + serial8250_update_uartclk(&port8250->port, ndata->new_rate); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + /* * Fill a struct uart_port for a given device node */ @@ -33,139 +89,99 @@ static int of_platform_serial_setup(struct platform_device *ofdev, struct of_serial_info *info) { struct resource resource; - struct device_node *np = ofdev->dev.of_node; + struct device *dev = &ofdev->dev; + struct device_node *np = dev->of_node; struct uart_port *port = &up->port; - u32 clk, spd, prop; - int ret, irq; + u32 spd; + int ret; - memset(port, 0, sizeof *port); + memset(port, 0, sizeof(*port)); pm_runtime_enable(&ofdev->dev); pm_runtime_get_sync(&ofdev->dev); - if (of_property_read_u32(np, "clock-frequency", &clk)) { - - /* Get clk rate through clk driver if present */ - info->clk = devm_clk_get(&ofdev->dev, NULL); - if (IS_ERR(info->clk)) { - ret = PTR_ERR(info->clk); - if (ret != -EPROBE_DEFER) - dev_warn(&ofdev->dev, - "failed to get clock: %d\n", ret); - goto err_pmruntime; - } - - ret = clk_prepare_enable(info->clk); - if (ret < 0) - goto err_pmruntime; - - clk = clk_get_rate(info->clk); - } - /* If current-speed was set, then try not to change it. */ - if (of_property_read_u32(np, "current-speed", &spd) == 0) - port->custom_divisor = clk / (16 * spd); - ret = of_address_to_resource(np, 0, &resource); if (ret) { - dev_warn(&ofdev->dev, "invalid address\n"); - goto err_unprepare; + dev_err_probe(dev, ret, "invalid address\n"); + goto err_pmruntime; } - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | - UPF_FIXED_TYPE; + port->dev = &ofdev->dev; + port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; spin_lock_init(&port->lock); if (resource_type(&resource) == IORESOURCE_IO) { - port->iotype = UPIO_PORT; port->iobase = resource.start; } else { port->mapbase = resource.start; port->mapsize = resource_size(&resource); - - /* Check for shifted address mapping */ - if (of_property_read_u32(np, "reg-offset", &prop) == 0) - port->mapbase += prop; - - port->iotype = UPIO_MEM; - if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { - switch (prop) { - case 1: - port->iotype = UPIO_MEM; - break; - case 2: - port->iotype = UPIO_MEM16; - break; - case 4: - port->iotype = of_device_is_big_endian(np) ? - UPIO_MEM32BE : UPIO_MEM32; - break; - default: - dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", - prop); - ret = -EINVAL; - goto err_unprepare; - } - } port->flags |= UPF_IOREMAP; } - /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */ - if (of_device_is_compatible(np, "mrvl,mmp-uart")) - port->regshift = 2; - - /* Check for registers offset within the devices address range */ - if (of_property_read_u32(np, "reg-shift", &prop) == 0) - port->regshift = prop; + ret = uart_read_and_validate_port_properties(port); + if (ret) + goto err_pmruntime; - /* Check for fifo size */ - if (of_property_read_u32(np, "fifo-size", &prop) == 0) - port->fifosize = prop; + /* Get clk rate through clk driver if present */ + if (!port->uartclk) { + struct clk *bus_clk; - /* Check for a fixed line number */ - ret = of_alias_get_id(np, "serial"); - if (ret >= 0) - port->line = ret; + bus_clk = devm_clk_get_optional_enabled(dev, "bus"); + if (IS_ERR(bus_clk)) { + ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n"); + goto err_pmruntime; + } - irq = of_irq_get(np, 0); - if (irq < 0) { - if (irq == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_unprepare; + /* If the bus clock is required, core clock must be named */ + info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL); + if (IS_ERR(info->clk)) { + ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n"); + goto err_pmruntime; } - /* IRQ support not mandatory */ - irq = 0; + + info->bus_clk = bus_clk; + port->uartclk = clk_get_rate(info->clk); } + /* If current-speed was set, then try not to change it. */ + if (of_property_read_u32(np, "current-speed", &spd) == 0) + port->custom_divisor = port->uartclk / (16 * spd); - port->irq = irq; + /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */ + if (of_device_is_compatible(np, "mrvl,mmp-uart")) + port->regshift = 2; info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); if (IS_ERR(info->rst)) { ret = PTR_ERR(info->rst); - goto err_unprepare; + goto err_pmruntime; } ret = reset_control_deassert(info->rst); if (ret) - goto err_unprepare; + goto err_pmruntime; port->type = type; - port->uartclk = clk; - - if (of_property_read_bool(np, "no-loopback-test")) - port->flags |= UPF_SKIP_TEST; - - port->dev = &ofdev->dev; port->rs485_config = serial8250_em485_config; + port->rs485_supported = serial8250_em485_supported; up->rs485_start_tx = serial8250_em485_start_tx; up->rs485_stop_tx = serial8250_em485_stop_tx; switch (type) { case PORT_RT2880: - port->iotype = UPIO_AU; + ret = rt288x_setup(port); + break; + case PORT_NPCM: + ret = npcm_setup(port); + break; + default: + /* Nothing to do */ + ret = 0; break; } + if (ret) + goto err_pmruntime; - if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) && + if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) && (of_device_is_compatible(np, "fsl,ns16550") || of_device_is_compatible(np, "fsl,16550-FIFO64"))) { port->handle_irq = fsl8250_handle_irq; @@ -173,8 +189,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, } return 0; -err_unprepare: - clk_disable_unprepare(info->clk); err_pmruntime: pm_runtime_put_sync(&ofdev->dev); pm_runtime_disable(&ofdev->dev); @@ -192,6 +206,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev) u32 tx_threshold; int ret; + if (IS_ENABLED(CONFIG_SERIAL_8250_BCM7271) && + of_device_is_compatible(ofdev->dev.of_node, "brcm,bcm7271-uart")) + return -ENODEV; + port_type = (unsigned long)of_device_get_match_data(&ofdev->dev); if (port_type == PORT_UNKNOWN) return -EINVAL; @@ -232,12 +250,22 @@ static int of_platform_serial_probe(struct platform_device *ofdev) info->type = port_type; info->line = ret; platform_set_drvdata(ofdev, info); + + if (info->clk) { + info->clk_notifier.notifier_call = of_platform_serial_clk_notifier_cb; + ret = clk_notifier_register(info->clk, &info->clk_notifier); + if (ret) { + dev_err_probe(port8250.port.dev, ret, "Failed to set the clock notifier\n"); + goto err_unregister; + } + } + return 0; +err_unregister: + serial8250_unregister_port(info->line); err_dispose: - irq_dispose_mapping(port8250.port.irq); pm_runtime_put_sync(&ofdev->dev); pm_runtime_disable(&ofdev->dev); - clk_disable_unprepare(info->clk); err_free: kfree(info); return ret; @@ -246,18 +274,19 @@ err_free: /* * Release a line */ -static int of_platform_serial_remove(struct platform_device *ofdev) +static void of_platform_serial_remove(struct platform_device *ofdev) { struct of_serial_info *info = platform_get_drvdata(ofdev); + if (info->clk) + clk_notifier_unregister(info->clk, &info->clk_notifier); + serial8250_unregister_port(info->line); reset_control_assert(info->rst); pm_runtime_put_sync(&ofdev->dev); pm_runtime_disable(&ofdev->dev); - clk_disable_unprepare(info->clk); kfree(info); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -272,6 +301,7 @@ static int of_serial_suspend(struct device *dev) if (!uart_console(port) || console_suspend_enabled) { pm_runtime_put_sync(dev); clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->bus_clk); } return 0; } @@ -284,6 +314,7 @@ static int of_serial_resume(struct device *dev) if (!uart_console(port) || console_suspend_enabled) { pm_runtime_get_sync(dev); + clk_prepare_enable(info->bus_clk); clk_prepare_enable(info->clk); } @@ -313,11 +344,14 @@ static const struct of_device_id of_platform_serial_table[] = { .data = (void *)PORT_ALTR_16550_F64, }, { .compatible = "altr,16550-FIFO128", .data = (void *)PORT_ALTR_16550_F128, }, + { .compatible = "fsl,16550-FIFO64", + .data = (void *)PORT_16550A_FSL64, }, { .compatible = "mediatek,mtk-btif", .data = (void *)PORT_MTK_BTIF, }, { .compatible = "mrvl,mmp-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, }, + { .compatible = "nuvoton,wpcm450-uart", .data = (void *)PORT_NPCM, }, { .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, }, { /* end of list */ }, }; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 16cfb887c5a3..9e49ef48b851 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -8,6 +8,7 @@ * */ +#include <linux/atomic.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/io.h> @@ -18,8 +19,6 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/delay.h> #include <linux/pm_runtime.h> @@ -27,10 +26,14 @@ #include <linux/pm_qos.h> #include <linux/pm_wakeirq.h> #include <linux/dma-mapping.h> +#include <linux/sys_soc.h> +#include <linux/reboot.h> +#include <linux/pinctrl/consumer.h> #include "8250.h" #define DEFAULT_CLK_SPEED 48000000 +#define OMAP_UART_REGSHIFT 2 #define UART_ERRATA_i202_MDR1_ACCESS (1 << 0) #define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1) @@ -41,6 +44,9 @@ */ #define UART_ERRATA_CLOCK_DISABLE (1 << 3) #define UART_HAS_EFR2 BIT(4) +#define UART_HAS_RHR_IT_DIS BIT(5) +#define UART_RX_TIMEOUT_QUIRK BIT(6) +#define UART_HAS_NATIVE_RS485 BIT(7) #define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_TX_TRIG 4 @@ -94,14 +100,32 @@ #define OMAP_UART_REV_52 0x0502 #define OMAP_UART_REV_63 0x0603 +/* Interrupt Enable Register 2 */ +#define UART_OMAP_IER2 0x1B +#define UART_OMAP_IER2_RHR_IT_DIS BIT(2) + +/* Mode Definition Register 3 */ +#define UART_OMAP_MDR3 0x20 +#define UART_OMAP_MDR3_DIR_POL BIT(3) +#define UART_OMAP_MDR3_DIR_EN BIT(4) + /* Enhanced features register 2 */ #define UART_OMAP_EFR2 0x23 #define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6) +/* RX FIFO occupancy indicator */ +#define UART_OMAP_RX_LVL 0x19 + +/* Timeout low and High */ +#define UART_OMAP_TO_L 0x26 +#define UART_OMAP_TO_H 0x27 + struct omap8250_priv { + void __iomem *membase; int line; u8 habit; u8 mdr1; + u8 mdr3; u8 efr; u8 scr; u8 wer; @@ -112,9 +136,9 @@ struct omap8250_priv { u8 tx_trigger; u8 rx_trigger; + atomic_t active; bool is_suspending; int wakeirq; - int wakeups_enabled; u32 latency; u32 calc_latency; struct pm_qos_request pm_qos_request; @@ -123,6 +147,9 @@ struct omap8250_priv { spinlock_t rx_dma_lock; bool rx_dma_broken; bool throttled; + + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_wakeup; }; struct omap8250_dma_params { @@ -142,15 +169,19 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p); static inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { } #endif -static u32 uart_read(struct uart_8250_port *up, u32 reg) +static u32 uart_read(struct omap8250_priv *priv, u32 reg) { - return readl(up->port.membase + (reg << up->port.regshift)); + return readl(priv->membase + (reg << OMAP_UART_REGSHIFT)); } -static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +/* + * Called on runtime PM resume path from omap8250_restore_regs(), and + * omap8250_set_mctrl(). + */ +static void __omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct uart_8250_port *up = up_to_u8250p(port); - struct omap8250_priv *priv = up->port.private_data; + struct omap8250_priv *priv = port->private_data; u8 lcr; serial8250_do_set_mctrl(port, mctrl); @@ -171,6 +202,20 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) } } +static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + int err; + + err = pm_runtime_resume_and_get(port->dev); + if (err) + return; + + __omap8250_set_mctrl(port, mctrl); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +} + /* * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460) * The access to uart register after MDR1 Access @@ -183,32 +228,10 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) static void omap_8250_mdr1_errataset(struct uart_8250_port *up, struct omap8250_priv *priv) { - u8 timeout = 255; - u8 old_mdr1; - - old_mdr1 = serial_in(up, UART_OMAP_MDR1); - if (old_mdr1 == priv->mdr1) - return; - serial_out(up, UART_OMAP_MDR1, priv->mdr1); udelay(2); serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); - /* - * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and - * TX_FIFO_E bit is 1. - */ - while (UART_LSR_THRE != (serial_in(up, UART_LSR) & - (UART_LSR_THRE | UART_LSR_DR))) { - timeout--; - if (!timeout) { - /* Should *never* happen. we warn and carry on */ - dev_crit(up->port.dev, "Errata i202: timedout %x\n", - serial_in(up, UART_LSR)); - break; - } - udelay(1); - } } static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud, @@ -285,8 +308,13 @@ static void omap8250_update_mdr1(struct uart_8250_port *up, static void omap8250_restore_regs(struct uart_8250_port *up) { - struct omap8250_priv *priv = up->port.private_data; + struct uart_port *port = &up->port; + struct omap8250_priv *priv = port->private_data; struct uart_8250_dma *dma = up->dma; + u8 mcr = serial8250_in_MCR(up); + + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); if (dma && dma->tx_running) { /* @@ -303,7 +331,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_EFR, UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial8250_out_MCR(up, UART_MCR_TCRTLR); + serial8250_out_MCR(up, mcr | UART_MCR_TCRTLR); serial_out(up, UART_FCR, up->fcr); omap8250_update_scr(up, priv); @@ -319,7 +347,8 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_LCR, 0); /* drop TCR + TLR access, we setup XON/XOFF later */ - serial8250_out_MCR(up, up->mcr); + serial8250_out_MCR(up, mcr); + serial_out(up, UART_IER, up->ier); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); @@ -336,37 +365,23 @@ static void omap8250_restore_regs(struct uart_8250_port *up) omap8250_update_mdr1(up, priv); - up->port.ops->set_mctrl(&up->port, up->port.mctrl); + __omap8250_set_mctrl(port, port->mctrl); + + serial_out(up, UART_OMAP_MDR3, priv->mdr3); + + if (port->rs485.flags & SER_RS485_ENABLED && + port->rs485_config == serial8250_em485_config) + serial8250_em485_stop_tx(up, true); } -/* - * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have - * some differences in how we want to handle flow control. - */ -static void omap_8250_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) +static void omap_8250_set_termios_atomic(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old, unsigned int baud) { struct uart_8250_port *up = up_to_u8250p(port); - struct omap8250_priv *priv = up->port.private_data; - unsigned char cval = 0; - unsigned int baud; + struct omap8250_priv *priv = port->private_data; + u8 cval; - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } + cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; @@ -377,59 +392,59 @@ static void omap_8250_set_termios(struct uart_port *port, if (termios->c_cflag & CMSPAR) cval |= UART_LCR_SPAR; - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / UART_DIV_MAX, - port->uartclk / 13); omap_8250_get_divisor(port, baud, priv); /* * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - pm_runtime_get_sync(port->dev); - spin_lock_irq(&port->lock); + guard(serial8250_rpm)(up); + guard(uart_port_lock_irq)(port); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + /* + * Specify which conditions may be considered for error + * handling and the ignoring of characters. The actual + * ignoring of characters only occurs if the bit is set + * in @ignore_status_mask as well. + */ + port->read_status_mask = UART_LSR_OE | UART_LSR_DR; if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (termios->c_iflag & (IGNBRK | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; + port->read_status_mask |= UART_LSR_BI; /* * Characters to ignore */ - up->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; + port->ignore_status_mask |= UART_LSR_BI; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; + port->ignore_status_mask |= UART_LSR_OE; } /* * ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; + port->ignore_status_mask |= UART_LSR_DR; /* * Modem status interrupts */ up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + if (UART_ENABLE_MS(port, termios->c_cflag)) up->ier |= UART_IER_MSI; up->lcr = cval; @@ -467,15 +482,15 @@ static void omap_8250_set_termios(struct uart_port *port, priv->xoff = termios->c_cc[VSTOP]; priv->efr = 0; - up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); + port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); - if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW && + if (termios->c_cflag & CRTSCTS && port->flags & UPF_HARD_FLOW && !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) && !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_CTS)) { /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */ - up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; + port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; priv->efr |= UART_EFR_CTS; - } else if (up->port.flags & UPF_SOFT_FLOW) { + } else if (port->flags & UPF_SOFT_FLOW) { /* * OMAP rx s/w flow control is borked; the transmitter remains * stuck off even if rx flow control is subsequently disabled @@ -487,15 +502,32 @@ static void omap_8250_set_termios(struct uart_port *port, * Transmit XON1, XOFF1 */ if (termios->c_iflag & IXOFF) { - up->port.status |= UPSTAT_AUTOXOFF; + port->status |= UPSTAT_AUTOXOFF; priv->efr |= OMAP_UART_SW_TX; } } omap8250_restore_regs(up); +} - spin_unlock_irq(&up->port.lock); - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); +/* + * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have + * some differences in how we want to handle flow control. + */ +static void omap_8250_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ + struct omap8250_priv *priv = port->private_data; + unsigned int baud; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / UART_DIV_MAX, + port->uartclk / 13); + + omap_8250_set_termios_atomic(port, termios, old, baud); /* calculate wakeup latency constraint */ priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud; @@ -515,7 +547,10 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, struct uart_8250_port *up = up_to_u8250p(port); u8 efr; - pm_runtime_get_sync(port->dev); + guard(serial8250_rpm)(up); + /* Synchronize UART_IER access against the console. */ + guard(uart_port_lock_irq)(port); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, efr | UART_EFR_ECB); @@ -525,18 +560,20 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } static void omap_serial_fill_features_erratas(struct uart_8250_port *up, struct omap8250_priv *priv) { + static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM65X", }, + { .family = "J721E", .revision = "SR1.0" }, + { /* sentinel */ } + }; u32 mvr, scheme; u16 revision, major, minor; - mvr = uart_read(up, UART_OMAP_MVER); + mvr = uart_read(priv, UART_OMAP_MVER); /* Check revision register scheme */ scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; @@ -580,6 +617,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up, default: break; } + + /* + * AM65x SR1.0, AM65x SR2.0 and J721e SR1.0 don't + * don't have RHR_IT_DIS bit in IER2 register. So drop to flag + * to enable errata workaround. + */ + if (soc_device_match(k3_soc_devices)) + priv->habit &= ~UART_HAS_RHR_IT_DIS; } static void omap8250_uart_qos_work(struct work_struct *work) @@ -596,22 +641,79 @@ static int omap_8250_dma_handle_irq(struct uart_port *port); static irqreturn_t omap8250_irq(int irq, void *dev_id) { - struct uart_port *port = dev_id; - struct uart_8250_port *up = up_to_u8250p(port); - unsigned int iir; + struct omap8250_priv *priv = dev_id; + struct uart_8250_port *up = serial8250_get_port(priv->line); + struct uart_port *port = &up->port; + unsigned int iir, lsr; int ret; + pm_runtime_get_noresume(port->dev); + + /* Shallow idle state wake-up to an IO interrupt? */ + if (atomic_add_unless(&priv->active, 1, 1)) { + priv->latency = priv->calc_latency; + schedule_work(&priv->qos_work); + } + #ifdef CONFIG_SERIAL_8250_DMA if (up->dma) { ret = omap_8250_dma_handle_irq(port); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put(port->dev); return IRQ_RETVAL(ret); } #endif - serial8250_rpm_get(up); + lsr = serial_port_in(port, UART_LSR); iir = serial_port_in(port, UART_IIR); ret = serial8250_handle_irq(port, iir); - serial8250_rpm_put(up); + + /* + * On K3 SoCs, it is observed that RX TIMEOUT is signalled after + * FIFO has been drained or erroneously. + * So apply solution of Errata i2310 as mentioned in + * https://www.ti.com/lit/pdf/sprz536 + */ + if (priv->habit & UART_RX_TIMEOUT_QUIRK && + (iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT && + serial_port_in(port, UART_OMAP_RX_LVL) == 0) { + unsigned char efr2, timeout_h, timeout_l; + + efr2 = serial_in(up, UART_OMAP_EFR2); + timeout_h = serial_in(up, UART_OMAP_TO_H); + timeout_l = serial_in(up, UART_OMAP_TO_L); + serial_out(up, UART_OMAP_TO_H, 0xFF); + serial_out(up, UART_OMAP_TO_L, 0xFF); + serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE); + serial_in(up, UART_IIR); + serial_out(up, UART_OMAP_EFR2, efr2); + serial_out(up, UART_OMAP_TO_H, timeout_h); + serial_out(up, UART_OMAP_TO_L, timeout_l); + } + + /* Stop processing interrupts on input overrun */ + if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) { + unsigned long delay; + + /* Synchronize UART_IER access against the console. */ + uart_port_lock(port); + up->ier = serial_port_in(port, UART_IER); + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); + } else { + /* Keep restarting the timer until + * the input overrun subsides. + */ + cancel_delayed_work(&up->overrun_backoff); + } + uart_port_unlock(port); + + delay = msecs_to_jiffies(up->overrun_backoff_time_ms); + schedule_delayed_work(&up->overrun_backoff, delay); + } + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put(port->dev); return IRQ_RETVAL(ret); } @@ -620,6 +722,7 @@ static int omap_8250_startup(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = port->private_data; + struct uart_8250_dma *dma = &priv->omap8250_dma; int ret; if (priv->wakeirq) { @@ -628,9 +731,12 @@ static int omap_8250_startup(struct uart_port *port) return ret; } - pm_runtime_get_sync(port->dev); +#ifdef CONFIG_PM + up->capabilities |= UART_CAP_RPM; +#endif + + guard(serial8250_rpm)(up); - up->mcr = 0; serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); serial_out(up, UART_LCR, UART_LCR_WLEN8); @@ -639,29 +745,23 @@ static int omap_8250_startup(struct uart_port *port) up->msr_saved_flags = 0; /* Disable DMA for console UART */ - if (uart_console(port)) - up->dma = NULL; - - if (up->dma) { + if (dma->fn && !uart_console(port)) { + up->dma = &priv->omap8250_dma; ret = serial8250_request_dma(up); if (ret) { dev_warn_ratelimited(port->dev, "failed to request DMA\n"); up->dma = NULL; } + } else { + up->dma = NULL; } - ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED, - dev_name(port->dev), port); - if (ret < 0) - goto err; - - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_out(up, UART_IER, up->ier); - -#ifdef CONFIG_PM - up->capabilities |= UART_CAP_RPM; -#endif + /* Synchronize UART_IER access against the console. */ + scoped_guard(uart_port_lock_irq, port) { + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + } /* Enable module level wake up */ priv->wer = OMAP_UART_WER_MOD_WKUP; @@ -669,17 +769,14 @@ static int omap_8250_startup(struct uart_port *port) priv->wer |= OMAP_UART_TX_WAKEUP_EN; serial_out(up, UART_OMAP_WER, priv->wer); - if (up->dma && !(priv->habit & UART_HAS_EFR2)) + if (up->dma && !(priv->habit & UART_HAS_EFR2)) { + guard(uart_port_lock_irq)(port); up->dma->rx_dma(up); + } + + enable_irq(port->irq); - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); return 0; -err: - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); - dev_pm_clear_wake_irq(port->dev); - return ret; } static void omap_8250_shutdown(struct uart_port *port) @@ -687,21 +784,27 @@ static void omap_8250_shutdown(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = port->private_data; + guard(serial8250_rpm)(up); + flush_work(&priv->qos_work); if (up->dma) omap_8250_rx_dma_flush(up); - pm_runtime_get_sync(port->dev); - serial_out(up, UART_OMAP_WER, 0); if (priv->habit & UART_HAS_EFR2) serial_out(up, UART_OMAP_EFR2, 0x0); - up->ier = 0; - serial_out(up, UART_IER, 0); + /* Synchronize UART_IER access against the console. */ + scoped_guard(uart_port_lock_irq, port) { + up->ier = 0; + serial_out(up, UART_IER, 0); + } - if (up->dma) - serial8250_release_dma(up); + disable_irq_nosync(port->irq); + dev_pm_clear_wake_irq(port->dev); + + serial8250_release_dma(up); + up->dma = NULL; /* * Disable break condition and FIFOs @@ -709,48 +812,101 @@ static void omap_8250_shutdown(struct uart_port *port) if (up->lcr & UART_LCR_SBC) serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC); serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); - free_irq(port->irq, port); - dev_pm_clear_wake_irq(port->dev); } static void omap_8250_throttle(struct uart_port *port) { struct omap8250_priv *priv = port->private_data; - unsigned long flags; - pm_runtime_get_sync(port->dev); + guard(serial8250_rpm)(up_to_u8250p(port)); + guard(uart_port_lock_irqsave)(port); - spin_lock_irqsave(&port->lock, flags); port->ops->stop_rx(port); priv->throttled = true; - spin_unlock_irqrestore(&port->lock, flags); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } static void omap_8250_unthrottle(struct uart_port *port) { struct omap8250_priv *priv = port->private_data; struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - pm_runtime_get_sync(port->dev); + guard(serial8250_rpm)(up); + /* Synchronize UART_IER access against the console. */ + guard(uart_port_lock_irqsave)(port); - spin_lock_irqsave(&port->lock, flags); priv->throttled = false; if (up->dma) up->dma->rx_dma(up); up->ier |= UART_IER_RLSI | UART_IER_RDI; - port->read_status_mask |= UART_LSR_DR; serial_out(up, UART_IER, up->ier); - spin_unlock_irqrestore(&port->lock, flags); +} - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); +static int omap8250_rs485_config(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct omap8250_priv *priv = port->private_data; + struct uart_8250_port *up = up_to_u8250p(port); + u32 fixed_delay_rts_before_send = 0; + u32 fixed_delay_rts_after_send = 0; + unsigned int baud; + + /* + * There is a fixed delay of 3 bit clock cycles after the TX shift + * register is going empty to allow time for the stop bit to transition + * through the transceiver before direction is changed to receive. + * + * Additionally there appears to be a 1 bit clock delay between writing + * to the THR register and transmission of the start bit, per page 8783 + * of the AM65 TRM: https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf + */ + if (priv->quot) { + if (priv->mdr1 == UART_OMAP_MDR1_16X_MODE) + baud = port->uartclk / (16 * priv->quot); + else + baud = port->uartclk / (13 * priv->quot); + + fixed_delay_rts_after_send = 3 * MSEC_PER_SEC / baud; + fixed_delay_rts_before_send = 1 * MSEC_PER_SEC / baud; + } + + /* + * Fall back to RS485 software emulation if the UART is missing + * hardware support, if the device tree specifies an mctrl_gpio + * (indicates that RTS is unavailable due to a pinmux conflict) + * or if the requested delays exceed the fixed hardware delays. + */ + if (!(priv->habit & UART_HAS_NATIVE_RS485) || + mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) || + rs485->delay_rts_after_send > fixed_delay_rts_after_send || + rs485->delay_rts_before_send > fixed_delay_rts_before_send) { + priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN; + serial_out(up, UART_OMAP_MDR3, priv->mdr3); + + port->rs485_config = serial8250_em485_config; + return serial8250_em485_config(port, termios, rs485); + } + + rs485->delay_rts_after_send = fixed_delay_rts_after_send; + rs485->delay_rts_before_send = fixed_delay_rts_before_send; + + if (rs485->flags & SER_RS485_ENABLED) + priv->mdr3 |= UART_OMAP_MDR3_DIR_EN; + else + priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN; + + /* + * Retain same polarity semantics as RS485 software emulation, + * i.e. SER_RS485_RTS_ON_SEND means driving RTS low on send. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + priv->mdr3 &= ~UART_OMAP_MDR3_DIR_POL; + else + priv->mdr3 |= UART_OMAP_MDR3_DIR_POL; + + serial_out(up, UART_OMAP_MDR3, priv->mdr3); + + return 0; } #ifdef CONFIG_SERIAL_8250_DMA @@ -761,17 +917,27 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; + struct omap8250_priv *priv = p->port.private_data; struct dma_chan *rxchan = dma->rxchan; dma_cookie_t cookie; struct dma_tx_state state; int count; int ret; + u32 reg; if (!dma->rx_running) goto out; cookie = dma->rx_cookie; dma->rx_running = 0; + + /* Re-enable RX FIFO interrupt now that transfer is complete */ + if (priv->habit & UART_HAS_RHR_IT_DIS) { + reg = serial_in(p, UART_OMAP_IER2); + reg &= ~UART_OMAP_IER2_RHR_IT_DIS; + serial_out(p, UART_OMAP_IER2, reg); + } + dmaengine_tx_status(rxchan, cookie, &state); count = dma->rx_size - state.residue + state.in_flight_bytes; @@ -789,7 +955,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) poll_count--) cpu_relax(); - if (!poll_count) + if (poll_count == -1) dev_err(p->port.dev, "teardown incomplete\n"); } } @@ -810,29 +976,26 @@ static void __dma_rx_complete(void *param) struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct dma_tx_state state; - unsigned long flags; - spin_lock_irqsave(&p->port.lock, flags); + /* Synchronize UART_IER access against the console. */ + guard(uart_port_lock_irqsave)(&p->port); /* * If the tx status is not DMA_COMPLETE, then this is a delayed * completion callback. A previous RX timeout flush would have * already pushed the data, so exit. */ - if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != - DMA_COMPLETE) { - spin_unlock_irqrestore(&p->port.lock, flags); + if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != DMA_COMPLETE) return; - } + __dma_rx_do_complete(p); - if (!priv->throttled) { - p->ier |= UART_IER_RLSI | UART_IER_RDI; - serial_out(p, UART_IER, p->ier); - if (!(priv->habit & UART_HAS_EFR2)) - omap_8250_rx_dma(p); - } + if (priv->throttled) + return; - spin_unlock_irqrestore(&p->port.lock, flags); + p->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(p, UART_IER, p->ier); + if (!(priv->habit & UART_HAS_EFR2)) + omap_8250_rx_dma(p); } static void omap_8250_rx_dma_flush(struct uart_8250_port *p) @@ -867,6 +1030,10 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) int err = 0; struct dma_async_tx_descriptor *desc; unsigned long flags; + u32 reg; + + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); if (priv->rx_dma_broken) return -EINVAL; @@ -902,6 +1069,17 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) dma->rx_cookie = dmaengine_submit(desc); + /* + * Disable RX FIFO interrupt while RX DMA is enabled, else + * spurious interrupt may be raised when data is in the RX FIFO + * but is yet to be drained by DMA. + */ + if (priv->habit & UART_HAS_RHR_IT_DIS) { + reg = serial_in(p, UART_OMAP_IER2); + reg |= UART_OMAP_IER2_RHR_IT_DIS; + serial_out(p, UART_OMAP_IER2, reg); + } + dma_async_issue_pending(dma->rxchan); out: spin_unlock_irqrestore(&priv->rx_dma_lock, flags); @@ -914,31 +1092,28 @@ static void omap_8250_dma_tx_complete(void *param) { struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; - struct circ_buf *xmit = &p->port.state->xmit; - unsigned long flags; + struct tty_port *tport = &p->port.state->port; bool en_thri = false; struct omap8250_priv *priv = p->port.private_data; dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); - spin_lock_irqsave(&p->port.lock, flags); + guard(uart_port_lock_irqsave)(&p->port); dma->tx_running = 0; - xmit->tail += dma->tx_size; - xmit->tail &= UART_XMIT_SIZE - 1; - p->port.icount.tx += dma->tx_size; + uart_xmit_advance(&p->port, dma->tx_size); if (priv->delayed_restore) { priv->delayed_restore = 0; omap8250_restore_regs(p); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&p->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&p->port)) { int ret; ret = omap_8250_tx_dma(p); @@ -952,22 +1127,21 @@ static void omap_8250_dma_tx_complete(void *param) dma->tx_err = 1; serial8250_set_THRI(p); } - - spin_unlock_irqrestore(&p->port.lock, flags); } static int omap_8250_tx_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; struct omap8250_priv *priv = p->port.private_data; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; struct dma_async_tx_descriptor *desc; - unsigned int skip_byte = 0; + struct scatterlist sg; + int skip_byte = -1; int ret; if (dma->tx_running) return 0; - if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { + if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) { /* * Even if no data, we need to return an error for the two cases @@ -982,8 +1156,8 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) return 0; } - dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (priv->habit & OMAP_DMA_TX_KICK) { + unsigned char c; u8 tx_lvl; /* @@ -1006,22 +1180,32 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) ret = -EBUSY; goto err; } - if (dma->tx_size < 4) { + if (kfifo_len(&tport->xmit_fifo) < 4) { + ret = -EINVAL; + goto err; + } + if (!uart_fifo_out(&p->port, &c, 1)) { ret = -EINVAL; goto err; } - skip_byte = 1; + skip_byte = c; } - desc = dmaengine_prep_slave_single(dma->txchan, - dma->tx_addr + xmit->tail + skip_byte, - dma->tx_size - skip_byte, DMA_MEM_TO_DEV, + sg_init_table(&sg, 1); + ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr); + if (ret != 1) { + ret = -EINVAL; + goto err; + } + + desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { ret = -EBUSY; goto err; } + dma->tx_size = sg_dma_len(&sg); dma->tx_running = 1; desc->callback = omap_8250_dma_tx_complete; @@ -1037,11 +1221,13 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) dma->tx_err = 0; serial8250_clear_THRI(p); - if (skip_byte) - serial_out(p, UART_TX, xmit->buf[xmit->tail]); - return 0; + ret = 0; + goto out_skip; err: dma->tx_err = 1; +out_skip: + if (skip_byte >= 0) + serial_out(p, UART_TX, skip_byte); return ret; } @@ -1057,8 +1243,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) return omap_8250_rx_dma(up); } -static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up, - u8 iir, unsigned char status) +static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status) { if ((status & (UART_LSR_DR | UART_LSR_BI)) && (iir & UART_IIR_RDI)) { @@ -1072,8 +1257,11 @@ static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up, } static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, - unsigned char status) + u16 status) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + /* * Queue a new transfer if FIFO has data. */ @@ -1099,43 +1287,41 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, /* * This is mostly serial8250_handle_irq(). We have a slightly different DMA - * hoook for RX/TX and need different logic for them in the ISR. Therefore we + * hook for RX/TX and need different logic for them in the ISR. Therefore we * use the default routine in the non-DMA case and this one for with DMA. */ static int omap_8250_dma_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - struct omap8250_priv *priv = up->port.private_data; - unsigned char status; - unsigned long flags; + struct omap8250_priv *priv = port->private_data; + u16 status; u8 iir; - serial8250_rpm_get(up); - iir = serial_port_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { - serial8250_rpm_put(up); return IRQ_HANDLED; } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock(port); status = serial_port_in(port, UART_LSR); - if (priv->habit & UART_HAS_EFR2) - am654_8250_handle_rx_dma(up, iir, status); - else - status = omap_8250_handle_rx_dma(up, iir, status); + if ((iir & 0x3f) != UART_IIR_THRI) { + if (priv->habit & UART_HAS_EFR2) + am654_8250_handle_rx_dma(up, iir, status); + else + status = omap_8250_handle_rx_dma(up, iir, status); + } serial8250_modem_status(up); if (status & UART_LSR_THRE && up->dma->tx_err) { - if (uart_tx_stopped(&up->port) || - uart_circ_empty(&up->port.state->xmit)) { + if (uart_tx_stopped(port) || + kfifo_is_empty(&port->state->port.xmit_fifo)) { up->dma->tx_err = 0; serial8250_tx_chars(up); } else { /* - * try again due to an earlier failer which + * try again due to an earlier failure which * might have been resolved by now. */ if (omap_8250_tx_dma(up)) @@ -1143,8 +1329,8 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) } } - uart_unlock_and_check_sysrq(port, flags); - serial8250_rpm_put(up); + uart_unlock_and_check_sysrq(port); + return 1; } @@ -1168,6 +1354,18 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static int omap8250_select_wakeup_pinctrl(struct device *dev, + struct omap8250_priv *priv) +{ + if (IS_ERR_OR_NULL(priv->pinctrl_wakeup)) + return 0; + + if (!device_may_wakeup(dev)) + return 0; + + return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup); +} + static struct omap8250_dma_params am654_dma = { .rx_size = SZ_2K, .rx_trigger = 1, @@ -1182,7 +1380,8 @@ static struct omap8250_dma_params am33xx_dma = { static struct omap8250_platdata am654_platdata = { .dma_params = &am654_dma, - .habit = UART_HAS_EFR2, + .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS | + UART_RX_TIMEOUT_QUIRK | UART_HAS_NATIVE_RS485, }; static struct omap8250_platdata am33xx_platdata = { @@ -1209,17 +1408,17 @@ MODULE_DEVICE_TABLE(of, omap8250_dt_ids); static int omap8250_probe(struct platform_device *pdev) { - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct device_node *np = pdev->dev.of_node; struct omap8250_priv *priv; const struct omap8250_platdata *pdata; struct uart_8250_port up; - int ret; + struct resource *regs; void __iomem *membase; + int ret; - if (!regs || !irq) { - dev_err(&pdev->dev, "missing registers or irq\n"); + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "missing registers\n"); return -EINVAL; } @@ -1236,7 +1435,6 @@ static int omap8250_probe(struct platform_device *pdev) up.port.dev = &pdev->dev; up.port.mapbase = regs->start; up.port.membase = membase; - up.port.irq = irq->start; /* * It claims to be 16C750 compatible however it is a little different. * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to @@ -1246,13 +1444,9 @@ static int omap8250_probe(struct platform_device *pdev) * or pm callback. */ up.port.type = PORT_8250; - up.port.iotype = UPIO_MEM; - up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | - UPF_HARD_FLOW; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | UPF_HARD_FLOW; up.port.private_data = priv; - up.port.regshift = 2; - up.port.fifosize = 64; up.tx_loadsz = 64; up.capabilities = UART_CAP_FIFO; #ifdef CONFIG_PM @@ -1271,19 +1465,21 @@ static int omap8250_probe(struct platform_device *pdev) up.port.shutdown = omap_8250_shutdown; up.port.throttle = omap_8250_throttle; up.port.unthrottle = omap_8250_unthrottle; - up.port.rs485_config = serial8250_em485_config; + up.port.rs485_config = omap8250_rs485_config; + /* same rs485_supported for software emulation and native RS485 */ + up.port.rs485_supported = serial8250_em485_supported; up.rs485_start_tx = serial8250_em485_start_tx; up.rs485_stop_tx = serial8250_em485_stop_tx; up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias\n"); + ret = uart_read_port_properties(&up.port); + if (ret) return ret; - } - up.port.line = ret; - if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) { + up.port.regshift = OMAP_UART_REGSHIFT; + up.port.fifosize = 64; + + if (!up.port.uartclk) { struct clk *clk; clk = devm_clk_get(&pdev->dev, NULL); @@ -1295,7 +1491,9 @@ static int omap8250_probe(struct platform_device *pdev) } } - priv->wakeirq = irq_of_parse_and_map(np, 1); + if (of_property_read_u32(np, "overrun-throttle-ms", + &up.overrun_backoff_time_ms) != 0) + up.overrun_backoff_time_ms = 0; pdata = of_device_get_match_data(&pdev->dev); if (pdata) @@ -1308,6 +1506,8 @@ static int omap8250_probe(struct platform_device *pdev) DEFAULT_CLK_SPEED); } + priv->membase = membase; + priv->line = -ENODEV; priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; priv->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; cpu_latency_qos_add_request(&priv->pm_qos_request, priv->latency); @@ -1315,7 +1515,12 @@ static int omap8250_probe(struct platform_device *pdev) spin_lock_init(&priv->rx_dma_lock); - device_init_wakeup(&pdev->dev, true); + platform_set_drvdata(pdev, priv); + + device_set_wakeup_capable(&pdev->dev, true); + if (of_property_read_bool(np, "wakeup-source")) + device_set_wakeup_enable(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); @@ -1329,8 +1534,6 @@ static int omap8250_probe(struct platform_device *pdev) if (!of_get_available_child_count(pdev->dev.of_node)) pm_runtime_set_autosuspend_delay(&pdev->dev, -1); - pm_runtime_irq_safe(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); omap_serial_fill_features_erratas(&up, priv); @@ -1349,58 +1552,81 @@ static int omap8250_probe(struct platform_device *pdev) ret = of_property_count_strings(np, "dma-names"); if (ret == 2) { struct omap8250_dma_params *dma_params = NULL; + struct uart_8250_dma *dma = &priv->omap8250_dma; - up.dma = &priv->omap8250_dma; - up.dma->fn = the_no_dma_filter_fn; - up.dma->tx_dma = omap_8250_tx_dma; - up.dma->rx_dma = omap_8250_rx_dma; + dma->fn = the_no_dma_filter_fn; + dma->tx_dma = omap_8250_tx_dma; + dma->rx_dma = omap_8250_rx_dma; if (pdata) dma_params = pdata->dma_params; if (dma_params) { - up.dma->rx_size = dma_params->rx_size; - up.dma->rxconf.src_maxburst = dma_params->rx_trigger; - up.dma->txconf.dst_maxburst = dma_params->tx_trigger; + dma->rx_size = dma_params->rx_size; + dma->rxconf.src_maxburst = dma_params->rx_trigger; + dma->txconf.dst_maxburst = dma_params->tx_trigger; priv->rx_trigger = dma_params->rx_trigger; priv->tx_trigger = dma_params->tx_trigger; } else { - up.dma->rx_size = RX_TRIGGER; - up.dma->rxconf.src_maxburst = RX_TRIGGER; - up.dma->txconf.dst_maxburst = TX_TRIGGER; + dma->rx_size = RX_TRIGGER; + dma->rxconf.src_maxburst = RX_TRIGGER; + dma->txconf.dst_maxburst = TX_TRIGGER; } } #endif + + irq_set_status_flags(up.port.irq, IRQ_NOAUTOEN); + ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0, + dev_name(&pdev->dev), priv); + if (ret < 0) + goto err; + + priv->wakeirq = irq_of_parse_and_map(np, 1); + ret = serial8250_register_8250_port(&up); if (ret < 0) { dev_err(&pdev->dev, "unable to register 8250 port\n"); goto err; } priv->line = ret; - platform_set_drvdata(pdev, priv); pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); + + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!IS_ERR_OR_NULL(priv->pinctrl)) + priv->pinctrl_wakeup = pinctrl_lookup_state(priv->pinctrl, "wakeup"); + return 0; err: pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); + flush_work(&priv->qos_work); pm_runtime_disable(&pdev->dev); + cpu_latency_qos_remove_request(&priv->pm_qos_request); return ret; } -static int omap8250_remove(struct platform_device *pdev) +static void omap8250_remove(struct platform_device *pdev) { struct omap8250_priv *priv = platform_get_drvdata(pdev); + struct uart_8250_port *up; + int err; + + err = pm_runtime_resume_and_get(&pdev->dev); + if (err) + dev_err(&pdev->dev, "Failed to resume hardware\n"); + up = serial8250_get_port(priv->line); + omap_8250_shutdown(&up->port); + serial8250_unregister_port(priv->line); + priv->line = -ENODEV; pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); + flush_work(&priv->qos_work); pm_runtime_disable(&pdev->dev); - serial8250_unregister_port(priv->line); cpu_latency_qos_remove_request(&priv->pm_qos_request); - device_init_wakeup(&pdev->dev, false); - return 0; + device_set_wakeup_capable(&pdev->dev, false); } -#ifdef CONFIG_PM_SLEEP static int omap8250_prepare(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); @@ -1424,33 +1650,57 @@ static int omap8250_suspend(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); + int err = 0; + + err = omap8250_select_wakeup_pinctrl(dev, priv); + if (err) { + dev_err(dev, "Failed to select wakeup pinctrl, aborting suspend %pe\n", + ERR_PTR(err)); + return err; + } serial8250_suspend_port(priv->line); - pm_runtime_get_sync(dev); + err = pm_runtime_resume_and_get(dev); + if (err) + return err; if (!device_may_wakeup(dev)) priv->wer = 0; serial_out(up, UART_OMAP_WER, priv->wer); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - + if (uart_console(&up->port) && console_suspend_enabled) + err = pm_runtime_force_suspend(dev); flush_work(&priv->qos_work); - return 0; + + return err; } static int omap8250_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + int err; + + err = pinctrl_select_default_state(dev); + if (err) { + dev_err(dev, "Failed to select default pinctrl state on resume: %pe\n", + ERR_PTR(err)); + return err; + } + + if (uart_console(&up->port) && console_suspend_enabled) { + err = pm_runtime_force_resume(dev); + if (err) + return err; + } serial8250_resume_port(priv->line); + /* Paired with pm_runtime_resume_and_get() in omap8250_suspend() */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; } -#else -#define omap8250_prepare NULL -#define omap8250_complete NULL -#endif -#ifdef CONFIG_PM static int omap8250_lost_context(struct uart_8250_port *up) { u32 val; @@ -1466,11 +1716,15 @@ static int omap8250_lost_context(struct uart_8250_port *up) return 0; } +static void uart_write(struct omap8250_priv *priv, u32 reg, u32 val) +{ + writel(val, priv->membase + (reg << OMAP_UART_REGSHIFT)); +} + /* TODO: in future, this should happen via API in drivers/reset/ */ static int omap8250_soft_reset(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); - struct uart_8250_port *up = serial8250_get_port(priv->line); int timeout = 100; int sysc; int syss; @@ -1484,20 +1738,20 @@ static int omap8250_soft_reset(struct device *dev) * needing omap8250_soft_reset() quirk. Do it in two writes as * recommended in the comment for omap8250_update_scr(). */ - serial_out(up, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1); - serial_out(up, UART_OMAP_SCR, + uart_write(priv, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1); + uart_write(priv, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL); - sysc = serial_in(up, UART_OMAP_SYSC); + sysc = uart_read(priv, UART_OMAP_SYSC); /* softreset the UART */ sysc |= OMAP_UART_SYSC_SOFTRESET; - serial_out(up, UART_OMAP_SYSC, sysc); + uart_write(priv, UART_OMAP_SYSC, sysc); /* By experiments, 1us enough for reset complete on AM335x */ do { udelay(1); - syss = serial_in(up, UART_OMAP_SYSS); + syss = uart_read(priv, UART_OMAP_SYSS); } while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE)); if (!timeout) { @@ -1511,23 +1765,10 @@ static int omap8250_soft_reset(struct device *dev) static int omap8250_runtime_suspend(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); - struct uart_8250_port *up; - - /* In case runtime-pm tries this before we are setup */ - if (!priv) - return 0; + struct uart_8250_port *up = NULL; - up = serial8250_get_port(priv->line); - /* - * When using 'no_console_suspend', the console UART must not be - * suspended. Since driver suspend is managed by runtime suspend, - * preventing runtime suspend (by returning error) will keep device - * active during suspend. - */ - if (priv->is_suspending && !console_suspend_enabled) { - if (uart_console(&up->port)) - return -EBUSY; - } + if (priv->line >= 0) + up = serial8250_get_port(priv->line); if (priv->habit & UART_ERRATA_CLOCK_DISABLE) { int ret; @@ -1536,17 +1777,20 @@ static int omap8250_runtime_suspend(struct device *dev) if (ret) return ret; - /* Restore to UART mode after reset (for wakeup) */ - omap8250_update_mdr1(up, priv); - /* Restore wakeup enable register */ - serial_out(up, UART_OMAP_WER, priv->wer); + if (up) { + /* Restore to UART mode after reset (for wakeup) */ + omap8250_update_mdr1(up, priv); + /* Restore wakeup enable register */ + serial_out(up, UART_OMAP_WER, priv->wer); + } } - if (up->dma && up->dma->rxchan) + if (up && up->dma && up->dma->rxchan) omap_8250_rx_dma_flush(up); priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; schedule_work(&priv->qos_work); + atomic_set(&priv->active, 0); return 0; } @@ -1554,25 +1798,31 @@ static int omap8250_runtime_suspend(struct device *dev) static int omap8250_runtime_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); - struct uart_8250_port *up; + struct uart_8250_port *up = NULL; - /* In case runtime-pm tries this before we are setup */ - if (!priv) + /* Did the hardware wake to a device IO interrupt before a wakeirq? */ + if (atomic_read(&priv->active)) return 0; - up = serial8250_get_port(priv->line); + if (priv->line >= 0) + up = serial8250_get_port(priv->line); - if (omap8250_lost_context(up)) + if (up && omap8250_lost_context(up)) { + guard(uart_port_lock_irq)(&up->port); omap8250_restore_regs(up); + } - if (up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) + if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) { + guard(uart_port_lock_irq)(&up->port); omap_8250_rx_dma(up); + } + atomic_set(&priv->active, 1); priv->latency = priv->calc_latency; schedule_work(&priv->qos_work); + return 0; } -#endif #ifdef CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP static int __init omap8250_console_fixup(void) @@ -1615,17 +1865,17 @@ console_initcall(omap8250_console_fixup); #endif static const struct dev_pm_ops omap8250_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume) - SET_RUNTIME_PM_OPS(omap8250_runtime_suspend, + SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume) + RUNTIME_PM_OPS(omap8250_runtime_suspend, omap8250_runtime_resume, NULL) - .prepare = omap8250_prepare, - .complete = omap8250_complete, + .prepare = pm_sleep_ptr(omap8250_prepare), + .complete = pm_sleep_ptr(omap8250_complete), }; static struct platform_driver omap8250_platform_driver = { .driver = { .name = "omap8250", - .pm = &omap8250_dev_pm_ops, + .pm = pm_ptr(&omap8250_dev_pm_ops), .of_match_table = omap8250_dt_ids, }, .probe = omap8250_probe, diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_parisc.c index 673cda3d011d..4ba05a98791c 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_parisc.c @@ -26,7 +26,7 @@ static int __init serial_init_chip(struct parisc_device *dev) unsigned long address; int err; -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) && defined(CONFIG_IOSAPIC) if (!dev->irq && (dev->id.sversion == 0xad)) dev->irq = iosapic_serial_irq(dev); #endif @@ -127,4 +127,5 @@ static int __init probe_serial_gsc(void) module_init(probe_serial_gsc); +MODULE_DESCRIPTION("Serial Device Initialisation for Lasi/Asp/Wax/Dino"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 1a74d511b02a..c5a932f48f74 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -11,6 +11,7 @@ #include <linux/pci.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/math.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/tty.h> @@ -18,11 +19,90 @@ #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> +#include <linux/bitfield.h> #include <asm/byteorder.h> #include <asm/io.h> #include "8250.h" +#include "8250_pcilib.h" + +#define PCI_VENDOR_ID_SBSMODULARIO 0x124B +#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B +#define PCI_DEVICE_ID_OCTPRO 0x0001 +#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108 +#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208 +#define PCI_SUBDEVICE_ID_POCTAL232 0x0308 +#define PCI_SUBDEVICE_ID_POCTAL422 0x0408 +#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500 +#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530 +#define PCI_VENDOR_ID_ADVANTECH 0x13fe +#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 +#define PCI_DEVICE_ID_ADVANTECH_PCI1600 0x1600 +#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1611 0x1611 +#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 +#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618 +#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618 +#define PCI_DEVICE_ID_TITAN_200I 0x8028 +#define PCI_DEVICE_ID_TITAN_400I 0x8048 +#define PCI_DEVICE_ID_TITAN_800I 0x8088 +#define PCI_DEVICE_ID_TITAN_800EH 0xA007 +#define PCI_DEVICE_ID_TITAN_800EHB 0xA008 +#define PCI_DEVICE_ID_TITAN_400EH 0xA009 +#define PCI_DEVICE_ID_TITAN_100E 0xA010 +#define PCI_DEVICE_ID_TITAN_200E 0xA012 +#define PCI_DEVICE_ID_TITAN_400E 0xA013 +#define PCI_DEVICE_ID_TITAN_800E 0xA014 +#define PCI_DEVICE_ID_TITAN_200EI 0xA016 +#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 +#define PCI_DEVICE_ID_TITAN_200V3 0xA306 +#define PCI_DEVICE_ID_TITAN_400V3 0xA310 +#define PCI_DEVICE_ID_TITAN_410V3 0xA312 +#define PCI_DEVICE_ID_TITAN_800V3 0xA314 +#define PCI_DEVICE_ID_TITAN_800V3B 0xA315 +#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 +#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 +#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 +#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d + +#define PCI_DEVICE_ID_WCHCN_CH352_2S 0x3253 +#define PCI_DEVICE_ID_WCHCN_CH355_4S 0x7173 + +#define PCI_VENDOR_ID_AGESTAR 0x5372 +#define PCI_DEVICE_ID_AGESTAR_9375 0x6872 +#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a +#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e + +#define PCI_DEVICE_ID_WCHIC_CH384_4S 0x3470 +#define PCI_DEVICE_ID_WCHIC_CH384_8S 0x3853 + +#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 +#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 +#define PCI_DEVICE_ID_MOXA_CP102N 0x1027 +#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 +#define PCI_DEVICE_ID_MOXA_CP104N 0x1046 +#define PCI_DEVICE_ID_MOXA_CP112N 0x1121 +#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 +#define PCI_DEVICE_ID_MOXA_CP114N 0x1145 +#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 +#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 +#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 +#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 +#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 +#define PCI_DEVICE_ID_MOXA_CP132N 0x1323 +#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 +#define PCI_DEVICE_ID_MOXA_CP134N 0x1343 +#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 +#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 + +#define PCI_DEVICE_ID_ADDIDATA_CPCI7500 0x7003 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG 0x7024 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG 0x7025 +#define PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG 0x7026 + +/* Unknown vendors/cards - this should not be in linux/pci_ids.h */ +#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 +#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 /* * init function returns: @@ -56,6 +136,8 @@ struct serial_private { int line[]; }; +#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e + static const struct pci_device_id pci_use_msi[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, 0xA000, 0x1000) }, @@ -63,6 +145,10 @@ static const struct pci_device_id pci_use_msi[] = { 0xA000, 0x1000) }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, 0xA000, 0x1000) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100, + 0xA000, 0x1000) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL, + PCI_ANY_ID, PCI_ANY_ID) }, { } }; @@ -71,42 +157,28 @@ static int pci_default_setup(struct serial_private*, static void moan_device(const char *str, struct pci_dev *dev) { - dev_err(&dev->dev, - "%s: %s\n" + pci_err(dev, "%s\n" "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" "manufacturer and name of serial board or\n" "modem board to <linux-serial@vger.kernel.org>.\n", - pci_name(dev), str, dev->vendor, dev->device, + str, dev->vendor, dev->device, dev->subsystem_vendor, dev->subsystem_device); } static int setup_port(struct serial_private *priv, struct uart_8250_port *port, - int bar, int offset, int regshift) + u8 bar, unsigned int offset, int regshift) { - struct pci_dev *dev = priv->dev; - - if (bar >= PCI_STD_NUM_BARS) - return -EINVAL; + void __iomem *iomem = NULL; - if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { - if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev)) + if (pci_resource_flags(priv->dev, bar) & IORESOURCE_MEM) { + iomem = pcim_iomap(priv->dev, bar, 0); + if (!iomem) return -ENOMEM; - - port->port.iotype = UPIO_MEM; - port->port.iobase = 0; - port->port.mapbase = pci_resource_start(dev, bar) + offset; - port->port.membase = pcim_iomap_table(dev)[bar] + offset; - port->port.regshift = regshift; - } else { - port->port.iotype = UPIO_PORT; - port->port.iobase = pci_resource_start(dev, bar) + offset; - port->port.mapbase = 0; - port->port.membase = NULL; - port->port.regshift = 0; } - return 0; + + return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift, iomem); } /* @@ -234,7 +306,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev) /* is firmware started? */ pci_read_config_dword(dev, 0x44, &oldval); if (oldval == 0x00001000L) { /* RESET value */ - dev_dbg(&dev->dev, "Local i960 firmware missing\n"); + pci_dbg(dev, "Local i960 firmware missing\n"); return -ENODEV; } return 0; @@ -511,7 +583,7 @@ static int pci_siig_init(struct pci_dev *dev) if (type == 0x1000) return pci_siig10x_init(dev); - else if (type == 0x2000) + if (type == 0x2000) return pci_siig20x_init(dev); moan_device("Unknown SIIG card", dev); @@ -584,9 +656,8 @@ static int pci_timedia_probe(struct pci_dev *dev) * (0,2,3,5,6: serial only -- 7,8,9: serial + parallel) */ if ((dev->subsystem_device & 0x00f0) >= 0x70) { - dev_info(&dev->dev, - "ignoring Timedia subdevice %04x for parport_serial\n", - dev->subsystem_device); + pci_info(dev, "ignoring Timedia subdevice %04x for parport_serial\n", + dev->subsystem_device); return -ENODEV; } @@ -631,7 +702,7 @@ pci_timedia_setup(struct serial_private *priv, break; case 3: offset = board->uart_offset; - /* FALLTHROUGH */ + fallthrough; case 4: /* BAR 2 */ case 5: /* BAR 3 */ case 6: /* BAR 4 */ @@ -788,9 +859,9 @@ static int pci_netmos_9900_setup(struct serial_private *priv, bar = 3 * idx; return setup_port(priv, port, bar, 0, board->reg_shift); - } else { - return pci_default_setup(priv, board, port, idx); } + + return pci_default_setup(priv, board, port, idx); } /* the 99xx series comes with a range of device IDs and a variety @@ -823,8 +894,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) if (sub_serports > 0) return sub_serports; - dev_err(&dev->dev, - "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + pci_err(dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); return 0; } @@ -893,18 +963,19 @@ static int pci_netmos_init(struct pci_dev *dev) /* enable IO_Space bit */ #define ITE_887x_POSIO_ENABLE (1 << 31) +/* inta_addr are the configuration addresses of the ITE */ +static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, 0x200, 0x280 }; static int pci_ite887x_init(struct pci_dev *dev) { - /* inta_addr are the configuration addresses of the ITE */ - static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, - 0x200, 0x280, 0 }; int ret, i, type; struct resource *iobase = NULL; u32 miscr, uartbar, ioport; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + /* search for the base-ioport */ - i = 0; - while (inta_addr[i] && iobase == NULL) { + for (i = 0; i < ARRAY_SIZE(inta_addr); i++) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, "ite887x"); if (iobase != NULL) { @@ -921,13 +992,11 @@ static int pci_ite887x_init(struct pci_dev *dev) break; } release_region(iobase->start, ITE_887x_IOSIZE); - iobase = NULL; } - i++; } - if (!inta_addr[i]) { - dev_err(&dev->dev, "ite887x: could not find iobase\n"); + if (i == ARRAY_SIZE(inta_addr)) { + pci_err(dev, "could not find iobase\n"); return -ENODEV; } @@ -997,43 +1066,29 @@ static void pci_ite887x_exit(struct pci_dev *dev) } /* - * EndRun Technologies. - * Determine the number of ports available on the device. + * Oxford Semiconductor Inc. + * Check if an OxSemi device is part of the Tornado range of devices. */ #define PCI_VENDOR_ID_ENDRUN 0x7401 #define PCI_DEVICE_ID_ENDRUN_1588 0xe100 -static int pci_endrun_init(struct pci_dev *dev) +static bool pci_oxsemi_tornado_p(struct pci_dev *dev) { - u8 __iomem *p; - unsigned long deviceID; - unsigned int number_uarts = 0; + /* OxSemi Tornado devices are all 0xCxxx */ + if (dev->vendor == PCI_VENDOR_ID_OXSEMI && + (dev->device & 0xf000) != 0xc000) + return false; - /* EndRun device is all 0xexxx */ + /* EndRun devices are all 0xExxx */ if (dev->vendor == PCI_VENDOR_ID_ENDRUN && - (dev->device & 0xf000) != 0xe000) - return 0; + (dev->device & 0xf000) != 0xe000) + return false; - p = pci_iomap(dev, 0, 5); - if (p == NULL) - return -ENOMEM; - - deviceID = ioread32(p); - /* EndRun device */ - if (deviceID == 0x07000200) { - number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on EndRun PCI Express device\n", - number_uarts); - } - pci_iounmap(dev, p); - return number_uarts; + return true; } /* - * Oxford Semiconductor Inc. - * Check that device is part of the Tornado range of devices, then determine - * the number of ports available on the device. + * Determine the number of ports available on a Tornado device. */ static int pci_oxsemi_tornado_init(struct pci_dev *dev) { @@ -1041,9 +1096,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) unsigned long deviceID; unsigned int number_uarts = 0; - /* OxSemi Tornado devices are all 0xCxxx */ - if (dev->vendor == PCI_VENDOR_ID_OXSEMI && - (dev->device & 0xF000) != 0xC000) + if (!pci_oxsemi_tornado_p(dev)) return 0; p = pci_iomap(dev, 0, 5); @@ -1054,28 +1107,221 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) /* Tornado device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on Oxford PCI Express device\n", - number_uarts); + pci_dbg(dev, "%d ports detected on %s PCI Express device\n", + number_uarts, + dev->vendor == PCI_VENDOR_ID_ENDRUN ? + "EndRun" : "Oxford"); } pci_iounmap(dev, p); return number_uarts; } -static int pci_asix_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) +/* Tornado-specific constants for the TCR and CPR registers; see below. */ +#define OXSEMI_TORNADO_TCR_MASK 0xf +#define OXSEMI_TORNADO_CPR_MASK 0x1ff +#define OXSEMI_TORNADO_CPR_MIN 0x008 +#define OXSEMI_TORNADO_CPR_DEF 0x10f + +/* + * Determine the oversampling rate, the clock prescaler, and the clock + * divisor for the requested baud rate. The clock rate is 62.5 MHz, + * which is four times the baud base, and the prescaler increments in + * steps of 1/8. Therefore to make calculations on integers we need + * to use a scaled clock rate, which is the baud base multiplied by 32 + * (or our assumed UART clock rate multiplied by 2). + * + * The allowed oversampling rates are from 4 up to 16 inclusive (values + * from 0 to 3 inclusive map to 16). Likewise the clock prescaler allows + * values between 1.000 and 63.875 inclusive (operation for values from + * 0.000 to 0.875 has not been specified). The clock divisor is the usual + * unsigned 16-bit integer. + * + * For the most accurate baud rate we use a table of predetermined + * oversampling rates and clock prescalers that records all possible + * products of the two parameters in the range from 4 up to 255 inclusive, + * and additionally 335 for the 1500000bps rate, with the prescaler scaled + * by 8. The table is sorted by the decreasing value of the oversampling + * rate and ties are resolved by sorting by the decreasing value of the + * product. This way preference is given to higher oversampling rates. + * + * We iterate over the table and choose the product of an oversampling + * rate and a clock prescaler that gives the lowest integer division + * result deviation, or if an exact integer divider is found we stop + * looking for it right away. We do some fixup if the resulting clock + * divisor required would be out of its unsigned 16-bit integer range. + * + * Finally we abuse the supposed fractional part returned to encode the + * 4-bit value of the oversampling rate and the 9-bit value of the clock + * prescaler which will end up in the TCR and CPR/CPR2 registers. + */ +static unsigned int pci_oxsemi_tornado_get_divisor(struct uart_port *port, + unsigned int baud, + unsigned int *frac) { - port->bugs |= UART_BUG_PARITY; - return pci_default_setup(priv, board, port, idx); + static u8 p[][2] = { + { 16, 14, }, { 16, 13, }, { 16, 12, }, { 16, 11, }, + { 16, 10, }, { 16, 9, }, { 16, 8, }, { 15, 17, }, + { 15, 16, }, { 15, 15, }, { 15, 14, }, { 15, 13, }, + { 15, 12, }, { 15, 11, }, { 15, 10, }, { 15, 9, }, + { 15, 8, }, { 14, 18, }, { 14, 17, }, { 14, 14, }, + { 14, 13, }, { 14, 12, }, { 14, 11, }, { 14, 10, }, + { 14, 9, }, { 14, 8, }, { 13, 19, }, { 13, 18, }, + { 13, 17, }, { 13, 13, }, { 13, 12, }, { 13, 11, }, + { 13, 10, }, { 13, 9, }, { 13, 8, }, { 12, 19, }, + { 12, 18, }, { 12, 17, }, { 12, 11, }, { 12, 9, }, + { 12, 8, }, { 11, 23, }, { 11, 22, }, { 11, 21, }, + { 11, 20, }, { 11, 19, }, { 11, 18, }, { 11, 17, }, + { 11, 11, }, { 11, 10, }, { 11, 9, }, { 11, 8, }, + { 10, 25, }, { 10, 23, }, { 10, 20, }, { 10, 19, }, + { 10, 17, }, { 10, 10, }, { 10, 9, }, { 10, 8, }, + { 9, 27, }, { 9, 23, }, { 9, 21, }, { 9, 19, }, + { 9, 18, }, { 9, 17, }, { 9, 9, }, { 9, 8, }, + { 8, 31, }, { 8, 29, }, { 8, 23, }, { 8, 19, }, + { 8, 17, }, { 8, 8, }, { 7, 35, }, { 7, 31, }, + { 7, 29, }, { 7, 25, }, { 7, 23, }, { 7, 21, }, + { 7, 19, }, { 7, 17, }, { 7, 15, }, { 7, 14, }, + { 7, 13, }, { 7, 12, }, { 7, 11, }, { 7, 10, }, + { 7, 9, }, { 7, 8, }, { 6, 41, }, { 6, 37, }, + { 6, 31, }, { 6, 29, }, { 6, 23, }, { 6, 19, }, + { 6, 17, }, { 6, 13, }, { 6, 11, }, { 6, 10, }, + { 6, 9, }, { 6, 8, }, { 5, 67, }, { 5, 47, }, + { 5, 43, }, { 5, 41, }, { 5, 37, }, { 5, 31, }, + { 5, 29, }, { 5, 25, }, { 5, 23, }, { 5, 19, }, + { 5, 17, }, { 5, 15, }, { 5, 13, }, { 5, 11, }, + { 5, 10, }, { 5, 9, }, { 5, 8, }, { 4, 61, }, + { 4, 59, }, { 4, 53, }, { 4, 47, }, { 4, 43, }, + { 4, 41, }, { 4, 37, }, { 4, 31, }, { 4, 29, }, + { 4, 23, }, { 4, 19, }, { 4, 17, }, { 4, 13, }, + { 4, 9, }, { 4, 8, }, + }; + /* Scale the quotient for comparison to get the fractional part. */ + const unsigned int quot_scale = 65536; + unsigned int sclk = port->uartclk * 2; + unsigned int sdiv = DIV_ROUND_CLOSEST(sclk, baud); + unsigned int best_squot; + unsigned int squot; + unsigned int quot; + u16 cpr; + u8 tcr; + int i; + + /* Old custom speed handling. */ + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { + unsigned int cust_div = port->custom_divisor; + + quot = cust_div & UART_DIV_MAX; + tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK; + cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK; + if (cpr < OXSEMI_TORNADO_CPR_MIN) + cpr = OXSEMI_TORNADO_CPR_DEF; + } else { + best_squot = quot_scale; + for (i = 0; i < ARRAY_SIZE(p); i++) { + unsigned int spre; + unsigned int srem; + u8 cp; + u8 tc; + + tc = p[i][0]; + cp = p[i][1]; + spre = tc * cp; + + srem = sdiv % spre; + if (srem > spre / 2) + srem = spre - srem; + squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre); + + if (srem == 0) { + tcr = tc; + cpr = cp; + quot = sdiv / spre; + break; + } else if (squot < best_squot) { + best_squot = squot; + tcr = tc; + cpr = cp; + quot = DIV_ROUND_CLOSEST(sdiv, spre); + } + } + while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 && + quot % 2 == 0) { + quot >>= 1; + tcr <<= 1; + } + while (quot > UART_DIV_MAX) { + if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) { + quot >>= 1; + tcr <<= 1; + } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) { + quot >>= 1; + cpr <<= 1; + } else { + quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK; + cpr = OXSEMI_TORNADO_CPR_MASK; + } + } + } + + *frac = (cpr << 8) | (tcr & OXSEMI_TORNADO_TCR_MASK); + return quot; } -/* Quatech devices have their own extra interface features */ +/* + * Set the oversampling rate in the transmitter clock cycle register (TCR), + * the clock prescaler in the clock prescaler register (CPR and CPR2), and + * the clock divisor in the divisor latch (DLL and DLM). Note that for + * backwards compatibility any write to CPR clears CPR2 and therefore CPR + * has to be written first, followed by CPR2, which occupies the location + * of CKS used with earlier UART designs. + */ +static void pci_oxsemi_tornado_set_divisor(struct uart_port *port, + unsigned int baud, + unsigned int quot, + unsigned int quot_frac) +{ + struct uart_8250_port *up = up_to_u8250p(port); + u8 cpr2 = quot_frac >> 16; + u8 cpr = quot_frac >> 8; + u8 tcr = quot_frac; + + serial_icr_write(up, UART_TCR, tcr); + serial_icr_write(up, UART_CPR, cpr); + serial_icr_write(up, UART_CKS, cpr2); + serial8250_do_set_divisor(port, baud, quot); +} -struct quatech_feature { - u16 devid; - bool amcc; -}; +/* + * For Tornado devices we force MCR[7] set for the Divide-by-M N/8 baud rate + * generator prescaler (CPR and CPR2). Otherwise no prescaler would be used. + */ +static void pci_oxsemi_tornado_set_mctrl(struct uart_port *port, + unsigned int mctrl) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->mcr |= UART_MCR_CLKSEL; + serial8250_do_set_mctrl(port, mctrl); +} + +/* + * We require EFR features for clock programming, so set UPF_FULL_PROBE + * for full probing regardless of CONFIG_SERIAL_8250_16550A_VARIANTS setting. + */ +static int pci_oxsemi_tornado_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *up, int idx) +{ + struct pci_dev *dev = priv->dev; + + if (pci_oxsemi_tornado_p(dev)) { + up->port.flags |= UPF_FULL_PROBE; + up->port.get_divisor = pci_oxsemi_tornado_get_divisor; + up->port.set_divisor = pci_oxsemi_tornado_set_divisor; + up->port.set_mctrl = pci_oxsemi_tornado_set_mctrl; + } + + return pci_default_setup(priv, board, up, idx); +} #define QPCR_TEST_FOR1 0x3F #define QPCR_TEST_GET1 0x00 @@ -1092,42 +1338,30 @@ struct quatech_feature { #define QOPR_CLOCK_X8 0x0003 #define QOPR_CLOCK_RATE_MASK 0x0003 - -static struct quatech_feature quatech_cards[] = { - { PCI_DEVICE_ID_QUATECH_QSC100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC100E, 0 }, - { PCI_DEVICE_ID_QUATECH_DSC200, 1 }, - { PCI_DEVICE_ID_QUATECH_DSC200E, 0 }, - { PCI_DEVICE_ID_QUATECH_ESC100D, 1 }, - { PCI_DEVICE_ID_QUATECH_ESC100M, 1 }, - { PCI_DEVICE_ID_QUATECH_QSCP100, 1 }, - { PCI_DEVICE_ID_QUATECH_DSCP100, 1 }, - { PCI_DEVICE_ID_QUATECH_QSCP200, 1 }, - { PCI_DEVICE_ID_QUATECH_DSCP200, 1 }, - { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 }, - { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 }, - { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 }, +/* Quatech devices have their own extra interface features */ +static struct pci_device_id quatech_cards[] = { + { PCI_DEVICE_DATA(QUATECH, QSC100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC100E, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSC200, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSC200E, 0) }, + { PCI_DEVICE_DATA(QUATECH, ESC100D, 1) }, + { PCI_DEVICE_DATA(QUATECH, ESC100M, 1) }, + { PCI_DEVICE_DATA(QUATECH, QSCP100, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSCP100, 1) }, + { PCI_DEVICE_DATA(QUATECH, QSCP200, 1) }, + { PCI_DEVICE_DATA(QUATECH, DSCP200, 1) }, + { PCI_DEVICE_DATA(QUATECH, ESCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, QSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, SSCLP100, 0) }, + { PCI_DEVICE_DATA(QUATECH, QSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, DSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, SSCLP200, 0) }, + { PCI_DEVICE_DATA(QUATECH, SPPXP_100, 0) }, { 0, } }; -static int pci_quatech_amcc(u16 devid) -{ - struct quatech_feature *qf = &quatech_cards[0]; - while (qf->devid) { - if (qf->devid == devid) - return qf->amcc; - qf++; - } - pr_err("quatech: unknown port type '0x%04X'.\n", devid); - return 0; -}; - static int pci_quatech_rqopr(struct uart_8250_port *port) { unsigned long base = port->port.iobase; @@ -1287,7 +1521,19 @@ static int pci_quatech_rs422(struct uart_8250_port *port) static int pci_quatech_init(struct pci_dev *dev) { - if (pci_quatech_amcc(dev->device)) { + const struct pci_device_id *match; + bool amcc = false; + + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + + match = pci_match_id(quatech_cards, dev); + if (match) + amcc = match->driver_data; + else + pci_err(dev, "unknown port type '0x%04X'.\n", dev->device); + + if (amcc) { unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; @@ -1295,7 +1541,7 @@ static int pci_quatech_init(struct pci_dev *dev) outl(inl(base + 0x38) | 0x00002000, base + 0x38); tmp = inl(base + 0x3c); outl(tmp | 0x01000000, base + 0x3c); - outl(tmp &= ~0x01000000, base + 0x3c); + outl(tmp & ~0x01000000, base + 0x3c); } } return 0; @@ -1305,20 +1551,19 @@ static int pci_quatech_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + /* Needed by pci_quatech calls below */ port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags)); /* Set up the clocking */ port->port.uartclk = pci_quatech_clock(port); /* For now just warn about RS422 */ if (pci_quatech_rs422(port)) - pr_warn("quatech: software control of RS422 features not currently supported.\n"); + pci_warn(priv->dev, "software control of RS422 features not currently supported.\n"); return pci_default_setup(priv, board, port, idx); } -static void pci_quatech_exit(struct pci_dev *dev) -{ -} - static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1339,85 +1584,6 @@ static int pci_default_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, board->reg_shift); } -static void -pericom_do_set_divisor(struct uart_port *port, unsigned int baud, - unsigned int quot, unsigned int quot_frac) -{ - int scr; - int lcr; - int actual_baud; - int tolerance; - - for (scr = 5 ; scr <= 15 ; scr++) { - actual_baud = 921600 * 16 / scr; - tolerance = actual_baud / 50; - - if ((baud < actual_baud + tolerance) && - (baud > actual_baud - tolerance)) { - - lcr = serial_port_in(port, UART_LCR); - serial_port_out(port, UART_LCR, lcr | 0x80); - - serial_port_out(port, UART_DLL, 1); - serial_port_out(port, UART_DLM, 0); - serial_port_out(port, 2, 16 - scr); - serial_port_out(port, UART_LCR, lcr); - return; - } else if (baud > actual_baud) { - break; - } - } - serial8250_do_set_divisor(port, baud, quot, quot_frac); -} -static int pci_pericom_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset, maxnr; - - bar = FL_GET_BASE(board->flags); - if (board->flags & FL_BASE_BARS) - bar += idx; - else - offset += idx * board->uart_offset; - - - maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> - (board->reg_shift + 3); - - if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) - return 1; - - port->port.set_divisor = pericom_do_set_divisor; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -static int pci_pericom_setup_four_at_eight(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset, maxnr; - - bar = FL_GET_BASE(board->flags); - if (board->flags & FL_BASE_BARS) - bar += idx; - else - offset += idx * board->uart_offset; - - if (idx==3) - offset = 0x38; - - maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> - (board->reg_shift + 3); - - if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) - return 1; - - port->port.set_divisor = pericom_do_set_divisor; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} static int ce4100_serial_setup(struct serial_private *priv, @@ -1461,7 +1627,7 @@ pci_brcm_trumanage_setup(struct serial_private *priv, #define FINTEK_RTS_INVERT BIT(5) /* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, +static int pci_fintek_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct pci_dev *pci_dev = to_pci_dev(port->dev); @@ -1470,16 +1636,6 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); - if (!rs485) - rs485 = &port->rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - if (rs485->flags & SER_RS485_ENABLED) { /* Enable RTS H/W control mode */ setting |= FINTEK_RTS_CONTROL_BY_HW; @@ -1491,9 +1647,6 @@ static int pci_fintek_rs485_config(struct uart_port *port, /* RTS driving low on TX */ setting |= FINTEK_RTS_INVERT; } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; } else { /* Disable RTS H/W control mode */ setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); @@ -1501,12 +1654,14 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - if (rs485 != &port->rs485) - port->rs485 = *rs485; - return 0; } +static const struct serial_rs485 pci_fintek_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, + /* F81504/508/512 does not support RTS delay before or after send */ +}; + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1516,16 +1671,20 @@ static int pci_fintek_setup(struct serial_private *priv, u8 config_base; u16 iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(pdev); + config_base = 0x40 + 0x08 * idx; /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, &iobase); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + pci_dbg(pdev, "idx=%d iobase=0x%x", idx, iobase); port->port.iotype = UPIO_PORT; port->port.iobase = iobase; port->port.rs485_config = pci_fintek_rs485_config; + port->port.rs485_supported = pci_fintek_rs485_supported; data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL); if (!data) @@ -1545,7 +1704,9 @@ static int pci_fintek_init(struct pci_dev *dev) resource_size_t bar_data[3]; u8 config_base; struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; + + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) || !(pci_resource_flags(dev, 4) & IORESOURCE_IO) || @@ -1592,13 +1753,7 @@ static int pci_fintek_init(struct pci_dev *dev) pci_write_config_byte(dev, config_base + 0x06, dev->irq); - if (priv) { - /* re-apply RS232/485 mode when - * pciserial_resume_ports() - */ - port = serial8250_get_port(priv->line[i]); - pci_fintek_rs485_config(&port->port, NULL); - } else { + if (!priv) { /* First init without port data * force init to RS232 Mode */ @@ -1609,7 +1764,7 @@ static int pci_fintek_init(struct pci_dev *dev) return max_port; } -static void f815xxa_mem_serial_out(struct uart_port *p, int offset, int value) +static void f815xxa_mem_serial_out(struct uart_port *p, unsigned int offset, u32 value) { struct f815xxa_data *data = p->private_data; unsigned long flags; @@ -1685,7 +1840,7 @@ static int skip_tx_en_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { port->port.quirks |= UPQ_NO_TXEN_TEST; - dev_dbg(&priv->dev->dev, + pci_dbg(priv->dev, "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, priv->dev->device, priv->dev->subsystem_vendor, priv->dev->subsystem_device); @@ -1704,10 +1859,10 @@ static void kt_handle_break(struct uart_port *p) serial8250_clear_and_reinit_fifos(up); } -static unsigned int kt_serial_in(struct uart_port *p, int offset) +static u32 kt_serial_in(struct uart_port *p, unsigned int offset) { struct uart_8250_port *up = up_to_u8250p(p); - unsigned int val; + u32 val; /* * When the Intel ME (management engine) gets reset its serial @@ -1731,6 +1886,9 @@ static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_BUG_THRE; port->port.serial_in = kt_serial_in; port->port.handle_break = kt_handle_break; @@ -1751,6 +1909,9 @@ pci_wch_ch353_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); @@ -1761,6 +1922,9 @@ pci_wch_ch355_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); @@ -1771,11 +1935,54 @@ pci_wch_ch38x_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16850; return pci_default_setup(priv, board, port, idx); } + +#define CH384_XINT_ENABLE_REG 0xEB +#define CH384_XINT_ENABLE_BIT 0x02 + +static int pci_wch_ch38x_init(struct pci_dev *dev) +{ + int max_port; + unsigned long iobase; + + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + + switch (dev->device) { + case 0x3853: /* 8 ports */ + max_port = 8; + break; + default: + return -EINVAL; + } + + iobase = pci_resource_start(dev, 0); + outb(CH384_XINT_ENABLE_BIT, iobase + CH384_XINT_ENABLE_REG); + + return max_port; +} + +static void pci_wch_ch38x_exit(struct pci_dev *dev) +{ + unsigned long iobase; + + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) { + serial_8250_warn_need_ioport(dev); + return; + } + + iobase = pci_resource_start(dev, 0); + outb(0x0, iobase + CH384_XINT_ENABLE_REG); +} + + static int pci_sunix_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1800,6 +2007,119 @@ pci_sunix_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, 0); } +#define MOXA_PUART_GPIO_EN 0x09 +#define MOXA_PUART_GPIO_OUT 0x0A + +#define MOXA_GPIO_PIN2 BIT(2) + +#define MOXA_RS232 0x00 +#define MOXA_RS422 0x01 +#define MOXA_RS485_4W 0x0B +#define MOXA_RS485_2W 0x0F +#define MOXA_UIR_OFFSET 0x04 +#define MOXA_EVEN_RS_MASK GENMASK(3, 0) +#define MOXA_ODD_RS_MASK GENMASK(7, 4) + +enum { + MOXA_SUPP_RS232 = BIT(0), + MOXA_SUPP_RS422 = BIT(1), + MOXA_SUPP_RS485 = BIT(2), +}; + +static unsigned short moxa_get_nports(unsigned short device) +{ + switch (device) { + case PCI_DEVICE_ID_MOXA_CP116E_A_A: + case PCI_DEVICE_ID_MOXA_CP116E_A_B: + return 8; + } + + return FIELD_GET(0x00F0, device); +} + +static bool pci_moxa_is_mini_pcie(unsigned short device) +{ + if (device == PCI_DEVICE_ID_MOXA_CP102N || + device == PCI_DEVICE_ID_MOXA_CP104N || + device == PCI_DEVICE_ID_MOXA_CP112N || + device == PCI_DEVICE_ID_MOXA_CP114N || + device == PCI_DEVICE_ID_MOXA_CP132N || + device == PCI_DEVICE_ID_MOXA_CP134N) + return true; + + return false; +} + +static unsigned int pci_moxa_supported_rs(struct pci_dev *dev) +{ + switch (dev->device & 0x0F00) { + case 0x0000: + case 0x0600: + return MOXA_SUPP_RS232; + case 0x0100: + return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485; + case 0x0300: + return MOXA_SUPP_RS422 | MOXA_SUPP_RS485; + } + return 0; +} + +static int pci_moxa_set_interface(const struct pci_dev *dev, + unsigned int port_idx, + u8 mode) +{ + resource_size_t iobar_addr = pci_resource_start(dev, 2); + resource_size_t UIR_addr = iobar_addr + MOXA_UIR_OFFSET + port_idx / 2; + u8 val; + + val = inb(UIR_addr); + + if (port_idx % 2) { + val &= ~MOXA_ODD_RS_MASK; + val |= FIELD_PREP(MOXA_ODD_RS_MASK, mode); + } else { + val &= ~MOXA_EVEN_RS_MASK; + val |= FIELD_PREP(MOXA_EVEN_RS_MASK, mode); + } + outb(val, UIR_addr); + + return 0; +} + +static int pci_moxa_init(struct pci_dev *dev) +{ + unsigned short device = dev->device; + resource_size_t iobar_addr = pci_resource_start(dev, 2); + unsigned int i, num_ports = moxa_get_nports(device); + u8 val, init_mode = MOXA_RS232; + + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + + if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) { + init_mode = MOXA_RS422; + } + for (i = 0; i < num_ports; ++i) + pci_moxa_set_interface(dev, i, init_mode); + + /* + * Enable hardware buffer to prevent break signal output when system boots up. + * This hardware buffer is only supported on Mini PCIe series. + */ + if (pci_moxa_is_mini_pcie(device)) { + /* Set GPIO direction */ + val = inb(iobar_addr + MOXA_PUART_GPIO_EN); + val |= MOXA_GPIO_PIN2; + outb(val, iobar_addr + MOXA_PUART_GPIO_EN); + /* Enable low GPIO */ + val = inb(iobar_addr + MOXA_PUART_GPIO_OUT); + val &= ~MOXA_GPIO_PIN2; + outb(val, iobar_addr + MOXA_PUART_GPIO_OUT); + } + + return num_ports; +} + static int pci_moxa_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1808,6 +2128,9 @@ pci_moxa_setup(struct serial_private *priv, unsigned int bar = FL_GET_BASE(board->flags); int offset; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + if (board->num_ports == 4 && idx == 3) offset = 7 * board->uart_offset; else @@ -1816,112 +2139,6 @@ pci_moxa_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, 0); } -#define PCI_VENDOR_ID_SBSMODULARIO 0x124B -#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B -#define PCI_DEVICE_ID_OCTPRO 0x0001 -#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108 -#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208 -#define PCI_SUBDEVICE_ID_POCTAL232 0x0308 -#define PCI_SUBDEVICE_ID_POCTAL422 0x0408 -#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500 -#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530 -#define PCI_VENDOR_ID_ADVANTECH 0x13fe -#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 -#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 -#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618 -#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618 -#define PCI_DEVICE_ID_TITAN_200I 0x8028 -#define PCI_DEVICE_ID_TITAN_400I 0x8048 -#define PCI_DEVICE_ID_TITAN_800I 0x8088 -#define PCI_DEVICE_ID_TITAN_800EH 0xA007 -#define PCI_DEVICE_ID_TITAN_800EHB 0xA008 -#define PCI_DEVICE_ID_TITAN_400EH 0xA009 -#define PCI_DEVICE_ID_TITAN_100E 0xA010 -#define PCI_DEVICE_ID_TITAN_200E 0xA012 -#define PCI_DEVICE_ID_TITAN_400E 0xA013 -#define PCI_DEVICE_ID_TITAN_800E 0xA014 -#define PCI_DEVICE_ID_TITAN_200EI 0xA016 -#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 -#define PCI_DEVICE_ID_TITAN_200V3 0xA306 -#define PCI_DEVICE_ID_TITAN_400V3 0xA310 -#define PCI_DEVICE_ID_TITAN_410V3 0xA312 -#define PCI_DEVICE_ID_TITAN_800V3 0xA314 -#define PCI_DEVICE_ID_TITAN_800V3B 0xA315 -#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 -#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 -#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 -#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d -#define PCI_VENDOR_ID_WCH 0x4348 -#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253 -#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453 -#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 -#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053 -#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 -#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173 -#define PCI_VENDOR_ID_AGESTAR 0x5372 -#define PCI_DEVICE_ID_AGESTAR_9375 0x6872 -#define PCI_VENDOR_ID_ASIX 0x9710 -#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a -#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e - -#define PCIE_VENDOR_ID_WCH 0x1c00 -#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 -#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 -#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253 - -#define PCI_VENDOR_ID_ACCESIO 0x494f -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB 0x1051 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S 0x1053 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB 0x105C -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S 0x105E -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB 0x1091 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2 0x1093 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB 0x1099 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4 0x109B -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB 0x10D1 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM 0x10D3 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB 0x10DA -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM 0x10DC -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1 0x1108 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2 0x1110 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2 0x1111 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4 0x1118 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4 0x1119 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S 0x1152 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S 0x115A -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2 0x1190 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2 0x1191 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4 0x1198 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4 0x1199 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM 0x11D0 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4 0x105A -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4 0x105B -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8 0x106A -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8 0x106B -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4 0x1098 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8 0x10A9 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM 0x10D9 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM 0x10E9 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8 - - -#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 -#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 -#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 -#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 -#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 -#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 -#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 -#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 -#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 -#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 -#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 -#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 - -/* Unknown vendors/cards - this should not be in linux/pci_ids.h */ -#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 -#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 - /* * Master list of serial port init/setup/exit quirks. * This does not describe the general nature of the port. @@ -1930,7 +2147,7 @@ pci_moxa_setup(struct serial_private *priv, * This list is ordered alphabetically by vendor then device. * Specific entries must come before more generic entries. */ -static struct pci_serial_quirk pci_serial_quirks[] __refdata = { +static struct pci_serial_quirk pci_serial_quirks[] = { /* * ADDI-DATA GmbH communication cards <info@addi-data.com> */ @@ -1964,6 +2181,16 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_hp_diva_setup, }, /* + * HPE PCI serial device + */ + { + .vendor = PCI_VENDOR_ID_HP_3PAR, + .device = PCI_DEVICE_ID_HPE_PCI_SERIAL, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_hp_diva_setup, + }, + /* * Intel */ { @@ -2149,7 +2376,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .init = pci_quatech_init, .setup = pci_quatech_setup, - .exit = pci_quatech_exit, }, /* * Panacom @@ -2173,16 +2399,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .exit = pci_plx9050_exit, }, /* - * Pericom (Only 7954 - It have a offset jump for port 4) - */ - { - .vendor = PCI_VENDOR_ID_PERICOM, - .device = PCI_DEVICE_ID_PERICOM_PI7C9X7954, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - /* * PLX */ { @@ -2212,118 +2428,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_default_setup, .exit = pci_plx9050_exit, }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, - }, /* + /* * SBS Technologies, Inc., PMC-OCTALPRO 232 */ { @@ -2458,7 +2563,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .init = pci_endrun_init, + .init = pci_oxsemi_tornado_init, .setup = pci_default_setup, }, /* @@ -2470,7 +2575,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, + .setup = pci_oxsemi_tornado_setup, }, { .vendor = PCI_VENDOR_ID_MAINPINE, @@ -2478,7 +2583,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, + .setup = pci_oxsemi_tornado_setup, }, { .vendor = PCI_VENDOR_ID_DIGI, @@ -2486,7 +2591,170 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_SUBVENDOR_ID_IBM, .subdevice = PCI_ANY_ID, .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, + .setup = pci_oxsemi_tornado_setup, + }, + /* + * Brainboxes devices - all Oxsemi based + */ + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4027, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4028, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4029, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4019, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4016, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4015, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x400A, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x400E, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x400C, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x400B, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x400F, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4010, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4011, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x401D, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x401E, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4013, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4017, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4018, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4026, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTASHIELD, + .device = 0x4021, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_oxsemi_tornado_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, @@ -2572,85 +2840,85 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, /* WCH CH353 1S1P card (16550 clone) */ { - .vendor = PCI_VENDOR_ID_WCH, - .device = PCI_DEVICE_ID_WCH_CH353_1S1P, + .vendor = PCI_VENDOR_ID_WCHCN, + .device = PCI_DEVICE_ID_WCHCN_CH353_1S1P, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, /* WCH CH353 2S1P card (16550 clone) */ { - .vendor = PCI_VENDOR_ID_WCH, - .device = PCI_DEVICE_ID_WCH_CH353_2S1P, + .vendor = PCI_VENDOR_ID_WCHCN, + .device = PCI_DEVICE_ID_WCHCN_CH353_2S1P, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, /* WCH CH353 4S card (16550 clone) */ { - .vendor = PCI_VENDOR_ID_WCH, - .device = PCI_DEVICE_ID_WCH_CH353_4S, + .vendor = PCI_VENDOR_ID_WCHCN, + .device = PCI_DEVICE_ID_WCHCN_CH353_4S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, /* WCH CH353 2S1PF card (16550 clone) */ { - .vendor = PCI_VENDOR_ID_WCH, - .device = PCI_DEVICE_ID_WCH_CH353_2S1PF, + .vendor = PCI_VENDOR_ID_WCHCN, + .device = PCI_DEVICE_ID_WCHCN_CH353_2S1PF, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, /* WCH CH352 2S card (16550 clone) */ { - .vendor = PCI_VENDOR_ID_WCH, - .device = PCI_DEVICE_ID_WCH_CH352_2S, + .vendor = PCI_VENDOR_ID_WCHCN, + .device = PCI_DEVICE_ID_WCHCN_CH352_2S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, /* WCH CH355 4S card (16550 clone) */ { - .vendor = PCI_VENDOR_ID_WCH, - .device = PCI_DEVICE_ID_WCH_CH355_4S, + .vendor = PCI_VENDOR_ID_WCHCN, + .device = PCI_DEVICE_ID_WCHCN_CH355_4S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch355_setup, }, /* WCH CH382 2S card (16850 clone) */ { - .vendor = PCIE_VENDOR_ID_WCH, - .device = PCIE_DEVICE_ID_WCH_CH382_2S, + .vendor = PCI_VENDOR_ID_WCHIC, + .device = PCI_DEVICE_ID_WCHIC_CH382_2S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch38x_setup, }, /* WCH CH382 2S1P card (16850 clone) */ { - .vendor = PCIE_VENDOR_ID_WCH, - .device = PCIE_DEVICE_ID_WCH_CH382_2S1P, + .vendor = PCI_VENDOR_ID_WCHIC, + .device = PCI_DEVICE_ID_WCHIC_CH382_2S1P, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch38x_setup, }, /* WCH CH384 4S card (16850 clone) */ { - .vendor = PCIE_VENDOR_ID_WCH, - .device = PCIE_DEVICE_ID_WCH_CH384_4S, + .vendor = PCI_VENDOR_ID_WCHIC, + .device = PCI_DEVICE_ID_WCHIC_CH384_4S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_wch_ch38x_setup, }, - /* - * ASIX devices with FIFO bug - */ + /* WCH CH384 8S card (16850 clone) */ { - .vendor = PCI_VENDOR_ID_ASIX, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_asix_setup, + .vendor = PCI_VENDOR_ID_WCHIC, + .device = PCI_DEVICE_ID_WCHIC_CH384_8S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_wch_ch38x_init, + .exit = pci_wch_ch38x_exit, + .setup = pci_wch_ch38x_setup, }, /* * Broadcom TruManage (NetXtreme) @@ -2694,6 +2962,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .init = pci_moxa_init, .setup = pci_moxa_setup, }, { @@ -2751,15 +3020,6 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) return quirk; } -static inline int get_pci_irq(struct pci_dev *dev, - const struct pciserial_board *board) -{ - if (board->flags & FL_NOIRQ) - return 0; - else - return dev->irq; -} - /* * This is the configuration table for all of the PCI serial boards * which we support. It is directly indexed by the pci_board_num_t enum @@ -2802,7 +3062,7 @@ enum pci_board_num_t { pbn_b0_2_1843200, pbn_b0_4_1843200, - pbn_b0_1_4000000, + pbn_b0_1_15625000, pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, @@ -2880,12 +3140,11 @@ enum pci_board_num_t { pbn_panacom2, pbn_panacom4, pbn_plx_romulus, - pbn_endrun_2_4000000, pbn_oxsemi, - pbn_oxsemi_1_4000000, - pbn_oxsemi_2_4000000, - pbn_oxsemi_4_4000000, - pbn_oxsemi_8_4000000, + pbn_oxsemi_1_15625000, + pbn_oxsemi_2_15625000, + pbn_oxsemi_4_15625000, + pbn_oxsemi_8_15625000, pbn_intel_i960, pbn_sgi_ioc3, pbn_computone_4, @@ -2913,18 +3172,19 @@ enum pci_board_num_t { pbn_fintek_F81512A, pbn_wch382_2, pbn_wch384_4, - pbn_pericom_PI7C9X7951, - pbn_pericom_PI7C9X7952, - pbn_pericom_PI7C9X7954, - pbn_pericom_PI7C9X7958, + pbn_wch384_8, pbn_sunix_pci_1s, pbn_sunix_pci_2s, pbn_sunix_pci_4s, pbn_sunix_pci_8s, pbn_sunix_pci_16s, - pbn_moxa8250_2p, - pbn_moxa8250_4p, - pbn_moxa8250_8p, + pbn_titan_1_4000000, + pbn_titan_2_4000000, + pbn_titan_4_4000000, + pbn_titan_8_4000000, + pbn_moxa_2, + pbn_moxa_4, + pbn_moxa_8, }; /* @@ -3027,10 +3287,10 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, }, - [pbn_b0_1_4000000] = { + [pbn_b0_1_15625000] = { .flags = FL_BASE0, .num_ports = 1, - .base_baud = 4000000, + .base_baud = 15625000, .uart_offset = 8, }, @@ -3402,20 +3662,6 @@ static struct pciserial_board pci_boards[] = { }, /* - * EndRun Technologies - * Uses the size of PCI Base region 0 to - * signal now many ports are available - * 2 port 952 Uart support - */ - [pbn_endrun_2_4000000] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 4000000, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - - /* * This board uses the size of PCI Base region 0 to * signal now many ports are available */ @@ -3425,31 +3671,31 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .uart_offset = 8, }, - [pbn_oxsemi_1_4000000] = { + [pbn_oxsemi_1_15625000] = { .flags = FL_BASE0, .num_ports = 1, - .base_baud = 4000000, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_2_4000000] = { + [pbn_oxsemi_2_15625000] = { .flags = FL_BASE0, .num_ports = 2, - .base_baud = 4000000, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_4_4000000] = { + [pbn_oxsemi_4_15625000] = { .flags = FL_BASE0, .num_ports = 4, - .base_baud = 4000000, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_8_4000000] = { + [pbn_oxsemi_8_15625000] = { .flags = FL_BASE0, .num_ports = 8, - .base_baud = 4000000, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, @@ -3650,32 +3896,12 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, .first_offset = 0xC0, }, - /* - * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART - */ - [pbn_pericom_PI7C9X7951] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 0x8, - }, - [pbn_pericom_PI7C9X7952] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 0x8, - }, - [pbn_pericom_PI7C9X7954] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 0x8, - }, - [pbn_pericom_PI7C9X7958] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 0x8, + [pbn_wch384_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + .first_offset = 0x00, }, [pbn_sunix_pci_1s] = { .num_ports = 1, @@ -3702,19 +3928,47 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .uart_offset = 0x8, }, - [pbn_moxa8250_2p] = { + [pbn_titan_1_4000000] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_titan_2_4000000] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_titan_4_4000000] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_titan_8_4000000] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_moxa_2] = { .flags = FL_BASE1, .num_ports = 2, .base_baud = 921600, .uart_offset = 0x200, }, - [pbn_moxa8250_4p] = { + [pbn_moxa_4] = { .flags = FL_BASE1, .num_ports = 4, .base_baud = 921600, .uart_offset = 0x200, }, - [pbn_moxa8250_8p] = { + [pbn_moxa_8] = { .flags = FL_BASE1, .num_ports = 8, .base_baud = 921600, @@ -3722,6 +3976,12 @@ static struct pciserial_board pci_boards[] = { }, }; +#define REPORT_CONFIG(option) \ + (IS_ENABLED(CONFIG_##option) ? 0 : (kernel_ulong_t)&#option) +#define REPORT_8250_CONFIG(option) \ + (IS_ENABLED(CONFIG_SERIAL_8250_##option) ? \ + 0 : (kernel_ulong_t)&"SERIAL_8250_"#option) + static const struct pci_device_id blacklist[] = { /* softmodems */ { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */ @@ -3729,30 +3989,43 @@ static const struct pci_device_id blacklist[] = { { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */ /* multi-io cards handled by parport_serial */ - { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ - { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ - { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ + /* WCH CH353 2S1P */ + { PCI_VDEVICE(WCHCN, 0x7053), REPORT_CONFIG(PARPORT_SERIAL), }, + /* WCH CH353 1S1P */ + { PCI_VDEVICE(WCHCN, 0x5053), REPORT_CONFIG(PARPORT_SERIAL), }, + /* WCH CH382 2S1P */ + { PCI_VDEVICE(WCHIC, 0x3250), REPORT_CONFIG(PARPORT_SERIAL), }, /* Intel platforms with MID UART */ - { PCI_VDEVICE(INTEL, 0x081b), }, - { PCI_VDEVICE(INTEL, 0x081c), }, - { PCI_VDEVICE(INTEL, 0x081d), }, - { PCI_VDEVICE(INTEL, 0x1191), }, - { PCI_VDEVICE(INTEL, 0x18d8), }, - { PCI_VDEVICE(INTEL, 0x19d8), }, + { PCI_VDEVICE(INTEL, 0x081b), REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x081c), REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x081d), REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x1191), REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x18d8), REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x19d8), REPORT_8250_CONFIG(MID), }, /* Intel platforms with DesignWare UART */ - { PCI_VDEVICE(INTEL, 0x0936), }, - { PCI_VDEVICE(INTEL, 0x0f0a), }, - { PCI_VDEVICE(INTEL, 0x0f0c), }, - { PCI_VDEVICE(INTEL, 0x228a), }, - { PCI_VDEVICE(INTEL, 0x228c), }, - { PCI_VDEVICE(INTEL, 0x9ce3), }, - { PCI_VDEVICE(INTEL, 0x9ce4), }, + { PCI_VDEVICE(INTEL, 0x0936), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x0f0a), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x0f0c), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x228a), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x228c), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b96), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b97), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b98), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b99), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b9a), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b9b), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x9ce3), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x9ce4), REPORT_8250_CONFIG(LPSS), }, /* Exar devices */ - { PCI_VDEVICE(EXAR, PCI_ANY_ID), }, - { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), }, + { PCI_VDEVICE(EXAR, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), }, + { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), }, + + /* Pericom devices */ + { PCI_VDEVICE(PERICOM, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), }, + { PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), }, /* End of the black list */ { } @@ -3886,9 +4159,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) nr_ports = rc; } - priv = kzalloc(sizeof(struct serial_private) + - sizeof(unsigned int) * nr_ports, - GFP_KERNEL); + priv = kzalloc(struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) { priv = ERR_PTR(-ENOMEM); goto err_deinit; @@ -3901,33 +4172,39 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; uart.port.uartclk = board->base_baud * 16; - if (pci_match_id(pci_use_msi, dev)) { - dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n"); - pci_set_master(dev); - rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); + if (board->flags & FL_NOIRQ) { + uart.port.irq = 0; } else { - dev_dbg(&dev->dev, "Using legacy interrupts\n"); - rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); - } - if (rc < 0) { - kfree(priv); - priv = ERR_PTR(rc); - goto err_deinit; + if (pci_match_id(pci_use_msi, dev)) { + pci_dbg(dev, "Using MSI(-X) interrupts\n"); + pci_set_master(dev); + uart.port.flags &= ~UPF_SHARE_IRQ; + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); + } else { + pci_dbg(dev, "Using legacy interrupts\n"); + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_INTX); + } + if (rc < 0) { + kfree(priv); + priv = ERR_PTR(rc); + goto err_deinit; + } + + uart.port.irq = pci_irq_vector(dev, 0); } - uart.port.irq = pci_irq_vector(dev, 0); uart.port.dev = &dev->dev; for (i = 0; i < nr_ports; i++) { if (quirk->setup(priv, board, &uart, i)) break; - dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + pci_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n", uart.port.iobase, uart.port.irq, uart.port.iotype); priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { - dev_err(&dev->dev, + pci_err(dev, "Couldn't register serial port %lx, irq %d, type %d, error %d\n", uart.port.iobase, uart.port.irq, uart.port.iotype, priv->line[i]); @@ -4023,16 +4300,19 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - dev_err(&dev->dev, "invalid driver_data: %ld\n", - ent->driver_data); + pci_err(dev, "invalid driver_data: %ld\n", ent->driver_data); return -EINVAL; } board = &pci_boards[ent->driver_data]; exclude = pci_match_id(blacklist, dev); - if (exclude) + if (exclude) { + if (exclude->driver_data) + pci_warn(dev, "ignoring port, enable %s to handle\n", + (const char *)exclude->driver_data); return -ENODEV; + } rc = pcim_enable_device(dev); pci_save_state(dev); @@ -4107,7 +4387,7 @@ static int pciserial_resume_one(struct device *dev) err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); + pci_err(pdev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; @@ -4118,6 +4398,9 @@ static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, pciserial_resume_one); static const struct pci_device_id serial_pci_tbl[] = { + { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600, + PCI_DEVICE_ID_ADVANTECH_PCI1600_1611, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, @@ -4301,13 +4584,6 @@ static const struct pci_device_id serial_pci_tbl[] = { 0x10b5, 0x106a, 0, 0, pbn_plx_romulus }, /* - * EndRun Technologies. PCI express device range. - * EndRun PTP/1588 has 2 Native UARTs. - */ - { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_endrun_2_4000000 }, - /* * Quatech cards. These actually have configurable clocks but for * now we just use the default. * @@ -4416,158 +4692,165 @@ static const struct pci_device_id serial_pci_tbl[] = { */ { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_oxsemi_4_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_oxsemi_4_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_oxsemi_8_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_oxsemi_8_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, /* * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado */ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_15625000 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_oxsemi_4_15625000 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_oxsemi_8_15625000 }, /* * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado */ { PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM, PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_15625000 }, + /* + * EndRun Technologies. PCI express device range. + * EndRun PTP/1588 has 2 Native UARTs utilizing OxSemi 952. + */ + { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_15625000 }, /* * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards, @@ -4641,22 +4924,22 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_b0_4_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_titan_1_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_titan_2_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_titan_4_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_titan_8_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_titan_2_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_titan_2_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_921600 }, @@ -4801,12 +5084,6 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_4_460800 }, @@ -4930,6 +5207,10 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_1_115200 }, + /* HPE PCI serial device */ + { PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_115200 }, { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -4941,127 +5222,6 @@ static const struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b3_8_115200 }, /* - * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART - */ - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7951 }, - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7958 }, - /* - * ACCES I/O Products quad - */ - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7951 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560, @@ -5076,10 +5236,16 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_b1_bt_1_115200 }, /* + * IntaShield IS-100 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0D60, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_115200 }, + /* * IntaShield IS-200 */ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0d80 */ pbn_b2_2_115200 }, /* * IntaShield IS-400 @@ -5088,7 +5254,62 @@ static const struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ pbn_b2_4_115200 }, /* - * BrainBoxes UC-260 + * IntaShield IX-100 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4027, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * IntaShield IX-200 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4028, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * IntaShield IX-400 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4029, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* Brainboxes Devices */ + /* + * Brainboxes UC-101 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0BA1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0BA2, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0BA3, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-235/246 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0AA1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0AA2, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_1_115200 }, + /* + * Brainboxes UC-253/UC-734 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0CA1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-260/271/701/756 */ { PCI_VENDOR_ID_INTASHIELD, 0x0D21, PCI_ANY_ID, PCI_ANY_ID, @@ -5096,9 +5317,349 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_b2_4_115200 }, { PCI_VENDOR_ID_INTASHIELD, 0x0E34, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, + /* + * Brainboxes UC-268 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0841, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + /* + * Brainboxes UC-275/279 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0881, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_8_115200 }, + /* + * Brainboxes UC-302 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x08E1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x08E2, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x08E3, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-310 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x08C1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-313 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x08A1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x08A2, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x08A3, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-320/324 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0A61, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_1_115200 }, + /* + * Brainboxes UC-346 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0B01, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0B02, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b2_4_115200 }, /* + * Brainboxes UC-357 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0A81, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0A82, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0A83, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-368 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0C41, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0C42, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0C43, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + /* + * Brainboxes UC-420 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0921, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + /* + * Brainboxes UC-607 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x09A1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x09A2, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x09A3, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UC-836 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0D41, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_4_115200 }, + /* + * Brainboxes UP-189 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0AC1, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0AC2, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0AC3, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UP-200 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0B21, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0B22, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0B23, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UP-869 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0C01, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0C02, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0C03, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes UP-880 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0C21, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0C22, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0C23, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_2_115200 }, + /* + * Brainboxes PX-101 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4005, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4019, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-235/246 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4004, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4016, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-203/PX-257 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4006, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4015, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-260/PX-701 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400A, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-275/279 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0E41, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b2_8_115200 }, + /* + * Brainboxes PX-310 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400E, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-313 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400C, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-320/324/PX-376/PX-387 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400B, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-335/346 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400F, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-368 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4010, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-420 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4000, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4011, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-475 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x401D, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-803/PX-857 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4009, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4018, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + { PCI_VENDOR_ID_INTASHIELD, 0x401E, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-820 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4002, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4013, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-835/PX-846 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4008, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4017, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes XC-235 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4026, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes XC-475 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4021, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + + /* * Perle PCI-RAS cards */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, @@ -5306,42 +5867,24 @@ static const struct pci_device_id serial_pci_tbl[] = { /* * MOXA */ - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_2p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102EL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_2p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_4p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114EL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_4p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_8p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_8p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_8p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_8p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132EL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_2p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_4p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP138E_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_8p }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_moxa8250_8p }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E), pbn_moxa_2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL), pbn_moxa_2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N), pbn_moxa_2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A), pbn_moxa_4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N), pbn_moxa_4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N), pbn_moxa_2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL), pbn_moxa_4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N), pbn_moxa_4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A), pbn_moxa_8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B), pbn_moxa_8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A), pbn_moxa_8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I), pbn_moxa_8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL), pbn_moxa_2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N), pbn_moxa_2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A), pbn_moxa_4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N), pbn_moxa_4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A), pbn_moxa_8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A), pbn_moxa_8 }, /* * ADDI-DATA GmbH communication cards <info@addi-data.com> @@ -5466,6 +6009,38 @@ static const struct pci_device_id serial_pci_tbl[] = { 0, pbn_ADDIDATA_PCIe_8_3906250 }, + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7500, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, PCI_VENDOR_ID_IBM, 0x0299, 0, 0, pbn_b0_bt_2_115200 }, @@ -5516,6 +6091,14 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, 0xA000, 0x3004, 0, 0, pbn_b0_bt_4_115200 }, + + /* + * ASIX AX99100 PCIe to Multi I/O Controller + */ + { PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100, + 0xA000, 0x1000, + 0, 0, pbn_b0_1_115200 }, + /* Intel CE4100 */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -5546,26 +6129,40 @@ static const struct pci_device_id serial_pci_tbl[] = { * WCH CH353 series devices: The 2S1P is handled by parport_serial * so not listed here. */ - { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S, + { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_4_115200 }, - { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF, + { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_2S1PF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S, + { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH355_4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_4_115200 }, - { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S, + { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH382_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_wch382_2 }, - { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S, + { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_wch384_4 }, + { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_8S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_wch384_8 }, + /* + * Realtek RealManage + */ + { PCI_VENDOR_ID_REALTEK, 0x816a, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_REALTEK, 0x816b, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_1_115200 }, + /* Fintek PCI serial cards */ { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, @@ -5626,7 +6223,6 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev) return PCI_ERS_RESULT_DISCONNECT; pci_restore_state(dev); - pci_save_state(dev); return PCI_ERS_RESULT_RECOVERED; } @@ -5668,3 +6264,4 @@ module_pci_driver(serial_pci_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); MODULE_DEVICE_TABLE(pci, serial_pci_tbl); +MODULE_IMPORT_NS("SERIAL_8250_PCI"); diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c new file mode 100644 index 000000000000..feeede164886 --- /dev/null +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -0,0 +1,887 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Probe module for 8250/16550-type MCHP PCI serial ports. + * + * Based on drivers/tty/serial/8250/8250_pci.c, + * + * Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/circ_buf.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gfp_types.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/overflow.h> +#include <linux/pci.h> +#include <linux/pm.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/serial_8250.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/time.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <asm/byteorder.h> + +#include "8250.h" +#include "8250_pcilib.h" + +#define PCI_DEVICE_ID_EFAR_PCI12000 0xa002 +#define PCI_DEVICE_ID_EFAR_PCI11010 0xa012 +#define PCI_DEVICE_ID_EFAR_PCI11101 0xa022 +#define PCI_DEVICE_ID_EFAR_PCI11400 0xa032 +#define PCI_DEVICE_ID_EFAR_PCI11414 0xa042 + +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p 0x0001 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012 0x0002 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013 0x0003 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023 0x0004 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123 0x0005 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01 0x0006 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02 0x0007 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03 0x0008 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12 0x0009 +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13 0x000a +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23 0x000b +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0 0x000c +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1 0x000d +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2 0x000e +#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 0x000f + +#define PCI_SUBDEVICE_ID_EFAR_PCI12000 PCI_DEVICE_ID_EFAR_PCI12000 +#define PCI_SUBDEVICE_ID_EFAR_PCI11010 PCI_DEVICE_ID_EFAR_PCI11010 +#define PCI_SUBDEVICE_ID_EFAR_PCI11101 PCI_DEVICE_ID_EFAR_PCI11101 +#define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400 +#define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414 + +#define UART_SYSTEM_ADDR_BASE 0x1000 +#define UART_DEV_REV_REG (UART_SYSTEM_ADDR_BASE + 0x00) +#define UART_DEV_REV_MASK GENMASK(7, 0) +#define UART_SYSLOCK_REG (UART_SYSTEM_ADDR_BASE + 0xA0) +#define UART_SYSLOCK BIT(2) +#define SYSLOCK_SLEEP_TIMEOUT 100 +#define SYSLOCK_RETRY_CNT 1000 + +#define UART_RX_BYTE_FIFO 0x00 +#define UART_TX_BYTE_FIFO 0x00 +#define UART_FIFO_CTL 0x02 + +#define UART_MODEM_CTL_REG 0x04 +#define UART_MODEM_CTL_RTS_SET BIT(1) + +#define UART_LINE_STAT_REG 0x05 +#define UART_LINE_XMIT_CHECK_MASK GENMASK(6, 5) + +#define UART_ACTV_REG 0x11 +#define UART_BLOCK_SET_ACTIVE BIT(0) + +#define UART_PCI_CTRL_REG 0x80 +#define UART_PCI_CTRL_SET_MULTIPLE_MSI BIT(4) +#define UART_PCI_CTRL_D3_CLK_ENABLE BIT(0) + +#define ADCL_CFG_REG 0x40 +#define ADCL_CFG_POL_SEL BIT(2) +#define ADCL_CFG_PIN_SEL BIT(1) +#define ADCL_CFG_EN BIT(0) + +#define UART_BIT_SAMPLE_CNT_8 8 +#define UART_BIT_SAMPLE_CNT_16 16 +#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8) +#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8) +#define FRAC_DIV_TX_END_POINT_MASK GENMASK(23, 20) + +#define UART_WAKE_REG 0x8C +#define UART_WAKE_MASK_REG 0x90 +#define UART_WAKE_N_PIN BIT(2) +#define UART_WAKE_NCTS BIT(1) +#define UART_WAKE_INT BIT(0) +#define UART_WAKE_SRCS \ + (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT) + +#define UART_BAUD_CLK_DIVISOR_REG 0x54 +#define FRAC_DIV_CFG_REG 0x58 + +#define UART_RESET_REG 0x94 +#define UART_RESET_D3_RESET_DISABLE BIT(16) +#define UART_RESET_HOT_RESET_DISABLE BIT(17) + +#define UART_BURST_STATUS_REG 0x9C +#define UART_TX_BURST_FIFO 0xA0 +#define UART_RX_BURST_FIFO 0xA4 + +#define UART_BIT_DIVISOR_8 0x26731000 +#define UART_BIT_DIVISOR_16 0x6ef71000 +#define UART_BAUD_4MBPS 4000000 + +#define MAX_PORTS 4 +#define PORT_OFFSET 0x100 +#define RX_BUF_SIZE 512 +#define UART_BYTE_SIZE 1 +#define UART_BURST_SIZE 4 + +#define UART_BST_STAT_RX_COUNT_MASK 0x00FF +#define UART_BST_STAT_TX_COUNT_MASK 0xFF00 +#define UART_BST_STAT_IIR_INT_PEND 0x100000 +#define UART_LSR_OVERRUN_ERR_CLR 0x43 +#define UART_BST_STAT_LSR_RX_MASK 0x9F000000 +#define UART_BST_STAT_LSR_RX_ERR_MASK 0x9E000000 +#define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000 +#define UART_BST_STAT_LSR_PARITY_ERR 0x4000000 +#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000 +#define UART_BST_STAT_LSR_THRE 0x20000000 + +#define GET_MODEM_CTL_RTS_STATUS(reg) ((reg) & UART_MODEM_CTL_RTS_SET) +#define GET_RTS_PIN_STATUS(val) (((val) & TIOCM_RTS) >> 1) +#define RTS_TOGGLE_STATUS_MASK(val, reg) (GET_MODEM_CTL_RTS_STATUS(reg) \ + != GET_RTS_PIN_STATUS(val)) + +struct pci1xxxx_8250 { + unsigned int nr; + u8 dev_rev; + u8 pad[3]; + void __iomem *membase; + int line[] __counted_by(nr); +}; + +static const struct serial_rs485 pci1xxxx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, + .delay_rts_after_send = 1, + /* Delay RTS before send is not supported */ +}; + +static int pci1xxxx_set_sys_lock(struct pci1xxxx_8250 *port) +{ + writel(UART_SYSLOCK, port->membase + UART_SYSLOCK_REG); + return readl(port->membase + UART_SYSLOCK_REG); +} + +static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_8250 *port) +{ + u32 regval; + + return readx_poll_timeout(pci1xxxx_set_sys_lock, port, regval, + (regval & UART_SYSLOCK), + SYSLOCK_SLEEP_TIMEOUT, + SYSLOCK_RETRY_CNT * SYSLOCK_SLEEP_TIMEOUT); +} + +static void pci1xxxx_release_sys_lock(struct pci1xxxx_8250 *port) +{ + writel(0x0, port->membase + UART_SYSLOCK_REG); +} + +static const int logical_to_physical_port_idx[][MAX_PORTS] = { + {0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */ + {0, 1, 2, 3}, /* PCI4p */ + {0, 1, 2, -1}, /* PCI3p012 */ + {0, 1, 3, -1}, /* PCI3p013 */ + {0, 2, 3, -1}, /* PCI3p023 */ + {1, 2, 3, -1}, /* PCI3p123 */ + {0, 1, -1, -1}, /* PCI2p01 */ + {0, 2, -1, -1}, /* PCI2p02 */ + {0, 3, -1, -1}, /* PCI2p03 */ + {1, 2, -1, -1}, /* PCI2p12 */ + {1, 3, -1, -1}, /* PCI2p13 */ + {2, 3, -1, -1}, /* PCI2p23 */ + {0, -1, -1, -1}, /* PCI1p0 */ + {1, -1, -1, -1}, /* PCI1p1 */ + {2, -1, -1, -1}, /* PCI1p2 */ + {3, -1, -1, -1}, /* PCI1p3 */ +}; + +static int pci1xxxx_get_num_ports(struct pci_dev *dev) +{ + switch (dev->subsystem_device) { + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3: + case PCI_SUBDEVICE_ID_EFAR_PCI12000: + case PCI_SUBDEVICE_ID_EFAR_PCI11010: + case PCI_SUBDEVICE_ID_EFAR_PCI11101: + case PCI_SUBDEVICE_ID_EFAR_PCI11400: + default: + return 1; + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23: + return 2; + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013: + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023: + return 3; + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p: + case PCI_SUBDEVICE_ID_EFAR_PCI11414: + return 4; + } +} + +static unsigned int pci1xxxx_get_divisor(struct uart_port *port, + unsigned int baud, unsigned int *frac) +{ + unsigned int uart_sample_cnt; + unsigned int quot; + + if (baud >= UART_BAUD_4MBPS) + uart_sample_cnt = UART_BIT_SAMPLE_CNT_8; + else + uart_sample_cnt = UART_BIT_SAMPLE_CNT_16; + + /* + * Calculate baud rate sampling period in nanoseconds. + * Fractional part x denotes x/255 parts of a nanosecond. + */ + quot = NSEC_PER_SEC / (baud * uart_sample_cnt); + *frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) * + 255 / uart_sample_cnt / baud; + + return quot; +} + +static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int frac) +{ + if (baud >= UART_BAUD_4MBPS) + writel(UART_BIT_DIVISOR_8, port->membase + FRAC_DIV_CFG_REG); + else + writel(UART_BIT_DIVISOR_16, port->membase + FRAC_DIV_CFG_REG); + + writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac, + port->membase + UART_BAUD_CLK_DIVISOR_REG); +} + +static void pci1xxxx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + u32 fract_div_cfg_reg; + u32 line_stat_reg; + u32 modem_ctl_reg; + u32 adcl_cfg_reg; + + adcl_cfg_reg = readl(port->membase + ADCL_CFG_REG); + + /* HW is responsible in ADCL_EN case */ + if ((adcl_cfg_reg & (ADCL_CFG_EN | ADCL_CFG_PIN_SEL))) + return; + + modem_ctl_reg = readl(port->membase + UART_MODEM_CTL_REG); + + serial8250_do_set_mctrl(port, mctrl); + + if (RTS_TOGGLE_STATUS_MASK(mctrl, modem_ctl_reg)) { + line_stat_reg = readl(port->membase + UART_LINE_STAT_REG); + if (line_stat_reg & UART_LINE_XMIT_CHECK_MASK) { + fract_div_cfg_reg = readl(port->membase + + FRAC_DIV_CFG_REG); + + writel((fract_div_cfg_reg & + ~(FRAC_DIV_TX_END_POINT_MASK)), + port->membase + FRAC_DIV_CFG_REG); + + /* Enable ADC and set the nRTS pin */ + writel((adcl_cfg_reg | (ADCL_CFG_EN | + ADCL_CFG_PIN_SEL)), + port->membase + ADCL_CFG_REG); + + /* Revert to the original settings */ + writel(adcl_cfg_reg, port->membase + ADCL_CFG_REG); + + writel(fract_div_cfg_reg, port->membase + + FRAC_DIV_CFG_REG); + } + } +} + +static int pci1xxxx_rs485_config(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + u32 delay_in_baud_periods; + u32 baud_period_in_ns; + u32 mode_cfg = 0; + u32 sample_cnt; + u32 clock_div; + u32 frac_div; + + frac_div = readl(port->membase + FRAC_DIV_CFG_REG); + + if (frac_div == UART_BIT_DIVISOR_16) + sample_cnt = UART_BIT_SAMPLE_CNT_16; + else + sample_cnt = UART_BIT_SAMPLE_CNT_8; + + /* + * pci1xxxx's uart hardware supports only RTS delay after + * Tx and in units of bit times to a maximum of 15 + */ + if (rs485->flags & SER_RS485_ENABLED) { + mode_cfg = ADCL_CFG_EN | ADCL_CFG_PIN_SEL; + + if (!(rs485->flags & SER_RS485_RTS_ON_SEND)) + mode_cfg |= ADCL_CFG_POL_SEL; + + if (rs485->delay_rts_after_send) { + clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG); + baud_period_in_ns = + FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) * + sample_cnt; + delay_in_baud_periods = + rs485->delay_rts_after_send * NSEC_PER_MSEC / + baud_period_in_ns; + delay_in_baud_periods = + min_t(u32, delay_in_baud_periods, + FIELD_MAX(ADCL_CFG_RTS_DELAY_MASK)); + mode_cfg |= FIELD_PREP(ADCL_CFG_RTS_DELAY_MASK, + delay_in_baud_periods); + rs485->delay_rts_after_send = + baud_period_in_ns * delay_in_baud_periods / + NSEC_PER_MSEC; + } + } + writel(mode_cfg, port->membase + ADCL_CFG_REG); + return 0; +} + +static u32 pci1xxxx_read_burst_status(struct uart_port *port) +{ + u32 status; + + status = readl(port->membase + UART_BURST_STATUS_REG); + if (status & UART_BST_STAT_LSR_RX_ERR_MASK) { + if (status & UART_BST_STAT_LSR_OVERRUN_ERR) { + writeb(UART_LSR_OVERRUN_ERR_CLR, + port->membase + UART_FIFO_CTL); + port->icount.overrun++; + } + + if (status & UART_BST_STAT_LSR_FRAME_ERR) + port->icount.frame++; + + if (status & UART_BST_STAT_LSR_PARITY_ERR) + port->icount.parity++; + } + return status; +} + +static void pci1xxxx_process_read_data(struct uart_port *port, + unsigned char *rx_buff, u32 *buff_index, + u32 *valid_byte_count) +{ + u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE; + u32 *burst_buf; + + /* + * Depending on the RX Trigger Level the number of bytes that can be + * stored in RX FIFO at a time varies. Each transaction reads data + * in DWORDs. If there are less than four remaining valid_byte_count + * to read, the data is received one byte at a time. + */ + while (valid_burst_count--) { + if (*buff_index > (RX_BUF_SIZE - UART_BURST_SIZE)) + break; + burst_buf = (u32 *)&rx_buff[*buff_index]; + *burst_buf = readl(port->membase + UART_RX_BURST_FIFO); + *buff_index += UART_BURST_SIZE; + *valid_byte_count -= UART_BURST_SIZE; + } + + while (*valid_byte_count) { + if (*buff_index >= RX_BUF_SIZE) + break; + rx_buff[*buff_index] = readb(port->membase + + UART_RX_BYTE_FIFO); + *buff_index += UART_BYTE_SIZE; + *valid_byte_count -= UART_BYTE_SIZE; + } +} + +static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status) +{ + u32 valid_byte_count = uart_status & UART_BST_STAT_RX_COUNT_MASK; + struct tty_port *tty_port = &port->state->port; + unsigned char rx_buff[RX_BUF_SIZE]; + u32 buff_index = 0; + u32 copied_len; + + if (valid_byte_count != 0 && + valid_byte_count < RX_BUF_SIZE) { + pci1xxxx_process_read_data(port, rx_buff, &buff_index, + &valid_byte_count); + + copied_len = (u32)tty_insert_flip_string(tty_port, rx_buff, + buff_index); + + if (copied_len != buff_index) + port->icount.overrun += buff_index - copied_len; + + port->icount.rx += buff_index; + tty_flip_buffer_push(tty_port); + } +} + +static void pci1xxxx_process_write_data(struct uart_port *port, + int *data_empty_count, + u32 *valid_byte_count) +{ + struct tty_port *tport = &port->state->port; + u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE; + + /* + * Each transaction transfers data in DWORDs. If there are less than + * four remaining valid_byte_count to transfer or if the circular + * buffer has insufficient space for a DWORD, the data is transferred + * one byte at a time. + */ + while (valid_burst_count) { + u32 c; + + if (*data_empty_count - UART_BURST_SIZE < 0) + break; + if (kfifo_len(&tport->xmit_fifo) < UART_BURST_SIZE) + break; + if (WARN_ON(kfifo_out(&tport->xmit_fifo, (u8 *)&c, sizeof(c)) != + sizeof(c))) + break; + writel(c, port->membase + UART_TX_BURST_FIFO); + *valid_byte_count -= UART_BURST_SIZE; + *data_empty_count -= UART_BURST_SIZE; + valid_burst_count -= UART_BYTE_SIZE; + } + + while (*valid_byte_count) { + u8 c; + + if (!kfifo_get(&tport->xmit_fifo, &c)) + break; + writeb(c, port->membase + UART_TX_BYTE_FIFO); + *data_empty_count -= UART_BYTE_SIZE; + *valid_byte_count -= UART_BYTE_SIZE; + + /* + * If there are any pending burst count, data is handled by + * transmitting DWORDs at a time. + */ + if (valid_burst_count && + kfifo_len(&tport->xmit_fifo) >= UART_BURST_SIZE) + break; + } +} + +static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status) +{ + struct uart_8250_port *up = up_to_u8250p(port); + struct tty_port *tport = &port->state->port; + u32 valid_byte_count; + int data_empty_count; + + if (port->x_char) { + writeb(port->x_char, port->membase + UART_TX); + port->icount.tx++; + port->x_char = 0; + return; + } + + if ((uart_tx_stopped(port)) || kfifo_is_empty(&tport->xmit_fifo)) { + port->ops->stop_tx(port); + } else { + data_empty_count = (pci1xxxx_read_burst_status(port) & + UART_BST_STAT_TX_COUNT_MASK) >> 8; + do { + valid_byte_count = kfifo_len(&tport->xmit_fifo); + + pci1xxxx_process_write_data(port, + &data_empty_count, + &valid_byte_count); + + port->icount.tx++; + if (kfifo_is_empty(&tport->xmit_fifo)) + break; + } while (data_empty_count && valid_byte_count); + } + + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* + * With RPM enabled, we have to wait until the FIFO is empty before + * the HW can go idle. So we get here once again with empty FIFO and + * disable the interrupt and RPM in __stop_tx() + */ + if (kfifo_is_empty(&tport->xmit_fifo) && + !(up->capabilities & UART_CAP_RPM)) + port->ops->stop_tx(port); +} + +static int pci1xxxx_handle_irq(struct uart_port *port) +{ + unsigned long flags; + u32 status; + + status = pci1xxxx_read_burst_status(port); + + if (status & UART_BST_STAT_IIR_INT_PEND) + return 0; + + spin_lock_irqsave(&port->lock, flags); + + if (status & UART_BST_STAT_LSR_RX_MASK) + pci1xxxx_rx_burst(port, status); + + if (status & UART_BST_STAT_LSR_THRE) + pci1xxxx_tx_burst(port, status); + + spin_unlock_irqrestore(&port->lock, flags); + + return 1; +} + +static bool pci1xxxx_port_suspend(int line) +{ + struct uart_8250_port *up = serial8250_get_port(line); + struct uart_port *port = &up->port; + struct tty_port *tport = &port->state->port; + unsigned long flags; + bool ret = false; + u8 wakeup_mask; + + mutex_lock(&tport->mutex); + if (port->suspended == 0 && port->dev) { + wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG); + + uart_port_lock_irqsave(port, &flags); + port->mctrl &= ~TIOCM_OUT2; + port->ops->set_mctrl(port, port->mctrl); + uart_port_unlock_irqrestore(port, flags); + + ret = (wakeup_mask & UART_WAKE_SRCS) != UART_WAKE_SRCS; + } + + writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG); + mutex_unlock(&tport->mutex); + + return ret; +} + +static void pci1xxxx_port_resume(int line) +{ + struct uart_8250_port *up = serial8250_get_port(line); + struct uart_port *port = &up->port; + struct tty_port *tport = &port->state->port; + unsigned long flags; + + mutex_lock(&tport->mutex); + writeb(UART_BLOCK_SET_ACTIVE, port->membase + UART_ACTV_REG); + writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG); + + if (port->suspended == 0) { + uart_port_lock_irqsave(port, &flags); + port->mctrl |= TIOCM_OUT2; + port->ops->set_mctrl(port, port->mctrl); + uart_port_unlock_irqrestore(port, flags); + } + mutex_unlock(&tport->mutex); +} + +static int pci1xxxx_suspend(struct device *dev) +{ + struct pci1xxxx_8250 *priv = dev_get_drvdata(dev); + struct pci_dev *pcidev = to_pci_dev(dev); + bool wakeup = false; + unsigned int data; + void __iomem *p; + int i; + + for (i = 0; i < priv->nr; i++) { + if (priv->line[i] >= 0) { + serial8250_suspend_port(priv->line[i]); + wakeup |= pci1xxxx_port_suspend(priv->line[i]); + } + } + + p = pci_ioremap_bar(pcidev, 0); + if (!p) { + dev_err(dev, "remapping of bar 0 memory failed"); + return -ENOMEM; + } + + data = readl(p + UART_RESET_REG); + + if (priv->dev_rev >= 0xC0) + data |= UART_RESET_HOT_RESET_DISABLE; + + writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG); + + if (wakeup) + writeb(UART_PCI_CTRL_D3_CLK_ENABLE, p + UART_PCI_CTRL_REG); + + iounmap(p); + device_set_wakeup_enable(dev, true); + pci_wake_from_d3(pcidev, true); + + return 0; +} + +static int pci1xxxx_resume(struct device *dev) +{ + struct pci1xxxx_8250 *priv = dev_get_drvdata(dev); + struct pci_dev *pcidev = to_pci_dev(dev); + unsigned int data; + void __iomem *p; + int i; + + p = pci_ioremap_bar(pcidev, 0); + if (!p) { + dev_err(dev, "remapping of bar 0 memory failed"); + return -ENOMEM; + } + + data = readl(p + UART_RESET_REG); + + if (priv->dev_rev >= 0xC0) + data &= ~UART_RESET_HOT_RESET_DISABLE; + + writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG); + + iounmap(p); + + for (i = 0; i < priv->nr; i++) { + if (priv->line[i] >= 0) { + pci1xxxx_port_resume(priv->line[i]); + serial8250_resume_port(priv->line[i]); + } + } + + return 0; +} + +static int pci1xxxx_setup(struct pci_dev *pdev, + struct uart_8250_port *port, int port_idx, struct pci1xxxx_8250 *priv) +{ + int ret; + + port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST; + port->port.type = PORT_MCHP16550A; + /* + * 8250 core considers prescaller value to be always 16. + * The MCHP ports support downscaled mode and hence the + * functional UART clock can be lower, i.e. 62.5MHz, than + * software expects in order to support higher baud rates. + * Assign here 64MHz to support 4Mbps. + * + * The value itself is not really used anywhere except baud + * rate calculations, so we can mangle it as we wish. + */ + port->port.uartclk = 64 * HZ_PER_MHZ; + port->port.set_termios = serial8250_do_set_termios; + port->port.get_divisor = pci1xxxx_get_divisor; + port->port.set_divisor = pci1xxxx_set_divisor; + port->port.rs485_config = pci1xxxx_rs485_config; + port->port.rs485_supported = pci1xxxx_rs485_supported; + + /* + * C0 and later revisions support Burst operation. + * RTS workaround in mctrl is applicable only to B0. + */ + if (priv->dev_rev >= 0xC0) + port->port.handle_irq = pci1xxxx_handle_irq; + else if (priv->dev_rev == 0xB0) + port->port.set_mctrl = pci1xxxx_set_mctrl; + + ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0, priv->membase); + if (ret < 0) + return ret; + + writeb(UART_BLOCK_SET_ACTIVE, port->port.membase + UART_ACTV_REG); + writeb(UART_WAKE_SRCS, port->port.membase + UART_WAKE_REG); + writeb(UART_WAKE_N_PIN, port->port.membase + UART_WAKE_MASK_REG); + + return 0; +} + +static unsigned int pci1xxxx_get_max_port(int subsys_dev) +{ + unsigned int i = MAX_PORTS; + + if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx)) + while (i--) { + if (logical_to_physical_port_idx[subsys_dev][i] != -1) + return logical_to_physical_port_idx[subsys_dev][i] + 1; + } + + if (subsys_dev == PCI_SUBDEVICE_ID_EFAR_PCI11414) + return 4; + + return 1; +} + +static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port) +{ + if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx)) + return logical_to_physical_port_idx[subsys_dev][port]; + + return logical_to_physical_port_idx[0][port]; +} + +static int pci1xxxx_get_device_revision(struct pci1xxxx_8250 *priv) +{ + u32 regval; + int ret; + + /* + * DEV REV is a system register, HW Syslock bit + * should be acquired before accessing the register + */ + ret = pci1xxxx_acquire_sys_lock(priv); + if (ret) + return ret; + + regval = readl(priv->membase + UART_DEV_REV_REG); + priv->dev_rev = regval & UART_DEV_REV_MASK; + + pci1xxxx_release_sys_lock(priv); + + return 0; +} + +static int pci1xxxx_serial_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct pci1xxxx_8250 *priv; + struct uart_8250_port uart; + unsigned int max_vec_reqd; + unsigned int nr_ports, i; + int num_vectors; + int subsys_dev; + int port_idx; + int ret; + int rc; + + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + nr_ports = pci1xxxx_get_num_ports(pdev); + + priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->membase = pci_ioremap_bar(pdev, 0); + if (!priv->membase) + return -ENOMEM; + + ret = pci1xxxx_get_device_revision(priv); + if (ret) + return ret; + + pci_set_master(pdev); + + priv->nr = nr_ports; + + subsys_dev = pdev->subsystem_device; + max_vec_reqd = pci1xxxx_get_max_port(subsys_dev); + + num_vectors = pci_alloc_irq_vectors(pdev, 1, max_vec_reqd, PCI_IRQ_ALL_TYPES); + if (num_vectors < 0) { + pci_iounmap(pdev, priv->membase); + return num_vectors; + } + + memset(&uart, 0, sizeof(uart)); + uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; + uart.port.dev = dev; + + if (num_vectors == max_vec_reqd) + writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG); + + for (i = 0; i < nr_ports; i++) { + priv->line[i] = -ENODEV; + + port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i); + + if (num_vectors == max_vec_reqd) + uart.port.irq = pci_irq_vector(pdev, port_idx); + else + uart.port.irq = pci_irq_vector(pdev, 0); + + rc = pci1xxxx_setup(pdev, &uart, port_idx, priv); + if (rc) { + dev_warn(dev, "Failed to setup port %u\n", i); + continue; + } + + priv->line[i] = serial8250_register_8250_port(&uart); + if (priv->line[i] < 0) { + dev_warn(dev, + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", + uart.port.iobase, uart.port.irq, uart.port.iotype, + priv->line[i]); + } + } + + pci_set_drvdata(pdev, priv); + + return 0; +} + +static void pci1xxxx_serial_remove(struct pci_dev *dev) +{ + struct pci1xxxx_8250 *priv = pci_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < priv->nr; i++) { + if (priv->line[i] >= 0) + serial8250_unregister_port(priv->line[i]); + } + + pci_free_irq_vectors(dev); + pci_iounmap(dev, priv->membase); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_pm_ops, pci1xxxx_suspend, pci1xxxx_resume); + +static const struct pci_device_id pci1xxxx_pci_tbl[] = { + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11010) }, + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11101) }, + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11400) }, + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11414) }, + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI12000) }, + {} +}; +MODULE_DEVICE_TABLE(pci, pci1xxxx_pci_tbl); + +static struct pci_driver pci1xxxx_pci_driver = { + .name = "pci1xxxx serial", + .probe = pci1xxxx_serial_probe, + .remove = pci1xxxx_serial_remove, + .driver = { + .pm = pm_sleep_ptr(&pci1xxxx_pm_ops), + }, + .id_table = pci1xxxx_pci_tbl, +}; +module_pci_driver(pci1xxxx_pci_driver); + +static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1)); + +MODULE_IMPORT_NS("SERIAL_8250_PCI"); +MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module"); +MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>"); +MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c new file mode 100644 index 000000000000..9d5d2531a33b --- /dev/null +++ b/drivers/tty/serial/8250/8250_pcilib.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 8250 PCI library. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + */ +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/types.h> + +#include "8250.h" +#include "8250_pcilib.h" + +int serial_8250_warn_need_ioport(struct pci_dev *dev) +{ + dev_warn(&dev->dev, + "Serial port not supported because of missing I/O resource\n"); + + return -ENXIO; +} +EXPORT_SYMBOL_NS_GPL(serial_8250_warn_need_ioport, "SERIAL_8250_PCI"); + +int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, + u8 bar, unsigned int offset, int regshift, void __iomem *iomem) +{ + if (bar >= PCI_STD_NUM_BARS) + return -EINVAL; + + if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { + port->port.iotype = UPIO_MEM; + port->port.iobase = 0; + port->port.mapbase = pci_resource_start(dev, bar) + offset; + port->port.membase = iomem + offset; + port->port.regshift = regshift; + } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { + port->port.iotype = UPIO_PORT; + port->port.iobase = pci_resource_start(dev, bar) + offset; + port->port.mapbase = 0; + port->port.membase = NULL; + port->port.regshift = 0; + } else { + return serial_8250_warn_need_ioport(dev); + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, "SERIAL_8250_PCI"); +MODULE_DESCRIPTION("8250 PCI library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h new file mode 100644 index 000000000000..ab18de8d1355 --- /dev/null +++ b/drivers/tty/serial/8250/8250_pcilib.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 8250 PCI library header file. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + */ + +#include <linux/types.h> + +struct pci_dev; + +struct uart_8250_port; + +int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar, + unsigned int offset, int regshift, void __iomem *iomem); + +int serial_8250_warn_need_ioport(struct pci_dev *dev); diff --git a/drivers/tty/serial/8250/8250_pericom.c b/drivers/tty/serial/8250/8250_pericom.c new file mode 100644 index 000000000000..b8d5b7714a9d --- /dev/null +++ b/drivers/tty/serial/8250/8250_pericom.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Driver for Pericom UART */ + +#include <linux/bits.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/pci.h> + +#include "8250.h" + +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SDB 0x1051 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2S 0x1053 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_4 0x105a +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_4 0x105b +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SDB 0x105c +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4S 0x105e +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_8 0x106a +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_8 0x106b +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_2DB 0x1091 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_2 0x1093 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4 0x1098 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4DB 0x1099 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_4 0x109b +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_8 0x10a9 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SMDB 0x10d1 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2SM 0x10d3 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SM 0x10d9 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SMDB 0x10da +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4SM 0x10dc +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_8SM 0x10e9 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_1 0x1108 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_2 0x1110 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_2 0x1111 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_4 0x1118 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_4 0x1119 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2S 0x1152 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4S 0x115a +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_2 0x1190 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_2 0x1191 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_4 0x1198 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_4 0x1199 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2SM 0x11d0 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4SM 0x11d8 + +struct pericom8250 { + void __iomem *virt; + unsigned int nr; + int line[]; +}; + +static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + int scr; + + for (scr = 16; scr > 4; scr--) { + unsigned int maxrate = port->uartclk / scr; + unsigned int divisor = max(maxrate / baud, 1U); + int delta = maxrate / divisor - baud; + + if (baud > maxrate + baud / 50) + continue; + + if (delta > baud / 50) + divisor++; + + if (divisor > 0xffff) + continue; + + /* Update delta due to possible divisor change */ + delta = maxrate / divisor - baud; + if (abs(delta) < baud / 50) { + struct uart_8250_port *up = up_to_u8250p(port); + int lcr = serial_port_in(port, UART_LCR); + + serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); + serial_dl_write(up, divisor); + serial_port_out(port, 2, 16 - scr); + serial_port_out(port, UART_LCR, lcr); + return; + } + } +} + +static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + unsigned int nr, i, bar = 0, maxnr; + struct pericom8250 *pericom; + struct uart_8250_port uart; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + maxnr = pci_resource_len(pdev, bar) >> 3; + + if (pdev->vendor == PCI_VENDOR_ID_PERICOM) + nr = pdev->device & 0x0f; + else if (pdev->vendor == PCI_VENDOR_ID_ACCESSIO) + nr = BIT(((pdev->device & 0x38) >> 3) - 1); + else + nr = 1; + + pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, line, nr), GFP_KERNEL); + if (!pericom) + return -ENOMEM; + + pericom->virt = pcim_iomap(pdev, bar, 0); + if (!pericom->virt) + return -ENOMEM; + + memset(&uart, 0, sizeof(uart)); + + uart.port.dev = &pdev->dev; + uart.port.irq = pdev->irq; + uart.port.private_data = pericom; + uart.port.iotype = UPIO_PORT; + uart.port.uartclk = 921600 * 16; + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + uart.port.set_divisor = pericom_do_set_divisor; + for (i = 0; i < nr && i < maxnr; i++) { + unsigned int offset = (i == 3 && nr == 4) ? 0x38 : i * 0x8; + + uart.port.iobase = pci_resource_start(pdev, bar) + offset; + + dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + uart.port.iobase, uart.port.irq, uart.port.iotype); + + pericom->line[i] = serial8250_register_8250_port(&uart); + if (pericom->line[i] < 0) { + dev_err(&pdev->dev, + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", + uart.port.iobase, uart.port.irq, + uart.port.iotype, pericom->line[i]); + break; + } + } + pericom->nr = i; + + pci_set_drvdata(pdev, pericom); + return 0; +} + +static void pericom8250_remove(struct pci_dev *pdev) +{ + struct pericom8250 *pericom = pci_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < pericom->nr; i++) + serial8250_unregister_port(pericom->line[i]); +} + +static const struct pci_device_id pericom8250_pci_ids[] = { + /* + * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART + * (Only 7954 has an offset jump for port 4) + */ + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951) }, + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952) }, + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954) }, + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958) }, + + /* + * ACCES I/O Products quad + * (Only 7954 has an offset jump for port 4) + */ + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_8) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_8) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_2DB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4DB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_8) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SMDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SMDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_8SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_1) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4SM) }, + { } +}; +MODULE_DEVICE_TABLE(pci, pericom8250_pci_ids); + +static struct pci_driver pericom8250_pci_driver = { + .name = "8250_pericom", + .id_table = pericom8250_pci_ids, + .probe = pericom8250_probe, + .remove = pericom8250_remove, +}; +module_pci_driver(pericom8250_pci_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Pericom UART driver"); diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c new file mode 100644 index 000000000000..86d12d2b5907 --- /dev/null +++ b/drivers/tty/serial/8250/8250_platform.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Universal/legacy platform driver for 8250/16550-type serial ports + * + * Supports: + * ISA-compatible 8250/16550 ports + * ACPI 8250/16550 ports + * PNP 8250/16550 ports + * "serial8250" platform devices + */ +#include <linux/acpi.h> +#include <linux/array_size.h> +#include <linux/cleanup.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/once.h> +#include <linux/platform_device.h> + +#include <linux/serial_8250.h> + +#ifdef CONFIG_SPARC +#include <linux/sunserialcore.h> +#endif + +#include "8250.h" + +/* + * Configuration: + * share_irqs: Whether we pass IRQF_SHARED to request_irq(). + * This option is unsafe when used on edge-triggered interrupts. + */ +static bool share_irqs = IS_ENABLED(CONFIG_SERIAL_8250_SHARE_IRQ); + +unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; + +#include <asm/serial.h> + +/* + * SERIAL_PORT_DFNS tells us about built-in ports that have no + * standard enumeration mechanism. Platforms that can find all + * serial ports via mechanisms like ACPI or PCI need not supply it. + */ +#ifndef SERIAL_PORT_DFNS +#define SERIAL_PORT_DFNS +#endif + +static const struct old_serial_port old_serial_port[] = { + SERIAL_PORT_DFNS /* defined in asm/serial.h */ +}; + +serial8250_isa_config_fn serial8250_isa_config; +void serial8250_set_isa_configurator(serial8250_isa_config_fn v) +{ + serial8250_isa_config = v; +} +EXPORT_SYMBOL(serial8250_set_isa_configurator); + +static void __init __serial8250_isa_init_ports(void) +{ + int i; + + if (nr_uarts > UART_NR) + nr_uarts = UART_NR; + + /* + * Set up initial ISA ports based on nr_uart module param, or else + * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not + * need to increase nr_uarts when setting up the initial ISA ports. + */ + for (i = 0; i < nr_uarts; i++) + serial8250_setup_port(i); + + /* chain base port ops to support Remote Supervisor Adapter */ + univ8250_port_ops = *univ8250_port_base_ops; + univ8250_rsa_support(&univ8250_port_ops, univ8250_port_base_ops); + + for (i = 0; i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++) { + struct uart_8250_port *up = serial8250_get_port(i); + struct uart_port *port = &up->port; + + port->iobase = old_serial_port[i].port; + port->irq = irq_canonicalize(old_serial_port[i].irq); + port->irqflags = 0; + port->uartclk = old_serial_port[i].baud_base * 16; + port->flags = old_serial_port[i].flags; + port->hub6 = 0; + port->membase = old_serial_port[i].iomem_base; + port->iotype = old_serial_port[i].io_type; + port->regshift = old_serial_port[i].iomem_reg_shift; + + if (share_irqs) + port->irqflags |= IRQF_SHARED; + + if (serial8250_isa_config != NULL) + serial8250_isa_config(i, &up->port, &up->capabilities); + } +} + +void __init serial8250_isa_init_ports(void) +{ + DO_ONCE(__serial8250_isa_init_ports); +} + +/* + * Generic 16550A platform devices + */ +static int serial8250_probe_acpi(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *regs; + int ret, line; + + struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + regs = platform_get_mem_or_io(pdev, 0); + if (!regs) + return dev_err_probe(dev, -EINVAL, "no registers defined\n"); + + switch (resource_type(regs)) { + case IORESOURCE_IO: + uart->port.iobase = regs->start; + break; + case IORESOURCE_MEM: + uart->port.mapbase = regs->start; + uart->port.mapsize = resource_size(regs); + uart->port.flags = UPF_IOREMAP; + break; + default: + return -EINVAL; + } + + /* default clock frequency */ + uart->port.uartclk = 1843200; + uart->port.type = PORT_16550A; + uart->port.dev = &pdev->dev; + uart->port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + + ret = uart_read_and_validate_port_properties(&uart->port); + /* no interrupt -> fall back to polling */ + if (ret == -ENXIO) + ret = 0; + if (ret) + return ret; + + line = serial8250_register_8250_port(uart); + if (line < 0) + return line; + + return 0; +} + +static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p) +{ + int ret, i; + + struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + for (i = 0; p && p->flags != 0; p++, i++) { + uart->port.iobase = p->iobase; + uart->port.membase = p->membase; + uart->port.irq = p->irq; + uart->port.irqflags = p->irqflags; + uart->port.uartclk = p->uartclk; + uart->port.regshift = p->regshift; + uart->port.iotype = p->iotype; + uart->port.flags = p->flags; + uart->port.mapbase = p->mapbase; + uart->port.mapsize = p->mapsize; + uart->port.hub6 = p->hub6; + uart->port.has_sysrq = p->has_sysrq; + uart->port.private_data = p->private_data; + uart->port.type = p->type; + uart->bugs = p->bugs; + uart->port.serial_in = p->serial_in; + uart->port.serial_out = p->serial_out; + uart->dl_read = p->dl_read; + uart->dl_write = p->dl_write; + uart->port.handle_irq = p->handle_irq; + uart->port.handle_break = p->handle_break; + uart->port.set_termios = p->set_termios; + uart->port.set_ldisc = p->set_ldisc; + uart->port.get_mctrl = p->get_mctrl; + uart->port.pm = p->pm; + uart->port.dev = &dev->dev; + + if (share_irqs) + uart->port.irqflags |= IRQF_SHARED; + + ret = serial8250_register_8250_port(uart); + if (ret < 0) { + dev_err(&dev->dev, "unable to register port at index %d " + "(IO%lx MEM%llx IRQ%d): %d\n", i, + p->iobase, (unsigned long long)p->mapbase, + p->irq, ret); + } + } + return 0; +} + +/* + * Register a set of serial devices attached to a platform device. + * The list is terminated with a zero flags entry, which means we expect + * all entries to have at least UPF_BOOT_AUTOCONF set. + */ +static int serial8250_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct plat_serial8250_port *p; + + p = dev_get_platdata(dev); + if (p) + return serial8250_probe_platform(pdev, p); + + /* + * Probe platform UART devices defined using standard hardware + * discovery mechanism like ACPI or DT. Support only ACPI based + * serial device for now. + */ + if (has_acpi_companion(dev)) + return serial8250_probe_acpi(pdev); + + return 0; +} + +/* + * Remove serial ports registered against a platform device. + */ +static void serial8250_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = serial8250_get_port(i); + + if (up->port.dev == &dev->dev) + serial8250_unregister_port(i); + } +} + +static int serial8250_suspend(struct platform_device *dev, pm_message_t state) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_8250_port *up = serial8250_get_port(i); + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_suspend_port(&serial8250_reg, &up->port); + } + + return 0; +} + +static int serial8250_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_8250_port *up = serial8250_get_port(i); + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + serial8250_resume_port(i); + } + + return 0; +} + +static const struct acpi_device_id acpi_platform_serial_table[] = { + { "RSCV0003" }, /* RISC-V Generic 16550A UART */ + { } +}; +MODULE_DEVICE_TABLE(acpi, acpi_platform_serial_table); + +static struct platform_driver serial8250_isa_driver = { + .probe = serial8250_probe, + .remove = serial8250_remove, + .suspend = serial8250_suspend, + .resume = serial8250_resume, + .driver = { + .name = "serial8250", + .acpi_match_table = acpi_platform_serial_table, + }, +}; + +/* + * This "device" covers _all_ ISA 8250-compatible serial devices listed + * in the table in include/asm/serial.h. + */ +struct platform_device *serial8250_isa_devs; + +static int __init serial8250_init(void) +{ + int ret; + + if (nr_uarts == 0) + return -ENODEV; + + serial8250_isa_init_ports(); + + pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n", + nr_uarts, str_enabled_disabled(share_irqs)); + +#ifdef CONFIG_SPARC + ret = sunserial_register_minors(&serial8250_reg, UART_NR); +#else + serial8250_reg.nr = UART_NR; + ret = uart_register_driver(&serial8250_reg); +#endif + if (ret) + goto out; + + ret = serial8250_pnp_init(); + if (ret) + goto unreg_uart_drv; + + serial8250_isa_devs = platform_device_alloc("serial8250", PLAT8250_DEV_LEGACY); + if (!serial8250_isa_devs) { + ret = -ENOMEM; + goto unreg_pnp; + } + + ret = platform_device_add(serial8250_isa_devs); + if (ret) + goto put_dev; + + serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); + + ret = platform_driver_register(&serial8250_isa_driver); + if (ret == 0) + goto out; + + platform_device_del(serial8250_isa_devs); +put_dev: + platform_device_put(serial8250_isa_devs); +unreg_pnp: + serial8250_pnp_exit(); +unreg_uart_drv: +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else + uart_unregister_driver(&serial8250_reg); +#endif +out: + return ret; +} +module_init(serial8250_init); + +static void __exit serial8250_exit(void) +{ + struct platform_device *isa_dev = serial8250_isa_devs; + + /* + * This tells serial8250_unregister_port() not to re-register + * the ports (thereby making serial8250_isa_driver permanently + * in use). + */ + serial8250_isa_devs = NULL; + + platform_driver_unregister(&serial8250_isa_driver); + platform_device_unregister(isa_dev); + + serial8250_pnp_exit(); + +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else + uart_unregister_driver(&serial8250_reg); +#endif +} +module_exit(serial8250_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 serial platform driver"); + +module_param_hw(share_irqs, bool, other, 0644); +MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)"); + +module_param(nr_uarts, uint, 0644); +MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); + +MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index de90d681b64c..7a837fdf9df1 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -10,9 +10,11 @@ */ #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm.h> #include <linux/pnp.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/property.h> #include <linux/serial_core.h> #include <linux/bitops.h> @@ -55,10 +57,6 @@ static const struct pnp_device_id pnp_dev_table[] = { { "BRI1400", 0 }, /* Boca 33.6 Kbps Internal FD34FSVD */ { "BRI3400", 0 }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { "BRI0A49", 0 }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { "BDP3336", 0 }, /* Computer Peripherals Inc */ /* EuroViVa CommCenter-33.6 SP PnP */ { "CPI4050", 0 }, @@ -437,7 +435,8 @@ static int serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct uart_8250_port uart, *port; - int ret, line, flags = dev_id->driver_data; + int ret, flags = dev_id->driver_data; + long line; if (flags & UNKNOWN_DEV) { ret = serial_pnp_guess_board(dev); @@ -446,36 +445,37 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) } memset(&uart, 0, sizeof(uart)); - if (pnp_irq_valid(dev, 0)) - uart.port.irq = pnp_irq(dev, 0); if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) { uart.port.iobase = pnp_port_start(dev, 2); - uart.port.iotype = UPIO_PORT; } else if (pnp_port_valid(dev, 0)) { uart.port.iobase = pnp_port_start(dev, 0); - uart.port.iotype = UPIO_PORT; } else if (pnp_mem_valid(dev, 0)) { uart.port.mapbase = pnp_mem_start(dev, 0); - uart.port.iotype = UPIO_MEM; + uart.port.mapsize = pnp_mem_len(dev, 0); uart.port.flags = UPF_IOREMAP; } else return -ENODEV; - dev_dbg(&dev->dev, - "Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n", - uart.port.iobase, (unsigned long long)uart.port.mapbase, - uart.port.irq, uart.port.iotype); + uart.port.uartclk = 1843200; + uart.port.dev = &dev->dev; + uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + + ret = uart_read_port_properties(&uart.port); + /* no interrupt -> fall back to polling */ + if (ret == -ENXIO) + ret = 0; + if (ret) + return ret; if (flags & CIR_PORT) { uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; uart.port.type = PORT_8250_CIR; } - uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) - uart.port.flags |= UPF_SHARE_IRQ; - uart.port.uartclk = 1843200; - uart.port.dev = &dev->dev; + dev_dbg(&dev->dev, + "Setup PNP port: port %#lx, mem %#llx, size %#llx, irq %u, type %u\n", + uart.port.iobase, (unsigned long long)uart.port.mapbase, + (unsigned long long)uart.port.mapsize, uart.port.irq, uart.port.iotype); line = serial8250_register_8250_port(&uart); if (line < 0 || (flags & CIR_PORT)) @@ -485,7 +485,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) if (uart_console(&port->port)) dev->capabilities |= PNP_CONSOLE; - pnp_set_drvdata(dev, (void *)((long)line + 1)); + pnp_set_drvdata(dev, (void *)line); return 0; } @@ -494,38 +494,33 @@ static void serial_pnp_remove(struct pnp_dev *dev) long line = (long)pnp_get_drvdata(dev); dev->capabilities &= ~PNP_CONSOLE; - if (line) - serial8250_unregister_port(line - 1); + serial8250_unregister_port(line); } -static int __maybe_unused serial_pnp_suspend(struct device *dev) +static int serial_pnp_suspend(struct device *dev) { long line = (long)dev_get_drvdata(dev); - if (!line) - return -ENODEV; - serial8250_suspend_port(line - 1); + serial8250_suspend_port(line); return 0; } -static int __maybe_unused serial_pnp_resume(struct device *dev) +static int serial_pnp_resume(struct device *dev) { long line = (long)dev_get_drvdata(dev); - if (!line) - return -ENODEV; - serial8250_resume_port(line - 1); + serial8250_resume_port(line); return 0; } -static SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume); static struct pnp_driver serial_pnp_driver = { .name = "serial", .probe = serial_pnp_probe, .remove = serial_pnp_remove, .driver = { - .pm = &serial_pnp_pm_ops, + .pm = pm_sleep_ptr(&serial_pnp_pm_ops), }, .id_table = pnp_dev_table, }; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1632f7d25acc..719faf92aa8a 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -15,7 +15,9 @@ #include <linux/moduleparam.h> #include <linux/ioport.h> #include <linux/init.h> +#include <linux/irq.h> #include <linux/console.h> +#include <linux/gpio/consumer.h> #include <linux/sysrq.h> #include <linux/delay.h> #include <linux/platform_device.h> @@ -36,21 +38,6 @@ #include "8250.h" -/* Nuvoton NPCM timeout register */ -#define UART_NPCM_TOR 7 -#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ - -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Here we define the default xmit fifo size used for each type of UART. */ @@ -121,7 +108,8 @@ static const struct serial8250_config uart_config[] = { .name = "16C950/954", .fifo_size = 128, .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01, + .rxtrig_bytes = {16, 32, 112, 120}, /* UART_CAP_EFR breaks billionon CF bluetooth card. */ .flags = UART_CAP_FIFO | UART_CAP_SLEEP, }, @@ -169,13 +157,6 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, - [PORT_AR7] = { - .name = "AR7", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO /* | UART_CAP_AFE */, - }, [PORT_U6_16550A] = { .name = "U6_16550A", .fifo_size = 64, @@ -261,7 +242,7 @@ static const struct serial8250_config uart_config[] = { .tx_loadsz = 63, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR7_64BYTE, - .flags = UART_CAP_FIFO, + .flags = UART_CAP_FIFO | UART_CAP_NOTEMT, }, [PORT_RT2880] = { .name = "Palmchip BK-3103", @@ -305,152 +286,134 @@ static const struct serial8250_config uart_config[] = { .rxtrig_bytes = {1, 32, 64, 112}, .flags = UART_CAP_FIFO | UART_CAP_SLEEP, }, + [PORT_ASPEED_VUART] = { + .name = "ASPEED VUART", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO, + }, + [PORT_MCHP16550A] = { + .name = "MCHP16550A", + .fifo_size = 256, + .tx_loadsz = 256, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01, + .rxtrig_bytes = {2, 66, 130, 194}, + .flags = UART_CAP_FIFO, + }, + [PORT_BCM7271] = { + .name = "Broadcom BCM7271 UART", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01, + .rxtrig_bytes = {1, 8, 16, 30}, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, }; /* Uart divisor latch read */ -static int default_serial_dl_read(struct uart_8250_port *up) +static u32 default_serial_dl_read(struct uart_8250_port *up) { - return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; + /* Assign these in pieces to truncate any bits above 7. */ + unsigned char dll = serial_in(up, UART_DLL); + unsigned char dlm = serial_in(up, UART_DLM); + + return dll | dlm << 8; } /* Uart divisor latch write */ -static void default_serial_dl_write(struct uart_8250_port *up, int value) +static void default_serial_dl_write(struct uart_8250_port *up, u32 value) { serial_out(up, UART_DLL, value & 0xff); serial_out(up, UART_DLM, value >> 8 & 0xff); } -#ifdef CONFIG_SERIAL_8250_RT288X - -/* Au1x00/RT288x UART hardware has a weird register layout */ -static const s8 au_io_in_map[8] = { - 0, /* UART_RX */ - 2, /* UART_IER */ - 3, /* UART_IIR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - 7, /* UART_LSR */ - 8, /* UART_MSR */ - -1, /* UART_SCR (unmapped) */ -}; - -static const s8 au_io_out_map[8] = { - 1, /* UART_TX */ - 2, /* UART_IER */ - 4, /* UART_FCR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - -1, /* UART_LSR (unmapped) */ - -1, /* UART_MSR (unmapped) */ - -1, /* UART_SCR (unmapped) */ -}; - -unsigned int au_serial_in(struct uart_port *p, int offset) -{ - if (offset >= ARRAY_SIZE(au_io_in_map)) - return UINT_MAX; - offset = au_io_in_map[offset]; - if (offset < 0) - return UINT_MAX; - return __raw_readl(p->membase + (offset << p->regshift)); -} - -void au_serial_out(struct uart_port *p, int offset, int value) -{ - if (offset >= ARRAY_SIZE(au_io_out_map)) - return; - offset = au_io_out_map[offset]; - if (offset < 0) - return; - __raw_writel(value, p->membase + (offset << p->regshift)); -} - -/* Au1x00 haven't got a standard divisor latch */ -static int au_serial_dl_read(struct uart_8250_port *up) -{ - return __raw_readl(up->port.membase + 0x28); -} - -static void au_serial_dl_write(struct uart_8250_port *up, int value) -{ - __raw_writel(value, up->port.membase + 0x28); -} - -#endif - -static unsigned int hub6_serial_in(struct uart_port *p, int offset) +#ifdef CONFIG_HAS_IOPORT +static u32 hub6_serial_in(struct uart_port *p, unsigned int offset) { offset = offset << p->regshift; outb(p->hub6 - 1 + offset, p->iobase); return inb(p->iobase + 1); } -static void hub6_serial_out(struct uart_port *p, int offset, int value) +static void hub6_serial_out(struct uart_port *p, unsigned int offset, u32 value) { offset = offset << p->regshift; outb(p->hub6 - 1 + offset, p->iobase); outb(value, p->iobase + 1); } +#endif /* CONFIG_HAS_IOPORT */ -static unsigned int mem_serial_in(struct uart_port *p, int offset) +static u32 mem_serial_in(struct uart_port *p, unsigned int offset) { offset = offset << p->regshift; return readb(p->membase + offset); } -static void mem_serial_out(struct uart_port *p, int offset, int value) +static void mem_serial_out(struct uart_port *p, unsigned int offset, u32 value) { offset = offset << p->regshift; writeb(value, p->membase + offset); } -static void mem16_serial_out(struct uart_port *p, int offset, int value) +static void mem16_serial_out(struct uart_port *p, unsigned int offset, u32 value) { offset = offset << p->regshift; writew(value, p->membase + offset); } -static unsigned int mem16_serial_in(struct uart_port *p, int offset) +static u32 mem16_serial_in(struct uart_port *p, unsigned int offset) { offset = offset << p->regshift; return readw(p->membase + offset); } -static void mem32_serial_out(struct uart_port *p, int offset, int value) +static void mem32_serial_out(struct uart_port *p, unsigned int offset, u32 value) { offset = offset << p->regshift; writel(value, p->membase + offset); } -static unsigned int mem32_serial_in(struct uart_port *p, int offset) +static u32 mem32_serial_in(struct uart_port *p, unsigned int offset) { offset = offset << p->regshift; return readl(p->membase + offset); } -static void mem32be_serial_out(struct uart_port *p, int offset, int value) +static void mem32be_serial_out(struct uart_port *p, unsigned int offset, u32 value) { offset = offset << p->regshift; iowrite32be(value, p->membase + offset); } -static unsigned int mem32be_serial_in(struct uart_port *p, int offset) +static u32 mem32be_serial_in(struct uart_port *p, unsigned int offset) { offset = offset << p->regshift; return ioread32be(p->membase + offset); } -static unsigned int io_serial_in(struct uart_port *p, int offset) +#ifdef CONFIG_HAS_IOPORT +static u32 io_serial_in(struct uart_port *p, unsigned int offset) { offset = offset << p->regshift; return inb(p->iobase + offset); } -static void io_serial_out(struct uart_port *p, int offset, int value) +static void io_serial_out(struct uart_port *p, unsigned int offset, u32 value) { offset = offset << p->regshift; outb(value, p->iobase + offset); } +#endif +static u32 no_serial_in(struct uart_port *p, unsigned int offset) +{ + return ~0U; +} + +static void no_serial_out(struct uart_port *p, unsigned int offset, u32 value) +{ +} static int serial8250_default_handle_irq(struct uart_port *port); @@ -462,10 +425,12 @@ static void set_io_from_upio(struct uart_port *p) up->dl_write = default_serial_dl_write; switch (p->iotype) { +#ifdef CONFIG_HAS_IOPORT case UPIO_HUB6: p->serial_in = hub6_serial_in; p->serial_out = hub6_serial_out; break; +#endif case UPIO_MEM: p->serial_in = mem_serial_in; @@ -486,20 +451,17 @@ static void set_io_from_upio(struct uart_port *p) p->serial_in = mem32be_serial_in; p->serial_out = mem32be_serial_out; break; - -#ifdef CONFIG_SERIAL_8250_RT288X - case UPIO_AU: - p->serial_in = au_serial_in; - p->serial_out = au_serial_out; - up->dl_read = au_serial_dl_read; - up->dl_write = au_serial_dl_write; - break; -#endif - - default: +#ifdef CONFIG_HAS_IOPORT + case UPIO_PORT: p->serial_in = io_serial_in; p->serial_out = io_serial_out; break; +#endif + default: + WARN(p->iotype != UPIO_PORT || p->iobase, + "Unsupported UART type %x\n", p->iotype); + p->serial_in = no_serial_in; + p->serial_out = no_serial_out; } /* Remember loaded iotype */ up->cur_iotype = p->iotype; @@ -524,27 +486,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) } /* - * For the 16C950 - */ -static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); -} - -static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) -{ - unsigned int value; - - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); - - return value; -} - -/* * FIFO support. */ static void serial8250_clear_fifos(struct uart_8250_port *p) @@ -606,24 +547,27 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put); */ static int serial8250_em485_init(struct uart_8250_port *p) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); + if (p->em485) - return 0; + goto deassert_rts; p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); if (!p->em485) return -ENOMEM; - hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx; - p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx; + hrtimer_setup(&p->em485->stop_tx_timer, &serial8250_em485_handle_stop_tx, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hrtimer_setup(&p->em485->start_tx_timer, &serial8250_em485_handle_start_tx, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); p->em485->port = p; p->em485->active_timer = NULL; p->em485->tx_stopped = true; - p->rs485_stop_tx(p); +deassert_rts: + if (p->em485->tx_stopped) + p->rs485_stop_tx(p, true); return 0; } @@ -654,49 +598,35 @@ void serial8250_em485_destroy(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_em485_destroy); +struct serial_rs485 serial8250_em485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_TERMINATE_BUS | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; +EXPORT_SYMBOL_GPL(serial8250_em485_supported); + /** * serial8250_em485_config() - generic ->rs485_config() callback * @port: uart port + * @termios: termios structure * @rs485: rs485 settings * * Generic callback usable by 8250 uart drivers to activate rs485 settings * if the uart is incapable of driving RTS as a Transmit Enable signal in * hardware, relying on software emulation instead. */ -int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) +int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { struct uart_8250_port *up = up_to_u8250p(port); - /* pick sane settings if the user hasn't */ - if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) == - !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { - rs485->flags |= SER_RS485_RTS_ON_SEND; - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - } - - /* clamp the delays to [0, 100ms] */ - rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); - rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); - - memset(rs485->padding, 0, sizeof(rs485->padding)); - port->rs485 = *rs485; - - gpiod_set_value(port->rs485_term_gpio, - rs485->flags & SER_RS485_TERMINATE_BUS); - /* * Both serial8250_em485_init() and serial8250_em485_destroy() * are idempotent. */ - if (rs485->flags & SER_RS485_ENABLED) { - int ret = serial8250_em485_init(up); - - if (ret) { - rs485->flags &= ~SER_RS485_ENABLED; - port->rs485.flags &= ~SER_RS485_ENABLED; - } - return ret; - } + if (rs485->flags & SER_RS485_ENABLED) + return serial8250_em485_init(up); serial8250_em485_destroy(up); return 0; @@ -708,7 +638,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config); * once and disable_runtime_pm_tx() will still disable RPM because the fifo is * empty and the HW can idle again. */ -void serial8250_rpm_get_tx(struct uart_8250_port *p) +static void serial8250_rpm_get_tx(struct uart_8250_port *p) { unsigned char rpm_active; @@ -720,9 +650,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p) return; pm_runtime_get_sync(p->port.dev); } -EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx); -void serial8250_rpm_put_tx(struct uart_8250_port *p) +static void serial8250_rpm_put_tx(struct uart_8250_port *p) { unsigned char rpm_active; @@ -735,7 +664,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p) pm_runtime_mark_last_busy(p->port.dev); pm_runtime_put_autosuspend(p->port.dev); } -EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx); /* * IER sleep support. UARTs which have EFRs need the "extended @@ -746,95 +674,45 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { unsigned char lcr = 0, efr = 0; - serial8250_rpm_get(p); - - if (p->capabilities & UART_CAP_SLEEP) { - if (p->capabilities & UART_CAP_EFR) { - lcr = serial_in(p, UART_LCR); - efr = serial_in(p, UART_EFR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, UART_EFR_ECB); - serial_out(p, UART_LCR, 0); - } - serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); - if (p->capabilities & UART_CAP_EFR) { - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, efr); - serial_out(p, UART_LCR, lcr); - } - } - - serial8250_rpm_put(p); -} + guard(serial8250_rpm)(p); -#ifdef CONFIG_SERIAL_8250_RSA -/* - * Attempts to turn on the RSA FIFO. Returns zero on failure. - * We set the port uart clock rate if we succeed. - */ -static int __enable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; + if (!(p->capabilities & UART_CAP_SLEEP)) + return; - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; + /* Synchronize UART_IER access against the console. */ + guard(uart_port_lock_irq)(&p->port); - if (!result) { - serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; + if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } + serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; - - return result; } -static void enable_rsa(struct uart_8250_port *up) +/* Clear the interrupt registers. */ +static void serial8250_clear_interrupts(struct uart_port *port) { - if (up->port.type == PORT_RSA) { - if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - __enable_rsa(up); - spin_unlock_irq(&up->port.lock); - } - if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_out(up, UART_RSA_FRR, 0); - } + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); } -/* - * Attempts to turn off the RSA FIFO. Returns zero on failure. - * It is unknown why interrupts were disabled in here. However, - * the caller is expected to preserve this behaviour by grabbing - * the spinlock before calling this function. - */ -static void disable_rsa(struct uart_8250_port *up) +static void serial8250_clear_IER(struct uart_8250_port *up) { - unsigned char mode; - int result; - - if (up->port.type == PORT_RSA && - up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); - } + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); } -#endif /* CONFIG_SERIAL_8250_RSA */ /* * This is a quickie test to see how big the FIFO is. @@ -843,7 +721,7 @@ static void disable_rsa(struct uart_8250_port *up) static int size_fifo(struct uart_8250_port *up) { unsigned char old_fcr, old_mcr, old_lcr; - unsigned short old_dl; + u32 old_dl; int count; old_lcr = serial_in(up, UART_LCR); @@ -856,7 +734,7 @@ static int size_fifo(struct uart_8250_port *up) serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); old_dl = serial_dl_read(up); serial_dl_write(up, 0x0001); - serial_out(up, UART_LCR, 0x03); + serial_out(up, UART_LCR, UART_LCR_WLEN8); for (count = 0; count < 256; count++) serial_out(up, UART_TX, count); mdelay(20);/* FIXME - schedule_timeout */ @@ -939,8 +817,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up) id3 = serial_icr_read(up, UART_ID3); rev = serial_icr_read(up, UART_REV); - DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); - if (id1 == 0x16 && id2 == 0xC9 && (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { up->port.type = PORT_16C950; @@ -964,7 +840,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up) * 0x14 - XR16C854. */ id1 = autoconfig_read_divisor_id(up); - DEBUG_AUTOCONF("850id=%04x ", id1); id2 = id1 >> 8; if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { @@ -1033,10 +908,14 @@ static void autoconfig_16550a(struct uart_8250_port *up) unsigned char status1, status2; unsigned int iersave; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + up->port.type = PORT_16550A; up->capabilities |= UART_CAP_FIFO; - if (!IS_ENABLED(CONFIG_SERIAL_8250_16550A_VARIANTS)) + if (!IS_ENABLED(CONFIG_SERIAL_8250_16550A_VARIANTS) && + !(up->port.flags & UPF_FULL_PROBE)) return; /* @@ -1047,21 +926,18 @@ static void autoconfig_16550a(struct uart_8250_port *up) if (serial_in(up, UART_EFR) == 0) { serial_out(up, UART_EFR, 0xA8); if (serial_in(up, UART_EFR) != 0) { - DEBUG_AUTOCONF("EFRv1 "); up->port.type = PORT_16650; up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; } else { serial_out(up, UART_LCR, 0); serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; + status1 = serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED_16750; serial_out(up, UART_FCR, 0); serial_out(up, UART_LCR, 0); - if (status1 == 7) + if (status1 == UART_IIR_FIFO_ENABLED_16750) up->port.type = PORT_16550A_FSL64; - else - DEBUG_AUTOCONF("Motorola 8xxx DUART "); } serial_out(up, UART_EFR, 0); return; @@ -1073,7 +949,6 @@ static void autoconfig_16550a(struct uart_8250_port *up) */ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { - DEBUG_AUTOCONF("EFRv2 "); autoconfig_has_efr(up); return; } @@ -1126,17 +1001,18 @@ static void autoconfig_16550a(struct uart_8250_port *up) */ serial_out(up, UART_LCR, 0); serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; + status1 = serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED_16750; serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status2 = serial_in(up, UART_IIR) >> 5; + status2 = serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED_16750; serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, 0); - DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + serial_out(up, UART_LCR, 0); - if (status1 == 6 && status2 == 7) { + if (status1 == UART_IIR_FIFO_ENABLED_16550A && + status2 == UART_IIR_FIFO_ENABLED_16750) { up->port.type = PORT_16750; up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; return; @@ -1148,7 +1024,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) * internal UARTs. * We're going to explicitly set the UUE bit to 0 before * trying to write and read a 1 just to make sure it's not - * already a 1 and maybe locked there before we even start start. + * already a 1 and maybe locked there before we even start. */ iersave = serial_in(up, UART_IER); serial_out(up, UART_IER, iersave & ~UART_IER_UUE); @@ -1163,17 +1039,10 @@ static void autoconfig_16550a(struct uart_8250_port *up) * It's an Xscale. * We'll leave the UART_IER_UUE bit set to 1 (enabled). */ - DEBUG_AUTOCONF("Xscale "); up->port.type = PORT_XSCALE; up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; return; } - } else { - /* - * If we got here we couldn't force the IER_UUE bit to 0. - * Log it and continue. - */ - DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); } serial_out(up, UART_IER, iersave); @@ -1205,14 +1074,13 @@ static void autoconfig(struct uart_8250_port *up) if (!port->iobase && !port->mapbase && !port->membase) return; - DEBUG_AUTOCONF("%s: autoconf (0x%04lx, 0x%p): ", - port->name, port->iobase, port->membase); - /* * We really do need global IRQs disabled here - we're going to * be frobbing the chips IRQ enable register to see if it exists. + * + * Synchronize UART_IER access against the console. */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); up->capabilities = 0; up->bugs = 0; @@ -1233,28 +1101,26 @@ static void autoconfig(struct uart_8250_port *up) */ scratch = serial_in(up, UART_IER); serial_out(up, UART_IER, 0); -#ifdef __i386__ +#if defined(__i386__) && defined(CONFIG_HAS_IOPORT) outb(0xff, 0x080); #endif /* * Mask out IER[7:4] bits for test as some UARTs (e.g. TL * 16C754B) allow only to modify them if an EFR bit is set. */ - scratch2 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, 0x0F); -#ifdef __i386__ + scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR; + serial_out(up, UART_IER, UART_IER_ALL_INTR); +#if defined(__i386__) && defined(CONFIG_HAS_IOPORT) outb(0, 0x080); #endif - scratch3 = serial_in(up, UART_IER) & 0x0f; + scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR; serial_out(up, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) { + if (scratch2 != 0 || scratch3 != UART_IER_ALL_INTR) { /* * We failed; there's nothing here */ - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", - scratch2, scratch3); - goto out; + uart_port_unlock_irqrestore(port, flags); + return; } } @@ -1271,14 +1137,12 @@ static void autoconfig(struct uart_8250_port *up) * that conflicts with COM 1-4 --- we hope! */ if (!(port->flags & UPF_SKIP_TEST)) { - serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A); - status1 = serial_in(up, UART_MSR) & 0xF0; + serial8250_out_MCR(up, UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS); + status1 = serial_in(up, UART_MSR) & UART_MSR_STATUS_BITS; serial8250_out_MCR(up, save_mcr); - if (status1 != 0x90) { - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("LOOP test failed (%02x) ", - status1); - goto out; + if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) { + uart_port_unlock_irqrestore(port, flags); + return; } } @@ -1296,31 +1160,23 @@ static void autoconfig(struct uart_8250_port *up) serial_out(up, UART_LCR, 0); serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(up, UART_IIR) >> 6; - switch (scratch) { - case 0: + switch (serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED) { + case UART_IIR_FIFO_ENABLED_8250: autoconfig_8250(up); break; - case 1: - port->type = PORT_UNKNOWN; - break; - case 2: + case UART_IIR_FIFO_ENABLED_16550: port->type = PORT_16550; break; - case 3: + case UART_IIR_FIFO_ENABLED_16550A: autoconfig_16550a(up); break; + default: + port->type = PORT_UNKNOWN; + break; } -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Only probe for RSA ports if we got the region. - */ - if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && - __enable_rsa(up)) - port->type = PORT_RSA; -#endif + rsa_autoconfig(up); serial_out(up, UART_LCR, save_lcr); @@ -1329,26 +1185,18 @@ static void autoconfig(struct uart_8250_port *up) up->capabilities = uart_config[port->type].flags; up->tx_loadsz = uart_config[port->type].tx_loadsz; - if (port->type == PORT_UNKNOWN) - goto out_lock; - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type == PORT_RSA) - serial_out(up, UART_RSA_FRR, 0); -#endif - serial8250_out_MCR(up, save_mcr); - serial8250_clear_fifos(up); - serial_in(up, UART_RX); - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); + if (port->type != PORT_UNKNOWN) { + /* + * Reset the UART. + */ + rsa_reset(up); + serial8250_out_MCR(up, save_mcr); + serial8250_clear_fifos(up); + serial_in(up, UART_RX); + serial8250_clear_IER(up); + } -out_lock: - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* * Check if the device is a Fintek F81216A @@ -1360,9 +1208,6 @@ out_lock: dev_warn(port->dev, "detected caps %08x should be %08x\n", old_capabilities, up->capabilities); } -out: - DEBUG_AUTOCONF("iir=%d ", scratch); - DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); } static void autoconfig_irq(struct uart_8250_port *up) @@ -1381,13 +1226,12 @@ static void autoconfig_irq(struct uart_8250_port *up) inb_p(ICP); } - if (uart_console(port)) - console_lock(); - /* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on()); save_mcr = serial8250_in_MCR(up); - save_ier = serial_in(up, UART_IER); + /* Synchronize UART_IER access against the console. */ + scoped_guard(uart_port_lock_irq, port) + save_ier = serial_in(up, UART_IER); serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); irqs = probe_irq_on(); @@ -1399,24 +1243,22 @@ static void autoconfig_irq(struct uart_8250_port *up) serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } - serial_out(up, UART_IER, 0x0f); /* enable all intrs */ - serial_in(up, UART_LSR); - serial_in(up, UART_RX); - serial_in(up, UART_IIR); - serial_in(up, UART_MSR); + /* Synchronize UART_IER access against the console. */ + scoped_guard(uart_port_lock_irq, port) + serial_out(up, UART_IER, UART_IER_ALL_INTR); + serial8250_clear_interrupts(port); serial_out(up, UART_TX, 0xFF); udelay(20); irq = probe_irq_off(irqs); serial8250_out_MCR(up, save_mcr); - serial_out(up, UART_IER, save_ier); + /* Synchronize UART_IER access against the console. */ + scoped_guard(uart_port_lock_irq, port) + serial_out(up, UART_IER, save_ier); if (port->flags & UPF_FOURPORT) outb_p(save_ICP, ICP); - if (uart_console(port)) - console_unlock(); - port->irq = (irq > 0) ? irq : 0; } @@ -1424,25 +1266,29 @@ static void serial8250_stop_rx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - serial8250_rpm_get(up); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + + guard(serial8250_rpm)(up); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); - up->port.read_status_mask &= ~UART_LSR_DR; serial_port_out(port, UART_IER, up->ier); - - serial8250_rpm_put(up); } /** * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback * @p: uart 8250 port + * @toggle_ier: true to allow enabling receive interrupts * * Generic callback usable by 8250 uart drivers to stop rs485 transmission. */ -void serial8250_em485_stop_tx(struct uart_8250_port *p) +void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier) { unsigned char mcr = serial8250_in_MCR(p); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); + if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) mcr |= UART_MCR_RTS; else @@ -1457,92 +1303,103 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p) if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { serial8250_clear_and_reinit_fifos(p); - p->ier |= UART_IER_RLSI | UART_IER_RDI; - serial_port_out(&p->port, UART_IER, p->ier); + if (toggle_ier) { + p->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_port_out(&p->port, UART_IER, p->ier); + } } } EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) { - struct uart_8250_em485 *em485; - struct uart_8250_port *p; - unsigned long flags; + struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, + stop_tx_timer); + struct uart_8250_port *p = em485->port; - em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); - p = em485->port; + guard(serial8250_rpm)(p); + guard(uart_port_lock_irqsave)(&p->port); - serial8250_rpm_get(p); - spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->stop_tx_timer) { - p->rs485_stop_tx(p); + p->rs485_stop_tx(p, true); em485->active_timer = NULL; em485->tx_stopped = true; } - spin_unlock_irqrestore(&p->port.lock, flags); - serial8250_rpm_put(p); + return HRTIMER_NORESTART; } static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) { - long sec = msec / 1000; - long nsec = (msec % 1000) * 1000000; - ktime_t t = ktime_set(sec, nsec); - - hrtimer_start(hrt, t, HRTIMER_MODE_REL); + hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL); } -static void __stop_tx_rs485(struct uart_8250_port *p) +static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay) { struct uart_8250_em485 *em485 = p->em485; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); + + stop_delay += (u64)p->port.rs485.delay_rts_after_send * NSEC_PER_MSEC; + /* * rs485_stop_tx() is going to set RTS according to config * AND flush RX FIFO if required. */ - if (p->port.rs485.delay_rts_after_send > 0) { + if (stop_delay > 0) { em485->active_timer = &em485->stop_tx_timer; - start_hrtimer_ms(&em485->stop_tx_timer, - p->port.rs485.delay_rts_after_send); + hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL); } else { - p->rs485_stop_tx(p); + p->rs485_stop_tx(p, true); em485->active_timer = NULL; em485->tx_stopped = true; } } -static inline void __do_stop_tx(struct uart_8250_port *p) -{ - if (serial8250_clear_THRI(p)) - serial8250_rpm_put_tx(p); -} - static inline void __stop_tx(struct uart_8250_port *p) { struct uart_8250_em485 *em485 = p->em485; if (em485) { - unsigned char lsr = serial_in(p, UART_LSR); + u16 lsr = serial_lsr_in(p); + u64 stop_delay = 0; + + if (!(lsr & UART_LSR_THRE)) + return; /* - * To provide required timeing and allow FIFO transfer, + * To provide required timing and allow FIFO transfer, * __stop_tx_rs485() must be called only when both FIFO and - * shift register are empty. It is for device driver to enable - * interrupt on TEMT. + * shift register are empty. The device driver should either + * enable interrupt on TEMT or set UART_CAP_NOTEMT that will + * enlarge stop_tx_timer by the tx time of one frame to cover + * for emptying of the shift register. */ - if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) - return; + if (!(lsr & UART_LSR_TEMT)) { + if (!(p->capabilities & UART_CAP_NOTEMT)) + return; + /* + * RTS might get deasserted too early with the normal + * frame timing formula. It seems to suggest THRE might + * get asserted already during tx of the stop bit + * rather than after it is fully sent. + * Roughly estimate 1 extra bit here with / 7. + */ + stop_delay = p->port.frame_time + DIV_ROUND_UP(p->port.frame_time, 7); + } - __stop_tx_rs485(p); + __stop_tx_rs485(p, stop_delay); } - __do_stop_tx(p); + + if (serial8250_clear_THRI(p)) + serial8250_rpm_put_tx(p); } static void serial8250_stop_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); __stop_tx(up); /* @@ -1552,7 +1409,6 @@ static void serial8250_stop_tx(struct uart_port *port) up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } - serial8250_rpm_put(up); } static inline void __start_tx(struct uart_port *port) @@ -1564,10 +1420,8 @@ static inline void __start_tx(struct uart_port *port) if (serial8250_set_THRI(up)) { if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; + u16 lsr = serial_lsr_in(up); - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); } @@ -1585,6 +1439,7 @@ static inline void __start_tx(struct uart_port *port) /** * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback * @up: uart 8250 port + * @toggle_ier: true to allow disabling receive interrupts * * Generic callback usable by 8250 uart drivers to start rs485 transmission. * Assumes that setting the RTS bit in the MCR register means RTS is high. @@ -1592,11 +1447,11 @@ static inline void __start_tx(struct uart_port *port) * stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.) */ -void serial8250_em485_start_tx(struct uart_8250_port *up) +void serial8250_em485_start_tx(struct uart_8250_port *up, bool toggle_ier) { unsigned char mcr = serial8250_in_MCR(up); - if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && toggle_ier) serial8250_stop_rx(&up->port); if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) @@ -1607,44 +1462,55 @@ void serial8250_em485_start_tx(struct uart_8250_port *up) } EXPORT_SYMBOL_GPL(serial8250_em485_start_tx); -static inline void start_tx_rs485(struct uart_port *port) +/* Returns false, if start_tx_timer was setup to defer TX start */ +static bool start_tx_rs485(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_em485 *em485 = up->em485; + /* + * While serial8250_em485_handle_stop_tx() is a noop if + * em485->active_timer != &em485->stop_tx_timer, it might happen that + * the timer is still armed and triggers only after the current bunch of + * chars is send and em485->active_timer == &em485->stop_tx_timer again. + * So cancel the timer. There is still a theoretical race condition if + * the timer is already running and only comes around to check for + * em485->active_timer when &em485->stop_tx_timer is armed again. + */ + if (em485->active_timer == &em485->stop_tx_timer) + hrtimer_try_to_cancel(&em485->stop_tx_timer); + em485->active_timer = NULL; if (em485->tx_stopped) { em485->tx_stopped = false; - up->rs485_start_tx(up); + up->rs485_start_tx(up, true); if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; start_hrtimer_ms(&em485->start_tx_timer, up->port.rs485.delay_rts_before_send); - return; + return false; } } - __start_tx(port); + return true; } static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) { - struct uart_8250_em485 *em485; - struct uart_8250_port *p; - unsigned long flags; + struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, + start_tx_timer); + struct uart_8250_port *p = em485->port; - em485 = container_of(t, struct uart_8250_em485, start_tx_timer); - p = em485->port; + guard(uart_port_lock_irqsave)(&p->port); - spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->start_tx_timer) { __start_tx(&p->port); em485->active_timer = NULL; } - spin_unlock_irqrestore(&p->port.lock, flags); + return HRTIMER_NORESTART; } @@ -1653,16 +1519,20 @@ static void serial8250_start_tx(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_em485 *em485 = up->em485; - serial8250_rpm_get_tx(up); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); - if (em485 && - em485->active_timer == &em485->start_tx_timer) + if (!port->x_char && kfifo_is_empty(&port->state->port.xmit_fifo)) return; - if (em485) - start_tx_rs485(port); - else - __start_tx(port); + serial8250_rpm_get_tx(up); + + if (em485) { + if ((em485->active_timer == &em485->start_tx_timer) || + !start_tx_rs485(port)) + return; + } + __start_tx(port); } static void serial8250_throttle(struct uart_port *port) @@ -1679,11 +1549,14 @@ static void serial8250_disable_ms(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + /* no MSR capabilities */ if (up->bugs & UART_BUG_NOMSR) return; - mctrl_gpio_disable_ms(up->gpios); + mctrl_gpio_disable_ms_no_sync(up->gpios); up->ier &= ~UART_IER_MSI; serial_port_out(port, UART_IER, up->ier); @@ -1693,6 +1566,9 @@ static void serial8250_enable_ms(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + /* no MSR capabilities */ if (up->bugs & UART_BUG_NOMSR) return; @@ -1701,16 +1577,14 @@ static void serial8250_enable_ms(struct uart_port *port) up->ier |= UART_IER_MSI; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); serial_port_out(port, UART_IER, up->ier); - serial8250_rpm_put(up); } -void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) +void serial8250_read_char(struct uart_8250_port *up, u16 lsr) { struct uart_port *port = &up->port; - unsigned char ch; - char flag = TTY_NORMAL; + u8 ch, flag = TTY_NORMAL; if (likely(lsr & UART_LSR_DR)) ch = serial_in(up, UART_RX); @@ -1769,11 +1643,13 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) EXPORT_SYMBOL_GPL(serial8250_read_char); /* - * serial8250_rx_chars: processes according to the passed in LSR - * value, and returns the remaining LSR bits not handled - * by this Rx routine. + * serial8250_rx_chars - Read characters. The first LSR value must be passed in. + * + * Returns LSR bits. The caller should rely only on non-Rx related LSR bits + * (such as THRE) because the LSR value might come from an already consumed + * character. */ -unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr) { struct uart_port *port = &up->port; int max_count = 256; @@ -1793,33 +1669,45 @@ EXPORT_SYMBOL_GPL(serial8250_rx_chars); void serial8250_tx_chars(struct uart_8250_port *up) { struct uart_port *port = &up->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int count; if (port->x_char) { - serial_out(up, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; + uart_xchar_out(port, UART_TX); return; } if (uart_tx_stopped(port)) { serial8250_stop_tx(port); return; } - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { __stop_tx(up); return; } count = up->tx_loadsz; do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) + unsigned char c; + + if (!uart_fifo_get(port, &c)) break; + + serial_out(up, UART_TX, c); + if (up->bugs & UART_BUG_TXRACE) { + /* + * The Aspeed BMC virtual UARTs have a bug where data + * may get stuck in the BMC's Tx FIFO from bursts of + * writes on the APB interface. + * + * Delay back-to-back writes by a read cycle to avoid + * stalling the VUART. Read a register that won't have + * side-effects and discard the result. + */ + serial_in(up, UART_SCR); + } + if ((up->capabilities & UART_CAP_HFIFO) && - (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY) + !uart_lsr_tx_empty(serial_in(up, UART_LSR))) break; /* The BCM2835 MINI UART THRE bit is really a not-full bit. */ if ((up->capabilities & UART_CAP_MINI) && @@ -1827,7 +1715,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) break; } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* @@ -1835,7 +1723,8 @@ void serial8250_tx_chars(struct uart_8250_port *up) * HW can go idle. So we get here once again with empty FIFO and disable * the interrupt and RPM in __stop_tx() */ - if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) + if (kfifo_is_empty(&tport->xmit_fifo) && + !(up->capabilities & UART_CAP_RPM)) __stop_tx(up); } EXPORT_SYMBOL_GPL(serial8250_tx_chars); @@ -1869,10 +1758,24 @@ EXPORT_SYMBOL_GPL(serial8250_modem_status); static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) { switch (iir & 0x3f) { + case UART_IIR_THRI: + /* + * Postpone DMA or not decision to IIR_RDI or IIR_RX_TIMEOUT + * because it's impossible to do an informed decision about + * that with IIR_THRI. + * + * This also fixes one known DMA Rx corruption issue where + * DR is asserted but DMA Rx only gets a corrupted zero byte + * (too early DR?). + */ + return false; + case UART_IIR_RDI: + if (!up->dma->rx_running) + break; + fallthrough; + case UART_IIR_RLSI: case UART_IIR_RX_TIMEOUT: serial8250_rx_dma_flush(up); - /* fall-through */ - case UART_IIR_RLSI: return true; } return up->dma->rx_dma(up); @@ -1883,17 +1786,18 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) */ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) { - unsigned char status; - unsigned long flags; struct uart_8250_port *up = up_to_u8250p(port); + struct tty_port *tport = &port->state->port; bool skip_rx = false; + unsigned long flags; + u16 status; if (iir & UART_IIR_NO_INT) return 0; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); - status = serial_port_in(port, UART_LSR); + status = serial_lsr_in(up); /* * If port is stopped and there are no error conditions in the @@ -1905,19 +1809,28 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) */ if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) && (port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) && - !(port->read_status_mask & UART_LSR_DR)) + !(up->ier & (UART_IER_RLSI | UART_IER_RDI))) skip_rx = true; if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) { + struct irq_data *d; + + d = irq_get_irq_data(port->irq); + if (d && irqd_is_wakeup_set(d)) + pm_wakeup_event(tport->tty->dev, 0); if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); - if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) && - (up->ier & UART_IER_THRI)) - serial8250_tx_chars(up); + if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) { + if (!up->dma || up->dma->tx_err) + serial8250_tx_chars(up); + else if (!up->dma->tx_running) + __stop_tx(up); + } + + uart_unlock_and_check_sysrq_irqrestore(port, flags); - uart_unlock_and_check_sysrq(port, flags); return 1; } EXPORT_SYMBOL_GPL(serial8250_handle_irq); @@ -1926,15 +1839,11 @@ static int serial8250_default_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir; - int ret; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); iir = serial_port_in(port, UART_IIR); - ret = serial8250_handle_irq(port, iir); - - serial8250_rpm_put(up); - return ret; + return serial8250_handle_irq(port, iir); } /* @@ -1945,16 +1854,14 @@ static int serial8250_default_handle_irq(struct uart_port *port) */ 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); + guard(uart_port_lock_irqsave)(port); serial8250_tx_chars(up); - spin_unlock_irqrestore(&port->lock, flags); } iir = serial_port_in(port, UART_IIR); @@ -1964,19 +1871,14 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port) static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - unsigned int lsr; - - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); - lsr = serial_port_in(port, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&port->lock, flags); + guard(serial8250_rpm)(up); + guard(uart_port_lock_irqsave)(port); - serial8250_rpm_put(up); + if (!serial8250_tx_dma_running(up) && uart_lsr_tx_empty(serial_lsr_in(up))) + return TIOCSER_TEMT; - return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; + return 0; } unsigned int serial8250_do_get_mctrl(struct uart_port *port) @@ -1985,9 +1887,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port) unsigned int status; unsigned int val; - serial8250_rpm_get(up); - status = serial8250_modem_status(up); - serial8250_rpm_put(up); + scoped_guard(serial8250_rpm, up) + status = serial8250_modem_status(up); val = serial8250_MSR_to_TIOCM(status); if (up->gpios) @@ -2009,16 +1910,9 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_8250_port *up = up_to_u8250p(port); unsigned char mcr; - if (port->rs485.flags & SER_RS485_ENABLED) { - if (serial8250_in_MCR(up) & UART_MCR_RTS) - mctrl |= TIOCM_RTS; - else - mctrl &= ~TIOCM_RTS; - } - mcr = serial8250_TIOCM_to_MCR(mctrl); - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + mcr |= up->mcr; serial8250_out_MCR(up, mcr); } @@ -2026,6 +1920,9 @@ EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) { + if (port->rs485.flags & SER_RS485_ENABLED) + return; + if (port->set_mctrl) port->set_mctrl(port, mctrl); else @@ -2035,31 +1932,33 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial8250_break_ctl(struct uart_port *port, int break_state) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); + guard(serial8250_rpm)(up); + guard(uart_port_lock_irqsave)(port); + if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_port_out(port, UART_LCR, up->lcr); - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); } -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) +/* Returns true if @bits were set, false on timeout */ +static bool wait_for_lsr(struct uart_8250_port *up, int bits) { - unsigned int status, tmout = 10000; + unsigned int status, tmout; - /* Wait up to 10ms for the character(s) to be sent. */ - for (;;) { - status = serial_in(up, UART_LSR); + /* + * Wait for a character to be sent. Fallback to a safe default + * timeout value if @frame_time is not available. + */ + if (up->port.frame_time) + tmout = up->port.frame_time * 2 / NSEC_PER_USEC; + else + tmout = 10000; - up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + for (;;) { + status = serial_lsr_in(up); if ((status & bits) == bits) break; @@ -2069,6 +1968,16 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) touch_nmi_watchdog(); } + return (tmout != 0); +} + +/* Wait for transmitter and holding register to empty with timeout */ +static void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int tmout; + + wait_for_lsr(up, bits); + /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { for (tmout = 1000000; tmout; tmout--) { @@ -2091,22 +2000,15 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) static int serial8250_get_poll_char(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned char lsr; - int status; + u16 lsr; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); lsr = serial_port_in(port, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; - if (!(lsr & UART_LSR_DR)) { - status = NO_POLL_CHAR; - goto out; - } - - status = serial_port_in(port, UART_RX); -out: - serial8250_rpm_put(up); - return status; + return serial_port_in(port, UART_RX); } @@ -2116,17 +2018,22 @@ static void serial8250_put_poll_char(struct uart_port *port, unsigned int ier; struct uart_8250_port *up = up_to_u8250p(port); - serial8250_rpm_get(up); + /* + * Normally the port is locked to synchronize UART_IER access + * against the console. However, this function is only used by + * KDB/KGDB, where it may not be possible to acquire the port + * lock because all other CPUs are quiesced. The quiescence + * should allow safe lockless usage here. + */ + + guard(serial8250_rpm)(up); /* * First save the IER then disable the interrupts */ ier = serial_port_in(port, UART_IER); - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); + serial8250_clear_IER(up); - wait_for_xmitr(up, BOTH_EMPTY); + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); /* * Send the character out. */ @@ -2136,34 +2043,24 @@ static void serial8250_put_poll_char(struct uart_port *port, * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(up, BOTH_EMPTY); + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); serial_port_out(port, UART_IER, ier); - serial8250_rpm_put(up); } #endif /* CONFIG_CONSOLE_POLL */ -int serial8250_do_startup(struct uart_port *port) +static void serial8250_startup_special(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - unsigned char lsr, iir; - int retval; - if (!port->fifosize) - port->fifosize = uart_config[port->type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[port->type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[port->type].flags; - up->mcr = 0; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - serial8250_rpm_get(up); - if (port->type == PORT_16C950) { - /* Wake up and initialize UART */ + switch (port->type) { + case PORT_16C950: { + /* + * Wake up and initialize UART + * + * Synchronize UART_IER access against the console. + */ + guard(uart_port_lock_irqsave)(port); up->acr = 0; serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); serial_port_out(port, UART_EFR, UART_EFR_ECB); @@ -2173,12 +2070,18 @@ int serial8250_do_startup(struct uart_port *port) serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); serial_port_out(port, UART_EFR, UART_EFR_ECB); serial_port_out(port, UART_LCR, 0); + break; } - - if (port->type == PORT_DA830) { - /* Reset the port */ - serial_port_out(port, UART_IER, 0); - serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); + case PORT_DA830: + /* + * Reset the port + * + * Synchronize UART_IER access against the console. + */ + scoped_guard(uart_port_lock_irqsave, port) { + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); + } mdelay(10); /* Enable Tx, Rx and free run mode */ @@ -2186,197 +2089,217 @@ int serial8250_do_startup(struct uart_port *port) UART_DA830_PWREMU_MGMT_UTRST | UART_DA830_PWREMU_MGMT_URRST | UART_DA830_PWREMU_MGMT_FREE); + break; + case PORT_RSA: + rsa_enable(up); + break; } +} - if (port->type == PORT_NPCM) { - /* - * Nuvoton calls the scratch register 'UART_TOR' (timeout - * register). Enable it, and set TIOC (timeout interrupt - * comparator) to be 0x20 for correct operation. - */ - serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - enable_rsa(up); -#endif - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial8250_clear_fifos(up); - - /* - * Clear the interrupt registers. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - - /* - * At this point, there's no way the LSR could still be 0xff; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(port->flags & UPF_BUGGY_UART) && - (serial_port_in(port, UART_LSR) == 0xff)) { - dev_info_ratelimited(port->dev, "LSR safety check engaged!\n"); - retval = -ENODEV; - goto out; - } +static void serial8250_set_TRG_levels(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); - /* - * For a XR16C850, we need to set the trigger levels - */ - if (port->type == PORT_16850) { - unsigned char fctr; + switch (port->type) { + /* For a XR16C850, we need to set the trigger levels */ + case PORT_16850: { + u8 fctr; serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_RX); + fctr |= UART_FCTR_TRGD; + serial_port_out(port, UART_FCTR, fctr | UART_FCTR_RX); serial_port_out(port, UART_TRG, UART_TRG_96); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_port_out(port, UART_FCTR, fctr | UART_FCTR_TX); serial_port_out(port, UART_TRG, UART_TRG_96); serial_port_out(port, UART_LCR, 0); + break; } + /* For the Altera 16550 variants, set TX threshold trigger level. */ + case PORT_ALTR_16550_F32: + case PORT_ALTR_16550_F64: + case PORT_ALTR_16550_F128: + if (port->fifosize <= 1) + return; - /* - * 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)) { + if (up->tx_loadsz < 2 || up->tx_loadsz > port->fifosize) { dev_err(port->dev, "TX FIFO Threshold errors, skipping\n"); - } 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; + return; } + 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; + break; } +} - /* Check if we need to have shared IRQs */ - if (port->irq && (up->port.flags & UPF_SHARE_IRQ)) - up->port.irqflags |= IRQF_SHARED; +static void serial8250_THRE_test(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + bool iir_noint1, iir_noint2; - if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { - unsigned char iir1; - /* - * Test for UARTs that do not reassert THRE when the - * transmitter is idle and the interrupt has already - * been cleared. Real 16550s should always reassert - * this interrupt whenever the transmitter is idle and - * the interrupt is enabled. Delays are necessary to - * allow register changes to become visible. - */ - spin_lock_irqsave(&port->lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(port->irq); + if (!port->irq) + return; + + if (up->port.flags & UPF_NO_THRE_TEST) + return; + if (port->irqflags & IRQF_SHARED) + disable_irq_nosync(port->irq); + + /* + * Test for UARTs that do not reassert THRE when the transmitter is idle and the interrupt + * has already been cleared. Real 16550s should always reassert this interrupt whenever the + * transmitter is idle and the interrupt is enabled. Delays are necessary to allow register + * changes to become visible. + * + * Synchronize UART_IER access against the console. + */ + scoped_guard(uart_port_lock_irqsave, port) { wait_for_xmitr(up, UART_LSR_THRE); serial_port_out_sync(port, UART_IER, UART_IER_THRI); udelay(1); /* allow THRE to set */ - iir1 = serial_port_in(port, UART_IIR); + iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; serial_port_out(port, UART_IER, 0); serial_port_out_sync(port, UART_IER, UART_IER_THRI); udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_port_in(port, UART_IIR); + iir_noint2 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; serial_port_out(port, UART_IER, 0); - - if (port->irqflags & IRQF_SHARED) - enable_irq(port->irq); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * If the interrupt is not reasserted, or we otherwise - * don't trust the iir, setup a timer to kick the UART - * on a regular basis. - */ - if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || - up->port.flags & UPF_BUG_THRE) { - up->bugs |= UART_BUG_THRE; - } } - retval = up->ops->setup_irq(up); - if (retval) - goto out; + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); /* - * Now, initialize the UART + * If the interrupt is not reasserted, or we otherwise don't trust the iir, setup a timer to + * kick the UART on a regular basis. */ - serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + if ((!iir_noint1 && iir_noint2) || up->port.flags & UPF_BUG_THRE) + up->bugs |= UART_BUG_THRE; +} - spin_lock_irqsave(&port->lock, flags); - if (up->port.flags & UPF_FOURPORT) { - if (!up->port.irq) - up->port.mctrl |= TIOCM_OUT1; - } else - /* - * Most PC uarts need OUT2 raised to enable interrupts. - */ +static void serial8250_init_mctrl(struct uart_port *port) +{ + if (port->flags & UPF_FOURPORT) { + if (!port->irq) + port->mctrl |= TIOCM_OUT1; + } else { + /* Most PC uarts need OUT2 raised to enable interrupts. */ if (port->irq) - up->port.mctrl |= TIOCM_OUT2; + port->mctrl |= TIOCM_OUT2; + } serial8250_set_mctrl(port, port->mctrl); +} - /* - * Serial over Lan (SoL) hack: - * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be - * used for Serial Over Lan. Those chips take a longer time than a - * normal serial device to signalize that a transmission data was - * queued. Due to that, the above test generally fails. One solution - * would be to delay the reading of iir. However, this is not - * reliable, since the timeout is variable. So, let's just don't - * test if we receive TX irq. This way, we'll never enable - * UART_BUG_TXEN. - */ - if (up->port.quirks & UPQ_NO_TXEN_TEST) - goto dont_test_tx_en; +static void serial8250_iir_txen_test(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + bool lsr_temt, iir_noint; - /* - * Do a quick test to see if we receive an interrupt when we enable - * the TX irq. - */ + if (port->quirks & UPQ_NO_TXEN_TEST) + return; + + /* Do a quick test to see if we receive an interrupt when we enable the TX irq. */ serial_port_out(port, UART_IER, UART_IER_THRI); - lsr = serial_port_in(port, UART_LSR); - iir = serial_port_in(port, UART_IIR); + lsr_temt = serial_port_in(port, UART_LSR) & UART_LSR_TEMT; + iir_noint = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; serial_port_out(port, UART_IER, 0); - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + /* + * Serial over Lan (SoL) hack: + * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be used for Serial Over + * Lan. Those chips take a longer time than a normal serial device to signalize that a + * transmission data was queued. Due to that, the above test generally fails. One solution + * would be to delay the reading of iir. However, this is not reliable, since the timeout is + * variable. So, in case of UPQ_NO_TXEN_TEST, let's just don't test if we receive TX irq. + * This way, we'll never enable UART_BUG_TXEN. + */ + if (lsr_temt && iir_noint) { if (!(up->bugs & UART_BUG_TXEN)) { up->bugs |= UART_BUG_TXEN; dev_dbg(port->dev, "enabling bad tx status workarounds\n"); } - } else { - up->bugs &= ~UART_BUG_TXEN; + return; } -dont_test_tx_en: - spin_unlock_irqrestore(&port->lock, flags); + /* FIXME: why is this needed? */ + up->bugs &= ~UART_BUG_TXEN; +} + +static void serial8250_initialize(struct uart_port *port) +{ + guard(uart_port_lock_irqsave)(port); + serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + + serial8250_init_mctrl(port); + serial8250_iir_txen_test(port); +} + +int serial8250_do_startup(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int retval; + + if (!port->fifosize) + port->fifosize = uart_config[port->type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[port->type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[port->type].flags; + up->mcr = 0; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + guard(serial8250_rpm)(up); + + serial8250_startup_special(port); + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial8250_clear_fifos(up); + + serial8250_clear_interrupts(port); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(port->flags & UPF_BUGGY_UART) && + (serial_port_in(port, UART_LSR) == 0xff)) { + dev_info_ratelimited(port->dev, "LSR safety check engaged!\n"); + return -ENODEV; + } + + serial8250_set_TRG_levels(port); + + /* Check if we need to have shared IRQs */ + if (port->irq && (up->port.flags & UPF_SHARE_IRQ)) + up->port.irqflags |= IRQF_SHARED; + + retval = up->ops->setup_irq(up); + if (retval) + return retval; + + serial8250_THRE_test(port); + + up->ops->setup_timer(up); + + serial8250_initialize(port); /* * Clear the interrupt registers again for luck, and clear the * saved flags to avoid getting false values from polling * routines or the previous session. */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); + serial8250_clear_interrupts(port); up->lsr_saved_flags = 0; up->msr_saved_flags = 0; @@ -2412,10 +2335,8 @@ dont_test_tx_en: outb_p(0x80, icp); inb_p(icp); } - retval = 0; -out: - serial8250_rpm_put(up); - return retval; + + return 0; } EXPORT_SYMBOL_GPL(serial8250_do_startup); @@ -2429,32 +2350,33 @@ static int serial8250_startup(struct uart_port *port) void serial8250_do_shutdown(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; serial8250_rpm_get(up); /* * Disable interrupts from this port + * + * Synchronize UART_IER access against the console. */ - spin_lock_irqsave(&port->lock, flags); - up->ier = 0; - serial_port_out(port, UART_IER, 0); - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(uart_port_lock_irqsave, port) { + up->ier = 0; + serial_port_out(port, UART_IER, 0); + } synchronize_irq(port->irq); if (up->dma) serial8250_release_dma(up); - spin_lock_irqsave(&port->lock, flags); - if (port->flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((port->iobase & 0xfe0) | 0x1f); - port->mctrl |= TIOCM_OUT1; - } else - port->mctrl &= ~TIOCM_OUT2; + scoped_guard(uart_port_lock_irqsave, port) { + if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((port->iobase & 0xfe0) | 0x1f); + port->mctrl |= TIOCM_OUT1; + } else + port->mctrl &= ~TIOCM_OUT2; - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); + serial8250_set_mctrl(port, port->mctrl); + } /* * Disable break condition and FIFOs @@ -2463,12 +2385,7 @@ void serial8250_do_shutdown(struct uart_port *port) serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); serial8250_clear_fifos(up); -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - disable_rsa(up); -#endif + rsa_disable(up); /* * Read data port to reset things, and then unlink from @@ -2489,35 +2406,56 @@ static void serial8250_shutdown(struct uart_port *port) serial8250_do_shutdown(port); } -/* Nuvoton NPCM UARTs have a custom divisor calculation */ -static unsigned int npcm_get_divisor(struct uart_8250_port *up, - unsigned int baud) +static void serial8250_flush_buffer(struct uart_port *port) { - struct uart_port *port = &up->port; + struct uart_8250_port *up = up_to_u8250p(port); - return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; + if (up->dma) + serial8250_tx_dma_flush(up); } -static unsigned int serial8250_do_get_divisor(struct uart_port *port, - unsigned int baud, - unsigned int *frac) +static unsigned int serial8250_do_get_divisor(struct uart_port *port, unsigned int baud) { + upf_t magic_multiplier = port->flags & UPF_MAGIC_MULTIPLIER; struct uart_8250_port *up = up_to_u8250p(port); unsigned int quot; /* - * Handle magic divisors for baud rates above baud_base on - * SMSC SuperIO chips. + * Handle magic divisors for baud rates above baud_base on SMSC + * Super I/O chips. We clamp custom rates from clk/6 and clk/12 + * up to clk/4 (0x8001) and clk/8 (0x8002) respectively. These + * magic divisors actually reprogram the baud rate generator's + * reference clock derived from chips's 14.318MHz clock input. + * + * Documentation claims that with these magic divisors the base + * frequencies of 7.3728MHz and 3.6864MHz are used respectively + * for the extra baud rates of 460800bps and 230400bps rather + * than the usual base frequency of 1.8462MHz. However empirical + * evidence contradicts that. * + * Instead bit 7 of the DLM register (bit 15 of the divisor) is + * effectively used as a clock prescaler selection bit for the + * base frequency of 7.3728MHz, always used. If set to 0, then + * the base frequency is divided by 4 for use by the Baud Rate + * Generator, for the usual arrangement where the value of 1 of + * the divisor produces the baud rate of 115200bps. Conversely, + * if set to 1 and high-speed operation has been enabled with the + * Serial Port Mode Register in the Device Configuration Space, + * then the base frequency is supplied directly to the Baud Rate + * Generator, so for the divisor values of 0x8001, 0x8002, 0x8003, + * 0x8004, etc. the respective baud rates produced are 460800bps, + * 230400bps, 153600bps, 115200bps, etc. + * + * In all cases only low 15 bits of the divisor are used to divide + * the baud base and therefore 32767 is the maximum divisor value + * possible, even though documentation says that the programmable + * Baud Rate Generator is capable of dividing the internal PLL + * clock by any divisor from 1 to 65535. */ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) + if (magic_multiplier && baud >= port->uartclk / 6) quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) + else if (magic_multiplier && baud >= port->uartclk / 12) quot = 0x8002; - else if (up->port.type == PORT_NPCM) - quot = npcm_get_divisor(up, baud); else quot = uart_get_divisor(port, baud); @@ -2537,49 +2475,27 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, if (port->get_divisor) return port->get_divisor(port, baud, frac); - return serial8250_do_get_divisor(port, baud, frac); + return serial8250_do_get_divisor(port, baud); } -static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, - tcflag_t c_cflag) +static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, tcflag_t c_cflag) { - unsigned char cval; - - switch (c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } + u8 lcr = UART_LCR_WLEN(tty_get_char_size(c_cflag)); if (c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (c_cflag & PARENB) { - cval |= UART_LCR_PARITY; - if (up->bugs & UART_BUG_PARITY) - up->fifo_bug = true; - } + lcr |= UART_LCR_STOP; + if (c_cflag & PARENB) + lcr |= UART_LCR_PARITY; if (!(c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR + lcr |= UART_LCR_EPAR; if (c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif + lcr |= UART_LCR_SPAR; - return cval; + return lcr; } void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, - unsigned int quot, unsigned int quot_frac) + unsigned int quot) { struct uart_8250_port *up = up_to_u8250p(port); @@ -2611,14 +2527,29 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, if (port->set_divisor) port->set_divisor(port, baud, quot, quot_frac); else - serial8250_do_set_divisor(port, baud, quot, quot_frac); + serial8250_do_set_divisor(port, baud, quot); } static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int tolerance = port->uartclk / 100; + unsigned int min; + unsigned int max; + + /* + * Handle magic divisors for baud rates above baud_base on SMSC + * Super I/O chips. Enable custom rates of clk/4 and clk/8, but + * disable divisor values beyond 32767, which are unavailable. + */ + if (port->flags & UPF_MAGIC_MULTIPLIER) { + min = port->uartclk / 16 / UART_DIV_MAX >> 1; + max = (port->uartclk + tolerance) / 4; + } else { + min = port->uartclk / 16 / UART_DIV_MAX; + max = (port->uartclk + tolerance) / 16; + } /* * Ask the core to calculate the divisor for us. @@ -2626,98 +2557,130 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, * slower than nominal still match standard baud rates without * causing transmission errors. */ - return uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / UART_DIV_MAX, - (port->uartclk + tolerance) / 16); + return uart_get_baud_rate(port, termios, old, min, max); } -void -serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +/* + * Note in order to avoid the tty port mutex deadlock don't use the next method + * within the uart port callbacks. Primarily it's supposed to be utilized to + * handle a sudden reference clock rate change. + */ +void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) { - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char cval; - unsigned long flags; - unsigned int baud, quot, frac = 0; + struct tty_port *tport = &port->state->port; - if (up->capabilities & UART_CAP_MINI) { - termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR); - if ((termios->c_cflag & CSIZE) == CS5 || - (termios->c_cflag & CSIZE) == CS6) - termios->c_cflag = (termios->c_cflag & ~CSIZE) | CS7; - } - cval = serial8250_compute_lcr(up, termios->c_cflag); + scoped_guard(tty_port_tty, tport) { + struct tty_struct *tty = scoped_tty(); - baud = serial8250_get_baud_rate(port, termios, old); - quot = serial8250_get_divisor(port, baud, &frac); + guard(rwsem_write)(&tty->termios_rwsem); + guard(mutex)(&tport->mutex); - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); + if (port->uartclk == uartclk) + return; - up->lcr = cval; /* Save computed LCR */ + port->uartclk = uartclk; - if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ - if ((baud < 2400 && !up->dma) || up->fifo_bug) { - up->fcr &= ~UART_FCR_TRIGGER_MASK; - up->fcr |= UART_FCR_TRIGGER_1; - } + if (!tty_port_initialized(tport)) + return; + + serial8250_do_set_termios(port, &tty->termios, NULL); + + return; } + guard(mutex)(&tport->mutex); + port->uartclk = uartclk; +} +EXPORT_SYMBOL_GPL(serial8250_update_uartclk); - /* - * MCR-based auto flow control. When AFE is enabled, RTS will be - * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. - */ - if (up->capabilities & UART_CAP_AFE) { - up->mcr &= ~UART_MCR_AFE; - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; +static void serial8250_set_mini(struct uart_port *port, struct ktermios *termios) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (!(up->capabilities & UART_CAP_MINI)) + return; + + termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR); + + tcflag_t csize = termios->c_cflag & CSIZE; + if (csize == CS5 || csize == CS6) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS7; } +} + +static void serial8250_set_trigger_for_slow_speed(struct uart_port *port, struct ktermios *termios, + unsigned int baud) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (!(up->capabilities & UART_CAP_FIFO)) + return; + if (port->fifosize <= 1) + return; + if (baud >= 2400) + return; + if (up->dma) + return; + + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= UART_FCR_TRIGGER_1; +} + +/* + * MCR-based auto flow control. When AFE is enabled, RTS will be deasserted when the receive FIFO + * contains more characters than the trigger, or the MCR RTS bit is cleared. + */ +static void serial8250_set_afe(struct uart_port *port, struct ktermios *termios) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (!(up->capabilities & UART_CAP_AFE)) + return; + + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; +} +static void serial8250_set_errors_and_ignores(struct uart_port *port, struct ktermios *termios) +{ /* - * Update the per-port timeout. + * Specify which conditions may be considered for error handling and the ignoring of + * characters. The actual ignoring of characters only occurs if the bit is set in + * @ignore_status_mask as well. */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + port->read_status_mask = UART_LSR_OE | UART_LSR_DR; if (termios->c_iflag & INPCK) port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_LSR_BI; - /* - * Characteres to ignore - */ + /* Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; if (termios->c_iflag & IGNBRK) { port->ignore_status_mask |= UART_LSR_BI; /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). + * If we're ignoring parity and break indicators, ignore overruns too (for real raw + * support). */ if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= UART_LSR_OE; } - /* - * ignore all characters if CREAD is not set - */ + /* ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= UART_LSR_DR; +} - /* - * CTS flow control flag and modem status interrupts - */ +static void serial8250_set_ier(struct uart_port *port, struct ktermios *termios) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* CTS flow control flag and modem status interrupts */ up->ier &= ~UART_IER_MSI; - if (!(up->bugs & UART_BUG_NOMSR) && - UART_ENABLE_MS(&up->port, termios->c_cflag)) + if (!(up->bugs & UART_BUG_NOMSR) && UART_ENABLE_MS(&up->port, termios->c_cflag)) up->ier |= UART_IER_MSI; if (up->capabilities & UART_CAP_UUE) up->ier |= UART_IER_UUE; @@ -2725,43 +2688,88 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, up->ier |= UART_IER_RTOIE; serial_port_out(port, UART_IER, up->ier); +} - if (up->capabilities & UART_CAP_EFR) { - unsigned char efr = 0; - /* - * TI16C752/Startech hardware flow control. FIXME: - * - TI16C752 requires control thresholds to be set. - * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. - */ - if (termios->c_cflag & CRTSCTS) - efr |= UART_EFR_CTS; - - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - if (port->flags & UPF_EXAR_EFR) - serial_port_out(port, UART_XR_EFR, efr); - else - serial_port_out(port, UART_EFR, efr); - } +static void serial8250_set_efr(struct uart_port *port, struct ktermios *termios) +{ + struct uart_8250_port *up = up_to_u8250p(port); + u8 efr_reg = UART_EFR; + u8 efr = 0; - serial8250_set_divisor(port, baud, quot, frac); + if (!(up->capabilities & UART_CAP_EFR)) + return; /* - * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR - * is written without DLAB set, this mode will be disabled. + * TI16C752/Startech hardware flow control. FIXME: + * - TI16C752 requires control thresholds to be set. + * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. */ - if (port->type == PORT_16750) + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + + if (port->flags & UPF_EXAR_EFR) + efr_reg = UART_XR_EFR; + + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, efr_reg, efr); +} + +static void serial8250_set_fcr(struct uart_port *port, struct ktermios *termios) +{ + struct uart_8250_port *up = up_to_u8250p(port); + bool is_16750 = port->type == PORT_16750; + + if (is_16750) serial_port_out(port, UART_FCR, up->fcr); - serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */ - if (port->type != PORT_16750) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - if (up->fcr & UART_FCR_ENABLE_FIFO) - serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ + /* + * LCR DLAB must be reset to enable 64-byte FIFO mode. If the FCR is written without DLAB + * set, this mode will be disabled. + */ + serial_port_out(port, UART_LCR, up->lcr); + + if (is_16750) + return; + + /* emulated UARTs (Lucent Venus 167x) need two steps */ + if (up->fcr & UART_FCR_ENABLE_FIFO) + serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + + serial_port_out(port, UART_FCR, up->fcr); +} + +void +serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int baud, quot, frac = 0; + u8 lcr; + + serial8250_set_mini(port, termios); + lcr = serial8250_compute_lcr(up, termios->c_cflag); + baud = serial8250_get_baud_rate(port, termios, old); + quot = serial8250_get_divisor(port, baud, &frac); + + /* + * Ok, we're now changing the port state. Do it with interrupts disabled. + * + * Synchronize UART_IER access against the console. + */ + scoped_guard(serial8250_rpm, up) { + guard(uart_port_lock_irqsave)(port); + + up->lcr = lcr; + serial8250_set_trigger_for_slow_speed(port, termios, baud); + serial8250_set_afe(port, termios); + uart_update_timeout(port, termios->c_cflag, baud); + serial8250_set_errors_and_ignores(port, termios); + serial8250_set_ier(port, termios); + serial8250_set_efr(port, termios); + serial8250_set_divisor(port, baud, quot, frac); + serial8250_set_fcr(port, termios); + serial8250_set_mctrl(port, port->mctrl); } - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) @@ -2771,7 +2779,7 @@ EXPORT_SYMBOL(serial8250_do_set_termios); static void serial8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { if (port->set_termios) port->set_termios(port, termios, old); @@ -2783,15 +2791,13 @@ void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios) { if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; - spin_lock_irq(&port->lock); + guard(uart_port_lock_irq)(port); serial8250_enable_ms(port); - spin_unlock_irq(&port->lock); } else { port->flags &= ~UPF_HARDPPS_CD; if (!UART_ENABLE_MS(port, termios->c_cflag)) { - spin_lock_irq(&port->lock); + guard(uart_port_lock_irq)(port); serial8250_disable_ms(port); - spin_unlock_irq(&port->lock); } } } @@ -2829,11 +2835,6 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt) { if (pt->port.mapsize) return pt->port.mapsize; - if (pt->port.iotype == UPIO_AU) { - if (pt->port.type == PORT_RT2880) - return 0x100; - return 0x1000; - } if (is_omap1_8250(pt)) return 0x16 << pt->port.regshift; @@ -2847,7 +2848,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) { unsigned int size = serial8250_port_size(up); struct uart_port *port = &up->port; - int ret = 0; switch (port->iotype) { case UPIO_AU: @@ -2857,29 +2857,29 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) case UPIO_MEM16: case UPIO_MEM: if (!port->mapbase) - break; + return -EINVAL; - if (!request_mem_region(port->mapbase, size, "serial")) { - ret = -EBUSY; - break; - } + if (!request_mem_region(port->mapbase, size, "serial")) + return -EBUSY; if (port->flags & UPF_IOREMAP) { port->membase = ioremap(port->mapbase, size); if (!port->membase) { release_mem_region(port->mapbase, size); - ret = -ENOMEM; + return -ENOMEM; } } - break; - + return 0; case UPIO_HUB6: case UPIO_PORT: if (!request_region(port->iobase, size, "serial")) - ret = -EBUSY; + return -EBUSY; + return 0; + case UPIO_UNKNOWN: break; } - return ret; + + return 0; } static void serial8250_release_std_resource(struct uart_8250_port *up) @@ -2909,6 +2909,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) case UPIO_PORT: release_region(port->iobase, size); break; + case UPIO_UNKNOWN: + break; } } @@ -2986,7 +2988,7 @@ static ssize_t rx_trig_bytes_show(struct device *dev, if (rxtrig_bytes < 0) return rxtrig_bytes; - return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); + return sysfs_emit(buf, "%d\n", rxtrig_bytes); } static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) @@ -2996,8 +2998,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) struct uart_8250_port *up = up_to_u8250p(uport); int rxtrig; - if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || - up->fifo_bug) + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) return -EINVAL; rxtrig = bytes_to_fcr_rxtrig(up, bytes); @@ -3081,13 +3082,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (flags & UART_CONFIG_TYPE) autoconfig(up); - if (port->rs485.flags & SER_RS485_ENABLED) - port->rs485_config(port, &port->rs485); - - /* if access method is AU, it is a 16550 with a quirk */ - if (port->type == PORT_16550A && port->iotype == UPIO_AU) - up->bugs |= UART_BUG_NOMSR; - /* HW bugs may trigger IRQ while IIR == NO_INT */ if (port->type == PORT_TEGRA) up->bugs |= UART_BUG_NOMSR; @@ -3105,7 +3099,7 @@ static void serial8250_config_port(struct uart_port *port, int flags) static int serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) { - if (ser->irq >= nr_irqs || ser->irq < 0 || + if (ser->irq >= irq_get_nr_irqs() || ser->irq < 0 || ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || ser->type == PORT_STARTECH) @@ -3135,6 +3129,7 @@ static const struct uart_ops serial8250_pops = { .break_ctl = serial8250_break_ctl, .startup = serial8250_startup, .shutdown = serial8250_shutdown, + .flush_buffer = serial8250_flush_buffer, .set_termios = serial8250_set_termios, .set_ldisc = serial8250_set_ldisc, .pm = serial8250_pm, @@ -3154,10 +3149,12 @@ void serial8250_init_port(struct uart_8250_port *up) struct uart_port *port = &up->port; spin_lock_init(&port->lock); + port->ctrl_id = 0; + port->pm = NULL; port->ops = &serial8250_pops; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); - up->cur_iotype = 0xFF; + up->cur_iotype = UPIO_UNKNOWN; } EXPORT_SYMBOL_GPL(serial8250_init_port); @@ -3190,12 +3187,17 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults); #ifdef CONFIG_SERIAL_8250_CONSOLE -static void serial8250_console_putchar(struct uart_port *port, int ch) +static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) +{ + serial_port_out(port, UART_TX, ch); +} + +static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch) { struct uart_8250_port *up = up_to_u8250p(port); wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out(port, UART_TX, ch); + serial8250_console_putchar(port, ch); } /* @@ -3208,15 +3210,69 @@ static void serial8250_console_restore(struct uart_8250_port *up) unsigned int baud, quot, frac = 0; termios.c_cflag = port->cons->cflag; - if (port->state->port.tty && termios.c_cflag == 0) + termios.c_ispeed = port->cons->ispeed; + termios.c_ospeed = port->cons->ospeed; + if (port->state->port.tty && termios.c_cflag == 0) { termios.c_cflag = port->state->port.tty->termios.c_cflag; + termios.c_ispeed = port->state->port.tty->termios.c_ispeed; + termios.c_ospeed = port->state->port.tty->termios.c_ospeed; + } baud = serial8250_get_baud_rate(port, &termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); - serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); + serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); +} + +static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + if (wait_for_lsr(up, UART_LSR_THRE)) + return; + } +} + +/* + * Print a string to the serial port using the device FIFO + * + * It sends fifosize bytes and then waits for the fifo + * to get empty. + */ +static void serial8250_console_fifo_write(struct uart_8250_port *up, + const char *s, unsigned int count) +{ + const char *end = s + count; + unsigned int fifosize = up->tx_loadsz; + struct uart_port *port = &up->port; + unsigned int tx_count = 0; + bool cr_sent = false; + unsigned int i; + + while (s != end) { + /* Allow timeout for each byte of a possibly full FIFO */ + fifo_wait_for_lsr(up, fifosize); + + for (i = 0; i < fifosize && s != end; ++i) { + if (*s == '\n' && !cr_sent) { + serial8250_console_putchar(port, '\r'); + cr_sent = true; + } else { + serial8250_console_putchar(port, *s++); + cr_sent = false; + } + } + tx_count = i; + } + + /* + * Allow timeout for each byte written since the caller will only wait + * for UART_LSR_BOTH_EMPTY using the timeout of a single character + */ + fifo_wait_for_lsr(up, tx_count); } /* @@ -3234,25 +3290,21 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, struct uart_8250_em485 *em485 = up->em485; struct uart_port *port = &up->port; unsigned long flags; - unsigned int ier; + unsigned int ier, use_fifo; int locked = 1; touch_nmi_watchdog(); if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* * First save the IER then disable the interrupts */ ier = serial_port_in(port, UART_IER); - - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); + serial8250_clear_IER(up); /* check scratch reg to see if port powered off during system sleep */ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { @@ -3262,22 +3314,45 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (em485) { if (em485->tx_stopped) - up->rs485_start_tx(up); + up->rs485_start_tx(up, false); mdelay(port->rs485.delay_rts_before_send); } - uart_console_write(port, s, count, serial8250_console_putchar); + use_fifo = (up->capabilities & UART_CAP_FIFO) && + /* + * BCM283x requires to check the fifo + * after each byte. + */ + !(up->capabilities & UART_CAP_MINI) && + /* + * tx_loadsz contains the transmit fifo size + */ + up->tx_loadsz > 1 && + (up->fcr & UART_FCR_ENABLE_FIFO) && + port->state && + test_bit(TTY_PORT_INITIALIZED, &port->state->port.iflags) && + /* + * After we put a data in the fifo, the controller will send + * it regardless of the CTS state. Therefore, only use fifo + * if we don't use control flow. + */ + !(up->port.flags & UPF_CONS_FLOW); + + if (likely(use_fifo)) + serial8250_console_fifo_write(up, s, count); + else + uart_console_write(port, s, count, serial8250_console_wait_putchar); /* * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(up, BOTH_EMPTY); + wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); if (em485) { mdelay(port->rs485.delay_rts_after_send); if (em485->tx_stopped) - up->rs485_stop_tx(up); + up->rs485_stop_tx(up, false); } serial_port_out(port, UART_IER, ier); @@ -3293,7 +3368,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, serial8250_modem_status(up); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static unsigned int probe_baud(struct uart_port *port) @@ -3347,4 +3422,5 @@ int serial8250_console_exit(struct uart_port *port) #endif /* CONFIG_SERIAL_8250_CONSOLE */ +MODULE_DESCRIPTION("Base port operations for 8250/16550-type serial ports"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index 11612d174716..6dd0190b4843 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -18,12 +18,10 @@ #include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/of.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/clk.h> -#include <linux/pm_runtime.h> #include "8250.h" @@ -62,7 +60,7 @@ static const struct of_device_id serial_pxa_dt_ids[] = { MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids); /* Uart divisor latch write */ -static void serial_pxa_dl_write(struct uart_8250_port *up, int value) +static void serial_pxa_dl_write(struct uart_8250_port *up, u32 value) { unsigned int dll; @@ -93,12 +91,11 @@ static int serial_pxa_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; struct pxa8250_data *data; - struct resource *mmres, *irqres; + struct resource *mmres; int ret; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) + if (!mmres) return -ENODEV; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); @@ -113,21 +110,22 @@ static int serial_pxa_probe(struct platform_device *pdev) if (ret) return ret; - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - uart.port.line = ret; - uart.port.type = PORT_XSCALE; - uart.port.iotype = UPIO_MEM32; uart.port.mapbase = mmres->start; - uart.port.regshift = 2; - uart.port.irq = irqres->start; - uart.port.fifosize = 64; uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE; uart.port.dev = &pdev->dev; uart.port.uartclk = clk_get_rate(data->clk); uart.port.pm = serial_pxa_pm; uart.port.private_data = data; + + ret = uart_read_port_properties(&uart.port); + if (ret) + return ret; + + uart.port.iotype = UPIO_MEM32; + uart.port.regshift = 2; + uart.port.fifosize = 64; + uart.tx_loadsz = 32; uart.dl_write = serial_pxa_dl_write; ret = serial8250_register_8250_port(&uart); @@ -145,15 +143,13 @@ static int serial_pxa_probe(struct platform_device *pdev) return ret; } -static int serial_pxa_remove(struct platform_device *pdev) +static void serial_pxa_remove(struct platform_device *pdev) { struct pxa8250_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_unprepare(data->clk); - - return 0; } static struct platform_driver serial_pxa_driver = { @@ -169,21 +165,7 @@ static struct platform_driver serial_pxa_driver = { module_platform_driver(serial_pxa_driver); -#ifdef CONFIG_SERIAL_8250_CONSOLE -static int __init early_serial_pxa_setup(struct earlycon_device *device, - const char *options) -{ - struct uart_port *port = &device->port; - - if (!(device->port.membase || device->port.iobase)) - return -ENODEV; - - port->regshift = 2; - return early_serial8250_setup(device, NULL); -} -OF_EARLYCON_DECLARE(early_pxa, "mrvl,pxa-uart", early_serial_pxa_setup); -#endif - MODULE_AUTHOR("Sergei Ianovich"); +MODULE_DESCRIPTION("driver for PXA on-board UARTS"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pxa2xx-uart"); diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c new file mode 100644 index 000000000000..fff9395948e3 --- /dev/null +++ b/drivers/tty/serial/8250/8250_rsa.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/moduleparam.h> + +#include <linux/serial.h> +#include <linux/serial_8250.h> + +#include "8250.h" + +#define PORT_RSA_MAX 4 +static unsigned long probe_rsa[PORT_RSA_MAX]; +static unsigned int probe_rsa_count; + +static const struct uart_ops *core_port_base_ops; + +static int rsa8250_request_resource(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned long start = UART_RSA_BASE << port->regshift; + unsigned int size = 8 << port->regshift; + + switch (port->iotype) { + case UPIO_HUB6: + case UPIO_PORT: + start += port->iobase; + if (!request_region(start, size, "serial-rsa")) + return -EBUSY; + return 0; + default: + return -EINVAL; + } +} + +static void rsa8250_release_resource(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned long offset = UART_RSA_BASE << port->regshift; + unsigned int size = 8 << port->regshift; + + switch (port->iotype) { + case UPIO_HUB6: + case UPIO_PORT: + release_region(port->iobase + offset, size); + break; + default: + break; + } +} + +static void univ8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int i; + + up->probe &= ~UART_PROBE_RSA; + if (port->type == PORT_RSA) { + if (rsa8250_request_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + } else if (flags & UART_CONFIG_TYPE) { + for (i = 0; i < probe_rsa_count; i++) { + if (probe_rsa[i] == up->port.iobase) { + if (rsa8250_request_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + break; + } + } + } + + core_port_base_ops->config_port(port, flags); + + if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA) + rsa8250_release_resource(up); +} + +static int univ8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + ret = core_port_base_ops->request_port(port); + if (ret == 0 && port->type == PORT_RSA) { + ret = rsa8250_request_resource(up); + if (ret < 0) + core_port_base_ops->release_port(port); + } + + return ret; +} + +static void univ8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (port->type == PORT_RSA) + rsa8250_release_resource(up); + core_port_base_ops->release_port(port); +} + +/* + * It is not allowed to directly reference any symbols from 8250.ko here as + * that would result in a dependency loop between the 8250.ko and + * 8250_base.ko modules. This function is called from 8250.ko and is used to + * break the symbolic dependency cycle. Anything that is needed from 8250.ko + * has to be passed as pointers to this function which then can adjust those + * variables on 8250.ko side or store them locally as needed. + */ +void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops) +{ + core_port_base_ops = core_ops; + ops->config_port = univ8250_config_port; + ops->request_port = univ8250_request_port; + ops->release_port = univ8250_release_port; +} +EXPORT_SYMBOL_FOR_MODULES(univ8250_rsa_support, "8250"); + +module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444); +MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); + +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __rsa_enable(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +/* + * If this is an RSA port, see if we can kick it up to the higher speed clock. + */ +void rsa_enable(struct uart_8250_port *up) +{ + if (up->port.type != PORT_RSA) + return; + + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + guard(uart_port_lock_irq)(&up->port); + __rsa_enable(up); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_out(up, UART_RSA_FRR, 0); +} + +/* + * Attempts to turn off the RSA FIFO and resets the RSA board back to 115kbps compat mode. It is + * unknown why interrupts were disabled in here. However, the caller is expected to preserve this + * behaviour by grabbing the spinlock before calling this function. + */ +void rsa_disable(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type != PORT_RSA) + return; + + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) + return; + + guard(uart_port_lock_irq)(&up->port); + + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; +} + +void rsa_autoconfig(struct uart_8250_port *up) +{ + /* Only probe for RSA ports if we got the region. */ + if (up->port.type != PORT_16550A) + return; + if (!(up->probe & UART_PROBE_RSA)) + return; + + if (__rsa_enable(up)) + up->port.type = PORT_RSA; +} + +void rsa_reset(struct uart_8250_port *up) +{ + if (up->port.type != PORT_RSA) + return; + + serial_out(up, UART_RSA_FRR, 0); +} diff --git a/drivers/tty/serial/8250/8250_rt288x.c b/drivers/tty/serial/8250/8250_rt288x.c new file mode 100644 index 000000000000..bf28b8a9a710 --- /dev/null +++ b/drivers/tty/serial/8250/8250_rt288x.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RT288x/Au1xxx driver + */ + +#include <linux/module.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> + +#include "8250.h" + +#define RT288X_DL 0x28 + +/* Au1x00/RT288x UART hardware has a weird register layout */ +static const u8 au_io_in_map[7] = { + [UART_RX] = 0, + [UART_IER] = 2, + [UART_IIR] = 3, + [UART_LCR] = 5, + [UART_MCR] = 6, + [UART_LSR] = 7, + [UART_MSR] = 8, +}; + +static const u8 au_io_out_map[5] = { + [UART_TX] = 1, + [UART_IER] = 2, + [UART_FCR] = 4, + [UART_LCR] = 5, + [UART_MCR] = 6, +}; + +static u32 au_serial_in(struct uart_port *p, unsigned int offset) +{ + if (offset >= ARRAY_SIZE(au_io_in_map)) + return UINT_MAX; + offset = au_io_in_map[offset]; + + return __raw_readl(p->membase + (offset << p->regshift)); +} + +static void au_serial_out(struct uart_port *p, unsigned int offset, u32 value) +{ + if (offset >= ARRAY_SIZE(au_io_out_map)) + return; + offset = au_io_out_map[offset]; + + __raw_writel(value, p->membase + (offset << p->regshift)); +} + +/* Au1x00 haven't got a standard divisor latch */ +static u32 au_serial_dl_read(struct uart_8250_port *up) +{ + return __raw_readl(up->port.membase + RT288X_DL); +} + +static void au_serial_dl_write(struct uart_8250_port *up, u32 value) +{ + __raw_writel(value, up->port.membase + RT288X_DL); +} + +int au_platform_setup(struct plat_serial8250_port *p) +{ + p->iotype = UPIO_AU; + + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; + p->dl_read = au_serial_dl_read; + p->dl_write = au_serial_dl_write; + + p->mapsize = 0x1000; + + p->bugs |= UART_BUG_NOMSR; + + return 0; +} +EXPORT_SYMBOL_GPL(au_platform_setup); + +int rt288x_setup(struct uart_port *p) +{ + struct uart_8250_port *up = up_to_u8250p(p); + + p->iotype = UPIO_AU; + + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; + up->dl_read = au_serial_dl_read; + up->dl_write = au_serial_dl_write; + + p->mapsize = 0x100; + + up->bugs |= UART_BUG_NOMSR; + + return 0; +} +EXPORT_SYMBOL_GPL(rt288x_setup); + +#ifdef CONFIG_SERIAL_8250_CONSOLE +static void au_putc(struct uart_port *port, unsigned char c) +{ + unsigned int status; + + au_serial_out(port, UART_TX, c); + + for (;;) { + status = au_serial_in(port, UART_LSR); + if (uart_lsr_tx_empty(status)) + break; + cpu_relax(); + } +} + +static void au_early_serial8250_write(struct console *console, + const char *s, unsigned int count) +{ + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; + + uart_console_write(port, s, count, au_putc); +} + +static int __init early_au_setup(struct earlycon_device *dev, const char *opt) +{ + rt288x_setup(&dev->port); + dev->con->write = au_early_serial8250_write; + + return 0; +} +OF_EARLYCON_DECLARE(palmchip, "ralink,rt2880-uart", early_au_setup); +#endif + +MODULE_DESCRIPTION("RT288x/Au1xxx UART driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c index c0ffad1572c6..2f3b0075763f 100644 --- a/drivers/tty/serial/8250/8250_tegra.c +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -11,6 +11,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/reset.h> #include <linux/slab.h> @@ -26,16 +27,17 @@ static void tegra_uart_handle_break(struct uart_port *p) { unsigned int status, tmout = 10000; - do { + while (1) { status = p->serial_in(p, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = p->serial_in(p, UART_RX); - else + if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))) break; + + p->serial_in(p, UART_RX); + if (--tmout == 0) break; udelay(1); - } while (1); + } } static int tegra_uart_probe(struct platform_device *pdev) @@ -55,25 +57,11 @@ static int tegra_uart_probe(struct platform_device *pdev) port = &port8250.port; spin_lock_init(&port->lock); - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | - UPF_FIXED_TYPE; - port->iotype = UPIO_MEM32; - port->regshift = 2; + port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->type = PORT_TEGRA; - port->irqflags |= IRQF_SHARED; port->dev = &pdev->dev; port->handle_break = tegra_uart_handle_break; - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - if (ret >= 0) - port->line = ret; - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - - port->irq = ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -86,12 +74,18 @@ static int tegra_uart_probe(struct platform_device *pdev) port->mapbase = res->start; port->mapsize = resource_size(res); + ret = uart_read_port_properties(port); + if (ret) + return ret; + + port->iotype = UPIO_MEM32; + port->regshift = 2; + uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); if (IS_ERR(uart->rst)) return PTR_ERR(uart->rst); - if (device_property_read_u32(&pdev->dev, "clock-frequency", - &port->uartclk)) { + if (!port->uartclk) { uart->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(uart->clk)) { dev_err(&pdev->dev, "failed to get clock!\n"); @@ -111,28 +105,28 @@ static int tegra_uart_probe(struct platform_device *pdev) ret = serial8250_register_8250_port(&port8250); if (ret < 0) - goto err_clkdisable; + goto err_ctrl_assert; platform_set_drvdata(pdev, uart); uart->line = ret; return 0; +err_ctrl_assert: + reset_control_assert(uart->rst); err_clkdisable: clk_disable_unprepare(uart->clk); return ret; } -static int tegra_uart_remove(struct platform_device *pdev) +static void tegra_uart_remove(struct platform_device *pdev) { struct tegra_uart *uart = platform_get_drvdata(pdev); serial8250_unregister_port(uart->line); reset_control_assert(uart->rst); clk_disable_unprepare(uart->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -174,7 +168,7 @@ static const struct of_device_id tegra_uart_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_uart_of_match); -static const struct acpi_device_id tegra_uart_acpi_match[] = { +static const struct acpi_device_id tegra_uart_acpi_match[] __maybe_unused = { { "NVDA0100", 0 }, { }, }; diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index e0b73a5402db..e3db60bf50c9 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -63,7 +63,7 @@ OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart", * The register map is slightly different from that of 8250. * IO callbacks must be overridden for correct access to FCR, LCR, MCR and SCR. */ -static unsigned int uniphier_serial_in(struct uart_port *p, int offset) +static u32 uniphier_serial_in(struct uart_port *p, unsigned int offset) { unsigned int valshift = 0; @@ -75,7 +75,7 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) break; case UART_LCR: valshift = 8; - /* fall through */ + fallthrough; case UART_MCR: offset = UNIPHIER_UART_LCR_MCR; break; @@ -92,7 +92,7 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) return (readl(p->membase + offset) >> valshift) & 0xff; } -static void uniphier_serial_out(struct uart_port *p, int offset, int value) +static void uniphier_serial_out(struct uart_port *p, unsigned int offset, u32 value) { unsigned int valshift = 0; bool normal = false; @@ -101,7 +101,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) case UART_SCR: /* No SCR for this hardware. Use CHAR as a scratch register */ valshift = 8; - /* fall through */ + fallthrough; case UART_FCR: offset = UNIPHIER_UART_CHAR_FCR; break; @@ -109,7 +109,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) valshift = 8; /* Divisor latch access bit does not exist. */ value &= ~UART_LCR_DLAB; - /* fall through */ + fallthrough; case UART_MCR: offset = UNIPHIER_UART_LCR_MCR; break; @@ -145,12 +145,12 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) * The divisor latch register exists at different address. * Override dl_read/write callbacks. */ -static int uniphier_serial_dl_read(struct uart_8250_port *up) +static u32 uniphier_serial_dl_read(struct uart_8250_port *up) { return readl(up->port.membase + UNIPHIER_UART_DLR); } -static void uniphier_serial_dl_write(struct uart_8250_port *up, int value) +static void uniphier_serial_dl_write(struct uart_8250_port *up, u32 value) { writel(value, up->port.membase + UNIPHIER_UART_DLR); } @@ -162,7 +162,6 @@ static int uniphier_uart_probe(struct platform_device *pdev) struct uniphier8250_priv *priv; struct resource *regs; void __iomem *membase; - int irq; int ret; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -175,23 +174,12 @@ static int uniphier_uart_probe(struct platform_device *pdev) if (!membase) return -ENOMEM; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; memset(&up, 0, sizeof(up)); - ret = of_alias_get_id(dev->of_node, "serial"); - if (ret < 0) { - dev_err(dev, "failed to get alias id\n"); - return ret; - } - up.port.line = ret; - priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { dev_err(dev, "failed to get clock\n"); @@ -211,7 +199,10 @@ static int uniphier_uart_probe(struct platform_device *pdev) up.port.mapbase = regs->start; up.port.mapsize = resource_size(regs); up.port.membase = membase; - up.port.irq = irq; + + ret = uart_read_port_properties(&up.port); + if (ret) + return ret; up.port.type = PORT_16550A; up.port.iotype = UPIO_MEM32; @@ -241,14 +232,12 @@ static int uniphier_uart_probe(struct platform_device *pdev) return 0; } -static int uniphier_uart_remove(struct platform_device *pdev) +static void uniphier_uart_remove(struct platform_device *pdev) { struct uniphier8250_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); clk_disable_unprepare(priv->clk); - - return 0; } static int __maybe_unused uniphier_uart_suspend(struct device *dev) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index d2ae033aea40..c488ff6f2865 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -15,8 +15,7 @@ config SERIAL_8250 here are those that are setting up dedicated Ethernet WWW/FTP servers, or users that have one of the various bus mice instead of a serial mouse and don't intend to use their machine's standard serial - port for anything. (Note that the Cyclades multi serial port driver - does not need this driver built in for it to work.) + port for anything. To compile this driver as a module, choose M here: the module will be called 8250. @@ -35,23 +34,6 @@ config SERIAL_8250 Most people will say Y or M here, so that they can use serial mice, modems and similar devices connecting to the standard serial ports. -config SERIAL_8250_DEPRECATED_OPTIONS - bool "Support 8250_core.* kernel options (DEPRECATED)" - depends on SERIAL_8250 - default y - help - In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to - accept kernel parameters in both forms like 8250_core.nr_uarts=4 and - 8250.nr_uarts=4. We now renamed the module back to 8250, but if - anybody noticed in 3.7 and changed their userspace we still have to - keep the 8250_core.* options around until they revert the changes - they already did. - - If 8250 is built as a module, this adds 8250_core alias instead. - - If you did not notice yet and/or you have userspace from pre-3.7, it - is safe (and recommended) to say N here. - config SERIAL_8250_PNP bool "8250/16550 PNP device support" if EXPERT depends on SERIAL_8250 && PNP @@ -72,14 +54,16 @@ config SERIAL_8250_16550A_VARIANTS console, you can say N here. config SERIAL_8250_FINTEK - bool "Support for Fintek F81216A LPC to 4 UART RS485 API" - depends on SERIAL_8250 + bool "Support for Fintek variants" + depends on SERIAL_8250 && HAS_IOPORT help - Selecting this option will add support for the RS485 capabilities - of the Fintek F81216A LPC to 4 UART. + Selecting this option will add support for the RS232 and RS485 + capabilities of the Fintek F81216A LPC to 4 UART as well similar + variants. If this option is not selected the device will be configured as a - standard 16550A serial port. + standard 16550A serial port, however the device may not function + correctly without this option enabled. If unsure, say N. @@ -117,9 +101,9 @@ config SERIAL_8250_CONSOLE If unsure, say N. -config SERIAL_8250_GSC +config SERIAL_8250_PARISC tristate - depends on SERIAL_8250 && GSC + depends on SERIAL_8250 && PARISC default SERIAL_8250 config SERIAL_8250_DMA @@ -130,9 +114,13 @@ config SERIAL_8250_DMA This builds DMA support that can be used with 8250/16650 compatible UART controllers that support DMA signaling. +config SERIAL_8250_PCILIB + bool + config SERIAL_8250_PCI tristate "8250/16550 PCI device support" depends on SERIAL_8250 && PCI + select SERIAL_8250_PCILIB default SERIAL_8250 help This builds standard PCI serial support. You may be able to @@ -143,7 +131,9 @@ config SERIAL_8250_PCI config SERIAL_8250_EXAR tristate "8250/16550 Exar/Commtech PCI/PCIe device support" - depends on SERIAL_8250_PCI + depends on SERIAL_8250 && PCI + select SERIAL_8250_PCILIB + select EEPROM_93CX6 default SERIAL_8250 help This builds support for XR17C1xx, XR17V3xx and some Commtech @@ -157,7 +147,7 @@ config SERIAL_8250_HP300 config SERIAL_8250_CS tristate "8250/16550 PCMCIA device support" - depends on PCMCIA && SERIAL_8250 + depends on PCMCIA && SERIAL_8250 && HAS_IOPORT help Say Y here to enable support for 16-bit PCMCIA serial devices, including serial port cards, modems, and the modem functions of @@ -217,16 +207,16 @@ config SERIAL_8250_EXTENDED config SERIAL_8250_MANY_PORTS bool "Support more than 4 legacy serial ports" - depends on SERIAL_8250_EXTENDED && !IA64 + depends on SERIAL_8250_EXTENDED help Say Y here if you have dumb serial boards other than the four standard COM 1/2/3/4 ports. This may happen if you have an AST FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available - from <http://www.tldp.org/docs.html#howto>), or other custom + from <https://www.tldp.org/docs.html#howto>), or other custom serial port hardware which acts similar to standard serial port hardware. If you only use the standard COM 1/2/3/4 ports, you can say N here to save some memory. You can also say Y if you have an - "intelligent" multiport card such as Cyclades, Digiboards, etc. + "intelligent" multiport card such as Digiboards, etc. # # Multi-port serial cards @@ -254,7 +244,9 @@ config SERIAL_8250_ASPEED_VUART tristate "Aspeed Virtual UART" depends on SERIAL_8250 depends on OF - depends on REGMAP && MFD_SYSCON + depends on MFD_SYSCON + depends on ARCH_ASPEED || COMPILE_TEST + select REGMAP help If you want to use the virtual UART (VUART) device on Aspeed BMC platforms, enable this option. This enables the 16550A- @@ -266,7 +258,7 @@ config SERIAL_8250_BOCA depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS help Say Y here if you have a Boca serial board. Please read the Boca - mini-HOWTO, available from <http://www.tldp.org/docs.html#howto> + mini-HOWTO, available from <https://www.tldp.org/docs.html#howto> To compile this driver as a module, choose M here: the module will be called 8250_boca. @@ -291,6 +283,16 @@ config SERIAL_8250_HUB6 To compile this driver as a module, choose M here: the module will be called 8250_hub6. +config SERIAL_8250_PCI1XXXX + tristate "Microchip 8250 based serial port" + depends on SERIAL_8250 && PCI + select SERIAL_8250_PCILIB + help + Select this option if you have a setup with Microchip PCIe + Switch with serial port enabled and wish to enable 8250 + serial driver for the serial interface. This driver support + will ensure to support baud rates upto 1.5Mpbs. + # # Misc. options/drivers. # @@ -362,9 +364,25 @@ config SERIAL_8250_BCM2835AUX If unsure, say N. config SERIAL_8250_FSL - bool - depends on SERIAL_8250_CONSOLE - default PPC || ARM || ARM64 + tristate "Freescale 16550 UART support" if COMPILE_TEST && !(PPC || ARM || ARM64) + depends on SERIAL_8250 + default SERIAL_8250 if PPC || ARM || ARM64 + help + Selecting this option enables a workaround for a break-detection + erratum for Freescale 16550 UARTs in the 8250 driver. It also + enables support for ACPI enumeration. + +config SERIAL_8250_DFL + tristate "DFL bus driver for Altera 16550 UART" + depends on SERIAL_8250 && FPGA_DFL + help + This option enables support for a Device Feature List (DFL) bus + driver for the Altera 16550 UART. One or more Altera 16550 UARTs + can be instantiated in a FPGA and then be discovered during + enumeration of the DFL bus. + + To compile this driver as a module, chose M here: the + module will be called 8250_dfl. config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" @@ -376,7 +394,8 @@ config SERIAL_8250_DW config SERIAL_8250_EM tristate "Support for Emma Mobile integrated serial port" - depends on SERIAL_8250 && ARM && HAVE_CLK + depends on SERIAL_8250 && HAVE_CLK + depends on ARCH_RENESAS || COMPILE_TEST help Selecting this option will add support for the integrated serial port hardware found on the Emma Mobile line of processors. @@ -384,7 +403,8 @@ config SERIAL_8250_EM config SERIAL_8250_IOC3 tristate "SGI IOC3 8250 UART support" - depends on SGI_MFD_IOC3 && SERIAL_8250 + depends on SERIAL_8250 + depends on SGI_MFD_IOC3 || COMPILE_TEST select SERIAL_8250_EXTENDED select SERIAL_8250_SHARE_IRQ help @@ -393,6 +413,19 @@ config SERIAL_8250_IOC3 behind the IOC3 device on those systems. Maximum baud speed is 38400bps using this driver. +config SERIAL_8250_KEBA + tristate "Support for KEBA 8250 UART" + depends on SERIAL_8250 + depends on KEBA_CP500 + help + Selecting this option will add support for KEBA UARTs. These UARTs + are used for the serial interfaces of KEBA PLCs. + + This driver can also be built as a module. If so, the module will + be called 8250_keba. + + If unsure, say N. + config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" depends on SERIAL_8250 @@ -404,7 +437,8 @@ config SERIAL_8250_RT288X config SERIAL_8250_OMAP tristate "Support for OMAP internal UART (8250 based driver)" - depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3) + depends on SERIAL_8250 + depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST help If you have a machine based on an Texas Instruments OMAP CPU you can enable its onboard serial ports by enabling this option. @@ -430,6 +464,16 @@ config SERIAL_8250_OMAP_TTYO_FIXUP not booting kernel because the serial console remains silent in case they forgot to update the command line. +config SERIAL_8250_LOONGSON + tristate "Loongson 8250 based serial port" + depends on SERIAL_8250 + depends on LOONGARCH || COMPILE_TEST + help + If you have a machine based on LoongArch CPU you can enable + its onboard serial ports by enabling this option. The option + is applicable to both devicetree and ACPI, say Y to this option. + If unsure, say N. + config SERIAL_8250_LPC18XX tristate "NXP LPC18xx/43xx serial port support" depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST) @@ -440,7 +484,8 @@ config SERIAL_8250_LPC18XX config SERIAL_8250_MT6577 tristate "Mediatek serial port support" - depends on SERIAL_8250 && ARCH_MEDIATEK + depends on SERIAL_8250 + depends on ARCH_MEDIATEK || COMPILE_TEST help If you have a Mediatek based board and want to use the serial port, say Y to this option. If unsure, say N. @@ -472,11 +517,12 @@ config SERIAL_8250_LPSS select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS) select RATIONAL help - Selecting this option will enable handling of the extra features - present on the UART found on various Intel platforms such as: + Selecting this option will enable handling of the UART found on + various Intel platforms such as: - Intel Baytrail SoC - Intel Braswell SoC - Intel Quark X1000 SoC + that are not covered by the more generic SERIAL_8250_PCI option. config SERIAL_8250_MID tristate "Support for serial ports on Intel MID platforms" @@ -487,14 +533,23 @@ config SERIAL_8250_MID select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID) select RATIONAL help - Selecting this option will enable handling of the extra features - present on the UART found on Intel Medfield SOC and various other - Intel platforms. + Selecting this option will enable handling of the UART found on + Intel Medfield SOC and various other Intel platforms that is not + covered by the more generic SERIAL_8250_PCI option. + +config SERIAL_8250_PERICOM + tristate "Support for Pericom and Acces I/O serial ports" + default SERIAL_8250 + depends on SERIAL_8250 && PCI + help + Selecting this option will enable handling of the Pericom and Acces + I/O UARTs that are not covered by the more generic SERIAL_8250_PCI + option. config SERIAL_8250_PXA tristate "PXA serial port support" depends on SERIAL_8250 - depends on ARCH_PXA || ARCH_MMP + depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST help If you have a machine based on an Intel XScale PXA2xx CPU you can enable its onboard serial ports by enabling this option. The option is @@ -510,6 +565,29 @@ config SERIAL_8250_TEGRA Select this option if you have machine with an NVIDIA Tegra SoC and wish to enable 8250 serial driver for the Tegra serial interfaces. +config SERIAL_8250_BCM7271 + tristate "Broadcom 8250 based serial port" + depends on SERIAL_8250 && (ARCH_BRCMSTB || COMPILE_TEST) + default ARCH_BRCMSTB + help + If you have a Broadcom STB based board and want to use the + enhanced features of the Broadcom 8250 based serial port, + including DMA support and high accuracy BAUD rates, say + Y to this option. If unsure, say N. + +config SERIAL_8250_NI + tristate "NI 16550 based serial port" + depends on SERIAL_8250 + depends on X86 || COMPILE_TEST + help + This driver supports the integrated serial ports on National + Instruments (NI) controller hardware. This is required for all NI + controller models with onboard RS-485 or dual-mode RS-485/RS-232 + ports. + + To compile this driver as a module, choose M here: the module + will be called 8250_ni. + config SERIAL_OF_PLATFORM tristate "Devicetree based probing for 8250 ports" depends on SERIAL_8250 && OF diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index a8bfb654d490..6d21402b4435 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -3,41 +3,59 @@ # Makefile for the 8250 serial device drivers. # -obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o +obj-$(CONFIG_SERIAL_8250) += 8250.o 8250-y := 8250_core.o +8250-y += 8250_platform.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o + +obj-$(CONFIG_SERIAL_8250) += 8250_base.o 8250_base-y := 8250_port.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o 8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o 8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o -obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o -obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o -obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o -obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o -obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o +8250_base-$(CONFIG_SERIAL_8250_PCILIB) += 8250_pcilib.o +8250_base-$(CONFIG_SERIAL_8250_RSA) += 8250_rsa.o + +obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o + +obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o -obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o -obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o -obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o +obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o -obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o -obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o -obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o -obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o +ifeq ($(CONFIG_SERIAL_8250),y) +obj-$(CONFIG_X86_INTEL_CE) += 8250_ce4100.o +endif +obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o +obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o +obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o +obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o +obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o +obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o +obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o +obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o -obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o +obj-$(CONFIG_SERIAL_8250_KEBA) += 8250_keba.o +obj-$(CONFIG_SERIAL_8250_LOONGSON) += 8250_loongson.o obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o -obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o -obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o -obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o +obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o +obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o +obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o +obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o +obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o +obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o +obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o +obj-$(CONFIG_SERIAL_8250_PCI1XXXX) += 8250_pci1xxxx.o +obj-$(CONFIG_SERIAL_8250_PERICOM) += 8250_pericom.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o +obj-$(CONFIG_SERIAL_8250_RT288X) += 8250_rt288x.o +obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o +obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o -obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index e3d10794dbba..58e279ea7ee0 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -90,12 +90,6 @@ struct serial_info { const struct serial_quirk *quirk; }; -struct serial_cfg_mem { - tuple_t tuple; - cisparse_t parse; - u_char buf[256]; -}; - /* * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6" * manfid 0x0160, 0x0104 @@ -306,6 +300,7 @@ static int serial_resume(struct pcmcia_device *link) static int serial_probe(struct pcmcia_device *link) { struct serial_info *info; + int ret; dev_dbg(&link->dev, "serial_attach()\n"); @@ -320,7 +315,15 @@ static int serial_probe(struct pcmcia_device *link) if (do_sound) link->config_flags |= CONF_ENABLE_SPKR; - return serial_config(link); + ret = serial_config(link); + if (ret) + goto free_info; + + return 0; + +free_info: + kfree(info); + return ret; } static void serial_detach(struct pcmcia_device *link) @@ -456,11 +459,11 @@ static int simple_config(struct pcmcia_device *link) * its base address, then try to grab any standard serial port * address, and finally try to get any free port. */ - if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) - goto found_port; - - dev_warn(&link->dev, "no usable port range found, giving up\n"); - return -1; + ret = pcmcia_loop_config(link, simple_config_check_notpicky, NULL); + if (ret) { + dev_warn(&link->dev, "no usable port range found, giving up\n"); + return ret; + } found_port: if (info->multi && (info->manfid == MANFID_3COM)) @@ -474,7 +477,7 @@ found_port: ret = pcmcia_enable_device(link); if (ret != 0) - return -1; + return ret; return setup_serial(link, info, link->resource[0]->start, link->irq); } @@ -559,16 +562,13 @@ static int multi_config(struct pcmcia_device *link) */ if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC)) { - int err; - if (link->config_index == 1 || link->config_index == 3) { - err = setup_serial(link, info, base2, - link->irq); + setup_serial(link, info, base2, link->irq); base2 = link->resource[0]->start; } else { - err = setup_serial(link, info, link->resource[0]->start, - link->irq); + setup_serial(link, info, link->resource[0]->start, + link->irq); } info->c950ctrl = base2; @@ -780,6 +780,7 @@ static const struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e), PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41), + PCMCIA_DEVICE_PROD_ID12("Option International", "GSM-Ready 56K/ISDN", 0x9d7cd6f5, 0xb23844aa), PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), @@ -807,7 +808,6 @@ static const struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"), PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"), - PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"), PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b), PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83), PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490), @@ -864,4 +864,5 @@ static struct pcmcia_driver serial_cs_driver = { }; module_pcmcia_driver(serial_cs_driver); +MODULE_DESCRIPTION("driver for PCMCIA serial devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 780908d43557..59221cce0028 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -8,6 +8,7 @@ menu "Serial drivers" config SERIAL_EARLYCON bool + depends on SERIAL_CORE help Support for early consoles with the earlycon parameter. This enables the console before standard serial driver is probed. The console is @@ -19,7 +20,7 @@ comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA + depends on ARM_AMBA || COMPILE_TEST select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have @@ -72,21 +73,21 @@ config SERIAL_AMBA_PL011_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_EARLYCON_ARM_SEMIHOST - bool "Early console using ARM semihosting" - depends on ARM64 || ARM +config SERIAL_EARLYCON_SEMIHOST + bool "Early console using Arm compatible semihosting" + depends on ARM64 || ARM || RISCV select SERIAL_CORE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help - Support for early debug console using ARM semihosting. This enables - the console before standard serial driver is probed. This is enabled - with "earlycon=smh" on the kernel command line. The console is - enabled when early_param is processed. + Support for early debug console using Arm compatible semihosting. + This enables the console before standard serial driver is probed. + This is enabled with "earlycon=smh" on the kernel command line. + The console is enabled when early_param is processed. config SERIAL_EARLYCON_RISCV_SBI bool "Early console using RISC-V SBI" - depends on RISCV_SBI_V01 + depends on RISCV_SBI select SERIAL_CORE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON @@ -126,7 +127,8 @@ config SERIAL_SB1250_DUART_CONSOLE config SERIAL_ATMEL bool "AT91 on-chip serial port support" - depends on ARCH_AT91 || COMPILE_TEST + depends on COMMON_CLK + depends on ARCH_MICROCHIP || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB select MFD_AT91_USART @@ -138,6 +140,7 @@ config SERIAL_ATMEL_CONSOLE bool "Support for console on AT91 serial port" depends on SERIAL_ATMEL=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Say Y here if you wish to use an on-chip UART on a Atmel AT91 processor as the system console (the system @@ -176,28 +179,9 @@ config SERIAL_ATMEL_TTYAT Say Y if you have an external 8250/16C550 UART. If unsure, say N. -config SERIAL_KGDB_NMI - bool "Serial console over KGDB NMI debugger port" - depends on KGDB_SERIAL_CONSOLE - help - This special driver allows you to temporary use NMI debugger port - as a normal console (assuming that the port is attached to KGDB). - - Unlike KDB's disable_nmi command, with this driver you are always - able to go back to the debugger using KGDB escape sequence ($3#33). - This is because this console driver processes the input in NMI - context, and thus is able to intercept the magic sequence. - - Note that since the console interprets input and uses polling - communication methods, for things like PPP you still must fully - detach debugger port from the KGDB NMI (i.e. disable_nmi), and - use raw console. - - If unsure, say N. - config SERIAL_MESON tristate "Meson serial port support" - depends on ARCH_MESON + depends on ARCH_MESON || COMPILE_TEST select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Amlogic @@ -205,7 +189,7 @@ config SERIAL_MESON config SERIAL_MESON_CONSOLE bool "Support for console on meson" - depends on SERIAL_MESON=y + depends on SERIAL_MESON select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help @@ -235,33 +219,27 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || ARCH_ARTPEC || COMPILE_TEST select SERIAL_CORE help - Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, - providing /dev/ttySAC0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured. + Support for the on-chip UARTs on the Samsung + S3C64xx/S5Pv210/Exynos and Apple M1 SoCs, providing + /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of + these ports, depending on how the serial port pins are configured. -config SERIAL_SAMSUNG_UARTS_4 - bool - depends on SERIAL_SAMSUNG - default y if !(CPU_S3C2410 || CPU_S3C2412 || CPU_S3C2440 || CPU_S3C2442) - help - Internal node for the common case of 4 Samsung compatible UARTs + Choose Y/M here only if you build for such SoC. config SERIAL_SAMSUNG_UARTS int depends on SERIAL_SAMSUNG - default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416 - default 3 + default 4 help Select the number of available UART ports for the Samsung S3C serial driver config SERIAL_SAMSUNG_CONSOLE bool "Support for console on Samsung SoC serial port" - depends on SERIAL_SAMSUNG=y + depends on SERIAL_SAMSUNG select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help @@ -275,31 +253,9 @@ config SERIAL_SAMSUNG_CONSOLE your boot loader about how to pass options to the kernel at boot time.) -config SERIAL_SIRFSOC - tristate "SiRF SoC Platform Serial port support" - depends on ARCH_SIRF - select SERIAL_CORE - help - Support for the on-chip UART on the CSR SiRFprimaII series, - providing /dev/ttySiRF0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured). - -config SERIAL_SIRFSOC_CONSOLE - bool "Support for console on SiRF SoC serial port" - depends on SERIAL_SIRFSOC=y - select SERIAL_CORE_CONSOLE - help - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySiRFx". (Try "man bootparam" or see the documentation of - your boot loader about how to pass options to the kernel at - boot time.) - config SERIAL_TEGRA tristate "NVIDIA Tegra20/30 SoC serial controller" - depends on ARCH_TEGRA && TEGRA20_APB_DMA + depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the NVIDIA Tegra series SOCs @@ -310,7 +266,8 @@ config SERIAL_TEGRA config SERIAL_TEGRA_TCU tristate "NVIDIA Tegra Combined UART" - depends on ARCH_TEGRA && TEGRA_HSP_MBOX + depends on MAILBOX + depends on (ARCH_TEGRA && TEGRA_HSP_MBOX) || COMPILE_TEST select SERIAL_CORE help Support for the mailbox-based TCU (Tegra Combined UART) serial port. @@ -330,18 +287,45 @@ config SERIAL_TEGRA_TCU_CONSOLE If unsure, say Y. +config SERIAL_TEGRA_UTC + tristate "NVIDIA Tegra UART Trace Controller" + depends on ARCH_TEGRA || COMPILE_TEST + select SERIAL_CORE + help + Support for Tegra UTC (UART Trace controller) client serial port. + + UTC is a HW based serial port that allows multiplexing multiple data + streams of up to 16 UTC clients into a single hardware serial port. + +config SERIAL_TEGRA_UTC_CONSOLE + bool "Support for console on a Tegra UTC serial port" + depends on SERIAL_TEGRA_UTC + select SERIAL_CORE_CONSOLE + default SERIAL_TEGRA_UTC + help + If you say Y here, it will be possible to use a Tegra UTC client as + the system console (the system console is the device which receives + all kernel messages and warnings and which allows logins in single + user mode). + + If unsure, say Y. + config SERIAL_MAX3100 - tristate "MAX3100 support" + tristate "MAX3100/3110/3111/3222 support" depends on SPI select SERIAL_CORE help - MAX3100 chip support + This selects support for an advanced UART from Maxim. + Supported ICs are MAX3100, MAX3110, MAX3111, MAX3222. + + Say Y here if you want to support these ICs. config SERIAL_MAX310X tristate "MAX310X support" depends on SPI_MASTER select SERIAL_CORE select REGMAP_SPI if SPI_MASTER + select REGMAP_I2C if I2C help This selects support for an advanced UART from Maxim (Dallas). Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830. @@ -444,7 +428,7 @@ config SERIAL_PXA config SERIAL_PXA_NON8250 bool - depends on !SERIAL_8250 + depends on !SERIAL_8250 || COMPILE_TEST config SERIAL_PXA_CONSOLE bool "Console on PXA serial port (DEPRECATED)" @@ -473,8 +457,8 @@ config SERIAL_SA1100 help If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you can enable its onboard serial port by enabling this option. - Please read <file:Documentation/arm/sa1100/serial_uart.rst> for further - info. + Please read <file:Documentation/arch/arm/sa1100/serial_uart.rst> for + further info. config SERIAL_SA1100_CONSOLE bool "Console on SA1100 serial port" @@ -502,20 +486,31 @@ config SERIAL_IMX can enable its onboard serial port by enabling this option. config SERIAL_IMX_CONSOLE - bool "Console on IMX serial port" - depends on SERIAL_IMX=y + tristate "Console on IMX serial port" + depends on SERIAL_IMX select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON if OF help If you have enabled the serial port on the Freescale IMX - CPU you can make it the console by answering Y to this option. + CPU you can make it the console by answering Y/M to this option. - Even if you say Y here, the currently visible virtual console + Even if you say Y/M here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as "console=ttymxc0". (Try "man bootparam" or see the documentation of your bootloader about how to pass options to the kernel at boot time.) +config SERIAL_IMX_EARLYCON + bool "Earlycon on IMX serial port" + depends on ARCH_MXC || COMPILE_TEST + depends on OF + select SERIAL_CORE + select SERIAL_EARLYCON + select SERIAL_CORE_CONSOLE + default y if SERIAL_IMX_CONSOLE + help + If you have enabled the earlycon on the Freescale IMX + CPU you can make it the earlycon by answering Y to this option. + config SERIAL_UARTLITE tristate "Xilinx uartlite serial port support" depends on HAS_IOMEM @@ -544,6 +539,9 @@ config SERIAL_UARTLITE_NR_UARTS help Set this to the number of uartlites in your system, or the number you think you might implement. + If maximum number of uartlite serial ports is more than 4, then the + driver uses dynamic allocation instead of static allocation for major + number. config SERIAL_SUNCORE bool @@ -608,21 +606,6 @@ config SERIAL_MUX_CONSOLE select SERIAL_CORE_CONSOLE default y -config PDC_CONSOLE - bool "PDC software console support" - depends on PARISC && !SERIAL_MUX && VT - help - Saying Y here will enable the software based PDC console to be - used as the system console. This is useful for machines in - which the hardware based console has not been written yet. The - following steps must be completed to use the PDC console: - - 1. create the device entry (mknod /dev/ttyB0 c 11 0) - 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 - 3. Add device ttyB0 to /etc/securetty (if you want to log on as - root on this console.) - 4. Change the kernel command console parameter to: console=ttyB0 - config SERIAL_SUNSAB tristate "Sun Siemens SAB82532 serial support" depends on SPARC && PCI @@ -661,7 +644,7 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST + depends on SUPERH || ARCH_RENESAS || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB @@ -670,7 +653,6 @@ config SERIAL_SH_SCI_NR_UARTS range 1 64 if 64BIT range 1 32 if !64BIT depends on SERIAL_SH_SCI - default "3" if H8300 default "10" if SUPERH default "18" if ARCH_RENESAS default "2" @@ -686,28 +668,19 @@ config SERIAL_SH_SCI_EARLYCON depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON - default ARCH_RENESAS || H8300 + default ARCH_RENESAS config SERIAL_SH_SCI_DMA bool "DMA support" if EXPERT depends on SERIAL_SH_SCI && DMA_ENGINE default ARCH_RENESAS -config SERIAL_PNX8XXX - bool "Enable PNX8XXX SoCs' UART Support" - depends on SOC_PNX833X - select SERIAL_CORE - help - If you have a MIPS-based Philips SoC such as PNX8330 and you want - to use serial ports, say Y. Otherwise, say N. - -config SERIAL_PNX8XXX_CONSOLE - bool "Enable PNX8XX0 serial console" - depends on SERIAL_PNX8XXX - select SERIAL_CORE_CONSOLE +config SERIAL_RSCI + tristate "Support for Renesas RZ/T2H SCI variant" + depends on SERIAL_SH_SCI help - If you have a MIPS-based Philips SoC such as PNX8330 and you want - to use serial console, say Y. Otherwise, say N. + Support for the RZ/T2H SCI variant with fifo. + Say Y if you want to be able to use the RZ/T2H SCI serial port. config SERIAL_HS_LPC32XX tristate "LPC32XX high speed serial port support" @@ -809,7 +782,7 @@ config SERIAL_CPM depends on CPM2 || CPM1 select SERIAL_CORE help - This driver supports the SCC and SMC serial ports on Motorola + This driver supports the SCC and SMC serial ports on Motorola embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx) config SERIAL_CPM_CONSOLE @@ -830,7 +803,7 @@ config SERIAL_CPM_CONSOLE config SERIAL_PIC32 tristate "Microchip PIC32 serial support" - depends on MACH_PIC32 + depends on MACH_PIC32 || (MIPS && COMPILE_TEST) select SERIAL_CORE help If you have a PIC32, this driver supports the serial ports. @@ -841,7 +814,7 @@ config SERIAL_PIC32 config SERIAL_PIC32_CONSOLE bool "PIC32 serial console support" - depends on SERIAL_PIC32 + depends on SERIAL_PIC32=y select SERIAL_CORE_CONSOLE help If you have a PIC32, this driver supports the putting a console on one @@ -878,7 +851,8 @@ config SERIAL_MPC52xx_CONSOLE_BAUD config SERIAL_ICOM tristate "IBM Multiport Serial Adapter" - depends on PCI && PPC_PSERIES + depends on PCI + depends on PPC_PSERIES || COMPILE_TEST select SERIAL_CORE select FW_LOADER help @@ -912,26 +886,9 @@ config SERIAL_TXX9_STDSERIAL bool "TX39XX/49XX SIO act as standard serial" depends on !SERIAL_8250 && SERIAL_TXX9 -config SERIAL_VR41XX - tristate "NEC VR4100 series Serial Interface Unit support" - depends on CPU_VR41XX - select SERIAL_CORE - help - If you have a NEC VR4100 series processor and you want to use - Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU) - (not include VR4111/VR4121 DSIU), say Y. Otherwise, say N. - -config SERIAL_VR41XX_CONSOLE - bool "Enable NEC VR4100 series Serial Interface Unit console" - depends on SERIAL_VR41XX=y - select SERIAL_CORE_CONSOLE - help - If you have a NEC VR4100 series processor and you want to use - a console on a serial port, say Y. Otherwise, say N. - config SERIAL_JSM tristate "Digi International NEO and Classic PCI Support" - depends on PCI + depends on PCI && HAS_IOPORT select SERIAL_CORE help This is a driver for Digi International's Neo and Classic series @@ -947,7 +904,7 @@ config SERIAL_JSM config SERIAL_MSM tristate "MSM on-chip serial port support" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -971,9 +928,17 @@ config SERIAL_QCOM_GENI_CONSOLE Serial console driver for Qualcomm Technologies Inc's GENI based QUP hardware. +config SERIAL_QCOM_GENI_UART_PORTS + int "Maximum number of GENI UART ports" + depends on SERIAL_QCOM_GENI + default "8" + help + Set this to the maximum number of serial ports you want the driver + to support. + config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" - depends on ARCH_VT8500 + depends on ARCH_VT8500 || COMPILE_TEST select SERIAL_CORE config SERIAL_VT8500_CONSOLE @@ -983,7 +948,7 @@ config SERIAL_VT8500_CONSOLE config SERIAL_OMAP tristate "OMAP serial port support" - depends on ARCH_OMAP2PLUS + depends on (ARCH_OMAP2PLUS && !SERIAL_8250_OMAP) || COMPILE_TEST select SERIAL_CORE help If you have a machine based on an Texas Instruments OMAP CPU you @@ -1011,6 +976,7 @@ config SERIAL_OMAP_CONSOLE config SERIAL_SIFIVE tristate "SiFive UART support" depends on OF + default ARCH_SIFIVE || ARCH_CANAAN select SERIAL_CORE help Select this option if you are building a kernel for a device that @@ -1020,6 +986,7 @@ config SERIAL_SIFIVE config SERIAL_SIFIVE_CONSOLE bool "Console on SiFive UART" depends on SERIAL_SIFIVE=y + default ARCH_SIFIVE || ARCH_CANAAN select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help @@ -1075,42 +1042,32 @@ config SERIAL_SCCNXP_CONSOLE help Support for console on SCCNXP serial ports. -config SERIAL_SC16IS7XX_CORE - tristate - config SERIAL_SC16IS7XX - tristate "SC16IS7xx serial support" + tristate "NXP SC16IS7xx UART support" + depends on SPI_MASTER || I2C || COMPILE_TEST select SERIAL_CORE - depends on (SPI_MASTER && !I2C) || I2C + select SERIAL_SC16IS7XX_SPI if SPI_MASTER + select SERIAL_SC16IS7XX_I2C if I2C help - This selects support for SC16IS7xx serial ports. - Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, - SC16IS760 and SC16IS762. Select supported buses using options below. + Core driver for NXP SC16IS7xx UARTs. + Supported ICs are: + + SC16IS740 + SC16IS741 + SC16IS750 + SC16IS752 + SC16IS760 + SC16IS762 + + The driver supports both I2C and SPI interfaces. config SERIAL_SC16IS7XX_I2C - bool "SC16IS7xx for I2C interface" - depends on SERIAL_SC16IS7XX - depends on I2C - select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX - select REGMAP_I2C if I2C - default y - help - Enable SC16IS7xx driver on I2C bus, - If required say y, and say n to i2c if not required, - Enabled by default to support oldconfig. - You must select at least one bus for the driver to be built. + tristate + select REGMAP_I2C config SERIAL_SC16IS7XX_SPI - bool "SC16IS7xx for spi interface" - depends on SERIAL_SC16IS7XX - depends on SPI_MASTER - select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX - select REGMAP_SPI if SPI_MASTER - help - Enable SC16IS7xx driver on SPI bus, - If required say y, and say n to spi if not required, - This is additional support to existing driver. - You must select at least one bus for the driver to be built. + tristate + select REGMAP_SPI config SERIAL_TIMBERDALE tristate "Support for timberdale UART" @@ -1122,7 +1079,8 @@ config SERIAL_TIMBERDALE config SERIAL_BCM63XX tristate "Broadcom BCM63xx/BCM33xx UART support" select SERIAL_CORE - depends on MIPS || ARM || COMPILE_TEST + depends on ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST + default ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC help This enables the driver for the onchip UART core found on the following chipsets: @@ -1209,13 +1167,6 @@ config SERIAL_ALTERA_UART_CONSOLE help Enable a Altera UART port to be the system console. -config SERIAL_IFX6X60 - tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB || COMPILE_TEST - depends on SPI && HAS_DMA - help - Support for the IFX6x60 modem devices on Intel MID platforms. - config SERIAL_PCH_UART tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" depends on PCI && (X86_32 || MIPS || COMPILE_TEST) @@ -1275,7 +1226,7 @@ config SERIAL_XILINX_PS_UART_CONSOLE config SERIAL_AR933X tristate "AR933X serial port support" - depends on HAVE_CLK && ATH79 + depends on (HAVE_CLK && ATH79) || (MIPS && COMPILE_TEST) select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB help @@ -1300,14 +1251,6 @@ config SERIAL_AR933X_NR_UARTS Set this to the number of serial ports you want the driver to support. -config SERIAL_EFM32_UART - tristate "EFM32 UART/USART port" - depends on ARM && (ARCH_EFM32 || COMPILE_TEST) - select SERIAL_CORE - help - This driver support the USART and UART ports on - Energy Micro's efm32 SoCs. - config SERIAL_MPS2_UART_CONSOLE bool "MPS2 UART console support" depends on SERIAL_MPS2_UART @@ -1321,11 +1264,6 @@ config SERIAL_MPS2_UART help This driver support the UART ports on ARM MPS2. -config SERIAL_EFM32_UART_CONSOLE - bool "EFM32 UART/USART console support" - depends on SERIAL_EFM32_UART=y - select SERIAL_CORE_CONSOLE - config SERIAL_ARC tristate "ARC UART driver support" select SERIAL_CORE @@ -1426,7 +1364,7 @@ config SERIAL_ST_ASC select SERIAL_CORE depends on ARM || COMPILE_TEST help - This driver is for the on-chip Asychronous Serial Controller on + This driver is for the on-chip Asynchronous Serial Controller on STMicroelectronics STi SoCs. ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality. It support all industry standard baud rates. @@ -1482,12 +1420,14 @@ config SERIAL_STM32 config SERIAL_STM32_CONSOLE bool "Support for console on STM32" - depends on SERIAL_STM32=y + depends on SERIAL_STM32 select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON config SERIAL_MVEBU_UART bool "Marvell EBU serial port support" depends on ARCH_MVEBU || COMPILE_TEST + depends on COMMON_CLK select SERIAL_CORE help This driver is for Marvell EBU SoC's UART. If you have a machine @@ -1572,6 +1512,113 @@ config SERIAL_MILBEAUT_USIO_CONSOLE receives all kernel messages and warnings and which allows logins in single user mode). +config SERIAL_LITEUART + tristate "LiteUART serial port support" + depends on HAS_IOMEM + depends on OF + depends on LITEX || COMPILE_TEST + select SERIAL_CORE + help + This driver is for the FPGA-based LiteUART serial controller from LiteX + SoC builder. + + Say 'Y' or 'M' here if you wish to use the LiteUART serial controller. + Otherwise, say 'N'. + +config SERIAL_LITEUART_MAX_PORTS + int "Maximum number of LiteUART ports" + depends on SERIAL_LITEUART + default "1" + help + Set this to the maximum number of serial ports you want the driver + to support. + +config SERIAL_LITEUART_CONSOLE + bool "LiteUART serial port console support" + depends on SERIAL_LITEUART=y + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Say 'Y' or 'M' here if you wish to use the FPGA-based LiteUART serial + controller from LiteX SoC builder as the system console + (the system console is the device which receives all kernel messages + and warnings and which allows logins in single user mode). + Otherwise, say 'N'. + +config SERIAL_SUNPLUS + tristate "Sunplus UART support" + depends on ARCH_SUNPLUS || COMPILE_TEST + select SERIAL_CORE + help + Select this option if you would like to use Sunplus serial port on + Sunplus SoC SP7021. + If you enable this option, Sunplus serial ports in the system will + be registered as ttySUPx. + This driver can also be built as a module. If so, the module will be + called sunplus-uart. + +config SERIAL_SUNPLUS_CONSOLE + bool "Console on Sunplus UART" + depends on SERIAL_SUNPLUS + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Select this option if you would like to use a Sunplus UART as the + system console. + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySUPx". + +config SERIAL_NUVOTON_MA35D1 + tristate "Nuvoton MA35D1 family UART support" + depends on ARCH_MA35 || COMPILE_TEST + select SERIAL_CORE + help + This driver supports Nuvoton MA35D1 family UART ports. If you would + like to use them, you must answer Y or M to this option. Note that + for use as console, it must be included in kernel and not as a + module. If you enable this option, Ma35D1 serial ports in the system + will be registered as ttyNVTx. + +config SERIAL_NUVOTON_MA35D1_CONSOLE + bool "Console on a Nuvotn MA35D1 family UART port" + depends on SERIAL_NUVOTON_MA35D1=y + select SERIAL_CORE_CONSOLE + help + Select this options if you'd like to use the UART port0 of the + Nuvoton MA35D1 family as a console. + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, + but you can alter that using a kernel command line option such as + "console=ttyNVTx". + +config SERIAL_ESP32 + tristate "Espressif ESP32 UART support" + depends on XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF) + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Driver for the UART controllers of the Espressif ESP32xx SoCs. + When earlycon option is enabled the following kernel command line + snippets may be used: + earlycon=esp32s3uart,mmio32,0x60000000,115200n8,40000000 + earlycon=esp32uart,mmio32,0x3ff40000,115200n8 + +config SERIAL_ESP32_ACM + tristate "Espressif ESP32 USB ACM gadget support" + depends on XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF) + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Driver for the CDC ACM gadget controller of the Espressif ESP32S3 + SoCs that share separate USB controller with the JTAG adapter. + When earlycon option is enabled the following kernel command line + snippet may be used: + earlycon=esp32s3acm,mmio32,0x60038000 + endmenu config SERIAL_MCTRL_GPIO diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index d056ee6cca33..a2ccbc508ec5 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -3,10 +3,11 @@ # Makefile for the kernel serial device drivers. # -obj-$(CONFIG_SERIAL_CORE) += serial_core.o +obj-$(CONFIG_SERIAL_CORE) += serial_base.o +serial_base-y := serial_core.o serial_base_bus.o serial_ctrl.o serial_port.o obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o -obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o +obj-$(CONFIG_SERIAL_EARLYCON_SEMIHOST) += earlycon-semihost.o obj-$(CONFIG_SERIAL_EARLYCON_RISCV_SBI) += earlycon-riscv-sbi.o # These Sparc drivers have to appear before others such as 8250 @@ -21,77 +22,81 @@ obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o obj-$(CONFIG_SERIAL_21285) += 21285.o # Now bring in any enabled 8250/16450/16550 type drivers. -obj-$(CONFIG_SERIAL_8250) += 8250/ +obj-y += 8250/ -obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o -obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o -obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o -obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o -obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o -obj-$(CONFIG_SERIAL_SA1100) += sa1100.o -obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o -obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o -obj-$(CONFIG_SERIAL_MAX3100) += max3100.o -obj-$(CONFIG_SERIAL_MAX310X) += max310x.o -obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o -obj-$(CONFIG_SERIAL_MUX) += mux.o -obj-$(CONFIG_SERIAL_MCF) += mcf.o -obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o -obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o -obj-$(CONFIG_SERIAL_DZ) += dz.o -obj-$(CONFIG_SERIAL_ZS) += zs.o -obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o -obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ -obj-$(CONFIG_SERIAL_IMX) += imx.o -obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o -obj-$(CONFIG_SERIAL_ICOM) += icom.o -obj-$(CONFIG_SERIAL_MESON) += meson_uart.o -obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o -obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o -obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o -obj-$(CONFIG_SERIAL_JSM) += jsm/ -obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o -obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o -obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o -obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o -obj-$(CONFIG_SERIAL_MSM) += msm_serial.o -obj-$(CONFIG_SERIAL_QCOM_GENI) += qcom_geni_serial.o -obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o -obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o -obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o -obj-$(CONFIG_SERIAL_QE) += ucc_uart.o -obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o +obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o +obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o +obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o +obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o -obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o -obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o -obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o -obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o -obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o -obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o -obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o -obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o -obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o -obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o -obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o -obj-$(CONFIG_SERIAL_ARC) += arc_uart.o -obj-$(CONFIG_SERIAL_RP2) += rp2.o -obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o -obj-$(CONFIG_SERIAL_FSL_LINFLEXUART) += fsl_linflexuart.o +obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o +obj-$(CONFIG_SERIAL_ARC) += arc_uart.o +obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o +obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o +obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o +obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o -obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o -obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o -obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o -obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o -obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o -obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o -obj-$(CONFIG_SERIAL_OWL) += owl-uart.o -obj-$(CONFIG_SERIAL_RDA) += rda-uart.o -obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o -obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o +obj-$(CONFIG_SERIAL_DZ) += dz.o +obj-$(CONFIG_SERIAL_ESP32) += esp32_uart.o +obj-$(CONFIG_SERIAL_ESP32_ACM) += esp32_acm.o +obj-$(CONFIG_SERIAL_FSL_LINFLEXUART) += fsl_linflexuart.o +obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o +obj-$(CONFIG_SERIAL_ICOM) += icom.o +obj-$(CONFIG_SERIAL_IMX) += imx.o +obj-$(CONFIG_SERIAL_IMX_EARLYCON) += imx_earlycon.o +obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o +obj-$(CONFIG_SERIAL_JSM) += jsm/ +obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o +obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o +obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o +obj-$(CONFIG_SERIAL_MAX3100) += max3100.o +obj-$(CONFIG_SERIAL_MAX310X) += max310x.o +obj-$(CONFIG_SERIAL_MCF) += mcf.o +obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o +obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o +obj-$(CONFIG_SERIAL_MESON) += meson_uart.o +obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o +obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o +obj-$(CONFIG_SERIAL_MSM) += msm_serial.o +obj-$(CONFIG_SERIAL_MUX) += mux.o +obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o +obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o +obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o +obj-$(CONFIG_SERIAL_OWL) += owl-uart.o +obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o +obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o +obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o +obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_QCOM_GENI) += qcom_geni_serial.o +obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_RDA) += rda-uart.o +obj-$(CONFIG_SERIAL_RP2) += rp2.o +obj-$(CONFIG_SERIAL_RSCI) += rsci.o +obj-$(CONFIG_SERIAL_SA1100) += sa1100.o +obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o +obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o +obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o +obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o +obj-$(CONFIG_SERIAL_SC16IS7XX_SPI) += sc16is7xx_spi.o +obj-$(CONFIG_SERIAL_SC16IS7XX_I2C) += sc16is7xx_i2c.o +obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o +obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o +obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o +obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o +obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o +obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o +obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o +obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o +obj-$(CONFIG_SERIAL_TEGRA_UTC) += tegra-utc.o +obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o +obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o +obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o +obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o +obj-$(CONFIG_SERIAL_ZS) += zs.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o -obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o +obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index c90e503d6b57..d47a62d1c9f7 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -9,6 +9,7 @@ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch> */ +#include <linux/bitfield.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -23,11 +24,9 @@ #include <linux/io.h> #include <linux/altera_jtaguart.h> -#define DRV_NAME "altera_jtaguart" - /* * Altera JTAG UART register definitions according to the Altera JTAG UART - * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf + * datasheet: https://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf */ #define ALTERA_JTAGUART_SIZE 8 @@ -48,21 +47,20 @@ #define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200 #define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400 #define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000 -#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16 -/* - * Local per-uart structure. - */ -struct altera_jtaguart { - struct uart_port port; - unsigned int sigs; /* Local copy of line sigs */ - unsigned long imr; /* Local IMR mirror */ -}; +static unsigned int altera_jtaguart_tx_space(struct uart_port *port, u32 *ctlp) +{ + u32 ctl = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG); + + if (ctlp) + *ctlp = ctl; + + return FIELD_GET(ALTERA_JTAGUART_CONTROL_WSPACE_MSK, ctl); +} static unsigned int altera_jtaguart_tx_empty(struct uart_port *port) { - return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0; + return altera_jtaguart_tx_space(port, NULL) ? TIOCSER_TEMT : 0; } static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port) @@ -76,29 +74,23 @@ static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs) static void altera_jtaguart_start_tx(struct uart_port *port) { - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - - pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + port->read_status_mask |= ALTERA_JTAGUART_CONTROL_WE_MSK; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); } static void altera_jtaguart_stop_tx(struct uart_port *port) { - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - - pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + port->read_status_mask &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); } static void altera_jtaguart_stop_rx(struct uart_port *port) { - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - - pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + port->read_status_mask &= ~ALTERA_JTAGUART_CONTROL_RE_MSK; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); } static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state) @@ -106,94 +98,61 @@ static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state) } static void altera_jtaguart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { /* Just copy the old termios settings back */ if (old) tty_termios_copy_hw(termios, old); } -static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) +static void altera_jtaguart_rx_chars(struct uart_port *port) { - struct uart_port *port = &pp->port; - unsigned char ch, flag; - unsigned long status; + u32 status; + u8 ch; while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) & ALTERA_JTAGUART_DATA_RVALID_MSK) { ch = status & ALTERA_JTAGUART_DATA_DATA_MSK; - flag = TTY_NORMAL; port->icount.rx++; if (uart_handle_sysrq_char(port, ch)) continue; - uart_insert_char(port, 0, 0, ch, flag); + uart_insert_char(port, 0, 0, ch, TTY_NORMAL); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } -static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) +static void altera_jtaguart_tx_chars(struct uart_port *port) { - struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned int pending, count; - - if (port->x_char) { - /* Send special char - probably flow control */ - writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG); - port->x_char = 0; - port->icount.tx++; - return; - } + unsigned int count; + u8 ch; - pending = uart_circ_chars_pending(xmit); - if (pending > 0) { - count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >> - ALTERA_JTAGUART_CONTROL_WSPACE_OFF; - if (count > pending) - count = pending; - if (count > 0) { - pending -= count; - while (count--) { - writel(xmit->buf[xmit->tail], - port->membase + ALTERA_JTAGUART_DATA_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if (pending < WAKEUP_CHARS) - uart_write_wakeup(port); - } - } + count = altera_jtaguart_tx_space(port, NULL); - if (pending == 0) { - pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); - } + uart_port_tx_limited(port, ch, count, + true, + writel(ch, port->membase + ALTERA_JTAGUART_DATA_REG), + ({})); } static irqreturn_t altera_jtaguart_interrupt(int irq, void *data) { struct uart_port *port = data; - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); unsigned int isr; isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >> - ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr; + ALTERA_JTAGUART_CONTROL_RI_OFF) & port->read_status_mask; - spin_lock(&port->lock); + uart_port_lock(port); if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK) - altera_jtaguart_rx_chars(pp); + altera_jtaguart_rx_chars(port); if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK) - altera_jtaguart_tx_chars(pp); + altera_jtaguart_tx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_RETVAL(isr); } @@ -208,43 +167,41 @@ static void altera_jtaguart_config_port(struct uart_port *port, int flags) static int altera_jtaguart_startup(struct uart_port *port) { - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); unsigned long flags; int ret; ret = request_irq(port->irq, altera_jtaguart_interrupt, 0, - DRV_NAME, port); + dev_name(port->dev), port); if (ret) { - pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d " - "interrupt vector=%d\n", port->line, port->irq); + dev_err(port->dev, "unable to attach Altera JTAG UART %d interrupt vector=%d\n", + port->line, port->irq); return ret; } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Enable RX interrupts now */ - pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + port->read_status_mask = ALTERA_JTAGUART_CONTROL_RE_MSK; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } static void altera_jtaguart_shutdown(struct uart_port *port) { - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable all interrupts now */ - pp->imr = 0; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + port->read_status_mask = 0; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); free_irq(port->irq, port); } @@ -295,51 +252,50 @@ static const struct uart_ops altera_jtaguart_ops = { }; #define ALTERA_JTAGUART_MAXPORTS 1 -static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; +static struct uart_port altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) -static void altera_jtaguart_console_putc(struct uart_port *port, int c) +static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c) { - unsigned long status; unsigned long flags; + u32 status; + + uart_port_lock_irqsave(port, &flags); + while (!altera_jtaguart_tx_space(port, &status)) { + uart_port_unlock_irqrestore(port, flags); - spin_lock_irqsave(&port->lock, flags); - while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) { - spin_unlock_irqrestore(&port->lock, flags); return; /* no connection activity */ } - spin_unlock_irqrestore(&port->lock, flags); + cpu_relax(); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); } writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } #else -static void altera_jtaguart_console_putc(struct uart_port *port, int c) +static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { - spin_unlock_irqrestore(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); + while (!altera_jtaguart_tx_space(port, NULL)) { + uart_port_unlock_irqrestore(port, flags); cpu_relax(); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); } writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } #endif static void altera_jtaguart_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; + struct uart_port *port = &altera_jtaguart_ports[co->index]; uart_console_write(port, s, count, altera_jtaguart_console_putc); } @@ -351,7 +307,7 @@ static int __init altera_jtaguart_console_setup(struct console *co, if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS) return -EINVAL; - port = &altera_jtaguart_ports[co->index].port; + port = &altera_jtaguart_ports[co->index]; if (port->membase == NULL) return -ENODEV; return 0; @@ -407,7 +363,7 @@ OF_EARLYCON_DECLARE(juart, "altr,juart-1.0", altera_jtaguart_earlycon_setup); static struct uart_driver altera_jtaguart_driver = { .owner = THIS_MODULE, - .driver_name = "altera_jtaguart", + .driver_name = KBUILD_MODNAME, .dev_name = "ttyJ", .major = ALTERA_JTAGUART_MAJOR, .minor = ALTERA_JTAGUART_MINOR, @@ -420,8 +376,9 @@ static int altera_jtaguart_probe(struct platform_device *pdev) struct altera_jtaguart_platform_uart *platp = dev_get_platdata(&pdev->dev); struct uart_port *port; - struct resource *res_irq, *res_mem; + struct resource *res_mem; int i = pdev->id; + int irq; /* -1 emphasizes that the platform must have one port, no .N suffix */ if (i == -1) @@ -430,7 +387,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev) if (i >= ALTERA_JTAGUART_MAXPORTS) return -EINVAL; - port = &altera_jtaguart_ports[i].port; + port = &altera_jtaguart_ports[i]; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res_mem) @@ -440,9 +397,11 @@ static int altera_jtaguart_probe(struct platform_device *pdev) else return -ENODEV; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res_irq) - port->irq = res_irq->start; + irq = platform_get_irq_optional(pdev, 0); + if (irq < 0 && irq != -ENXIO) + return irq; + if (irq > 0) + port->irq = irq; else if (platp) port->irq = platp->irq; else @@ -464,7 +423,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev) return 0; } -static int altera_jtaguart_remove(struct platform_device *pdev) +static void altera_jtaguart_remove(struct platform_device *pdev) { struct uart_port *port; int i = pdev->id; @@ -472,11 +431,9 @@ static int altera_jtaguart_remove(struct platform_device *pdev) if (i == -1) i = 0; - port = &altera_jtaguart_ports[i].port; + port = &altera_jtaguart_ports[i]; uart_remove_one_port(&altera_jtaguart_driver, port); iounmap(port->membase); - - return 0; } #ifdef CONFIG_OF @@ -490,9 +447,9 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match); static struct platform_driver altera_jtaguart_platform_driver = { .probe = altera_jtaguart_probe, - .remove = altera_jtaguart_remove, + .remove = altera_jtaguart_remove, .driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(altera_jtaguart_match), }, }; @@ -522,4 +479,4 @@ module_exit(altera_jtaguart_exit); MODULE_DESCRIPTION("Altera JTAG UART driver"); MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("platform:" KBUILD_MODNAME); diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 0e487ce091ac..837991dc4db9 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -24,7 +24,6 @@ #include <linux/io.h> #include <linux/altera_uart.h> -#define DRV_NAME "altera_uart" #define SERIAL_ALTERA_MAJOR 204 #define SERIAL_ALTERA_MINOR 213 @@ -164,18 +163,18 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (break_state == -1) pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; altera_uart_update_ctrl_reg(pp); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void altera_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, baudclk; @@ -187,10 +186,10 @@ static void altera_uart_set_termios(struct uart_port *port, tty_termios_copy_hw(termios, old); tty_termios_encode_baud_rate(termios, baud, baud); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, termios->c_cflag, baud); altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* * FIXME: port->read_status_mask and port->ignore_status_mask @@ -199,11 +198,10 @@ static void altera_uart_set_termios(struct uart_port *port, */ } -static void altera_uart_rx_chars(struct altera_uart *pp) +static void altera_uart_rx_chars(struct uart_port *port) { - struct uart_port *port = &pp->port; - unsigned char ch, flag; unsigned short status; + u8 ch, flag; while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) & ALTERA_UART_STATUS_RRDY_MSK) { @@ -243,64 +241,41 @@ static void altera_uart_rx_chars(struct altera_uart *pp) flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } -static void altera_uart_tx_chars(struct altera_uart *pp) +static void altera_uart_tx_chars(struct uart_port *port) { - struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - /* Send special char - probably flow control */ - altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG); - port->x_char = 0; - port->icount.tx++; - return; - } - - while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK) { - if (xmit->head == xmit->tail) - break; - altera_uart_writel(port, xmit->buf[xmit->tail], - ALTERA_UART_TXDATA_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } + u8 ch; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (xmit->head == xmit->tail) { - pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_update_ctrl_reg(pp); - } + uart_port_tx(port, ch, + altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TRDY_MSK, + altera_uart_writel(port, ch, ALTERA_UART_TXDATA_REG)); } static irqreturn_t altera_uart_interrupt(int irq, void *data) { struct uart_port *port = data; struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned long flags; unsigned int isr; isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr; - spin_lock(&port->lock); + uart_port_lock_irqsave(port, &flags); if (isr & ALTERA_UART_STATUS_RRDY_MSK) - altera_uart_rx_chars(pp); + altera_uart_rx_chars(port); if (isr & ALTERA_UART_STATUS_TRDY_MSK) - altera_uart_tx_chars(pp); - spin_unlock(&port->lock); + altera_uart_tx_chars(port); + uart_port_unlock_irqrestore(port, flags); return IRQ_RETVAL(isr); } static void altera_uart_timer(struct timer_list *t) { - struct altera_uart *pp = from_timer(pp, t, tmr); + struct altera_uart *pp = timer_container_of(pp, t, tmr); struct uart_port *port = &pp->port; altera_uart_interrupt(0, port); @@ -329,21 +304,21 @@ static int altera_uart_startup(struct uart_port *port) int ret; ret = request_irq(port->irq, altera_uart_interrupt, 0, - DRV_NAME, port); + dev_name(port->dev), port); if (ret) { - pr_err(DRV_NAME ": unable to attach Altera UART %d " - "interrupt vector=%d\n", port->line, port->irq); + dev_err(port->dev, "unable to attach Altera UART %d interrupt vector=%d\n", + port->line, port->irq); return ret; } } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Enable RX interrupts now */ pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; altera_uart_update_ctrl_reg(pp); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -353,18 +328,18 @@ static void altera_uart_shutdown(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable all interrupts now */ pp->imr = 0; altera_uart_update_ctrl_reg(pp); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); if (port->irq) free_irq(port->irq, port); else - del_timer_sync(&pp->tmr); + timer_delete_sync(&pp->tmr); } static const char *altera_uart_type(struct uart_port *port) @@ -440,7 +415,7 @@ static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) -static void altera_uart_console_putc(struct uart_port *port, int c) +static void altera_uart_console_putc(struct uart_port *port, unsigned char c) { while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TRDY_MSK)) @@ -542,7 +517,7 @@ OF_EARLYCON_DECLARE(uart, "altr,uart-1.0", altera_uart_earlycon_setup); */ static struct uart_driver altera_uart_driver = { .owner = THIS_MODULE, - .driver_name = DRV_NAME, + .driver_name = KBUILD_MODNAME, .dev_name = "ttyAL", .major = SERIAL_ALTERA_MAJOR, .minor = SERIAL_ALTERA_MINOR, @@ -555,7 +530,6 @@ static int altera_uart_probe(struct platform_device *pdev) struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev); struct uart_port *port; struct resource *res_mem; - struct resource *res_irq; int i = pdev->id; int ret; @@ -579,9 +553,11 @@ static int altera_uart_probe(struct platform_device *pdev) else return -EINVAL; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res_irq) - port->irq = res_irq->start; + ret = platform_get_irq_optional(pdev, 0); + if (ret < 0 && ret != -ENXIO) + return ret; + if (ret > 0) + port->irq = ret; else if (platp) port->irq = platp->irq; @@ -618,7 +594,7 @@ static int altera_uart_probe(struct platform_device *pdev) return 0; } -static int altera_uart_remove(struct platform_device *pdev) +static void altera_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); @@ -627,8 +603,6 @@ static int altera_uart_remove(struct platform_device *pdev) port->mapbase = 0; iounmap(port->membase); } - - return 0; } #ifdef CONFIG_OF @@ -642,9 +616,9 @@ MODULE_DEVICE_TABLE(of, altera_uart_match); static struct platform_driver altera_uart_platform_driver = { .probe = altera_uart_probe, - .remove = altera_uart_remove, + .remove = altera_uart_remove, .driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(altera_uart_match), }, }; @@ -674,5 +648,5 @@ module_exit(altera_uart_exit); MODULE_DESCRIPTION("Altera UART driver"); MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("platform:" KBUILD_MODNAME); MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR); diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 3284f34e9dfe..c3a7fad02ac9 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -110,38 +110,39 @@ static void pl010_enable_ms(struct uart_port *port) writel(cr, uap->port.membase + UART010_CR); } -static void pl010_rx_chars(struct uart_amba_port *uap) +static void pl010_rx_chars(struct uart_port *port) { - unsigned int status, ch, flag, rsr, max_count = 256; + unsigned int status, rsr, max_count = 256; + u8 ch, flag; - status = readb(uap->port.membase + UART01x_FR); + status = readb(port->membase + UART01x_FR); while (UART_RX_DATA(status) && max_count--) { - ch = readb(uap->port.membase + UART01x_DR); + ch = readb(port->membase + UART01x_DR); flag = TTY_NORMAL; - uap->port.icount.rx++; + port->icount.rx++; /* * Note that the error handling code is * out of the main execution path */ - rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; + rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX; if (unlikely(rsr & UART01x_RSR_ANY)) { - writel(0, uap->port.membase + UART01x_ECR); + writel(0, port->membase + UART01x_ECR); if (rsr & UART01x_RSR_BE) { rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); - uap->port.icount.brk++; - if (uart_handle_break(&uap->port)) + port->icount.brk++; + if (uart_handle_break(port)) goto ignore_char; } else if (rsr & UART01x_RSR_PE) - uap->port.icount.parity++; + port->icount.parity++; else if (rsr & UART01x_RSR_FE) - uap->port.icount.frame++; + port->icount.frame++; if (rsr & UART01x_RSR_OE) - uap->port.icount.overrun++; + port->icount.overrun++; - rsr &= uap->port.read_status_mask; + rsr &= port->read_status_mask; if (rsr & UART01x_RSR_BE) flag = TTY_BREAK; @@ -151,58 +152,35 @@ static void pl010_rx_chars(struct uart_amba_port *uap) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&uap->port, ch)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; - uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); + uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); ignore_char: - status = readb(uap->port.membase + UART01x_FR); + status = readb(port->membase + UART01x_FR); } - spin_unlock(&uap->port.lock); - tty_flip_buffer_push(&uap->port.state->port); - spin_lock(&uap->port.lock); + tty_flip_buffer_push(&port->state->port); } -static void pl010_tx_chars(struct uart_amba_port *uap) +static void pl010_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &uap->port.state->xmit; - int count; + u8 ch; - if (uap->port.x_char) { - writel(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { - pl010_stop_tx(&uap->port); - return; - } - - count = uap->port.fifosize >> 1; - do { - writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); - - if (uart_circ_empty(xmit)) - pl010_stop_tx(&uap->port); + uart_port_tx_limited(port, ch, port->fifosize >> 1, + true, + writel(ch, port->membase + UART01x_DR), + ({})); } static void pl010_modem_status(struct uart_amba_port *uap) { + struct uart_port *port = &uap->port; unsigned int status, delta; - writel(0, uap->port.membase + UART010_ICR); + writel(0, port->membase + UART010_ICR); - status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY; delta = status ^ uap->old_status; uap->old_status = status; @@ -211,65 +189,63 @@ static void pl010_modem_status(struct uart_amba_port *uap) return; if (delta & UART01x_FR_DCD) - uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); + uart_handle_dcd_change(port, status & UART01x_FR_DCD); if (delta & UART01x_FR_DSR) - uap->port.icount.dsr++; + port->icount.dsr++; if (delta & UART01x_FR_CTS) - uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + uart_handle_cts_change(port, status & UART01x_FR_CTS); - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); } static irqreturn_t pl010_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; + struct uart_port *port = &uap->port; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; - spin_lock(&uap->port.lock); + uart_port_lock(port); - status = readb(uap->port.membase + UART010_IIR); + status = readb(port->membase + UART010_IIR); if (status) { do { if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) - pl010_rx_chars(uap); + pl010_rx_chars(port); if (status & UART010_IIR_MIS) pl010_modem_status(uap); if (status & UART010_IIR_TIS) - pl010_tx_chars(uap); + pl010_tx_chars(port); if (pass_counter-- == 0) break; - status = readb(uap->port.membase + UART010_IIR); + status = readb(port->membase + UART010_IIR); } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS | UART010_IIR_TIS)); handled = 1; } - spin_unlock(&uap->port.lock); + uart_port_unlock(port); return IRQ_RETVAL(handled); } static unsigned int pl010_tx_empty(struct uart_port *port) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); - unsigned int status = readb(uap->port.membase + UART01x_FR); + unsigned int status = readb(port->membase + UART01x_FR); + return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; } static unsigned int pl010_get_mctrl(struct uart_port *port) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); unsigned int result = 0; unsigned int status; - status = readb(uap->port.membase + UART01x_FR); + status = readb(port->membase + UART01x_FR); if (status & UART01x_FR_DCD) result |= TIOCM_CAR; if (status & UART01x_FR_DSR) @@ -286,24 +262,22 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) container_of(port, struct uart_amba_port, port); if (uap->data) - uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl); + uap->data->set_mctrl(uap->dev, port->membase, mctrl); } static void pl010_break_ctl(struct uart_port *port, int break_state) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); unsigned long flags; unsigned int lcr_h; - spin_lock_irqsave(&uap->port.lock, flags); - lcr_h = readb(uap->port.membase + UART010_LCRH); + uart_port_lock_irqsave(port, &flags); + lcr_h = readb(port->membase + UART010_LCRH); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; - writel(lcr_h, uap->port.membase + UART010_LCRH); - spin_unlock_irqrestore(&uap->port.lock, flags); + writel(lcr_h, port->membase + UART010_LCRH); + uart_port_unlock_irqrestore(port, flags); } static int pl010_startup(struct uart_port *port) @@ -319,25 +293,25 @@ static int pl010_startup(struct uart_port *port) if (retval) goto out; - uap->port.uartclk = clk_get_rate(uap->clk); + port->uartclk = clk_get_rate(uap->clk); /* * Allocate the IRQ */ - retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap); + retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", uap); if (retval) goto clk_dis; /* * initialise the old status of the modem signals */ - uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY; /* * Finally, enable interrupts */ writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE, - uap->port.membase + UART010_CR); + port->membase + UART010_CR); return 0; @@ -355,17 +329,17 @@ static void pl010_shutdown(struct uart_port *port) /* * Free the interrupt */ - free_irq(uap->port.irq, uap); + free_irq(port->irq, uap); /* * disable all interrupts, disable the port */ - writel(0, uap->port.membase + UART010_CR); + writel(0, port->membase + UART010_CR); /* disable break condition and fifos */ - writel(readb(uap->port.membase + UART010_LCRH) & + writel(readb(port->membase + UART010_LCRH) & ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), - uap->port.membase + UART010_LCRH); + port->membase + UART010_LCRH); /* * Shut down the clock producer @@ -375,10 +349,8 @@ static void pl010_shutdown(struct uart_port *port) static void pl010_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot; @@ -386,7 +358,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); quot = uart_get_divisor(port, baud); switch (termios->c_cflag & CSIZE) { @@ -410,81 +382,78 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; } - if (uap->port.fifosize > 1) + if (port->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(port, &flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); - uap->port.read_status_mask = UART01x_RSR_OE; + port->read_status_mask = UART01x_RSR_OE; if (termios->c_iflag & INPCK) - uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - uap->port.read_status_mask |= UART01x_RSR_BE; + port->read_status_mask |= UART01x_RSR_BE; /* * Characters to ignore */ - uap->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & IGNBRK) { - uap->port.ignore_status_mask |= UART01x_RSR_BE; + port->ignore_status_mask |= UART01x_RSR_BE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - uap->port.ignore_status_mask |= UART01x_RSR_OE; + port->ignore_status_mask |= UART01x_RSR_OE; } /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) - uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX; + port->ignore_status_mask |= UART_DUMMY_RSR_RX; - /* first, disable everything */ - old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE; + old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE; if (UART_ENABLE_MS(port, termios->c_cflag)) old_cr |= UART010_CR_MSIE; - writel(0, uap->port.membase + UART010_CR); - /* Set baud rate */ quot -= 1; - writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM); - writel(quot & 0xff, uap->port.membase + UART010_LCRL); + writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM); + writel(quot & 0xff, port->membase + UART010_LCRL); /* * ----------v----------v----------v----------v----- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L * ----------^----------^----------^----------^----- */ - writel(lcr_h, uap->port.membase + UART010_LCRH); - writel(old_cr, uap->port.membase + UART010_CR); + writel(lcr_h, port->membase + UART010_LCRH); + writel(old_cr, port->membase + UART010_CR); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios) { if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); pl010_enable_ms(port); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } else { port->flags &= ~UPF_HARDPPS_CD; if (!UART_ENABLE_MS(port, termios->c_cflag)) { - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); pl010_disable_ms(port); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } } } @@ -530,7 +499,7 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; @@ -561,23 +530,22 @@ static struct uart_amba_port *amba_ports[UART_NR]; #ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE -static void pl010_console_putchar(struct uart_port *port, int ch) +static void pl010_console_putchar(struct uart_port *port, unsigned char ch) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); unsigned int status; do { - status = readb(uap->port.membase + UART01x_FR); + status = readb(port->membase + UART01x_FR); barrier(); } while (!UART_TX_READY(status)); - writel(ch, uap->port.membase + UART01x_DR); + writel(ch, port->membase + UART01x_DR); } static void pl010_console_write(struct console *co, const char *s, unsigned int count) { struct uart_amba_port *uap = amba_ports[co->index]; + struct uart_port *port = &uap->port; unsigned int status, old_cr; clk_enable(uap->clk); @@ -585,20 +553,20 @@ pl010_console_write(struct console *co, const char *s, unsigned int count) /* * First save the CR then disable the interrupts */ - old_cr = readb(uap->port.membase + UART010_CR); - writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR); + old_cr = readb(port->membase + UART010_CR); + writel(UART01x_CR_UARTEN, port->membase + UART010_CR); - uart_console_write(&uap->port, s, count, pl010_console_putchar); + uart_console_write(port, s, count, pl010_console_putchar); /* * Finally, wait for transmitter to become empty * and restore the TCR */ do { - status = readb(uap->port.membase + UART01x_FR); + status = readb(port->membase + UART01x_FR); barrier(); } while (status & UART01x_FR_BUSY); - writel(old_cr, uap->port.membase + UART010_CR); + writel(old_cr, port->membase + UART010_CR); clk_disable(uap->clk); } @@ -754,7 +722,7 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id) return ret; } -static int pl010_remove(struct amba_device *dev) +static void pl010_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); int i; @@ -770,8 +738,6 @@ static int pl010_remove(struct amba_device *dev) if (!busy) uart_unregister_driver(&amba_reg); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8efd7c2a34fe..7f17d288c807 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -20,6 +20,7 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/platform_device.h> #include <linux/sysrq.h> #include <linux/device.h> #include <linux/tty.h> @@ -36,14 +37,11 @@ #include <linux/delay.h> #include <linux/types.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> #include <linux/io.h> #include <linux/acpi.h> -#include "amba-pl011.h" - #define UART_NR 14 #define SERIAL_AMBA_MAJOR 204 @@ -52,8 +50,38 @@ #define AMBA_ISR_PASS_LIMIT 256 -#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) -#define UART_DUMMY_DR_RX (1 << 16) +#define UART_DR_ERROR (UART011_DR_OE | UART011_DR_BE | UART011_DR_PE | UART011_DR_FE) +#define UART_DUMMY_DR_RX BIT(16) + +enum { + REG_DR, + REG_ST_DMAWM, + REG_ST_TIMEOUT, + REG_FR, + REG_LCRH_RX, + REG_LCRH_TX, + REG_IBRD, + REG_FBRD, + REG_CR, + REG_IFLS, + REG_IMSC, + REG_RIS, + REG_MIS, + REG_ICR, + REG_DMACR, + REG_ST_XFCR, + REG_ST_XON1, + REG_ST_XON2, + REG_ST_XOFF1, + REG_ST_XOFF2, + REG_ST_ITCR, + REG_ST_ITIP, + REG_ST_ABCR, + REG_ST_ABIMSC, + + /* The size of the array - must be last */ + REG_ARRAY_SIZE, +}; static u16 pl011_std_offsets[REG_ARRAY_SIZE] = { [REG_DR] = UART01x_DR, @@ -97,7 +125,7 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .reg_offset = pl011_std_offsets, - .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8, .fr_busy = UART01x_FR_BUSY, .fr_dsr = UART01x_FR_DSR, .fr_cts = UART01x_FR_CTS, @@ -175,7 +203,7 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .reg_offset = pl011_st_offsets, - .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .ifls = UART011_IFLS_RX_HALF | UART011_IFLS_TX_HALF, .fr_busy = UART01x_FR_BUSY, .fr_dsr = UART01x_FR_DSR, .fr_cts = UART01x_FR_CTS, @@ -188,51 +216,20 @@ static struct vendor_data vendor_st = { .get_fifosize = get_fifosize_st, }; -static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = { - [REG_DR] = ZX_UART011_DR, - [REG_FR] = ZX_UART011_FR, - [REG_LCRH_RX] = ZX_UART011_LCRH, - [REG_LCRH_TX] = ZX_UART011_LCRH, - [REG_IBRD] = ZX_UART011_IBRD, - [REG_FBRD] = ZX_UART011_FBRD, - [REG_CR] = ZX_UART011_CR, - [REG_IFLS] = ZX_UART011_IFLS, - [REG_IMSC] = ZX_UART011_IMSC, - [REG_RIS] = ZX_UART011_RIS, - [REG_MIS] = ZX_UART011_MIS, - [REG_ICR] = ZX_UART011_ICR, - [REG_DMACR] = ZX_UART011_DMACR, -}; - -static unsigned int get_fifosize_zte(struct amba_device *dev) -{ - return 16; -} - -static struct vendor_data vendor_zte = { - .reg_offset = pl011_zte_offsets, - .access_32b = true, - .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .fr_busy = ZX_UART01x_FR_BUSY, - .fr_dsr = ZX_UART01x_FR_DSR, - .fr_cts = ZX_UART01x_FR_CTS, - .fr_ri = ZX_UART011_FR_RI, - .get_fifosize = get_fifosize_zte, -}; - /* Deals with DMA transactions */ -struct pl011_sgbuf { - struct scatterlist sg; - char *buf; +struct pl011_dmabuf { + dma_addr_t dma; + size_t len; + char *buf; }; struct pl011_dmarx_data { struct dma_chan *chan; struct completion complete; bool use_buf_b; - struct pl011_sgbuf sgbuf_a; - struct pl011_sgbuf sgbuf_b; + struct pl011_dmabuf dbuf_a; + struct pl011_dmabuf dbuf_b; dma_cookie_t cookie; bool running; struct timer_list timer; @@ -245,11 +242,19 @@ struct pl011_dmarx_data { struct pl011_dmatx_data { struct dma_chan *chan; - struct scatterlist sg; + dma_addr_t dma; + size_t len; char *buf; bool queued; }; +enum pl011_rs485_tx_state { + OFF, + WAIT_AFTER_RTS, + SEND, + WAIT_AFTER_SEND, +}; + /* * We wrap our port structure around the generic uart_port. */ @@ -258,15 +263,19 @@ struct uart_amba_port { const u16 *reg_offset; struct clk *clk; const struct vendor_data *vendor; - unsigned int dmacr; /* dma control reg */ unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int fifosize; /* vendor-specific */ - unsigned int old_cr; /* state during shutdown */ unsigned int fixed_baud; /* vendor-set fixed baud rate */ char type[12]; + ktime_t rs485_tx_drain_interval; /* nano */ + enum pl011_rs485_tx_state rs485_tx_state; + struct hrtimer trigger_start_tx; + struct hrtimer trigger_stop_tx; + bool console_line_ended; #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ + unsigned int dmacr; /* dma control reg */ bool using_tx_dma; bool using_rx_dma; struct pl011_dmarx_data dmarx; @@ -275,14 +284,16 @@ struct uart_amba_port { #endif }; +static unsigned int pl011_tx_empty(struct uart_port *port); + static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap, - unsigned int reg) + unsigned int reg) { return uap->reg_offset[reg]; } static unsigned int pl011_read(const struct uart_amba_port *uap, - unsigned int reg) + unsigned int reg) { void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg); @@ -291,7 +302,7 @@ static unsigned int pl011_read(const struct uart_amba_port *uap, } static void pl011_write(unsigned int val, const struct uart_amba_port *uap, - unsigned int reg) + unsigned int reg) { void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg); @@ -308,8 +319,10 @@ static void pl011_write(unsigned int val, const struct uart_amba_port *uap, */ static int pl011_fifo_to_tty(struct uart_amba_port *uap) { + unsigned int ch, fifotaken; + int sysrq; u16 status; - unsigned int ch, flag, fifotaken; + u8 flag; for (fifotaken = 0; fifotaken != 256; fifotaken++) { status = pl011_read(uap, REG_FR); @@ -327,10 +340,11 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) uap->port.icount.brk++; if (uart_handle_break(&uap->port)) continue; - } else if (ch & UART011_DR_PE) + } else if (ch & UART011_DR_PE) { uap->port.icount.parity++; - else if (ch & UART011_DR_FE) + } else if (ch & UART011_DR_FE) { uap->port.icount.frame++; + } if (ch & UART011_DR_OE) uap->port.icount.overrun++; @@ -344,16 +358,14 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&uap->port, ch & 255)) - continue; - - uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); + sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255); + if (!sysrq) + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); } return fifotaken; } - /* * All the DMA operation mode stuff goes inside this ifdef. * This assumes that you have a generic DMA device interface, @@ -363,32 +375,24 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) #define PL011_DMA_BUFFER_SIZE PAGE_SIZE -static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg, - enum dma_data_direction dir) +static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db, + enum dma_data_direction dir) { - dma_addr_t dma_addr; - - sg->buf = dma_alloc_coherent(chan->device->dev, - PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL); - if (!sg->buf) + db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE, + &db->dma, GFP_KERNEL); + if (!db->buf) return -ENOMEM; - - sg_init_table(&sg->sg, 1); - sg_set_page(&sg->sg, phys_to_page(dma_addr), - PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr)); - sg_dma_address(&sg->sg) = dma_addr; - sg_dma_len(&sg->sg) = PL011_DMA_BUFFER_SIZE; + db->len = PL011_DMA_BUFFER_SIZE; return 0; } -static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, - enum dma_data_direction dir) +static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db, + enum dma_data_direction dir) { - if (sg->buf) { + if (db->buf) { dma_free_coherent(chan->device->dev, - PL011_DMA_BUFFER_SIZE, sg->buf, - sg_dma_address(&sg->sg)); + PL011_DMA_BUFFER_SIZE, db->buf, db->dma); } } @@ -418,7 +422,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) /* We need platform data */ if (!plat || !plat->dma_filter) { - dev_info(uap->port.dev, "no DMA platform data\n"); + dev_dbg(uap->port.dev, "no DMA platform data\n"); return; } @@ -427,7 +431,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) dma_cap_set(DMA_SLAVE, mask); chan = dma_request_channel(mask, plat->dma_filter, - plat->dma_tx_param); + plat->dma_tx_param); if (!chan) { dev_err(uap->port.dev, "no TX DMA channel!\n"); return; @@ -441,9 +445,9 @@ static void pl011_dma_probe(struct uart_amba_port *uap) dma_chan_name(uap->dmatx.chan)); /* Optionally make use of an RX channel as well */ - chan = dma_request_slave_channel(dev, "rx"); + chan = dma_request_chan(dev, "rx"); - if (!chan && plat && plat->dma_rx_param) { + if (IS_ERR(chan) && plat && plat->dma_rx_param) { chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); if (!chan) { @@ -452,7 +456,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) } } - if (chan) { + if (!IS_ERR(chan)) { struct dma_slave_config rx_conf = { .src_addr = uap->port.mapbase + pl011_reg_to_offset(uap, REG_DR), @@ -468,12 +472,12 @@ static void pl011_dma_probe(struct uart_amba_port *uap) * If the controller does, check for suitable residue processing * otherwise assime all is well. */ - if (0 == dma_get_slave_caps(chan, &caps)) { + if (dma_get_slave_caps(chan, &caps) == 0) { if (caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) { dma_release_channel(chan); dev_info(uap->port.dev, - "RX DMA disabled - no residue processing\n"); + "RX DMA disabled - no residue processing\n"); return; } } @@ -502,18 +506,16 @@ static void pl011_dma_probe(struct uart_amba_port *uap) else uap->dmarx.poll_timeout = 3000; } else if (!plat && dev->of_node) { - uap->dmarx.auto_poll_rate = of_property_read_bool( - dev->of_node, "auto-poll"); + uap->dmarx.auto_poll_rate = + of_property_read_bool(dev->of_node, "auto-poll"); if (uap->dmarx.auto_poll_rate) { u32 x; - if (0 == of_property_read_u32(dev->of_node, - "poll-rate-ms", &x)) + if (of_property_read_u32(dev->of_node, "poll-rate-ms", &x) == 0) uap->dmarx.poll_rate = x; else uap->dmarx.poll_rate = 100; - if (0 == of_property_read_u32(dev->of_node, - "poll-timeout-ms", &x)) + if (of_property_read_u32(dev->of_node, "poll-timeout-ms", &x) == 0) uap->dmarx.poll_timeout = x; else uap->dmarx.poll_timeout = 3000; @@ -543,14 +545,15 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap); static void pl011_dma_tx_callback(void *data) { struct uart_amba_port *uap = data; + struct tty_port *tport = &uap->port.state->port; struct pl011_dmatx_data *dmatx = &uap->dmatx; unsigned long flags; u16 dmacr; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); if (uap->dmatx.queued) - dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, - DMA_TO_DEVICE); + dma_unmap_single(dmatx->chan->device->dev, dmatx->dma, + dmatx->len, DMA_TO_DEVICE); dmacr = uap->dmacr; uap->dmacr = dmacr & ~UART011_TXDMAE; @@ -566,9 +569,9 @@ static void pl011_dma_tx_callback(void *data) * get further refills (hence we check dmacr). */ if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || - uart_circ_empty(&uap->port.state->xmit)) { + kfifo_is_empty(&tport->xmit_fifo)) { uap->dmatx.queued = false; - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); return; } @@ -579,7 +582,7 @@ static void pl011_dma_tx_callback(void *data) */ pl011_start_tx_pio(uap); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); } /* @@ -596,7 +599,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) struct dma_chan *chan = dmatx->chan; struct dma_device *dma_dev = chan->device; struct dma_async_tx_descriptor *desc; - struct circ_buf *xmit = &uap->port.state->xmit; + struct tty_port *tport = &uap->port.state->port; unsigned int count; /* @@ -605,7 +608,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) * the standard interrupt handling. This ensures that we * issue a uart_write_wakeup() at the appropriate time. */ - count = uart_circ_chars_pending(xmit); + count = kfifo_len(&tport->xmit_fifo); if (count < (uap->fifosize >> 1)) { uap->dmatx.queued = false; return 0; @@ -621,33 +624,20 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) if (count > PL011_DMA_BUFFER_SIZE) count = PL011_DMA_BUFFER_SIZE; - if (xmit->tail < xmit->head) - memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); - else { - size_t first = UART_XMIT_SIZE - xmit->tail; - size_t second; - - if (first > count) - first = count; - second = count - first; - - memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); - if (second) - memcpy(&dmatx->buf[first], &xmit->buf[0], second); - } - - dmatx->sg.length = count; - - if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { + count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count); + dmatx->len = count; + dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count, + DMA_TO_DEVICE); + if (dma_mapping_error(dma_dev->dev, dmatx->dma)) { uap->dmatx.queued = false; dev_dbg(uap->port.dev, "unable to map TX DMA\n"); return -EBUSY; } - desc = dmaengine_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { - dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); + dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE); uap->dmatx.queued = false; /* * If DMA cannot be used right now, we complete this @@ -675,10 +665,9 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) * Now we know that DMA will fire, so advance the ring buffer * with the stuff we just dispatched. */ - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx += count; + uart_xmit_advance(&uap->port, count); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); return 1; @@ -757,8 +746,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; pl011_write(uap->im, uap, REG_IMSC); - } else + } else { ret = false; + } } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; pl011_write(uap->dmacr, uap, REG_DMACR); @@ -811,8 +801,8 @@ __acquires(&uap->port.lock) dmaengine_terminate_async(uap->dmatx.chan); if (uap->dmatx.queued) { - dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, - DMA_TO_DEVICE); + dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma, + uap->dmatx.len, DMA_TO_DEVICE); uap->dmatx.queued = false; uap->dmacr &= ~UART011_TXDMAE; pl011_write(uap->dmacr, uap, REG_DMACR); @@ -826,17 +816,17 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) struct dma_chan *rxchan = uap->dmarx.chan; struct pl011_dmarx_data *dmarx = &uap->dmarx; struct dma_async_tx_descriptor *desc; - struct pl011_sgbuf *sgbuf; + struct pl011_dmabuf *dbuf; if (!rxchan) return -EIO; /* Start the RX DMA job */ - sgbuf = uap->dmarx.use_buf_b ? - &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; - desc = dmaengine_prep_slave_sg(rxchan, &sgbuf->sg, 1, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + dbuf = uap->dmarx.use_buf_b ? + &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a; + desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); /* * If the DMA engine is busy and cannot prepare a * channel, no big deal, the driver will fall back @@ -874,8 +864,8 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, bool readfifo) { struct tty_port *port = &uap->port.state->port; - struct pl011_sgbuf *sgbuf = use_buf_b ? - &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; + struct pl011_dmabuf *dbuf = use_buf_b ? + &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a; int dma_count = 0; u32 fifotaken = 0; /* only used for vdbg() */ @@ -884,7 +874,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, if (uap->dmarx.poll_rate) { /* The data can be taken by polling */ - dmataken = sgbuf->sg.length - dmarx->last_residue; + dmataken = dbuf->len - dmarx->last_residue; /* Recalculate the pending size */ if (pending >= dmataken) pending -= dmataken; @@ -892,14 +882,12 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, /* Pick the remain data from the DMA */ if (pending) { - /* * First take all chars in the DMA pipe, then look in the FIFO. * Note that tty_insert_flip_buf() tries to take as many chars * as it can. */ - dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken, - pending); + dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, pending); uap->port.icount.rx += dma_count; if (dma_count < pending) @@ -909,7 +897,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, /* Reset the last_residue for Rx DMA poll */ if (uap->dmarx.poll_rate) - dmarx->last_residue = sgbuf->sg.length; + dmarx->last_residue = dbuf->len; /* * Only continue with trying to read the FIFO if all DMA chars have @@ -934,20 +922,18 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, fifotaken = pl011_fifo_to_tty(uap); } - spin_unlock(&uap->port.lock); dev_vdbg(uap->port.dev, "Took %d chars from DMA buffer and %d chars from the FIFO\n", dma_count, fifotaken); tty_flip_buffer_push(port); - spin_lock(&uap->port.lock); } static void pl011_dma_rx_irq(struct uart_amba_port *uap) { struct pl011_dmarx_data *dmarx = &uap->dmarx; struct dma_chan *rxchan = dmarx->chan; - struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ? - &dmarx->sgbuf_b : &dmarx->sgbuf_a; + struct pl011_dmabuf *dbuf = dmarx->use_buf_b ? + &dmarx->dbuf_b : &dmarx->dbuf_a; size_t pending; struct dma_tx_state state; enum dma_status dmastat; @@ -969,7 +955,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) pl011_write(uap->dmacr, uap, REG_DMACR); uap->dmarx.running = false; - pending = sgbuf->sg.length - state.residue; + pending = dbuf->len - state.residue; BUG_ON(pending > PL011_DMA_BUFFER_SIZE); /* Then we terminate the transfer - we now know our residue */ dmaengine_terminate_all(rxchan); @@ -983,8 +969,8 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) /* Switch buffer & re-trigger DMA job */ dmarx->use_buf_b = !dmarx->use_buf_b; if (pl011_dma_rx_trigger_dma(uap)) { - dev_dbg(uap->port.dev, "could not retrigger RX DMA job " - "fall back to interrupt mode\n"); + dev_dbg(uap->port.dev, + "could not retrigger RX DMA job fall back to interrupt mode\n"); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); } @@ -996,8 +982,8 @@ static void pl011_dma_rx_callback(void *data) struct pl011_dmarx_data *dmarx = &uap->dmarx; struct dma_chan *rxchan = dmarx->chan; bool lastbuf = dmarx->use_buf_b; - struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ? - &dmarx->sgbuf_b : &dmarx->sgbuf_a; + struct pl011_dmabuf *dbuf = dmarx->use_buf_b ? + &dmarx->dbuf_b : &dmarx->dbuf_a; size_t pending; struct dma_tx_state state; int ret; @@ -1009,13 +995,13 @@ static void pl011_dma_rx_callback(void *data) * routine to flush out the secondary DMA buffer while * we immediately trigger the next DMA job. */ - spin_lock_irq(&uap->port.lock); + uart_port_lock_irq(&uap->port); /* * Rx data can be taken by the UART interrupts during * the DMA irq handler. So we check the residue here. */ rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state); - pending = sgbuf->sg.length - state.residue; + pending = dbuf->len - state.residue; BUG_ON(pending > PL011_DMA_BUFFER_SIZE); /* Then we terminate the transfer - we now know our residue */ dmaengine_terminate_all(rxchan); @@ -1025,14 +1011,14 @@ static void pl011_dma_rx_callback(void *data) ret = pl011_dma_rx_trigger_dma(uap); pl011_dma_rx_chars(uap, pending, lastbuf, false); - spin_unlock_irq(&uap->port.lock); + uart_unlock_and_check_sysrq(&uap->port); /* * Do this check after we picked the DMA chars so we don't * get some IRQ immediately from RX. */ if (ret) { - dev_dbg(uap->port.dev, "could not retrigger RX DMA job " - "fall back to interrupt mode\n"); + dev_dbg(uap->port.dev, + "could not retrigger RX DMA job fall back to interrupt mode\n"); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); } @@ -1045,6 +1031,9 @@ static void pl011_dma_rx_callback(void *data) */ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) { + if (!uap->using_rx_dma) + return; + /* FIXME. Just disable the DMA enable */ uap->dmacr &= ~UART011_RXDMAE; pl011_write(uap->dmacr, uap, REG_DMACR); @@ -1057,24 +1046,24 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) */ static void pl011_dma_rx_poll(struct timer_list *t) { - struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer); + struct uart_amba_port *uap = timer_container_of(uap, t, dmarx.timer); struct tty_port *port = &uap->port.state->port; struct pl011_dmarx_data *dmarx = &uap->dmarx; struct dma_chan *rxchan = uap->dmarx.chan; - unsigned long flags = 0; + unsigned long flags; unsigned int dmataken = 0; unsigned int size = 0; - struct pl011_sgbuf *sgbuf; + struct pl011_dmabuf *dbuf; int dma_count; struct dma_tx_state state; - sgbuf = dmarx->use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; + dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a; rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state); if (likely(state.residue < dmarx->last_residue)) { - dmataken = sgbuf->sg.length - dmarx->last_residue; + dmataken = dbuf->len - dmarx->last_residue; size = dmarx->last_residue - state.residue; - dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken, - size); + dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, + size); if (dma_count == size) dmarx->last_residue = state.residue; dmarx->last_jiffies = jiffies; @@ -1087,19 +1076,18 @@ static void pl011_dma_rx_poll(struct timer_list *t) */ if (jiffies_to_msecs(jiffies - dmarx->last_jiffies) > uap->dmarx.poll_timeout) { - - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); uap->dmarx.running = false; dmaengine_terminate_all(rxchan); - del_timer(&uap->dmarx.timer); + timer_delete(&uap->dmarx.timer); } else { mod_timer(&uap->dmarx.timer, - jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); + jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); } } @@ -1115,12 +1103,11 @@ static void pl011_dma_startup(struct uart_amba_port *uap) uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA); if (!uap->dmatx.buf) { - dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); uap->port.fifosize = uap->fifosize; return; } - sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); + uap->dmatx.len = PL011_DMA_BUFFER_SIZE; /* The DMA buffer is now the FIFO the TTY subsystem can use */ uap->port.fifosize = PL011_DMA_BUFFER_SIZE; @@ -1130,21 +1117,21 @@ static void pl011_dma_startup(struct uart_amba_port *uap) goto skip_rx; /* Allocate and map DMA RX buffers */ - ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_a, - DMA_FROM_DEVICE); + ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a, + DMA_FROM_DEVICE); if (ret) { dev_err(uap->port.dev, "failed to init DMA %s: %d\n", "RX buffer A", ret); goto skip_rx; } - ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_b, - DMA_FROM_DEVICE); + ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b, + DMA_FROM_DEVICE); if (ret) { dev_err(uap->port.dev, "failed to init DMA %s: %d\n", "RX buffer B", ret); - pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, - DMA_FROM_DEVICE); + pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, + DMA_FROM_DEVICE); goto skip_rx; } @@ -1166,13 +1153,12 @@ skip_rx: if (uap->using_rx_dma) { if (pl011_dma_rx_trigger_dma(uap)) - dev_dbg(uap->port.dev, "could not trigger initial " - "RX DMA job, fall back to interrupt mode\n"); + dev_dbg(uap->port.dev, + "could not trigger initial RX DMA job, fall back to interrupt mode\n"); if (uap->dmarx.poll_rate) { timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0); mod_timer(&uap->dmarx.timer, - jiffies + - msecs_to_jiffies(uap->dmarx.poll_rate)); + jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE; uap->dmarx.last_jiffies = jiffies; } @@ -1188,17 +1174,18 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy) cpu_relax(); - spin_lock_irq(&uap->port.lock); + uart_port_lock_irq(&uap->port); uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); pl011_write(uap->dmacr, uap, REG_DMACR); - spin_unlock_irq(&uap->port.lock); + uart_port_unlock_irq(&uap->port); if (uap->using_tx_dma) { /* In theory, this should already be done by pl011_dma_flush_buffer */ dmaengine_terminate_all(uap->dmatx.chan); if (uap->dmatx.queued) { - dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, - DMA_TO_DEVICE); + dma_unmap_single(uap->dmatx.chan->device->dev, + uap->dmatx.dma, uap->dmatx.len, + DMA_TO_DEVICE); uap->dmatx.queued = false; } @@ -1209,10 +1196,10 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) if (uap->using_rx_dma) { dmaengine_terminate_all(uap->dmarx.chan); /* Clean up the RX DMA */ - pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE); - pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE); + pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE); + pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE); if (uap->dmarx.poll_rate) - del_timer_sync(&uap->dmarx.timer); + timer_delete_sync(&uap->dmarx.timer); uap->using_rx_dma = false; } } @@ -1281,14 +1268,66 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #define pl011_dma_flush_buffer NULL #endif +static void pl011_rs485_tx_stop(struct uart_amba_port *uap) +{ + struct uart_port *port = &uap->port; + u32 cr; + + if (uap->rs485_tx_state == SEND) + uap->rs485_tx_state = WAIT_AFTER_SEND; + + if (uap->rs485_tx_state == WAIT_AFTER_SEND) { + /* Schedule hrtimer if tx queue not empty */ + if (!pl011_tx_empty(port)) { + hrtimer_start(&uap->trigger_stop_tx, + uap->rs485_tx_drain_interval, + HRTIMER_MODE_REL); + return; + } + if (port->rs485.delay_rts_after_send > 0) { + hrtimer_start(&uap->trigger_stop_tx, + ms_to_ktime(port->rs485.delay_rts_after_send), + HRTIMER_MODE_REL); + return; + } + /* Continue without any delay */ + } else if (uap->rs485_tx_state == WAIT_AFTER_RTS) { + hrtimer_try_to_cancel(&uap->trigger_start_tx); + } + + cr = pl011_read(uap, REG_CR); + + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + cr &= ~UART011_CR_RTS; + else + cr |= UART011_CR_RTS; + + /* Disable the transmitter and reenable the transceiver */ + cr &= ~UART011_CR_TXE; + cr |= UART011_CR_RXE; + pl011_write(cr, uap, REG_CR); + + uap->rs485_tx_state = OFF; +} + static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + if (port->rs485.flags & SER_RS485_ENABLED && + uap->rs485_tx_state == WAIT_AFTER_RTS) { + pl011_rs485_tx_stop(uap); + return; + } + uap->im &= ~UART011_TXIM; pl011_write(uap->im, uap, REG_IMSC); pl011_dma_tx_stop(uap); + + if (port->rs485.flags & SER_RS485_ENABLED && + uap->rs485_tx_state != OFF) + pl011_rs485_tx_stop(uap); } static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); @@ -1302,33 +1341,116 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap) } } +static void pl011_rs485_tx_start(struct uart_amba_port *uap) +{ + struct uart_port *port = &uap->port; + u32 cr; + + if (uap->rs485_tx_state == WAIT_AFTER_RTS) { + uap->rs485_tx_state = SEND; + return; + } + if (uap->rs485_tx_state == WAIT_AFTER_SEND) { + hrtimer_try_to_cancel(&uap->trigger_stop_tx); + uap->rs485_tx_state = SEND; + return; + } + /* uap->rs485_tx_state == OFF */ + /* Enable transmitter */ + cr = pl011_read(uap, REG_CR); + cr |= UART011_CR_TXE; + /* Disable receiver if half-duplex */ + if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) + cr &= ~UART011_CR_RXE; + + if (port->rs485.flags & SER_RS485_RTS_ON_SEND) + cr &= ~UART011_CR_RTS; + else + cr |= UART011_CR_RTS; + + pl011_write(cr, uap, REG_CR); + + if (port->rs485.delay_rts_before_send > 0) { + uap->rs485_tx_state = WAIT_AFTER_RTS; + hrtimer_start(&uap->trigger_start_tx, + ms_to_ktime(port->rs485.delay_rts_before_send), + HRTIMER_MODE_REL); + } else { + uap->rs485_tx_state = SEND; + } +} + static void pl011_start_tx(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + if ((uap->port.rs485.flags & SER_RS485_ENABLED) && + uap->rs485_tx_state != SEND) { + pl011_rs485_tx_start(uap); + if (uap->rs485_tx_state == WAIT_AFTER_RTS) + return; + } + if (!pl011_dma_tx_start(uap)) pl011_start_tx_pio(uap); } +static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t) +{ + struct uart_amba_port *uap = + container_of(t, struct uart_amba_port, trigger_start_tx); + unsigned long flags; + + uart_port_lock_irqsave(&uap->port, &flags); + if (uap->rs485_tx_state == WAIT_AFTER_RTS) + pl011_start_tx(&uap->port); + uart_port_unlock_irqrestore(&uap->port, flags); + + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t) +{ + struct uart_amba_port *uap = + container_of(t, struct uart_amba_port, trigger_stop_tx); + unsigned long flags; + + uart_port_lock_irqsave(&uap->port, &flags); + if (uap->rs485_tx_state == WAIT_AFTER_SEND) + pl011_rs485_tx_stop(uap); + uart_port_unlock_irqrestore(&uap->port, flags); + + return HRTIMER_NORESTART; +} + static void pl011_stop_rx(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| - UART011_PEIM|UART011_BEIM|UART011_OEIM); + uap->im &= ~(UART011_RXIM | UART011_RTIM | UART011_FEIM | + UART011_PEIM | UART011_BEIM | UART011_OEIM); pl011_write(uap->im, uap, REG_IMSC); pl011_dma_rx_stop(uap); } +static void pl011_throttle_rx(struct uart_port *port) +{ + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + pl011_stop_rx(port); + uart_port_unlock_irqrestore(port, flags); +} + static void pl011_enable_ms(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; + uap->im |= UART011_RIMIM | UART011_CTSMIM | UART011_DCDMIM | UART011_DSRMIM; pl011_write(uap->im, uap, REG_IMSC); } @@ -1338,7 +1460,7 @@ __acquires(&uap->port.lock) { pl011_fifo_to_tty(uap); - spin_unlock(&uap->port.lock); + uart_port_unlock(&uap->port); tty_flip_buffer_push(&uap->port.state->port); /* * If we were temporarily out of DMA mode for a while, @@ -1346,8 +1468,8 @@ __acquires(&uap->port.lock) */ if (pl011_dma_rx_available(uap)) { if (pl011_dma_rx_trigger_dma(uap)) { - dev_dbg(uap->port.dev, "could not trigger RX DMA job " - "fall back to interrupt mode again\n"); + dev_dbg(uap->port.dev, + "could not trigger RX DMA job fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); } else { @@ -1357,13 +1479,12 @@ __acquires(&uap->port.lock) uap->dmarx.last_jiffies = jiffies; uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE; mod_timer(&uap->dmarx.timer, - jiffies + - msecs_to_jiffies(uap->dmarx.poll_rate)); + jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); } #endif } } - spin_lock(&uap->port.lock); + uart_port_lock(&uap->port); } static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, @@ -1382,7 +1503,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, /* Returns true if tx interrupts have to be (kept) enabled */ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { - struct circ_buf *xmit = &uap->port.state->xmit; + struct tty_port *tport = &uap->port.state->port; int count = uap->fifosize >> 1; if (uap->port.x_char) { @@ -1391,7 +1512,7 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) uap->port.x_char = 0; --count; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); return false; } @@ -1400,20 +1521,25 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) if (pl011_dma_tx_irq(uap)) return true; - do { + while (1) { + unsigned char c; + if (likely(from_irq) && count-- == 0) break; - if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) + if (!kfifo_peek(&tport->xmit_fifo, &c)) break; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } while (!uart_circ_empty(xmit)); + if (!pl011_tx_char(uap, c, from_irq)) + break; + + kfifo_skip(&tport->xmit_fifo); + } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { pl011_stop_tx(&uap->port); return false; } @@ -1465,28 +1591,26 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap) static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; - unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock(&uap->port); status = pl011_read(uap, REG_RIS) & uap->im; if (status) { do { check_apply_cts_event_workaround(uap); - pl011_write(status & ~(UART011_TXIS|UART011_RTIS| - UART011_RXIS), + pl011_write(status & ~(UART011_TXIS | UART011_RTIS | UART011_RXIS), uap, REG_ICR); - if (status & (UART011_RTIS|UART011_RXIS)) { + if (status & (UART011_RTIS | UART011_RXIS)) { if (pl011_dma_rx_running(uap)) pl011_dma_rx_irq(uap); else pl011_rx_chars(uap); } - if (status & (UART011_DSRMIS|UART011_DCDMIS| - UART011_CTSMIS|UART011_RIMIS)) + if (status & (UART011_DSRMIS | UART011_DCDMIS | + UART011_CTSMIS | UART011_RIMIS)) pl011_modem_status(uap); if (status & UART011_TXIS) pl011_tx_chars(uap, true); @@ -1499,7 +1623,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) handled = 1; } - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_unlock_and_check_sysrq(&uap->port); return IRQ_RETVAL(handled); } @@ -1516,6 +1640,12 @@ static unsigned int pl011_tx_empty(struct uart_port *port) 0 : TIOCSER_TEMT; } +static void pl011_maybe_set_bit(bool cond, unsigned int *ptr, unsigned int mask) +{ + if (cond) + *ptr |= mask; +} + static unsigned int pl011_get_mctrl(struct uart_port *port) { struct uart_amba_port *uap = @@ -1523,18 +1653,22 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) unsigned int result = 0; unsigned int status = pl011_read(uap, REG_FR); -#define TIOCMBIT(uartbit, tiocmbit) \ - if (status & uartbit) \ - result |= tiocmbit + pl011_maybe_set_bit(status & UART01x_FR_DCD, &result, TIOCM_CAR); + pl011_maybe_set_bit(status & uap->vendor->fr_dsr, &result, TIOCM_DSR); + pl011_maybe_set_bit(status & uap->vendor->fr_cts, &result, TIOCM_CTS); + pl011_maybe_set_bit(status & uap->vendor->fr_ri, &result, TIOCM_RNG); - TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR); - TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS); - TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG); -#undef TIOCMBIT return result; } +static void pl011_assign_bit(bool cond, unsigned int *ptr, unsigned int mask) +{ + if (cond) + *ptr |= mask; + else + *ptr &= ~mask; +} + static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct uart_amba_port *uap = @@ -1543,23 +1677,16 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) cr = pl011_read(uap, REG_CR); -#define TIOCMBIT(tiocmbit, uartbit) \ - if (mctrl & tiocmbit) \ - cr |= uartbit; \ - else \ - cr &= ~uartbit - - TIOCMBIT(TIOCM_RTS, UART011_CR_RTS); - TIOCMBIT(TIOCM_DTR, UART011_CR_DTR); - TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1); - TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2); - TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE); + pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTS); + pl011_assign_bit(mctrl & TIOCM_DTR, &cr, UART011_CR_DTR); + pl011_assign_bit(mctrl & TIOCM_OUT1, &cr, UART011_CR_OUT1); + pl011_assign_bit(mctrl & TIOCM_OUT2, &cr, UART011_CR_OUT2); + pl011_assign_bit(mctrl & TIOCM_LOOP, &cr, UART011_CR_LBE); if (port->status & UPSTAT_AUTORTS) { /* We need to disable auto-RTS if we want to turn RTS off */ - TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN); + pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTSEN); } -#undef TIOCMBIT pl011_write(cr, uap, REG_CR); } @@ -1571,14 +1698,14 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) unsigned long flags; unsigned int lcr_h; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); lcr_h = pl011_read(uap, REG_LCRH_TX); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; pl011_write(lcr_h, uap, REG_LCRH_TX); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); } #ifdef CONFIG_CONSOLE_POLL @@ -1625,8 +1752,7 @@ static int pl011_get_poll_char(struct uart_port *port) return pl011_read(uap, REG_DR); } -static void pl011_put_poll_char(struct uart_port *port, - unsigned char ch) +static void pl011_put_poll_char(struct uart_port *port, unsigned char ch) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); @@ -1714,9 +1840,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) */ static void pl011_enable_interrupts(struct uart_amba_port *uap) { + unsigned long flags; unsigned int i; - spin_lock_irq(&uap->port.lock); + uart_port_lock_irqsave(&uap->port, &flags); /* Clear out any spuriously appearing RX interrupts */ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); @@ -1738,7 +1865,30 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); - spin_unlock_irq(&uap->port.lock); + uart_port_unlock_irqrestore(&uap->port, flags); +} + +static void pl011_unthrottle_rx(struct uart_port *port) +{ + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + unsigned long flags; + + uart_port_lock_irqsave(&uap->port, &flags); + + uap->im = UART011_RTIM; + if (!pl011_dma_rx_running(uap)) + uap->im |= UART011_RXIM; + + pl011_write(uap->im, uap, REG_IMSC); + +#ifdef CONFIG_DMA_ENGINE + if (uap->using_rx_dma) { + uap->dmacr |= UART011_RXDMAE; + pl011_write(uap->dmacr, uap, REG_DMACR); + } +#endif + + uart_port_unlock_irqrestore(&uap->port, flags); } static int pl011_startup(struct uart_port *port) @@ -1758,14 +1908,18 @@ static int pl011_startup(struct uart_port *port) pl011_write(uap->vendor->ifls, uap, REG_IFLS); - spin_lock_irq(&uap->port.lock); + uart_port_lock_irq(&uap->port); + + cr = pl011_read(uap, REG_CR); + cr &= UART011_CR_RTS | UART011_CR_DTR; + cr |= UART01x_CR_UARTEN | UART011_CR_RXE; + + if (!(port->rs485.flags & SER_RS485_ENABLED)) + cr |= UART011_CR_TXE; - /* restore RTS and DTR */ - cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); - cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; pl011_write(cr, uap, REG_CR); - spin_unlock_irq(&uap->port.lock); + uart_port_unlock_irq(&uap->port); /* * initialise the old status of the modem signals @@ -1806,14 +1960,13 @@ static int sbsa_uart_startup(struct uart_port *port) return 0; } -static void pl011_shutdown_channel(struct uart_amba_port *uap, - unsigned int lcrh) +static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh) { - unsigned long val; + unsigned long val; - val = pl011_read(uap, lcrh); - val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); - pl011_write(val, uap, lcrh); + val = pl011_read(uap, lcrh); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + pl011_write(val, uap, lcrh); } /* @@ -1826,13 +1979,12 @@ static void pl011_disable_uart(struct uart_amba_port *uap) unsigned int cr; uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); - spin_lock_irq(&uap->port.lock); + uart_port_lock_irq(&uap->port); cr = pl011_read(uap, REG_CR); - uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; pl011_write(cr, uap, REG_CR); - spin_unlock_irq(&uap->port.lock); + uart_port_unlock_irq(&uap->port); /* * disable break condition and fifos @@ -1844,14 +1996,14 @@ static void pl011_disable_uart(struct uart_amba_port *uap) static void pl011_disable_interrupts(struct uart_amba_port *uap) { - spin_lock_irq(&uap->port.lock); + uart_port_lock_irq(&uap->port); /* mask all interrupts and clear all pending ones */ uap->im = 0; pl011_write(uap->im, uap, REG_IMSC); pl011_write(0xffff, uap, REG_ICR); - spin_unlock_irq(&uap->port.lock); + uart_port_unlock_irq(&uap->port); } static void pl011_shutdown(struct uart_port *port) @@ -1863,6 +2015,9 @@ static void pl011_shutdown(struct uart_port *port) pl011_dma_shutdown(uap); + if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF)) + pl011_rs485_tx_stop(uap); + free_irq(uap->port.irq, uap); pl011_disable_uart(uap); @@ -1933,13 +2088,14 @@ pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios) static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot, clkdiv; + unsigned int bits; if (uap->vendor->oversampling) clkdiv = 8; @@ -1959,7 +2115,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud); #endif - if (baud > port->uartclk/16) + if (baud > port->uartclk / 16) quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); else quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); @@ -1990,21 +2146,31 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, if (uap->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; - spin_lock_irqsave(&port->lock, flags); + bits = tty_get_frame_size(termios->c_cflag); + + uart_port_lock_irqsave(port, &flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); + /* + * Calculate the approximated time it takes to transmit one character + * with the given baud rate. We use this as the poll interval when we + * wait for the tx queue to empty. + */ + uap->rs485_tx_drain_interval = ns_to_ktime(DIV_ROUND_UP(bits * NSEC_PER_SEC, baud)); + pl011_setup_status_masks(port, termios); if (UART_ENABLE_MS(port, termios->c_cflag)) pl011_enable_ms(port); - /* first, disable everything */ + if (port->rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + old_cr = pl011_read(uap, REG_CR); - pl011_write(0, uap, REG_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) @@ -2031,9 +2197,9 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * else we see data corruption. */ if (uap->vendor->oversampling) { - if ((baud >= 3000000) && (baud < 3250000) && (quot > 1)) + if (baud >= 3000000 && baud < 3250000 && quot > 1) quot -= 1; - else if ((baud > 3250000) && (quot > 2)) + else if (baud > 3250000 && quot > 2) quot -= 2; } /* Set baud rate */ @@ -2047,14 +2213,21 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * ----------^----------^----------^----------^----- */ pl011_write_lcr_h(uap, lcr_h); + + /* + * Receive was disabled by pl011_disable_uart during shutdown. + * Need to reenable receive if you need to use a tty_driver + * returns from tty_find_polling_driver() after a port shutdown. + */ + old_cr |= UART011_CR_RXE; pl011_write(old_cr, uap, REG_CR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); @@ -2067,10 +2240,10 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, termios->c_cflag &= ~(CMSPAR | CRTSCTS); termios->c_cflag |= CS8 | CLOCAL; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, CS8, uap->fixed_baud); pl011_setup_status_masks(port, termios); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *pl011_type(struct uart_port *port) @@ -2081,31 +2254,12 @@ static const char *pl011_type(struct uart_port *port) } /* - * Release the memory region(s) being used by 'port' - */ -static void pl011_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, SZ_4K); -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int pl011_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") - != NULL ? 0 : -EBUSY; -} - -/* * Configure/autoconfigure the port. */ static void pl011_config_port(struct uart_port *port, int flags) { - if (flags & UART_CONFIG_TYPE) { + if (flags & UART_CONFIG_TYPE) port->type = PORT_AMBA; - pl011_request_port(port); - } } /* @@ -2114,15 +2268,39 @@ static void pl011_config_port(struct uart_port *port, int flags) static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; + if (port->mapbase != (unsigned long)ser->iomem_base) + ret = -EINVAL; return ret; } +static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + if (port->rs485.flags & SER_RS485_ENABLED) + pl011_rs485_tx_stop(uap); + + /* Make sure auto RTS is disabled */ + if (rs485->flags & SER_RS485_ENABLED) { + u32 cr = pl011_read(uap, REG_CR); + + cr &= ~UART011_CR_RTSEN; + pl011_write(cr, uap, REG_CR); + port->status &= ~UPSTAT_AUTORTS; + } + + return 0; +} + static const struct uart_ops amba_pl011_pops = { .tx_empty = pl011_tx_empty, .set_mctrl = pl011_set_mctrl, @@ -2130,6 +2308,8 @@ static const struct uart_ops amba_pl011_pops = { .stop_tx = pl011_stop_tx, .start_tx = pl011_start_tx, .stop_rx = pl011_stop_rx, + .throttle = pl011_throttle_rx, + .unthrottle = pl011_unthrottle_rx, .enable_ms = pl011_enable_ms, .break_ctl = pl011_break_ctl, .startup = pl011_startup, @@ -2137,8 +2317,6 @@ static const struct uart_ops amba_pl011_pops = { .flush_buffer = pl011_dma_flush_buffer, .set_termios = pl011_set_termios, .type = pl011_type, - .release_port = pl011_release_port, - .request_port = pl011_request_port, .config_port = pl011_config_port, .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL @@ -2168,8 +2346,6 @@ static const struct uart_ops sbsa_uart_pops = { .shutdown = sbsa_uart_shutdown, .set_termios = sbsa_uart_set_termios, .type = pl011_type, - .release_port = pl011_release_port, - .request_port = pl011_request_port, .config_port = pl011_config_port, .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL @@ -2183,7 +2359,7 @@ static struct uart_amba_port *amba_ports[UART_NR]; #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE -static void pl011_console_putchar(struct uart_port *port, int ch) +static void pl011_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); @@ -2191,92 +2367,43 @@ static void pl011_console_putchar(struct uart_port *port, int ch) while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) cpu_relax(); pl011_write(ch, uap, REG_DR); + uap->console_line_ended = (ch == '\n'); } -static void -pl011_console_write(struct console *co, const char *s, unsigned int count) +static void pl011_console_get_options(struct uart_amba_port *uap, int *baud, + int *parity, int *bits) { - struct uart_amba_port *uap = amba_ports[co->index]; - unsigned int old_cr = 0, new_cr; - unsigned long flags; - int locked = 1; + unsigned int lcr_h, ibrd, fbrd; - clk_enable(uap->clk); + if (!(pl011_read(uap, REG_CR) & UART01x_CR_UARTEN)) + return; - local_irq_save(flags); - if (uap->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&uap->port.lock); - else - spin_lock(&uap->port.lock); + lcr_h = pl011_read(uap, REG_LCRH_TX); - /* - * First save the CR then disable the interrupts - */ - if (!uap->vendor->always_enabled) { - old_cr = pl011_read(uap, REG_CR); - new_cr = old_cr & ~UART011_CR_CTSEN; - new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - pl011_write(new_cr, uap, REG_CR); + *parity = 'n'; + if (lcr_h & UART01x_LCRH_PEN) { + if (lcr_h & UART01x_LCRH_EPS) + *parity = 'e'; + else + *parity = 'o'; } - uart_console_write(&uap->port, s, count, pl011_console_putchar); - - /* - * Finally, wait for transmitter to become empty and restore the - * TCR. Allow feature register bits to be inverted to work around - * errata. - */ - while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) - & uap->vendor->fr_busy) - cpu_relax(); - if (!uap->vendor->always_enabled) - pl011_write(old_cr, uap, REG_CR); - - if (locked) - spin_unlock(&uap->port.lock); - local_irq_restore(flags); - - clk_disable(uap->clk); -} - -static void __init -pl011_console_get_options(struct uart_amba_port *uap, int *baud, - int *parity, int *bits) -{ - if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) { - unsigned int lcr_h, ibrd, fbrd; - - lcr_h = pl011_read(uap, REG_LCRH_TX); - - *parity = 'n'; - if (lcr_h & UART01x_LCRH_PEN) { - if (lcr_h & UART01x_LCRH_EPS) - *parity = 'e'; - else - *parity = 'o'; - } - - if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) - *bits = 7; - else - *bits = 8; + if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) + *bits = 7; + else + *bits = 8; - ibrd = pl011_read(uap, REG_IBRD); - fbrd = pl011_read(uap, REG_FBRD); + ibrd = pl011_read(uap, REG_IBRD); + fbrd = pl011_read(uap, REG_FBRD); - *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); + *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); - if (uap->vendor->oversampling) { - if (pl011_read(uap, REG_CR) - & ST_UART011_CR_OVSFACT) - *baud *= 2; - } - } + if (uap->vendor->oversampling && + (pl011_read(uap, REG_CR) & ST_UART011_CR_OVSFACT)) + *baud *= 2; } -static int __init pl011_console_setup(struct console *co, char *options) +static int pl011_console_setup(struct console *co, char *options) { struct uart_amba_port *uap; int baud = 38400; @@ -2303,6 +2430,8 @@ static int __init pl011_console_setup(struct console *co, char *options) if (ret) return ret; + uap->console_line_ended = true; + if (dev_get_platdata(uap->port.dev)) { struct amba_pl011_data *plat; @@ -2344,10 +2473,10 @@ static int __init pl011_console_setup(struct console *co, char *options) * * Returns 0 if console matches; otherwise non-zero to use default matching */ -static int __init pl011_console_match(struct console *co, char *name, int idx, - char *options) +static int pl011_console_match(struct console *co, char *name, int idx, + char *options) { - unsigned char iotype; + enum uart_iotype iotype; resource_size_t addr; int i; @@ -2379,28 +2508,119 @@ static int __init pl011_console_match(struct console *co, char *name, int idx, continue; co->index = i; - port->cons = co; + uart_port_set_cons(port, co); return pl011_console_setup(co, options); } return -ENODEV; } +static void +pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt) +{ + struct uart_amba_port *uap = amba_ports[co->index]; + unsigned int old_cr = 0; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + clk_enable(uap->clk); + + if (!uap->vendor->always_enabled) { + old_cr = pl011_read(uap, REG_CR); + pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE), + uap, REG_CR); + } + + if (!uap->console_line_ended) + uart_console_write(&uap->port, "\n", 1, pl011_console_putchar); + uart_console_write(&uap->port, wctxt->outbuf, wctxt->len, pl011_console_putchar); + + while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy) + cpu_relax(); + + if (!uap->vendor->always_enabled) + pl011_write(old_cr, uap, REG_CR); + + clk_disable(uap->clk); + + nbcon_exit_unsafe(wctxt); +} + +static void +pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt) +{ + struct uart_amba_port *uap = amba_ports[co->index]; + unsigned int old_cr = 0; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + clk_enable(uap->clk); + + if (!uap->vendor->always_enabled) { + old_cr = pl011_read(uap, REG_CR); + pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE), + uap, REG_CR); + } + + if (nbcon_exit_unsafe(wctxt)) { + int i; + unsigned int len = READ_ONCE(wctxt->len); + + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + uart_console_write(&uap->port, wctxt->outbuf + i, 1, pl011_console_putchar); + if (!nbcon_exit_unsafe(wctxt)) + break; + } + } + + while (!nbcon_enter_unsafe(wctxt)) + nbcon_reacquire_nobuf(wctxt); + + while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy) + cpu_relax(); + + if (!uap->vendor->always_enabled) + pl011_write(old_cr, uap, REG_CR); + + clk_disable(uap->clk); + + nbcon_exit_unsafe(wctxt); +} + +static void +pl011_console_device_lock(struct console *co, unsigned long *flags) +{ + __uart_port_lock_irqsave(&amba_ports[co->index]->port, flags); +} + +static void +pl011_console_device_unlock(struct console *co, unsigned long flags) +{ + __uart_port_unlock_irqrestore(&amba_ports[co->index]->port, flags); +} + static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAMA", - .write = pl011_console_write, .device = uart_console_device, .setup = pl011_console_setup, .match = pl011_console_match, - .flags = CON_PRINTBUFFER | CON_ANYTIME, + .write_atomic = pl011_console_write_atomic, + .write_thread = pl011_console_write_thread, + .device_lock = pl011_console_device_lock, + .device_unlock = pl011_console_device_unlock, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON, .index = -1, .data = &amba_reg, }; #define AMBA_CONSOLE (&amba_console) -static void qdf2400_e44_putc(struct uart_port *port, int c) +static void qdf2400_e44_putc(struct uart_port *port, unsigned char c) { while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) cpu_relax(); @@ -2409,14 +2629,14 @@ static void qdf2400_e44_putc(struct uart_port *port, int c) cpu_relax(); } -static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned n) +static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; uart_console_write(&dev->port, s, n, qdf2400_e44_putc); } -static void pl011_putc(struct uart_port *port, int c) +static void pl011_putc(struct uart_port *port, unsigned char c) { while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) cpu_relax(); @@ -2428,7 +2648,7 @@ static void pl011_putc(struct uart_port *port, int c) cpu_relax(); } -static void pl011_early_write(struct console *con, const char *s, unsigned n) +static void pl011_early_write(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; @@ -2489,7 +2709,9 @@ static int __init pl011_early_console_setup(struct earlycon_device *device, return 0; } + OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); + OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup); /* @@ -2512,6 +2734,7 @@ qdf2400_e44_early_console_setup(struct earlycon_device *device, device->con->write = qdf2400_e44_early_write; return 0; } + EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup); #else @@ -2531,8 +2754,8 @@ static struct uart_driver amba_reg = { static int pl011_probe_dt_alias(int index, struct device *dev) { struct device_node *np; - static bool seen_dev_with_alias = false; - static bool seen_dev_without_alias = false; + static bool seen_dev_with_alias; + static bool seen_dev_without_alias; int ret = index; if (!IS_ENABLED(CONFIG_OF)) @@ -2548,7 +2771,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev) ret = index; } else { seen_dev_with_alias = true; - if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) { + if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret]) { dev_warn(dev, "requested serial port %d not available.\n", ret); ret = index; } @@ -2582,7 +2805,7 @@ static int pl011_find_free_port(void) int i; for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == NULL) + if (!amba_ports[i]) return i; return -EBUSY; @@ -2592,6 +2815,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, struct resource *mmiobase, int index) { void __iomem *base; + int ret; base = devm_ioremap_resource(dev, mmiobase); if (IS_ERR(base)) @@ -2599,7 +2823,6 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, index = pl011_probe_dt_alias(index, dev); - uap->old_cr = 0; uap->port.dev = dev; uap->port.mapbase = mmiobase->start; uap->port.membase = base; @@ -2607,7 +2830,10 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE); uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = index; - spin_lock_init(&uap->port.lock); + + ret = uart_get_rs485_mode(&uap->port); + if (ret) + return ret; amba_ports[index] = uap; @@ -2616,7 +2842,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, static int pl011_register_port(struct uart_amba_port *uap) { - int ret; + int ret, i; /* Ensure interrupts from this UART are masked and cleared */ pl011_write(0, uap, REG_IMSC); @@ -2627,6 +2853,9 @@ static int pl011_register_port(struct uart_amba_port *uap) if (ret < 0) { dev_err(uap->port.dev, "Failed to register AMBA-PL011 driver\n"); + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) + if (amba_ports[i] == uap) + amba_ports[i] = NULL; return ret; } } @@ -2638,11 +2867,19 @@ static int pl011_register_port(struct uart_amba_port *uap) return ret; } +static const struct serial_rs485 pl011_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; struct vendor_data *vendor = id->data; int portnr, ret; + u32 val; portnr = pl011_find_free_port(); if (portnr < 0) @@ -2663,9 +2900,29 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; - + uap->port.rs485_config = pl011_rs485_config; + uap->port.rs485_supported = pl011_rs485_supported; snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + if (device_property_read_u32(&dev->dev, "reg-io-width", &val) == 0) { + switch (val) { + case 1: + uap->port.iotype = UPIO_MEM; + break; + case 4: + uap->port.iotype = UPIO_MEM32; + break; + default: + dev_warn(&dev->dev, "unsupported reg-io-width (%d)\n", + val); + return -EINVAL; + } + } + hrtimer_setup(&uap->trigger_start_tx, pl011_trigger_start_tx, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hrtimer_setup(&uap->trigger_stop_tx, pl011_trigger_stop_tx, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); if (ret) return ret; @@ -2675,13 +2932,12 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) return pl011_register_port(uap); } -static int pl011_remove(struct amba_device *dev) +static void pl011_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); uart_remove_one_port(&amba_reg, &uap->port); pl011_unregister_port(uap); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -2708,6 +2964,22 @@ static int pl011_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); +#ifdef CONFIG_ACPI_SPCR_TABLE +static void qpdf2400_erratum44_workaround(struct device *dev, + struct uart_amba_port *uap) +{ + if (!qdf2400_e44_present) + return; + + dev_info(dev, "working around QDF2400 SoC erratum 44\n"); + uap->vendor = &vendor_qdt_qdf2400_e44; +} +#else +static void qpdf2400_erratum44_workaround(struct device *dev, + struct uart_amba_port *uap) +{ /* empty */ } +#endif + static int sbsa_uart_probe(struct platform_device *pdev) { struct uart_amba_port *uap; @@ -2743,13 +3015,8 @@ static int sbsa_uart_probe(struct platform_device *pdev) return ret; uap->port.irq = ret; -#ifdef CONFIG_ACPI_SPCR_TABLE - if (qdf2400_e44_present) { - dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n"); - uap->vendor = &vendor_qdt_qdf2400_e44; - } else -#endif - uap->vendor = &vendor_sbsa; + uap->vendor = &vendor_sbsa; + qpdf2400_erratum44_workaround(&pdev->dev, uap); uap->reg_offset = uap->vendor->reg_offset; uap->fifosize = 32; @@ -2770,13 +3037,12 @@ static int sbsa_uart_probe(struct platform_device *pdev) return pl011_register_port(uap); } -static int sbsa_uart_remove(struct platform_device *pdev) +static void sbsa_uart_remove(struct platform_device *pdev) { struct uart_amba_port *uap = platform_get_drvdata(pdev); uart_remove_one_port(&amba_reg, &uap->port); pl011_unregister_port(uap); - return 0; } static const struct of_device_id sbsa_uart_of_match[] = { @@ -2787,6 +3053,7 @@ MODULE_DEVICE_TABLE(of, sbsa_uart_of_match); static const struct acpi_device_id sbsa_uart_acpi_match[] = { { "ARMH0011", 0 }, + { "ARMHB000", 0 }, {}, }; MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match); @@ -2797,8 +3064,8 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { .driver = { .name = "sbsa-uart", .pm = &pl011_dev_pm_ops, - .of_match_table = of_match_ptr(sbsa_uart_of_match), - .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match), + .of_match_table = sbsa_uart_of_match, + .acpi_match_table = sbsa_uart_acpi_match, .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011), }, }; @@ -2814,11 +3081,6 @@ static const struct amba_id pl011_ids[] = { .mask = 0x00ffffff, .data = &vendor_st, }, - { - .id = AMBA_LINUX_ID(0x00, 0x1, 0xffe), - .mask = 0x00ffffff, - .data = &vendor_zte, - }, { 0, 0 }, }; @@ -2837,7 +3099,7 @@ static struct amba_driver pl011_driver = { static int __init pl011_init(void) { - printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); + pr_info("Serial: AMBA PL011 UART driver\n"); if (platform_driver_register(&arm_sbsa_uart_platform_driver)) pr_warn("could not register SBSA UART platform driver\n"); diff --git a/drivers/tty/serial/amba-pl011.h b/drivers/tty/serial/amba-pl011.h deleted file mode 100644 index 077eb12a3472..000000000000 --- a/drivers/tty/serial/amba-pl011.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef AMBA_PL011_H -#define AMBA_PL011_H - -enum { - REG_DR, - REG_ST_DMAWM, - REG_ST_TIMEOUT, - REG_FR, - REG_LCRH_RX, - REG_LCRH_TX, - REG_IBRD, - REG_FBRD, - REG_CR, - REG_IFLS, - REG_IMSC, - REG_RIS, - REG_MIS, - REG_ICR, - REG_DMACR, - REG_ST_XFCR, - REG_ST_XON1, - REG_ST_XON2, - REG_ST_XOFF1, - REG_ST_XOFF2, - REG_ST_ITCR, - REG_ST_ITIP, - REG_ST_ABCR, - REG_ST_ABIMSC, - - /* The size of the array - must be last */ - REG_ARRAY_SIZE, -}; - -#endif diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index e8d56e899ec7..364599f256db 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -22,9 +22,6 @@ #include <linux/kthread.h> #include <linux/device.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_platform.h> -#include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/serial_core.h> @@ -70,8 +67,9 @@ static void apbuart_stop_rx(struct uart_port *port) static void apbuart_rx_chars(struct uart_port *port) { - unsigned int status, ch, rsr, flag; + unsigned int status, rsr; unsigned int max_chars = port->fifosize; + u8 ch, flag; status = UART_GET_STATUS(port); @@ -117,43 +115,17 @@ static void apbuart_rx_chars(struct uart_port *port) status = UART_GET_STATUS(port); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void apbuart_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - apbuart_stop_tx(port); - return; - } - - /* amba: fill FIFO */ - count = port->fifosize >> 1; - do { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + u8 ch; - if (uart_circ_empty(xmit)) - apbuart_stop_tx(port); + uart_port_tx_limited(port, ch, port->fifosize, + true, + UART_PUT_CHAR(port, ch), + ({})); } static irqreturn_t apbuart_int(int irq, void *dev_id) @@ -161,7 +133,7 @@ static irqreturn_t apbuart_int(int irq, void *dev_id) struct uart_port *port = dev_id; unsigned int status; - spin_lock(&port->lock); + uart_port_lock(port); status = UART_GET_STATUS(port); if (status & UART_STATUS_DR) @@ -169,7 +141,7 @@ static irqreturn_t apbuart_int(int irq, void *dev_id) if (status & UART_STATUS_THE) apbuart_tx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -230,7 +202,7 @@ static void apbuart_shutdown(struct uart_port *port) } static void apbuart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, const struct ktermios *old) { unsigned int cr; unsigned long flags; @@ -256,7 +228,7 @@ static void apbuart_set_termios(struct uart_port *port, if (termios->c_cflag & CRTSCTS) cr |= UART_CTRL_FL; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); @@ -279,7 +251,7 @@ static void apbuart_set_termios(struct uart_port *port, UART_PUT_SCAL(port, quot); UART_PUT_CTRL(port, cr); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *apbuart_type(struct uart_port *port) @@ -415,7 +387,7 @@ static void apbuart_flush_fifo(struct uart_port *port) #ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE -static void apbuart_console_putchar(struct uart_port *port, int ch) +static void apbuart_console_putchar(struct uart_port *port, unsigned char ch) { unsigned int status; do { diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 0c80a79d7442..5b491db9d2fc 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -133,9 +133,9 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port) unsigned long flags; unsigned int rdata; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT; } @@ -220,14 +220,14 @@ static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) container_of(port, struct ar933x_uart_port, port); unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (break_state == -1) ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, AR933X_UART_CS_TX_BREAK); else ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, AR933X_UART_CS_TX_BREAK); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } /* @@ -283,7 +283,7 @@ static void ar933x_uart_get_scale_step(unsigned int clk, static void ar933x_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { struct ar933x_uart_port *up = container_of(port, struct ar933x_uart_port, port); @@ -318,7 +318,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* disable the UART */ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, @@ -352,7 +352,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); if (tty_termios_baud_rate(new)) tty_termios_encode_baud_rate(new, baud, baud); @@ -378,21 +378,19 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) up->port.icount.rx++; ch = rdata & AR933X_UART_DATA_TX_RX_MASK; - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) continue; if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) tty_insert_flip_char(port, ch, TTY_NORMAL); } while (max_count-- > 0); - spin_unlock(&up->port.lock); tty_flip_buffer_push(port); - spin_lock(&up->port.lock); } static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; struct serial_rs485 *rs485conf = &up->port.rs485; int count; bool half_duplex_send = false; @@ -401,7 +399,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) return; if ((rs485conf->flags & SER_RS485_ENABLED) && - (up->port.x_char || !uart_circ_empty(xmit))) { + (up->port.x_char || !kfifo_is_empty(&tport->xmit_fifo))) { ar933x_uart_stop_rx_interrupt(up); gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND)); half_duplex_send = true; @@ -410,6 +408,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) count = up->port.fifosize; do { unsigned int rdata; + unsigned char c; rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) @@ -422,19 +421,16 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) continue; } - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&up->port, &c)) break; - ar933x_uart_putc(up, xmit->buf[xmit->tail]); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; + ar933x_uart_putc(up, c); } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { ar933x_uart_start_tx_interrupt(up); } else if (half_duplex_send) { ar933x_uart_wait_tx_complete(up); @@ -453,7 +449,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) if ((status & AR933X_UART_CS_HOST_INT) == 0) return IRQ_NONE; - spin_lock(&up->port.lock); + uart_port_lock(&up->port); status = ar933x_uart_read(up, AR933X_UART_INT_REG); status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); @@ -471,7 +467,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) ar933x_uart_tx_chars(up); } - spin_unlock(&up->port.lock); + uart_unlock_and_check_sysrq(&up->port); return IRQ_HANDLED; } @@ -488,7 +484,7 @@ static int ar933x_uart_startup(struct uart_port *port) if (ret) return ret; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* Enable HOST interrupts */ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, @@ -501,7 +497,7 @@ static int ar933x_uart_startup(struct uart_port *port) /* Enable RX interrupts */ ar933x_uart_start_rx_interrupt(up); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return 0; } @@ -564,6 +560,64 @@ static int ar933x_uart_verify_port(struct uart_port *port, return 0; } +#ifdef CONFIG_CONSOLE_POLL +static int ar933x_poll_get_char(struct uart_port *port) +{ + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + unsigned int rdata; + unsigned char ch; + u32 imr; + + /* Disable all interrupts */ + imr = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); + + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) { + /* Enable interrupts */ + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr); + return NO_POLL_CHAR; + } + + /* remove the character from the FIFO */ + ar933x_uart_write(up, AR933X_UART_DATA_REG, + AR933X_UART_DATA_RX_CSR); + + ch = rdata & AR933X_UART_DATA_TX_RX_MASK; + + /* Enable interrupts */ + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr); + + return ch; +} + +static void ar933x_poll_put_char(struct uart_port *port, unsigned char c) +{ + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + u32 imr; + + /* Disable all interrupts */ + imr = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); + + /* Wait until FIFO is empty */ + while (!(ar933x_uart_read(up, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR)) + cpu_relax(); + + /* Write a character */ + ar933x_uart_putc(up, c); + + /* Wait until FIFO is empty */ + while (!(ar933x_uart_read(up, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR)) + cpu_relax(); + + /* Enable interrupts */ + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr); +} +#endif + static const struct uart_ops ar933x_uart_ops = { .tx_empty = ar933x_uart_tx_empty, .set_mctrl = ar933x_uart_set_mctrl, @@ -580,20 +634,22 @@ static const struct uart_ops ar933x_uart_ops = { .request_port = ar933x_uart_request_port, .config_port = ar933x_uart_config_port, .verify_port = ar933x_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = ar933x_poll_get_char, + .poll_put_char = ar933x_poll_put_char, +#endif }; -static int ar933x_config_rs485(struct uart_port *port, +static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct ar933x_uart_port *up = - container_of(port, struct ar933x_uart_port, port); + container_of(port, struct ar933x_uart_port, port); + + if (port->rs485.flags & SER_RS485_ENABLED) + gpiod_set_value(up->rts_gpiod, + !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND)); - if ((rs485conf->flags & SER_RS485_ENABLED) && - !up->rts_gpiod) { - dev_err(port->dev, "RS485 needs rts-gpio\n"); - return 1; - } - port->rs485 = *rs485conf; return 0; } @@ -615,7 +671,7 @@ static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) } while ((status & AR933X_UART_DATA_TX_CSR) == 0); } -static void ar933x_uart_console_putchar(struct uart_port *port, int ch) +static void ar933x_uart_console_putchar(struct uart_port *port, unsigned char ch) { struct ar933x_uart_port *up = container_of(port, struct ar933x_uart_port, port); @@ -632,14 +688,10 @@ static void ar933x_uart_console_write(struct console *co, const char *s, unsigned int int_en; int locked = 1; - local_irq_save(flags); - - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&up->port.lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock(&up->port.lock); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -659,9 +711,7 @@ static void ar933x_uart_console_write(struct console *co, const char *s, ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); if (locked) - spin_unlock(&up->port.lock); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int ar933x_uart_console_setup(struct console *co, char *options) @@ -704,16 +754,20 @@ static struct uart_driver ar933x_uart_driver = { .cons = NULL, /* filled in runtime */ }; +static const struct serial_rs485 ar933x_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, +}; + static int ar933x_uart_probe(struct platform_device *pdev) { struct ar933x_uart_port *up; struct uart_port *port; struct resource *mem_res; - struct resource *irq_res; struct device_node *np; unsigned int baud; int id; int ret; + int irq; np = pdev->dev.of_node; if (IS_ENABLED(CONFIG_OF) && np) { @@ -732,11 +786,9 @@ static int ar933x_uart_probe(struct platform_device *pdev) if (id >= CONFIG_SERIAL_AR933X_NR_UARTS) return -EINVAL; - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { - dev_err(&pdev->dev, "no IRQ resource\n"); - return -EINVAL; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; up = devm_kzalloc(&pdev->dev, sizeof(struct ar933x_uart_port), GFP_KERNEL); @@ -751,8 +803,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port = &up->port; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - port->membase = devm_ioremap_resource(&pdev->dev, mem_res); + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); @@ -768,7 +819,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->mapbase = mem_res->start; port->line = id; - port->irq = irq_res->start; + port->irq = irq; port->dev = &pdev->dev; port->type = PORT_AR933X; port->iotype = UPIO_MEM32; @@ -777,6 +828,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->fifosize = AR933X_UART_FIFO_SIZE; port->ops = &ar933x_uart_ops; port->rs485_config = ar933x_config_rs485; + port->rs485_supported = ar933x_rs485_supported; baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); @@ -789,15 +841,19 @@ static int ar933x_uart_probe(struct platform_device *pdev) goto err_disable_clk; up->gpios = mctrl_gpio_init(port, 0); - if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) - return PTR_ERR(up->gpios); + if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) { + ret = PTR_ERR(up->gpios); + goto err_disable_clk; + } up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); - if ((port->rs485.flags & SER_RS485_ENABLED) && - !up->rts_gpiod) { - dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); - port->rs485.flags &= ~SER_RS485_ENABLED; + if (!up->rts_gpiod) { + port->rs485_supported.flags &= ~SER_RS485_ENABLED; + if (port->rs485.flags & SER_RS485_ENABLED) { + dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); + port->rs485.flags &= ~SER_RS485_ENABLED; + } } #ifdef CONFIG_SERIAL_AR933X_CONSOLE @@ -816,7 +872,7 @@ err_disable_clk: return ret; } -static int ar933x_uart_remove(struct platform_device *pdev) +static void ar933x_uart_remove(struct platform_device *pdev) { struct ar933x_uart_port *up; @@ -826,8 +882,6 @@ static int ar933x_uart_remove(struct platform_device *pdev) uart_remove_one_port(&ar933x_uart_driver, &up->port); clk_disable_unprepare(up->clk); } - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 17c3fc398fc6..5c4895d154c0 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -149,13 +149,13 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port) /* * Driver internal routine, used by both tty(serial core) as well as tx-isr * -Called under spinlock in either cases - * -also tty->stopped has already been checked + * -also tty->flow.stopped has already been checked * = by uart_start( ) before calling us * = tx_ist checks that too before calling */ static void arc_serial_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int sent = 0; unsigned char ch; @@ -164,10 +164,7 @@ static void arc_serial_tx_chars(struct uart_port *port) port->icount.tx++; port->x_char = 0; sent = 1; - } else if (!uart_circ_empty(xmit)) { - ch = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + } else if (uart_fifo_get(port, &ch)) { while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); UART_SET_DATA(port, ch); @@ -178,7 +175,7 @@ static void arc_serial_tx_chars(struct uart_port *port) * If num chars in xmit buffer are too few, ask tty layer for more. * By Hard ISR to schedule processing in software interrupt part */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); if (sent) @@ -196,8 +193,6 @@ static void arc_serial_start_tx(struct uart_port *port) static void arc_serial_rx_chars(struct uart_port *port, unsigned int status) { - unsigned int ch, flg = 0; - /* * UART has 4 deep RX-FIFO. Driver's recongnition of this fact * is very subtle. Here's how ... @@ -208,24 +203,23 @@ static void arc_serial_rx_chars(struct uart_port *port, unsigned int status) * controller, which is indeed the Rx-FIFO. */ do { + u8 ch, flg = TTY_NORMAL; + /* * This could be an Rx Intr for err (no data), * so check err and clear that Intr first */ - if (unlikely(status & (RXOERR | RXFERR))) { - if (status & RXOERR) { - port->icount.overrun++; - flg = TTY_OVERRUN; - UART_CLR_STATUS(port, RXOERR); - } - - if (status & RXFERR) { - port->icount.frame++; - flg = TTY_FRAME; - UART_CLR_STATUS(port, RXFERR); - } - } else - flg = TTY_NORMAL; + if (status & RXOERR) { + port->icount.overrun++; + flg = TTY_OVERRUN; + UART_CLR_STATUS(port, RXOERR); + } + + if (status & RXFERR) { + port->icount.frame++; + flg = TTY_FRAME; + UART_CLR_STATUS(port, RXFERR); + } if (status & RXEMPTY) continue; @@ -236,9 +230,7 @@ static void arc_serial_rx_chars(struct uart_port *port, unsigned int status) if (!(uart_handle_sysrq_char(port, ch))) uart_insert_char(port, status, RXOERR, ch, flg); - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } while (!((status = UART_GET_STATUS(port)) & RXEMPTY)); } @@ -285,9 +277,9 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) if (status & RXIENB) { /* already in ISR, no need of xx_irqsave */ - spin_lock(&port->lock); + uart_port_lock(port); arc_serial_rx_chars(port, status); - spin_unlock(&port->lock); + uart_port_unlock(port); } if ((status & TXIENB) && (status & TXEMPTY)) { @@ -297,12 +289,12 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) */ UART_TX_IRQ_DISABLE(port); - spin_lock(&port->lock); + uart_port_lock(port); if (!uart_tx_stopped(port)) arc_serial_tx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); } return IRQ_HANDLED; @@ -353,7 +345,7 @@ static void arc_serial_shutdown(struct uart_port *port) static void arc_serial_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { struct arc_uart_port *uart = to_arc_port(port); unsigned int baud, uartl, uarth, hw_val; @@ -372,7 +364,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, uartl = hw_val & 0xFF; uarth = (hw_val >> 8) & 0xFF; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); UART_ALL_IRQ_DISABLE(port); @@ -397,7 +389,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, uart_update_timeout(port, new->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *arc_serial_type(struct uart_port *port) @@ -510,7 +502,7 @@ static int arc_serial_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static void arc_serial_console_putchar(struct uart_port *port, int ch) +static void arc_serial_console_putchar(struct uart_port *port, unsigned char ch) { while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); @@ -527,9 +519,9 @@ static void arc_serial_console_write(struct console *co, const char *s, struct uart_port *port = &arc_uart_ports[co->index].port; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_console_write(port, s, count, arc_serial_console_putchar); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static struct console arc_console = { @@ -609,10 +601,11 @@ static int arc_serial_probe(struct platform_device *pdev) } uart->baud = val; - port->membase = of_iomap(np, 0); - if (!port->membase) + port->membase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(port->membase)) { /* No point of dev_err since UART itself is hosed here */ - return -ENXIO; + return PTR_ERR(port->membase); + } port->irq = irq_of_parse_and_map(np, 0); @@ -634,12 +627,6 @@ static int arc_serial_probe(struct platform_device *pdev) return uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); } -static int arc_serial_remove(struct platform_device *pdev) -{ - /* This will never be called */ - return 0; -} - static const struct of_device_id arc_uart_dt_ids[] = { { .compatible = "snps,arc-uart" }, { /* Sentinel */ } @@ -648,7 +635,6 @@ MODULE_DEVICE_TABLE(of, arc_uart_dt_ids); static struct platform_driver arc_platform_driver = { .probe = arc_serial_probe, - .remove = arc_serial_remove, .driver = { .name = DRIVER_NAME, .of_match_table = arc_uart_dt_ids, diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e43471b33710..08dd8f887956 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -8,18 +8,19 @@ * * DMA support added by Chip Coldwell. */ +#include <linux/circ_buf.h> #include <linux/tty.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/serial.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/console.h> #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/atmel_pdc.h> @@ -30,9 +31,9 @@ #include <linux/irq.h> #include <linux/suspend.h> #include <linux/mm.h> +#include <linux/io.h> #include <asm/div64.h> -#include <asm/io.h> #include <asm/ioctls.h> #define PDC_BUFFER_SIZE 512 @@ -95,7 +96,9 @@ struct atmel_uart_char { * can contain up to 1024 characters in PIO mode and up to 4096 characters in * DMA mode. */ -#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RX_SIZE array_size(sizeof(struct atmel_uart_char), \ + ATMEL_SERIAL_RINGSIZE) /* * at91: 6 USARTs and one DBGU port (SAM9260) @@ -109,6 +112,7 @@ struct atmel_uart_char { struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ + struct clk *gclk; /* uart generic clock */ int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ u32 backup_imr; /* IMR saved during suspend */ int break_active; /* break being received */ @@ -130,8 +134,8 @@ struct atmel_uart_port { struct dma_async_tx_descriptor *desc_rx; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx; - struct scatterlist sg_tx; - struct scatterlist sg_rx; + dma_addr_t tx_phys; + dma_addr_t rx_phys; struct tasklet_struct tasklet_rx; struct tasklet_struct tasklet_tx; atomic_t tasklet_shutdown; @@ -149,6 +153,7 @@ struct atmel_uart_port { u32 rts_low; bool ms_irq_enabled; u32 rtor; /* address of receiver timeout register if it exists */ + bool is_usart; bool has_frac_baudrate; bool has_hw_timer; struct timer_list uart_timer; @@ -165,7 +170,6 @@ struct atmel_uart_port { unsigned int fidi_min; unsigned int fidi_max; -#ifdef CONFIG_PM struct { u32 cr; u32 mr; @@ -176,7 +180,6 @@ struct atmel_uart_port { u32 fmr; u32 fimr; } cache; -#endif int (*prepare_rx)(struct uart_port *port); int (*prepare_tx)(struct uart_port *port); @@ -229,6 +232,11 @@ static inline int atmel_uart_is_half_duplex(struct uart_port *port) (port->iso7816.flags & SER_ISO7816_ENABLED); } +static inline int atmel_error_rate(int desired_value, int actual_value) +{ + return 100 - (desired_value * 100) / actual_value; +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -284,7 +292,7 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, } /* Enable or disable the rs485 support */ -static int atmel_config_rs485(struct uart_port *port, +static int atmel_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -295,20 +303,16 @@ static int atmel_config_rs485(struct uart_port *port, mode = atmel_uart_readl(port, ATMEL_US_MR); - /* Resetting serial mode to RS232 (0x0) */ - mode &= ~ATMEL_US_USMODE; - - port->rs485 = *rs485conf; - if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); - if (port->rs485.flags & SER_RS485_RX_DURING_TX) + if (rs485conf->flags & SER_RS485_RX_DURING_TX) atmel_port->tx_done_mask = ATMEL_US_TXRDY; else atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; atmel_uart_writel(port, ATMEL_US_TTGR, rs485conf->delay_rts_after_send); + mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -549,19 +553,23 @@ static u_int atmel_get_mctrl(struct uart_port *port) static void atmel_stop_tx(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + bool is_pdc = atmel_use_pdc_tx(port); + bool is_dma = is_pdc || atmel_use_dma_tx(port); - if (atmel_use_pdc_tx(port)) { + if (is_pdc) { /* disable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); } - /* - * Disable the transmitter. - * This is mandatory when DMA is used, otherwise the DMA buffer - * is fully transmitted. - */ - atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); - atmel_port->tx_stopped = true; + if (is_dma) { + /* + * Disable the transmitter. + * This is mandatory when DMA is used, otherwise the DMA buffer + * is fully transmitted. + */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); + atmel_port->tx_stopped = true; + } /* Disable interrupts */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); @@ -569,7 +577,6 @@ static void atmel_stop_tx(struct uart_port *port) if (atmel_uart_is_half_duplex(port)) if (!atomic_read(&atmel_port->tasklet_shutdown)) atmel_start_rx(port); - } /* @@ -578,27 +585,31 @@ static void atmel_stop_tx(struct uart_port *port) static void atmel_start_tx(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + bool is_pdc = atmel_use_pdc_tx(port); + bool is_dma = is_pdc || atmel_use_dma_tx(port); - if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR) + if (is_pdc && (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN)) /* The transmitter is already running. Yes, we really need this.*/ return; - if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) - if (atmel_uart_is_half_duplex(port)) - atmel_stop_rx(port); + if (is_dma && atmel_uart_is_half_duplex(port)) + atmel_stop_rx(port); - if (atmel_use_pdc_tx(port)) + if (is_pdc) { /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); + } /* Enable interrupts */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); - /* re-enable the transmitter */ - atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); - atmel_port->tx_stopped = false; + if (is_dma) { + /* re-enable the transmitter */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); + atmel_port->tx_stopped = false; + } } /* @@ -689,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port) atmel_port->ms_irq_enabled = false; - mctrl_gpio_disable_ms(atmel_port->gpios); + mctrl_gpio_disable_ms_no_sync(atmel_port->gpios); if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) idr |= ATMEL_US_CTSIC; @@ -821,30 +832,14 @@ static void atmel_rx_chars(struct uart_port *port) */ static void atmel_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + bool pending; + u8 ch; - if (port->x_char && - (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) { - atmel_uart_write_char(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - while (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY) { - atmel_uart_write_char(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!uart_circ_empty(xmit)) { + pending = uart_port_tx(port, ch, + atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY, + atmel_uart_write_char(port, ch)); + if (pending) { /* we still have characters to transmit, so we should continue * transmitting them when TX is ready, regardless of * mode or duplexity @@ -864,34 +859,31 @@ static void atmel_complete_tx_dma(void *arg) { struct atmel_uart_port *atmel_port = arg; struct uart_port *port = &atmel_port->uart; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (chan) dmaengine_terminate_all(chan); - xmit->tail += atmel_port->tx_len; - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += atmel_port->tx_len; + uart_xmit_advance(port, atmel_port->tx_len); - spin_lock_irq(&atmel_port->lock_tx); + spin_lock(&atmel_port->lock_tx); async_tx_ack(atmel_port->desc_tx); atmel_port->cookie_tx = -EINVAL; atmel_port->desc_tx = NULL; - spin_unlock_irq(&atmel_port->lock_tx); + spin_unlock(&atmel_port->lock_tx); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* - * xmit is a circular buffer so, if we have just send data from - * xmit->tail to the end of xmit->buf, now we have to transmit the - * remaining data from the beginning of xmit->buf to xmit->head. + * xmit is a circular buffer so, if we have just send data from the + * tail to the end, now we have to transmit the remaining data from the + * beginning to the head. */ - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); else if (atmel_uart_is_half_duplex(port)) { /* @@ -903,7 +895,7 @@ static void atmel_complete_tx_dma(void *arg) atmel_port->tx_done_mask); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void atmel_release_tx_dma(struct uart_port *port) @@ -914,8 +906,8 @@ static void atmel_release_tx_dma(struct uart_port *port) if (chan) { dmaengine_terminate_all(chan); dma_release_channel(chan); - dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1, - DMA_TO_DEVICE); + dma_unmap_single(port->dev, atmel_port->tx_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); } atmel_port->desc_tx = NULL; @@ -929,18 +921,18 @@ static void atmel_release_tx_dma(struct uart_port *port) static void atmel_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; - struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; - unsigned int tx_len, part1_len, part2_len, sg_len; + struct scatterlist sgl[2], *sg; + unsigned int tx_len, tail, part1_len, part2_len, sg_len; dma_addr_t phys_addr; /* Make sure we have an idle channel */ if (atmel_port->desc_tx != NULL) return; - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) { /* * DMA is idle now. * Port xmit buffer is already mapped, @@ -950,9 +942,8 @@ static void atmel_tx_dma(struct uart_port *port) * Take the port lock to get a * consistent xmit buffer state. */ - tx_len = CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE); + tx_len = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); if (atmel_port->fifo_size) { /* multi data mode */ @@ -966,7 +957,7 @@ static void atmel_tx_dma(struct uart_port *port) sg_init_table(sgl, 2); sg_len = 0; - phys_addr = sg_dma_address(sg_tx) + xmit->tail; + phys_addr = atmel_port->tx_phys + tail; if (part1_len) { sg = &sgl[sg_len++]; sg_dma_address(sg) = phys_addr; @@ -983,7 +974,7 @@ static void atmel_tx_dma(struct uart_port *port) /* * save tx_len so atmel_complete_tx_dma() will increase - * xmit->tail correctly + * tail correctly */ atmel_port->tx_len = tx_len; @@ -998,56 +989,61 @@ static void atmel_tx_dma(struct uart_port *port) return; } - dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); + dma_sync_single_for_device(port->dev, atmel_port->tx_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); atmel_port->desc_tx = desc; desc->callback = atmel_complete_tx_dma; desc->callback_param = atmel_port; atmel_port->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(atmel_port->cookie_tx)) { + dev_err(port->dev, "dma_submit_error %d\n", + atmel_port->cookie_tx); + return; + } + + dma_async_issue_pending(chan); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } static int atmel_prepare_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_port *tport = &port->state->port; struct device *mfd_dev = port->dev->parent; dma_cap_mask_t mask; struct dma_slave_config config; - int ret, nent; + struct dma_chan *chan; + int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx"); - if (atmel_port->chan_tx == NULL) + chan = dma_request_chan(mfd_dev, "tx"); + if (IS_ERR(chan)) { + atmel_port->chan_tx = NULL; goto chan_err; + } + atmel_port->chan_tx = chan; dev_info(port->dev, "using %s for tx DMA transfers\n", dma_chan_name(atmel_port->chan_tx)); spin_lock_init(&atmel_port->lock_tx); - sg_init_table(&atmel_port->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf)); - sg_set_page(&atmel_port->sg_tx, - virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, - offset_in_page(port->state->xmit.buf)); - nent = dma_map_sg(port->dev, - &atmel_port->sg_tx, - 1, - DMA_TO_DEVICE); - - if (!nent) { + BUG_ON(!PAGE_ALIGNED(tport->xmit_buf)); + atmel_port->tx_phys = dma_map_single(port->dev, tport->xmit_buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + if (dma_mapping_error(port->dev, atmel_port->tx_phys)) { dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, - sg_dma_len(&atmel_port->sg_tx), - port->state->xmit.buf, - &sg_dma_address(&atmel_port->sg_tx)); + dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__, + UART_XMIT_SIZE, tport->xmit_buf, + &atmel_port->tx_phys); } /* Configure the slave DMA */ @@ -1092,8 +1088,8 @@ static void atmel_release_rx_dma(struct uart_port *port) if (chan) { dmaengine_terminate_all(chan); dma_release_channel(chan); - dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, - DMA_FROM_DEVICE); + dma_unmap_single(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); } atmel_port->desc_rx = NULL; @@ -1126,10 +1122,8 @@ static void atmel_rx_from_dma(struct uart_port *port) } /* CPU claims ownership of RX DMA buffer */ - dma_sync_sg_for_cpu(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); /* * ring->head points to the end of data already written by the DMA. @@ -1138,8 +1132,8 @@ static void atmel_rx_from_dma(struct uart_port *port) * The current transfer size should not be larger than the dma buffer * length. */ - ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue; - BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx)); + ring->head = ATMEL_SERIAL_RX_SIZE - state.residue; + BUG_ON(ring->head > ATMEL_SERIAL_RX_SIZE); /* * At this point ring->head may point to the first byte right after the * last byte of the dma buffer: @@ -1153,7 +1147,7 @@ static void atmel_rx_from_dma(struct uart_port *port) * tail to the end of the buffer then reset tail. */ if (ring->head < ring->tail) { - count = sg_dma_len(&atmel_port->sg_rx) - ring->tail; + count = ATMEL_SERIAL_RX_SIZE - ring->tail; tty_insert_flip_string(tport, ring->buf + ring->tail, count); ring->tail = 0; @@ -1166,25 +1160,17 @@ static void atmel_rx_from_dma(struct uart_port *port) tty_insert_flip_string(tport, ring->buf + ring->tail, count); /* Wrap ring->head if needed */ - if (ring->head >= sg_dma_len(&atmel_port->sg_rx)) + if (ring->head >= ATMEL_SERIAL_RX_SIZE) ring->head = 0; ring->tail = ring->head; port->icount.rx += count; } - /* USART retreives ownership of RX DMA buffer */ - dma_sync_sg_for_device(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); + /* USART retrieves ownership of RX DMA buffer */ + dma_sync_single_for_device(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); } @@ -1197,40 +1183,36 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_cap_mask_t mask; struct dma_slave_config config; struct circ_buf *ring; - int ret, nent; + struct dma_chan *chan; + int ret; ring = &atmel_port->rx_ring; dma_cap_zero(mask); dma_cap_set(DMA_CYCLIC, mask); - atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx"); - if (atmel_port->chan_rx == NULL) + chan = dma_request_chan(mfd_dev, "rx"); + if (IS_ERR(chan)) { + atmel_port->chan_rx = NULL; goto chan_err; + } + atmel_port->chan_rx = chan; dev_info(port->dev, "using %s for rx DMA transfers\n", dma_chan_name(atmel_port->chan_rx)); spin_lock_init(&atmel_port->lock_rx); - sg_init_table(&atmel_port->sg_rx, 1); /* UART circular rx buffer is an aligned page. */ BUG_ON(!PAGE_ALIGNED(ring->buf)); - sg_set_page(&atmel_port->sg_rx, - virt_to_page(ring->buf), - sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, - offset_in_page(ring->buf)); - nent = dma_map_sg(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); - - if (!nent) { + atmel_port->rx_phys = dma_map_single(port->dev, ring->buf, + ATMEL_SERIAL_RX_SIZE, + DMA_FROM_DEVICE); + + if (dma_mapping_error(port->dev, atmel_port->rx_phys)) { dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, - sg_dma_len(&atmel_port->sg_rx), - ring->buf, - &sg_dma_address(&atmel_port->sg_rx)); + dev_dbg(port->dev, "%s: mapped %zu@%p to %pad\n", __func__, + ATMEL_SERIAL_RX_SIZE, ring->buf, &atmel_port->rx_phys); } /* Configure the slave DMA */ @@ -1251,9 +1233,9 @@ static int atmel_prepare_rx_dma(struct uart_port *port) * each one is half ring buffer size */ desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx, - sg_dma_address(&atmel_port->sg_rx), - sg_dma_len(&atmel_port->sg_rx), - sg_dma_len(&atmel_port->sg_rx)/2, + atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, + ATMEL_SERIAL_RX_SIZE / 2, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!desc) { @@ -1264,6 +1246,13 @@ static int atmel_prepare_rx_dma(struct uart_port *port) desc->callback_param = port; atmel_port->desc_rx = desc; atmel_port->cookie_rx = dmaengine_submit(desc); + if (dma_submit_error(atmel_port->cookie_rx)) { + dev_err(port->dev, "dma_submit_error %d\n", + atmel_port->cookie_rx); + goto chan_err; + } + + dma_async_issue_pending(atmel_port->chan_rx); return 0; @@ -1277,8 +1266,8 @@ chan_err: static void atmel_uart_timer_callback(struct timer_list *t) { - struct atmel_uart_port *atmel_port = from_timer(atmel_port, t, - uart_timer); + struct atmel_uart_port *atmel_port = timer_container_of(atmel_port, t, + uart_timer); struct uart_port *port = &atmel_port->uart; if (!atomic_read(&atmel_port->tasklet_shutdown)) { @@ -1453,18 +1442,13 @@ static void atmel_release_tx_pdc(struct uart_port *port) static void atmel_tx_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - int count; /* nothing left to transmit? */ if (atmel_uart_readl(port, ATMEL_PDC_TCR)) return; - - xmit->tail += pdc->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += pdc->ofs; + uart_xmit_advance(port, pdc->ofs); pdc->ofs = 0; /* more to transmit - setup next transfer */ @@ -1472,17 +1456,19 @@ static void atmel_tx_pdc(struct uart_port *port) /* disable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) { + unsigned int count, tail; + dma_sync_single_for_device(port->dev, pdc->dma_addr, pdc->dma_size, DMA_TO_DEVICE); - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); pdc->ofs = count; - atmel_uart_writel(port, ATMEL_PDC_TPR, - pdc->dma_addr + xmit->tail); + atmel_uart_writel(port, ATMEL_PDC_TPR, pdc->dma_addr + tail); atmel_uart_writel(port, ATMEL_PDC_TCR, count); /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); @@ -1496,7 +1482,7 @@ static void atmel_tx_pdc(struct uart_port *port) } } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -1504,9 +1490,9 @@ static int atmel_prepare_tx_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - pdc->buf = xmit->buf; + pdc->buf = tport->xmit_buf; pdc->dma_addr = dma_map_single(port->dev, pdc->buf, UART_XMIT_SIZE, @@ -1521,8 +1507,8 @@ static void atmel_rx_from_ring(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct circ_buf *ring = &atmel_port->rx_ring; - unsigned int flg; unsigned int status; + u8 flg; while (ring->head != ring->tail) { struct atmel_uart_char c; @@ -1576,13 +1562,7 @@ static void atmel_rx_from_ring(struct uart_port *port) uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); } - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void atmel_release_rx_pdc(struct uart_port *port) @@ -1667,13 +1647,7 @@ static void atmel_rx_from_pdc(struct uart_port *port) } } while (head >= pdc->dma_size); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); @@ -1722,26 +1696,28 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) /* * tasklet handling tty stuff outside the interrupt handler. */ -static void atmel_tasklet_rx_func(unsigned long data) +static void atmel_tasklet_rx_func(struct tasklet_struct *t) { - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, + tasklet_rx); + struct uart_port *port = &atmel_port->uart; /* The interrupt handler does not take the lock */ - spin_lock(&port->lock); + uart_port_lock(port); atmel_port->schedule_rx(port); - spin_unlock(&port->lock); + uart_port_unlock(port); } -static void atmel_tasklet_tx_func(unsigned long data) +static void atmel_tasklet_tx_func(struct tasklet_struct *t) { - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, + tasklet_tx); + struct uart_port *port = &atmel_port->uart; /* The interrupt handler does not take the lock */ - spin_lock(&port->lock); + uart_port_lock(port); atmel_port->schedule_tx(port); - spin_unlock(&port->lock); + uart_port_unlock(port); } static void atmel_init_property(struct atmel_uart_port *atmel_port, @@ -1751,26 +1727,16 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port, /* DMA/PDC usage specification */ if (of_property_read_bool(np, "atmel,use-dma-rx")) { - if (of_property_read_bool(np, "dmas")) { - atmel_port->use_dma_rx = true; - atmel_port->use_pdc_rx = false; - } else { - atmel_port->use_dma_rx = false; - atmel_port->use_pdc_rx = true; - } + atmel_port->use_dma_rx = of_property_present(np, "dmas"); + atmel_port->use_pdc_rx = !atmel_port->use_dma_rx; } else { atmel_port->use_dma_rx = false; atmel_port->use_pdc_rx = false; } if (of_property_read_bool(np, "atmel,use-dma-tx")) { - if (of_property_read_bool(np, "dmas")) { - atmel_port->use_dma_tx = true; - atmel_port->use_pdc_tx = false; - } else { - atmel_port->use_dma_tx = false; - atmel_port->use_pdc_tx = true; - } + atmel_port->use_dma_tx = of_property_present(np, "dmas"); + atmel_port->use_pdc_tx = !atmel_port->use_dma_tx; } else { atmel_port->use_dma_tx = false; atmel_port->use_pdc_tx = false; @@ -1832,6 +1798,7 @@ static void atmel_get_ip_name(struct uart_port *port) */ atmel_port->has_frac_baudrate = false; atmel_port->has_hw_timer = false; + atmel_port->is_usart = false; if (name == new_uart) { dev_dbg(port->dev, "Uart with hw timer"); @@ -1841,11 +1808,12 @@ static void atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "Usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; + atmel_port->is_usart = true; atmel_port->rtor = ATMEL_US_RTOR; version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { case 0x814: /* sama5d2 */ - /* fall through */ + fallthrough; case 0x701: /* sama5d4 */ atmel_port->fidi_min = 3; atmel_port->fidi_max = 65535; @@ -1870,6 +1838,7 @@ static void atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "This version is usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; + atmel_port->is_usart = true; atmel_port->rtor = ATMEL_US_RTOR; break; case 0x203: @@ -1911,10 +1880,8 @@ static int atmel_startup(struct uart_port *port) } atomic_set(&atmel_port->tasklet_shutdown, 0); - tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, - (unsigned long)port); - tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, - (unsigned long)port); + tasklet_setup(&atmel_port->tasklet_rx, atmel_tasklet_rx_func); + tasklet_setup(&atmel_port->tasklet_tx, atmel_tasklet_tx_func); /* * Initialize DMA (if necessary) @@ -2050,7 +2017,7 @@ static void atmel_shutdown(struct uart_port *port) * Prevent any tasklets being scheduled during * cleanup */ - del_timer_sync(&atmel_port->uart_timer); + timer_delete_sync(&atmel_port->uart_timer); /* Make sure that no interrupt is on the fly */ synchronize_irq(port->irq); @@ -2102,7 +2069,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); switch (state) { - case 0: + case UART_PM_STATE_ON: /* * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. @@ -2112,7 +2079,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* re-enable interrupts if we disabled some on suspend */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; - case 3: + case UART_PM_STATE_OFF: /* Back up the interrupt mask and disable all interrupts */ atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); atmel_uart_writel(port, ATMEL_US_IDR, -1); @@ -2122,6 +2089,8 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, * This is called on uart_close() or a suspend event. */ clk_disable_unprepare(atmel_port->clk); + if (__clk_is_enabled(atmel_port->gclk)) + clk_disable_unprepare(atmel_port->gclk); break; default: dev_err(port->dev, "atmel_serial: unknown pm %d\n", state); @@ -2131,19 +2100,25 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* * Change the port parameters */ -static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static void atmel_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0; + unsigned int old_mode, mode, imr, quot, div, cd, fp = 0; + unsigned int baud, actual_baud, gclk_rate; + int ret; /* save the current mode register */ mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); /* reset the mode, clock divisor, parity, stop bits and data size */ - mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | - ATMEL_US_PAR | ATMEL_US_USMODE); + if (atmel_port->is_usart) + mode &= ~(ATMEL_US_NBSTOP | ATMEL_US_PAR | ATMEL_US_CHRL | + ATMEL_US_USCLKS | ATMEL_US_USMODE); + else + mode &= ~(ATMEL_UA_BRSRCCK | ATMEL_US_PAR | ATMEL_UA_FILTER); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); @@ -2182,7 +2157,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, } else mode |= ATMEL_US_PAR_NONE; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); port->read_status_mask = ATMEL_US_OVRE; if (termios->c_iflag & INPCK) @@ -2291,10 +2266,60 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, cd = uart_get_divisor(port, baud); } - if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + /* + * If the current value of the Clock Divisor surpasses the 16 bit + * ATMEL_US_CD mask and the IP is USART, switch to the Peripheral + * Clock implicitly divided by 8. + * If the IP is UART however, keep the highest possible value for + * the CD and avoid needless division of CD, since UART IP's do not + * support implicit division of the Peripheral Clock. + */ + if (atmel_port->is_usart && cd > ATMEL_US_CD) { cd /= 8; mode |= ATMEL_US_USCLKS_MCK_DIV8; + } else { + cd = min_t(unsigned int, cd, ATMEL_US_CD); } + + /* + * If there is no Fractional Part, there is a high chance that + * we may be able to generate a baudrate closer to the desired one + * if we use the GCLK as the clock source driving the baudrate + * generator. + */ + if (!atmel_port->has_frac_baudrate) { + if (__clk_is_enabled(atmel_port->gclk)) + clk_disable_unprepare(atmel_port->gclk); + gclk_rate = clk_round_rate(atmel_port->gclk, 16 * baud); + actual_baud = clk_get_rate(atmel_port->clk) / (16 * cd); + if (gclk_rate && abs(atmel_error_rate(baud, actual_baud)) > + abs(atmel_error_rate(baud, gclk_rate / 16))) { + clk_set_rate(atmel_port->gclk, 16 * baud); + ret = clk_prepare_enable(atmel_port->gclk); + if (ret) + goto gclk_fail; + + if (atmel_port->is_usart) { + mode &= ~ATMEL_US_USCLKS; + mode |= ATMEL_US_USCLKS_GCLK; + } else { + mode |= ATMEL_UA_BRSRCCK; + } + + /* + * Set the Clock Divisor for GCLK to 1. + * Since we were able to generate the smallest + * multiple of the desired baudrate times 16, + * then we surely can generate a bigger multiple + * with the exact error rate for an equally increased + * CD. Thus no need to take into account + * a higher value for CD. + */ + cd = 1; + } + } + +gclk_fail: quot = cd | fp << ATMEL_US_FP_OFFSET; if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) @@ -2334,22 +2359,22 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, else atmel_disable_ms(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios) { if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); atmel_enable_ms(port); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } else { port->flags &= ~UPF_HARDPPS_CD; if (!UART_ENABLE_MS(port, termios->c_cflag)) { - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); atmel_disable_ms(port); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } } } @@ -2384,17 +2409,11 @@ static void atmel_release_port(struct uart_port *port) static int atmel_request_port(struct uart_port *port) { struct platform_device *mpdev = to_platform_device(port->dev->parent); - int size = resource_size(mpdev->resource); - - if (!request_mem_region(port->mapbase, size, "atmel_serial")) - return -EBUSY; if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_mem_region(port->mapbase, size); - return -ENOMEM; - } + port->membase = devm_platform_ioremap_resource(mpdev, 0); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); } return 0; @@ -2478,6 +2497,12 @@ static const struct uart_ops atmel_pops = { #endif }; +static const struct serial_rs485 atmel_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + /* * Configure the port from the platform device resource info. */ @@ -2497,8 +2522,9 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->fifosize = 1; port->dev = &pdev->dev; port->mapbase = mpdev->resource[0].start; - port->irq = mpdev->resource[1].start; + port->irq = platform_get_irq(mpdev, 0); port->rs485_config = atmel_config_rs485; + port->rs485_supported = atmel_rs485_supported; port->iso7816_config = atmel_config_iso7816; port->membase = NULL; @@ -2508,24 +2534,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, if (ret) return ret; - /* for console, the clock could already be configured */ - if (!atmel_port->clk) { - atmel_port->clk = clk_get(&mpdev->dev, "usart"); - if (IS_ERR(atmel_port->clk)) { - ret = PTR_ERR(atmel_port->clk); - atmel_port->clk = NULL; - return ret; - } - ret = clk_prepare_enable(atmel_port->clk); - if (ret) { - clk_put(atmel_port->clk); - atmel_port->clk = NULL; - return ret; - } - port->uartclk = clk_get_rate(atmel_port->clk); - clk_disable_unprepare(atmel_port->clk); - /* only enable clock when USART is in use */ - } + port->uartclk = clk_get_rate(atmel_port->clk); /* * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or @@ -2544,7 +2553,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, } #ifdef CONFIG_SERIAL_ATMEL_CONSOLE -static void atmel_console_putchar(struct uart_port *port, int ch) +static void atmel_console_putchar(struct uart_port *port, unsigned char ch) { while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); @@ -2623,18 +2632,11 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, else if (mr == ATMEL_US_PAR_ODD) *parity = 'o'; - /* - * The serial core only rounds down when matching this to a - * supported baud rate. Make sure we don't end up slightly - * lower than one of those, as it would make us fall through - * to a much lower baud rate than we really want. - */ - *baud = port->uartclk / (16 * (quot - 1)); + *baud = port->uartclk / (16 * quot); } static int __init atmel_console_setup(struct console *co, char *options) { - int ret; struct uart_port *port = &atmel_ports[co->index].uart; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int baud = 115200; @@ -2647,10 +2649,6 @@ static int __init atmel_console_setup(struct console *co, char *options) return -ENODEV; } - ret = clk_prepare_enable(atmel_ports[co->index].clk); - if (ret) - return ret; - atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -2676,6 +2674,30 @@ static struct console atmel_console = { .data = &atmel_uart, }; +static void atmel_serial_early_write(struct console *con, const char *s, + unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, atmel_console_putchar); +} + +static int __init atmel_early_console_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = atmel_serial_early_write; + + return 0; +} + +OF_EARLYCON_DECLARE(atmel_serial, "atmel,at91rm9200-usart", + atmel_early_console_setup); +OF_EARLYCON_DECLARE(atmel_serial, "atmel,at91sam9260-usart", + atmel_early_console_setup); + #define ATMEL_CONSOLE_DEVICE (&atmel_console) #else @@ -2692,7 +2714,6 @@ static struct uart_driver atmel_uart = { .cons = ATMEL_CONSOLE_DEVICE, }; -#ifdef CONFIG_PM static bool atmel_serial_clk_will_stop(void) { #ifdef CONFIG_ARCH_AT91 @@ -2702,10 +2723,9 @@ static bool atmel_serial_clk_will_stop(void) #endif } -static int atmel_serial_suspend(struct platform_device *pdev, - pm_message_t state) +static int __maybe_unused atmel_serial_suspend(struct device *dev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct uart_port *port = dev_get_drvdata(dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (uart_console(port) && console_suspend_enabled) { @@ -2730,14 +2750,14 @@ static int atmel_serial_suspend(struct platform_device *pdev, } /* we can not wake up if we're running on slow clock */ - atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); + atmel_port->may_wakeup = device_may_wakeup(dev); if (atmel_serial_clk_will_stop()) { unsigned long flags; spin_lock_irqsave(&atmel_port->lock_suspended, flags); atmel_port->suspended = true; spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); - device_set_wakeup_enable(&pdev->dev, 0); + device_set_wakeup_enable(dev, 0); } uart_suspend_port(&atmel_uart, port); @@ -2745,9 +2765,9 @@ static int atmel_serial_suspend(struct platform_device *pdev, return 0; } -static int atmel_serial_resume(struct platform_device *pdev) +static int __maybe_unused atmel_serial_resume(struct device *dev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct uart_port *port = dev_get_drvdata(dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; @@ -2782,14 +2802,10 @@ static int atmel_serial_resume(struct platform_device *pdev) spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); uart_resume_port(&atmel_uart, port); - device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); + device_set_wakeup_enable(dev, atmel_port->may_wakeup); return 0; } -#else -#define atmel_serial_suspend NULL -#define atmel_serial_resume NULL -#endif static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, struct platform_device *pdev) @@ -2878,23 +2894,36 @@ static int atmel_serial_probe(struct platform_device *pdev) atomic_set(&atmel_port->tasklet_shutdown, 0); spin_lock_init(&atmel_port->lock_suspended); + atmel_port->clk = devm_clk_get(&pdev->dev, "usart"); + if (IS_ERR(atmel_port->clk)) { + ret = PTR_ERR(atmel_port->clk); + goto err; + } + ret = clk_prepare_enable(atmel_port->clk); + if (ret) + goto err; + + atmel_port->gclk = devm_clk_get_optional(&pdev->dev, "gclk"); + if (IS_ERR(atmel_port->gclk)) { + ret = PTR_ERR(atmel_port->gclk); + goto err_clk_disable_unprepare; + } + ret = atmel_init_port(atmel_port, pdev); if (ret) - goto err_clear_bit; + goto err_clk_disable_unprepare; atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0); if (IS_ERR(atmel_port->gpios)) { ret = PTR_ERR(atmel_port->gpios); - goto err_clear_bit; + goto err_clk_disable_unprepare; } if (!atmel_use_pdc_rx(&atmel_port->uart)) { ret = -ENOMEM; - data = kmalloc_array(ATMEL_SERIAL_RINGSIZE, - sizeof(struct atmel_uart_char), - GFP_KERNEL); + data = kmalloc(ATMEL_SERIAL_RX_SIZE, GFP_KERNEL); if (!data) - goto err_alloc_ring; + goto err_clk_disable_unprepare; atmel_port->rx_ring.buf = data; } @@ -2904,26 +2933,9 @@ static int atmel_serial_probe(struct platform_device *pdev) if (ret) goto err_add_port; -#ifdef CONFIG_SERIAL_ATMEL_CONSOLE - if (uart_console(&atmel_port->uart) - && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { - /* - * The serial core enabled the clock for us, so undo - * the clk_prepare_enable() in atmel_console_setup() - */ - clk_disable_unprepare(atmel_port->clk); - } -#endif - device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, atmel_port); - /* - * The peripheral clock has been disabled by atmel_init_port(): - * enable it before accessing I/O registers - */ - clk_prepare_enable(atmel_port->clk); - if (rs485_enabled) { atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR, ATMEL_US_USMODE_NORMAL); @@ -2947,12 +2959,8 @@ static int atmel_serial_probe(struct platform_device *pdev) err_add_port: kfree(atmel_port->rx_ring.buf); atmel_port->rx_ring.buf = NULL; -err_alloc_ring: - if (!uart_console(&atmel_port->uart)) { - clk_put(atmel_port->clk); - atmel_port->clk = NULL; - } -err_clear_bit: +err_clk_disable_unprepare: + clk_disable_unprepare(atmel_port->clk); clear_bit(atmel_port->uart.line, atmel_ports_in_use); err: return ret; @@ -2967,18 +2975,17 @@ err: * protocol that needs bitbanging on IO lines, but use the regular serial * port in the normal case. */ -static int atmel_serial_remove(struct platform_device *pdev) +static void atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int ret = 0; tasklet_kill(&atmel_port->tasklet_rx); tasklet_kill(&atmel_port->tasklet_tx); device_init_wakeup(&pdev->dev, 0); - ret = uart_remove_one_port(&atmel_uart, port); + uart_remove_one_port(&atmel_uart, port); kfree(atmel_port->rx_ring.buf); @@ -2986,21 +2993,19 @@ static int atmel_serial_remove(struct platform_device *pdev) clear_bit(port->line, atmel_ports_in_use); - clk_put(atmel_port->clk); - atmel_port->clk = NULL; pdev->dev.of_node = NULL; - - return ret; } +static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, + atmel_serial_resume); + static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, .remove = atmel_serial_remove, - .suspend = atmel_serial_suspend, - .resume = atmel_serial_resume, .driver = { .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), + .pm = pm_ptr(&atmel_serial_pm_ops), }, }; diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h index 0d8a0f9cc5c3..87f8f7996307 100644 --- a/drivers/tty/serial/atmel_serial.h +++ b/drivers/tty/serial/atmel_serial.h @@ -9,6 +9,8 @@ * Based on AT91RM9200 datasheet revision E. */ +#include <linux/bitfield.h> + #ifndef ATMEL_SERIAL_H #define ATMEL_SERIAL_H @@ -39,39 +41,42 @@ #define ATMEL_US_MR 0x04 /* Mode Register */ #define ATMEL_US_USMODE GENMASK(3, 0) /* Mode of the USART */ -#define ATMEL_US_USMODE_NORMAL 0 -#define ATMEL_US_USMODE_RS485 1 -#define ATMEL_US_USMODE_HWHS 2 -#define ATMEL_US_USMODE_MODEM 3 -#define ATMEL_US_USMODE_ISO7816_T0 4 -#define ATMEL_US_USMODE_ISO7816_T1 6 -#define ATMEL_US_USMODE_IRDA 8 +#define ATMEL_US_USMODE_NORMAL FIELD_PREP(ATMEL_US_USMODE, 0) +#define ATMEL_US_USMODE_RS485 FIELD_PREP(ATMEL_US_USMODE, 1) +#define ATMEL_US_USMODE_HWHS FIELD_PREP(ATMEL_US_USMODE, 2) +#define ATMEL_US_USMODE_MODEM FIELD_PREP(ATMEL_US_USMODE, 3) +#define ATMEL_US_USMODE_ISO7816_T0 FIELD_PREP(ATMEL_US_USMODE, 4) +#define ATMEL_US_USMODE_ISO7816_T1 FIELD_PREP(ATMEL_US_USMODE, 6) +#define ATMEL_US_USMODE_IRDA FIELD_PREP(ATMEL_US_USMODE, 8) #define ATMEL_US_USCLKS GENMASK(5, 4) /* Clock Selection */ -#define ATMEL_US_USCLKS_MCK (0 << 4) -#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) -#define ATMEL_US_USCLKS_SCK (3 << 4) +#define ATMEL_US_USCLKS_MCK FIELD_PREP(ATMEL_US_USCLKS, 0) +#define ATMEL_US_USCLKS_MCK_DIV8 FIELD_PREP(ATMEL_US_USCLKS, 1) +#define ATMEL_US_USCLKS_GCLK FIELD_PREP(ATMEL_US_USCLKS, 2) +#define ATMEL_US_USCLKS_SCK FIELD_PREP(ATMEL_US_USCLKS, 3) +#define ATMEL_UA_FILTER BIT(4) #define ATMEL_US_CHRL GENMASK(7, 6) /* Character Length */ -#define ATMEL_US_CHRL_5 (0 << 6) -#define ATMEL_US_CHRL_6 (1 << 6) -#define ATMEL_US_CHRL_7 (2 << 6) -#define ATMEL_US_CHRL_8 (3 << 6) +#define ATMEL_US_CHRL_5 FIELD_PREP(ATMEL_US_CHRL, 0) +#define ATMEL_US_CHRL_6 FIELD_PREP(ATMEL_US_CHRL, 1) +#define ATMEL_US_CHRL_7 FIELD_PREP(ATMEL_US_CHRL, 2) +#define ATMEL_US_CHRL_8 FIELD_PREP(ATMEL_US_CHRL, 3) #define ATMEL_US_SYNC BIT(8) /* Synchronous Mode Select */ #define ATMEL_US_PAR GENMASK(11, 9) /* Parity Type */ -#define ATMEL_US_PAR_EVEN (0 << 9) -#define ATMEL_US_PAR_ODD (1 << 9) -#define ATMEL_US_PAR_SPACE (2 << 9) -#define ATMEL_US_PAR_MARK (3 << 9) -#define ATMEL_US_PAR_NONE (4 << 9) -#define ATMEL_US_PAR_MULTI_DROP (6 << 9) +#define ATMEL_US_PAR_EVEN FIELD_PREP(ATMEL_US_PAR, 0) +#define ATMEL_US_PAR_ODD FIELD_PREP(ATMEL_US_PAR, 1) +#define ATMEL_US_PAR_SPACE FIELD_PREP(ATMEL_US_PAR, 2) +#define ATMEL_US_PAR_MARK FIELD_PREP(ATMEL_US_PAR, 3) +#define ATMEL_US_PAR_NONE FIELD_PREP(ATMEL_US_PAR, 4) +#define ATMEL_US_PAR_MULTI_DROP FIELD_PREP(ATMEL_US_PAR, 6) #define ATMEL_US_NBSTOP GENMASK(13, 12) /* Number of Stop Bits */ -#define ATMEL_US_NBSTOP_1 (0 << 12) -#define ATMEL_US_NBSTOP_1_5 (1 << 12) -#define ATMEL_US_NBSTOP_2 (2 << 12) +#define ATMEL_US_NBSTOP_1 FIELD_PREP(ATMEL_US_NBSTOP, 0) +#define ATMEL_US_NBSTOP_1_5 FIELD_PREP(ATMEL_US_NBSTOP, 1) +#define ATMEL_US_NBSTOP_2 FIELD_PREP(ATMEL_US_NBSTOP, 2) +#define ATMEL_UA_BRSRCCK BIT(12) /* Clock Selection for UART */ #define ATMEL_US_CHMODE GENMASK(15, 14) /* Channel Mode */ -#define ATMEL_US_CHMODE_NORMAL (0 << 14) -#define ATMEL_US_CHMODE_ECHO (1 << 14) -#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) -#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) +#define ATMEL_US_CHMODE_NORMAL FIELD_PREP(ATMEL_US_CHMODE, 0) +#define ATMEL_US_CHMODE_ECHO FIELD_PREP(ATMEL_US_CHMODE, 1) +#define ATMEL_US_CHMODE_LOC_LOOP FIELD_PREP(ATMEL_US_CHMODE, 2) +#define ATMEL_US_CHMODE_REM_LOOP FIELD_PREP(ATMEL_US_CHMODE, 3) #define ATMEL_US_MSBF BIT(16) /* Bit Order */ #define ATMEL_US_MODE9 BIT(17) /* 9-bit Character Length */ #define ATMEL_US_CLKO BIT(18) /* Clock Output Select */ @@ -79,7 +84,7 @@ #define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */ #define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */ #define ATMEL_US_MAX_ITER_MASK GENMASK(26, 24) /* Max Iterations */ -#define ATMEL_US_MAX_ITER(n) (((n) << 24) & ATMEL_US_MAX_ITER_MASK) +#define ATMEL_US_MAX_ITER(n) FIELD_PREP(ATMEL_US_MAX_ITER_MASK, (n)) #define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */ #define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ @@ -131,19 +136,19 @@ #define ATMEL_US_CMPR 0x90 /* Comparaison Register */ #define ATMEL_US_FMR 0xa0 /* FIFO Mode Register */ -#define ATMEL_US_TXRDYM(data) (((data) & 0x3) << 0) /* TX Ready Mode */ -#define ATMEL_US_RXRDYM(data) (((data) & 0x3) << 4) /* RX Ready Mode */ +#define ATMEL_US_TXRDYM(data) FIELD_PREP(GENMASK(1, 0), (data)) /* TX Ready Mode */ +#define ATMEL_US_RXRDYM(data) FIELD_PREP(GENMASK(5, 4), (data)) /* RX Ready Mode */ #define ATMEL_US_ONE_DATA 0x0 #define ATMEL_US_TWO_DATA 0x1 #define ATMEL_US_FOUR_DATA 0x2 #define ATMEL_US_FRTSC BIT(7) /* FIFO RTS pin Control */ -#define ATMEL_US_TXFTHRES(thr) (((thr) & 0x3f) << 8) /* TX FIFO Threshold */ -#define ATMEL_US_RXFTHRES(thr) (((thr) & 0x3f) << 16) /* RX FIFO Threshold */ -#define ATMEL_US_RXFTHRES2(thr) (((thr) & 0x3f) << 24) /* RX FIFO Threshold2 */ +#define ATMEL_US_TXFTHRES(thr) FIELD_PREP(GENMASK(13, 8), (thr)) /* TX FIFO Threshold */ +#define ATMEL_US_RXFTHRES(thr) FIELD_PREP(GENMASK(21, 16), (thr)) /* RX FIFO Threshold */ +#define ATMEL_US_RXFTHRES2(thr) FIELD_PREP(GENMASK(29, 24), (thr)) /* RX FIFO Threshold2 */ #define ATMEL_US_FLR 0xa4 /* FIFO Level Register */ -#define ATMEL_US_TXFL(reg) (((reg) >> 0) & 0x3f) /* TX FIFO Level */ -#define ATMEL_US_RXFL(reg) (((reg) >> 16) & 0x3f) /* RX FIFO Level */ +#define ATMEL_US_TXFL(reg) FIELD_GET(GENMASK(5, 0), (reg)) /* TX FIFO Level */ +#define ATMEL_US_RXFL(reg) FIELD_GET(GENMASK(21, 16), (reg)) /* RX FIFO Level */ #define ATMEL_US_FIER 0xa8 /* FIFO Interrupt Enable Register */ #define ATMEL_US_FIDR 0xac /* FIFO Interrupt Disable Register */ diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 5674da2b76f0..51df9d2d8bfc 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -201,7 +201,7 @@ static void bcm_uart_break_ctl(struct uart_port *port, int ctl) unsigned long flags; unsigned int val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = bcm_uart_readl(port, UART_CTL_REG); if (ctl) @@ -210,7 +210,7 @@ static void bcm_uart_break_ctl(struct uart_port *port, int ctl) val &= ~UART_CTL_XMITBRK_MASK; bcm_uart_writel(port, val, UART_CTL_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* @@ -285,18 +285,15 @@ static void bcm_uart_do_rx(struct uart_port *port) flag = TTY_PARITY; } - if (uart_handle_sysrq_char(port, c)) + if (uart_prepare_sysrq_char(port, c)) continue; - if ((cstat & port->ignore_status_mask) == 0) tty_insert_flip_char(tty_port, c, flag); } while (--max_count); - spin_unlock(&port->lock); tty_flip_buffer_push(tty_port); - spin_lock(&port->lock); } /* @@ -305,53 +302,27 @@ static void bcm_uart_do_rx(struct uart_port *port) */ static void bcm_uart_do_tx(struct uart_port *port) { - struct circ_buf *xmit; - unsigned int val, max_count; - - if (port->x_char) { - bcm_uart_writel(port, port->x_char, UART_FIFO_REG); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_tx_stopped(port)) { - bcm_uart_stop_tx(port); - return; - } - - xmit = &port->state->xmit; - if (uart_circ_empty(xmit)) - goto txq_empty; + unsigned int val; + bool pending; + u8 ch; val = bcm_uart_readl(port, UART_MCTL_REG); val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; - max_count = port->fifosize - val; - - while (max_count--) { - unsigned int c; - - c = xmit->buf[xmit->tail]; - bcm_uart_writel(port, c, UART_FIFO_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - goto txq_empty; - return; + pending = uart_port_tx_limited_flags(port, ch, UART_TX_NOSTOP, + port->fifosize - val, + true, + bcm_uart_writel(port, ch, UART_FIFO_REG), + ({})); + if (pending) + return; -txq_empty: /* nothing to send, disable transmit interrupt */ val = bcm_uart_readl(port, UART_IR_REG); val &= ~UART_TX_INT_MASK; bcm_uart_writel(port, val, UART_IR_REG); - return; + + if (uart_tx_stopped(port)) + bcm_uart_stop_tx(port); } /* @@ -363,7 +334,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) unsigned int irqstat; port = dev_id; - spin_lock(&port->lock); + uart_port_lock(port); irqstat = bcm_uart_readl(port, UART_IR_REG); if (irqstat & UART_RX_INT_STAT) @@ -384,7 +355,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) estat & UART_EXTINP_DCD_MASK); } - spin_unlock(&port->lock); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -482,9 +453,9 @@ static void bcm_uart_shutdown(struct uart_port *port) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); bcm_uart_writel(port, 0, UART_IR_REG); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); bcm_uart_disable(port); bcm_uart_flush(port); @@ -494,15 +465,14 @@ static void bcm_uart_shutdown(struct uart_port *port) /* * serial core request to change current uart setting */ -static void bcm_uart_set_termios(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) +static void bcm_uart_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) { unsigned int ctl, baud, quot, ier; unsigned long flags; int tries; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Drain the hot tub fully before we power it off for the winter. */ for (tries = 3; !bcm_uart_tx_empty(port) && tries; tries--) @@ -578,7 +548,7 @@ static void bcm_uart_set_termios(struct uart_port *port, uart_update_timeout(port, new->c_cflag, baud); bcm_uart_enable(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* @@ -628,6 +598,40 @@ static int bcm_uart_verify_port(struct uart_port *port, return 0; } +#ifdef CONFIG_CONSOLE_POLL +/* + * return true when outstanding tx equals fifo size + */ +static bool bcm_uart_tx_full(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_MCTL_REG); + val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; + return !(port->fifosize - val); +} + +static int bcm_uart_poll_get_char(struct uart_port *port) +{ + unsigned int iestat; + + iestat = bcm_uart_readl(port, UART_IR_REG); + if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) + return NO_POLL_CHAR; + + return bcm_uart_readl(port, UART_FIFO_REG); +} + +static void bcm_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ + while (bcm_uart_tx_full(port)) { + cpu_relax(); + } + + bcm_uart_writel(port, c, UART_FIFO_REG); +} +#endif + /* serial core callbacks */ static const struct uart_ops bcm_uart_ops = { .tx_empty = bcm_uart_tx_empty, @@ -646,6 +650,10 @@ static const struct uart_ops bcm_uart_ops = { .request_port = bcm_uart_request_port, .config_port = bcm_uart_config_port, .verify_port = bcm_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = bcm_uart_poll_get_char, + .poll_put_char = bcm_uart_poll_put_char, +#endif }; @@ -683,7 +691,7 @@ static void wait_for_xmitr(struct uart_port *port) /* * output given char */ -static void bcm_console_putchar(struct uart_port *port, int ch) +static void bcm_console_putchar(struct uart_port *port, unsigned char ch) { wait_for_xmitr(port); bcm_uart_writel(port, ch, UART_FIFO_REG); @@ -697,20 +705,14 @@ static void bcm_console_write(struct console *co, const char *s, { struct uart_port *port; unsigned long flags; - int locked; + int locked = 1; port = &ports[co->index]; - local_irq_save(flags); - if (port->sysrq) { - /* bcm_uart_interrupt() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else { - spin_lock(&port->lock); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); /* call helper to deal with \r\n */ uart_console_write(port, s, count, bcm_console_putchar); @@ -719,8 +721,7 @@ static void bcm_console_write(struct console *co, const char *s, wait_for_xmitr(port); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } /* @@ -806,7 +807,7 @@ static struct uart_driver bcm_uart_driver = { */ static int bcm_uart_probe(struct platform_device *pdev) { - struct resource *res_mem, *res_irq; + struct resource *res_mem; struct uart_port *port; struct clk *clk; int ret; @@ -826,18 +827,15 @@ static int bcm_uart_probe(struct platform_device *pdev) return -EBUSY; memset(port, 0, sizeof(*port)); - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_mem) - return -ENODEV; - - port->mapbase = res_mem->start; - port->membase = devm_ioremap_resource(&pdev->dev, res_mem); + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res_mem); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); + port->mapbase = res_mem->start; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) - return -ENODEV; + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + port->irq = ret; clk = clk_get(&pdev->dev, "refclk"); if (IS_ERR(clk) && pdev->dev.of_node) @@ -847,7 +845,6 @@ static int bcm_uart_probe(struct platform_device *pdev) return -ENODEV; port->iotype = UPIO_MEM; - port->irq = res_irq->start; port->ops = &bcm_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->dev = &pdev->dev; @@ -866,7 +863,7 @@ static int bcm_uart_probe(struct platform_device *pdev) return 0; } -static int bcm_uart_remove(struct platform_device *pdev) +static void bcm_uart_remove(struct platform_device *pdev) { struct uart_port *port; @@ -874,7 +871,6 @@ static int bcm_uart_remove(struct platform_device *pdev) uart_remove_one_port(&bcm_uart_driver, port); /* mark port as free */ ports[pdev->id].membase = NULL; - return 0; } static const struct of_device_id bcm63xx_of_match[] = { @@ -888,7 +884,7 @@ MODULE_DEVICE_TABLE(of, bcm63xx_of_match); */ static struct platform_driver bcm_uart_platform_driver = { .probe = bcm_uart_probe, - .remove = bcm_uart_remove, + .remove = bcm_uart_remove, .driver = { .name = "bcm63xx_uart", .of_match_table = bcm63xx_of_match, diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 95abc6faa3d5..83186bf50002 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -92,8 +92,9 @@ static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct clps711x_port *s = dev_get_drvdata(port->dev); - unsigned int status, flg; + unsigned int status; u16 ch; + u8 flg; for (;;) { u32 sysflg = 0; @@ -145,7 +146,8 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct clps711x_port *s = dev_get_drvdata(port->dev); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char c; if (port->x_char) { writew(port->x_char, port->membase + UARTDR_OFFSET); @@ -154,7 +156,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) return IRQ_HANDLED; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { if (s->tx_enabled) { disable_irq_nosync(port->irq); s->tx_enabled = 0; @@ -162,19 +164,17 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) return IRQ_HANDLED; } - while (!uart_circ_empty(xmit)) { + while (uart_fifo_get(port, &c)) { u32 sysflg = 0; - writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + writew(c, port->membase + UARTDR_OFFSET); regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); if (sysflg & SYSFLG_UTXFF) break; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); return IRQ_HANDLED; @@ -251,7 +251,7 @@ static void uart_clps711x_shutdown(struct uart_port *port) static void uart_clps711x_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { u32 ubrlcr; unsigned int baud, quot; @@ -348,7 +348,7 @@ static const struct uart_ops uart_clps711x_ops = { }; #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -static void uart_clps711x_console_putchar(struct uart_port *port, int ch) +static void uart_clps711x_console_putchar(struct uart_port *port, unsigned char ch) { struct clps711x_port *s = dev_get_drvdata(port->dev); u32 sysflg = 0; @@ -451,8 +451,7 @@ static int uart_clps711x_probe(struct platform_device *pdev) if (IS_ERR(uart_clk)) return PTR_ERR(uart_clk); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - s->port.membase = devm_ioremap_resource(&pdev->dev, res); + s->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(s->port.membase)) return PTR_ERR(s->port.membase); @@ -511,11 +510,11 @@ static int uart_clps711x_probe(struct platform_device *pdev) return ret; } -static int uart_clps711x_remove(struct platform_device *pdev) +static void uart_clps711x_remove(struct platform_device *pdev) { struct clps711x_port *s = platform_get_drvdata(pdev); - return uart_remove_one_port(&clps711x_uart, &s->port); + uart_remove_one_port(&clps711x_uart, &s->port); } static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { @@ -530,7 +529,7 @@ static struct platform_driver clps711x_uart_platform = { .of_match_table = of_match_ptr(clps711x_uart_dt_ids), }, .probe = uart_clps711x_probe, - .remove = uart_clps711x_remove, + .remove = uart_clps711x_remove, }; static int __init uart_clps711x_init(void) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart.c index a04f74d2e854..b778a20ec9b1 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart.c @@ -26,17 +26,17 @@ #include <linux/device.h> #include <linux/memblock.h> #include <linux/dma-mapping.h> -#include <linux/fs_uart_pd.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/gpio/consumer.h> #include <linux/clk.h> +#include <sysdev/fsl_soc.h> + #include <asm/io.h> #include <asm/irq.h> #include <asm/delay.h> -#include <asm/fs_pd.h> #include <asm/udbg.h> #include <linux/serial_core.h> @@ -48,14 +48,17 @@ /**************************************************************/ static int cpm_uart_tx_pump(struct uart_port *port); -static void cpm_uart_init_smc(struct uart_cpm_port *pinfo); -static void cpm_uart_init_scc(struct uart_cpm_port *pinfo); static void cpm_uart_initbd(struct uart_cpm_port *pinfo); /**************************************************************/ #define HW_BUF_SPD_THRESHOLD 2400 +static void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + cpm_command(port->command, cmd); +} + /* * Check, if transmit buffers are processed */ @@ -484,12 +487,11 @@ static void cpm_uart_shutdown(struct uart_port *port) static void cpm_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { int baud; unsigned long flags; u16 cval, scval, prev_mode; - int bits, sbits; struct uart_cpm_port *pinfo = container_of(port, struct uart_cpm_port, port); smc_t __iomem *smcp = pinfo->smcp; @@ -499,8 +501,7 @@ static void cpm_uart_set_termios(struct uart_port *port, pr_debug("CPM uart[%d]:set_termios\n", port->line); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - if (baud < HW_BUF_SPD_THRESHOLD || - (pinfo->port.state && pinfo->port.state->port.low_latency)) + if (baud < HW_BUF_SPD_THRESHOLD || port->flags & UPF_LOW_LATENCY) pinfo->rx_fifosize = 1; else pinfo->rx_fifosize = RX_BUF_SIZE; @@ -516,45 +517,17 @@ static void cpm_uart_set_termios(struct uart_port *port, if (maxidl > 0x10) maxidl = 0x10; - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ cval = 0; scval = 0; - /* byte size */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = 5; - break; - case CS6: - bits = 6; - break; - case CS7: - bits = 7; - break; - case CS8: - bits = 8; - break; - /* Never happens, but GCC is too dumb to figure it out */ - default: - bits = 8; - break; - } - sbits = bits - 5; - if (termios->c_cflag & CSTOPB) { cval |= SMCMR_SL; /* Two stops */ scval |= SCU_PSMR_SL; - bits++; } if (termios->c_cflag & PARENB) { cval |= SMCMR_PEN; scval |= SCU_PSMR_PEN; - bits++; if (!(termios->c_cflag & PARODD)) { cval |= SMCMR_PM_EVEN; scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); @@ -596,14 +569,11 @@ static void cpm_uart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->read_status_mask &= ~BD_SC_EMPTY; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; if (IS_SMC(pinfo)) { + unsigned int bits = tty_get_frame_size(termios->c_cflag); + /* * MRBLR can be changed while an SMC/SCC is operating only * if it is done in a single bus cycle with one 16-bit move @@ -622,20 +592,24 @@ static void cpm_uart_set_termios(struct uart_port *port, */ prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN); /* Output in *one* operation, so we don't interrupt RX/TX if they - * were already enabled. */ - out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | - SMCMR_SM_UART | prev_mode); + * were already enabled. + * Character length programmed into the register is frame bits minus 1. + */ + out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits - 1) | cval | + SMCMR_SM_UART | prev_mode); } else { + unsigned int bits = tty_get_char_size(termios->c_cflag); + out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); out_be16(&pinfo->sccup->scc_maxidl, maxidl); - out_be16(&sccp->scc_psmr, (sbits << 12) | scval); + out_be16(&sccp->scc_psmr, (UART_LCR_WLEN(bits) << 12) | scval); } if (pinfo->clk) clk_set_rate(pinfo->clk, baud); else - cpm_set_brg(pinfo->brg - 1, baud); - spin_unlock_irqrestore(&port->lock, flags); + cpm_setbrg(pinfo->brg - 1, baud); + uart_port_unlock_irqrestore(port, flags); } static const char *cpm_uart_type(struct uart_port *port) @@ -657,7 +631,7 @@ static int cpm_uart_verify_port(struct uart_port *port, if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; @@ -674,7 +648,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) int count; struct uart_cpm_port *pinfo = container_of(port, struct uart_cpm_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; /* Handle xon/xoff */ if (port->x_char) { @@ -699,7 +673,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) return 1; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { cpm_uart_stop_tx(port); return 0; } @@ -708,17 +682,9 @@ static int cpm_uart_tx_pump(struct uart_port *port) bdp = pinfo->tx_cur; while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && - xmit->tail != xmit->head) { - count = 0; + !kfifo_is_empty(&tport->xmit_fifo)) { p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); - while (count < pinfo->tx_fifosize) { - *p++ = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - count++; - if (xmit->head == xmit->tail) - break; - } + count = uart_fifo_out(port, p, pinfo->tx_fifosize); out_be16(&bdp->cbd_datlen, count); setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ @@ -729,10 +695,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) } pinfo->tx_cur = bdp; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { cpm_uart_stop_tx(port); return 0; } @@ -802,7 +768,8 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) * parameter ram. */ - cpm_set_scc_fcr(sup); + out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB); out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); out_be16(&sup->scc_maxidl, 0x10); @@ -873,7 +840,8 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) /* Set up the uart parameters in the * parameter ram. */ - cpm_set_smc_fcr(up); + out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB); /* Using idle character time requires some additional tuning. */ out_be16(&up->smc_mrblr, pinfo->rx_fifosize); @@ -895,6 +863,78 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) } /* + * Allocate DP-Ram and memory buffers. We need to allocate a transmit and + * receive buffer descriptors from dual port ram, and a character + * buffer area from host mem. If we are allocating for the console we need + * to do it from bootmem + */ +static int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) +{ + int dpmemsz, memsz; + u8 __iomem *dp_mem; + unsigned long dp_offset; + u8 *mem_addr; + dma_addr_t dma_addr = 0; + + pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); + + dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); + dp_offset = cpm_muram_alloc(dpmemsz, 8); + if (IS_ERR_VALUE(dp_offset)) { + pr_err("%s: could not allocate buffer descriptors\n", __func__); + return -ENOMEM; + } + + dp_mem = cpm_muram_addr(dp_offset); + + memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); + if (IS_ENABLED(CONFIG_CPM1) && is_con) { + /* was hostalloc but changed cause it blows away the */ + /* large tlb mapping when pinning the kernel area */ + mem_addr = (u8 __force *)cpm_muram_addr(cpm_muram_alloc(memsz, 8)); + dma_addr = cpm_muram_dma((void __iomem *)mem_addr); + } else if (is_con) { + mem_addr = kzalloc(memsz, GFP_NOWAIT); + dma_addr = virt_to_bus(mem_addr); + } else { + mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, + GFP_KERNEL); + } + + if (!mem_addr) { + cpm_muram_free(dp_offset); + pr_err("%s: could not allocate coherent memory\n", __func__); + return -ENOMEM; + } + + pinfo->dp_addr = dp_offset; + pinfo->mem_addr = mem_addr; + pinfo->dma_addr = dma_addr; + pinfo->mem_size = memsz; + + pinfo->rx_buf = mem_addr; + pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos + * pinfo->rx_fifosize); + + pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem; + pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; + + return 0; +} + +static void cpm_uart_freebuf(struct uart_cpm_port *pinfo) +{ + dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * + pinfo->rx_fifosize) + + L1_CACHE_ALIGN(pinfo->tx_nrfifos * + pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, + pinfo->dma_addr); + + cpm_muram_free(pinfo->dp_addr); +} + +/* * Initialize port. This is called from early_console stuff * so we have to be careful here ! */ @@ -1107,6 +1147,34 @@ static void cpm_put_poll_char(struct uart_port *port, ch[0] = (char)c; cpm_uart_early_write(pinfo, ch, 1, false); } + +#ifdef CONFIG_SERIAL_CPM_CONSOLE +static struct uart_port *udbg_port; + +static void udbg_cpm_putc(char c) +{ + if (c == '\n') + cpm_put_poll_char(udbg_port, '\r'); + cpm_put_poll_char(udbg_port, c); +} + +static int udbg_cpm_getc_poll(void) +{ + int c = cpm_get_poll_char(udbg_port); + + return c == NO_POLL_CHAR ? -1 : c; +} + +static int udbg_cpm_getc(void) +{ + int c; + + while ((c = udbg_cpm_getc_poll()) == -1) + cpu_relax(); + return c; +} +#endif /* CONFIG_SERIAL_CPM_CONSOLE */ + #endif /* CONFIG_CONSOLE_POLL */ static const struct uart_ops cpm_uart_pops = { @@ -1131,7 +1199,55 @@ static const struct uart_ops cpm_uart_pops = { #endif }; -struct uart_cpm_port cpm_uart_ports[UART_NR]; +static struct uart_cpm_port cpm_uart_ports[UART_NR]; + +static void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np) +{ + void __iomem *pram; + unsigned long offset; + struct resource res; + resource_size_t len; + + /* Don't remap parameter RAM if it has already been initialized + * during console setup. + */ + if (IS_SMC(port) && port->smcup) + return port->smcup; + else if (!IS_SMC(port) && port->sccup) + return port->sccup; + + if (of_address_to_resource(np, 1, &res)) + return NULL; + + len = resource_size(&res); + pram = ioremap(res.start, len); + if (!pram) + return NULL; + + if (!IS_ENABLED(CONFIG_CPM2) || !IS_SMC(port)) + return pram; + + if (len != 2) { + pr_warn("cpm_uart[%d]: device tree references " + "SMC pram, using boot loader/wrapper pram mapping. " + "Please fix your device tree to reference the pram " + "base register instead.\n", + port->port.line); + return pram; + } + + offset = cpm_muram_alloc(64, 64); + out_be16(pram, offset); + iounmap(pram); + return cpm_muram_addr(offset); +} + +static void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) +{ + if (!IS_ENABLED(CONFIG_CPM2) || !IS_SMC(port)) + iounmap(pram); +} static int cpm_uart_init_port(struct device_node *np, struct uart_cpm_port *pinfo) @@ -1204,18 +1320,17 @@ static int cpm_uart_init_port(struct device_node *np, pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; spin_lock_init(&pinfo->port.lock); - pinfo->port.irq = irq_of_parse_and_map(np, 0); - if (pinfo->port.irq == NO_IRQ) { - ret = -EINVAL; - goto out_pram; - } - for (i = 0; i < NUM_GPIOS; i++) { struct gpio_desc *gpiod; pinfo->gpios[i] = NULL; - gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); + gpiod = devm_gpiod_get_index_optional(dev, NULL, i, GPIOD_ASIS); + + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + goto out_pram; + } if (gpiod) { if (i == GPIO_RTS || i == GPIO_DTR) @@ -1232,7 +1347,10 @@ static int cpm_uart_init_port(struct device_node *np, } #ifdef CONFIG_PPC_EARLY_DEBUG_CPM - udbg_putc = NULL; +#if defined(CONFIG_CONSOLE_POLL) && defined(CONFIG_SERIAL_CPM_CONSOLE) + if (!udbg_port) +#endif + udbg_putc = NULL; #endif return cpm_uart_request_port(&pinfo->port); @@ -1256,20 +1374,15 @@ static void cpm_uart_console_write(struct console *co, const char *s, { struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index]; unsigned long flags; - int nolock = oops_in_progress; - if (unlikely(nolock)) { + if (unlikely(oops_in_progress)) { local_irq_save(flags); - } else { - spin_lock_irqsave(&pinfo->port.lock, flags); - } - - cpm_uart_early_write(pinfo, s, count, true); - - if (unlikely(nolock)) { + cpm_uart_early_write(pinfo, s, count, true); local_irq_restore(flags); } else { - spin_unlock_irqrestore(&pinfo->port.lock, flags); + uart_port_lock_irqsave(&pinfo->port, &flags); + cpm_uart_early_write(pinfo, s, count, true); + uart_port_unlock_irqrestore(&pinfo->port, flags); } } @@ -1320,7 +1433,8 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); } else { - if ((baud = uart_baudrate()) == -1) + baud = get_baudrate(); + if (baud == -1) baud = 9600; } @@ -1351,6 +1465,15 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) uart_set_options(port, co, baud, parity, bits, flow); cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); +#ifdef CONFIG_CONSOLE_POLL + if (!udbg_port) { + udbg_port = &pinfo->port; + udbg_putc = udbg_cpm_putc; + udbg_getc = udbg_cpm_getc; + udbg_getc_poll = udbg_cpm_getc_poll; + } +#endif + return 0; } @@ -1407,17 +1530,24 @@ static int cpm_uart_probe(struct platform_device *ofdev) /* initialize the device pointer for the port */ pinfo->port.dev = &ofdev->dev; + pinfo->port.irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + if (!pinfo->port.irq) + return -EINVAL; + ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo); - if (ret) - return ret; + if (!ret) + return uart_add_one_port(&cpm_reg, &pinfo->port); + + irq_dispose_mapping(pinfo->port.irq); - return uart_add_one_port(&cpm_reg, &pinfo->port); + return ret; } -static int cpm_uart_remove(struct platform_device *ofdev) +static void cpm_uart_remove(struct platform_device *ofdev) { struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev); - return uart_remove_one_port(&cpm_reg, &pinfo->port); + + uart_remove_one_port(&cpm_reg, &pinfo->port); } static const struct of_device_id cpm_uart_match[] = { diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart.h index 6113b953ce25..37bb6e976e03 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart.h @@ -11,41 +11,31 @@ #define CPM_UART_H #include <linux/platform_device.h> -#include <linux/fs_uart_pd.h> struct gpio_desc; #if defined(CONFIG_CPM2) -#include "cpm_uart_cpm2.h" +#include "asm/cpm2.h" #elif defined(CONFIG_CPM1) -#include "cpm_uart_cpm1.h" +#include "asm/cpm1.h" #endif +#define DPRAM_BASE ((u8 __iomem *)cpm_muram_addr(0)) + #define SERIAL_CPM_MAJOR 204 #define SERIAL_CPM_MINOR 46 #define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC) -#define IS_DISCARDING(pinfo) (pinfo->flags & FLAG_DISCARDING) -#define FLAG_DISCARDING 0x00000004 /* when set, don't discard */ #define FLAG_SMC 0x00000002 #define FLAG_CONSOLE 0x00000001 -#define UART_SMC1 fsid_smc1_uart -#define UART_SMC2 fsid_smc2_uart -#define UART_SCC1 fsid_scc1_uart -#define UART_SCC2 fsid_scc2_uart -#define UART_SCC3 fsid_scc3_uart -#define UART_SCC4 fsid_scc4_uart - -#define UART_NR fs_uart_nr +#define UART_NR 6 #define RX_NUM_FIFO 4 #define RX_BUF_SIZE 32 #define TX_NUM_FIFO 4 #define TX_BUF_SIZE 32 -#define SCC_WAIT_CLOSING 100 - #define GPIO_CTS 0 #define GPIO_RTS 1 #define GPIO_DCD 2 @@ -85,25 +75,6 @@ struct uart_cpm_port { struct gpio_desc *gpios[NUM_GPIOS]; }; -extern int cpm_uart_nr; -extern struct uart_cpm_port cpm_uart_ports[UART_NR]; - -/* these are located in their respective files */ -void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd); -void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, - struct device_node *np); -void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram); -int cpm_uart_init_portdesc(void); -int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); -void cpm_uart_freebuf(struct uart_cpm_port *pinfo); - -void smc1_lineif(struct uart_cpm_port *pinfo); -void smc2_lineif(struct uart_cpm_port *pinfo); -void scc1_lineif(struct uart_cpm_port *pinfo); -void scc2_lineif(struct uart_cpm_port *pinfo); -void scc3_lineif(struct uart_cpm_port *pinfo); -void scc4_lineif(struct uart_cpm_port *pinfo); - /* virtual to phys transtalion */ diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile deleted file mode 100644 index 3f3a6ed02ed4..000000000000 --- a/drivers/tty/serial/cpm_uart/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Motorola 8xx FEC ethernet controller -# - -obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o - -# Select the correct platform objects. -cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o -cpm_uart-objs-$(CONFIG_CPM1) += cpm_uart_cpm1.o - -cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c deleted file mode 100644 index 56fc527015cb..000000000000 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for CPM (SCC/SMC) serial ports; CPM1 definitions - * - * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) - * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * - * Copyright (C) 2004 Freescale Semiconductor, Inc. - * (C) 2004 Intracom, S.A. - * (C) 2006 MontaVista Software, Inc. - * Vitaly Bordug <vbordug@ru.mvista.com> - */ - -#include <linux/module.h> -#include <linux/tty.h> -#include <linux/gfp.h> -#include <linux/ioport.h> -#include <linux/serial.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/device.h> -#include <linux/memblock.h> -#include <linux/dma-mapping.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/fs_pd.h> - -#include <linux/serial_core.h> -#include <linux/kernel.h> - -#include <linux/of.h> -#include <linux/of_address.h> - -#include "cpm_uart.h" - -/**************************************************************/ - -void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) -{ - cpm_command(port->command, cmd); -} - -void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, - struct device_node *np) -{ - return of_iomap(np, 1); -} - -void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) -{ - iounmap(pram); -} - -/* - * Allocate DP-Ram and memory buffers. We need to allocate a transmit and - * receive buffer descriptors from dual port ram, and a character - * buffer area from host mem. If we are allocating for the console we need - * to do it from bootmem - */ -int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) -{ - int dpmemsz, memsz; - u8 *dp_mem; - unsigned long dp_offset; - u8 *mem_addr; - dma_addr_t dma_addr = 0; - - pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); - - dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); - dp_offset = cpm_dpalloc(dpmemsz, 8); - if (IS_ERR_VALUE(dp_offset)) { - printk(KERN_ERR - "cpm_uart_cpm1.c: could not allocate buffer descriptors\n"); - return -ENOMEM; - } - dp_mem = cpm_dpram_addr(dp_offset); - - memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); - if (is_con) { - /* was hostalloc but changed cause it blows away the */ - /* large tlb mapping when pinning the kernel area */ - mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); - dma_addr = (u32)cpm_dpram_phys(mem_addr); - } else - mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, - GFP_KERNEL); - - if (mem_addr == NULL) { - cpm_dpfree(dp_offset); - printk(KERN_ERR - "cpm_uart_cpm1.c: could not allocate coherent memory\n"); - return -ENOMEM; - } - - pinfo->dp_addr = dp_offset; - pinfo->mem_addr = mem_addr; /* virtual address*/ - pinfo->dma_addr = dma_addr; /* physical address*/ - pinfo->mem_size = memsz; - - pinfo->rx_buf = mem_addr; - pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos - * pinfo->rx_fifosize); - - pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; - pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; - - return 0; -} - -void cpm_uart_freebuf(struct uart_cpm_port *pinfo) -{ - dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * - pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * - pinfo->tx_fifosize), pinfo->mem_addr, - pinfo->dma_addr); - - cpm_dpfree(pinfo->dp_addr); -} diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h deleted file mode 100644 index 18ec0849918a..000000000000 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Driver for CPM (SCC/SMC) serial ports - * - * definitions for cpm1 - * - */ - -#ifndef CPM_UART_CPM1_H -#define CPM_UART_CPM1_H - -#include <asm/cpm1.h> - -static inline void cpm_set_brg(int brg, int baud) -{ - cpm_setbrg(brg, baud); -} - -static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup) -{ - out_8(&sup->scc_genscc.scc_rfcr, SMC_EB); - out_8(&sup->scc_genscc.scc_tfcr, SMC_EB); -} - -static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up) -{ - out_8(&up->smc_rfcr, SMC_EB); - out_8(&up->smc_tfcr, SMC_EB); -} - -#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) - -#endif diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c deleted file mode 100644 index 6a1cd03bfe39..000000000000 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for CPM (SCC/SMC) serial ports; CPM2 definitions - * - * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) - * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * - * Copyright (C) 2004 Freescale Semiconductor, Inc. - * (C) 2004 Intracom, S.A. - * (C) 2006 MontaVista Software, Inc. - * Vitaly Bordug <vbordug@ru.mvista.com> - */ - -#include <linux/module.h> -#include <linux/tty.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/serial.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/device.h> -#include <linux/memblock.h> -#include <linux/dma-mapping.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/fs_pd.h> -#include <asm/prom.h> - -#include <linux/serial_core.h> -#include <linux/kernel.h> - -#include "cpm_uart.h" - -/**************************************************************/ - -void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) -{ - cpm_command(port->command, cmd); -} - -void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, - struct device_node *np) -{ - void __iomem *pram; - unsigned long offset; - struct resource res; - resource_size_t len; - - /* Don't remap parameter RAM if it has already been initialized - * during console setup. - */ - if (IS_SMC(port) && port->smcup) - return port->smcup; - else if (!IS_SMC(port) && port->sccup) - return port->sccup; - - if (of_address_to_resource(np, 1, &res)) - return NULL; - - len = resource_size(&res); - pram = ioremap(res.start, len); - if (!pram) - return NULL; - - if (!IS_SMC(port)) - return pram; - - if (len != 2) { - printk(KERN_WARNING "cpm_uart[%d]: device tree references " - "SMC pram, using boot loader/wrapper pram mapping. " - "Please fix your device tree to reference the pram " - "base register instead.\n", - port->port.line); - return pram; - } - - offset = cpm_dpalloc(PROFF_SMC_SIZE, 64); - out_be16(pram, offset); - iounmap(pram); - return cpm_muram_addr(offset); -} - -void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) -{ - if (!IS_SMC(port)) - iounmap(pram); -} - -/* - * Allocate DP-Ram and memory buffers. We need to allocate a transmit and - * receive buffer descriptors from dual port ram, and a character - * buffer area from host mem. If we are allocating for the console we need - * to do it from bootmem - */ -int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) -{ - int dpmemsz, memsz; - u8 __iomem *dp_mem; - unsigned long dp_offset; - u8 *mem_addr; - dma_addr_t dma_addr = 0; - - pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); - - dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); - dp_offset = cpm_dpalloc(dpmemsz, 8); - if (IS_ERR_VALUE(dp_offset)) { - printk(KERN_ERR - "cpm_uart_cpm.c: could not allocate buffer descriptors\n"); - return -ENOMEM; - } - - dp_mem = cpm_dpram_addr(dp_offset); - - memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); - if (is_con) { - mem_addr = kzalloc(memsz, GFP_NOWAIT); - dma_addr = virt_to_bus(mem_addr); - } - else - mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, - GFP_KERNEL); - - if (mem_addr == NULL) { - cpm_dpfree(dp_offset); - printk(KERN_ERR - "cpm_uart_cpm.c: could not allocate coherent memory\n"); - return -ENOMEM; - } - - pinfo->dp_addr = dp_offset; - pinfo->mem_addr = mem_addr; - pinfo->dma_addr = dma_addr; - pinfo->mem_size = memsz; - - pinfo->rx_buf = mem_addr; - pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos - * pinfo->rx_fifosize); - - pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem; - pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; - - return 0; -} - -void cpm_uart_freebuf(struct uart_cpm_port *pinfo) -{ - dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * - pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * - pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, - pinfo->dma_addr); - - cpm_dpfree(pinfo->dp_addr); -} diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h deleted file mode 100644 index 051a8509c3e5..000000000000 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Driver for CPM (SCC/SMC) serial ports - * - * definitions for cpm2 - * - */ - -#ifndef CPM_UART_CPM2_H -#define CPM_UART_CPM2_H - -#include <asm/cpm2.h> - -static inline void cpm_set_brg(int brg, int baud) -{ - cpm_setbrg(brg, baud); -} - -static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup) -{ - out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB); - out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB); -} - -static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up) -{ - out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB); - out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB); -} - -#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) - -#endif diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index 13ac36e2da4f..d2482df5cb9b 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -133,11 +133,10 @@ static void digicolor_uart_rx(struct uart_port *port) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); while (1) { - u8 status, ch; - unsigned int ch_flag; + u8 status, ch, ch_flag; if (digicolor_uart_rx_empty(port)) break; @@ -173,20 +172,21 @@ static void digicolor_uart_rx(struct uart_port *port) ch_flag); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); tty_flip_buffer_push(&port->state->port); } static void digicolor_uart_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; + unsigned char c; if (digicolor_uart_tx_full(port)) return; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (port->x_char) { writeb_relaxed(port->x_char, port->membase + UA_EMI_REC); @@ -195,25 +195,23 @@ static void digicolor_uart_tx(struct uart_port *port) goto out; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { digicolor_uart_stop_tx(port); goto out; } - while (!uart_circ_empty(xmit)) { - writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + while (uart_fifo_get(port, &c)) { + writeb(c, port->membase + UA_EMI_REC); if (digicolor_uart_tx_full(port)) break; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); out: - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static irqreturn_t digicolor_uart_int(int irq, void *dev_id) @@ -287,7 +285,7 @@ static void digicolor_uart_shutdown(struct uart_port *port) static void digicolor_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud, divisor; u8 config = 0; @@ -309,6 +307,8 @@ static void digicolor_uart_set_termios(struct uart_port *port, case CS8: default: config |= UA_CONFIG_CHAR_LEN; + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; break; } @@ -333,7 +333,7 @@ static void digicolor_uart_set_termios(struct uart_port *port, port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR | UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, termios->c_cflag, baud); @@ -341,7 +341,7 @@ static void digicolor_uart_set_termios(struct uart_port *port, writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO); writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *digicolor_uart_type(struct uart_port *port) @@ -381,7 +381,7 @@ static const struct uart_ops digicolor_uart_ops = { .request_port = digicolor_uart_request_port, }; -static void digicolor_uart_console_putchar(struct uart_port *port, int ch) +static void digicolor_uart_console_putchar(struct uart_port *port, unsigned char ch) { while (digicolor_uart_tx_full(port)) cpu_relax(); @@ -398,14 +398,14 @@ static void digicolor_uart_console_write(struct console *co, const char *c, int locked = 1; if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_console_write(port, c, n, digicolor_uart_console_putchar); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Wait for transmitter to become empty */ do { @@ -471,11 +471,10 @@ static int digicolor_uart_probe(struct platform_device *pdev) if (IS_ERR(uart_clk)) return PTR_ERR(uart_clk); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dp->port.mapbase = res->start; - dp->port.membase = devm_ioremap_resource(&pdev->dev, res); + dp->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dp->port.membase)) return PTR_ERR(dp->port.membase); + dp->port.mapbase = res->start; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -504,13 +503,11 @@ static int digicolor_uart_probe(struct platform_device *pdev) return uart_add_one_port(&digicolor_uart, &dp->port); } -static int digicolor_uart_remove(struct platform_device *pdev) +static void digicolor_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&digicolor_uart, port); - - return 0; } static const struct of_device_id digicolor_uart_dt_ids[] = { @@ -525,7 +522,7 @@ static struct platform_driver digicolor_uart_platform = { .of_match_table = of_match_ptr(digicolor_uart_dt_ids), }, .probe = digicolor_uart_probe, - .remove = digicolor_uart_remove, + .remove = digicolor_uart_remove, }; static int __init digicolor_uart_init(void) diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 4552742c3859..eba91daedef8 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -47,8 +47,8 @@ #include <linux/tty_flip.h> #include <linux/atomic.h> +#include <linux/io.h> #include <asm/bootinfo.h> -#include <asm/io.h> #include <asm/dec/interrupts.h> #include <asm/dec/kn01.h> @@ -115,7 +115,7 @@ static void dz_out(struct dz_port *dport, unsigned offset, u16 value) * rs_stop () and rs_start () * * These routines are called before setting or resetting - * tty->stopped. They enable or disable transmitter interrupts, + * tty->flow.stopped. They enable or disable transmitter interrupts, * as necessary. * ------------------------------------------------------------ */ @@ -181,8 +181,8 @@ static inline void dz_receive_chars(struct dz_mux *mux) struct dz_port *dport = &mux->dport[0]; struct uart_icount *icount; int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 }; - unsigned char ch, flag; u16 status; + u8 ch, flag; int i; while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) { @@ -252,13 +252,13 @@ static inline void dz_receive_chars(struct dz_mux *mux) static inline void dz_transmit_chars(struct dz_mux *mux) { struct dz_port *dport = &mux->dport[0]; - struct circ_buf *xmit; + struct tty_port *tport; unsigned char tmp; u16 status; status = dz_in(dport, DZ_CSR); dport = &mux->dport[LINE(status)]; - xmit = &dport->port.state->xmit; + tport = &dport->port.state->port; if (dport->port.x_char) { /* XON/XOFF chars */ dz_out(dport, DZ_TDR, dport->port.x_char); @@ -267,10 +267,11 @@ static inline void dz_transmit_chars(struct dz_mux *mux) return; } /* If nothing to do or stopped or hardware stopped. */ - if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { - spin_lock(&dport->port.lock); + if (uart_tx_stopped(&dport->port) || + !uart_fifo_get(&dport->port, &tmp)) { + uart_port_lock(&dport->port); dz_stop_tx(&dport->port); - spin_unlock(&dport->port.lock); + uart_port_unlock(&dport->port); return; } @@ -278,19 +279,16 @@ static inline void dz_transmit_chars(struct dz_mux *mux) * If something to do... (remember the dz has no output fifo, * so we go one char at a time) :-< */ - tmp = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1); dz_out(dport, DZ_TDR, tmp); - dport->port.icount.tx++; - if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < DZ_WAKEUP_CHARS) uart_write_wakeup(&dport->port); /* Are we are done. */ - if (uart_circ_empty(xmit)) { - spin_lock(&dport->port.lock); + if (kfifo_is_empty(&tport->xmit_fifo)) { + uart_port_lock(&dport->port); dz_stop_tx(&dport->port); - spin_unlock(&dport->port.lock); + uart_port_unlock(&dport->port); } } @@ -416,14 +414,14 @@ static int dz_startup(struct uart_port *uport) return ret; } - spin_lock_irqsave(&dport->port.lock, flags); + uart_port_lock_irqsave(&dport->port, &flags); /* Enable interrupts. */ tmp = dz_in(dport, DZ_CSR); tmp |= DZ_RIE | DZ_TIE; dz_out(dport, DZ_CSR, tmp); - spin_unlock_irqrestore(&dport->port.lock, flags); + uart_port_unlock_irqrestore(&dport->port, flags); return 0; } @@ -444,9 +442,9 @@ static void dz_shutdown(struct uart_port *uport) int irq_guard; u16 tmp; - spin_lock_irqsave(&dport->port.lock, flags); + uart_port_lock_irqsave(&dport->port, &flags); dz_stop_tx(&dport->port); - spin_unlock_irqrestore(&dport->port.lock, flags); + uart_port_unlock_irqrestore(&dport->port, flags); irq_guard = atomic_add_return(-1, &mux->irq_guard); if (!irq_guard) { @@ -492,14 +490,14 @@ static void dz_break_ctl(struct uart_port *uport, int break_state) unsigned long flags; unsigned short tmp, mask = 1 << dport->port.line; - spin_lock_irqsave(&uport->lock, flags); + uart_port_lock_irqsave(uport, &flags); tmp = dz_in(dport, DZ_TCR); if (break_state) tmp |= mask; else tmp &= ~mask; dz_out(dport, DZ_TCR, tmp); - spin_unlock_irqrestore(&uport->lock, flags); + uart_port_unlock_irqrestore(uport, flags); } static int dz_encode_baud_rate(unsigned int baud) @@ -559,7 +557,7 @@ static void dz_reset(struct dz_port *dport) } static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct dz_port *dport = to_dport(uport); unsigned long flags; @@ -592,9 +590,12 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600); bflag = dz_encode_baud_rate(baud); - if (bflag < 0) { /* Try to keep unchanged. */ - baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600); - bflag = dz_encode_baud_rate(baud); + if (bflag < 0) { + if (old_termios) { + /* Keep unchanged. */ + baud = tty_termios_baud_rate(old_termios); + bflag = dz_encode_baud_rate(baud); + } if (bflag < 0) { /* Resort to 9600. */ baud = 9600; bflag = DZ_B9600; @@ -606,7 +607,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, if (termios->c_cflag & CREAD) cflag |= DZ_RXENAB; - spin_lock_irqsave(&dport->port.lock, flags); + uart_port_lock_irqsave(&dport->port, &flags); uart_update_timeout(uport, termios->c_cflag, baud); @@ -629,7 +630,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, if (termios->c_iflag & IGNBRK) dport->port.ignore_status_mask |= DZ_BREAK; - spin_unlock_irqrestore(&dport->port.lock, flags); + uart_port_unlock_irqrestore(&dport->port, flags); } /* @@ -643,12 +644,12 @@ static void dz_pm(struct uart_port *uport, unsigned int state, struct dz_port *dport = to_dport(uport); unsigned long flags; - spin_lock_irqsave(&dport->port.lock, flags); + uart_port_lock_irqsave(&dport->port, &flags); if (state < 3) dz_start_tx(&dport->port); else dz_stop_tx(&dport->port); - spin_unlock_irqrestore(&dport->port.lock, flags); + uart_port_unlock_irqrestore(&dport->port, flags); } @@ -802,14 +803,14 @@ static void __init dz_init_ports(void) * restored. Welcome to the world of PDP-11! * ------------------------------------------------------------------- */ -static void dz_console_putchar(struct uart_port *uport, int ch) +static void dz_console_putchar(struct uart_port *uport, unsigned char ch) { struct dz_port *dport = to_dport(uport); unsigned long flags; unsigned short csr, tcr, trdy, mask; int loops = 10000; - spin_lock_irqsave(&dport->port.lock, flags); + uart_port_lock_irqsave(&dport->port, &flags); csr = dz_in(dport, DZ_CSR); dz_out(dport, DZ_CSR, csr & ~DZ_TIE); tcr = dz_in(dport, DZ_TCR); @@ -817,7 +818,7 @@ static void dz_console_putchar(struct uart_port *uport, int ch) mask = tcr; dz_out(dport, DZ_TCR, mask); iob(); - spin_unlock_irqrestore(&dport->port.lock, flags); + uart_port_unlock_irqrestore(&dport->port, flags); do { trdy = dz_in(dport, DZ_CSR); diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c index ce81523c3113..0162155f0c83 100644 --- a/drivers/tty/serial/earlycon-riscv-sbi.c +++ b/drivers/tty/serial/earlycon-riscv-sbi.c @@ -10,22 +10,43 @@ #include <linux/serial_core.h> #include <asm/sbi.h> -static void sbi_putc(struct uart_port *port, int c) +static void sbi_putc(struct uart_port *port, unsigned char c) { sbi_console_putchar(c); } -static void sbi_console_write(struct console *con, - const char *s, unsigned n) +static void sbi_0_1_console_write(struct console *con, + const char *s, unsigned int n) { struct earlycon_device *dev = con->data; uart_console_write(&dev->port, s, n, sbi_putc); } +static void sbi_dbcn_console_write(struct console *con, + const char *s, unsigned int n) +{ + int ret; + + while (n) { + ret = sbi_debug_console_write(s, n); + if (ret < 0) + break; + + s += ret; + n -= ret; + } +} + static int __init early_sbi_setup(struct earlycon_device *device, const char *opt) { - device->con->write = sbi_console_write; + if (sbi_debug_console_available) + device->con->write = sbi_dbcn_console_write; + else if (IS_ENABLED(CONFIG_RISCV_SBI_V01)) + device->con->write = sbi_0_1_console_write; + else + return -ENODEV; + return 0; } EARLYCON_DECLARE(sbi, early_sbi_setup); diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-semihost.c index fa096c10b591..e4692a8433f9 100644 --- a/drivers/tty/serial/earlycon-arm-semihost.c +++ b/drivers/tty/serial/earlycon-semihost.c @@ -11,30 +11,7 @@ #include <linux/console.h> #include <linux/init.h> #include <linux/serial_core.h> - -#ifdef CONFIG_THUMB2_KERNEL -#define SEMIHOST_SWI "0xab" -#else -#define SEMIHOST_SWI "0x123456" -#endif - -/* - * Semihosting-based debug console - */ -static void smh_putc(struct uart_port *port, int c) -{ -#ifdef CONFIG_ARM64 - asm volatile("mov x1, %0\n" - "mov x0, #3\n" - "hlt 0xf000\n" - : : "r" (&c) : "x0", "x1", "memory"); -#else - asm volatile("mov r1, %0\n" - "mov r0, #3\n" - "svc " SEMIHOST_SWI "\n" - : : "r" (&c) : "r0", "r1", "memory"); -#endif -} +#include <asm/semihost.h> static void smh_write(struct console *con, const char *s, unsigned n) { diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 2ae9190b64bb..ab9af37f6cda 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -56,7 +56,6 @@ static void __init earlycon_init(struct earlycon_device *device, const char *name) { struct console *earlycon = device->con; - struct uart_port *port = &device->port; const char *s; size_t len; @@ -68,8 +67,14 @@ static void __init earlycon_init(struct earlycon_device *device, if (*s) earlycon->index = simple_strtoul(s, NULL, 10); len = s - name; - strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); + strscpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); earlycon->data = &early_console_dev; +} + +static void __init earlycon_print_info(struct earlycon_device *device) +{ + struct console *earlycon = device->con; + struct uart_port *port = &device->port; if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) @@ -115,10 +120,16 @@ static int __init parse_options(struct earlycon_device *device, char *options) } if (options) { + char *uartclk; + device->baud = simple_strtoul(options, NULL, 0); + uartclk = strchr(options, ','); + if (uartclk && kstrtouint(uartclk + 1, 0, &port->uartclk) < 0) + pr_warn("[%s] unsupported earlycon uart clkrate option\n", + options); length = min(strcspn(options, " ") + 1, (size_t)(sizeof(device->options))); - strlcpy(device->options, options, length); + strscpy(device->options, options, length); } return 0; @@ -134,12 +145,14 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) buf = NULL; spin_lock_init(&port->lock); - port->uartclk = BASE_BAUD * 16; + if (!port->uartclk) + port->uartclk = BASE_BAUD * 16; if (port->mapbase) port->membase = earlycon_map(port->mapbase, 64); earlycon_init(&early_console_dev, match->name); err = match->setup(&early_console_dev, buf); + earlycon_print_info(&early_console_dev); if (err < 0) return err; if (!early_console_dev.con->write) @@ -169,19 +182,17 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) */ int __init setup_earlycon(char *buf) { - const struct earlycon_id **p_match; + const struct earlycon_id *match; bool empty_compatible = true; if (!buf || !buf[0]) return -EINVAL; - if (early_con.flags & CON_ENABLED) + if (console_is_registered(&early_con)) return -EALREADY; again: - for (p_match = __earlycon_table; p_match < __earlycon_table_end; - p_match++) { - const struct earlycon_id *match = *p_match; + for (match = __earlycon_table; match < __earlycon_table_end; match++) { size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) @@ -237,6 +248,29 @@ static int __init param_setup_earlycon(char *buf) } early_param("earlycon", param_setup_earlycon); +/* + * The `console` parameter is overloaded. It's handled here as an early param + * and in `printk.c` as a late param. It's possible to specify an early + * `bootconsole` using `earlycon=uartXXXX` (handled above), or via + * the `console=uartXXX` alias. See the comment in `8250_early.c`. + */ +static int __init param_setup_earlycon_console_alias(char *buf) +{ + /* + * A plain `console` parameter must not enable the SPCR `bootconsole` + * like a plain `earlycon` does. + * + * A `console=` parameter that specifies an empty value is used to + * disable the `console`, not the `earlycon` `bootconsole`. The + * disabling of the `console` is handled by `printk.c`. + */ + if (!buf || !buf[0]) + return 0; + + return param_setup_earlycon(buf); +} +early_param("console", param_setup_earlycon_console_alias); + #ifdef CONFIG_OF_EARLY_FLATTREE int __init of_setup_earlycon(const struct earlycon_id *match, @@ -249,6 +283,9 @@ int __init of_setup_earlycon(const struct earlycon_id *match, bool big_endian; u64 addr; + if (console_is_registered(&early_con)) + return -EALREADY; + spin_lock_init(&port->lock); port->iotype = UPIO_MEM; addr = of_flat_dt_translate_address(node); @@ -297,11 +334,12 @@ int __init of_setup_earlycon(const struct earlycon_id *match, if (options) { early_console_dev.baud = simple_strtoul(options, NULL, 0); - strlcpy(early_console_dev.options, options, + strscpy(early_console_dev.options, options, sizeof(early_console_dev.options)); } earlycon_init(&early_console_dev, match->name); err = match->setup(&early_console_dev, options); + earlycon_print_info(&early_console_dev); if (err < 0) return err; if (!early_console_dev.con->write) diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c deleted file mode 100644 index f12f29cf4f31..000000000000 --- a/drivers/tty/serial/efm32-uart.c +++ /dev/null @@ -1,852 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/serial_core.h> -#include <linux/tty_flip.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/of.h> -#include <linux/of_device.h> - -#include <linux/platform_data/efm32-uart.h> - -#define DRIVER_NAME "efm32-uart" -#define DEV_NAME "ttyefm" - -#define UARTn_CTRL 0x00 -#define UARTn_CTRL_SYNC 0x0001 -#define UARTn_CTRL_TXBIL 0x1000 - -#define UARTn_FRAME 0x04 -#define UARTn_FRAME_DATABITS__MASK 0x000f -#define UARTn_FRAME_DATABITS(n) ((n) - 3) -#define UARTn_FRAME_PARITY__MASK 0x0300 -#define UARTn_FRAME_PARITY_NONE 0x0000 -#define UARTn_FRAME_PARITY_EVEN 0x0200 -#define UARTn_FRAME_PARITY_ODD 0x0300 -#define UARTn_FRAME_STOPBITS_HALF 0x0000 -#define UARTn_FRAME_STOPBITS_ONE 0x1000 -#define UARTn_FRAME_STOPBITS_TWO 0x3000 - -#define UARTn_CMD 0x0c -#define UARTn_CMD_RXEN 0x0001 -#define UARTn_CMD_RXDIS 0x0002 -#define UARTn_CMD_TXEN 0x0004 -#define UARTn_CMD_TXDIS 0x0008 - -#define UARTn_STATUS 0x10 -#define UARTn_STATUS_TXENS 0x0002 -#define UARTn_STATUS_TXC 0x0020 -#define UARTn_STATUS_TXBL 0x0040 -#define UARTn_STATUS_RXDATAV 0x0080 - -#define UARTn_CLKDIV 0x14 - -#define UARTn_RXDATAX 0x18 -#define UARTn_RXDATAX_RXDATA__MASK 0x01ff -#define UARTn_RXDATAX_PERR 0x4000 -#define UARTn_RXDATAX_FERR 0x8000 -/* - * This is a software only flag used for ignore_status_mask and - * read_status_mask! It's used for breaks that the hardware doesn't report - * explicitly. - */ -#define SW_UARTn_RXDATAX_BERR 0x2000 - -#define UARTn_TXDATA 0x34 - -#define UARTn_IF 0x40 -#define UARTn_IF_TXC 0x0001 -#define UARTn_IF_TXBL 0x0002 -#define UARTn_IF_RXDATAV 0x0004 -#define UARTn_IF_RXOF 0x0010 - -#define UARTn_IFS 0x44 -#define UARTn_IFC 0x48 -#define UARTn_IEN 0x4c - -#define UARTn_ROUTE 0x54 -#define UARTn_ROUTE_LOCATION__MASK 0x0700 -#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK) -#define UARTn_ROUTE_RXPEN 0x0001 -#define UARTn_ROUTE_TXPEN 0x0002 - -struct efm32_uart_port { - struct uart_port port; - unsigned int txirq; - struct clk *clk; - struct efm32_uart_pdata pdata; -}; -#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port) -#define efm_debug(efm_port, format, arg...) \ - dev_dbg(efm_port->port.dev, format, ##arg) - -static void efm32_uart_write32(struct efm32_uart_port *efm_port, - u32 value, unsigned offset) -{ - writel_relaxed(value, efm_port->port.membase + offset); -} - -static u32 efm32_uart_read32(struct efm32_uart_port *efm_port, - unsigned offset) -{ - return readl_relaxed(efm_port->port.membase + offset); -} - -static unsigned int efm32_uart_tx_empty(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); - - if (status & UARTn_STATUS_TXC) - return TIOCSER_TEMT; - else - return 0; -} - -static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* sorry, neither handshaking lines nor loop functionallity */ -} - -static unsigned int efm32_uart_get_mctrl(struct uart_port *port) -{ - /* sorry, no handshaking lines available */ - return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; -} - -static void efm32_uart_stop_tx(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - u32 ien = efm32_uart_read32(efm_port, UARTn_IEN); - - efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD); - ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL); - efm32_uart_write32(efm_port, ien, UARTn_IEN); -} - -static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port) -{ - struct uart_port *port = &efm_port->port; - struct circ_buf *xmit = &port->state->xmit; - - while (efm32_uart_read32(efm_port, UARTn_STATUS) & - UARTn_STATUS_TXBL) { - if (port->x_char) { - port->icount.tx++; - efm32_uart_write32(efm_port, port->x_char, - UARTn_TXDATA); - port->x_char = 0; - continue; - } - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { - port->icount.tx++; - efm32_uart_write32(efm_port, xmit->buf[xmit->tail], - UARTn_TXDATA); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!port->x_char && uart_circ_empty(xmit) && - efm32_uart_read32(efm_port, UARTn_STATUS) & - UARTn_STATUS_TXC) - efm32_uart_stop_tx(port); -} - -static void efm32_uart_start_tx(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - u32 ien; - - efm32_uart_write32(efm_port, - UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC); - ien = efm32_uart_read32(efm_port, UARTn_IEN); - efm32_uart_write32(efm_port, - ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN); - efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD); - - efm32_uart_tx_chars(efm_port); -} - -static void efm32_uart_stop_rx(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - - efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD); -} - -static void efm32_uart_break_ctl(struct uart_port *port, int ctl) -{ - /* not possible without fiddling with gpios */ -} - -static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port) -{ - struct uart_port *port = &efm_port->port; - - while (efm32_uart_read32(efm_port, UARTn_STATUS) & - UARTn_STATUS_RXDATAV) { - u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX); - int flag = 0; - - /* - * This is a reserved bit and I only saw it read as 0. But to be - * sure not to be confused too much by new devices adhere to the - * warning in the reference manual that reserved bits might - * read as 1 in the future. - */ - rxdata &= ~SW_UARTn_RXDATAX_BERR; - - port->icount.rx++; - - if ((rxdata & UARTn_RXDATAX_FERR) && - !(rxdata & UARTn_RXDATAX_RXDATA__MASK)) { - rxdata |= SW_UARTn_RXDATAX_BERR; - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (rxdata & UARTn_RXDATAX_PERR) - port->icount.parity++; - else if (rxdata & UARTn_RXDATAX_FERR) - port->icount.frame++; - - rxdata &= port->read_status_mask; - - if (rxdata & SW_UARTn_RXDATAX_BERR) - flag = TTY_BREAK; - else if (rxdata & UARTn_RXDATAX_PERR) - flag = TTY_PARITY; - else if (rxdata & UARTn_RXDATAX_FERR) - flag = TTY_FRAME; - else if (uart_handle_sysrq_char(port, - rxdata & UARTn_RXDATAX_RXDATA__MASK)) - continue; - - if ((rxdata & port->ignore_status_mask) == 0) - tty_insert_flip_char(&port->state->port, - rxdata & UARTn_RXDATAX_RXDATA__MASK, flag); - } -} - -static irqreturn_t efm32_uart_rxirq(int irq, void *data) -{ - struct efm32_uart_port *efm_port = data; - u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); - int handled = IRQ_NONE; - struct uart_port *port = &efm_port->port; - struct tty_port *tport = &port->state->port; - - spin_lock(&port->lock); - - if (irqflag & UARTn_IF_RXDATAV) { - efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC); - efm32_uart_rx_chars(efm_port); - - handled = IRQ_HANDLED; - } - - if (irqflag & UARTn_IF_RXOF) { - efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC); - port->icount.overrun++; - tty_insert_flip_char(tport, 0, TTY_OVERRUN); - - handled = IRQ_HANDLED; - } - - spin_unlock(&port->lock); - - tty_flip_buffer_push(tport); - - return handled; -} - -static irqreturn_t efm32_uart_txirq(int irq, void *data) -{ - struct efm32_uart_port *efm_port = data; - u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); - - /* TXBL doesn't need to be cleared */ - if (irqflag & UARTn_IF_TXC) - efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC); - - if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) { - efm32_uart_tx_chars(efm_port); - return IRQ_HANDLED; - } else - return IRQ_NONE; -} - -static int efm32_uart_startup(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - int ret; - - ret = clk_enable(efm_port->clk); - if (ret) { - efm_debug(efm_port, "failed to enable clk\n"); - goto err_clk_enable; - } - port->uartclk = clk_get_rate(efm_port->clk); - - /* Enable pins at configured location */ - efm32_uart_write32(efm_port, - UARTn_ROUTE_LOCATION(efm_port->pdata.location) | - UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, - UARTn_ROUTE); - - ret = request_irq(port->irq, efm32_uart_rxirq, 0, - DRIVER_NAME, efm_port); - if (ret) { - efm_debug(efm_port, "failed to register rxirq\n"); - goto err_request_irq_rx; - } - - /* disable all irqs */ - efm32_uart_write32(efm_port, 0, UARTn_IEN); - - ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0, - DRIVER_NAME, efm_port); - if (ret) { - efm_debug(efm_port, "failed to register txirq\n"); - free_irq(port->irq, efm_port); -err_request_irq_rx: - - clk_disable(efm_port->clk); - } else { - efm32_uart_write32(efm_port, - UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN); - efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD); - } - -err_clk_enable: - return ret; -} - -static void efm32_uart_shutdown(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - - efm32_uart_write32(efm_port, 0, UARTn_IEN); - free_irq(port->irq, efm_port); - - clk_disable(efm_port->clk); -} - -static void efm32_uart_set_termios(struct uart_port *port, - struct ktermios *new, struct ktermios *old) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - unsigned long flags; - unsigned baud; - u32 clkdiv; - u32 frame = 0; - - /* no modem control lines */ - new->c_cflag &= ~(CRTSCTS | CMSPAR); - - baud = uart_get_baud_rate(port, new, old, - DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192), - DIV_ROUND_CLOSEST(port->uartclk, 16)); - - switch (new->c_cflag & CSIZE) { - case CS5: - frame |= UARTn_FRAME_DATABITS(5); - break; - case CS6: - frame |= UARTn_FRAME_DATABITS(6); - break; - case CS7: - frame |= UARTn_FRAME_DATABITS(7); - break; - case CS8: - frame |= UARTn_FRAME_DATABITS(8); - break; - } - - if (new->c_cflag & CSTOPB) - /* the receiver only verifies the first stop bit */ - frame |= UARTn_FRAME_STOPBITS_TWO; - else - frame |= UARTn_FRAME_STOPBITS_ONE; - - if (new->c_cflag & PARENB) { - if (new->c_cflag & PARODD) - frame |= UARTn_FRAME_PARITY_ODD; - else - frame |= UARTn_FRAME_PARITY_EVEN; - } else - frame |= UARTn_FRAME_PARITY_NONE; - - /* - * the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25. - * port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow. - */ - clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6; - - spin_lock_irqsave(&port->lock, flags); - - efm32_uart_write32(efm_port, - UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD); - - port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK; - if (new->c_iflag & INPCK) - port->read_status_mask |= - UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; - if (new->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= SW_UARTn_RXDATAX_BERR; - - port->ignore_status_mask = 0; - if (new->c_iflag & IGNPAR) - port->ignore_status_mask |= - UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; - if (new->c_iflag & IGNBRK) - port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR; - - uart_update_timeout(port, new->c_cflag, baud); - - efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL); - efm32_uart_write32(efm_port, frame, UARTn_FRAME); - efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV); - - efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN, - UARTn_CMD); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *efm32_uart_type(struct uart_port *port) -{ - return port->type == PORT_EFMUART ? "efm32-uart" : NULL; -} - -static void efm32_uart_release_port(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - - clk_unprepare(efm_port->clk); - clk_put(efm_port->clk); - iounmap(port->membase); -} - -static int efm32_uart_request_port(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - int ret; - - port->membase = ioremap(port->mapbase, 60); - if (!efm_port->port.membase) { - ret = -ENOMEM; - efm_debug(efm_port, "failed to remap\n"); - goto err_ioremap; - } - - efm_port->clk = clk_get(port->dev, NULL); - if (IS_ERR(efm_port->clk)) { - ret = PTR_ERR(efm_port->clk); - efm_debug(efm_port, "failed to get clock\n"); - goto err_clk_get; - } - - ret = clk_prepare(efm_port->clk); - if (ret) { - clk_put(efm_port->clk); -err_clk_get: - - iounmap(port->membase); -err_ioremap: - return ret; - } - return 0; -} - -static void efm32_uart_config_port(struct uart_port *port, int type) -{ - if (type & UART_CONFIG_TYPE && - !efm32_uart_request_port(port)) - port->type = PORT_EFMUART; -} - -static int efm32_uart_verify_port(struct uart_port *port, - struct serial_struct *serinfo) -{ - int ret = 0; - - if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART) - ret = -EINVAL; - - return ret; -} - -static const struct uart_ops efm32_uart_pops = { - .tx_empty = efm32_uart_tx_empty, - .set_mctrl = efm32_uart_set_mctrl, - .get_mctrl = efm32_uart_get_mctrl, - .stop_tx = efm32_uart_stop_tx, - .start_tx = efm32_uart_start_tx, - .stop_rx = efm32_uart_stop_rx, - .break_ctl = efm32_uart_break_ctl, - .startup = efm32_uart_startup, - .shutdown = efm32_uart_shutdown, - .set_termios = efm32_uart_set_termios, - .type = efm32_uart_type, - .release_port = efm32_uart_release_port, - .request_port = efm32_uart_request_port, - .config_port = efm32_uart_config_port, - .verify_port = efm32_uart_verify_port, -}; - -static struct efm32_uart_port *efm32_uart_ports[5]; - -#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE -static void efm32_uart_console_putchar(struct uart_port *port, int ch) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - unsigned int timeout = 0x400; - u32 status; - - while (1) { - status = efm32_uart_read32(efm_port, UARTn_STATUS); - - if (status & UARTn_STATUS_TXBL) - break; - if (!timeout--) - return; - } - efm32_uart_write32(efm_port, ch, UARTn_TXDATA); -} - -static void efm32_uart_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct efm32_uart_port *efm_port = efm32_uart_ports[co->index]; - u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); - unsigned int timeout = 0x400; - - if (!(status & UARTn_STATUS_TXENS)) - efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD); - - uart_console_write(&efm_port->port, s, count, - efm32_uart_console_putchar); - - /* Wait for the transmitter to become empty */ - while (1) { - u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); - if (status & UARTn_STATUS_TXC) - break; - if (!timeout--) - break; - } - - if (!(status & UARTn_STATUS_TXENS)) - efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD); -} - -static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port, - int *baud, int *parity, int *bits) -{ - u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL); - u32 route, clkdiv, frame; - - if (ctrl & UARTn_CTRL_SYNC) - /* not operating in async mode */ - return; - - route = efm32_uart_read32(efm_port, UARTn_ROUTE); - if (!(route & UARTn_ROUTE_TXPEN)) - /* tx pin not routed */ - return; - - clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV); - - *baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk, - 16 * (4 + (clkdiv >> 6))); - - frame = efm32_uart_read32(efm_port, UARTn_FRAME); - switch (frame & UARTn_FRAME_PARITY__MASK) { - case UARTn_FRAME_PARITY_ODD: - *parity = 'o'; - break; - case UARTn_FRAME_PARITY_EVEN: - *parity = 'e'; - break; - default: - *parity = 'n'; - } - - *bits = (frame & UARTn_FRAME_DATABITS__MASK) - - UARTn_FRAME_DATABITS(4) + 4; - - efm_debug(efm_port, "get_opts: options=%d%c%d\n", - *baud, *parity, *bits); -} - -static int efm32_uart_console_setup(struct console *co, char *options) -{ - struct efm32_uart_port *efm_port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) { - unsigned i; - for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) { - if (efm32_uart_ports[i]) { - pr_warn("efm32-console: fall back to console index %u (from %hhi)\n", - i, co->index); - co->index = i; - break; - } - } - } - - efm_port = efm32_uart_ports[co->index]; - if (!efm_port) { - pr_warn("efm32-console: No port at %d\n", co->index); - return -ENODEV; - } - - ret = clk_prepare(efm_port->clk); - if (ret) { - dev_warn(efm_port->port.dev, - "console: clk_prepare failed: %d\n", ret); - return ret; - } - - efm_port->port.uartclk = clk_get_rate(efm_port->clk); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - efm32_uart_console_get_options(efm_port, - &baud, &parity, &bits); - - return uart_set_options(&efm_port->port, co, baud, parity, bits, flow); -} - -static struct uart_driver efm32_uart_reg; - -static struct console efm32_uart_console = { - .name = DEV_NAME, - .write = efm32_uart_console_write, - .device = uart_console_device, - .setup = efm32_uart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &efm32_uart_reg, -}; - -#else -#define efm32_uart_console (*(struct console *)NULL) -#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */ - -static struct uart_driver efm32_uart_reg = { - .owner = THIS_MODULE, - .driver_name = DRIVER_NAME, - .dev_name = DEV_NAME, - .nr = ARRAY_SIZE(efm32_uart_ports), - .cons = &efm32_uart_console, -}; - -static int efm32_uart_probe_dt(struct platform_device *pdev, - struct efm32_uart_port *efm_port) -{ - struct device_node *np = pdev->dev.of_node; - u32 location; - int ret; - - if (!np) - return 1; - - ret = of_property_read_u32(np, "energymicro,location", &location); - - if (ret) - /* fall back to wrongly namespaced property */ - ret = of_property_read_u32(np, "efm32,location", &location); - - if (ret) - /* fall back to old and (wrongly) generic property "location" */ - ret = of_property_read_u32(np, "location", &location); - - if (!ret) { - if (location > 5) { - dev_err(&pdev->dev, "invalid location\n"); - return -EINVAL; - } - efm_debug(efm_port, "using location %u\n", location); - efm_port->pdata.location = location; - } else { - efm_debug(efm_port, "fall back to location 0\n"); - } - - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); - return ret; - } else { - efm_port->port.line = ret; - return 0; - } - -} - -static int efm32_uart_probe(struct platform_device *pdev) -{ - struct efm32_uart_port *efm_port; - struct resource *res; - unsigned int line; - int ret; - - efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL); - if (!efm_port) { - dev_dbg(&pdev->dev, "failed to allocate private data\n"); - return -ENOMEM; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_dbg(&pdev->dev, "failed to determine base address\n"); - goto err_get_base; - } - - if (resource_size(res) < 60) { - ret = -EINVAL; - dev_dbg(&pdev->dev, "memory resource too small\n"); - goto err_too_small; - } - - ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_dbg(&pdev->dev, "failed to get rx irq\n"); - goto err_get_rxirq; - } - - efm_port->port.irq = ret; - - ret = platform_get_irq(pdev, 1); - if (ret <= 0) - ret = efm_port->port.irq + 1; - - efm_port->txirq = ret; - - efm_port->port.dev = &pdev->dev; - efm_port->port.mapbase = res->start; - efm_port->port.type = PORT_EFMUART; - efm_port->port.iotype = UPIO_MEM32; - efm_port->port.fifosize = 2; - efm_port->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_EFM32_UART_CONSOLE); - efm_port->port.ops = &efm32_uart_pops; - efm_port->port.flags = UPF_BOOT_AUTOCONF; - - ret = efm32_uart_probe_dt(pdev, efm_port); - if (ret > 0) { - /* not created by device tree */ - const struct efm32_uart_pdata *pdata = dev_get_platdata(&pdev->dev); - - efm_port->port.line = pdev->id; - - if (pdata) - efm_port->pdata = *pdata; - } else if (ret < 0) - goto err_probe_dt; - - line = efm_port->port.line; - - if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports)) - efm32_uart_ports[line] = efm_port; - - ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port); - if (ret) { - dev_dbg(&pdev->dev, "failed to add port: %d\n", ret); - - if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports)) - efm32_uart_ports[line] = NULL; -err_probe_dt: -err_get_rxirq: -err_too_small: -err_get_base: - kfree(efm_port); - } else { - platform_set_drvdata(pdev, efm_port); - dev_dbg(&pdev->dev, "\\o/\n"); - } - - return ret; -} - -static int efm32_uart_remove(struct platform_device *pdev) -{ - struct efm32_uart_port *efm_port = platform_get_drvdata(pdev); - unsigned int line = efm_port->port.line; - - uart_remove_one_port(&efm32_uart_reg, &efm_port->port); - - if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports)) - efm32_uart_ports[line] = NULL; - - kfree(efm_port); - - return 0; -} - -static const struct of_device_id efm32_uart_dt_ids[] = { - { - .compatible = "energymicro,efm32-uart", - }, { - /* doesn't follow the "vendor,device" scheme, don't use */ - .compatible = "efm32,uart", - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids); - -static struct platform_driver efm32_uart_driver = { - .probe = efm32_uart_probe, - .remove = efm32_uart_remove, - - .driver = { - .name = DRIVER_NAME, - .of_match_table = efm32_uart_dt_ids, - }, -}; - -static int __init efm32_uart_init(void) -{ - int ret; - - ret = uart_register_driver(&efm32_uart_reg); - if (ret) - return ret; - - ret = platform_driver_register(&efm32_uart_driver); - if (ret) - uart_unregister_driver(&efm32_uart_reg); - - pr_info("EFM32 UART/USART driver\n"); - - return ret; -} -module_init(efm32_uart_init); - -static void __exit efm32_uart_exit(void) -{ - platform_driver_unregister(&efm32_uart_driver); - uart_unregister_driver(&efm32_uart_reg); -} -module_exit(efm32_uart_exit); - -MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); -MODULE_DESCRIPTION("EFM32 UART/USART driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/tty/serial/esp32_acm.c b/drivers/tty/serial/esp32_acm.c new file mode 100644 index 000000000000..bb7cc65427f0 --- /dev/null +++ b/drivers/tty/serial/esp32_acm.c @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty_flip.h> +#include <asm/serial.h> + +#define DRIVER_NAME "esp32s3-acm" +#define DEV_NAME "ttyGS" +#define UART_NR 4 + +#define ESP32S3_ACM_TX_FIFO_SIZE 64 + +#define USB_SERIAL_JTAG_EP1_REG 0x00 +#define USB_SERIAL_JTAG_EP1_CONF_REG 0x04 +#define USB_SERIAL_JTAG_WR_DONE BIT(0) +#define USB_SERIAL_JTAG_SERIAL_IN_EP_DATA_FREE BIT(1) +#define USB_SERIAL_JTAG_INT_ST_REG 0x0c +#define USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT_INT_ST BIT(2) +#define USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT_ST BIT(3) +#define USB_SERIAL_JTAG_INT_ENA_REG 0x10 +#define USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT_INT_ENA BIT(2) +#define USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT_ENA BIT(3) +#define USB_SERIAL_JTAG_INT_CLR_REG 0x14 +#define USB_SERIAL_JTAG_IN_EP1_ST_REG 0x2c +#define USB_SERIAL_JTAG_IN_EP1_WR_ADDR GENMASK(8, 2) +#define USB_SERIAL_JTAG_OUT_EP1_ST_REG 0x3c +#define USB_SERIAL_JTAG_OUT_EP1_REC_DATA_CNT GENMASK(22, 16) + +static const struct of_device_id esp32s3_acm_dt_ids[] = { + { + .compatible = "esp,esp32s3-acm", + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, esp32s3_acm_dt_ids); + +static struct uart_port *esp32s3_acm_ports[UART_NR]; + +static void esp32s3_acm_write(struct uart_port *port, unsigned long reg, u32 v) +{ + writel(v, port->membase + reg); +} + +static u32 esp32s3_acm_read(struct uart_port *port, unsigned long reg) +{ + return readl(port->membase + reg); +} + +static u32 esp32s3_acm_tx_fifo_free(struct uart_port *port) +{ + u32 status = esp32s3_acm_read(port, USB_SERIAL_JTAG_EP1_CONF_REG); + + return status & USB_SERIAL_JTAG_SERIAL_IN_EP_DATA_FREE; +} + +static u32 esp32s3_acm_tx_fifo_cnt(struct uart_port *port) +{ + u32 status = esp32s3_acm_read(port, USB_SERIAL_JTAG_IN_EP1_ST_REG); + + return FIELD_GET(USB_SERIAL_JTAG_IN_EP1_WR_ADDR, status); +} + +static u32 esp32s3_acm_rx_fifo_cnt(struct uart_port *port) +{ + u32 status = esp32s3_acm_read(port, USB_SERIAL_JTAG_OUT_EP1_ST_REG); + + return FIELD_GET(USB_SERIAL_JTAG_OUT_EP1_REC_DATA_CNT, status); +} + +/* return TIOCSER_TEMT when transmitter is not busy */ +static unsigned int esp32s3_acm_tx_empty(struct uart_port *port) +{ + return esp32s3_acm_tx_fifo_cnt(port) == 0 ? TIOCSER_TEMT : 0; +} + +static void esp32s3_acm_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int esp32s3_acm_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR; +} + +static void esp32s3_acm_stop_tx(struct uart_port *port) +{ + u32 int_ena; + + int_ena = esp32s3_acm_read(port, USB_SERIAL_JTAG_INT_ENA_REG); + int_ena &= ~USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT_ENA; + esp32s3_acm_write(port, USB_SERIAL_JTAG_INT_ENA_REG, int_ena); +} + +static void esp32s3_acm_rxint(struct uart_port *port) +{ + struct tty_port *tty_port = &port->state->port; + u32 rx_fifo_cnt = esp32s3_acm_rx_fifo_cnt(port); + unsigned long flags; + u32 i; + + if (!rx_fifo_cnt) + return; + + spin_lock_irqsave(&port->lock, flags); + + for (i = 0; i < rx_fifo_cnt; ++i) { + u32 rx = esp32s3_acm_read(port, USB_SERIAL_JTAG_EP1_REG); + + ++port->icount.rx; + tty_insert_flip_char(tty_port, rx, TTY_NORMAL); + } + spin_unlock_irqrestore(&port->lock, flags); + + tty_flip_buffer_push(tty_port); +} + +static void esp32s3_acm_push(struct uart_port *port) +{ + if (esp32s3_acm_tx_fifo_free(port)) + esp32s3_acm_write(port, USB_SERIAL_JTAG_EP1_CONF_REG, + USB_SERIAL_JTAG_WR_DONE); +} + +static void esp32s3_acm_put_char(struct uart_port *port, u8 c) +{ + esp32s3_acm_write(port, USB_SERIAL_JTAG_EP1_REG, c); +} + +static void esp32s3_acm_put_char_sync(struct uart_port *port, u8 c) +{ + unsigned long timeout = jiffies + HZ; + + while (!esp32s3_acm_tx_fifo_free(port)) { + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, "timeout waiting for TX FIFO\n"); + return; + } + cpu_relax(); + } + esp32s3_acm_put_char(port, c); + esp32s3_acm_push(port); +} + +static void esp32s3_acm_transmit_buffer(struct uart_port *port) +{ + u32 tx_fifo_used; + unsigned int pending; + u8 ch; + + if (!esp32s3_acm_tx_fifo_free(port)) + return; + + tx_fifo_used = esp32s3_acm_tx_fifo_cnt(port); + pending = uart_port_tx_limited(port, ch, + ESP32S3_ACM_TX_FIFO_SIZE - tx_fifo_used, + true, esp32s3_acm_put_char(port, ch), + ({})); + if (pending) { + u32 int_ena; + + int_ena = esp32s3_acm_read(port, USB_SERIAL_JTAG_INT_ENA_REG); + int_ena |= USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT_ENA; + esp32s3_acm_write(port, USB_SERIAL_JTAG_INT_ENA_REG, int_ena); + } + esp32s3_acm_push(port); +} + +static void esp32s3_acm_txint(struct uart_port *port) +{ + esp32s3_acm_transmit_buffer(port); +} + +static irqreturn_t esp32s3_acm_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + u32 status; + + status = esp32s3_acm_read(port, USB_SERIAL_JTAG_INT_ST_REG); + esp32s3_acm_write(port, USB_SERIAL_JTAG_INT_CLR_REG, status); + + if (status & USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT_INT_ST) + esp32s3_acm_rxint(port); + if (status & USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT_ST) + esp32s3_acm_txint(port); + + return IRQ_RETVAL(status); +} + +static void esp32s3_acm_start_tx(struct uart_port *port) +{ + esp32s3_acm_transmit_buffer(port); +} + +static void esp32s3_acm_stop_rx(struct uart_port *port) +{ + u32 int_ena; + + int_ena = esp32s3_acm_read(port, USB_SERIAL_JTAG_INT_ENA_REG); + int_ena &= ~USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT_INT_ENA; + esp32s3_acm_write(port, USB_SERIAL_JTAG_INT_ENA_REG, int_ena); +} + +static int esp32s3_acm_startup(struct uart_port *port) +{ + int ret; + + ret = request_irq(port->irq, esp32s3_acm_int, 0, DRIVER_NAME, port); + if (ret) + return ret; + esp32s3_acm_write(port, USB_SERIAL_JTAG_INT_ENA_REG, + USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT_INT_ENA); + + return 0; +} + +static void esp32s3_acm_shutdown(struct uart_port *port) +{ + esp32s3_acm_write(port, USB_SERIAL_JTAG_INT_ENA_REG, 0); + free_irq(port->irq, port); +} + +static void esp32s3_acm_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ +} + +static const char *esp32s3_acm_type(struct uart_port *port) +{ + return "ESP32S3 ACM"; +} + +/* configure/auto-configure the port */ +static void esp32s3_acm_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_GENERIC; +} + +#ifdef CONFIG_CONSOLE_POLL +static void esp32s3_acm_poll_put_char(struct uart_port *port, unsigned char c) +{ + esp32s3_acm_put_char_sync(port, c); +} + +static int esp32s3_acm_poll_get_char(struct uart_port *port) +{ + if (esp32s3_acm_rx_fifo_cnt(port)) + return esp32s3_acm_read(port, USB_SERIAL_JTAG_EP1_REG); + else + return NO_POLL_CHAR; +} +#endif + +static const struct uart_ops esp32s3_acm_pops = { + .tx_empty = esp32s3_acm_tx_empty, + .set_mctrl = esp32s3_acm_set_mctrl, + .get_mctrl = esp32s3_acm_get_mctrl, + .stop_tx = esp32s3_acm_stop_tx, + .start_tx = esp32s3_acm_start_tx, + .stop_rx = esp32s3_acm_stop_rx, + .startup = esp32s3_acm_startup, + .shutdown = esp32s3_acm_shutdown, + .set_termios = esp32s3_acm_set_termios, + .type = esp32s3_acm_type, + .config_port = esp32s3_acm_config_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = esp32s3_acm_poll_put_char, + .poll_get_char = esp32s3_acm_poll_get_char, +#endif +}; + +static void esp32s3_acm_string_write(struct uart_port *port, const char *s, + unsigned int count) +{ + uart_console_write(port, s, count, esp32s3_acm_put_char_sync); +} + +static void +esp32s3_acm_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = esp32s3_acm_ports[co->index]; + unsigned long flags; + bool locked = true; + + if (port->sysrq) + locked = false; + else if (oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); + + esp32s3_acm_string_write(port, s, count); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); +} + +static struct uart_driver esp32s3_acm_reg; +static struct console esp32s3_acm_console = { + .name = DEV_NAME, + .write = esp32s3_acm_console_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &esp32s3_acm_reg, +}; + +static void esp32s3_acm_earlycon_write(struct console *con, const char *s, + unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, esp32s3_acm_put_char_sync); +} + +#ifdef CONFIG_CONSOLE_POLL +static int esp32s3_acm_earlycon_read(struct console *con, char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + unsigned int num_read = 0; + + while (num_read < n) { + int c = esp32s3_acm_poll_get_char(&dev->port); + + if (c == NO_POLL_CHAR) + break; + s[num_read++] = c; + } + return num_read; +} +#endif + +static int __init esp32s3_acm_early_console_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = esp32s3_acm_earlycon_write; +#ifdef CONFIG_CONSOLE_POLL + device->con->read = esp32s3_acm_earlycon_read; +#endif + return 0; +} + +OF_EARLYCON_DECLARE(esp32s3acm, "esp,esp32s3-acm", + esp32s3_acm_early_console_setup); + +static struct uart_driver esp32s3_acm_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = DEV_NAME, + .nr = ARRAY_SIZE(esp32s3_acm_ports), + .cons = &esp32s3_acm_console, +}; + +static int esp32s3_acm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct uart_port *port; + struct resource *res; + int ret; + + port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + if (ret >= UART_NR) { + dev_err(&pdev->dev, "driver limited to %d serial ports\n", + UART_NR); + return -ENOMEM; + } + + port->line = ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + port->mapbase = res->start; + port->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + + port->dev = &pdev->dev; + port->type = PORT_GENERIC; + port->iotype = UPIO_MEM; + port->irq = platform_get_irq(pdev, 0); + port->ops = &esp32s3_acm_pops; + port->flags = UPF_BOOT_AUTOCONF; + port->has_sysrq = 1; + port->fifosize = ESP32S3_ACM_TX_FIFO_SIZE; + + esp32s3_acm_ports[port->line] = port; + + platform_set_drvdata(pdev, port); + + return uart_add_one_port(&esp32s3_acm_reg, port); +} + +static void esp32s3_acm_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + uart_remove_one_port(&esp32s3_acm_reg, port); +} + + +static struct platform_driver esp32s3_acm_driver = { + .probe = esp32s3_acm_probe, + .remove = esp32s3_acm_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = esp32s3_acm_dt_ids, + }, +}; + +static int __init esp32s3_acm_init(void) +{ + int ret; + + ret = uart_register_driver(&esp32s3_acm_reg); + if (ret) + return ret; + + ret = platform_driver_register(&esp32s3_acm_driver); + if (ret) + uart_unregister_driver(&esp32s3_acm_reg); + + return ret; +} + +static void __exit esp32s3_acm_exit(void) +{ + platform_driver_unregister(&esp32s3_acm_driver); + uart_unregister_driver(&esp32s3_acm_reg); +} + +module_init(esp32s3_acm_init); +module_exit(esp32s3_acm_exit); + +MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>"); +MODULE_DESCRIPTION("Espressif ESP32 USB ACM gadget support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/esp32_uart.c b/drivers/tty/serial/esp32_uart.c new file mode 100644 index 000000000000..667c2198a03a --- /dev/null +++ b/drivers/tty/serial/esp32_uart.c @@ -0,0 +1,779 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty_flip.h> +#include <asm/serial.h> + +#define DRIVER_NAME "esp32-uart" +#define DEV_NAME "ttyS" +#define UART_NR 3 + +#define ESP32_UART_TX_FIFO_SIZE 127 +#define ESP32_UART_RX_FIFO_SIZE 127 + +#define UART_FIFO_REG 0x00 +#define UART_INT_RAW_REG 0x04 +#define UART_INT_ST_REG 0x08 +#define UART_INT_ENA_REG 0x0c +#define UART_INT_CLR_REG 0x10 +#define UART_RXFIFO_FULL_INT BIT(0) +#define UART_TXFIFO_EMPTY_INT BIT(1) +#define UART_BRK_DET_INT BIT(7) +#define UART_CLKDIV_REG 0x14 +#define ESP32_UART_CLKDIV GENMASK(19, 0) +#define ESP32S3_UART_CLKDIV GENMASK(11, 0) +#define UART_CLKDIV_SHIFT 0 +#define UART_CLKDIV_FRAG GENMASK(23, 20) +#define UART_STATUS_REG 0x1c +#define ESP32_UART_RXFIFO_CNT GENMASK(7, 0) +#define ESP32S3_UART_RXFIFO_CNT GENMASK(9, 0) +#define UART_RXFIFO_CNT_SHIFT 0 +#define UART_DSRN BIT(13) +#define UART_CTSN BIT(14) +#define ESP32_UART_TXFIFO_CNT GENMASK(23, 16) +#define ESP32S3_UART_TXFIFO_CNT GENMASK(25, 16) +#define UART_TXFIFO_CNT_SHIFT 16 +#define UART_CONF0_REG 0x20 +#define UART_PARITY BIT(0) +#define UART_PARITY_EN BIT(1) +#define UART_BIT_NUM GENMASK(3, 2) +#define UART_BIT_NUM_5 0 +#define UART_BIT_NUM_6 1 +#define UART_BIT_NUM_7 2 +#define UART_BIT_NUM_8 3 +#define UART_STOP_BIT_NUM GENMASK(5, 4) +#define UART_STOP_BIT_NUM_1 1 +#define UART_STOP_BIT_NUM_2 3 +#define UART_SW_RTS BIT(6) +#define UART_SW_DTR BIT(7) +#define UART_LOOPBACK BIT(14) +#define UART_TX_FLOW_EN BIT(15) +#define UART_RTS_INV BIT(23) +#define UART_DTR_INV BIT(24) +#define UART_CONF1_REG 0x24 +#define UART_RXFIFO_FULL_THRHD_SHIFT 0 +#define ESP32_UART_TXFIFO_EMPTY_THRHD_SHIFT 8 +#define ESP32S3_UART_TXFIFO_EMPTY_THRHD_SHIFT 10 +#define ESP32_UART_RX_FLOW_EN BIT(23) +#define ESP32S3_UART_RX_FLOW_EN BIT(22) +#define ESP32S3_UART_CLK_CONF_REG 0x78 +#define ESP32S3_UART_SCLK_DIV_B GENMASK(5, 0) +#define ESP32S3_UART_SCLK_DIV_A GENMASK(11, 6) +#define ESP32S3_UART_SCLK_DIV_NUM GENMASK(19, 12) +#define ESP32S3_UART_SCLK_SEL GENMASK(21, 20) +#define APB_CLK 1 +#define RC_FAST_CLK 2 +#define XTAL_CLK 3 +#define ESP32S3_UART_SCLK_EN BIT(22) +#define ESP32S3_UART_RST_CORE BIT(23) +#define ESP32S3_UART_TX_SCLK_EN BIT(24) +#define ESP32S3_UART_RX_SCLK_EN BIT(25) +#define ESP32S3_UART_TX_RST_CORE BIT(26) +#define ESP32S3_UART_RX_RST_CORE BIT(27) + +#define ESP32S3_UART_CLK_CONF_DEFAULT \ + (ESP32S3_UART_RX_SCLK_EN | \ + ESP32S3_UART_TX_SCLK_EN | \ + ESP32S3_UART_SCLK_EN | \ + FIELD_PREP(ESP32S3_UART_SCLK_SEL, XTAL_CLK)) + +struct esp32_port { + struct uart_port port; + struct clk *clk; +}; + +struct esp32_uart_variant { + u32 clkdiv_mask; + u32 rxfifo_cnt_mask; + u32 txfifo_cnt_mask; + u32 txfifo_empty_thrhd_shift; + u32 rx_flow_en; + const char *type; + bool has_clkconf; +}; + +static const struct esp32_uart_variant esp32_variant = { + .clkdiv_mask = ESP32_UART_CLKDIV, + .rxfifo_cnt_mask = ESP32_UART_RXFIFO_CNT, + .txfifo_cnt_mask = ESP32_UART_TXFIFO_CNT, + .txfifo_empty_thrhd_shift = ESP32_UART_TXFIFO_EMPTY_THRHD_SHIFT, + .rx_flow_en = ESP32_UART_RX_FLOW_EN, + .type = "ESP32 UART", +}; + +static const struct esp32_uart_variant esp32s3_variant = { + .clkdiv_mask = ESP32S3_UART_CLKDIV, + .rxfifo_cnt_mask = ESP32S3_UART_RXFIFO_CNT, + .txfifo_cnt_mask = ESP32S3_UART_TXFIFO_CNT, + .txfifo_empty_thrhd_shift = ESP32S3_UART_TXFIFO_EMPTY_THRHD_SHIFT, + .rx_flow_en = ESP32S3_UART_RX_FLOW_EN, + .type = "ESP32S3 UART", + .has_clkconf = true, +}; + +static const struct of_device_id esp32_uart_dt_ids[] = { + { + .compatible = "esp,esp32-uart", + .data = &esp32_variant, + }, { + .compatible = "esp,esp32s3-uart", + .data = &esp32s3_variant, + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, esp32_uart_dt_ids); + +static struct esp32_port *esp32_uart_ports[UART_NR]; + +static const struct esp32_uart_variant *port_variant(struct uart_port *port) +{ + return port->private_data; +} + +static void esp32_uart_write(struct uart_port *port, unsigned long reg, u32 v) +{ + writel(v, port->membase + reg); +} + +static u32 esp32_uart_read(struct uart_port *port, unsigned long reg) +{ + return readl(port->membase + reg); +} + +static u32 esp32_uart_tx_fifo_cnt(struct uart_port *port) +{ + u32 status = esp32_uart_read(port, UART_STATUS_REG); + + return (status & port_variant(port)->txfifo_cnt_mask) >> UART_TXFIFO_CNT_SHIFT; +} + +static u32 esp32_uart_rx_fifo_cnt(struct uart_port *port) +{ + u32 status = esp32_uart_read(port, UART_STATUS_REG); + + return (status & port_variant(port)->rxfifo_cnt_mask) >> UART_RXFIFO_CNT_SHIFT; +} + +/* return TIOCSER_TEMT when transmitter is not busy */ +static unsigned int esp32_uart_tx_empty(struct uart_port *port) +{ + return esp32_uart_tx_fifo_cnt(port) ? 0 : TIOCSER_TEMT; +} + +static void esp32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + u32 conf0 = esp32_uart_read(port, UART_CONF0_REG); + + conf0 &= ~(UART_LOOPBACK | + UART_SW_RTS | UART_RTS_INV | + UART_SW_DTR | UART_DTR_INV); + + if (mctrl & TIOCM_RTS) + conf0 |= UART_SW_RTS; + if (mctrl & TIOCM_DTR) + conf0 |= UART_SW_DTR; + if (mctrl & TIOCM_LOOP) + conf0 |= UART_LOOPBACK; + + esp32_uart_write(port, UART_CONF0_REG, conf0); +} + +static unsigned int esp32_uart_get_mctrl(struct uart_port *port) +{ + u32 status = esp32_uart_read(port, UART_STATUS_REG); + unsigned int ret = TIOCM_CAR; + + if (status & UART_DSRN) + ret |= TIOCM_DSR; + if (status & UART_CTSN) + ret |= TIOCM_CTS; + + return ret; +} + +static void esp32_uart_stop_tx(struct uart_port *port) +{ + u32 int_ena; + + int_ena = esp32_uart_read(port, UART_INT_ENA_REG); + int_ena &= ~UART_TXFIFO_EMPTY_INT; + esp32_uart_write(port, UART_INT_ENA_REG, int_ena); +} + +static void esp32_uart_rxint(struct uart_port *port) +{ + struct tty_port *tty_port = &port->state->port; + u32 rx_fifo_cnt = esp32_uart_rx_fifo_cnt(port); + unsigned long flags; + u32 i; + + if (!rx_fifo_cnt) + return; + + spin_lock_irqsave(&port->lock, flags); + + for (i = 0; i < rx_fifo_cnt; ++i) { + u32 rx = esp32_uart_read(port, UART_FIFO_REG); + + if (!rx && + (esp32_uart_read(port, UART_INT_ST_REG) & UART_BRK_DET_INT)) { + esp32_uart_write(port, UART_INT_CLR_REG, UART_BRK_DET_INT); + ++port->icount.brk; + uart_handle_break(port); + } else { + if (uart_handle_sysrq_char(port, (unsigned char)rx)) + continue; + tty_insert_flip_char(tty_port, rx, TTY_NORMAL); + ++port->icount.rx; + } + } + spin_unlock_irqrestore(&port->lock, flags); + + tty_flip_buffer_push(tty_port); +} + +static void esp32_uart_put_char(struct uart_port *port, u8 c) +{ + esp32_uart_write(port, UART_FIFO_REG, c); +} + +static void esp32_uart_put_char_sync(struct uart_port *port, u8 c) +{ + unsigned long timeout = jiffies + HZ; + + while (esp32_uart_tx_fifo_cnt(port) >= ESP32_UART_TX_FIFO_SIZE) { + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, "timeout waiting for TX FIFO\n"); + return; + } + cpu_relax(); + } + esp32_uart_put_char(port, c); +} + +static void esp32_uart_transmit_buffer(struct uart_port *port) +{ + u32 tx_fifo_used = esp32_uart_tx_fifo_cnt(port); + unsigned int pending; + u8 ch; + + if (tx_fifo_used >= ESP32_UART_TX_FIFO_SIZE) + return; + + pending = uart_port_tx_limited(port, ch, + ESP32_UART_TX_FIFO_SIZE - tx_fifo_used, + true, esp32_uart_put_char(port, ch), + ({})); + if (pending) { + u32 int_ena; + + int_ena = esp32_uart_read(port, UART_INT_ENA_REG); + int_ena |= UART_TXFIFO_EMPTY_INT; + esp32_uart_write(port, UART_INT_ENA_REG, int_ena); + } +} + +static void esp32_uart_txint(struct uart_port *port) +{ + esp32_uart_transmit_buffer(port); +} + +static irqreturn_t esp32_uart_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + u32 status; + + status = esp32_uart_read(port, UART_INT_ST_REG); + + if (status & (UART_RXFIFO_FULL_INT | UART_BRK_DET_INT)) + esp32_uart_rxint(port); + if (status & UART_TXFIFO_EMPTY_INT) + esp32_uart_txint(port); + + esp32_uart_write(port, UART_INT_CLR_REG, status); + + return IRQ_RETVAL(status); +} + +static void esp32_uart_start_tx(struct uart_port *port) +{ + esp32_uart_transmit_buffer(port); +} + +static void esp32_uart_stop_rx(struct uart_port *port) +{ + u32 int_ena; + + int_ena = esp32_uart_read(port, UART_INT_ENA_REG); + int_ena &= ~UART_RXFIFO_FULL_INT; + esp32_uart_write(port, UART_INT_ENA_REG, int_ena); +} + +static int esp32_uart_startup(struct uart_port *port) +{ + int ret = 0; + unsigned long flags; + struct esp32_port *sport = container_of(port, struct esp32_port, port); + + ret = clk_prepare_enable(sport->clk); + if (ret) + return ret; + + ret = request_irq(port->irq, esp32_uart_int, 0, DRIVER_NAME, port); + if (ret) { + clk_disable_unprepare(sport->clk); + return ret; + } + + spin_lock_irqsave(&port->lock, flags); + if (port_variant(port)->has_clkconf) + esp32_uart_write(port, ESP32S3_UART_CLK_CONF_REG, + ESP32S3_UART_CLK_CONF_DEFAULT); + esp32_uart_write(port, UART_CONF1_REG, + (1 << UART_RXFIFO_FULL_THRHD_SHIFT) | + (1 << port_variant(port)->txfifo_empty_thrhd_shift)); + esp32_uart_write(port, UART_INT_CLR_REG, UART_RXFIFO_FULL_INT | UART_BRK_DET_INT); + esp32_uart_write(port, UART_INT_ENA_REG, UART_RXFIFO_FULL_INT | UART_BRK_DET_INT); + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} + +static void esp32_uart_shutdown(struct uart_port *port) +{ + struct esp32_port *sport = container_of(port, struct esp32_port, port); + + esp32_uart_write(port, UART_INT_ENA_REG, 0); + free_irq(port->irq, port); + clk_disable_unprepare(sport->clk); +} + +static bool esp32_uart_set_baud(struct uart_port *port, u32 baud) +{ + u32 sclk = port->uartclk; + u32 div = sclk / baud; + + if (port_variant(port)->has_clkconf) { + u32 sclk_div = div / port_variant(port)->clkdiv_mask; + + if (div > port_variant(port)->clkdiv_mask) { + sclk /= (sclk_div + 1); + div = sclk / baud; + } + esp32_uart_write(port, ESP32S3_UART_CLK_CONF_REG, + FIELD_PREP(ESP32S3_UART_SCLK_DIV_NUM, sclk_div) | + ESP32S3_UART_CLK_CONF_DEFAULT); + } + + if (div <= port_variant(port)->clkdiv_mask) { + u32 frag = (sclk * 16) / baud - div * 16; + + esp32_uart_write(port, UART_CLKDIV_REG, + div | FIELD_PREP(UART_CLKDIV_FRAG, frag)); + return true; + } + + return false; +} + +static void esp32_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ + unsigned long flags; + u32 conf0, conf1; + u32 baud; + const u32 rx_flow_en = port_variant(port)->rx_flow_en; + u32 max_div = port_variant(port)->clkdiv_mask; + + termios->c_cflag &= ~CMSPAR; + + if (port_variant(port)->has_clkconf) + max_div *= FIELD_MAX(ESP32S3_UART_SCLK_DIV_NUM); + + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / max_div, + port->uartclk / 16); + + spin_lock_irqsave(&port->lock, flags); + + conf0 = esp32_uart_read(port, UART_CONF0_REG); + conf0 &= ~(UART_PARITY_EN | UART_PARITY | UART_BIT_NUM | UART_STOP_BIT_NUM); + + conf1 = esp32_uart_read(port, UART_CONF1_REG); + conf1 &= ~rx_flow_en; + + if (termios->c_cflag & PARENB) { + conf0 |= UART_PARITY_EN; + if (termios->c_cflag & PARODD) + conf0 |= UART_PARITY; + } + + switch (termios->c_cflag & CSIZE) { + case CS5: + conf0 |= FIELD_PREP(UART_BIT_NUM, UART_BIT_NUM_5); + break; + case CS6: + conf0 |= FIELD_PREP(UART_BIT_NUM, UART_BIT_NUM_6); + break; + case CS7: + conf0 |= FIELD_PREP(UART_BIT_NUM, UART_BIT_NUM_7); + break; + case CS8: + conf0 |= FIELD_PREP(UART_BIT_NUM, UART_BIT_NUM_8); + break; + } + + if (termios->c_cflag & CSTOPB) + conf0 |= FIELD_PREP(UART_STOP_BIT_NUM, UART_STOP_BIT_NUM_2); + else + conf0 |= FIELD_PREP(UART_STOP_BIT_NUM, UART_STOP_BIT_NUM_1); + + if (termios->c_cflag & CRTSCTS) + conf1 |= rx_flow_en; + + esp32_uart_write(port, UART_CONF0_REG, conf0); + esp32_uart_write(port, UART_CONF1_REG, conf1); + + if (baud) { + esp32_uart_set_baud(port, baud); + uart_update_timeout(port, termios->c_cflag, baud); + } else { + if (esp32_uart_set_baud(port, 115200)) { + baud = 115200; + tty_termios_encode_baud_rate(termios, baud, baud); + uart_update_timeout(port, termios->c_cflag, baud); + } else { + dev_warn(port->dev, + "unable to set speed to %d baud or the default 115200\n", + baud); + } + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *esp32_uart_type(struct uart_port *port) +{ + return port_variant(port)->type; +} + +/* configure/auto-configure the port */ +static void esp32_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_GENERIC; +} + +#ifdef CONFIG_CONSOLE_POLL +static int esp32_uart_poll_init(struct uart_port *port) +{ + struct esp32_port *sport = container_of(port, struct esp32_port, port); + + return clk_prepare_enable(sport->clk); +} + +static void esp32_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ + esp32_uart_put_char_sync(port, c); +} + +static int esp32_uart_poll_get_char(struct uart_port *port) +{ + if (esp32_uart_rx_fifo_cnt(port)) + return esp32_uart_read(port, UART_FIFO_REG); + else + return NO_POLL_CHAR; + +} +#endif + +static const struct uart_ops esp32_uart_pops = { + .tx_empty = esp32_uart_tx_empty, + .set_mctrl = esp32_uart_set_mctrl, + .get_mctrl = esp32_uart_get_mctrl, + .stop_tx = esp32_uart_stop_tx, + .start_tx = esp32_uart_start_tx, + .stop_rx = esp32_uart_stop_rx, + .startup = esp32_uart_startup, + .shutdown = esp32_uart_shutdown, + .set_termios = esp32_uart_set_termios, + .type = esp32_uart_type, + .config_port = esp32_uart_config_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = esp32_uart_poll_init, + .poll_put_char = esp32_uart_poll_put_char, + .poll_get_char = esp32_uart_poll_get_char, +#endif +}; + +static void esp32_uart_console_putchar(struct uart_port *port, u8 c) +{ + esp32_uart_put_char_sync(port, c); +} + +static void esp32_uart_string_write(struct uart_port *port, const char *s, + unsigned int count) +{ + uart_console_write(port, s, count, esp32_uart_console_putchar); +} + +static void +esp32_uart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct esp32_port *sport = esp32_uart_ports[co->index]; + struct uart_port *port = &sport->port; + unsigned long flags; + bool locked = true; + + if (port->sysrq) + locked = false; + else if (oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); + + esp32_uart_string_write(port, s, count); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); +} + +static int __init esp32_uart_console_setup(struct console *co, char *options) +{ + struct esp32_port *sport; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + /* + * check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= ARRAY_SIZE(esp32_uart_ports)) + co->index = 0; + + sport = esp32_uart_ports[co->index]; + if (!sport) + return -ENODEV; + + ret = clk_prepare_enable(sport->clk); + if (ret) + return ret; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static int esp32_uart_console_exit(struct console *co) +{ + struct esp32_port *sport = esp32_uart_ports[co->index]; + + clk_disable_unprepare(sport->clk); + return 0; +} + +static struct uart_driver esp32_uart_reg; +static struct console esp32_uart_console = { + .name = DEV_NAME, + .write = esp32_uart_console_write, + .device = uart_console_device, + .setup = esp32_uart_console_setup, + .exit = esp32_uart_console_exit, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &esp32_uart_reg, +}; + +static void esp32_uart_earlycon_putchar(struct uart_port *port, u8 c) +{ + esp32_uart_put_char_sync(port, c); +} + +static void esp32_uart_earlycon_write(struct console *con, const char *s, + unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, esp32_uart_earlycon_putchar); +} + +#ifdef CONFIG_CONSOLE_POLL +static int esp32_uart_earlycon_read(struct console *con, char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + unsigned int num_read = 0; + + while (num_read < n) { + int c = esp32_uart_poll_get_char(&dev->port); + + if (c == NO_POLL_CHAR) + break; + s[num_read++] = c; + } + return num_read; +} +#endif + +static int __init esp32xx_uart_early_console_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = esp32_uart_earlycon_write; +#ifdef CONFIG_CONSOLE_POLL + device->con->read = esp32_uart_earlycon_read; +#endif + if (device->port.uartclk != BASE_BAUD * 16) + esp32_uart_set_baud(&device->port, device->baud); + + return 0; +} + +static int __init esp32_uart_early_console_setup(struct earlycon_device *device, + const char *options) +{ + device->port.private_data = (void *)&esp32_variant; + + return esp32xx_uart_early_console_setup(device, options); +} + +OF_EARLYCON_DECLARE(esp32uart, "esp,esp32-uart", + esp32_uart_early_console_setup); + +static int __init esp32s3_uart_early_console_setup(struct earlycon_device *device, + const char *options) +{ + device->port.private_data = (void *)&esp32s3_variant; + + return esp32xx_uart_early_console_setup(device, options); +} + +OF_EARLYCON_DECLARE(esp32s3uart, "esp,esp32s3-uart", + esp32s3_uart_early_console_setup); + +static struct uart_driver esp32_uart_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = DEV_NAME, + .nr = ARRAY_SIZE(esp32_uart_ports), + .cons = &esp32_uart_console, +}; + +static int esp32_uart_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct uart_port *port; + struct esp32_port *sport; + struct resource *res; + int ret; + + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + port = &sport->port; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + if (ret >= UART_NR) { + dev_err(&pdev->dev, "driver limited to %d serial ports\n", UART_NR); + return -ENOMEM; + } + + port->line = ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + port->mapbase = res->start; + port->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + + sport->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sport->clk)) + return PTR_ERR(sport->clk); + + port->uartclk = clk_get_rate(sport->clk); + port->dev = &pdev->dev; + port->type = PORT_GENERIC; + port->iotype = UPIO_MEM; + port->irq = platform_get_irq(pdev, 0); + port->ops = &esp32_uart_pops; + port->flags = UPF_BOOT_AUTOCONF; + port->has_sysrq = 1; + port->fifosize = ESP32_UART_TX_FIFO_SIZE; + port->private_data = (void *)device_get_match_data(&pdev->dev); + + esp32_uart_ports[port->line] = sport; + + platform_set_drvdata(pdev, port); + + return uart_add_one_port(&esp32_uart_reg, port); +} + +static void esp32_uart_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + uart_remove_one_port(&esp32_uart_reg, port); +} + + +static struct platform_driver esp32_uart_driver = { + .probe = esp32_uart_probe, + .remove = esp32_uart_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = esp32_uart_dt_ids, + }, +}; + +static int __init esp32_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&esp32_uart_reg); + if (ret) + return ret; + + ret = platform_driver_register(&esp32_uart_driver); + if (ret) + uart_unregister_driver(&esp32_uart_reg); + + return ret; +} + +static void __exit esp32_uart_exit(void) +{ + platform_driver_unregister(&esp32_uart_driver); + uart_unregister_driver(&esp32_uart_reg); +} + +module_init(esp32_uart_init); +module_exit(esp32_uart_exit); + +MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>"); +MODULE_DESCRIPTION("Espressif ESP32 UART support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 3e28be402aef..e70a56de1fce 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -11,7 +11,7 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/platform_device.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty_flip.h> @@ -157,33 +157,35 @@ static void linflex_stop_rx(struct uart_port *port) writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER); } -static inline void linflex_transmit_buffer(struct uart_port *sport) +static void linflex_put_char(struct uart_port *sport, unsigned char c) { - struct circ_buf *xmit = &sport->state->xmit; - unsigned char c; unsigned long status; - while (!uart_circ_empty(xmit)) { - c = xmit->buf[xmit->tail]; - writeb(c, sport->membase + BDRL); + writeb(c, sport->membase + BDRL); - /* Waiting for data transmission completed. */ - while (((status = readl(sport->membase + UARTSR)) & - LINFLEXD_UARTSR_DTFTFF) != - LINFLEXD_UARTSR_DTFTFF) - ; + /* Waiting for data transmission completed. */ + while (((status = readl(sport->membase + UARTSR)) & + LINFLEXD_UARTSR_DTFTFF) != + LINFLEXD_UARTSR_DTFTFF) + ; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->icount.tx++; + writel(status | LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR); +} + +static inline void linflex_transmit_buffer(struct uart_port *sport) +{ + struct tty_port *tport = &sport->state->port; + unsigned char c; - writel(status | LINFLEXD_UARTSR_DTFTFF, - sport->membase + UARTSR); + while (uart_fifo_get(sport, &c)) { + linflex_put_char(sport, c); + sport->icount.tx++; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(sport); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) linflex_stop_tx(sport); } @@ -199,38 +201,24 @@ static void linflex_start_tx(struct uart_port *port) static irqreturn_t linflex_txint(int irq, void *dev_id) { struct uart_port *sport = dev_id; - struct circ_buf *xmit = &sport->state->xmit; + struct tty_port *tport = &sport->state->port; unsigned long flags; - unsigned long status; - spin_lock_irqsave(&sport->lock, flags); + uart_port_lock_irqsave(sport, &flags); if (sport->x_char) { - writeb(sport->x_char, sport->membase + BDRL); - - /* waiting for data transmission completed */ - while (((status = readl(sport->membase + UARTSR)) & - LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF) - ; - - writel(status | LINFLEXD_UARTSR_DTFTFF, - sport->membase + UARTSR); - + linflex_put_char(sport, sport->x_char); goto out; } - if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(sport)) { linflex_stop_tx(sport); goto out; } linflex_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(sport); - out: - spin_unlock_irqrestore(&sport->lock, flags); + uart_port_unlock_irqrestore(sport, flags); return IRQ_HANDLED; } @@ -243,7 +231,7 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) unsigned char rx; bool brk; - spin_lock_irqsave(&sport->lock, flags); + uart_port_lock_irqsave(sport, &flags); status = readl(sport->membase + UARTSR); while (status & LINFLEXD_UARTSR_RMB) { @@ -252,23 +240,22 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) flg = TTY_NORMAL; sport->icount.rx++; - if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | - LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { - if (status & LINFLEXD_UARTSR_SZF) - status |= LINFLEXD_UARTSR_SZF; + if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_FEF | + LINFLEXD_UARTSR_PE)) { if (status & LINFLEXD_UARTSR_BOF) - status |= LINFLEXD_UARTSR_BOF; + sport->icount.overrun++; if (status & LINFLEXD_UARTSR_FEF) { - if (!rx) + if (!rx) { brk = true; - status |= LINFLEXD_UARTSR_FEF; + sport->icount.brk++; + } else + sport->icount.frame++; } if (status & LINFLEXD_UARTSR_PE) - status |= LINFLEXD_UARTSR_PE; + sport->icount.parity++; } - writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, - sport->membase + UARTSR); + writel(status, sport->membase + UARTSR); status = readl(sport->membase + UARTSR); if (brk) { @@ -280,7 +267,7 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) } } - spin_unlock_irqrestore(&sport->lock, flags); + uart_port_unlock_irqrestore(sport, flags); tty_flip_buffer_push(port); @@ -383,11 +370,11 @@ static int linflex_startup(struct uart_port *port) int ret = 0; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); linflex_setup_watermark(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); ret = devm_request_irq(port->dev, port->irq, linflex_int, 0, DRIVER_NAME, port); @@ -400,21 +387,21 @@ static void linflex_shutdown(struct uart_port *port) unsigned long ier; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* disable interrupts */ ier = readl(port->membase + LINIER); ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); writel(ier, port->membase + LINIER); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); devm_free_irq(port->dev, port->irq, port); } static void linflex_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned long cr, old_cr, cr1; @@ -488,7 +475,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios, cr &= ~LINFLEXD_UARTCR_PCE; } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); port->read_status_mask = 0; @@ -521,7 +508,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios, writel(cr1, port->membase + LINCR1); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *linflex_type(struct uart_port *port) @@ -566,7 +553,7 @@ static const struct uart_ops linflex_pops = { static struct uart_port *linflex_ports[UART_NR]; #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE -static void linflex_console_putchar(struct uart_port *port, int ch) +static void linflex_console_putchar(struct uart_port *port, unsigned char ch) { unsigned long cr; @@ -591,7 +578,7 @@ static void linflex_console_putchar(struct uart_port *port, int ch) } } -static void linflex_earlycon_putchar(struct uart_port *port, int ch) +static void linflex_earlycon_putchar(struct uart_port *port, unsigned char ch) { unsigned long flags; char *ret; @@ -660,14 +647,14 @@ linflex_console_write(struct console *co, const char *s, unsigned int count) if (sport->sysrq) locked = 0; else if (oops_in_progress) - locked = spin_trylock_irqsave(&sport->lock, flags); + locked = uart_port_trylock_irqsave(sport, &flags); else - spin_lock_irqsave(&sport->lock, flags); + uart_port_lock_irqsave(sport, &flags); linflex_string_write(sport, s, count); if (locked) - spin_unlock_irqrestore(&sport->lock, flags); + uart_port_unlock_irqrestore(sport, flags); } /* @@ -841,19 +828,18 @@ static int linflex_probe(struct platform_device *pdev) sport->line = ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - sport->mapbase = res->start; - sport->membase = devm_ioremap_resource(&pdev->dev, res); + sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(sport->membase)) return PTR_ERR(sport->membase); + sport->mapbase = res->start; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; sport->dev = &pdev->dev; - sport->type = PORT_LINFLEXUART; sport->iotype = UPIO_MEM; - sport->irq = platform_get_irq(pdev, 0); + sport->irq = ret; sport->ops = &linflex_pops; sport->flags = UPF_BOOT_AUTOCONF; sport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE); @@ -862,20 +848,14 @@ static int linflex_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sport); - ret = uart_add_one_port(&linflex_reg, sport); - if (ret) - return ret; - - return 0; + return uart_add_one_port(&linflex_reg, sport); } -static int linflex_remove(struct platform_device *pdev) +static void linflex_remove(struct platform_device *pdev) { struct uart_port *sport = platform_get_drvdata(pdev); uart_remove_one_port(&linflex_reg, sport); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 90298c403042..1bd7ec9c81ea 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -5,17 +5,24 @@ * Copyright 2012-2014 Freescale Semiconductor, Inc. */ +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/circ_buf.h> #include <linux/clk.h> #include <linux/console.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/dmapool.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_dma.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty_flip.h> @@ -109,6 +116,11 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 +/* 32-bit global registers only for i.MX7ULP/i.MX8x + * Used to reset all internal logic and registers, except the Global Register. + */ +#define UART_GLOBAL 0x8 + /* 32-bit register definition */ #define UARTBAUD 0x00 #define UARTSTAT 0x04 @@ -172,7 +184,8 @@ #define UARTCTRL_SBK 0x00010000 #define UARTCTRL_MA1IE 0x00008000 #define UARTCTRL_MA2IE 0x00004000 -#define UARTCTRL_IDLECFG 0x00000100 +#define UARTCTRL_M7 0x00000800 +#define UARTCTRL_IDLECFG GENMASK(10, 8) #define UARTCTRL_LOOPS 0x00000080 #define UARTCTRL_DOZEEN 0x00000040 #define UARTCTRL_RSRC 0x00000020 @@ -190,6 +203,7 @@ #define UARTDATA_MASK 0x3ff #define UARTMODIR_IREN 0x00020000 +#define UARTMODIR_RTSWATER GENMASK(10, 8) #define UARTMODIR_TXCTSSRC 0x00000020 #define UARTMODIR_TXCTSC 0x00000010 #define UARTMODIR_RXRTSE 0x00000008 @@ -203,6 +217,7 @@ #define UARTFIFO_RXUF 0x00010000 #define UARTFIFO_TXFLUSH 0x00008000 #define UARTFIFO_RXFLUSH 0x00004000 +#define UARTFIFO_RXIDEN GENMASK(12, 10) #define UARTFIFO_TXOFE 0x00000200 #define UARTFIFO_RXUFE 0x00000100 #define UARTFIFO_TXFE 0x00000080 @@ -219,24 +234,30 @@ #define UARTWATER_TXWATER_OFF 0 #define UARTWATER_RXWATER_OFF 16 +#define UART_GLOBAL_RST 0x2 +#define GLOBAL_RST_MIN_US 20 +#define GLOBAL_RST_MAX_US 40 + /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ #define DMA_RX_TIMEOUT (10) +#define DMA_RX_IDLE_CHARS 8 +#define UART_AUTOSUSPEND_TIMEOUT 3000 #define DRIVER_NAME "fsl-lpuart" #define DEV_NAME "ttyLP" -#define UART_NR 6 +#define UART_NR 12 /* IMX lpuart has four extra unused regs located at the beginning */ #define IMX_REG_OFF 0x10 -static DEFINE_IDA(fsl_lpuart_ida); - enum lpuart_type { VF610_LPUART, LS1021A_LPUART, LS1028A_LPUART, IMX7ULP_LPUART, + IMX8ULP_LPUART, IMX8QXP_LPUART, + IMXRT1050_LPUART, }; struct lpuart_port { @@ -247,6 +268,7 @@ struct lpuart_port { unsigned int txfifo_size; unsigned int rxfifo_size; + u8 rx_watermark; bool lpuart_dma_tx_use; bool lpuart_dma_rx_use; struct dma_chan *dma_tx_chan; @@ -263,42 +285,64 @@ struct lpuart_port { struct scatterlist rx_sgl, tx_sgl[2]; struct circ_buf rx_ring; int rx_dma_rng_buf_len; + int last_residue; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; - bool id_allocated; + bool is_cs7; /* Set to true when character size is 7 */ + /* and the parity is enabled */ + bool dma_idle_int; }; struct lpuart_soc_data { enum lpuart_type devtype; char iotype; u8 reg_off; + u8 rx_watermark; }; static const struct lpuart_soc_data vf_data = { .devtype = VF610_LPUART, .iotype = UPIO_MEM, + .rx_watermark = 1, }; static const struct lpuart_soc_data ls1021a_data = { .devtype = LS1021A_LPUART, .iotype = UPIO_MEM32BE, + .rx_watermark = 1, }; static const struct lpuart_soc_data ls1028a_data = { .devtype = LS1028A_LPUART, .iotype = UPIO_MEM32, + .rx_watermark = 0, }; -static struct lpuart_soc_data imx7ulp_data = { +static const struct lpuart_soc_data imx7ulp_data = { .devtype = IMX7ULP_LPUART, .iotype = UPIO_MEM32, .reg_off = IMX_REG_OFF, + .rx_watermark = 1, +}; + +static const struct lpuart_soc_data imx8ulp_data = { + .devtype = IMX8ULP_LPUART, + .iotype = UPIO_MEM32, + .reg_off = IMX_REG_OFF, + .rx_watermark = 3, }; -static struct lpuart_soc_data imx8qxp_data = { +static const struct lpuart_soc_data imx8qxp_data = { .devtype = IMX8QXP_LPUART, .iotype = UPIO_MEM32, .reg_off = IMX_REG_OFF, + .rx_watermark = 7, /* A lower watermark is ideal for low baud rates. */ +}; +static const struct lpuart_soc_data imxrt1050_data = { + .devtype = IMXRT1050_LPUART, + .iotype = UPIO_MEM32, + .reg_off = IMX_REG_OFF, + .rx_watermark = 1, }; static const struct of_device_id lpuart_dt_ids[] = { @@ -306,7 +350,9 @@ static const struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, }, { .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, }, { .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, }, + { .compatible = "fsl,imx8ulp-lpuart", .data = &imx8ulp_data, }, { .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, }, + { .compatible = "fsl,imxrt1050-lpuart", .data = &imxrt1050_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, lpuart_dt_ids); @@ -314,9 +360,20 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids); /* Forward declare this for the dma callbacks*/ static void lpuart_dma_tx_complete(void *arg); -static inline bool is_ls1028a_lpuart(struct lpuart_port *sport) +static inline bool is_layerscape_lpuart(struct lpuart_port *sport) +{ + return (sport->devtype == LS1021A_LPUART || + sport->devtype == LS1028A_LPUART); +} + +static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport) +{ + return sport->devtype == IMX7ULP_LPUART; +} + +static inline bool is_imx8ulp_lpuart(struct lpuart_port *sport) { - return sport->devtype == LS1028A_LPUART; + return sport->devtype == IMX8ULP_LPUART; } static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport) @@ -346,6 +403,8 @@ static inline void lpuart32_write(struct uart_port *port, u32 val, case UPIO_MEM32BE: iowrite32be(val, port->membase + off); break; + default: + break; } } @@ -384,41 +443,41 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport) static void lpuart_stop_tx(struct uart_port *port) { - unsigned char temp; + u8 cr2; - temp = readb(port->membase + UARTCR2); - temp &= ~(UARTCR2_TIE | UARTCR2_TCIE); - writeb(temp, port->membase + UARTCR2); + cr2 = readb(port->membase + UARTCR2); + cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE); + writeb(cr2, port->membase + UARTCR2); } static void lpuart32_stop_tx(struct uart_port *port) { - unsigned long temp; + u32 ctrl; - temp = lpuart32_read(port, UARTCTRL); - temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); - lpuart32_write(port, temp, UARTCTRL); + ctrl = lpuart32_read(port, UARTCTRL); + ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); + lpuart32_write(port, ctrl, UARTCTRL); } static void lpuart_stop_rx(struct uart_port *port) { - unsigned char temp; + u8 cr2; - temp = readb(port->membase + UARTCR2); - writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2); + cr2 = readb(port->membase + UARTCR2); + writeb(cr2 & ~UARTCR2_RE, port->membase + UARTCR2); } static void lpuart32_stop_rx(struct uart_port *port) { - unsigned long temp; + u32 ctrl; - temp = lpuart32_read(port, UARTCTRL); - lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL); + ctrl = lpuart32_read(port, UARTCTRL); + lpuart32_write(port, ctrl & ~UARTCTRL_RE, UARTCTRL); } static void lpuart_dma_tx(struct lpuart_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = sport->tx_sgl; struct device *dev = sport->port.dev; struct dma_chan *chan = sport->dma_tx_chan; @@ -427,18 +486,10 @@ static void lpuart_dma_tx(struct lpuart_port *sport) if (sport->dma_tx_in_progress) return; - sport->dma_tx_bytes = uart_circ_chars_pending(xmit); - - if (xmit->tail < xmit->head || xmit->head == 0) { - sport->dma_tx_nents = 1; - sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes); - } else { - sport->dma_tx_nents = 2; - sg_init_table(sgl, 2); - sg_set_buf(sgl, xmit->buf + xmit->tail, - UART_XMIT_SIZE - xmit->tail); - sg_set_buf(sgl + 1, xmit->buf, xmit->head); - } + sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl)); + sport->dma_tx_bytes = kfifo_len(&tport->xmit_fifo); + sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl, + ARRAY_SIZE(sport->tx_sgl), sport->dma_tx_bytes); ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); @@ -466,29 +517,32 @@ static void lpuart_dma_tx(struct lpuart_port *sport) static bool lpuart_stopped_or_empty(struct uart_port *port) { - return uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port); + return kfifo_is_empty(&port->state->port.xmit_fifo) || + uart_tx_stopped(port); } static void lpuart_dma_tx_complete(void *arg) { struct lpuart_port *sport = arg; struct scatterlist *sgl = &sport->tx_sgl[0]; - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct dma_chan *chan = sport->dma_tx_chan; unsigned long flags; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); + if (!sport->dma_tx_in_progress) { + uart_port_unlock_irqrestore(&sport->port, flags); + return; + } dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); - xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); - - sport->port.icount.tx += sport->dma_tx_bytes; + uart_xmit_advance(&sport->port, sport->dma_tx_bytes); sport->dma_tx_in_progress = false; - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); if (waitqueue_active(&sport->dma_wait)) { @@ -496,12 +550,12 @@ static void lpuart_dma_tx_complete(void *arg) return; } - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); if (!lpuart_stopped_or_empty(&sport->port)) lpuart_dma_tx(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport) @@ -511,8 +565,9 @@ static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport) return sport->port.mapbase + UARTDATA; case UPIO_MEM32BE: return sport->port.mapbase + UARTDATA + sizeof(u32) - 1; + default: + return sport->port.mapbase + UARTDR; } - return sport->port.mapbase + UARTDR; } static int lpuart_dma_tx_request(struct uart_port *port) @@ -529,7 +584,7 @@ static int lpuart_dma_tx_request(struct uart_port *port) ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); if (ret) { - dev_err(sport->port.dev, + dev_err(port->dev, "DMA slave config failed, err = %d\n", ret); return ret; } @@ -547,7 +602,7 @@ static void lpuart_flush_buffer(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); struct dma_chan *chan = sport->dma_tx_chan; - u32 val; + u32 fifo; if (sport->lpuart_dma_tx_use) { if (sport->dma_tx_in_progress) { @@ -555,17 +610,17 @@ static void lpuart_flush_buffer(struct uart_port *port) sport->dma_tx_nents, DMA_TO_DEVICE); sport->dma_tx_in_progress = false; } - dmaengine_terminate_all(chan); + dmaengine_terminate_async(chan); } if (lpuart_is_32(sport)) { - val = lpuart32_read(&sport->port, UARTFIFO); - val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; - lpuart32_write(&sport->port, val, UARTFIFO); + fifo = lpuart32_read(port, UARTFIFO); + fifo |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + lpuart32_write(port, fifo, UARTFIFO); } else { - val = readb(sport->port.membase + UARTCFIFO); - val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH; - writeb(val, sport->port.membase + UARTCFIFO); + fifo = readb(port->membase + UARTCFIFO); + fifo |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH; + writeb(fifo, port->membase + UARTCFIFO); } } @@ -587,38 +642,36 @@ static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset, static int lpuart_poll_init(struct uart_port *port) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); unsigned long flags; - unsigned char temp; + u8 fifo; - sport->port.fifosize = 0; + port->fifosize = 0; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable Rx & Tx */ - writeb(0, sport->port.membase + UARTCR2); + writeb(0, port->membase + UARTCR2); - temp = readb(sport->port.membase + UARTPFIFO); + fifo = readb(port->membase + UARTPFIFO); /* Enable Rx and Tx FIFO */ - writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE, - sport->port.membase + UARTPFIFO); + writeb(fifo | UARTPFIFO_RXFE | UARTPFIFO_TXFE, + port->membase + UARTPFIFO); /* flush Tx and Rx FIFO */ writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, - sport->port.membase + UARTCFIFO); + port->membase + UARTCFIFO); /* explicitly clear RDRF */ - if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) { - readb(sport->port.membase + UARTDR); - writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO); + if (readb(port->membase + UARTSR1) & UARTSR1_RDRF) { + readb(port->membase + UARTDR); + writeb(UARTSFIFO_RXUF, port->membase + UARTSFIFO); } - writeb(0, sport->port.membase + UARTTWFIFO); - writeb(1, sport->port.membase + UARTRWFIFO); + writeb(0, port->membase + UARTTWFIFO); + writeb(1, port->membase + UARTRWFIFO); /* Enable Rx and Tx */ - writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2); - spin_unlock_irqrestore(&sport->port.lock, flags); + writeb(UARTCR2_RE | UARTCR2_TE, port->membase + UARTCR2); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -641,35 +694,32 @@ static int lpuart_poll_get_char(struct uart_port *port) static int lpuart32_poll_init(struct uart_port *port) { unsigned long flags; - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - u32 temp; + u32 fifo; - sport->port.fifosize = 0; + port->fifosize = 0; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable Rx & Tx */ - lpuart32_write(&sport->port, UARTCTRL, 0); + lpuart32_write(port, 0, UARTCTRL); - temp = lpuart32_read(&sport->port, UARTFIFO); + fifo = lpuart32_read(port, UARTFIFO); /* Enable Rx and Tx FIFO */ - lpuart32_write(&sport->port, UARTFIFO, - temp | UARTFIFO_RXFE | UARTFIFO_TXFE); + lpuart32_write(port, fifo | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO); /* flush Tx and Rx FIFO */ - lpuart32_write(&sport->port, UARTFIFO, - UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH); + lpuart32_write(port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO); /* explicitly clear RDRF */ - if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { - lpuart32_read(&sport->port, UARTDATA); - lpuart32_write(&sport->port, UARTFIFO, UARTFIFO_RXUF); + if (lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF) { + lpuart32_read(port, UARTDATA); + lpuart32_write(port, UARTFIFO_RXUF, UARTFIFO); } /* Enable Rx and Tx */ - lpuart32_write(&sport->port, UARTCTRL, UARTCTRL_RE | UARTCTRL_TE); - spin_unlock_irqrestore(&sport->port.lock, flags); + lpuart32_write(port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -677,12 +727,12 @@ static int lpuart32_poll_init(struct uart_port *port) static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) { lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); - lpuart32_write(port, UARTDATA, c); + lpuart32_write(port, c, UARTDATA); } static int lpuart32_poll_get_char(struct uart_port *port) { - if (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF)) + if (!(lpuart32_read(port, UARTWATER) >> UARTWATER_RXCNT_OFF)) return NO_POLL_CHAR; return lpuart32_read(port, UARTDATA); @@ -691,38 +741,19 @@ static int lpuart32_poll_get_char(struct uart_port *port) static inline void lpuart_transmit_buffer(struct lpuart_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; - - if (sport->port.x_char) { - writeb(sport->port.x_char, sport->port.membase + UARTDR); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - if (lpuart_stopped_or_empty(&sport->port)) { - lpuart_stop_tx(&sport->port); - return; - } - - while (!uart_circ_empty(xmit) && - (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) { - writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - } + struct uart_port *port = &sport->port; + u8 ch; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - lpuart_stop_tx(&sport->port); + uart_port_tx(port, ch, + readb(port->membase + UARTTCFIFO) < sport->txfifo_size, + writeb(ch, port->membase + UARTDR)); } static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long txcnt; + struct tty_port *tport = &sport->port.state->port; + u32 txcnt; + unsigned char c; if (sport->port.x_char) { lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); @@ -739,19 +770,18 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) txcnt = lpuart32_read(&sport->port, UARTWATER); txcnt = txcnt >> UARTWATER_TXCNT_OFF; txcnt &= UARTWATER_COUNT_MASK; - while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) { - lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; + while (txcnt < sport->txfifo_size && + uart_fifo_get(&sport->port, &c)) { + lpuart32_write(&sport->port, c, UARTDATA); txcnt = lpuart32_read(&sport->port, UARTWATER); txcnt = txcnt >> UARTWATER_TXCNT_OFF; txcnt &= UARTWATER_COUNT_MASK; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) lpuart32_stop_tx(&sport->port); } @@ -759,10 +789,10 @@ static void lpuart_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char temp; + u8 cr2; - temp = readb(port->membase + UARTCR2); - writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); + cr2 = readb(port->membase + UARTCR2); + writeb(cr2 | UARTCR2_TIE, port->membase + UARTCR2); if (sport->lpuart_dma_tx_use) { if (!lpuart_stopped_or_empty(port)) @@ -776,27 +806,41 @@ static void lpuart_start_tx(struct uart_port *port) static void lpuart32_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long temp; + u32 ctrl; if (sport->lpuart_dma_tx_use) { if (!lpuart_stopped_or_empty(port)) lpuart_dma_tx(sport); } else { - temp = lpuart32_read(port, UARTCTRL); - lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL); + ctrl = lpuart32_read(port, UARTCTRL); + lpuart32_write(port, ctrl | UARTCTRL_TIE, UARTCTRL); if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE) lpuart32_transmit_buffer(sport); } } +static void +lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +{ + switch (state) { + case UART_PM_STATE_OFF: + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + break; + default: + pm_runtime_get_sync(port->dev); + break; + } +} + /* return TIOCSER_TEMT when transmitter is not busy */ static unsigned int lpuart_tx_empty(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char sr1 = readb(port->membase + UARTSR1); - unsigned char sfifo = readb(port->membase + UARTSFIFO); + u8 sr1 = readb(port->membase + UARTSR1); + u8 sfifo = readb(port->membase + UARTSFIFO); if (sport->dma_tx_in_progress) return 0; @@ -811,13 +855,19 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long stat = lpuart32_read(port, UARTSTAT); - unsigned long sfifo = lpuart32_read(port, UARTFIFO); + u32 stat = lpuart32_read(port, UARTSTAT); + u32 sfifo = lpuart32_read(port, UARTFIFO); + u32 ctrl = lpuart32_read(port, UARTCTRL); if (sport->dma_tx_in_progress) return 0; - if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) + /* + * LPUART Transmission Complete Flag may never be set while queuing a break + * character, so avoid checking for transmission complete when UARTCTRL_SBK + * is asserted. + */ + if ((stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) || ctrl & UARTCTRL_SBK) return TIOCSER_TEMT; return 0; @@ -825,21 +875,18 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) static void lpuart_txint(struct lpuart_port *sport) { - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock(&sport->port); lpuart_transmit_buffer(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock(&sport->port); } static void lpuart_rxint(struct lpuart_port *sport) { unsigned int flg, ignored = 0, overrun = 0; struct tty_port *port = &sport->port.state->port; - unsigned long flags; - unsigned char rx, sr; + u8 rx, sr; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock(&sport->port); while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) { flg = TTY_NORMAL; @@ -851,7 +898,7 @@ static void lpuart_rxint(struct lpuart_port *sport) sr = readb(sport->port.membase + UARTSR1); rx = readb(sport->port.membase + UARTDR); - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + if (uart_prepare_sysrq_char(&sport->port, rx)) continue; if (sr & (UARTSR1_PE | UARTSR1_OR | UARTSR1_FE)) { @@ -882,7 +929,8 @@ static void lpuart_rxint(struct lpuart_port *sport) sport->port.sysrq = 0; } - tty_insert_flip_char(port, rx, flg); + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -897,28 +945,26 @@ out: writeb(UARTSFIFO_RXOF, sport->port.membase + UARTSFIFO); } - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_unlock_and_check_sysrq(&sport->port); tty_flip_buffer_push(port); } static void lpuart32_txint(struct lpuart_port *sport) { - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock(&sport->port); lpuart32_transmit_buffer(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock(&sport->port); } static void lpuart32_rxint(struct lpuart_port *sport) { unsigned int flg, ignored = 0; struct tty_port *port = &sport->port.state->port; - unsigned long flags; - unsigned long rx, sr; + u32 rx, sr; + bool is_break; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock(&sport->port); while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) { flg = TTY_NORMAL; @@ -929,16 +975,29 @@ static void lpuart32_rxint(struct lpuart_port *sport) */ sr = lpuart32_read(&sport->port, UARTSTAT); rx = lpuart32_read(&sport->port, UARTDATA); - rx &= 0x3ff; + rx &= UARTDATA_MASK; + + /* + * The LPUART can't distinguish between a break and a framing error, + * thus we assume it is a break if the received data is zero. + */ + is_break = (sr & UARTSTAT_FE) && !rx; - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + if (is_break && uart_handle_break(&sport->port)) + continue; + + if (uart_prepare_sysrq_char(&sport->port, rx)) continue; if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) { - if (sr & UARTSTAT_PE) + if (sr & UARTSTAT_PE) { sport->port.icount.parity++; - else if (sr & UARTSTAT_FE) - sport->port.icount.frame++; + } else if (sr & UARTSTAT_FE) { + if (is_break) + sport->port.icount.brk++; + else + sport->port.icount.frame++; + } if (sr & UARTSTAT_OR) sport->port.icount.overrun++; @@ -951,22 +1010,28 @@ static void lpuart32_rxint(struct lpuart_port *sport) sr &= sport->port.read_status_mask; - if (sr & UARTSTAT_PE) + if (sr & UARTSTAT_PE) { flg = TTY_PARITY; - else if (sr & UARTSTAT_FE) - flg = TTY_FRAME; + } else if (sr & UARTSTAT_FE) { + if (is_break) + flg = TTY_BREAK; + else + flg = TTY_FRAME; + } if (sr & UARTSTAT_OR) flg = TTY_OVERRUN; - - sport->port.sysrq = 0; } - tty_insert_flip_char(port, rx, flg); + if (sport->is_cs7) + rx &= 0x7F; + + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_unlock_and_check_sysrq(&sport->port); tty_flip_buffer_push(port); } @@ -974,10 +1039,19 @@ out: static irqreturn_t lpuart_int(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; - unsigned char sts; + u8 sts; sts = readb(sport->port.membase + UARTSR1); + /* SysRq, using dma, check for linebreak by framing err. */ + if (sts & UARTSR1_FE && sport->lpuart_dma_rx_use) { + readb(sport->port.membase + UARTDR); + uart_handle_break(&sport->port); + /* linebreak produces some garbage, removing it */ + writeb(UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); + return IRQ_HANDLED; + } + if (sts & UARTSR1_RDRF && !sport->lpuart_dma_rx_use) lpuart_rxint(sport); @@ -987,23 +1061,45 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t lpuart32_int(int irq, void *dev_id) +static inline void lpuart_handle_sysrq_chars(struct uart_port *port, + unsigned char *p, int count) { - struct lpuart_port *sport = dev_id; - unsigned long sts, rxcount; + while (count--) { + if (*p && uart_handle_sysrq_char(port, *p)) + return; + p++; + } +} - sts = lpuart32_read(&sport->port, UARTSTAT); - rxcount = lpuart32_read(&sport->port, UARTWATER); - rxcount = rxcount >> UARTWATER_RXCNT_OFF; +static void lpuart_handle_sysrq(struct lpuart_port *sport) +{ + struct circ_buf *ring = &sport->rx_ring; + int count; - if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) - lpuart32_rxint(sport); + if (ring->head < ring->tail) { + count = sport->rx_sgl.length - ring->tail; + lpuart_handle_sysrq_chars(&sport->port, + ring->buf + ring->tail, count); + ring->tail = 0; + } - if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) - lpuart32_txint(sport); + if (ring->head > ring->tail) { + count = ring->head - ring->tail; + lpuart_handle_sysrq_chars(&sport->port, + ring->buf + ring->tail, count); + ring->tail = ring->head; + } +} - lpuart32_write(&sport->port, sts, UARTSTAT); - return IRQ_HANDLED; +static int lpuart_tty_insert_flip_string(struct tty_port *port, + unsigned char *chars, size_t size, bool is_cs7) +{ + int i; + + if (is_cs7) + for (i = 0; i < size; i++) + chars[i] &= 0x7F; + return tty_insert_flip_string(port, chars, size); } static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) @@ -1014,14 +1110,14 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) struct dma_chan *chan = sport->dma_rx_chan; struct circ_buf *ring = &sport->rx_ring; unsigned long flags; - int count = 0; + int count, copied; if (lpuart_is_32(sport)) { - unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); + u32 sr = lpuart32_read(&sport->port, UARTSTAT); if (sr & (UARTSTAT_PE | UARTSTAT_FE)) { - /* Read DR to clear the error flags */ - lpuart32_read(&sport->port, UARTDATA); + /* Clear the error flags */ + lpuart32_write(&sport->port, sr, UARTSTAT); if (sr & UARTSTAT_PE) sport->port.icount.parity++; @@ -1029,10 +1125,10 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) sport->port.icount.frame++; } } else { - unsigned char sr = readb(sport->port.membase + UARTSR1); + u8 sr = readb(sport->port.membase + UARTSR1); if (sr & (UARTSR1_PE | UARTSR1_FE)) { - unsigned char cr2; + u8 cr2; /* Disable receiver during this operation... */ cr2 = readb(sport->port.membase + UARTCR2); @@ -1070,12 +1166,12 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) async_tx_ack(sport->dma_rx_desc); - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state); if (dmastat == DMA_ERROR) { dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); return; } @@ -1092,6 +1188,15 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) */ ring->head = sport->rx_sgl.length - state.residue; BUG_ON(ring->head > sport->rx_sgl.length); + + /* + * Silent handling of keys pressed in the sysrq timeframe + */ + if (sport->port.sysrq) { + lpuart_handle_sysrq(sport); + goto exit; + } + /* * At this point ring->head may point to the first byte right after the * last byte of the dma buffer: @@ -1107,29 +1212,39 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) if (ring->head < ring->tail) { count = sport->rx_sgl.length - ring->tail; - tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail, + count, sport->is_cs7); + if (copied != count) + sport->port.icount.buf_overrun++; ring->tail = 0; - sport->port.icount.rx += count; + sport->port.icount.rx += copied; } /* Finally we read data from tail to head */ if (ring->tail < ring->head) { count = ring->head - ring->tail; - tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail, + count, sport->is_cs7); + if (copied != count) + sport->port.icount.buf_overrun++; /* Wrap ring->head if needed */ if (ring->head >= sport->rx_sgl.length) ring->head = 0; ring->tail = ring->head; - sport->port.icount.rx += count; + sport->port.icount.rx += copied; } + sport->last_residue = state.residue; + +exit: dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); tty_flip_buffer_push(port); - mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); + if (!sport->dma_idle_int) + mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); } static void lpuart_dma_rx_complete(void *arg) @@ -1139,11 +1254,87 @@ static void lpuart_dma_rx_complete(void *arg) lpuart_copy_rx_to_tty(sport); } +static void lpuart32_dma_idleint(struct lpuart_port *sport) +{ + enum dma_status dmastat; + struct dma_chan *chan = sport->dma_rx_chan; + struct circ_buf *ring = &sport->rx_ring; + struct dma_tx_state state; + int count = 0; + + dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state); + if (dmastat == DMA_ERROR) { + dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); + return; + } + + ring->head = sport->rx_sgl.length - state.residue; + count = CIRC_CNT(ring->head, ring->tail, sport->rx_sgl.length); + + /* Check if new data received before copying */ + if (count) + lpuart_copy_rx_to_tty(sport); +} + +static irqreturn_t lpuart32_int(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + u32 sts, rxcount; + + sts = lpuart32_read(&sport->port, UARTSTAT); + rxcount = lpuart32_read(&sport->port, UARTWATER); + rxcount = rxcount >> UARTWATER_RXCNT_OFF; + + if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) + lpuart32_rxint(sport); + + if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) + lpuart32_txint(sport); + + if ((sts & UARTSTAT_IDLE) && sport->lpuart_dma_rx_use && sport->dma_idle_int) + lpuart32_dma_idleint(sport); + + lpuart32_write(&sport->port, sts, UARTSTAT); + return IRQ_HANDLED; +} + +/* + * Timer function to simulate the hardware EOP (End Of Package) event. + * The timer callback is to check for new RX data and copy to TTY buffer. + * If no new data are received since last interval, the EOP condition is + * met, complete the DMA transfer by copying the data. Otherwise, just + * restart timer. + */ static void lpuart_timer_func(struct timer_list *t) { - struct lpuart_port *sport = from_timer(sport, t, lpuart_timer); + struct lpuart_port *sport = timer_container_of(sport, t, lpuart_timer); + enum dma_status dmastat; + struct dma_chan *chan = sport->dma_rx_chan; + struct circ_buf *ring = &sport->rx_ring; + struct dma_tx_state state; + unsigned long flags; + int count; - lpuart_copy_rx_to_tty(sport); + dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state); + if (dmastat == DMA_ERROR) { + dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); + return; + } + + ring->head = sport->rx_sgl.length - state.residue; + count = CIRC_CNT(ring->head, ring->tail, sport->rx_sgl.length); + + /* Check if new data received before copying */ + if ((count != 0) && (sport->last_residue == state.residue)) + lpuart_copy_rx_to_tty(sport); + else + mod_timer(&sport->lpuart_timer, + jiffies + sport->dma_rx_timeout); + + if (uart_port_trylock_irqsave(&sport->port, &flags)) { + sport->last_residue = state.residue; + uart_port_unlock_irqrestore(&sport->port, flags); + } } static inline int lpuart_start_rx_dma(struct lpuart_port *sport) @@ -1151,27 +1342,33 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) struct dma_slave_config dma_rx_sconfig = {}; struct circ_buf *ring = &sport->rx_ring; int ret, nent; - int bits, baud; struct tty_port *port = &sport->port.state->port; struct tty_struct *tty = port->tty; struct ktermios *termios = &tty->termios; struct dma_chan *chan = sport->dma_rx_chan; - - baud = tty_get_baud_rate(tty); - - bits = (termios->c_cflag & CSIZE) == CS7 ? 9 : 10; - if (termios->c_cflag & PARENB) - bits++; + unsigned int bits = tty_get_frame_size(termios->c_cflag); + unsigned int baud = tty_get_baud_rate(tty); /* * Calculate length of one DMA buffer size to keep latency below * 10ms at any baud rate. */ sport->rx_dma_rng_buf_len = (DMA_RX_TIMEOUT * baud / bits / 1000) * 2; - sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1)); + sport->rx_dma_rng_buf_len = (1 << fls(sport->rx_dma_rng_buf_len)); + sport->rx_dma_rng_buf_len = max_t(int, + sport->rxfifo_size * 2, + sport->rx_dma_rng_buf_len); + /* + * Keep this condition check in case rxfifo_size is unavailable + * for some SoCs. + */ if (sport->rx_dma_rng_buf_len < 16) sport->rx_dma_rng_buf_len = 16; + sport->last_residue = 0; + sport->dma_rx_timeout = max(nsecs_to_jiffies( + sport->port.frame_time * DMA_RX_IDLE_CHARS), 1UL); + ring->buf = kzalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); if (!ring->buf) return -ENOMEM; @@ -1214,9 +1411,15 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) dma_async_issue_pending(chan); if (lpuart_is_32(sport)) { - unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); + u32 baud = lpuart32_read(&sport->port, UARTBAUD); + + lpuart32_write(&sport->port, baud | UARTBAUD_RDMAE, UARTBAUD); - lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); + if (sport->dma_idle_int) { + u32 ctrl = lpuart32_read(&sport->port, UARTCTRL); + + lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL); + } } else { writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, sport->port.membase + UARTCR5); @@ -1231,7 +1434,10 @@ static void lpuart_dma_rx_free(struct uart_port *port) struct lpuart_port, port); struct dma_chan *chan = sport->dma_rx_chan; - dmaengine_terminate_all(chan); + dmaengine_terminate_sync(chan); + if (!sport->dma_idle_int) + timer_delete_sync(&sport->lpuart_timer); + dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); kfree(sport->rx_ring.buf); sport->rx_ring.tail = 0; @@ -1240,88 +1446,56 @@ static void lpuart_dma_rx_free(struct uart_port *port) sport->dma_rx_cookie = -EINVAL; } -static int lpuart_config_rs485(struct uart_port *port, +static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - u8 modem = readb(sport->port.membase + UARTMODEM) & + u8 modem = readb(port->membase + UARTMODEM) & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); - writeb(modem, sport->port.membase + UARTMODEM); - - /* clear unsupported configurations */ - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; - rs485->flags &= ~SER_RS485_RX_DURING_TX; + writeb(modem, port->membase + UARTMODEM); if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ modem |= UARTMODEM_TXRTSE; /* - * RTS needs to be logic HIGH either during transer _or_ after - * transfer, other variants are not supported by the hardware. - */ - - if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND))) - rs485->flags |= SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_RTS_ON_SEND && - rs485->flags & SER_RS485_RTS_AFTER_SEND) - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - - /* * The hardware defaults to RTS logic HIGH while transfer. * Switch polarity in case RTS shall be logic HIGH * after transfer. * Note: UART is assumed to be active high. */ if (rs485->flags & SER_RS485_RTS_ON_SEND) - modem &= ~UARTMODEM_TXRTSPOL; - else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) modem |= UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem &= ~UARTMODEM_TXRTSPOL; } - /* Store the new configuration */ - sport->port.rs485 = *rs485; - - writeb(modem, sport->port.membase + UARTMODEM); + writeb(modem, port->membase + UARTMODEM); return 0; } -static int lpuart32_config_rs485(struct uart_port *port, +static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); + u32 modem = lpuart32_read(port, UARTMODIR) + & ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); + u32 ctrl; - unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) - & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); - lpuart32_write(&sport->port, modem, UARTMODIR); + /* TXRTSE and TXRTSPOL only can be changed when transmitter is disabled. */ + ctrl = lpuart32_read(port, UARTCTRL); + if (ctrl & UARTCTRL_TE) { + /* wait for the transmit engine to complete */ + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); + lpuart32_write(port, ctrl & ~UARTCTRL_TE, UARTCTRL); + + while (lpuart32_read(port, UARTCTRL) & UARTCTRL_TE) + cpu_relax(); + } - /* clear unsupported configurations */ - rs485->delay_rts_before_send = 0; - rs485->delay_rts_after_send = 0; - rs485->flags &= ~SER_RS485_RX_DURING_TX; + lpuart32_write(port, modem, UARTMODIR); if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ - modem |= UARTMODEM_TXRTSE; - - /* - * RTS needs to be logic HIGH either during transer _or_ after - * transfer, other variants are not supported by the hardware. - */ - - if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND))) - rs485->flags |= SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_RTS_ON_SEND && - rs485->flags & SER_RS485_RTS_AFTER_SEND) - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + modem |= UARTMODIR_TXRTSE; /* * The hardware defaults to RTS logic HIGH while transfer. @@ -1330,102 +1504,120 @@ static int lpuart32_config_rs485(struct uart_port *port, * Note: UART is assumed to be active high. */ if (rs485->flags & SER_RS485_RTS_ON_SEND) - modem &= ~UARTMODEM_TXRTSPOL; + modem |= UARTMODIR_TXRTSPOL; else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) - modem |= UARTMODEM_TXRTSPOL; + modem &= ~UARTMODIR_TXRTSPOL; } - /* Store the new configuration */ - sport->port.rs485 = *rs485; + lpuart32_write(port, modem, UARTMODIR); + + if (ctrl & UARTCTRL_TE) + lpuart32_write(port, ctrl, UARTCTRL); - lpuart32_write(&sport->port, modem, UARTMODIR); return 0; } static unsigned int lpuart_get_mctrl(struct uart_port *port) { - unsigned int temp = 0; - unsigned char reg; + unsigned int mctrl = 0; + u8 cr1; - reg = readb(port->membase + UARTMODEM); - if (reg & UARTMODEM_TXCTSE) - temp |= TIOCM_CTS; + cr1 = readb(port->membase + UARTCR1); + if (cr1 & UARTCR1_LOOPS) + mctrl |= TIOCM_LOOP; - if (reg & UARTMODEM_RXRTSE) - temp |= TIOCM_RTS; - - return temp; + return mctrl; } static unsigned int lpuart32_get_mctrl(struct uart_port *port) { - unsigned int temp = 0; - unsigned long reg; - - reg = lpuart32_read(port, UARTMODIR); - if (reg & UARTMODIR_TXCTSE) - temp |= TIOCM_CTS; + unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + u32 ctrl; - if (reg & UARTMODIR_RXRTSE) - temp |= TIOCM_RTS; + ctrl = lpuart32_read(port, UARTCTRL); + if (ctrl & UARTCTRL_LOOPS) + mctrl |= TIOCM_LOOP; - return temp; + return mctrl; } static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - unsigned char temp; - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - /* Make sure RXRTSE bit is not set when RS485 is enabled */ - if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) { - temp = readb(sport->port.membase + UARTMODEM) & - ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + u8 cr1; - if (mctrl & TIOCM_RTS) - temp |= UARTMODEM_RXRTSE; + cr1 = readb(port->membase + UARTCR1); - if (mctrl & TIOCM_CTS) - temp |= UARTMODEM_TXCTSE; + /* for internal loopback we need LOOPS=1 and RSRC=0 */ + cr1 &= ~(UARTCR1_LOOPS | UARTCR1_RSRC); + if (mctrl & TIOCM_LOOP) + cr1 |= UARTCR1_LOOPS; - writeb(temp, port->membase + UARTMODEM); - } + writeb(cr1, port->membase + UARTCR1); } static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) { + u32 ctrl; + + ctrl = lpuart32_read(port, UARTCTRL); + /* for internal loopback we need LOOPS=1 and RSRC=0 */ + ctrl &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC); + if (mctrl & TIOCM_LOOP) + ctrl |= UARTCTRL_LOOPS; + + lpuart32_write(port, ctrl, UARTCTRL); } static void lpuart_break_ctl(struct uart_port *port, int break_state) { - unsigned char temp; + u8 cr2; - temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK; + cr2 = readb(port->membase + UARTCR2) & ~UARTCR2_SBK; if (break_state != 0) - temp |= UARTCR2_SBK; + cr2 |= UARTCR2_SBK; - writeb(temp, port->membase + UARTCR2); + writeb(cr2, port->membase + UARTCR2); } static void lpuart32_break_ctl(struct uart_port *port, int break_state) { - unsigned long temp; - - temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK; + u32 ctrl; - if (break_state != 0) - temp |= UARTCTRL_SBK; + ctrl = lpuart32_read(port, UARTCTRL); - lpuart32_write(port, temp, UARTCTRL); + /* + * LPUART IP now has two known bugs, one is CTS has higher priority than the + * break signal, which causes the break signal sending through UARTCTRL_SBK + * may impacted by the CTS input if the HW flow control is enabled. It + * exists on all platforms we support in this driver. + * Another bug is i.MX8QM LPUART may have an additional break character + * being sent after SBK was cleared. + * To avoid above two bugs, we use Transmit Data Inversion function to send + * the break signal instead of UARTCTRL_SBK. + */ + if (break_state != 0) { + /* + * Disable the transmitter to prevent any data from being sent out + * during break, then invert the TX line to send break. + */ + ctrl &= ~UARTCTRL_TE; + lpuart32_write(port, ctrl, UARTCTRL); + ctrl |= UARTCTRL_TXINV; + lpuart32_write(port, ctrl, UARTCTRL); + } else { + /* Disable the TXINV to turn off break and re-enable transmitter. */ + ctrl &= ~UARTCTRL_TXINV; + lpuart32_write(port, ctrl, UARTCTRL); + ctrl |= UARTCTRL_TE; + lpuart32_write(port, ctrl, UARTCTRL); + } } static void lpuart_setup_watermark(struct lpuart_port *sport) { - unsigned char val, cr2; - unsigned char cr2_saved; + u8 fifo, cr2, cr2_saved; cr2 = readb(sport->port.membase + UARTCR2); cr2_saved = cr2; @@ -1433,8 +1625,8 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) UARTCR2_RIE | UARTCR2_RE); writeb(cr2, sport->port.membase + UARTCR2); - val = readb(sport->port.membase + UARTPFIFO); - writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE, + fifo = readb(sport->port.membase + UARTPFIFO); + writeb(fifo | UARTPFIFO_TXFE | UARTPFIFO_RXFE, sport->port.membase + UARTPFIFO); /* flush Tx and Rx FIFO */ @@ -1447,8 +1639,10 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO); } + if (uart_console(&sport->port)) + sport->rx_watermark = 1; writeb(0, sport->port.membase + UARTTWFIFO); - writeb(1, sport->port.membase + UARTRWFIFO); + writeb(sport->rx_watermark, sport->port.membase + UARTRWFIFO); /* Restore cr2 */ writeb(cr2_saved, sport->port.membase + UARTCR2); @@ -1456,7 +1650,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) static void lpuart_setup_watermark_enable(struct lpuart_port *sport) { - unsigned char cr2; + u8 cr2; lpuart_setup_watermark(sport); @@ -1467,42 +1661,56 @@ static void lpuart_setup_watermark_enable(struct lpuart_port *sport) static void lpuart32_setup_watermark(struct lpuart_port *sport) { - unsigned long val, ctrl; - unsigned long ctrl_saved; + u32 val, ctrl, ctrl_saved; ctrl = lpuart32_read(&sport->port, UARTCTRL); ctrl_saved = ctrl; ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE | - UARTCTRL_RIE | UARTCTRL_RE); + UARTCTRL_RIE | UARTCTRL_RE | UARTCTRL_ILIE); lpuart32_write(&sport->port, ctrl, UARTCTRL); /* enable FIFO mode */ val = lpuart32_read(&sport->port, UARTFIFO); val |= UARTFIFO_TXFE | UARTFIFO_RXFE; val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + val |= FIELD_PREP(UARTFIFO_RXIDEN, 0x3); lpuart32_write(&sport->port, val, UARTFIFO); /* set the watermark */ - val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF); + if (uart_console(&sport->port)) + sport->rx_watermark = 1; + val = (sport->rx_watermark << UARTWATER_RXWATER_OFF) | + (0x0 << UARTWATER_TXWATER_OFF); lpuart32_write(&sport->port, val, UARTWATER); + /* set RTS watermark */ + if (!uart_console(&sport->port)) { + val = lpuart32_read(&sport->port, UARTMODIR); + val |= FIELD_PREP(UARTMODIR_RTSWATER, sport->rxfifo_size >> 1); + lpuart32_write(&sport->port, val, UARTMODIR); + } + /* Restore cr2 */ lpuart32_write(&sport->port, ctrl_saved, UARTCTRL); } static void lpuart32_setup_watermark_enable(struct lpuart_port *sport) { - u32 temp; + u32 ctrl; lpuart32_setup_watermark(sport); - temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; - lpuart32_write(&sport->port, temp, UARTCTRL); + ctrl = lpuart32_read(&sport->port, UARTCTRL); + ctrl |= UARTCTRL_RE | UARTCTRL_TE; + ctrl |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7); + lpuart32_write(&sport->port, ctrl, UARTCTRL); } static void rx_dma_timer_init(struct lpuart_port *sport) { + if (sport->dma_idle_int) + return; + timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; add_timer(&sport->lpuart_timer); @@ -1532,6 +1740,9 @@ static void lpuart_tx_dma_startup(struct lpuart_port *sport) u32 uartbaud; int ret; + if (uart_console(&sport->port)) + goto err; + if (!sport->dma_tx_chan) goto err; @@ -1559,131 +1770,159 @@ err: static void lpuart_rx_dma_startup(struct lpuart_port *sport) { int ret; + u8 cr3; + + if (uart_console(&sport->port)) + goto err; if (!sport->dma_rx_chan) goto err; + /* set default Rx DMA timeout */ + sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); + ret = lpuart_start_rx_dma(sport); if (ret) goto err; - /* set Rx DMA timeout */ - sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); if (!sport->dma_rx_timeout) sport->dma_rx_timeout = 1; sport->lpuart_dma_rx_use = true; rx_dma_timer_init(sport); + if (sport->port.has_sysrq && !lpuart_is_32(sport)) { + cr3 = readb(sport->port.membase + UARTCR3); + cr3 |= UARTCR3_FEIE; + writeb(cr3, sport->port.membase + UARTCR3); + } + return; err: sport->lpuart_dma_rx_use = false; } +static void lpuart_hw_setup(struct lpuart_port *sport) +{ + unsigned long flags; + + uart_port_lock_irqsave(&sport->port, &flags); + + lpuart_setup_watermark_enable(sport); + + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); + + uart_port_unlock_irqrestore(&sport->port, flags); +} + static int lpuart_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long flags; - unsigned char temp; + u8 fifo; /* determine FIFO size and enable FIFO mode */ - temp = readb(sport->port.membase + UARTPFIFO); + fifo = readb(port->membase + UARTPFIFO); - sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) & + sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_TXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK); - sport->port.fifosize = sport->txfifo_size; + port->fifosize = sport->txfifo_size; - sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & + sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_RXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK); lpuart_request_dma(sport); + lpuart_hw_setup(sport); - spin_lock_irqsave(&sport->port.lock, flags); - - lpuart_setup_watermark_enable(sport); - - lpuart_rx_dma_startup(sport); - lpuart_tx_dma_startup(sport); + return 0; +} - spin_unlock_irqrestore(&sport->port.lock, flags); +static void lpuart32_hw_disable(struct lpuart_port *sport) +{ + u32 ctrl; - return 0; + ctrl = lpuart32_read(&sport->port, UARTCTRL); + ctrl &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | + UARTCTRL_TIE | UARTCTRL_TE); + lpuart32_write(&sport->port, ctrl, UARTCTRL); } static void lpuart32_configure(struct lpuart_port *sport) { - unsigned long temp; + u32 ctrl; - if (sport->lpuart_dma_rx_use) { - /* RXWATER must be 0 */ - temp = lpuart32_read(&sport->port, UARTWATER); - temp &= ~(UARTWATER_WATER_MASK << UARTWATER_RXWATER_OFF); - lpuart32_write(&sport->port, temp, UARTWATER); - } - temp = lpuart32_read(&sport->port, UARTCTRL); + ctrl = lpuart32_read(&sport->port, UARTCTRL); if (!sport->lpuart_dma_rx_use) - temp |= UARTCTRL_RIE; + ctrl |= UARTCTRL_RIE | UARTCTRL_ILIE; if (!sport->lpuart_dma_tx_use) - temp |= UARTCTRL_TIE; - lpuart32_write(&sport->port, temp, UARTCTRL); + ctrl |= UARTCTRL_TIE; + lpuart32_write(&sport->port, ctrl, UARTCTRL); +} + +static void lpuart32_hw_setup(struct lpuart_port *sport) +{ + unsigned long flags; + + uart_port_lock_irqsave(&sport->port, &flags); + + lpuart32_hw_disable(sport); + + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); + + lpuart32_setup_watermark_enable(sport); + lpuart32_configure(sport); + + uart_port_unlock_irqrestore(&sport->port, flags); } static int lpuart32_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long flags; - unsigned long temp; + u32 fifo; /* determine FIFO size */ - temp = lpuart32_read(&sport->port, UARTFIFO); + fifo = lpuart32_read(port, UARTFIFO); - sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) & + sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); - sport->port.fifosize = sport->txfifo_size; + port->fifosize = sport->txfifo_size; - sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) & + sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); /* - * The LS1028A has a fixed length of 16 words. Although it supports the - * RX/TXSIZE fields their encoding is different. Eg the reference manual - * states 0b101 is 16 words. + * The LS1021A and LS1028A have a fixed FIFO depth of 16 words. + * Although they support the RX/TXSIZE fields, their encoding is + * different. Eg the reference manual states 0b101 is 16 words. */ - if (is_ls1028a_lpuart(sport)) { + if (is_layerscape_lpuart(sport)) { sport->rxfifo_size = 16; sport->txfifo_size = 16; - sport->port.fifosize = sport->txfifo_size; + port->fifosize = sport->txfifo_size; } lpuart_request_dma(sport); + lpuart32_hw_setup(sport); - spin_lock_irqsave(&sport->port.lock, flags); - - lpuart32_setup_watermark_enable(sport); - - lpuart_rx_dma_startup(sport); - lpuart_tx_dma_startup(sport); - - lpuart32_configure(sport); - - spin_unlock_irqrestore(&sport->port.lock, flags); return 0; } static void lpuart_dma_shutdown(struct lpuart_port *sport) { if (sport->lpuart_dma_rx_use) { - del_timer_sync(&sport->lpuart_timer); lpuart_dma_rx_free(&sport->port); + sport->lpuart_dma_rx_use = false; } if (sport->lpuart_dma_tx_use) { - if (wait_event_interruptible(sport->dma_wait, - !sport->dma_tx_in_progress) != false) { + if (wait_event_interruptible_timeout(sport->dma_wait, + !sport->dma_tx_in_progress, msecs_to_jiffies(300)) <= 0) { sport->dma_tx_in_progress = false; - dmaengine_terminate_all(sport->dma_tx_chan); + dmaengine_terminate_sync(sport->dma_tx_chan); } + sport->lpuart_dma_tx_use = false; } if (sport->dma_tx_chan) @@ -1695,18 +1934,18 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) static void lpuart_shutdown(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char temp; + u8 cr2; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* disable Rx/Tx and interrupts */ - temp = readb(port->membase + UARTCR2); - temp &= ~(UARTCR2_TE | UARTCR2_RE | + cr2 = readb(port->membase + UARTCR2); + cr2 &= ~(UARTCR2_TE | UARTCR2_RE | UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); - writeb(temp, port->membase + UARTCR2); + writeb(cr2, port->membase + UARTCR2); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); lpuart_dma_shutdown(sport); } @@ -1715,39 +1954,53 @@ static void lpuart32_shutdown(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long temp; + u32 temp; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); - /* disable Rx/Tx and interrupts */ + /* clear status */ + temp = lpuart32_read(port, UARTSTAT); + lpuart32_write(port, temp, UARTSTAT); + + /* disable Rx/Tx DMA */ + temp = lpuart32_read(port, UARTBAUD); + temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE); + lpuart32_write(port, temp, UARTBAUD); + + /* disable Rx/Tx and interrupts and break condition */ temp = lpuart32_read(port, UARTCTRL); - temp &= ~(UARTCTRL_TE | UARTCTRL_RE | - UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE); + temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_ILIE | + UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK); lpuart32_write(port, temp, UARTCTRL); - spin_unlock_irqrestore(&port->lock, flags); + /* flush Rx/Tx FIFO */ + temp = lpuart32_read(port, UARTFIFO); + temp |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + lpuart32_write(port, temp, UARTFIFO); + + uart_port_unlock_irqrestore(port, flags); lpuart_dma_shutdown(sport); } static void lpuart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; + u8 cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int sbr, brfa; - cr1 = old_cr1 = readb(sport->port.membase + UARTCR1); - old_cr2 = readb(sport->port.membase + UARTCR2); - cr3 = readb(sport->port.membase + UARTCR3); - cr4 = readb(sport->port.membase + UARTCR4); - bdh = readb(sport->port.membase + UARTBDH); - modem = readb(sport->port.membase + UARTMODEM); + cr1 = old_cr1 = readb(port->membase + UARTCR1); + old_cr2 = readb(port->membase + UARTCR2); + cr3 = readb(port->membase + UARTCR3); + cr4 = readb(port->membase + UARTCR4); + bdh = readb(port->membase + UARTBDH); + modem = readb(port->membase + UARTMODEM); /* * only support CS8 and CS7, and for CS7 must enable PE. * supported mode: @@ -1779,7 +2032,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, * When auto RS-485 RTS mode is enabled, * hardware flow control need to be disabled. */ - if (sport->port.rs485.flags & SER_RS485_ENABLED) + if (port->rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; if (termios->c_cflag & CRTSCTS) @@ -1820,61 +2073,59 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, * Need to update the Ring buffer length according to the selected * baud rate and restart Rx DMA path. * - * Since timer function acqures sport->port.lock, need to stop before - * acquring same lock because otherwise del_timer_sync() can deadlock. + * Since timer function acqures port->lock, need to stop before + * acquring same lock because otherwise timer_delete_sync() can deadlock. */ - if (old && sport->lpuart_dma_rx_use) { - del_timer_sync(&sport->lpuart_timer); - lpuart_dma_rx_free(&sport->port); - } + if (old && sport->lpuart_dma_rx_use) + lpuart_dma_rx_free(port); - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(port, &flags); - sport->port.read_status_mask = 0; + port->read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE; + port->read_status_mask |= UARTSR1_FE | UARTSR1_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - sport->port.read_status_mask |= UARTSR1_FE; + port->read_status_mask |= UARTSR1_FE; /* characters to ignore */ - sport->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSR1_PE; + port->ignore_status_mask |= UARTSR1_PE; if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= UARTSR1_FE; + port->ignore_status_mask |= UARTSR1_FE; /* * if we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSR1_OR; + port->ignore_status_mask |= UARTSR1_OR; } /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ - lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); + lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TC); /* disable transmit and receive */ writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE), - sport->port.membase + UARTCR2); + port->membase + UARTCR2); - sbr = sport->port.uartclk / (16 * baud); - brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud; + sbr = port->uartclk / (16 * baud); + brfa = ((port->uartclk - (16 * sbr * baud)) * 2) / baud; bdh &= ~UARTBDH_SBR_MASK; bdh |= (sbr >> 8) & 0x1F; cr4 &= ~UARTCR4_BRFA_MASK; brfa &= UARTCR4_BRFA_MASK; - writeb(cr4 | brfa, sport->port.membase + UARTCR4); - writeb(bdh, sport->port.membase + UARTBDH); - writeb(sbr & 0xFF, sport->port.membase + UARTBDL); - writeb(cr3, sport->port.membase + UARTCR3); - writeb(cr1, sport->port.membase + UARTCR1); - writeb(modem, sport->port.membase + UARTMODEM); + writeb(cr4 | brfa, port->membase + UARTCR4); + writeb(bdh, port->membase + UARTBDH); + writeb(sbr & 0xFF, port->membase + UARTBDL); + writeb(cr3, port->membase + UARTCR3); + writeb(cr1, port->membase + UARTCR1); + writeb(modem, port->membase + UARTMODEM); /* restore control register */ - writeb(old_cr2, sport->port.membase + UARTCR2); + writeb(old_cr2, port->membase + UARTCR2); if (old && sport->lpuart_dma_rx_use) { if (!lpuart_start_rx_dma(sport)) @@ -1883,14 +2134,14 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, sport->lpuart_dma_rx_use = false; } - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void __lpuart32_serial_setbrg(struct uart_port *port, unsigned int baudrate, bool use_rx_dma, bool use_tx_dma) { - u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp; + u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, baud; u32 clk = port->uartclk; /* @@ -1919,12 +2170,15 @@ static void __lpuart32_serial_setbrg(struct uart_port *port, tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate; /* select best values between sbr and sbr+1 */ - tmp = clk / (tmp_osr * (tmp_sbr + 1)); - if (tmp_diff > (baudrate - tmp)) { - tmp_diff = baudrate - tmp; + baud = clk / (tmp_osr * (tmp_sbr + 1)); + if (tmp_diff > (baudrate - baud)) { + tmp_diff = baudrate - baud; tmp_sbr++; } + if (tmp_sbr > UARTBAUD_SBR_MASK) + continue; + if (tmp_diff <= baud_diff) { baud_diff = tmp_diff; osr = tmp_osr; @@ -1940,23 +2194,23 @@ static void __lpuart32_serial_setbrg(struct uart_port *port, dev_warn(port->dev, "unacceptable baud rate difference of more than 3%%\n"); - tmp = lpuart32_read(port, UARTBAUD); + baud = lpuart32_read(port, UARTBAUD); if ((osr > 3) && (osr < 8)) - tmp |= UARTBAUD_BOTHEDGE; + baud |= UARTBAUD_BOTHEDGE; - tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT); - tmp |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT; + baud &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT); + baud |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT; - tmp &= ~UARTBAUD_SBR_MASK; - tmp |= sbr & UARTBAUD_SBR_MASK; + baud &= ~UARTBAUD_SBR_MASK; + baud |= sbr & UARTBAUD_SBR_MASK; if (!use_rx_dma) - tmp &= ~UARTBAUD_RDMAE; + baud &= ~UARTBAUD_RDMAE; if (!use_tx_dma) - tmp &= ~UARTBAUD_TDMAE; + baud &= ~UARTBAUD_TDMAE; - lpuart32_write(port, tmp, UARTBAUD); + lpuart32_write(port, baud, UARTBAUD); } static void lpuart32_serial_setbrg(struct lpuart_port *sport, @@ -1970,19 +2224,22 @@ static void lpuart32_serial_setbrg(struct lpuart_port *sport, static void lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned long ctrl, old_ctrl, modem; + u32 ctrl, old_ctrl, bd, modem; unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL); - modem = lpuart32_read(&sport->port, UARTMODIR); + ctrl = old_ctrl = lpuart32_read(port, UARTCTRL); + bd = lpuart32_read(port, UARTBAUD); + modem = lpuart32_read(port, UARTMODIR); + sport->is_cs7 = false; /* - * only support CS8 and CS7, and for CS7 must enable PE. + * only support CS8 and CS7 * supported mode: + * - (7,n,1) (imx only) * - (7,e/o,1) * - (8,n,1) * - (8,m/s,1) @@ -1997,7 +2254,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & CSIZE) == CS8 || (termios->c_cflag & CSIZE) == CS7) - ctrl = old_ctrl & ~UARTCTRL_M; + ctrl = old_ctrl & ~(UARTCTRL_M | UARTCTRL_M7); if (termios->c_cflag & CMSPAR) { if ((termios->c_cflag & CSIZE) != CS8) { @@ -2011,22 +2268,31 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, * When auto RS-485 RTS mode is enabled, * hardware flow control need to be disabled. */ - if (sport->port.rs485.flags & SER_RS485_ENABLED) + if (port->rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; - if (termios->c_cflag & CRTSCTS) { - modem |= (UARTMODIR_RXRTSE | UARTMODIR_TXCTSE); - } else { - termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) + modem |= UARTMODIR_RXRTSE | UARTMODIR_TXCTSE; + else modem &= ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE); - } if (termios->c_cflag & CSTOPB) - termios->c_cflag &= ~CSTOPB; + bd |= UARTBAUD_SBNS; + else + bd &= ~UARTBAUD_SBNS; - /* parity must be enabled when CS7 to match 8-bits format */ - if ((termios->c_cflag & CSIZE) == CS7) - termios->c_cflag |= PARENB; + /* + * imx support 7-bits format, no limitation on parity when CS7 + * for layerscape, parity must be enabled when CS7 to match 8-bits format + */ + if ((termios->c_cflag & CSIZE) == CS7 && !(termios->c_cflag & PARENB)) { + if (is_imx7ulp_lpuart(sport) || + is_imx8ulp_lpuart(sport) || + is_imx8qxp_lpuart(sport)) + ctrl |= UARTCTRL_M7; + else + termios->c_cflag |= PARENB; + } if ((termios->c_cflag & PARENB)) { if (termios->c_cflag & CMSPAR) { @@ -2052,50 +2318,64 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, * Need to update the Ring buffer length according to the selected * baud rate and restart Rx DMA path. * - * Since timer function acqures sport->port.lock, need to stop before - * acquring same lock because otherwise del_timer_sync() can deadlock. + * Since timer function acqures port->lock, need to stop before + * acquring same lock because otherwise timer_delete_sync() can deadlock. */ - if (old && sport->lpuart_dma_rx_use) { - del_timer_sync(&sport->lpuart_timer); - lpuart_dma_rx_free(&sport->port); - } + if (old && sport->lpuart_dma_rx_use) + lpuart_dma_rx_free(port); - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(port, &flags); - sport->port.read_status_mask = 0; + port->read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; + port->read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - sport->port.read_status_mask |= UARTSTAT_FE; + port->read_status_mask |= UARTSTAT_FE; /* characters to ignore */ - sport->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSTAT_PE; + port->ignore_status_mask |= UARTSTAT_PE; if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= UARTSTAT_FE; + port->ignore_status_mask |= UARTSTAT_FE; /* * if we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSTAT_OR; + port->ignore_status_mask |= UARTSTAT_OR; } /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - /* wait transmit engin complete */ - lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); + /* + * disable CTS to ensure the transmit engine is not blocked by the flow + * control when there is dirty data in TX FIFO + */ + lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + + /* + * LPUART Transmission Complete Flag may never be set while queuing a break + * character, so skip waiting for transmission complete when UARTCTRL_SBK is + * asserted. + */ + if (!(old_ctrl & UARTCTRL_SBK)) + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); /* disable transmit and receive */ - lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), + lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), UARTCTRL); + lpuart32_write(port, bd, UARTBAUD); lpuart32_serial_setbrg(sport, baud); - lpuart32_write(&sport->port, modem, UARTMODIR); - lpuart32_write(&sport->port, ctrl, UARTCTRL); /* restore control register */ + lpuart32_write(port, ctrl, UARTCTRL); + /* re-enable the CTS if needed */ + lpuart32_write(port, modem, UARTMODIR); + + if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE) + sport->is_cs7 = true; if (old && sport->lpuart_dma_rx_use) { if (!lpuart_start_rx_dma(sport)) @@ -2104,7 +2384,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, sport->lpuart_dma_rx_use = false; } - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *lpuart_type(struct uart_port *port) @@ -2159,6 +2439,7 @@ static const struct uart_ops lpuart_pops = { .startup = lpuart_startup, .shutdown = lpuart_shutdown, .set_termios = lpuart_set_termios, + .pm = lpuart_uart_pm, .type = lpuart_type, .request_port = lpuart_request_port, .release_port = lpuart_release_port, @@ -2183,6 +2464,7 @@ static const struct uart_ops lpuart32_pops = { .startup = lpuart32_startup, .shutdown = lpuart32_shutdown, .set_termios = lpuart32_set_termios, + .pm = lpuart_uart_pm, .type = lpuart_type, .request_port = lpuart_request_port, .release_port = lpuart_release_port, @@ -2199,13 +2481,13 @@ static const struct uart_ops lpuart32_pops = { static struct lpuart_port *lpuart_ports[UART_NR]; #ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE -static void lpuart_console_putchar(struct uart_port *port, int ch) +static void lpuart_console_putchar(struct uart_port *port, unsigned char ch) { lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TDRE); writeb(ch, port->membase + UARTDR); } -static void lpuart32_console_putchar(struct uart_port *port, int ch) +static void lpuart32_console_putchar(struct uart_port *port, unsigned char ch) { lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); lpuart32_write(port, ch, UARTDATA); @@ -2215,14 +2497,14 @@ static void lpuart_console_write(struct console *co, const char *s, unsigned int count) { struct lpuart_port *sport = lpuart_ports[co->index]; - unsigned char old_cr2, cr2; + u8 old_cr2, cr2; unsigned long flags; int locked = 1; - if (sport->port.sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&sport->port.lock, flags); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&sport->port, &flags); else - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); /* first save CR2 and then disable interrupts */ cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); @@ -2238,21 +2520,21 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) writeb(old_cr2, sport->port.membase + UARTCR2); if (locked) - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } static void lpuart32_console_write(struct console *co, const char *s, unsigned int count) { struct lpuart_port *sport = lpuart_ports[co->index]; - unsigned long old_cr, cr; + u32 old_cr, cr; unsigned long flags; int locked = 1; - if (sport->port.sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&sport->port.lock, flags); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&sport->port, &flags); else - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); /* first save CR2 and then disable interrupts */ cr = old_cr = lpuart32_read(&sport->port, UARTCTRL); @@ -2268,7 +2550,7 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) lpuart32_write(&sport->port, old_cr, UARTCTRL); if (locked) - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } /* @@ -2279,7 +2561,7 @@ static void __init lpuart_console_get_options(struct lpuart_port *sport, int *baud, int *parity, int *bits) { - unsigned char cr, bdh, bdl, brfa; + u8 cr, bdh, bdl, brfa; unsigned int sbr, uartclk, baud_raw; cr = readb(sport->port.membase + UARTCR2); @@ -2328,7 +2610,7 @@ static void __init lpuart32_console_get_options(struct lpuart_port *sport, int *baud, int *parity, int *bits) { - unsigned long cr, bd; + u32 cr, bd; unsigned int sbr, uartclk, baud_raw; cr = lpuart32_read(&sport->port, UARTCTRL); @@ -2355,6 +2637,9 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud, bd = lpuart32_read(&sport->port, UARTBAUD); bd &= UARTBAUD_SBR_MASK; + if (!bd) + return; + sbr = bd; uartclk = lpuart_get_baud_clk_rate(sport); /* @@ -2501,6 +2786,9 @@ OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8ulp-lpuart", lpuart32_imx_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8qxp-lpuart", lpuart32_imx_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,imxrt1050-lpuart", lpuart32_imx_early_console_setup); EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); @@ -2519,30 +2807,84 @@ static struct uart_driver lpuart_reg = { .cons = LPUART_CONSOLE, }; +static const struct serial_rs485 lpuart_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + /* delay_rts_* and RX_DURING_TX are not supported */ +}; + +static int lpuart_global_reset(struct lpuart_port *sport) +{ + struct uart_port *port = &sport->port; + void __iomem *global_addr; + u32 ctrl, bd; + unsigned int val = 0; + int ret; + + ret = clk_prepare_enable(sport->ipg_clk); + if (ret) { + dev_err(port->dev, "failed to enable uart ipg clk: %d\n", ret); + return ret; + } + + if (is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) { + /* + * If the transmitter is used by earlycon, wait for transmit engine to + * complete and then reset. + */ + ctrl = lpuart32_read(port, UARTCTRL); + if (ctrl & UARTCTRL_TE) { + bd = lpuart32_read(port, UARTBAUD); + if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false, + port)) { + dev_warn(port->dev, + "timeout waiting for transmit engine to complete\n"); + clk_disable_unprepare(sport->ipg_clk); + return 0; + } + } + + global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF; + writel(UART_GLOBAL_RST, global_addr); + usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); + writel(0, global_addr); + usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); + + /* Recover the transmitter for earlycon. */ + if (ctrl & UARTCTRL_TE) { + lpuart32_write(port, bd, UARTBAUD); + lpuart32_write(port, ctrl, UARTCTRL); + } + } + + clk_disable_unprepare(sport->ipg_clk); + return 0; +} + static int lpuart_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = of_match_device(lpuart_dt_ids, - &pdev->dev); - const struct lpuart_soc_data *sdata = of_id->data; + const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev); struct device_node *np = pdev->dev.of_node; struct lpuart_port *sport; struct resource *res; + irq_handler_t handler; int ret; sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sport->port.membase = devm_ioremap_resource(&pdev->dev, res); + sport->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(sport->port.membase)) return PTR_ERR(sport->port.membase); sport->port.membase += sdata->reg_off; - sport->port.mapbase = res->start; + sport->port.mapbase = res->start + sdata->reg_off; sport->port.dev = &pdev->dev; sport->port.type = PORT_LPUART; sport->devtype = sdata->devtype; + sport->rx_watermark = sdata->rx_watermark; + sport->dma_idle_int = is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) || + is_imx8qxp_lpuart(sport); ret = platform_get_irq(pdev, 0); if (ret < 0) return ret; @@ -2559,12 +2901,12 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485_config = lpuart32_config_rs485; else sport->port.rs485_config = lpuart_config_rs485; + sport->port.rs485_supported = lpuart_rs485_supported; sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->ipg_clk)) { ret = PTR_ERR(sport->ipg_clk); - dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret); - return ret; + return dev_err_probe(&pdev->dev, ret, "failed to get uart ipg clk\n"); } sport->baud_clk = NULL; @@ -2572,30 +2914,24 @@ static int lpuart_probe(struct platform_device *pdev) sport->baud_clk = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(sport->baud_clk)) { ret = PTR_ERR(sport->baud_clk); - dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret); - return ret; + return dev_err_probe(&pdev->dev, ret, "failed to get uart baud clk\n"); } } ret = of_alias_get_id(np, "serial"); if (ret < 0) { - ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL); - if (ret < 0) { - dev_err(&pdev->dev, "port line is full, add device failed\n"); - return ret; - } - sport->id_allocated = true; + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; } if (ret >= ARRAY_SIZE(lpuart_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", ret); - ret = -EINVAL; - goto failed_out_of_range; + return -EINVAL; } sport->port.line = ret; ret = lpuart_enable_clks(sport); if (ret) - goto failed_clock_enable; + return ret; sport->port.uartclk = lpuart_get_baud_clk_rate(sport); lpuart_ports[sport->port.line] = sport; @@ -2604,56 +2940,55 @@ static int lpuart_probe(struct platform_device *pdev) if (lpuart_is_32(sport)) { lpuart_reg.cons = LPUART32_CONSOLE; - ret = devm_request_irq(&pdev->dev, sport->port.irq, lpuart32_int, 0, - DRIVER_NAME, sport); + handler = lpuart32_int; } else { lpuart_reg.cons = LPUART_CONSOLE; - ret = devm_request_irq(&pdev->dev, sport->port.irq, lpuart_int, 0, - DRIVER_NAME, sport); + handler = lpuart_int; } - if (ret) - goto failed_irq_request; + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); - ret = uart_add_one_port(&lpuart_reg, &sport->port); + ret = lpuart_global_reset(sport); if (ret) - goto failed_attach_port; + goto failed_reset; ret = uart_get_rs485_mode(&sport->port); if (ret) goto failed_get_rs485; - if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) - dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); - - if (sport->port.rs485.delay_rts_before_send || - sport->port.rs485.delay_rts_after_send) - dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); + ret = uart_add_one_port(&lpuart_reg, &sport->port); + if (ret) + goto failed_attach_port; - sport->port.rs485_config(&sport->port, &sport->port.rs485); + ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, + dev_name(&pdev->dev), sport); + if (ret) + goto failed_irq_request; return 0; -failed_get_rs485: -failed_attach_port: failed_irq_request: + uart_remove_one_port(&lpuart_reg, &sport->port); +failed_attach_port: +failed_get_rs485: +failed_reset: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); lpuart_disable_clks(sport); -failed_clock_enable: -failed_out_of_range: - if (sport->id_allocated) - ida_simple_remove(&fsl_lpuart_ida, sport->port.line); return ret; } -static int lpuart_remove(struct platform_device *pdev) +static void lpuart_remove(struct platform_device *pdev) { struct lpuart_port *sport = platform_get_drvdata(pdev); uart_remove_one_port(&lpuart_reg, &sport->port); - if (sport->id_allocated) - ida_simple_remove(&fsl_lpuart_ida, sport->port.line); - lpuart_disable_clks(sport); if (sport->dma_tx_chan) @@ -2662,100 +2997,248 @@ static int lpuart_remove(struct platform_device *pdev) if (sport->dma_rx_chan) dma_release_channel(sport->dma_rx_chan); - return 0; + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); } -static int __maybe_unused lpuart_suspend(struct device *dev) +static int lpuart_runtime_suspend(struct device *dev) { - struct lpuart_port *sport = dev_get_drvdata(dev); - unsigned long temp; - bool irq_wake; + struct platform_device *pdev = to_platform_device(dev); + struct lpuart_port *sport = platform_get_drvdata(pdev); - if (lpuart_is_32(sport)) { - /* disable Rx/Tx and interrupts */ - temp = lpuart32_read(&sport->port, UARTCTRL); - temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); - lpuart32_write(&sport->port, temp, UARTCTRL); - } else { - /* disable Rx/Tx and interrupts */ - temp = readb(sport->port.membase + UARTCR2); - temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE); - writeb(temp, sport->port.membase + UARTCR2); - } + lpuart_disable_clks(sport); - uart_suspend_port(&lpuart_reg, &sport->port); + return 0; +}; - /* uart_suspend_port() might set wakeup flag */ - irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); +static int lpuart_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpuart_port *sport = platform_get_drvdata(pdev); - if (sport->lpuart_dma_rx_use) { - /* - * EDMA driver during suspend will forcefully release any - * non-idle DMA channels. If port wakeup is enabled or if port - * is console port or 'no_console_suspend' is set the Rx DMA - * cannot resume as as expected, hence gracefully release the - * Rx DMA path before suspend and start Rx DMA path on resume. - */ - if (irq_wake) { - del_timer_sync(&sport->lpuart_timer); - lpuart_dma_rx_free(&sport->port); - } + return lpuart_enable_clks(sport); +}; - /* Disable Rx DMA to use UART port as wakeup source */ - if (lpuart_is_32(sport)) { - temp = lpuart32_read(&sport->port, UARTBAUD); - lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, - UARTBAUD); +static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on) +{ + u32 val, baud; + + if (lpuart_is_32(sport)) { + val = lpuart32_read(&sport->port, UARTCTRL); + baud = lpuart32_read(&sport->port, UARTBAUD); + if (on) { + /* set rx_watermark to 0 in wakeup source mode */ + lpuart32_write(&sport->port, 0, UARTWATER); + val |= UARTCTRL_RIE; + /* clear RXEDGIF flag before enable RXEDGIE interrupt */ + lpuart32_write(&sport->port, UARTSTAT_RXEDGIF, UARTSTAT); + baud |= UARTBAUD_RXEDGIE; } else { - writeb(readb(sport->port.membase + UARTCR5) & - ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + val &= ~UARTCTRL_RIE; + baud &= ~UARTBAUD_RXEDGIE; } + lpuart32_write(&sport->port, val, UARTCTRL); + lpuart32_write(&sport->port, baud, UARTBAUD); + } else { + val = readb(sport->port.membase + UARTCR2); + if (on) + val |= UARTCR2_RIE; + else + val &= ~UARTCR2_RIE; + writeb(val, sport->port.membase + UARTCR2); } +} - if (sport->lpuart_dma_tx_use) { - sport->dma_tx_in_progress = false; - dmaengine_terminate_all(sport->dma_tx_chan); +static bool lpuart_uport_is_active(struct lpuart_port *sport) +{ + struct tty_port *port = &sport->port.state->port; + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + tty = tty_port_tty_get(port); + if (tty) { + tty_dev = tty->dev; + may_wake = tty_dev && device_may_wakeup(tty_dev); + tty_kref_put(tty); } - if (sport->port.suspended && !irq_wake) - lpuart_disable_clks(sport); + if ((tty_port_initialized(port) && may_wake) || + (!console_suspend_enabled && uart_console(&sport->port))) + return true; - return 0; + return false; } -static int __maybe_unused lpuart_resume(struct device *dev) +static int lpuart_suspend_noirq(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); - if (sport->port.suspended && !irq_wake) - lpuart_enable_clks(sport); + if (lpuart_uport_is_active(sport)) + serial_lpuart_enable_wakeup(sport, !!irq_wake); - if (lpuart_is_32(sport)) - lpuart32_setup_watermark_enable(sport); - else - lpuart_setup_watermark_enable(sport); + pinctrl_pm_select_sleep_state(dev); - if (sport->lpuart_dma_rx_use) { - if (irq_wake) { - if (!lpuart_start_rx_dma(sport)) - rx_dma_timer_init(sport); - else - sport->lpuart_dma_rx_use = false; + return 0; +} + +static int lpuart_resume_noirq(struct device *dev) +{ + struct lpuart_port *sport = dev_get_drvdata(dev); + struct tty_port *port = &sport->port.state->port; + bool wake_active; + u32 stat; + + pinctrl_pm_select_default_state(dev); + + if (lpuart_uport_is_active(sport)) { + serial_lpuart_enable_wakeup(sport, false); + + /* clear the wakeup flags */ + if (lpuart_is_32(sport)) { + stat = lpuart32_read(&sport->port, UARTSTAT); + lpuart32_write(&sport->port, stat, UARTSTAT); + + /* check whether lpuart wakeup was triggered */ + wake_active = stat & (UARTSTAT_RDRF | UARTSTAT_RXEDGIF); + + if (wake_active && irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq))) + pm_wakeup_event(tty_port_tty_get(port)->dev, 0); } } - lpuart_tx_dma_startup(sport); + return 0; +} - if (lpuart_is_32(sport)) - lpuart32_configure(sport); +static int lpuart_suspend(struct device *dev) +{ + struct lpuart_port *sport = dev_get_drvdata(dev); + u32 temp; + unsigned long flags; + uart_suspend_port(&lpuart_reg, &sport->port); + + if (lpuart_uport_is_active(sport)) { + uart_port_lock_irqsave(&sport->port, &flags); + if (lpuart_is_32(sport)) { + /* disable Rx/Tx and interrupts */ + temp = lpuart32_read(&sport->port, UARTCTRL); + temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); + lpuart32_write(&sport->port, temp, UARTCTRL); + } else { + /* disable Rx/Tx and interrupts */ + temp = readb(sport->port.membase + UARTCR2); + temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE); + writeb(temp, sport->port.membase + UARTCR2); + } + uart_port_unlock_irqrestore(&sport->port, flags); + + if (sport->lpuart_dma_rx_use) { + /* + * EDMA driver during suspend will forcefully release any + * non-idle DMA channels. If port wakeup is enabled or if port + * is console port or 'no_console_suspend' is set the Rx DMA + * cannot resume as expected, hence gracefully release the + * Rx DMA path before suspend and start Rx DMA path on resume. + */ + lpuart_dma_rx_free(&sport->port); + + /* Disable Rx DMA to use UART port as wakeup source */ + uart_port_lock_irqsave(&sport->port, &flags); + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, + UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) & + ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + } + uart_port_unlock_irqrestore(&sport->port, flags); + } + + if (sport->lpuart_dma_tx_use) { + uart_port_lock_irqsave(&sport->port, &flags); + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + temp &= ~UARTBAUD_TDMAE; + lpuart32_write(&sport->port, temp, UARTBAUD); + } else { + temp = readb(sport->port.membase + UARTCR5); + temp &= ~UARTCR5_TDMAS; + writeb(temp, sport->port.membase + UARTCR5); + } + uart_port_unlock_irqrestore(&sport->port, flags); + sport->dma_tx_in_progress = false; + dmaengine_terminate_sync(sport->dma_tx_chan); + } + } else if (pm_runtime_active(sport->port.dev)) { + lpuart_disable_clks(sport); + pm_runtime_disable(sport->port.dev); + pm_runtime_set_suspended(sport->port.dev); + } + + return 0; +} + +static void lpuart_console_fixup(struct lpuart_port *sport) +{ + struct tty_port *port = &sport->port.state->port; + struct uart_port *uport = &sport->port; + struct ktermios termios; + + /* i.MX7ULP enter VLLS mode that lpuart module power off and registers + * all lost no matter the port is wakeup source. + * For console port, console baud rate setting lost and print messy + * log when enable the console port as wakeup source. To avoid the + * issue happen, user should not enable uart port as wakeup source + * in VLLS mode, or restore console setting here. + */ + if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) && + console_suspend_enabled && uart_console(uport)) { + + mutex_lock(&port->mutex); + memset(&termios, 0, sizeof(struct ktermios)); + termios.c_cflag = uport->cons->cflag; + if (port->tty && termios.c_cflag == 0) + termios = port->tty->termios; + uport->ops->set_termios(uport, &termios, NULL); + mutex_unlock(&port->mutex); + } +} + +static int lpuart_resume(struct device *dev) +{ + struct lpuart_port *sport = dev_get_drvdata(dev); + int ret; + + if (lpuart_uport_is_active(sport)) { + if (lpuart_is_32(sport)) + lpuart32_hw_setup(sport); + else + lpuart_hw_setup(sport); + } else if (pm_runtime_active(sport->port.dev)) { + ret = lpuart_enable_clks(sport); + if (ret) + return ret; + pm_runtime_set_active(sport->port.dev); + pm_runtime_enable(sport->port.dev); + } + + lpuart_console_fixup(sport); uart_resume_port(&lpuart_reg, &sport->port); return 0; } -static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume); +static const struct dev_pm_ops lpuart_pm_ops = { + RUNTIME_PM_OPS(lpuart_runtime_suspend, + lpuart_runtime_resume, NULL) + NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq, + lpuart_resume_noirq) + SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume) +}; static struct platform_driver lpuart_driver = { .probe = lpuart_probe, @@ -2763,7 +3246,7 @@ static struct platform_driver lpuart_driver = { .driver = { .name = "fsl-lpuart", .of_match_table = lpuart_dt_ids, - .pm = &lpuart_pm_ops, + .pm = pm_ptr(&lpuart_pm_ops), }, }; @@ -2783,7 +3266,6 @@ static int __init lpuart_serial_init(void) static void __exit lpuart_serial_exit(void) { - ida_destroy(&fsl_lpuart_ida); platform_driver_unregister(&lpuart_driver); uart_unregister_driver(&lpuart_reg); } diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 624f3d541c68..b7e33a896589 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -19,6 +19,7 @@ #include <linux/fs.h> #include <linux/tty_flip.h> #include <linux/serial.h> +#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/major.h> #include <linux/string.h> @@ -37,19 +38,277 @@ #include <linux/firmware.h> #include <linux/bitops.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <linux/uaccess.h> -#include "icom.h" - /*#define ICOM_TRACE enable port trace capabilities */ #define ICOM_DRIVER_NAME "icom" -#define ICOM_VERSION_STR "1.3.1" #define NR_PORTS 128 -#define ICOM_PORT ((struct icom_port *)port) -#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref) + +static const unsigned int icom_acfg_baud[] = { + 300, + 600, + 900, + 1200, + 1800, + 2400, + 3600, + 4800, + 7200, + 9600, + 14400, + 19200, + 28800, + 38400, + 57600, + 76800, + 115200, + 153600, + 230400, + 307200, + 460800, +}; +#define BAUD_TABLE_LIMIT (ARRAY_SIZE(icom_acfg_baud) - 1) + +struct icom_regs { + u32 control; /* Adapter Control Register */ + u32 interrupt; /* Adapter Interrupt Register */ + u32 int_mask; /* Adapter Interrupt Mask Reg */ + u32 int_pri; /* Adapter Interrupt Priority r */ + u32 int_reg_b; /* Adapter non-masked Interrupt */ + u32 resvd01; + u32 resvd02; + u32 resvd03; + u32 control_2; /* Adapter Control Register 2 */ + u32 interrupt_2; /* Adapter Interrupt Register 2 */ + u32 int_mask_2; /* Adapter Interrupt Mask 2 */ + u32 int_pri_2; /* Adapter Interrupt Prior 2 */ + u32 int_reg_2b; /* Adapter non-masked 2 */ +}; + +struct func_dram { + u32 reserved[108]; /* 0-1B0 reserved by personality code */ + u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ + u8 RcvStnAddr; /* 1B4 Receive Station Addr */ + u8 IdleState; /* 1B5 Idle State */ + u8 IdleMonitor; /* 1B6 Idle Monitor */ + u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ + u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ + u8 StartXmitCmd; /* 1BC Start Xmit Command */ + u8 HDLCConfigReg; /* 1BD Reserved */ + u8 CauseCode; /* 1BE Cause code for fatal error */ + u8 xchar; /* 1BF High priority send */ + u32 reserved3; /* 1C0-1C3 Reserved */ + u8 PrevCmdReg; /* 1C4 Reserved */ + u8 CmdReg; /* 1C5 Command Register */ + u8 async_config2; /* 1C6 Async Config Byte 2 */ + u8 async_config3; /* 1C7 Async Config Byte 3 */ + u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ + u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ + u8 misc_flags; /* 1DD misc flags */ +#define V2_HARDWARE 0x40 +#define ICOM_HDW_ACTIVE 0x01 + u8 call_length; /* 1DE Phone #/CFI buff ln */ + u8 call_length2; /* 1DF Upper byte (unused) */ + u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ + u16 timer_value; /* 1E4-1E5 general timer value */ + u8 timer_command; /* 1E6 general timer cmd */ + u8 dce_command; /* 1E7 dce command reg */ + u8 dce_cmd_status; /* 1E8 dce command stat */ + u8 x21_r1_ioff; /* 1E9 dce ready counter */ + u8 x21_r0_ioff; /* 1EA dce not ready ctr */ + u8 x21_ralt_ioff; /* 1EB dce CNR counter */ + u8 x21_r1_ion; /* 1EC dce ready I on ctr */ + u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ + u8 ier; /* 1EE Interrupt Enable */ + u8 isr; /* 1EF Input Signal Reg */ + u8 osr; /* 1F0 Output Signal Reg */ + u8 reset; /* 1F1 Reset/Reload Reg */ + u8 disable; /* 1F2 Disable Reg */ + u8 sync; /* 1F3 Sync Reg */ + u8 error_stat; /* 1F4 Error Status */ + u8 cable_id; /* 1F5 Cable ID */ + u8 cs_length; /* 1F6 CS Load Length */ + u8 mac_length; /* 1F7 Mac Load Length */ + u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ + u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ +}; + +/* + * adapter defines and structures + */ +#define ICOM_CONTROL_START_A 0x00000008 +#define ICOM_CONTROL_STOP_A 0x00000004 +#define ICOM_CONTROL_START_B 0x00000002 +#define ICOM_CONTROL_STOP_B 0x00000001 +#define ICOM_CONTROL_START_C 0x00000008 +#define ICOM_CONTROL_STOP_C 0x00000004 +#define ICOM_CONTROL_START_D 0x00000002 +#define ICOM_CONTROL_STOP_D 0x00000001 +#define ICOM_IRAM_OFFSET 0x1000 +#define ICOM_IRAM_SIZE 0x0C00 +#define ICOM_DCE_IRAM_OFFSET 0x0A00 +#define ICOM_CABLE_ID_VALID 0x01 +#define ICOM_CABLE_ID_MASK 0xF0 +#define ICOM_DISABLE 0x80 +#define CMD_XMIT_RCV_ENABLE 0xC0 +#define CMD_XMIT_ENABLE 0x40 +#define CMD_RCV_DISABLE 0x00 +#define CMD_RCV_ENABLE 0x80 +#define CMD_RESTART 0x01 +#define CMD_HOLD_XMIT 0x02 +#define CMD_SND_BREAK 0x04 +#define RS232_CABLE 0x06 +#define V24_CABLE 0x0E +#define V35_CABLE 0x0C +#define V36_CABLE 0x02 +#define NO_CABLE 0x00 +#define START_DOWNLOAD 0x80 +#define ICOM_INT_MASK_PRC_A 0x00003FFF +#define ICOM_INT_MASK_PRC_B 0x3FFF0000 +#define ICOM_INT_MASK_PRC_C 0x00003FFF +#define ICOM_INT_MASK_PRC_D 0x3FFF0000 +#define INT_RCV_COMPLETED 0x1000 +#define INT_XMIT_COMPLETED 0x2000 +#define INT_IDLE_DETECT 0x0800 +#define INT_RCV_DISABLED 0x0400 +#define INT_XMIT_DISABLED 0x0200 +#define INT_RCV_XMIT_SHUTDOWN 0x0100 +#define INT_FATAL_ERROR 0x0080 +#define INT_CABLE_PULL 0x0020 +#define INT_SIGNAL_CHANGE 0x0010 +#define HDLC_PPP_PURE_ASYNC 0x02 +#define HDLC_FF_FILL 0x00 +#define HDLC_HDW_FLOW 0x01 +#define START_XMIT 0x80 +#define ICOM_ACFG_DRIVE1 0x20 +#define ICOM_ACFG_NO_PARITY 0x00 +#define ICOM_ACFG_PARITY_ENAB 0x02 +#define ICOM_ACFG_PARITY_ODD 0x01 +#define ICOM_ACFG_8BPC 0x00 +#define ICOM_ACFG_7BPC 0x04 +#define ICOM_ACFG_6BPC 0x08 +#define ICOM_ACFG_5BPC 0x0C +#define ICOM_ACFG_1STOP_BIT 0x00 +#define ICOM_ACFG_2STOP_BIT 0x10 +#define ICOM_DTR 0x80 +#define ICOM_RTS 0x40 +#define ICOM_RI 0x08 +#define ICOM_DSR 0x80 +#define ICOM_DCD 0x20 +#define ICOM_CTS 0x40 + +#define NUM_XBUFFS 1 +#define NUM_RBUFFS 2 +#define RCV_BUFF_SZ 0x0200 +#define XMIT_BUFF_SZ 0x1000 +struct statusArea { + /**********************************************/ + /* Transmit Status Area */ + /**********************************************/ + struct xmit_status_area{ + __le32 leNext; /* Next entry in Little Endian on Adapter */ + __le32 leNextASD; + __le32 leBuffer; /* Buffer for entry in LE for Adapter */ + __le16 leLengthASD; + __le16 leOffsetASD; + __le16 leLength; /* Length of data in segment */ + __le16 flags; +#define SA_FLAGS_DONE 0x0080 /* Done with Segment */ +#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ +#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ +#define SA_FLAGS_READY_TO_XMIT 0x0800 +#define SA_FLAGS_STAT_MASK 0x007F + } xmit[NUM_XBUFFS]; + + /**********************************************/ + /* Receive Status Area */ + /**********************************************/ + struct { + __le32 leNext; /* Next entry in Little Endian on Adapter */ + __le32 leNextASD; + __le32 leBuffer; /* Buffer for entry in LE for Adapter */ + __le16 WorkingLength; /* size of segment */ + __le16 reserv01; + __le16 leLength; /* Length of data in segment */ + __le16 flags; +#define SA_FL_RCV_DONE 0x0010 /* Data ready */ +#define SA_FLAGS_OVERRUN 0x0040 +#define SA_FLAGS_PARITY_ERROR 0x0080 +#define SA_FLAGS_FRAME_ERROR 0x0001 +#define SA_FLAGS_FRAME_TRUNC 0x0002 +#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ +#define SA_FLAGS_RCV_MASK 0xFFE6 + } rcv[NUM_RBUFFS]; +}; + +struct icom_adapter; + + +#define ICOM_MAJOR 243 +#define ICOM_MINOR_START 0 + +struct icom_port { + struct uart_port uart_port; + unsigned char cable_id; + unsigned char read_status_mask; + unsigned char ignore_status_mask; + void __iomem * int_reg; + struct icom_regs __iomem *global_reg; + struct func_dram __iomem *dram; + int port; + struct statusArea *statStg; + dma_addr_t statStg_pci; + __le32 *xmitRestart; + dma_addr_t xmitRestart_pci; + unsigned char *xmit_buf; + dma_addr_t xmit_buf_pci; + unsigned char *recv_buf; + dma_addr_t recv_buf_pci; + int next_rcv; + int status; +#define ICOM_PORT_ACTIVE 1 /* Port exists. */ +#define ICOM_PORT_OFF 0 /* Port does not exist. */ + struct icom_adapter *adapter; +}; + +struct icom_adapter { + void __iomem * base_addr; + unsigned long base_addr_pci; + struct pci_dev *pci_dev; + struct icom_port port_info[4]; + int index; + int version; +#define ADAPTER_V1 0x0001 +#define ADAPTER_V2 0x0002 + u32 subsystem_id; +#define FOUR_PORT_MODEL 0x0252 +#define V2_TWO_PORTS_RVX 0x021A +#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 + int numb_ports; + struct list_head icom_adapter_entry; + struct kref kref; +}; + +/* prototype */ +extern void iCom_sercons_init(void); + +struct lookup_proc_table { + u32 __iomem *global_control_reg; + unsigned long processor_id; +}; + +struct lookup_int_table { + u32 __iomem *global_int_mask; + unsigned long processor_id; +}; + +static inline struct icom_port *to_icom_port(struct uart_port *port) +{ + return container_of(port, struct icom_port, uart_port); +} static const struct pci_device_id icom_pci_table[] = { { @@ -118,7 +377,7 @@ MODULE_DEVICE_TABLE(pci, icom_pci_table); static LIST_HEAD(icom_adapter_head); /* spinlock for adapter initialization and changing adapter operations */ -static spinlock_t icom_lock; +static DEFINE_SPINLOCK(icom_lock); #ifdef ICOM_TRACE static inline void trace(struct icom_port *icom_port, char *trace_pt, @@ -138,24 +397,24 @@ static void free_port_memory(struct icom_port *icom_port) trace(icom_port, "RET_PORT_MEM", 0); if (icom_port->recv_buf) { - pci_free_consistent(dev, 4096, icom_port->recv_buf, - icom_port->recv_buf_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->recv_buf, + icom_port->recv_buf_pci); icom_port->recv_buf = NULL; } if (icom_port->xmit_buf) { - pci_free_consistent(dev, 4096, icom_port->xmit_buf, - icom_port->xmit_buf_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->xmit_buf, + icom_port->xmit_buf_pci); icom_port->xmit_buf = NULL; } if (icom_port->statStg) { - pci_free_consistent(dev, 4096, icom_port->statStg, - icom_port->statStg_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->statStg, + icom_port->statStg_pci); icom_port->statStg = NULL; } if (icom_port->xmitRestart) { - pci_free_consistent(dev, 4096, icom_port->xmitRestart, - icom_port->xmitRestart_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->xmitRestart, + icom_port->xmitRestart_pci); icom_port->xmitRestart = NULL; } } @@ -169,7 +428,8 @@ static int get_port_memory(struct icom_port *icom_port) struct pci_dev *dev = icom_port->adapter->pci_dev; icom_port->xmit_buf = - pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->xmit_buf_pci, + GFP_KERNEL); if (!icom_port->xmit_buf) { dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); return -ENOMEM; @@ -179,7 +439,8 @@ static int get_port_memory(struct icom_port *icom_port) (unsigned long) icom_port->xmit_buf); icom_port->recv_buf = - pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->recv_buf_pci, + GFP_KERNEL); if (!icom_port->recv_buf) { dev_err(&dev->dev, "Can not allocate Receive buffer\n"); free_port_memory(icom_port); @@ -189,7 +450,8 @@ static int get_port_memory(struct icom_port *icom_port) (unsigned long) icom_port->recv_buf); icom_port->statStg = - pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->statStg_pci, + GFP_KERNEL); if (!icom_port->statStg) { dev_err(&dev->dev, "Can not allocate Status buffer\n"); free_port_memory(icom_port); @@ -199,7 +461,8 @@ static int get_port_memory(struct icom_port *icom_port) (unsigned long) icom_port->statStg); icom_port->xmitRestart = - pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->xmitRestart_pci, + GFP_KERNEL); if (!icom_port->xmitRestart) { dev_err(&dev->dev, "Can not allocate xmit Restart buffer\n"); @@ -218,7 +481,7 @@ static int get_port_memory(struct icom_port *icom_port) if (index < (NUM_XBUFFS - 1)) { memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); icom_port->statStg->xmit[index].leLengthASD = - (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + cpu_to_le16(XMIT_BUFF_SZ); trace(icom_port, "FOD_ADDR", stgAddr); trace(icom_port, "FOD_XBUFF", (unsigned long) icom_port->xmit_buf); @@ -227,7 +490,7 @@ static int get_port_memory(struct icom_port *icom_port) } else if (index == (NUM_XBUFFS - 1)) { memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); icom_port->statStg->xmit[index].leLengthASD = - (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + cpu_to_le16(XMIT_BUFF_SZ); trace(icom_port, "FOD_XBUFF", (unsigned long) icom_port->xmit_buf); icom_port->statStg->xmit[index].leBuffer = @@ -245,7 +508,7 @@ static int get_port_memory(struct icom_port *icom_port) stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]); icom_port->statStg->rcv[index].leLength = 0; icom_port->statStg->rcv[index].WorkingLength = - (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + cpu_to_le16(RCV_BUFF_SZ); if (index < (NUM_RBUFFS - 1) ) { offset = stgAddr - (unsigned long) icom_port->statStg; icom_port->statStg->rcv[index].leNext = @@ -414,7 +677,7 @@ static void load_code(struct icom_port *icom_port) /*Set up data in icom DRAM to indicate where personality *code is located and its length. */ - new_page = pci_alloc_consistent(dev, 4096, &temp_pci); + new_page = dma_alloc_coherent(&dev->dev, 4096, &temp_pci, GFP_KERNEL); if (!new_page) { dev_err(&dev->dev, "Can not allocate DMA buffer\n"); @@ -494,10 +757,10 @@ static void load_code(struct icom_port *icom_port) } if (new_page != NULL) - pci_free_consistent(dev, 4096, new_page, temp_pci); + dma_free_coherent(&dev->dev, 4096, new_page, temp_pci); } -static int startup(struct icom_port *icom_port) +static int icom_startup(struct icom_port *icom_port) { unsigned long temp; unsigned char cable_id, raw_cable_id; @@ -569,7 +832,7 @@ unlock: return 0; } -static void shutdown(struct icom_port *icom_port) +static void icom_shutdown(struct icom_port *icom_port) { unsigned long temp; unsigned char cmdReg; @@ -613,47 +876,40 @@ unlock: static int icom_write(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); + struct tty_port *tport = &port->state->port; unsigned long data_count; unsigned char cmdReg; unsigned long offset; - int temp_tail = port->state->xmit.tail; - trace(ICOM_PORT, "WRITE", 0); + trace(icom_port, "WRITE", 0); - if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + if (le16_to_cpu(icom_port->statStg->xmit[0].flags) & SA_FLAGS_READY_TO_XMIT) { - trace(ICOM_PORT, "WRITE_FULL", 0); + trace(icom_port, "WRITE_FULL", 0); return 0; } - data_count = 0; - while ((port->state->xmit.head != temp_tail) && - (data_count <= XMIT_BUFF_SZ)) { - - ICOM_PORT->xmit_buf[data_count++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - } + data_count = kfifo_out_peek(&tport->xmit_fifo, icom_port->xmit_buf, + XMIT_BUFF_SZ); if (data_count) { - ICOM_PORT->statStg->xmit[0].flags = + icom_port->statStg->xmit[0].flags = cpu_to_le16(SA_FLAGS_READY_TO_XMIT); - ICOM_PORT->statStg->xmit[0].leLength = + icom_port->statStg->xmit[0].leLength = cpu_to_le16(data_count); offset = - (unsigned long) &ICOM_PORT->statStg->xmit[0] - - (unsigned long) ICOM_PORT->statStg; - *ICOM_PORT->xmitRestart = - cpu_to_le32(ICOM_PORT->statStg_pci + offset); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); + (unsigned long) &icom_port->statStg->xmit[0] - + (unsigned long) icom_port->statStg; + *icom_port->xmitRestart = + cpu_to_le32(icom_port->statStg_pci + offset); + cmdReg = readb(&icom_port->dram->CmdReg); writeb(cmdReg | CMD_XMIT_RCV_ENABLE, - &ICOM_PORT->dram->CmdReg); - writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd); - trace(ICOM_PORT, "WRITE_START", data_count); + &icom_port->dram->CmdReg); + writeb(START_XMIT, &icom_port->dram->StartXmitCmd); + trace(icom_port, "WRITE_START", data_count); /* write flush */ - readb(&ICOM_PORT->dram->StartXmitCmd); + readb(&icom_port->dram->StartXmitCmd); } return data_count; @@ -665,7 +921,7 @@ static inline void check_modem_status(struct icom_port *icom_port) char delta_status; unsigned char status; - spin_lock(&icom_port->uart_port.lock); + uart_port_lock(&icom_port->uart_port); /*modem input register */ status = readb(&icom_port->dram->isr); @@ -687,13 +943,13 @@ static inline void check_modem_status(struct icom_port *icom_port) port.delta_msr_wait); old_status = status; } - spin_unlock(&icom_port->uart_port.lock); + uart_port_unlock(&icom_port->uart_port); } static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) { - unsigned short int count; - int i; + struct tty_port *tport = &icom_port->uart_port.state->port; + u16 count; if (port_int_reg & (INT_XMIT_COMPLETED)) { trace(icom_port, "XMIT_COMPLETE", 0); @@ -702,17 +958,10 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) icom_port->statStg->xmit[0].flags &= cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); - count = (unsigned short int) - cpu_to_le16(icom_port->statStg->xmit[0].leLength); + count = le16_to_cpu(icom_port->statStg->xmit[0].leLength); icom_port->uart_port.icount.tx += count; - for (i=0; i<count && - !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) { - - icom_port->uart_port.state->xmit.tail++; - icom_port->uart_port.state->xmit.tail &= - (UART_XMIT_SIZE - 1); - } + kfifo_skip_count(&tport->xmit_fifo, count); if (!icom_write(&icom_port->uart_port)) /* activate write queue */ @@ -725,7 +974,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) { short int count, rcv_buff; struct tty_port *port = &icom_port->uart_port.state->port; - unsigned short int status; + u16 status; struct uart_icount *icount; unsigned long offset; unsigned char flag; @@ -733,19 +982,18 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) trace(icom_port, "RCV_COMPLETE", 0); rcv_buff = icom_port->next_rcv; - status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags); while (status & SA_FL_RCV_DONE) { int first = -1; trace(icom_port, "FID_STATUS", status); - count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); + count = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].leLength); trace(icom_port, "RCV_COUNT", count); trace(icom_port, "REAL_COUNT", count); - offset = - cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - + offset = le32_to_cpu(icom_port->statStg->rcv[rcv_buff].leBuffer) - icom_port->recv_buf_pci; /* Block copy all but the last byte as this may have status */ @@ -815,26 +1063,24 @@ ignore_char: icom_port->statStg->rcv[rcv_buff].flags = 0; icom_port->statStg->rcv[rcv_buff].leLength = 0; icom_port->statStg->rcv[rcv_buff].WorkingLength = - (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + cpu_to_le16(RCV_BUFF_SZ); rcv_buff++; if (rcv_buff == NUM_RBUFFS) rcv_buff = 0; - status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags); } icom_port->next_rcv = rcv_buff; - spin_unlock(&icom_port->uart_port.lock); tty_flip_buffer_push(port); - spin_lock(&icom_port->uart_port.lock); } static void process_interrupt(u16 port_int_reg, struct icom_port *icom_port) { - spin_lock(&icom_port->uart_port.lock); + uart_port_lock(&icom_port->uart_port); trace(icom_port, "INTERRUPT", port_int_reg); if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) @@ -843,7 +1089,7 @@ static void process_interrupt(u16 port_int_reg, if (port_int_reg & INT_RCV_COMPLETED) recv_interrupt(port_int_reg, icom_port); - spin_unlock(&icom_port->uart_port.lock); + uart_port_unlock(&icom_port->uart_port); } static irqreturn_t icom_interrupt(int irq, void *dev_id) @@ -923,54 +1169,57 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id) */ static unsigned int icom_tx_empty(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); int ret; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + uart_port_lock_irqsave(port, &flags); + if (le16_to_cpu(icom_port->statStg->xmit[0].flags) & SA_FLAGS_READY_TO_XMIT) ret = TIOCSER_TEMT; else ret = 0; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return ret; } static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct icom_port *icom_port = to_icom_port(port); unsigned char local_osr; - trace(ICOM_PORT, "SET_MODEM", 0); - local_osr = readb(&ICOM_PORT->dram->osr); + trace(icom_port, "SET_MODEM", 0); + local_osr = readb(&icom_port->dram->osr); if (mctrl & TIOCM_RTS) { - trace(ICOM_PORT, "RAISE_RTS", 0); + trace(icom_port, "RAISE_RTS", 0); local_osr |= ICOM_RTS; } else { - trace(ICOM_PORT, "LOWER_RTS", 0); + trace(icom_port, "LOWER_RTS", 0); local_osr &= ~ICOM_RTS; } if (mctrl & TIOCM_DTR) { - trace(ICOM_PORT, "RAISE_DTR", 0); + trace(icom_port, "RAISE_DTR", 0); local_osr |= ICOM_DTR; } else { - trace(ICOM_PORT, "LOWER_DTR", 0); + trace(icom_port, "LOWER_DTR", 0); local_osr &= ~ICOM_DTR; } - writeb(local_osr, &ICOM_PORT->dram->osr); + writeb(local_osr, &icom_port->dram->osr); } static unsigned int icom_get_mctrl(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); unsigned char status; unsigned int result; - trace(ICOM_PORT, "GET_MODEM", 0); + trace(icom_port, "GET_MODEM", 0); - status = readb(&ICOM_PORT->dram->isr); + status = readb(&icom_port->dram->isr); result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) | ((status & ICOM_RI) ? TIOCM_RNG : 0) @@ -981,86 +1230,92 @@ static unsigned int icom_get_mctrl(struct uart_port *port) static void icom_stop_tx(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); unsigned char cmdReg; - trace(ICOM_PORT, "STOP", 0); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); + trace(icom_port, "STOP", 0); + cmdReg = readb(&icom_port->dram->CmdReg); + writeb(cmdReg | CMD_HOLD_XMIT, &icom_port->dram->CmdReg); } static void icom_start_tx(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); unsigned char cmdReg; - trace(ICOM_PORT, "START", 0); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); + trace(icom_port, "START", 0); + cmdReg = readb(&icom_port->dram->CmdReg); if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) writeb(cmdReg & ~CMD_HOLD_XMIT, - &ICOM_PORT->dram->CmdReg); + &icom_port->dram->CmdReg); icom_write(port); } static void icom_send_xchar(struct uart_port *port, char ch) { + struct icom_port *icom_port = to_icom_port(port); unsigned char xdata; int index; unsigned long flags; - trace(ICOM_PORT, "SEND_XCHAR", ch); + trace(icom_port, "SEND_XCHAR", ch); /* wait .1 sec to send char */ for (index = 0; index < 10; index++) { - spin_lock_irqsave(&port->lock, flags); - xdata = readb(&ICOM_PORT->dram->xchar); + uart_port_lock_irqsave(port, &flags); + xdata = readb(&icom_port->dram->xchar); if (xdata == 0x00) { - trace(ICOM_PORT, "QUICK_WRITE", 0); - writeb(ch, &ICOM_PORT->dram->xchar); + trace(icom_port, "QUICK_WRITE", 0); + writeb(ch, &icom_port->dram->xchar); /* flush write operation */ - xdata = readb(&ICOM_PORT->dram->xchar); - spin_unlock_irqrestore(&port->lock, flags); + xdata = readb(&icom_port->dram->xchar); + uart_port_unlock_irqrestore(port, flags); break; } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); msleep(10); } } static void icom_stop_rx(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); unsigned char cmdReg; - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); + cmdReg = readb(&icom_port->dram->CmdReg); + writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg); } static void icom_break(struct uart_port *port, int break_state) { + struct icom_port *icom_port = to_icom_port(port); unsigned char cmdReg; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - trace(ICOM_PORT, "BREAK", 0); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); + uart_port_lock_irqsave(port, &flags); + trace(icom_port, "BREAK", 0); + cmdReg = readb(&icom_port->dram->CmdReg); if (break_state == -1) { - writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_SND_BREAK, &icom_port->dram->CmdReg); } else { - writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int icom_open(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); int retval; - kref_get(&ICOM_PORT->adapter->kref); - retval = startup(ICOM_PORT); + kref_get(&icom_port->adapter->kref); + retval = icom_startup(icom_port); if (retval) { - kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); - trace(ICOM_PORT, "STARTUP_ERROR", 0); + kref_put(&icom_port->adapter->kref, icom_kref_release); + trace(icom_port, "STARTUP_ERROR", 0); return retval; } @@ -1069,23 +1324,24 @@ static int icom_open(struct uart_port *port) static void icom_close(struct uart_port *port) { + struct icom_port *icom_port = to_icom_port(port); unsigned char cmdReg; - trace(ICOM_PORT, "CLOSE", 0); + trace(icom_port, "CLOSE", 0); /* stop receiver */ - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); + cmdReg = readb(&icom_port->dram->CmdReg); + writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg); - shutdown(ICOM_PORT); + icom_shutdown(icom_port); - kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); + kref_put(&icom_port->adapter->kref, icom_kref_release); } -static void icom_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old_termios) +static void icom_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old_termios) { + struct icom_port *icom_port = to_icom_port(port); int baud; unsigned cflag, iflag; char new_config2; @@ -1096,8 +1352,8 @@ static void icom_set_termios(struct uart_port *port, unsigned long offset; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - trace(ICOM_PORT, "CHANGE_SPEED", 0); + uart_port_lock_irqsave(port, &flags); + trace(icom_port, "CHANGE_SPEED", 0); cflag = termios->c_cflag; iflag = termios->c_iflag; @@ -1128,12 +1384,12 @@ static void icom_set_termios(struct uart_port *port, if (cflag & PARENB) { /* parity bit enabled */ new_config2 |= ICOM_ACFG_PARITY_ENAB; - trace(ICOM_PORT, "PARENB", 0); + trace(icom_port, "PARENB", 0); } if (cflag & PARODD) { /* odd parity */ new_config2 |= ICOM_ACFG_PARITY_ODD; - trace(ICOM_PORT, "PARODD", 0); + trace(icom_port, "PARODD", 0); } /* Determine divisor based on baud rate */ @@ -1153,102 +1409,101 @@ static void icom_set_termios(struct uart_port *port, uart_update_timeout(port, cflag, baud); /* CTS flow control flag and modem status interrupts */ - tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + tmp_byte = readb(&(icom_port->dram->HDLCConfigReg)); if (cflag & CRTSCTS) tmp_byte |= HDLC_HDW_FLOW; else tmp_byte &= ~HDLC_HDW_FLOW; - writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg)); /* * Set up parity check flag */ - ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; + icom_port->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; if (iflag & INPCK) - ICOM_PORT->read_status_mask |= + icom_port->read_status_mask |= SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR; if ((iflag & BRKINT) || (iflag & PARMRK)) - ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET; + icom_port->read_status_mask |= SA_FLAGS_BREAK_DET; /* * Characters to ignore */ - ICOM_PORT->ignore_status_mask = 0; + icom_port->ignore_status_mask = 0; if (iflag & IGNPAR) - ICOM_PORT->ignore_status_mask |= + icom_port->ignore_status_mask |= SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR; if (iflag & IGNBRK) { - ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET; + icom_port->ignore_status_mask |= SA_FLAGS_BREAK_DET; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ if (iflag & IGNPAR) - ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN; + icom_port->ignore_status_mask |= SA_FLAGS_OVERRUN; } /* * !!! ignore all characters if CREAD is not set */ if ((cflag & CREAD) == 0) - ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE; + icom_port->ignore_status_mask |= SA_FL_RCV_DONE; /* Turn off Receiver to prepare for reset */ - writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg); + writeb(CMD_RCV_DISABLE, &icom_port->dram->CmdReg); for (index = 0; index < 10; index++) { - if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) { + if (readb(&icom_port->dram->PrevCmdReg) == 0x00) { break; } } /* clear all current buffers of data */ for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) { - ICOM_PORT->statStg->rcv[rcv_buff].flags = 0; - ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0; - ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength = - (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + icom_port->statStg->rcv[rcv_buff].flags = 0; + icom_port->statStg->rcv[rcv_buff].leLength = 0; + icom_port->statStg->rcv[rcv_buff].WorkingLength = + cpu_to_le16(RCV_BUFF_SZ); } for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) { - ICOM_PORT->statStg->xmit[xmit_buff].flags = 0; + icom_port->statStg->xmit[xmit_buff].flags = 0; } /* activate changes and start xmit and receiver here */ /* Enable the receiver */ - writeb(new_config3, &(ICOM_PORT->dram->async_config3)); - writeb(new_config2, &(ICOM_PORT->dram->async_config2)); - tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + writeb(new_config3, &(icom_port->dram->async_config3)); + writeb(new_config2, &(icom_port->dram->async_config2)); + tmp_byte = readb(&(icom_port->dram->HDLCConfigReg)); tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL; - writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); - writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */ - writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */ + writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg)); + writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0xFF, &(icom_port->dram->ier)); /* enable modem signal interrupts */ /* reset processor */ - writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg); + writeb(CMD_RESTART, &icom_port->dram->CmdReg); for (index = 0; index < 10; index++) { - if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) { + if (readb(&icom_port->dram->CmdReg) == 0x00) { break; } } /* Enable Transmitter and Receiver */ offset = - (unsigned long) &ICOM_PORT->statStg->rcv[0] - - (unsigned long) ICOM_PORT->statStg; - writel(ICOM_PORT->statStg_pci + offset, - &ICOM_PORT->dram->RcvStatusAddr); - ICOM_PORT->next_rcv = 0; - ICOM_PORT->put_length = 0; - *ICOM_PORT->xmitRestart = 0; - writel(ICOM_PORT->xmitRestart_pci, - &ICOM_PORT->dram->XmitStatusAddr); - trace(ICOM_PORT, "XR_ENAB", 0); - writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); - - spin_unlock_irqrestore(&port->lock, flags); + (unsigned long) &icom_port->statStg->rcv[0] - + (unsigned long) icom_port->statStg; + writel(icom_port->statStg_pci + offset, + &icom_port->dram->RcvStatusAddr); + icom_port->next_rcv = 0; + *icom_port->xmitRestart = 0; + writel(icom_port->xmitRestart_pci, + &icom_port->dram->XmitStatusAddr); + trace(icom_port, "XR_ENAB", 0); + writeb(CMD_XMIT_RCV_ENABLE, &icom_port->dram->CmdReg); + + uart_port_unlock_irqrestore(port, flags); } static const char *icom_type(struct uart_port *port) @@ -1256,15 +1511,6 @@ static const char *icom_type(struct uart_port *port) return "icom"; } -static void icom_release_port(struct uart_port *port) -{ -} - -static int icom_request_port(struct uart_port *port) -{ - return 0; -} - static void icom_config_port(struct uart_port *port, int flags) { port->type = PORT_ICOM; @@ -1283,8 +1529,6 @@ static const struct uart_ops icom_ops = { .shutdown = icom_close, .set_termios = icom_set_termios, .type = icom_type, - .release_port = icom_release_port, - .request_port = icom_request_port, .config_port = icom_config_port, }; @@ -1313,7 +1557,6 @@ static int icom_init_ports(struct icom_adapter *icom_adapter) icom_port = &icom_adapter->port_info[i]; icom_port->port = i; icom_port->status = ICOM_PORT_ACTIVE; - icom_port->imbed_modem = ICOM_UNKNOWN; } } else { if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) { @@ -1324,26 +1567,15 @@ static int icom_init_ports(struct icom_adapter *icom_adapter) icom_port->port = i; icom_port->status = ICOM_PORT_ACTIVE; - icom_port->imbed_modem = ICOM_IMBED_MODEM; } } else { icom_adapter->numb_ports = 4; icom_adapter->port_info[0].port = 0; icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE; - - if (subsystem_id == - PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) { - icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM; - } else { - icom_adapter->port_info[0].imbed_modem = ICOM_RVX; - } - icom_adapter->port_info[1].status = ICOM_PORT_OFF; - icom_adapter->port_info[2].port = 2; icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE; - icom_adapter->port_info[2].imbed_modem = ICOM_RVX; icom_adapter->port_info[3].status = ICOM_PORT_OFF; } } @@ -1399,7 +1631,6 @@ static int icom_alloc_adapter(struct icom_adapter int adapter_count = 0; struct icom_adapter *icom_adapter; struct icom_adapter *cur_adapter_entry; - struct list_head *tmp; icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL); @@ -1407,10 +1638,8 @@ static int icom_alloc_adapter(struct icom_adapter return -ENOMEM; } - list_for_each(tmp, &icom_adapter_head) { - cur_adapter_entry = - list_entry(tmp, struct icom_adapter, - icom_adapter_entry); + list_for_each_entry(cur_adapter_entry, &icom_adapter_head, + icom_adapter_entry) { if (cur_adapter_entry->index != adapter_count) { break; } @@ -1418,7 +1647,8 @@ static int icom_alloc_adapter(struct icom_adapter } icom_adapter->index = adapter_count; - list_add_tail(&icom_adapter->icom_adapter_entry, tmp); + list_add_tail(&icom_adapter->icom_adapter_entry, + &cur_adapter_entry->icom_adapter_entry); *icom_adapter_ref = icom_adapter; return 0; @@ -1430,8 +1660,10 @@ static void icom_free_adapter(struct icom_adapter *icom_adapter) kfree(icom_adapter); } -static void icom_remove_adapter(struct icom_adapter *icom_adapter) +static void icom_kref_release(struct kref *kref) { + struct icom_adapter *icom_adapter = container_of(kref, + struct icom_adapter, kref); struct icom_port *icom_port; int index; @@ -1464,14 +1696,6 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) icom_free_adapter(icom_adapter); } -static void icom_kref_release(struct kref *kref) -{ - struct icom_adapter *icom_adapter; - - icom_adapter = to_icom_adapter(kref); - icom_remove_adapter(icom_adapter); -} - static int icom_probe(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -1499,7 +1723,8 @@ static int icom_probe(struct pci_dev *dev, retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg); if (retval) { dev_err(&dev->dev, "PCI Config read FAILED\n"); - return retval; + retval = pcibios_err_to_errno(retval); + goto probe_exit0; } pci_write_config_dword(dev, PCI_COMMAND, @@ -1540,11 +1765,10 @@ static int icom_probe(struct pci_dev *dev, goto probe_exit1; } - /* save off irq and request irq line */ - retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter); - if (retval) { - goto probe_exit2; - } + /* save off irq and request irq line */ + retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, icom_adapter); + if (retval) + goto probe_exit2; retval = icom_load_ports(icom_adapter); @@ -1587,11 +1811,9 @@ probe_exit0: static void icom_remove(struct pci_dev *dev) { struct icom_adapter *icom_adapter; - struct list_head *tmp; - list_for_each(tmp, &icom_adapter_head) { - icom_adapter = list_entry(tmp, struct icom_adapter, - icom_adapter_entry); + list_for_each_entry(icom_adapter, &icom_adapter_head, + icom_adapter_entry) { if (icom_adapter->pci_dev == dev) { kref_put(&icom_adapter->kref, icom_kref_release); return; @@ -1612,8 +1834,6 @@ static int __init icom_init(void) { int ret; - spin_lock_init(&icom_lock); - ret = uart_register_driver(&icom_uart_driver); if (ret) return ret; @@ -1637,8 +1857,6 @@ module_exit(icom_exit); MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); -MODULE_SUPPORTED_DEVICE - ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("icom_call_setup.bin"); MODULE_FIRMWARE("icom_res_dce.bin"); diff --git a/drivers/tty/serial/icom.h b/drivers/tty/serial/icom.h deleted file mode 100644 index 26e3aa7b01e2..000000000000 --- a/drivers/tty/serial/icom.h +++ /dev/null @@ -1,274 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * icom.h - * - * Copyright (C) 2001 Michael Anderson, IBM Corporation - * - * Serial device driver include file. - */ - -#include <linux/serial_core.h> - -#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1) -static int icom_acfg_baud[] = { - 300, - 600, - 900, - 1200, - 1800, - 2400, - 3600, - 4800, - 7200, - 9600, - 14400, - 19200, - 28800, - 38400, - 57600, - 76800, - 115200, - 153600, - 230400, - 307200, - 460800, -}; - -struct icom_regs { - u32 control; /* Adapter Control Register */ - u32 interrupt; /* Adapter Interrupt Register */ - u32 int_mask; /* Adapter Interrupt Mask Reg */ - u32 int_pri; /* Adapter Interrupt Priority r */ - u32 int_reg_b; /* Adapter non-masked Interrupt */ - u32 resvd01; - u32 resvd02; - u32 resvd03; - u32 control_2; /* Adapter Control Register 2 */ - u32 interrupt_2; /* Adapter Interrupt Register 2 */ - u32 int_mask_2; /* Adapter Interrupt Mask 2 */ - u32 int_pri_2; /* Adapter Interrupt Prior 2 */ - u32 int_reg_2b; /* Adapter non-masked 2 */ -}; - -struct func_dram { - u32 reserved[108]; /* 0-1B0 reserved by personality code */ - u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ - u8 RcvStnAddr; /* 1B4 Receive Station Addr */ - u8 IdleState; /* 1B5 Idle State */ - u8 IdleMonitor; /* 1B6 Idle Monitor */ - u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ - u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ - u8 StartXmitCmd; /* 1BC Start Xmit Command */ - u8 HDLCConfigReg; /* 1BD Reserved */ - u8 CauseCode; /* 1BE Cause code for fatal error */ - u8 xchar; /* 1BF High priority send */ - u32 reserved3; /* 1C0-1C3 Reserved */ - u8 PrevCmdReg; /* 1C4 Reserved */ - u8 CmdReg; /* 1C5 Command Register */ - u8 async_config2; /* 1C6 Async Config Byte 2 */ - u8 async_config3; /* 1C7 Async Config Byte 3 */ - u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ - u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ - u8 misc_flags; /* 1DD misc flags */ -#define V2_HARDWARE 0x40 -#define ICOM_HDW_ACTIVE 0x01 - u8 call_length; /* 1DE Phone #/CFI buff ln */ - u8 call_length2; /* 1DF Upper byte (unused) */ - u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ - u16 timer_value; /* 1E4-1E5 general timer value */ - u8 timer_command; /* 1E6 general timer cmd */ - u8 dce_command; /* 1E7 dce command reg */ - u8 dce_cmd_status; /* 1E8 dce command stat */ - u8 x21_r1_ioff; /* 1E9 dce ready counter */ - u8 x21_r0_ioff; /* 1EA dce not ready ctr */ - u8 x21_ralt_ioff; /* 1EB dce CNR counter */ - u8 x21_r1_ion; /* 1EC dce ready I on ctr */ - u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ - u8 ier; /* 1EE Interrupt Enable */ - u8 isr; /* 1EF Input Signal Reg */ - u8 osr; /* 1F0 Output Signal Reg */ - u8 reset; /* 1F1 Reset/Reload Reg */ - u8 disable; /* 1F2 Disable Reg */ - u8 sync; /* 1F3 Sync Reg */ - u8 error_stat; /* 1F4 Error Status */ - u8 cable_id; /* 1F5 Cable ID */ - u8 cs_length; /* 1F6 CS Load Length */ - u8 mac_length; /* 1F7 Mac Load Length */ - u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ - u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ -}; - -/* - * adapter defines and structures - */ -#define ICOM_CONTROL_START_A 0x00000008 -#define ICOM_CONTROL_STOP_A 0x00000004 -#define ICOM_CONTROL_START_B 0x00000002 -#define ICOM_CONTROL_STOP_B 0x00000001 -#define ICOM_CONTROL_START_C 0x00000008 -#define ICOM_CONTROL_STOP_C 0x00000004 -#define ICOM_CONTROL_START_D 0x00000002 -#define ICOM_CONTROL_STOP_D 0x00000001 -#define ICOM_IRAM_OFFSET 0x1000 -#define ICOM_IRAM_SIZE 0x0C00 -#define ICOM_DCE_IRAM_OFFSET 0x0A00 -#define ICOM_CABLE_ID_VALID 0x01 -#define ICOM_CABLE_ID_MASK 0xF0 -#define ICOM_DISABLE 0x80 -#define CMD_XMIT_RCV_ENABLE 0xC0 -#define CMD_XMIT_ENABLE 0x40 -#define CMD_RCV_DISABLE 0x00 -#define CMD_RCV_ENABLE 0x80 -#define CMD_RESTART 0x01 -#define CMD_HOLD_XMIT 0x02 -#define CMD_SND_BREAK 0x04 -#define RS232_CABLE 0x06 -#define V24_CABLE 0x0E -#define V35_CABLE 0x0C -#define V36_CABLE 0x02 -#define NO_CABLE 0x00 -#define START_DOWNLOAD 0x80 -#define ICOM_INT_MASK_PRC_A 0x00003FFF -#define ICOM_INT_MASK_PRC_B 0x3FFF0000 -#define ICOM_INT_MASK_PRC_C 0x00003FFF -#define ICOM_INT_MASK_PRC_D 0x3FFF0000 -#define INT_RCV_COMPLETED 0x1000 -#define INT_XMIT_COMPLETED 0x2000 -#define INT_IDLE_DETECT 0x0800 -#define INT_RCV_DISABLED 0x0400 -#define INT_XMIT_DISABLED 0x0200 -#define INT_RCV_XMIT_SHUTDOWN 0x0100 -#define INT_FATAL_ERROR 0x0080 -#define INT_CABLE_PULL 0x0020 -#define INT_SIGNAL_CHANGE 0x0010 -#define HDLC_PPP_PURE_ASYNC 0x02 -#define HDLC_FF_FILL 0x00 -#define HDLC_HDW_FLOW 0x01 -#define START_XMIT 0x80 -#define ICOM_ACFG_DRIVE1 0x20 -#define ICOM_ACFG_NO_PARITY 0x00 -#define ICOM_ACFG_PARITY_ENAB 0x02 -#define ICOM_ACFG_PARITY_ODD 0x01 -#define ICOM_ACFG_8BPC 0x00 -#define ICOM_ACFG_7BPC 0x04 -#define ICOM_ACFG_6BPC 0x08 -#define ICOM_ACFG_5BPC 0x0C -#define ICOM_ACFG_1STOP_BIT 0x00 -#define ICOM_ACFG_2STOP_BIT 0x10 -#define ICOM_DTR 0x80 -#define ICOM_RTS 0x40 -#define ICOM_RI 0x08 -#define ICOM_DSR 0x80 -#define ICOM_DCD 0x20 -#define ICOM_CTS 0x40 - -#define NUM_XBUFFS 1 -#define NUM_RBUFFS 2 -#define RCV_BUFF_SZ 0x0200 -#define XMIT_BUFF_SZ 0x1000 -struct statusArea { - /**********************************************/ - /* Transmit Status Area */ - /**********************************************/ - struct xmit_status_area{ - u32 leNext; /* Next entry in Little Endian on Adapter */ - u32 leNextASD; - u32 leBuffer; /* Buffer for entry in LE for Adapter */ - u16 leLengthASD; - u16 leOffsetASD; - u16 leLength; /* Length of data in segment */ - u16 flags; -#define SA_FLAGS_DONE 0x0080 /* Done with Segment */ -#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ -#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ -#define SA_FLAGS_READY_TO_XMIT 0x0800 -#define SA_FLAGS_STAT_MASK 0x007F - } xmit[NUM_XBUFFS]; - - /**********************************************/ - /* Receive Status Area */ - /**********************************************/ - struct { - u32 leNext; /* Next entry in Little Endian on Adapter */ - u32 leNextASD; - u32 leBuffer; /* Buffer for entry in LE for Adapter */ - u16 WorkingLength; /* size of segment */ - u16 reserv01; - u16 leLength; /* Length of data in segment */ - u16 flags; -#define SA_FL_RCV_DONE 0x0010 /* Data ready */ -#define SA_FLAGS_OVERRUN 0x0040 -#define SA_FLAGS_PARITY_ERROR 0x0080 -#define SA_FLAGS_FRAME_ERROR 0x0001 -#define SA_FLAGS_FRAME_TRUNC 0x0002 -#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ -#define SA_FLAGS_RCV_MASK 0xFFE6 - } rcv[NUM_RBUFFS]; -}; - -struct icom_adapter; - - -#define ICOM_MAJOR 243 -#define ICOM_MINOR_START 0 - -struct icom_port { - struct uart_port uart_port; - u8 imbed_modem; -#define ICOM_UNKNOWN 1 -#define ICOM_RVX 2 -#define ICOM_IMBED_MODEM 3 - unsigned char cable_id; - unsigned char read_status_mask; - unsigned char ignore_status_mask; - void __iomem * int_reg; - struct icom_regs __iomem *global_reg; - struct func_dram __iomem *dram; - int port; - struct statusArea *statStg; - dma_addr_t statStg_pci; - u32 *xmitRestart; - dma_addr_t xmitRestart_pci; - unsigned char *xmit_buf; - dma_addr_t xmit_buf_pci; - unsigned char *recv_buf; - dma_addr_t recv_buf_pci; - int next_rcv; - int put_length; - int status; -#define ICOM_PORT_ACTIVE 1 /* Port exists. */ -#define ICOM_PORT_OFF 0 /* Port does not exist. */ - int load_in_progress; - struct icom_adapter *adapter; -}; - -struct icom_adapter { - void __iomem * base_addr; - unsigned long base_addr_pci; - struct pci_dev *pci_dev; - struct icom_port port_info[4]; - int index; - int version; -#define ADAPTER_V1 0x0001 -#define ADAPTER_V2 0x0002 - u32 subsystem_id; -#define FOUR_PORT_MODEL 0x0252 -#define V2_TWO_PORTS_RVX 0x021A -#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 - int numb_ports; - struct list_head icom_adapter_entry; - struct kref kref; -}; - -/* prototype */ -extern void iCom_sercons_init(void); - -struct lookup_proc_table { - u32 __iomem *global_control_reg; - unsigned long processor_id; -}; - -struct lookup_int_table { - u32 __iomem *global_int_mask; - unsigned long processor_id; -}; diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c deleted file mode 100644 index 7d16fe41932f..000000000000 --- a/drivers/tty/serial/ifx6x60.c +++ /dev/null @@ -1,1390 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/**************************************************************************** - * - * Driver for the IFX 6x60 spi modem. - * - * Copyright (C) 2008 Option International - * Copyright (C) 2008 Filip Aben <f.aben@option.com> - * Denis Joseph Barrow <d.barow@option.com> - * Jan Dumon <j.dumon@option.com> - * - * Copyright (C) 2009, 2010 Intel Corp - * Russ Gorby <russ.gorby@intel.com> - * - * Driver modified by Intel from Option gtm501l_spi.c - * - * Notes - * o The driver currently assumes a single device only. If you need to - * change this then look for saved_ifx_dev and add a device lookup - * o The driver is intended to be big-endian safe but has never been - * tested that way (no suitable hardware). There are a couple of FIXME - * notes by areas that may need addressing - * o Some of the GPIO naming/setup assumptions may need revisiting if - * you need to use this driver for another platform. - * - *****************************************************************************/ -#include <linux/dma-mapping.h> -#include <linux/module.h> -#include <linux/termios.h> -#include <linux/tty.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/kfifo.h> -#include <linux/tty_flip.h> -#include <linux/timer.h> -#include <linux/serial.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/rfkill.h> -#include <linux/fs.h> -#include <linux/ip.h> -#include <linux/dmapool.h> -#include <linux/gpio/consumer.h> -#include <linux/sched.h> -#include <linux/time.h> -#include <linux/wait.h> -#include <linux/pm.h> -#include <linux/pm_runtime.h> -#include <linux/spi/ifx_modem.h> -#include <linux/delay.h> -#include <linux/reboot.h> - -#include "ifx6x60.h" - -#define IFX_SPI_MORE_MASK 0x10 -#define IFX_SPI_MORE_BIT 4 /* bit position in u8 */ -#define IFX_SPI_CTS_BIT 6 /* bit position in u8 */ -#define IFX_SPI_MODE SPI_MODE_1 -#define IFX_SPI_TTY_ID 0 -#define IFX_SPI_TIMEOUT_SEC 2 -#define IFX_SPI_HEADER_0 (-1) -#define IFX_SPI_HEADER_F (-2) - -#define PO_POST_DELAY 200 - -/* forward reference */ -static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); -static int ifx_modem_reboot_callback(struct notifier_block *nfb, - unsigned long event, void *data); -static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev); - -/* local variables */ -static int spi_bpw = 16; /* 8, 16 or 32 bit word length */ -static struct tty_driver *tty_drv; -static struct ifx_spi_device *saved_ifx_dev; -static struct lock_class_key ifx_spi_key; - -static struct notifier_block ifx_modem_reboot_notifier_block = { - .notifier_call = ifx_modem_reboot_callback, -}; - -static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev) -{ - gpiod_set_value(ifx_dev->gpio.pmu_reset, 1); - msleep(PO_POST_DELAY); - - return 0; -} - -static int ifx_modem_reboot_callback(struct notifier_block *nfb, - unsigned long event, void *data) -{ - if (saved_ifx_dev) - ifx_modem_power_off(saved_ifx_dev); - else - pr_warn("no ifx modem active;\n"); - - return NOTIFY_OK; -} - -/* GPIO/GPE settings */ - -/** - * mrdy_set_high - set MRDY GPIO - * @ifx: device we are controlling - * - */ -static inline void mrdy_set_high(struct ifx_spi_device *ifx) -{ - gpiod_set_value(ifx->gpio.mrdy, 1); -} - -/** - * mrdy_set_low - clear MRDY GPIO - * @ifx: device we are controlling - * - */ -static inline void mrdy_set_low(struct ifx_spi_device *ifx) -{ - gpiod_set_value(ifx->gpio.mrdy, 0); -} - -/** - * ifx_spi_power_state_set - * @ifx_dev: our SPI device - * @val: bits to set - * - * Set bit in power status and signal power system if status becomes non-0 - */ -static void -ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&ifx_dev->power_lock, flags); - - /* - * if power status is already non-0, just update, else - * tell power system - */ - if (!ifx_dev->power_status) - pm_runtime_get(&ifx_dev->spi_dev->dev); - ifx_dev->power_status |= val; - - spin_unlock_irqrestore(&ifx_dev->power_lock, flags); -} - -/** - * ifx_spi_power_state_clear - clear power bit - * @ifx_dev: our SPI device - * @val: bits to clear - * - * clear bit in power status and signal power system if status becomes 0 - */ -static void -ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&ifx_dev->power_lock, flags); - - if (ifx_dev->power_status) { - ifx_dev->power_status &= ~val; - if (!ifx_dev->power_status) - pm_runtime_put(&ifx_dev->spi_dev->dev); - } - - spin_unlock_irqrestore(&ifx_dev->power_lock, flags); -} - -/** - * swap_buf_8 - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf_8(unsigned char *buf, int len, void *end) -{ - /* don't swap buffer if SPI word width is 8 bits */ - return; -} - -/** - * swap_buf_16 - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf_16(unsigned char *buf, int len, void *end) -{ - int n; - - u16 *buf_16 = (u16 *)buf; - len = ((len + 1) >> 1); - if ((void *)&buf_16[len] > end) { - pr_err("swap_buf_16: swap exceeds boundary (%p > %p)!", - &buf_16[len], end); - return; - } - for (n = 0; n < len; n++) { - *buf_16 = cpu_to_be16(*buf_16); - buf_16++; - } -} - -/** - * swap_buf_32 - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf_32(unsigned char *buf, int len, void *end) -{ - int n; - - u32 *buf_32 = (u32 *)buf; - len = (len + 3) >> 2; - - if ((void *)&buf_32[len] > end) { - pr_err("swap_buf_32: swap exceeds boundary (%p > %p)!\n", - &buf_32[len], end); - return; - } - for (n = 0; n < len; n++) { - *buf_32 = cpu_to_be32(*buf_32); - buf_32++; - } -} - -/** - * mrdy_assert - assert MRDY line - * @ifx_dev: our SPI device - * - * Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low - * now. - * - * FIXME: Can SRDY even go high as we are running this code ? - */ -static void mrdy_assert(struct ifx_spi_device *ifx_dev) -{ - int val = gpiod_get_value(ifx_dev->gpio.srdy); - if (!val) { - if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING, - &ifx_dev->flags)) { - mod_timer(&ifx_dev->spi_timer,jiffies + IFX_SPI_TIMEOUT_SEC*HZ); - - } - } - ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING); - mrdy_set_high(ifx_dev); -} - -/** - * ifx_spi_timeout - SPI timeout - * @arg: our SPI device - * - * The SPI has timed out: hang up the tty. Users will then see a hangup - * and error events. - */ -static void ifx_spi_timeout(struct timer_list *t) -{ - struct ifx_spi_device *ifx_dev = from_timer(ifx_dev, t, spi_timer); - - dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***"); - tty_port_tty_hangup(&ifx_dev->tty_port, false); - mrdy_set_low(ifx_dev); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); -} - -/* char/tty operations */ - -/** - * ifx_spi_tiocmget - get modem lines - * @tty: our tty device - * @filp: file handle issuing the request - * - * Map the signal state into Linux modem flags and report the value - * in Linux terms - */ -static int ifx_spi_tiocmget(struct tty_struct *tty) -{ - unsigned int value; - struct ifx_spi_device *ifx_dev = tty->driver_data; - - value = - (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) | - (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) | - (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) | - (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) | - (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) | - (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0); - return value; -} - -/** - * ifx_spi_tiocmset - set modem bits - * @tty: the tty structure - * @set: bits to set - * @clear: bits to clear - * - * The IFX6x60 only supports DTR and RTS. Set them accordingly - * and flag that an update to the modem is needed. - * - * FIXME: do we need to kick the tranfers when we do this ? - */ -static int ifx_spi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - - if (set & TIOCM_RTS) - set_bit(IFX_SPI_RTS, &ifx_dev->signal_state); - if (set & TIOCM_DTR) - set_bit(IFX_SPI_DTR, &ifx_dev->signal_state); - if (clear & TIOCM_RTS) - clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state); - if (clear & TIOCM_DTR) - clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state); - - set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state); - return 0; -} - -/** - * ifx_spi_open - called on tty open - * @tty: our tty device - * @filp: file handle being associated with the tty - * - * Open the tty interface. We let the tty_port layer do all the work - * for us. - * - * FIXME: Remove single device assumption and saved_ifx_dev - */ -static int ifx_spi_open(struct tty_struct *tty, struct file *filp) -{ - return tty_port_open(&saved_ifx_dev->tty_port, tty, filp); -} - -/** - * ifx_spi_close - called when our tty closes - * @tty: the tty being closed - * @filp: the file handle being closed - * - * Perform the close of the tty. We use the tty_port layer to do all - * our hard work. - */ -static void ifx_spi_close(struct tty_struct *tty, struct file *filp) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - tty_port_close(&ifx_dev->tty_port, tty, filp); - /* FIXME: should we do an ifx_spi_reset here ? */ -} - -/** - * ifx_decode_spi_header - decode received header - * @buffer: the received data - * @length: decoded length - * @more: decoded more flag - * @received_cts: status of cts we received - * - * Note how received_cts is handled -- if header is all F it is left - * the same as it was, if header is all 0 it is set to 0 otherwise it is - * taken from the incoming header. - * - * FIXME: endianness - */ -static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length, - unsigned char *more, unsigned char *received_cts) -{ - u16 h1; - u16 h2; - u16 *in_buffer = (u16 *)buffer; - - h1 = *in_buffer; - h2 = *(in_buffer+1); - - if (h1 == 0 && h2 == 0) { - *received_cts = 0; - *more = 0; - return IFX_SPI_HEADER_0; - } else if (h1 == 0xffff && h2 == 0xffff) { - *more = 0; - /* spi_slave_cts remains as it was */ - return IFX_SPI_HEADER_F; - } - - *length = h1 & 0xfff; /* upper bits of byte are flags */ - *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1; - *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1; - return 0; -} - -/** - * ifx_setup_spi_header - set header fields - * @txbuffer: pointer to start of SPI buffer - * @tx_count: bytes - * @more: indicate if more to follow - * - * Format up an SPI header for a transfer - * - * FIXME: endianness? - */ -static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count, - unsigned char more) -{ - *(u16 *)(txbuffer) = tx_count; - *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE; - txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK; -} - -/** - * ifx_spi_prepare_tx_buffer - prepare transmit frame - * @ifx_dev: our SPI device - * - * The transmit buffr needs a header and various other bits of - * information followed by as much data as we can pull from the FIFO - * and transfer. This function formats up a suitable buffer in the - * ifx_dev->tx_buffer - * - * FIXME: performance - should we wake the tty when the queue is half - * empty ? - */ -static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev) -{ - int temp_count; - int queue_length; - int tx_count; - unsigned char *tx_buffer; - - tx_buffer = ifx_dev->tx_buffer; - - /* make room for required SPI header */ - tx_buffer += IFX_SPI_HEADER_OVERHEAD; - tx_count = IFX_SPI_HEADER_OVERHEAD; - - /* clear to signal no more data if this turns out to be the - * last buffer sent in a sequence */ - ifx_dev->spi_more = 0; - - /* if modem cts is set, just send empty buffer */ - if (!ifx_dev->spi_slave_cts) { - /* see if there's tx data */ - queue_length = kfifo_len(&ifx_dev->tx_fifo); - if (queue_length != 0) { - /* data to mux -- see if there's room for it */ - temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE); - temp_count = kfifo_out_locked(&ifx_dev->tx_fifo, - tx_buffer, temp_count, - &ifx_dev->fifo_lock); - - /* update buffer pointer and data count in message */ - tx_buffer += temp_count; - tx_count += temp_count; - if (temp_count == queue_length) - /* poke port to get more data */ - tty_port_tty_wakeup(&ifx_dev->tty_port); - else /* more data in port, use next SPI message */ - ifx_dev->spi_more = 1; - } - } - /* have data and info for header -- set up SPI header in buffer */ - /* spi header needs payload size, not entire buffer size */ - ifx_spi_setup_spi_header(ifx_dev->tx_buffer, - tx_count-IFX_SPI_HEADER_OVERHEAD, - ifx_dev->spi_more); - /* swap actual data in the buffer */ - ifx_dev->swap_buf((ifx_dev->tx_buffer), tx_count, - &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]); - return tx_count; -} - -/** - * ifx_spi_write - line discipline write - * @tty: our tty device - * @buf: pointer to buffer to write (kernel space) - * @count: size of buffer - * - * Write the characters we have been given into the FIFO. If the device - * is not active then activate it, when the SRDY line is asserted back - * this will commence I/O - */ -static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - unsigned char *tmp_buf = (unsigned char *)buf; - unsigned long flags; - bool is_fifo_empty; - int tx_count; - - spin_lock_irqsave(&ifx_dev->fifo_lock, flags); - is_fifo_empty = kfifo_is_empty(&ifx_dev->tx_fifo); - tx_count = kfifo_in(&ifx_dev->tx_fifo, tmp_buf, count); - spin_unlock_irqrestore(&ifx_dev->fifo_lock, flags); - if (is_fifo_empty) - mrdy_assert(ifx_dev); - - return tx_count; -} - -/** - * ifx_spi_chars_in_buffer - line discipline helper - * @tty: our tty device - * - * Report how much data we can accept before we drop bytes. As we use - * a simple FIFO this is nice and easy. - */ -static int ifx_spi_write_room(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo); -} - -/** - * ifx_spi_chars_in_buffer - line discipline helper - * @tty: our tty device - * - * Report how many characters we have buffered. In our case this is the - * number of bytes sitting in our transmit FIFO. - */ -static int ifx_spi_chars_in_buffer(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - return kfifo_len(&ifx_dev->tx_fifo); -} - -/** - * ifx_port_hangup - * @port: our tty port - * - * tty port hang up. Called when tty_hangup processing is invoked either - * by loss of carrier, or by software (eg vhangup). Serialized against - * activate/shutdown by the tty layer. - */ -static void ifx_spi_hangup(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - tty_port_hangup(&ifx_dev->tty_port); -} - -/** - * ifx_port_activate - * @port: our tty port - * - * tty port activate method - called for first open. Serialized - * with hangup and shutdown by the tty layer. - */ -static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = - container_of(port, struct ifx_spi_device, tty_port); - - /* clear any old data; can't do this in 'close' */ - kfifo_reset(&ifx_dev->tx_fifo); - - /* clear any flag which may be set in port shutdown procedure */ - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); - clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); - - /* put port data into this tty */ - tty->driver_data = ifx_dev; - - /* allows flip string push from int context */ - port->low_latency = 1; - - /* set flag to allows data transfer */ - set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); - - return 0; -} - -/** - * ifx_port_shutdown - * @port: our tty port - * - * tty port shutdown method - called for last port close. Serialized - * with hangup and activate by the tty layer. - */ -static void ifx_port_shutdown(struct tty_port *port) -{ - struct ifx_spi_device *ifx_dev = - container_of(port, struct ifx_spi_device, tty_port); - - clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); - mrdy_set_low(ifx_dev); - del_timer(&ifx_dev->spi_timer); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); - tasklet_kill(&ifx_dev->io_work_tasklet); -} - -static const struct tty_port_operations ifx_tty_port_ops = { - .activate = ifx_port_activate, - .shutdown = ifx_port_shutdown, -}; - -static const struct tty_operations ifx_spi_serial_ops = { - .open = ifx_spi_open, - .close = ifx_spi_close, - .write = ifx_spi_write, - .hangup = ifx_spi_hangup, - .write_room = ifx_spi_write_room, - .chars_in_buffer = ifx_spi_chars_in_buffer, - .tiocmget = ifx_spi_tiocmget, - .tiocmset = ifx_spi_tiocmset, -}; - -/** - * ifx_spi_insert_fip_string - queue received data - * @ifx_ser: our SPI device - * @chars: buffer we have received - * @size: number of chars reeived - * - * Queue bytes to the tty assuming the tty side is currently open. If - * not the discard the data. - */ -static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev, - unsigned char *chars, size_t size) -{ - tty_insert_flip_string(&ifx_dev->tty_port, chars, size); - tty_flip_buffer_push(&ifx_dev->tty_port); -} - -/** - * ifx_spi_complete - SPI transfer completed - * @ctx: our SPI device - * - * An SPI transfer has completed. Process any received data and kick off - * any further transmits we can commence. - */ -static void ifx_spi_complete(void *ctx) -{ - struct ifx_spi_device *ifx_dev = ctx; - int length; - int actual_length; - unsigned char more = 0; - unsigned char cts; - int local_write_pending = 0; - int queue_length; - int srdy; - int decode_result; - - mrdy_set_low(ifx_dev); - - if (!ifx_dev->spi_msg.status) { - /* check header validity, get comm flags */ - ifx_dev->swap_buf(ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD, - &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]); - decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer, - &length, &more, &cts); - if (decode_result == IFX_SPI_HEADER_0) { - dev_dbg(&ifx_dev->spi_dev->dev, - "ignore input: invalid header 0"); - ifx_dev->spi_slave_cts = 0; - goto complete_exit; - } else if (decode_result == IFX_SPI_HEADER_F) { - dev_dbg(&ifx_dev->spi_dev->dev, - "ignore input: invalid header F"); - goto complete_exit; - } - - ifx_dev->spi_slave_cts = cts; - - actual_length = min((unsigned int)length, - ifx_dev->spi_msg.actual_length); - ifx_dev->swap_buf( - (ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD), - actual_length, - &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]); - ifx_spi_insert_flip_string( - ifx_dev, - ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD, - (size_t)actual_length); - } else { - more = 0; - dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d", - ifx_dev->spi_msg.status); - } - -complete_exit: - if (ifx_dev->write_pending) { - ifx_dev->write_pending = 0; - local_write_pending = 1; - } - - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags)); - - queue_length = kfifo_len(&ifx_dev->tx_fifo); - srdy = gpiod_get_value(ifx_dev->gpio.srdy); - if (!srdy) - ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY); - - /* schedule output if there is more to do */ - if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags)) - tasklet_schedule(&ifx_dev->io_work_tasklet); - else { - if (more || ifx_dev->spi_more || queue_length > 0 || - local_write_pending) { - if (ifx_dev->spi_slave_cts) { - if (more) - mrdy_assert(ifx_dev); - } else - mrdy_assert(ifx_dev); - } else { - /* - * poke line discipline driver if any for more data - * may or may not get more data to write - * for now, say not busy - */ - ifx_spi_power_state_clear(ifx_dev, - IFX_SPI_POWER_DATA_PENDING); - tty_port_tty_wakeup(&ifx_dev->tty_port); - } - } -} - -/** - * ifx_spio_io - I/O tasklet - * @data: our SPI device - * - * Queue data for transmission if possible and then kick off the - * transfer. - */ -static void ifx_spi_io(unsigned long data) -{ - int retval; - struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data; - - if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags) && - test_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags)) { - if (ifx_dev->gpio.unack_srdy_int_nb > 0) - ifx_dev->gpio.unack_srdy_int_nb--; - - ifx_spi_prepare_tx_buffer(ifx_dev); - - spi_message_init(&ifx_dev->spi_msg); - INIT_LIST_HEAD(&ifx_dev->spi_msg.queue); - - ifx_dev->spi_msg.context = ifx_dev; - ifx_dev->spi_msg.complete = ifx_spi_complete; - - /* set up our spi transfer */ - /* note len is BYTES, not transfers */ - ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE; - ifx_dev->spi_xfer.cs_change = 0; - ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz; - /* ifx_dev->spi_xfer.speed_hz = 390625; */ - ifx_dev->spi_xfer.bits_per_word = - ifx_dev->spi_dev->bits_per_word; - - ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; - ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; - - /* - * setup dma pointers - */ - if (ifx_dev->use_dma) { - ifx_dev->spi_msg.is_dma_mapped = 1; - ifx_dev->tx_dma = ifx_dev->tx_bus; - ifx_dev->rx_dma = ifx_dev->rx_bus; - ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma; - ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma; - } else { - ifx_dev->spi_msg.is_dma_mapped = 0; - ifx_dev->tx_dma = (dma_addr_t)0; - ifx_dev->rx_dma = (dma_addr_t)0; - ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0; - ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0; - } - - spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg); - - /* Assert MRDY. This may have already been done by the write - * routine. - */ - mrdy_assert(ifx_dev); - - retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg); - if (retval) { - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, - &ifx_dev->flags); - tasklet_schedule(&ifx_dev->io_work_tasklet); - return; - } - } else - ifx_dev->write_pending = 1; -} - -/** - * ifx_spi_free_port - free up the tty side - * @ifx_dev: IFX device going away - * - * Unregister and free up a port when the device goes away - */ -static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev) -{ - if (ifx_dev->tty_dev) - tty_unregister_device(tty_drv, ifx_dev->minor); - tty_port_destroy(&ifx_dev->tty_port); - kfifo_free(&ifx_dev->tx_fifo); -} - -/** - * ifx_spi_create_port - create a new port - * @ifx_dev: our spi device - * - * Allocate and initialise the tty port that goes with this interface - * and add it to the tty layer so that it can be opened. - */ -static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) -{ - int ret = 0; - struct tty_port *pport = &ifx_dev->tty_port; - - spin_lock_init(&ifx_dev->fifo_lock); - lockdep_set_class_and_subclass(&ifx_dev->fifo_lock, - &ifx_spi_key, 0); - - if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) { - ret = -ENOMEM; - goto error_ret; - } - - tty_port_init(pport); - pport->ops = &ifx_tty_port_ops; - ifx_dev->minor = IFX_SPI_TTY_ID; - ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv, - ifx_dev->minor, &ifx_dev->spi_dev->dev); - if (IS_ERR(ifx_dev->tty_dev)) { - dev_dbg(&ifx_dev->spi_dev->dev, - "%s: registering tty device failed", __func__); - ret = PTR_ERR(ifx_dev->tty_dev); - goto error_port; - } - return 0; - -error_port: - tty_port_destroy(pport); -error_ret: - ifx_spi_free_port(ifx_dev); - return ret; -} - -/** - * ifx_spi_handle_srdy - handle SRDY - * @ifx_dev: device asserting SRDY - * - * Check our device state and see what we need to kick off when SRDY - * is asserted. This usually means killing the timer and firing off the - * I/O processing. - */ -static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev) -{ - if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { - del_timer(&ifx_dev->spi_timer); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); - } - - ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY); - - if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) - tasklet_schedule(&ifx_dev->io_work_tasklet); - else - set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); -} - -/** - * ifx_spi_srdy_interrupt - SRDY asserted - * @irq: our IRQ number - * @dev: our ifx device - * - * The modem asserted SRDY. Handle the srdy event - */ -static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev) -{ - struct ifx_spi_device *ifx_dev = dev; - ifx_dev->gpio.unack_srdy_int_nb++; - ifx_spi_handle_srdy(ifx_dev); - return IRQ_HANDLED; -} - -/** - * ifx_spi_reset_interrupt - Modem has changed reset state - * @irq: interrupt number - * @dev: our device pointer - * - * The modem has either entered or left reset state. Check the GPIO - * line to see which. - * - * FIXME: review locking on MR_INPROGRESS versus - * parallel unsolicited reset/solicited reset - */ -static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev) -{ - struct ifx_spi_device *ifx_dev = dev; - int val = gpiod_get_value(ifx_dev->gpio.reset_out); - int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state); - - if (val == 0) { - /* entered reset */ - set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); - if (!solreset) { - /* unsolicited reset */ - tty_port_tty_hangup(&ifx_dev->tty_port, false); - } - } else { - /* exited reset */ - clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); - if (solreset) { - set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state); - wake_up(&ifx_dev->mdm_reset_wait); - } - } - return IRQ_HANDLED; -} - -/** - * ifx_spi_free_device - free device - * @ifx_dev: device to free - * - * Free the IFX device - */ -static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev) -{ - ifx_spi_free_port(ifx_dev); - dma_free_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - ifx_dev->tx_buffer, - ifx_dev->tx_bus); - dma_free_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - ifx_dev->rx_buffer, - ifx_dev->rx_bus); -} - -/** - * ifx_spi_reset - reset modem - * @ifx_dev: modem to reset - * - * Perform a reset on the modem - */ -static int ifx_spi_reset(struct ifx_spi_device *ifx_dev) -{ - int ret; - /* - * set up modem power, reset - * - * delays are required on some platforms for the modem - * to reset properly - */ - set_bit(MR_START, &ifx_dev->mdm_reset_state); - gpiod_set_value(ifx_dev->gpio.po, 0); - gpiod_set_value(ifx_dev->gpio.reset, 0); - msleep(25); - gpiod_set_value(ifx_dev->gpio.reset, 1); - msleep(1); - gpiod_set_value(ifx_dev->gpio.po, 1); - msleep(1); - gpiod_set_value(ifx_dev->gpio.po, 0); - ret = wait_event_timeout(ifx_dev->mdm_reset_wait, - test_bit(MR_COMPLETE, - &ifx_dev->mdm_reset_state), - IFX_RESET_TIMEOUT); - if (!ret) - dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)", - ifx_dev->mdm_reset_state); - - ifx_dev->mdm_reset_state = 0; - return ret; -} - -/** - * ifx_spi_spi_probe - probe callback - * @spi: our possible matching SPI device - * - * Probe for a 6x60 modem on SPI bus. Perform any needed device and - * GPIO setup. - * - * FIXME: - * - Support for multiple devices - * - Split out MID specific GPIO handling eventually - */ - -static int ifx_spi_spi_probe(struct spi_device *spi) -{ - int ret; - int srdy; - struct ifx_modem_platform_data *pl_data; - struct ifx_spi_device *ifx_dev; - struct device *dev = &spi->dev; - - if (saved_ifx_dev) { - dev_dbg(dev, "ignoring subsequent detection"); - return -ENODEV; - } - - pl_data = dev_get_platdata(dev); - if (!pl_data) { - dev_err(dev, "missing platform data!"); - return -ENODEV; - } - - /* initialize structure to hold our device variables */ - ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); - if (!ifx_dev) { - dev_err(dev, "spi device allocation failed"); - return -ENOMEM; - } - saved_ifx_dev = ifx_dev; - ifx_dev->spi_dev = spi; - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); - spin_lock_init(&ifx_dev->write_lock); - spin_lock_init(&ifx_dev->power_lock); - ifx_dev->power_status = 0; - timer_setup(&ifx_dev->spi_timer, ifx_spi_timeout, 0); - ifx_dev->modem = pl_data->modem_type; - ifx_dev->use_dma = pl_data->use_dma; - ifx_dev->max_hz = pl_data->max_hz; - /* initialize spi mode, etc */ - spi->max_speed_hz = ifx_dev->max_hz; - spi->mode = IFX_SPI_MODE | (SPI_LOOP & spi->mode); - spi->bits_per_word = spi_bpw; - ret = spi_setup(spi); - if (ret) { - dev_err(dev, "SPI setup wasn't successful %d", ret); - kfree(ifx_dev); - return -ENODEV; - } - - /* init swap_buf function according to word width configuration */ - if (spi->bits_per_word == 32) - ifx_dev->swap_buf = swap_buf_32; - else if (spi->bits_per_word == 16) - ifx_dev->swap_buf = swap_buf_16; - else - ifx_dev->swap_buf = swap_buf_8; - - /* ensure SPI protocol flags are initialized to enable transfer */ - ifx_dev->spi_more = 0; - ifx_dev->spi_slave_cts = 0; - - /*initialize transfer and dma buffers */ - ifx_dev->tx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent, - IFX_SPI_TRANSFER_SIZE, - &ifx_dev->tx_bus, - GFP_KERNEL); - if (!ifx_dev->tx_buffer) { - dev_err(dev, "DMA-TX buffer allocation failed"); - ret = -ENOMEM; - goto error_ret; - } - ifx_dev->rx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent, - IFX_SPI_TRANSFER_SIZE, - &ifx_dev->rx_bus, - GFP_KERNEL); - if (!ifx_dev->rx_buffer) { - dev_err(dev, "DMA-RX buffer allocation failed"); - ret = -ENOMEM; - goto error_ret; - } - - /* initialize waitq for modem reset */ - init_waitqueue_head(&ifx_dev->mdm_reset_wait); - - spi_set_drvdata(spi, ifx_dev); - tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io, - (unsigned long)ifx_dev); - - set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags); - - /* create our tty port */ - ret = ifx_spi_create_port(ifx_dev); - if (ret != 0) { - dev_err(dev, "create default tty port failed"); - goto error_ret; - } - - ifx_dev->gpio.reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ifx_dev->gpio.reset)) { - dev_err(dev, "could not obtain reset GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.reset); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.reset, "ifxModem reset"); - ifx_dev->gpio.po = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW); - if (IS_ERR(ifx_dev->gpio.po)) { - dev_err(dev, "could not obtain power GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.po); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.po, "ifxModem power"); - ifx_dev->gpio.mrdy = devm_gpiod_get(dev, "mrdy", GPIOD_OUT_LOW); - if (IS_ERR(ifx_dev->gpio.mrdy)) { - dev_err(dev, "could not obtain mrdy GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.mrdy); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.mrdy, "ifxModem mrdy"); - ifx_dev->gpio.srdy = devm_gpiod_get(dev, "srdy", GPIOD_IN); - if (IS_ERR(ifx_dev->gpio.srdy)) { - dev_err(dev, "could not obtain srdy GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.srdy); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.srdy, "ifxModem srdy"); - ifx_dev->gpio.reset_out = devm_gpiod_get(dev, "rst_out", GPIOD_IN); - if (IS_ERR(ifx_dev->gpio.reset_out)) { - dev_err(dev, "could not obtain rst_out GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.reset_out); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.reset_out, "ifxModem reset out"); - ifx_dev->gpio.pmu_reset = devm_gpiod_get(dev, "pmu_reset", GPIOD_ASIS); - if (IS_ERR(ifx_dev->gpio.pmu_reset)) { - dev_err(dev, "could not obtain pmu_reset GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.pmu_reset); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.pmu_reset, "ifxModem PMU reset"); - - ret = request_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), - ifx_spi_reset_interrupt, - IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, - ifx_dev); - if (ret) { - dev_err(dev, "Unable to get irq %x\n", - gpiod_to_irq(ifx_dev->gpio.reset_out)); - goto error_ret; - } - - ret = ifx_spi_reset(ifx_dev); - - ret = request_irq(gpiod_to_irq(ifx_dev->gpio.srdy), - ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, - ifx_dev); - if (ret) { - dev_err(dev, "Unable to get irq %x", - gpiod_to_irq(ifx_dev->gpio.srdy)); - goto error_ret2; - } - - /* set pm runtime power state and register with power system */ - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - /* handle case that modem is already signaling SRDY */ - /* no outgoing tty open at this point, this just satisfies the - * modem's read and should reset communication properly - */ - srdy = gpiod_get_value(ifx_dev->gpio.srdy); - - if (srdy) { - mrdy_assert(ifx_dev); - ifx_spi_handle_srdy(ifx_dev); - } else - mrdy_set_low(ifx_dev); - return 0; - -error_ret2: - free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev); -error_ret: - ifx_spi_free_device(ifx_dev); - saved_ifx_dev = NULL; - return ret; -} - -/** - * ifx_spi_spi_remove - SPI device was removed - * @spi: SPI device - * - * FIXME: We should be shutting the device down here not in - * the module unload path. - */ - -static int ifx_spi_spi_remove(struct spi_device *spi) -{ - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - /* stop activity */ - tasklet_kill(&ifx_dev->io_work_tasklet); - - pm_runtime_disable(&spi->dev); - - /* free irq */ - free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev); - free_irq(gpiod_to_irq(ifx_dev->gpio.srdy), ifx_dev); - - /* free allocations */ - ifx_spi_free_device(ifx_dev); - - saved_ifx_dev = NULL; - return 0; -} - -/** - * ifx_spi_spi_shutdown - called on SPI shutdown - * @spi: SPI device - * - * No action needs to be taken here - */ - -static void ifx_spi_spi_shutdown(struct spi_device *spi) -{ - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - - ifx_modem_power_off(ifx_dev); -} - -/* - * various suspends and resumes have nothing to do - * no hardware to save state for - */ - -/** - * ifx_spi_pm_suspend - suspend modem on system suspend - * @dev: device being suspended - * - * Suspend the modem. No action needed on Intel MID platforms, may - * need extending for other systems. - */ -static int ifx_spi_pm_suspend(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_resume - resume modem on system resume - * @dev: device being suspended - * - * Allow the modem to resume. No action needed. - * - * FIXME: do we need to reset anything here ? - */ -static int ifx_spi_pm_resume(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_resume - suspend modem - * @dev: device being suspended - * - * Allow the modem to resume. No action needed. - */ -static int ifx_spi_pm_runtime_resume(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_suspend - suspend modem - * @dev: device being suspended - * - * Allow the modem to suspend and thus suspend to continue up the - * device tree. - */ -static int ifx_spi_pm_runtime_suspend(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_idle - check if modem idle - * @dev: our device - * - * Check conditions and queue runtime suspend if idle. - */ -static int ifx_spi_pm_runtime_idle(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - - if (!ifx_dev->power_status) - pm_runtime_suspend(dev); - - return 0; -} - -static const struct dev_pm_ops ifx_spi_pm = { - .resume = ifx_spi_pm_resume, - .suspend = ifx_spi_pm_suspend, - .runtime_resume = ifx_spi_pm_runtime_resume, - .runtime_suspend = ifx_spi_pm_runtime_suspend, - .runtime_idle = ifx_spi_pm_runtime_idle -}; - -static const struct spi_device_id ifx_id_table[] = { - {"ifx6160", 0}, - {"ifx6260", 0}, - { } -}; -MODULE_DEVICE_TABLE(spi, ifx_id_table); - -/* spi operations */ -static struct spi_driver ifx_spi_driver = { - .driver = { - .name = DRVNAME, - .pm = &ifx_spi_pm, - }, - .probe = ifx_spi_spi_probe, - .shutdown = ifx_spi_spi_shutdown, - .remove = ifx_spi_spi_remove, - .id_table = ifx_id_table -}; - -/** - * ifx_spi_exit - module exit - * - * Unload the module. - */ - -static void __exit ifx_spi_exit(void) -{ - /* unregister */ - spi_unregister_driver(&ifx_spi_driver); - tty_unregister_driver(tty_drv); - put_tty_driver(tty_drv); - unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); -} - -/** - * ifx_spi_init - module entry point - * - * Initialise the SPI and tty interfaces for the IFX SPI driver - * We need to initialize upper-edge spi driver after the tty - * driver because otherwise the spi probe will race - */ - -static int __init ifx_spi_init(void) -{ - int result; - - tty_drv = alloc_tty_driver(1); - if (!tty_drv) { - pr_err("%s: alloc_tty_driver failed", DRVNAME); - return -ENOMEM; - } - - tty_drv->driver_name = DRVNAME; - tty_drv->name = TTYNAME; - tty_drv->minor_start = IFX_SPI_TTY_ID; - tty_drv->type = TTY_DRIVER_TYPE_SERIAL; - tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_drv->init_termios = tty_std_termios; - - tty_set_operations(tty_drv, &ifx_spi_serial_ops); - - result = tty_register_driver(tty_drv); - if (result) { - pr_err("%s: tty_register_driver failed(%d)", - DRVNAME, result); - goto err_free_tty; - } - - result = spi_register_driver(&ifx_spi_driver); - if (result) { - pr_err("%s: spi_register_driver failed(%d)", - DRVNAME, result); - goto err_unreg_tty; - } - - result = register_reboot_notifier(&ifx_modem_reboot_notifier_block); - if (result) { - pr_err("%s: register ifx modem reboot notifier failed(%d)", - DRVNAME, result); - goto err_unreg_spi; - } - - return 0; -err_unreg_spi: - spi_unregister_driver(&ifx_spi_driver); -err_unreg_tty: - tty_unregister_driver(tty_drv); -err_free_tty: - put_tty_driver(tty_drv); - - return result; -} - -module_init(ifx_spi_init); -module_exit(ifx_spi_exit); - -MODULE_AUTHOR("Intel"); -MODULE_DESCRIPTION("IFX6x60 spi driver"); -MODULE_LICENSE("GPL"); -MODULE_INFO(Version, "0.1-IFX6x60"); diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h deleted file mode 100644 index ecb841d928a7..000000000000 --- a/drivers/tty/serial/ifx6x60.h +++ /dev/null @@ -1,118 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/**************************************************************************** - * - * Driver for the IFX spi modem. - * - * Copyright (C) 2009, 2010 Intel Corp - * Jim Stanley <jim.stanley@intel.com> - * - *****************************************************************************/ -#ifndef _IFX6X60_H -#define _IFX6X60_H - -struct gpio_desc; - -#define DRVNAME "ifx6x60" -#define TTYNAME "ttyIFX" - -#define IFX_SPI_MAX_MINORS 1 -#define IFX_SPI_TRANSFER_SIZE 2048 -#define IFX_SPI_FIFO_SIZE 4096 - -#define IFX_SPI_HEADER_OVERHEAD 4 -#define IFX_RESET_TIMEOUT msecs_to_jiffies(50) - -/* device flags bitfield definitions */ -#define IFX_SPI_STATE_PRESENT 0 -#define IFX_SPI_STATE_IO_IN_PROGRESS 1 -#define IFX_SPI_STATE_IO_READY 2 -#define IFX_SPI_STATE_TIMER_PENDING 3 -#define IFX_SPI_STATE_IO_AVAILABLE 4 - -/* flow control bitfields */ -#define IFX_SPI_DCD 0 -#define IFX_SPI_CTS 1 -#define IFX_SPI_DSR 2 -#define IFX_SPI_RI 3 -#define IFX_SPI_DTR 4 -#define IFX_SPI_RTS 5 -#define IFX_SPI_TX_FC 6 -#define IFX_SPI_RX_FC 7 -#define IFX_SPI_UPDATE 8 - -#define IFX_SPI_PAYLOAD_SIZE (IFX_SPI_TRANSFER_SIZE - \ - IFX_SPI_HEADER_OVERHEAD) - -#define IFX_SPI_IRQ_TYPE DETECT_EDGE_RISING -#define IFX_SPI_GPIO_TARGET 0 -#define IFX_SPI_GPIO0 0x105 - -#define IFX_SPI_STATUS_TIMEOUT (2000*HZ) - -/* values for bits in power status byte */ -#define IFX_SPI_POWER_DATA_PENDING 1 -#define IFX_SPI_POWER_SRDY 2 - -struct ifx_spi_device { - /* Our SPI device */ - struct spi_device *spi_dev; - - /* Port specific data */ - struct kfifo tx_fifo; - spinlock_t fifo_lock; - unsigned long signal_state; - - /* TTY Layer logic */ - struct tty_port tty_port; - struct device *tty_dev; - int minor; - - /* Low level I/O work */ - struct tasklet_struct io_work_tasklet; - unsigned long flags; - dma_addr_t rx_dma; - dma_addr_t tx_dma; - - int modem; /* Modem type */ - int use_dma; /* provide dma-able addrs in SPI msg */ - long max_hz; /* max SPI frequency */ - - spinlock_t write_lock; - int write_pending; - spinlock_t power_lock; - unsigned char power_status; - - unsigned char *rx_buffer; - unsigned char *tx_buffer; - dma_addr_t rx_bus; - dma_addr_t tx_bus; - unsigned char spi_more; - unsigned char spi_slave_cts; - - struct timer_list spi_timer; - - struct spi_message spi_msg; - struct spi_transfer spi_xfer; - - struct { - /* gpio lines */ - struct gpio_desc *srdy; /* slave-ready gpio */ - struct gpio_desc *mrdy; /* master-ready gpio */ - struct gpio_desc *reset; /* modem-reset gpio */ - struct gpio_desc *po; /* modem-on gpio */ - struct gpio_desc *reset_out; /* modem-in-reset gpio */ - struct gpio_desc *pmu_reset; /* PMU reset gpio */ - /* state/stats */ - int unack_srdy_int_nb; - } gpio; - - /* modem reset */ - unsigned long mdm_reset_state; -#define MR_START 0 -#define MR_INPROGRESS 1 -#define MR_COMPLETE 2 - wait_queue_head_t mdm_reset_wait; - void (*swap_buf)(unsigned char *buf, int len, void *end); -}; - -#endif /* _IFX6X60_H */ diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 1265e8d86d8a..c488e5d372ff 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -8,6 +8,7 @@ * Copyright (C) 2004 Pengutronix */ +#include <linux/circ_buf.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/init.h> @@ -20,17 +21,17 @@ #include <linux/serial.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/ktime.h> #include <linux/pinctrl/consumer.h> #include <linux/rational.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/dma-mapping.h> -#include <asm/irq.h> -#include <linux/platform_data/serial-imx.h> -#include <linux/platform_data/dma-imx.h> +#include <linux/irq.h> +#include <linux/dma/imx-dma.h> #include "serial_mctrl_gpio.h" @@ -119,6 +120,7 @@ #define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_RXTL_MASK 0x3F /* Receiver trigger 6 bits wide */ #define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */ #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ #define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) @@ -178,8 +180,6 @@ enum imx_uart_type { IMX1_UART, IMX21_UART, - IMX53_UART, - IMX6Q_UART, }; /* device type dependent stuff */ @@ -188,6 +188,13 @@ struct imx_uart_data { enum imx_uart_type devtype; }; +enum imx_tx_state { + OFF, + WAIT_AFTER_RTS, + SEND, + WAIT_AFTER_SEND, +}; + struct imx_port { struct uart_port port; struct timer_list timer; @@ -203,12 +210,8 @@ struct imx_port { struct mctrl_gpios *gpios; - /* shadow registers */ - unsigned int ucr1; - unsigned int ucr2; - unsigned int ucr3; - unsigned int ucr4; - unsigned int ufcr; + /* counter to stop 0xff flood */ + int idle_counter; /* DMA fields */ unsigned int dma_is_enabled:1; @@ -218,12 +221,21 @@ struct imx_port { struct scatterlist rx_sgl, tx_sgl[2]; void *rx_buf; struct circ_buf rx_ring; + unsigned int rx_buf_size; + unsigned int rx_period_length; unsigned int rx_periods; dma_cookie_t rx_cookie; unsigned int tx_bytes; unsigned int dma_tx_nents; unsigned int saved_reg[10]; bool context_saved; + + bool last_putchar_was_newline; + + enum imx_tx_state tx_state; + struct hrtimer trigger_start_tx; + struct hrtimer trigger_stop_tx; + unsigned int rxtl; }; struct imx_port_ucrs { @@ -232,106 +244,43 @@ struct imx_port_ucrs { unsigned int ucr3; }; -static struct imx_uart_data imx_uart_devdata[] = { - [IMX1_UART] = { - .uts_reg = IMX1_UTS, - .devtype = IMX1_UART, - }, - [IMX21_UART] = { - .uts_reg = IMX21_UTS, - .devtype = IMX21_UART, - }, - [IMX53_UART] = { - .uts_reg = IMX21_UTS, - .devtype = IMX53_UART, - }, - [IMX6Q_UART] = { - .uts_reg = IMX21_UTS, - .devtype = IMX6Q_UART, - }, +static const struct imx_uart_data imx_uart_imx1_devdata = { + .uts_reg = IMX1_UTS, + .devtype = IMX1_UART, }; -static const struct platform_device_id imx_uart_devtype[] = { - { - .name = "imx1-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART], - }, { - .name = "imx21-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART], - }, { - .name = "imx53-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART], - }, { - .name = "imx6q-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART], - }, { - /* sentinel */ - } +static const struct imx_uart_data imx_uart_imx21_devdata = { + .uts_reg = IMX21_UTS, + .devtype = IMX21_UART, }; -MODULE_DEVICE_TABLE(platform, imx_uart_devtype); static const struct of_device_id imx_uart_dt_ids[] = { - { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, - { .compatible = "fsl,imx53-uart", .data = &imx_uart_devdata[IMX53_UART], }, - { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, - { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, + /* + * For reasons unknown to me, some UART devices (e.g. imx6ul's) are + * compatible to fsl,imx6q-uart, but not fsl,imx21-uart, while the + * original imx6q's UART is compatible to fsl,imx21-uart. This driver + * doesn't make any distinction between these two variants. + */ + { .compatible = "fsl,imx6q-uart", .data = &imx_uart_imx21_devdata, }, + { .compatible = "fsl,imx1-uart", .data = &imx_uart_imx1_devdata, }, + { .compatible = "fsl,imx21-uart", .data = &imx_uart_imx21_devdata, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_uart_dt_ids); -static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset) -{ - switch (offset) { - case UCR1: - sport->ucr1 = val; - break; - case UCR2: - sport->ucr2 = val; - break; - case UCR3: - sport->ucr3 = val; - break; - case UCR4: - sport->ucr4 = val; - break; - case UFCR: - sport->ufcr = val; - break; - default: - break; - } +static inline struct imx_port *to_imx_port(struct uart_port *port) +{ + return container_of(port, struct imx_port, port); +} + +static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset) +{ writel(val, sport->port.membase + offset); } -static u32 imx_uart_readl(struct imx_port *sport, u32 offset) +static inline u32 imx_uart_readl(struct imx_port *sport, u32 offset) { - switch (offset) { - case UCR1: - return sport->ucr1; - break; - case UCR2: - /* - * UCR2_SRST is the only bit in the cached registers that might - * differ from the value that was last written. As it only - * automatically becomes one after being cleared, reread - * conditionally. - */ - if (!(sport->ucr2 & UCR2_SRST)) - sport->ucr2 = readl(sport->port.membase + offset); - return sport->ucr2; - break; - case UCR3: - return sport->ucr3; - break; - case UCR4: - return sport->ucr4; - break; - case UFCR: - return sport->ufcr; - break; - default: - return readl(sport->port.membase + offset); - } + return readl(sport->port.membase + offset); } static inline unsigned imx_uart_uts_reg(struct imx_port *sport) @@ -344,24 +293,10 @@ static inline int imx_uart_is_imx1(struct imx_port *sport) return sport->devdata->devtype == IMX1_UART; } -static inline int imx_uart_is_imx21(struct imx_port *sport) -{ - return sport->devdata->devtype == IMX21_UART; -} - -static inline int imx_uart_is_imx53(struct imx_port *sport) -{ - return sport->devdata->devtype == IMX53_UART; -} - -static inline int imx_uart_is_imx6q(struct imx_port *sport) -{ - return sport->devdata->devtype == IMX6Q_UART; -} /* * Save and restore functions for UCR1, UCR2 and UCR3 registers */ -#if defined(CONFIG_SERIAL_IMX_CONSOLE) +#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) static void imx_uart_ucrs_save(struct imx_port *sport, struct imx_port_ucrs *ucr) { @@ -386,8 +321,7 @@ static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2) { *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); - sport->port.mctrl |= TIOCM_RTS; - mctrl_gpio_set(sport->gpios, sport->port.mctrl); + mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS); } /* called with port.lock taken and irqs caller dependent */ @@ -396,14 +330,64 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) *ucr2 &= ~UCR2_CTSC; *ucr2 |= UCR2_CTS; - sport->port.mctrl &= ~TIOCM_RTS; - mctrl_gpio_set(sport->gpios, sport->port.mctrl); + mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS); +} + +static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) +{ + hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL); +} + +/* called with port.lock taken and irqs off */ +static void imx_uart_soft_reset(struct imx_port *sport) +{ + int i = 10; + u32 ucr2, ubir, ubmr, uts; + + /* + * According to the Reference Manual description of the UART SRST bit: + * + * "Reset the transmit and receive state machines, + * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD + * and UTS[6-3]". + * + * We don't need to restore the old values from USR1, USR2, URXD and + * UTXD. UBRC is read only, so only save/restore the other three + * registers. + */ + ubir = imx_uart_readl(sport, UBIR); + ubmr = imx_uart_readl(sport, UBMR); + uts = imx_uart_readl(sport, IMX21_UTS); + + ucr2 = imx_uart_readl(sport, UCR2); + imx_uart_writel(sport, ucr2 & ~UCR2_SRST, UCR2); + + while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) + udelay(1); + + /* Restore the registers */ + imx_uart_writel(sport, ubir, UBIR); + imx_uart_writel(sport, ubmr, UBMR); + imx_uart_writel(sport, uts, IMX21_UTS); + + sport->idle_counter = 0; +} + +/* called with port.lock taken and irqs off */ +static void imx_uart_disable_loopback_rs485(struct imx_port *sport) +{ + unsigned int uts; + + /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */ + uts = imx_uart_readl(sport, imx_uart_uts_reg(sport)); + uts &= ~UTS_LOOP; + imx_uart_writel(sport, uts, imx_uart_uts_reg(sport)); } /* called with port.lock taken and irqs off */ static void imx_uart_start_rx(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int ucr1, ucr2; ucr1 = imx_uart_readl(sport, UCR1); @@ -421,13 +405,17 @@ static void imx_uart_start_rx(struct uart_port *port) /* Write UCR2 first as it includes RXEN */ imx_uart_writel(sport, ucr2, UCR2); imx_uart_writel(sport, ucr1, UCR1); + imx_uart_disable_loopback_rs485(sport); } /* called with port.lock taken and irqs off */ static void imx_uart_stop_tx(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - u32 ucr1; + struct imx_port *sport = to_imx_port(port); + u32 ucr1, ucr4, usr2; + + if (sport->tx_state == OFF) + return; /* * We are maybe in the SMP context, so if the DMA TX thread is running @@ -439,49 +427,102 @@ static void imx_uart_stop_tx(struct uart_port *port) ucr1 = imx_uart_readl(sport, UCR1); imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1); - /* in rs485 mode disable transmitter if shifter is empty */ - if (port->rs485.flags & SER_RS485_ENABLED && - imx_uart_readl(sport, USR2) & USR2_TXDC) { - u32 ucr2 = imx_uart_readl(sport, UCR2), ucr4; - if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - imx_uart_rts_active(sport, &ucr2); - else - imx_uart_rts_inactive(sport, &ucr2); - imx_uart_writel(sport, ucr2, UCR2); + ucr4 = imx_uart_readl(sport, UCR4); + usr2 = imx_uart_readl(sport, USR2); + if ((!(usr2 & USR2_TXDC)) && (ucr4 & UCR4_TCEN)) { + /* The shifter is still busy, so retry once TC triggers */ + return; + } - imx_uart_start_rx(port); + ucr4 &= ~UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); - ucr4 = imx_uart_readl(sport, UCR4); - ucr4 &= ~UCR4_TCEN; - imx_uart_writel(sport, ucr4, UCR4); + /* in rs485 mode disable transmitter */ + if (port->rs485.flags & SER_RS485_ENABLED) { + if (sport->tx_state == SEND) { + sport->tx_state = WAIT_AFTER_SEND; + + if (port->rs485.delay_rts_after_send > 0) { + start_hrtimer_ms(&sport->trigger_stop_tx, + port->rs485.delay_rts_after_send); + return; + } + + /* continue without any delay */ + } + + if (sport->tx_state == WAIT_AFTER_RTS || + sport->tx_state == WAIT_AFTER_SEND) { + u32 ucr2; + + hrtimer_try_to_cancel(&sport->trigger_start_tx); + + ucr2 = imx_uart_readl(sport, UCR2); + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + imx_uart_rts_active(sport, &ucr2); + else + imx_uart_rts_inactive(sport, &ucr2); + imx_uart_writel(sport, ucr2, UCR2); + + if (!port->rs485_rx_during_tx_gpio) + imx_uart_start_rx(port); + + sport->tx_state = OFF; + } + } else { + sport->tx_state = OFF; } } /* called with port.lock taken and irqs off */ -static void imx_uart_stop_rx(struct uart_port *port) +static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback) { - struct imx_port *sport = (struct imx_port *)port; - u32 ucr1, ucr2; + struct imx_port *sport = to_imx_port(port); + u32 ucr1, ucr2, ucr4, uts; ucr1 = imx_uart_readl(sport, UCR1); ucr2 = imx_uart_readl(sport, UCR2); + ucr4 = imx_uart_readl(sport, UCR4); if (sport->dma_is_enabled) { ucr1 &= ~(UCR1_RXDMAEN | UCR1_ATDMAEN); } else { ucr1 &= ~UCR1_RRDYEN; ucr2 &= ~UCR2_ATEN; + ucr4 &= ~UCR4_OREN; } imx_uart_writel(sport, ucr1, UCR1); + imx_uart_writel(sport, ucr4, UCR4); + + /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */ + if (port->rs485.flags & SER_RS485_ENABLED && + port->rs485.flags & SER_RS485_RTS_ON_SEND && + sport->have_rtscts && !sport->have_rtsgpio && loopback) { + uts = imx_uart_readl(sport, imx_uart_uts_reg(sport)); + uts |= UTS_LOOP; + imx_uart_writel(sport, uts, imx_uart_uts_reg(sport)); + ucr2 |= UCR2_RXEN; + } else { + ucr2 &= ~UCR2_RXEN; + } - ucr2 &= ~UCR2_RXEN; imx_uart_writel(sport, ucr2, UCR2); } /* called with port.lock taken and irqs off */ +static void imx_uart_stop_rx(struct uart_port *port) +{ + /* + * Stop RX and enable loopback in order to make sure RS485 bus + * is not blocked. Se comment in imx_uart_probe(). + */ + imx_uart_stop_rx_with_loopback_ctrl(port, true); +} + +/* called with port.lock taken and irqs off */ static void imx_uart_enable_ms(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); mod_timer(&sport->timer, jiffies); @@ -493,7 +534,8 @@ static void imx_uart_dma_tx(struct imx_port *sport); /* called with port.lock taken and irqs off */ static inline void imx_uart_transmit_buffer(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; + unsigned char c; if (sport->port.x_char) { /* Send next char */ @@ -503,7 +545,8 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || + uart_tx_stopped(&sport->port)) { imx_uart_stop_tx(&sport->port); return; } @@ -527,31 +570,26 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) return; } - while (!uart_circ_empty(xmit) && - !(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)) { - /* send xmit->buf[xmit->tail] - * out the port here */ - imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - } + while (!(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) && + uart_fifo_get(&sport->port, &c)) + imx_uart_writel(sport, c, URTX0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) imx_uart_stop_tx(&sport->port); } static void imx_uart_dma_tx_callback(void *data) { struct imx_port *sport = data; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = &sport->tx_sgl[0]; - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; u32 ucr1; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); @@ -559,18 +597,17 @@ static void imx_uart_dma_tx_callback(void *data) ucr1 &= ~UCR1_TXDMAEN; imx_uart_writel(sport, ucr1, UCR1); - /* update the stat */ - xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx += sport->tx_bytes; + uart_xmit_advance(&sport->port, sport->tx_bytes); dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); sport->dma_is_txing = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + if (!kfifo_is_empty(&tport->xmit_fifo) && + !uart_tx_stopped(&sport->port)) imx_uart_dma_tx(sport); else if (sport->port.rs485.flags & SER_RS485_ENABLED) { u32 ucr4 = imx_uart_readl(sport, UCR4); @@ -578,13 +615,13 @@ static void imx_uart_dma_tx_callback(void *data) imx_uart_writel(sport, ucr4, UCR4); } - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } /* called with port.lock taken and irqs off */ static void imx_uart_dma_tx(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = sport->tx_sgl; struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; @@ -599,18 +636,10 @@ static void imx_uart_dma_tx(struct imx_port *sport) ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); - sport->tx_bytes = uart_circ_chars_pending(xmit); - - if (xmit->tail < xmit->head || xmit->head == 0) { - sport->dma_tx_nents = 1; - sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); - } else { - sport->dma_tx_nents = 2; - sg_init_table(sgl, 2); - sg_set_buf(sgl, xmit->buf + xmit->tail, - UART_XMIT_SIZE - xmit->tail); - sg_set_buf(sgl + 1, xmit->buf, xmit->head); - } + sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl)); + sport->tx_bytes = kfifo_len(&tport->xmit_fifo); + sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl, + ARRAY_SIZE(sport->tx_sgl), sport->tx_bytes); ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); if (ret == 0) { @@ -628,8 +657,7 @@ static void imx_uart_dma_tx(struct imx_port *sport) desc->callback = imx_uart_dma_tx_callback; desc->callback_param = sport; - dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", - uart_circ_chars_pending(xmit)); + dev_dbg(dev, "TX: prepare to send %u bytes by DMA.\n", sport->tx_bytes); ucr1 = imx_uart_readl(sport, UCR1); ucr1 |= UCR1_TXDMAEN; @@ -645,34 +673,68 @@ static void imx_uart_dma_tx(struct imx_port *sport) /* called with port.lock taken and irqs off */ static void imx_uart_start_tx(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); + struct tty_port *tport = &sport->port.state->port; u32 ucr1; - if (!sport->port.x_char && uart_circ_empty(&port->state->xmit)) + if (!sport->port.x_char && kfifo_is_empty(&tport->xmit_fifo)) return; + /* + * We cannot simply do nothing here if sport->tx_state == SEND already + * because UCR1_TXMPTYEN might already have been cleared in + * imx_uart_stop_tx(), but tx_state is still SEND. + */ + if (port->rs485.flags & SER_RS485_ENABLED) { - u32 ucr2; + if (sport->tx_state == OFF) { + u32 ucr2 = imx_uart_readl(sport, UCR2); + if (port->rs485.flags & SER_RS485_RTS_ON_SEND) + imx_uart_rts_active(sport, &ucr2); + else + imx_uart_rts_inactive(sport, &ucr2); + imx_uart_writel(sport, ucr2, UCR2); - ucr2 = imx_uart_readl(sport, UCR2); - if (port->rs485.flags & SER_RS485_RTS_ON_SEND) - imx_uart_rts_active(sport, &ucr2); - else - imx_uart_rts_inactive(sport, &ucr2); - imx_uart_writel(sport, ucr2, UCR2); + /* + * Since we are about to transmit we can not stop RX + * with loopback enabled because that will make our + * transmitted data being just looped to RX. + */ + if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) && + !port->rs485_rx_during_tx_gpio) + imx_uart_stop_rx_with_loopback_ctrl(port, false); - if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) - imx_uart_stop_rx(port); + sport->tx_state = WAIT_AFTER_RTS; - /* - * Enable transmitter and shifter empty irq only if DMA is off. - * In the DMA case this is done in the tx-callback. - */ - if (!sport->dma_is_enabled) { - u32 ucr4 = imx_uart_readl(sport, UCR4); - ucr4 |= UCR4_TCEN; - imx_uart_writel(sport, ucr4, UCR4); + if (port->rs485.delay_rts_before_send > 0) { + start_hrtimer_ms(&sport->trigger_start_tx, + port->rs485.delay_rts_before_send); + return; + } + + /* continue without any delay */ + } + + if (sport->tx_state == WAIT_AFTER_SEND + || sport->tx_state == WAIT_AFTER_RTS) { + + hrtimer_try_to_cancel(&sport->trigger_stop_tx); + + /* + * Enable transmitter and shifter empty irq only if DMA + * is off. In the DMA case this is done in the + * tx-callback. + */ + if (!sport->dma_is_enabled) { + u32 ucr4 = imx_uart_readl(sport, UCR4); + ucr4 |= UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); + } + + sport->tx_state = SEND; } + } else { + sport->tx_state = SEND; } if (!sport->dma_is_enabled) { @@ -691,7 +753,7 @@ static void imx_uart_start_tx(struct uart_port *port) return; } - if (!uart_circ_empty(&port->state->xmit) && + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) imx_uart_dma_tx(sport); return; @@ -705,7 +767,22 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id) imx_uart_writel(sport, USR1_RTSD, USR1); usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS; - uart_handle_cts_change(&sport->port, !!usr1); + /* + * Update sport->old_status here, so any follow-up calls to + * imx_uart_mctrl_check() will be able to recognize that RTS + * state changed since last imx_uart_mctrl_check() call. + * + * In case RTS has been detected as asserted here and later on + * deasserted by the time imx_uart_mctrl_check() was called, + * imx_uart_mctrl_check() can detect the RTS state change and + * trigger uart_handle_cts_change() to unblock the port for + * further TX transfers. + */ + if (usr1 & USR1_RTSS) + sport->old_status |= TIOCM_CTS; + else + sport->old_status &= ~TIOCM_CTS; + uart_handle_cts_change(&sport->port, usr1); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); return IRQ_HANDLED; @@ -716,11 +793,11 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id) struct imx_port *sport = dev_id; irqreturn_t ret; - spin_lock(&sport->port.lock); + uart_port_lock(&sport->port); ret = __imx_uart_rtsint(irq, dev_id); - spin_unlock(&sport->port.lock); + uart_port_unlock(&sport->port); return ret; } @@ -729,39 +806,82 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - spin_lock(&sport->port.lock); + uart_port_lock(&sport->port); imx_uart_transmit_buffer(sport); - spin_unlock(&sport->port.lock); + uart_port_unlock(&sport->port); return IRQ_HANDLED; } +/* Check if hardware Rx flood is in progress, and issue soft reset to stop it. + * This is to be called from Rx ISRs only when some bytes were actually + * received. + * + * A way to reproduce the flood (checked on iMX6SX) is: open iMX UART at 9600 + * 8N1, and from external source send 0xf0 char at 115200 8N1. In about 90% of + * cases this starts a flood of "receiving" of 0xff characters by the iMX6 UART + * that is terminated by any activity on RxD line, or could be stopped by + * issuing soft reset to the UART (just stop/start of RX does not help). Note + * that what we do here is sending isolated start bit about 2.4 times shorter + * than it is to be on UART configured baud rate. + * + * Called with port.lock taken and irqs off. + */ +static void imx_uart_check_flood(struct imx_port *sport, u32 usr2) +{ + /* To detect hardware 0xff flood we monitor RxD line between RX + * interrupts to isolate "receiving" of char(s) with no activity + * on RxD line, that'd never happen on actual data transfers. + * + * We use USR2_WAKE bit to check for activity on RxD line, but we have a + * race here if we clear USR2_WAKE when receiving of a char is in + * progress, so we might get RX interrupt later with USR2_WAKE bit + * cleared. Note though that as we don't try to clear USR2_WAKE when we + * detected no activity, this race may hide actual activity only once. + * + * Yet another case where receive interrupt may occur without RxD + * activity is expiration of aging timer, so we consider this as well. + * + * We use 'idle_counter' to ensure that we got at least so many RX + * interrupts without any detected activity on RxD line. 2 cases + * described plus 1 to be on the safe side gives us a margin of 3, + * below. In practice I was not able to produce a false positive to + * induce soft reset at regular data transfers even using 1 as the + * margin, so 3 is actually very strong. + * + * We count interrupts, not chars in 'idle-counter' for simplicity. + */ + + if (usr2 & USR2_WAKE) { + imx_uart_writel(sport, USR2_WAKE, USR2); + sport->idle_counter = 0; + } else if (++sport->idle_counter > 3) { + dev_warn(sport->port.dev, "RX flood detected: soft reset."); + imx_uart_soft_reset(sport); /* also clears 'sport->idle_counter' */ + } +} + +/* called with port.lock taken and irqs off */ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int rx, flg, ignored = 0; struct tty_port *port = &sport->port.state->port; + u32 usr2, rx; - while (imx_uart_readl(sport, USR2) & USR2_RDR) { - u32 usr2; + /* If we received something, check for 0xff flood */ + usr2 = imx_uart_readl(sport, USR2); + if (usr2 & USR2_RDR) + imx_uart_check_flood(sport, usr2); - flg = TTY_NORMAL; + while ((rx = imx_uart_readl(sport, URXD0)) & URXD_CHARRDY) { + unsigned int flg = TTY_NORMAL; sport->port.icount.rx++; - rx = imx_uart_readl(sport, URXD0); - - usr2 = imx_uart_readl(sport, USR2); - if (usr2 & USR2_BRCD) { - imx_uart_writel(sport, USR2_BRCD, USR2); - if (uart_handle_break(&sport->port)) - continue; - } - - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) - continue; - if (unlikely(rx & URXD_ERR)) { - if (rx & URXD_BRK) + if (rx & URXD_BRK) { sport->port.icount.brk++; + if (uart_handle_break(&sport->port)) + continue; + } else if (rx & URXD_PRERR) sport->port.icount.parity++; else if (rx & URXD_FRMERR) @@ -769,11 +889,8 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id) if (rx & URXD_OVRRUN) sport->port.icount.overrun++; - if (rx & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out; + if (rx & sport->port.ignore_status_mask) continue; - } rx &= (sport->port.read_status_mask | 0xFF); @@ -787,16 +904,17 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id) flg = TTY_OVERRUN; sport->port.sysrq = 0; + } else if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) { + continue; } if (sport->port.ignore_status_mask & URXD_DUMMY_READ) - goto out; + continue; if (tty_insert_flip_char(port, rx, flg) == 0) sport->port.icount.buf_overrun++; } -out: tty_flip_buffer_push(port); return IRQ_HANDLED; @@ -807,11 +925,11 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id) struct imx_port *sport = dev_id; irqreturn_t ret; - spin_lock(&sport->port.lock); + uart_port_lock(&sport->port); ret = __imx_uart_rxint(irq, dev_id); - spin_unlock(&sport->port.lock); + uart_port_unlock(&sport->port); return ret; } @@ -821,6 +939,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport); /* * We have a modem side uart, so the meanings of RTS and CTS are inverted. */ +/* called with port.lock taken and irqs off */ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) { unsigned int tmp = TIOCM_DSR; @@ -843,6 +962,8 @@ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) /* * Handle any change of modem status signal since we were last called. + * + * Called with port.lock taken and irqs off. */ static void imx_uart_mctrl_check(struct imx_port *sport) { @@ -874,7 +995,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; - spin_lock(&sport->port.lock); + uart_port_lock(&sport->port); usr1 = imx_uart_readl(sport, USR1); usr2 = imx_uart_readl(sport, USR2); @@ -944,7 +1065,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - spin_unlock(&sport->port.lock); + uart_port_unlock(&sport->port); return ret; } @@ -954,7 +1075,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) */ static unsigned int imx_uart_tx_empty(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int ret; ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; @@ -969,7 +1090,7 @@ static unsigned int imx_uart_tx_empty(struct uart_port *port) /* called with port.lock taken and irqs off */ static unsigned int imx_uart_get_mctrl(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int ret = imx_uart_get_hwmctrl(sport); mctrl_gpio_get(sport->gpios, &ret); @@ -980,7 +1101,7 @@ static unsigned int imx_uart_get_mctrl(struct uart_port *port) /* called with port.lock taken and irqs off */ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); u32 ucr3, uts; if (!(port->rs485.flags & SER_RS485_ENABLED)) { @@ -1023,11 +1144,11 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) */ static void imx_uart_break_ctl(struct uart_port *port, int break_state) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr1; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK; @@ -1036,7 +1157,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state) imx_uart_writel(sport, ucr1, UCR1); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } /* @@ -1045,13 +1166,13 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state) */ static void imx_uart_timeout(struct timer_list *t) { - struct imx_port *sport = from_timer(sport, t, timer); + struct imx_port *sport = timer_container_of(sport, t, timer); unsigned long flags; if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); imx_uart_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); } @@ -1081,55 +1202,62 @@ static void imx_uart_dma_rx_callback(void *data) status = dmaengine_tx_status(chan, sport->rx_cookie, &state); if (status == DMA_ERROR) { + uart_port_lock(&sport->port); imx_uart_clear_rx_errors(sport); + uart_port_unlock(&sport->port); return; } - if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { + /* + * The state-residue variable represents the empty space + * relative to the entire buffer. Taking this in consideration + * the head is always calculated base on the buffer total + * length - DMA transaction residue. The UART script from the + * SDMA firmware will jump to the next buffer descriptor, + * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4). + * Taking this in consideration the tail is always at the + * beginning of the buffer descriptor that contains the head. + */ - /* - * The state-residue variable represents the empty space - * relative to the entire buffer. Taking this in consideration - * the head is always calculated base on the buffer total - * length - DMA transaction residue. The UART script from the - * SDMA firmware will jump to the next buffer descriptor, - * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4). - * Taking this in consideration the tail is always at the - * beginning of the buffer descriptor that contains the head. - */ + /* Calculate the head */ + rx_ring->head = sg_dma_len(sgl) - state.residue; - /* Calculate the head */ - rx_ring->head = sg_dma_len(sgl) - state.residue; + /* Calculate the tail. */ + bd_size = sg_dma_len(sgl) / sport->rx_periods; + rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size; - /* Calculate the tail. */ - bd_size = sg_dma_len(sgl) / sport->rx_periods; - rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size; + if (rx_ring->head <= sg_dma_len(sgl) && + rx_ring->head > rx_ring->tail) { - if (rx_ring->head <= sg_dma_len(sgl) && - rx_ring->head > rx_ring->tail) { + /* Move data from tail to head */ + r_bytes = rx_ring->head - rx_ring->tail; - /* Move data from tail to head */ - r_bytes = rx_ring->head - rx_ring->tail; + /* If we received something, check for 0xff flood */ + uart_port_lock(&sport->port); + imx_uart_check_flood(sport, imx_uart_readl(sport, USR2)); + uart_port_unlock(&sport->port); + + if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { /* CPU claims ownership of RX DMA buffer */ dma_sync_sg_for_cpu(sport->port.dev, sgl, 1, - DMA_FROM_DEVICE); + DMA_FROM_DEVICE); w_bytes = tty_insert_flip_string(port, - sport->rx_buf + rx_ring->tail, r_bytes); + sport->rx_buf + rx_ring->tail, r_bytes); /* UART retrieves ownership of RX DMA buffer */ dma_sync_sg_for_device(sport->port.dev, sgl, 1, - DMA_FROM_DEVICE); + DMA_FROM_DEVICE); if (w_bytes != r_bytes) sport->port.icount.buf_overrun++; sport->port.icount.rx += w_bytes; - } else { - WARN_ON(rx_ring->head > sg_dma_len(sgl)); - WARN_ON(rx_ring->head <= rx_ring->tail); } + } else { + WARN_ON(rx_ring->head > sg_dma_len(sgl)); + WARN_ON(rx_ring->head <= rx_ring->tail); } if (w_bytes) { @@ -1138,10 +1266,6 @@ static void imx_uart_dma_rx_callback(void *data) } } -/* RX DMA buffer periods */ -#define RX_DMA_PERIODS 16 -#define RX_BUF_SIZE (RX_DMA_PERIODS * PAGE_SIZE / 4) - static int imx_uart_start_rx_dma(struct imx_port *sport) { struct scatterlist *sgl = &sport->rx_sgl; @@ -1152,9 +1276,8 @@ static int imx_uart_start_rx_dma(struct imx_port *sport) sport->rx_ring.head = 0; sport->rx_ring.tail = 0; - sport->rx_periods = RX_DMA_PERIODS; - sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); + sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size); ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); if (ret == 0) { dev_err(dev, "DMA mapping error for RX.\n"); @@ -1180,6 +1303,7 @@ static int imx_uart_start_rx_dma(struct imx_port *sport) return 0; } +/* called with port.lock taken and irqs off */ static void imx_uart_clear_rx_errors(struct imx_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -1210,10 +1334,13 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport) imx_uart_writel(sport, USR2_ORE, USR2); } + sport->idle_counter = 0; + } -#define TXTL_DEFAULT 2 /* reset default */ -#define RXTL_DEFAULT 1 /* reset default */ +#define TXTL_DEFAULT 8 +#define RXTL_DEFAULT 8 /* 8 characters or aging timer */ +#define RXTL_CONSOLE_DEFAULT 1 #define TXTL_DMA 8 /* DMA burst setting */ #define RXTL_DMA 9 /* DMA burst setting */ @@ -1250,15 +1377,18 @@ static int imx_uart_dma_init(struct imx_port *sport) { struct dma_slave_config slave_config = {}; struct device *dev = sport->port.dev; + struct dma_chan *chan; int ret; /* Prepare for RX : */ - sport->dma_chan_rx = dma_request_slave_channel(dev, "rx"); - if (!sport->dma_chan_rx) { + chan = dma_request_chan(dev, "rx"); + if (IS_ERR(chan)) { dev_dbg(dev, "cannot get the DMA channel.\n"); - ret = -EINVAL; + sport->dma_chan_rx = NULL; + ret = PTR_ERR(chan); goto err; } + sport->dma_chan_rx = chan; slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = sport->port.mapbase + URXD0; @@ -1271,7 +1401,8 @@ static int imx_uart_dma_init(struct imx_port *sport) goto err; } - sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); + sport->rx_buf_size = sport->rx_period_length * sport->rx_periods; + sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL); if (!sport->rx_buf) { ret = -ENOMEM; goto err; @@ -1279,12 +1410,14 @@ static int imx_uart_dma_init(struct imx_port *sport) sport->rx_ring.buf = sport->rx_buf; /* Prepare for TX : */ - sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); - if (!sport->dma_chan_tx) { + chan = dma_request_chan(dev, "tx"); + if (IS_ERR(chan)) { dev_err(dev, "cannot get the TX DMA channel!\n"); - ret = -EINVAL; + sport->dma_chan_tx = NULL; + ret = PTR_ERR(chan); goto err; } + sport->dma_chan_tx = chan; slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = sport->port.mapbase + URTX0; @@ -1302,6 +1435,7 @@ err: return ret; } +/* called with port.lock taken and irqs off */ static void imx_uart_enable_dma(struct imx_port *sport) { u32 ucr1; @@ -1325,7 +1459,7 @@ static void imx_uart_disable_dma(struct imx_port *sport) ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); imx_uart_writel(sport, ucr1, UCR1); - imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl); sport->dma_is_enabled = 0; } @@ -1335,8 +1469,8 @@ static void imx_uart_disable_dma(struct imx_port *sport) static int imx_uart_startup(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - int retval, i; + struct imx_port *sport = to_imx_port(port); + int retval; unsigned long flags; int dma_is_inited = 0; u32 ucr1, ucr2, ucr3, ucr4; @@ -1350,7 +1484,12 @@ static int imx_uart_startup(struct uart_port *port) return retval; } - imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + if (uart_console(&sport->port)) + sport->rxtl = RXTL_CONSOLE_DEFAULT; + else + sport->rxtl = RXTL_DEFAULT; + + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs @@ -1364,19 +1503,15 @@ static int imx_uart_startup(struct uart_port *port) imx_uart_writel(sport, ucr4 & ~UCR4_DREN, UCR4); /* Can we enable the DMA support? */ - if (!uart_console(port) && imx_uart_dma_init(sport) == 0) + if (!uart_console(port) && imx_uart_dma_init(sport) == 0) { + lockdep_set_subclass(&port->lock, 1); dma_is_inited = 1; + } - spin_lock_irqsave(&sport->port.lock, flags); - /* Reset fifo's and state machines */ - i = 100; - - ucr2 = imx_uart_readl(sport, UCR2); - ucr2 &= ~UCR2_SRST; - imx_uart_writel(sport, ucr2, UCR2); + uart_port_lock_irqsave(&sport->port, &flags); - while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) - udelay(1); + /* Reset fifo's and state machines */ + imx_uart_soft_reset(sport); /* * Finally, clear and enable interrupts @@ -1392,7 +1527,7 @@ static int imx_uart_startup(struct uart_port *port) imx_uart_writel(sport, ucr1, UCR1); ucr4 = imx_uart_readl(sport, UCR4) & ~(UCR4_OREN | UCR4_INVR); - if (!sport->dma_is_enabled) + if (!dma_is_inited) ucr4 |= UCR4_OREN; if (sport->inverted_rx) ucr4 |= UCR4_INVR; @@ -1444,16 +1579,19 @@ static int imx_uart_startup(struct uart_port *port) imx_uart_writel(sport, ucr2, UCR2); } - spin_unlock_irqrestore(&sport->port.lock, flags); + imx_uart_disable_loopback_rs485(sport); + + uart_port_unlock_irqrestore(&sport->port, flags); return 0; } static void imx_uart_shutdown(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; - u32 ucr1, ucr2, ucr4; + u32 ucr1, ucr2, ucr4, uts; + int loops; if (sport->dma_is_enabled) { dmaengine_terminate_sync(sport->dma_chan_tx); @@ -1469,41 +1607,104 @@ static void imx_uart_shutdown(struct uart_port *port) sport->dma_is_rxing = 0; } - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); imx_uart_stop_tx(port); imx_uart_stop_rx(port); imx_uart_disable_dma(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); imx_uart_dma_exit(sport); } - mctrl_gpio_disable_ms(sport->gpios); + mctrl_gpio_disable_ms_sync(sport->gpios); - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); ucr2 = imx_uart_readl(sport, UCR2); ucr2 &= ~(UCR2_TXEN | UCR2_ATEN); imx_uart_writel(sport, ucr2, UCR2); - - ucr4 = imx_uart_readl(sport, UCR4); - ucr4 &= ~UCR4_OREN; - imx_uart_writel(sport, ucr4, UCR4); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); /* * Stop our timer. */ - del_timer_sync(&sport->timer); + timer_delete_sync(&sport->timer); /* * Disable all interrupts, port and break condition. */ - spin_lock_irqsave(&sport->port.lock, flags); - ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); + uart_port_lock_irqsave(&sport->port, &flags); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | + UCR1_ATDMAEN | UCR1_SNDBRK); + /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */ + if (port->rs485.flags & SER_RS485_ENABLED && + port->rs485.flags & SER_RS485_RTS_ON_SEND && + sport->have_rtscts && !sport->have_rtsgpio) { + uts = imx_uart_readl(sport, imx_uart_uts_reg(sport)); + uts |= UTS_LOOP; + imx_uart_writel(sport, uts, imx_uart_uts_reg(sport)); + ucr1 |= UCR1_UARTEN; + } else { + ucr1 &= ~UCR1_UARTEN; + } imx_uart_writel(sport, ucr1, UCR1); - spin_unlock_irqrestore(&sport->port.lock, flags); + + ucr4 = imx_uart_readl(sport, UCR4); + ucr4 &= ~UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); + + /* + * We have to ensure the tx state machine ends up in OFF. This + * is especially important for rs485 where we must not leave + * the RTS signal high, blocking the bus indefinitely. + * + * All interrupts are now disabled, so imx_uart_stop_tx() will + * no longer be called from imx_uart_transmit_buffer(). It may + * still be called via the hrtimers, and if those are in play, + * we have to honour the delays. + */ + if (sport->tx_state == WAIT_AFTER_RTS || sport->tx_state == SEND) + imx_uart_stop_tx(port); + + /* + * In many cases (rs232 mode, or if tx_state was + * WAIT_AFTER_RTS, or if tx_state was SEND and there is no + * delay_rts_after_send), this will have moved directly to + * OFF. In rs485 mode, tx_state might already have been + * WAIT_AFTER_SEND and the hrtimer thus already started, or + * the above imx_uart_stop_tx() call could have started it. In + * those cases, we have to wait for the hrtimer to fire and + * complete the transition to OFF. + */ + loops = port->rs485.flags & SER_RS485_ENABLED ? + port->rs485.delay_rts_after_send : 0; + while (sport->tx_state != OFF && loops--) { + uart_port_unlock_irqrestore(&sport->port, flags); + msleep(1); + uart_port_lock_irqsave(&sport->port, &flags); + } + + if (sport->tx_state != OFF) { + dev_warn(sport->port.dev, "unexpected tx_state %d\n", + sport->tx_state); + /* + * This machine may be busted, but ensure the RTS + * signal is inactive in order not to block other + * devices. + */ + if (port->rs485.flags & SER_RS485_ENABLED) { + ucr2 = imx_uart_readl(sport, UCR2); + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + imx_uart_rts_active(sport, &ucr2); + else + imx_uart_rts_inactive(sport, &ucr2); + imx_uart_writel(sport, ucr2, UCR2); + } + sport->tx_state = OFF; + } + + uart_port_unlock_irqrestore(&sport->port, flags); clk_disable_unprepare(sport->clk_per); clk_disable_unprepare(sport->clk_ipg); @@ -1512,10 +1713,8 @@ static void imx_uart_shutdown(struct uart_port *port) /* called with port.lock taken and irqs off */ static void imx_uart_flush_buffer(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); struct scatterlist *sgl = &sport->tx_sgl[0]; - u32 ucr2; - int i = 100, ubir, ubmr, uts; if (!sport->dma_chan_tx) return; @@ -1533,39 +1732,15 @@ static void imx_uart_flush_buffer(struct uart_port *port) sport->dma_is_txing = 0; } - /* - * According to the Reference Manual description of the UART SRST bit: - * - * "Reset the transmit and receive state machines, - * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD - * and UTS[6-3]". - * - * We don't need to restore the old values from USR1, USR2, URXD and - * UTXD. UBRC is read only, so only save/restore the other three - * registers. - */ - ubir = imx_uart_readl(sport, UBIR); - ubmr = imx_uart_readl(sport, UBMR); - uts = imx_uart_readl(sport, IMX21_UTS); - - ucr2 = imx_uart_readl(sport, UCR2); - ucr2 &= ~UCR2_SRST; - imx_uart_writel(sport, ucr2, UCR2); + imx_uart_soft_reset(sport); - while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) - udelay(1); - - /* Restore the registers */ - imx_uart_writel(sport, ubir, UBIR); - imx_uart_writel(sport, ubmr, UBMR); - imx_uart_writel(sport, uts, IMX21_UTS); } static void imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr2, old_ucr2, ufcr; unsigned int baud, quot; @@ -1584,7 +1759,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, old_csize = CS8; } - del_timer_sync(&sport->timer); + timer_delete_sync(&sport->timer); /* * Ask the core to calculate the divisor for us. @@ -1592,7 +1767,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); quot = uart_get_divisor(port, baud); - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); /* * Read current UCR2 and save it for future use, then clear all the bits @@ -1630,7 +1805,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CRTSCTS) ucr2 &= ~UCR2_IRTS; - if (termios->c_cflag & CSTOPB) ucr2 |= UCR2_STPB; if (termios->c_cflag & PARENB) { @@ -1721,14 +1895,12 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) imx_uart_enable_ms(&sport->port); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } static const char *imx_uart_type(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - - return sport->port.type == PORT_IMX ? "IMX" : NULL; + return port->type == PORT_IMX ? "IMX" : NULL; } /* @@ -1736,10 +1908,8 @@ static const char *imx_uart_type(struct uart_port *port) */ static void imx_uart_config_port(struct uart_port *port, int flags) { - struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE) - sport->port.type = PORT_IMX; + port->type = PORT_IMX; } /* @@ -1750,20 +1920,19 @@ static void imx_uart_config_port(struct uart_port *port, int flags) static int imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct imx_port *sport = (struct imx_port *)port; int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX) ret = -EINVAL; - if (sport->port.irq != ser->irq) + if (port->irq != ser->irq) ret = -EINVAL; if (ser->io_type != UPIO_MEM) ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) + if (port->uartclk / 16 != ser->baud_base) ret = -EINVAL; - if (sport->port.mapbase != (unsigned long)ser->iomem_base) + if (port->mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; - if (sport->port.iobase != ser->port) + if (port->iobase != ser->port) ret = -EINVAL; if (ser->hub6 != 0) ret = -EINVAL; @@ -1774,7 +1943,7 @@ imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) static int imx_uart_poll_init(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr1, ucr2; int retval; @@ -1786,9 +1955,9 @@ static int imx_uart_poll_init(struct uart_port *port) if (retval) clk_disable_unprepare(sport->clk_ipg); - imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl); - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); /* * Be careful about the order of enabling bits here. First enable the @@ -1806,7 +1975,7 @@ static int imx_uart_poll_init(struct uart_port *port) ucr1 |= UCR1_UARTEN; ucr1 &= ~(UCR1_TRDYEN | UCR1_RTSDEN | UCR1_RRDYEN); - ucr2 |= UCR2_RXEN; + ucr2 |= UCR2_RXEN | UCR2_TXEN; ucr2 &= ~UCR2_ATEN; imx_uart_writel(sport, ucr1, UCR1); @@ -1816,14 +1985,14 @@ static int imx_uart_poll_init(struct uart_port *port) imx_uart_writel(sport, ucr1 | UCR1_RRDYEN, UCR1); imx_uart_writel(sport, ucr2 | UCR2_ATEN, UCR2); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); return 0; } static int imx_uart_poll_get_char(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); if (!(imx_uart_readl(sport, USR2) & USR2_RDR)) return NO_POLL_CHAR; @@ -1832,7 +2001,7 @@ static int imx_uart_poll_get_char(struct uart_port *port) static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int status; /* drain */ @@ -1851,19 +2020,11 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) #endif /* called with port.lock taken and irqs off or from .probe without locking */ -static int imx_uart_rs485_config(struct uart_port *port, +static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { - struct imx_port *sport = (struct imx_port *)port; - u32 ucr2; - - /* unimplemented */ - rs485conf->delay_rts_before_send = 0; - rs485conf->delay_rts_after_send = 0; - - /* RTS is required to control the transmitter */ - if (!sport->have_rtscts && !sport->have_rtsgpio) - rs485conf->flags &= ~SER_RS485_ENABLED; + struct imx_port *sport = to_imx_port(port); + u32 ucr2, ufcr; if (rs485conf->flags & SER_RS485_ENABLED) { /* Enable receiver if low-active RTS signal is requested */ @@ -1882,10 +2043,13 @@ static int imx_uart_rs485_config(struct uart_port *port, /* Make sure Rx is enabled in case Tx is active with Rx disabled */ if (!(rs485conf->flags & SER_RS485_ENABLED) || - rs485conf->flags & SER_RS485_RX_DURING_TX) + rs485conf->flags & SER_RS485_RX_DURING_TX) { + /* If the receiver trigger is 0, set it to a default value */ + ufcr = imx_uart_readl(sport, UFCR); + if ((ufcr & UFCR_RXTL_MASK) == 0) + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl); imx_uart_start_rx(port); - - port->rs485 = *rs485conf; + } return 0; } @@ -1915,45 +2079,43 @@ static const struct uart_ops imx_uart_pops = { static struct imx_port *imx_uart_ports[UART_NR]; -#ifdef CONFIG_SERIAL_IMX_CONSOLE -static void imx_uart_console_putchar(struct uart_port *port, int ch) +#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) +static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) barrier(); imx_uart_writel(sport, ch, URTX0); + + sport->last_putchar_was_newline = (ch == '\n'); } -/* - * Interrupts are disabled on entering - */ -static void -imx_uart_console_write(struct console *co, const char *s, unsigned int count) +static void imx_uart_console_device_lock(struct console *co, unsigned long *flags) +{ + struct uart_port *up = &imx_uart_ports[co->index]->port; + + return __uart_port_lock_irqsave(up, flags); +} + +static void imx_uart_console_device_unlock(struct console *co, unsigned long flags) +{ + struct uart_port *up = &imx_uart_ports[co->index]->port; + + return __uart_port_unlock_irqrestore(up, flags); +} + +static void imx_uart_console_write_atomic(struct console *co, + struct nbcon_write_context *wctxt) { struct imx_port *sport = imx_uart_ports[co->index]; + struct uart_port *port = &sport->port; struct imx_port_ucrs old_ucr; - unsigned int ucr1; - unsigned long flags = 0; - int locked = 1; - int retval; + unsigned int ucr1, usr2; - retval = clk_enable(sport->clk_per); - if (retval) + if (!nbcon_enter_unsafe(wctxt)) return; - retval = clk_enable(sport->clk_ipg); - if (retval) { - clk_disable(sport->clk_per); - return; - } - - if (sport->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock_irqsave(&sport->port.lock, flags); - else - spin_lock_irqsave(&sport->port.lock, flags); /* * First, save UCR1/2/3 and then disable interrupts @@ -1967,31 +2129,95 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); - imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); - uart_console_write(&sport->port, s, count, imx_uart_console_putchar); + if (!sport->last_putchar_was_newline) + uart_console_write(port, "\n", 1, imx_uart_console_putchar); + uart_console_write(port, wctxt->outbuf, wctxt->len, + imx_uart_console_putchar); /* * Finally, wait for transmitter to become empty * and restore UCR1/2/3 */ - while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)); - + read_poll_timeout_atomic(imx_uart_readl, usr2, usr2 & USR2_TXDC, + 0, USEC_PER_SEC, false, sport, USR2); imx_uart_ucrs_restore(sport, &old_ucr); - if (locked) - spin_unlock_irqrestore(&sport->port.lock, flags); + nbcon_exit_unsafe(wctxt); +} - clk_disable(sport->clk_ipg); - clk_disable(sport->clk_per); +static void imx_uart_console_write_thread(struct console *co, + struct nbcon_write_context *wctxt) +{ + struct imx_port *sport = imx_uart_ports[co->index]; + struct uart_port *port = &sport->port; + struct imx_port_ucrs old_ucr; + unsigned int ucr1, usr2; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + /* + * First, save UCR1/2/3 and then disable interrupts + */ + imx_uart_ucrs_save(sport, &old_ucr); + ucr1 = old_ucr.ucr1; + + if (imx_uart_is_imx1(sport)) + ucr1 |= IMX1_UCR1_UARTCLKEN; + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); + + imx_uart_writel(sport, ucr1, UCR1); + imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); + + if (nbcon_exit_unsafe(wctxt)) { + int len = READ_ONCE(wctxt->len); + int i; + + /* + * Write out the message. Toggle unsafe for each byte in order + * to give another (higher priority) context the opportunity + * for a friendly takeover. If such a takeover occurs, this + * context must reacquire ownership in order to perform final + * actions (such as re-enabling the interrupts). + * + * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid + * after a reacquire so writing the message must be + * aborted. + */ + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + + uart_console_write(port, wctxt->outbuf + i, 1, + imx_uart_console_putchar); + + if (!nbcon_exit_unsafe(wctxt)) + break; + } + } + + while (!nbcon_enter_unsafe(wctxt)) + nbcon_reacquire_nobuf(wctxt); + + /* + * Finally, wait for transmitter to become empty + * and restore UCR1/2/3 + */ + read_poll_timeout(imx_uart_readl, usr2, usr2 & USR2_TXDC, + 0, USEC_PER_SEC, false, sport, USR2); + imx_uart_ucrs_restore(sport, &old_ucr); + + nbcon_exit_unsafe(wctxt); } /* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. */ -static void __init +static void imx_uart_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { @@ -2050,7 +2276,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud, } } -static int __init +static int imx_uart_console_setup(struct console *co, char *options) { struct imx_port *sport; @@ -2076,75 +2302,58 @@ imx_uart_console_setup(struct console *co, char *options) if (retval) goto error_console; + sport->last_putchar_was_newline = true; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else imx_uart_console_get_options(sport, &baud, &parity, &bits); - imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl); retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); - clk_disable(sport->clk_ipg); if (retval) { - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); goto error_console; } - retval = clk_prepare(sport->clk_per); + retval = clk_prepare_enable(sport->clk_per); if (retval) - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); error_console: return retval; } +static int +imx_uart_console_exit(struct console *co) +{ + struct imx_port *sport = imx_uart_ports[co->index]; + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); + + return 0; +} + static struct uart_driver imx_uart_uart_driver; static struct console imx_uart_console = { .name = DEV_NAME, - .write = imx_uart_console_write, + .write_atomic = imx_uart_console_write_atomic, + .write_thread = imx_uart_console_write_thread, + .device_lock = imx_uart_console_device_lock, + .device_unlock = imx_uart_console_device_unlock, + .flags = CON_PRINTBUFFER | CON_NBCON, .device = uart_console_device, .setup = imx_uart_console_setup, - .flags = CON_PRINTBUFFER, + .exit = imx_uart_console_exit, .index = -1, .data = &imx_uart_uart_driver, }; #define IMX_CONSOLE &imx_uart_console -#ifdef CONFIG_OF -static void imx_uart_console_early_putchar(struct uart_port *port, int ch) -{ - struct imx_port *sport = (struct imx_port *)port; - - while (imx_uart_readl(sport, IMX21_UTS) & UTS_TXFULL) - cpu_relax(); - - imx_uart_writel(sport, ch, URTX0); -} - -static void imx_uart_console_early_write(struct console *con, const char *s, - unsigned count) -{ - struct earlycon_device *dev = con->data; - - uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar); -} - -static int __init -imx_console_early_setup(struct earlycon_device *dev, const char *opt) -{ - if (!dev->port.membase) - return -ENODEV; - - dev->con->write = imx_uart_console_early_write; - - return 0; -} -OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup); -OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup); -#endif - #else #define IMX_CONSOLE NULL #endif @@ -2159,76 +2368,51 @@ static struct uart_driver imx_uart_uart_driver = { .cons = IMX_CONSOLE, }; -#ifdef CONFIG_OF -/* - * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it - * could successfully get all information from dt or a negative errno. - */ -static int imx_uart_probe_dt(struct imx_port *sport, - struct platform_device *pdev) +static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t) { - struct device_node *np = pdev->dev.of_node; - int ret; - - sport->devdata = of_device_get_match_data(&pdev->dev); - if (!sport->devdata) - /* no device tree device */ - return 1; - - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); - return ret; - } - sport->port.line = ret; - - if (of_get_property(np, "uart-has-rtscts", NULL) || - of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) - sport->have_rtscts = 1; - - if (of_get_property(np, "fsl,dte-mode", NULL)) - sport->dte_mode = 1; - - if (of_get_property(np, "rts-gpios", NULL)) - sport->have_rtsgpio = 1; - - if (of_get_property(np, "fsl,inverted-tx", NULL)) - sport->inverted_tx = 1; + struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx); + unsigned long flags; - if (of_get_property(np, "fsl,inverted-rx", NULL)) - sport->inverted_rx = 1; + uart_port_lock_irqsave(&sport->port, &flags); + if (sport->tx_state == WAIT_AFTER_RTS) + imx_uart_start_tx(&sport->port); + uart_port_unlock_irqrestore(&sport->port, flags); - return 0; -} -#else -static inline int imx_uart_probe_dt(struct imx_port *sport, - struct platform_device *pdev) -{ - return 1; + return HRTIMER_NORESTART; } -#endif -static void imx_uart_probe_pdata(struct imx_port *sport, - struct platform_device *pdev) +static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) { - struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev); - - sport->port.line = pdev->id; - sport->devdata = (struct imx_uart_data *) pdev->id_entry->driver_data; + struct imx_port *sport = container_of(t, struct imx_port, trigger_stop_tx); + unsigned long flags; - if (!pdata) - return; + uart_port_lock_irqsave(&sport->port, &flags); + if (sport->tx_state == WAIT_AFTER_SEND) + imx_uart_stop_tx(&sport->port); + uart_port_unlock_irqrestore(&sport->port, flags); - if (pdata->flags & IMXUART_HAVE_RTSCTS) - sport->have_rtscts = 1; + return HRTIMER_NORESTART; } +static const struct serial_rs485 imx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + +/* Default RX DMA buffer configuration */ +#define RX_DMA_PERIODS 16 +#define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4) + static int imx_uart_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct imx_port *sport; void __iomem *base; + u32 dma_buf_conf[2]; int ret = 0; - u32 ucr1; + u32 ucr1, ucr2, uts; struct resource *res; int txirq, rxirq, rtsirq; @@ -2236,11 +2420,33 @@ static int imx_uart_probe(struct platform_device *pdev) if (!sport) return -ENOMEM; - ret = imx_uart_probe_dt(sport, pdev); - if (ret > 0) - imx_uart_probe_pdata(sport, pdev); - else if (ret < 0) + sport->devdata = of_device_get_match_data(&pdev->dev); + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); return ret; + } + sport->port.line = ret; + + sport->have_rtscts = of_property_read_bool(np, "uart-has-rtscts") || + of_property_read_bool(np, "fsl,uart-has-rtscts"); /* deprecated */ + + sport->dte_mode = of_property_read_bool(np, "fsl,dte-mode"); + + sport->have_rtsgpio = of_property_present(np, "rts-gpios"); + + sport->inverted_tx = of_property_read_bool(np, "fsl,inverted-tx"); + + sport->inverted_rx = of_property_read_bool(np, "fsl,inverted-rx"); + + if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) { + sport->rx_period_length = dma_buf_conf[0]; + sport->rx_periods = dma_buf_conf[1]; + } else { + sport->rx_period_length = RX_DMA_PERIOD_LEN; + sport->rx_periods = RX_DMA_PERIODS; + } if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", @@ -2248,8 +2454,7 @@ static int imx_uart_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); @@ -2262,13 +2467,16 @@ static int imx_uart_probe(struct platform_device *pdev) sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; sport->port.membase = base; - sport->port.type = PORT_IMX, + sport->port.type = PORT_IMX; sport->port.iotype = UPIO_MEM; sport->port.irq = rxirq; sport->port.fifosize = 32; sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE); sport->port.ops = &imx_uart_pops; sport->port.rs485_config = imx_uart_rs485_config; + /* RTS is required to control the RS485 transmitter */ + if (sport->have_rtscts || sport->have_rtsgpio) + sport->port.rs485_supported = imx_rs485_supported; sport->port.flags = UPF_BOOT_AUTOCONF; timer_setup(&sport->timer, imx_uart_timeout, 0); @@ -2295,26 +2503,13 @@ static int imx_uart_probe(struct platform_device *pdev) /* For register access, we only need to enable the ipg clock. */ ret = clk_prepare_enable(sport->clk_ipg); if (ret) { - dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret); + dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret); return ret; } - /* initialize shadow register values */ - sport->ucr1 = readl(sport->port.membase + UCR1); - sport->ucr2 = readl(sport->port.membase + UCR2); - sport->ucr3 = readl(sport->port.membase + UCR3); - sport->ucr4 = readl(sport->port.membase + UCR4); - sport->ufcr = readl(sport->port.membase + UFCR); - ret = uart_get_rs485_mode(&sport->port); - if (ret) { - clk_disable_unprepare(sport->clk_ipg); - return ret; - } - - if (sport->port.rs485.flags & SER_RS485_ENABLED && - (!sport->have_rtscts && !sport->have_rtsgpio)) - dev_err(&pdev->dev, "no RTS control, disabling rs485\n"); + if (ret) + goto err_clk; /* * If using the i.MX UART RTS/CTS control then the RTS (CTS_B) @@ -2328,14 +2523,41 @@ static int imx_uart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "low-active RTS not possible when receiver is off, enabling receiver\n"); - imx_uart_rs485_config(&sport->port, &sport->port.rs485); - /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | - UCR1_TRDYEN | UCR1_RTSDEN); + ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); + /* Disable Ageing Timer interrupt */ + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~UCR2_ATEN; + imx_uart_writel(sport, ucr2, UCR2); + + /* + * In case RS485 is enabled without GPIO RTS control, the UART IP + * is used to control CTS signal. Keep both the UART and Receiver + * enabled, otherwise the UART IP pulls CTS signal always HIGH no + * matter how the UCR2 CTSC and CTS bits are set. To prevent any + * data from being fed into the RX FIFO, enable loopback mode in + * UTS register, which disconnects the RX path from external RXD + * pin and connects it to the Transceiver, which is disabled, so + * no data can be fed to the RX FIFO that way. + */ + if (sport->port.rs485.flags & SER_RS485_ENABLED && + sport->have_rtscts && !sport->have_rtsgpio) { + uts = imx_uart_readl(sport, imx_uart_uts_reg(sport)); + uts |= UTS_LOOP; + imx_uart_writel(sport, uts, imx_uart_uts_reg(sport)); + + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_UARTEN; + imx_uart_writel(sport, ucr1, UCR1); + + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 |= UCR2_RXEN; + imx_uart_writel(sport, ucr2, UCR2); + } + if (!imx_uart_is_imx1(sport) && sport->dte_mode) { /* * The DCEDTE bit changes the direction of DSR, DCD, DTR and RI @@ -2367,7 +2589,10 @@ static int imx_uart_probe(struct platform_device *pdev) imx_uart_writel(sport, ucr3, UCR3); } - clk_disable_unprepare(sport->clk_ipg); + hrtimer_setup(&sport->trigger_start_tx, imx_trigger_start_tx, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hrtimer_setup(&sport->trigger_stop_tx, imx_trigger_stop_tx, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later @@ -2379,7 +2604,7 @@ static int imx_uart_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request rx irq: %d\n", ret); - return ret; + goto err_clk; } ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0, @@ -2387,7 +2612,7 @@ static int imx_uart_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request tx irq: %d\n", ret); - return ret; + goto err_clk; } ret = devm_request_irq(&pdev->dev, rtsirq, imx_uart_rtsint, 0, @@ -2395,41 +2620,43 @@ static int imx_uart_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request rts irq: %d\n", ret); - return ret; + goto err_clk; } } else { ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0, dev_name(&pdev->dev), sport); if (ret) { dev_err(&pdev->dev, "failed to request irq: %d\n", ret); - return ret; + goto err_clk; } } - /* We need to initialize lock even for non-registered console */ - spin_lock_init(&sport->port.lock); - imx_uart_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); - return uart_add_one_port(&imx_uart_uart_driver, &sport->port); + ret = uart_add_one_port(&imx_uart_uart_driver, &sport->port); + +err_clk: + clk_disable_unprepare(sport->clk_ipg); + + return ret; } -static int imx_uart_remove(struct platform_device *pdev) +static void imx_uart_remove(struct platform_device *pdev) { struct imx_port *sport = platform_get_drvdata(pdev); - return uart_remove_one_port(&imx_uart_uart_driver, &sport->port); + uart_remove_one_port(&imx_uart_uart_driver, &sport->port); } static void imx_uart_restore_context(struct imx_port *sport) { unsigned long flags; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); if (!sport->context_saved) { - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); return; } @@ -2444,7 +2671,7 @@ static void imx_uart_restore_context(struct imx_port *sport) imx_uart_writel(sport, sport->saved_reg[2], UCR3); imx_uart_writel(sport, sport->saved_reg[3], UCR4); sport->context_saved = false; - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } static void imx_uart_save_context(struct imx_port *sport) @@ -2452,7 +2679,7 @@ static void imx_uart_save_context(struct imx_port *sport) unsigned long flags; /* Save necessary regs */ - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); sport->saved_reg[0] = imx_uart_readl(sport, UCR1); sport->saved_reg[1] = imx_uart_readl(sport, UCR2); sport->saved_reg[2] = imx_uart_readl(sport, UCR3); @@ -2464,30 +2691,57 @@ static void imx_uart_save_context(struct imx_port *sport) sport->saved_reg[8] = imx_uart_readl(sport, UBMR); sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS); sport->context_saved = true; - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } +/* called with irq off */ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) { - u32 ucr3; + struct tty_port *port = &sport->port.state->port; + struct device *tty_dev; + bool may_wake = false, wake_active = false; + u32 ucr3, usr1; + + scoped_guard(tty_port_tty, port) { + struct tty_struct *tty = scoped_tty(); + + tty_dev = tty->dev; + may_wake = tty_dev && device_may_wakeup(tty_dev); + } + + /* only configure the wake register when device set as wakeup source */ + if (!may_wake) + return; + + uart_port_lock_irq(&sport->port); + usr1 = imx_uart_readl(sport, USR1); ucr3 = imx_uart_readl(sport, UCR3); if (on) { imx_uart_writel(sport, USR1_AWAKE, USR1); ucr3 |= UCR3_AWAKEN; } else { ucr3 &= ~UCR3_AWAKEN; + wake_active = usr1 & USR1_AWAKE; } imx_uart_writel(sport, ucr3, UCR3); if (sport->have_rtscts) { u32 ucr1 = imx_uart_readl(sport, UCR1); - if (on) + if (on) { + imx_uart_writel(sport, USR1_RTSD, USR1); ucr1 |= UCR1_RTSDEN; - else + } else { ucr1 &= ~UCR1_RTSDEN; + wake_active = wake_active || (usr1 & USR1_RTSD); + } imx_uart_writel(sport, ucr1, UCR1); } + + if (wake_active && irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq))) + pm_wakeup_event(tty_port_tty_get(port)->dev, 0); + + uart_port_unlock_irq(&sport->port); } static int imx_uart_suspend_noirq(struct device *dev) @@ -2576,6 +2830,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = { .suspend_noirq = imx_uart_suspend_noirq, .resume_noirq = imx_uart_resume_noirq, .freeze_noirq = imx_uart_suspend_noirq, + .thaw_noirq = imx_uart_resume_noirq, .restore_noirq = imx_uart_resume_noirq, .suspend = imx_uart_suspend, .resume = imx_uart_resume, @@ -2588,7 +2843,6 @@ static struct platform_driver imx_uart_platform_driver = { .probe = imx_uart_probe, .remove = imx_uart_remove, - .id_table = imx_uart_devtype, .driver = { .name = "imx-uart", .of_match_table = imx_uart_dt_ids, diff --git a/drivers/tty/serial/imx_earlycon.c b/drivers/tty/serial/imx_earlycon.c new file mode 100644 index 000000000000..7aab38b2bd8c --- /dev/null +++ b/drivers/tty/serial/imx_earlycon.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/io.h> + +#define URTX0 0x40 /* Transmitter Register */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/ + +static void imx_uart_console_early_putchar(struct uart_port *port, unsigned char ch) +{ + while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL) + cpu_relax(); + + writel_relaxed(ch, port->membase + URTX0); +} + +static void imx_uart_console_early_write(struct console *con, const char *s, + unsigned count) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar); +} + +static int __init +imx_console_early_setup(struct earlycon_device *dev, const char *opt) +{ + if (!dev->port.membase) + return -ENODEV; + + dev->con->write = imx_uart_console_early_write; + + return 0; +} +OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup); +OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup); + +MODULE_AUTHOR("NXP"); +MODULE_DESCRIPTION("IMX earlycon driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 86fff69d7e7c..6e19c6713849 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -30,8 +30,9 @@ #include <linux/console.h> #include <linux/spinlock.h> #include <linux/init.h> +#include <linux/platform_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/sgialib.h> #include <asm/sgi/ioc.h> @@ -50,8 +51,9 @@ #define ZSDELAY_LONG() udelay(20) #define ZS_WSYNC(channel) do { } while (0) -#define NUM_IP22ZILOG 1 -#define NUM_CHANNELS (NUM_IP22ZILOG * 2) +#define NUM_CHANNELS 2 +#define CHANNEL_B 0 +#define CHANNEL_A 1 #define ZS_CLOCK 3672000 /* Zilog input clock rate. */ #define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ @@ -62,9 +64,6 @@ struct uart_ip22zilog_port { struct uart_port port; - /* IRQ servicing chain. */ - struct uart_ip22zilog_port *next; - /* Current values of Zilog write registers. */ unsigned char curregs[NUM_ZSREGS]; @@ -72,7 +71,6 @@ struct uart_ip22zilog_port { #define IP22ZILOG_FLAG_IS_CONS 0x00000004 #define IP22ZILOG_FLAG_IS_KGDB 0x00000008 #define IP22ZILOG_FLAG_MODEM_STATUS 0x00000010 -#define IP22ZILOG_FLAG_IS_CHANNEL_A 0x00000020 #define IP22ZILOG_FLAG_REGS_HELD 0x00000040 #define IP22ZILOG_FLAG_TX_STOPPED 0x00000080 #define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100 @@ -84,6 +82,8 @@ struct uart_ip22zilog_port { unsigned char prev_status; }; +static struct uart_ip22zilog_port ip22zilog_port_table[NUM_CHANNELS]; + #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT)) #define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \ @@ -93,7 +93,6 @@ struct uart_ip22zilog_port { #define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS) #define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB) #define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS) -#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A) #define ZS_REGS_HELD(UP) ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD) #define ZS_TX_STOPPED(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED) #define ZS_TX_ACTIVE(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE) @@ -248,8 +247,8 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up, static bool ip22zilog_receive_chars(struct uart_ip22zilog_port *up, struct zilog_channel *channel) { - unsigned char ch, flag; unsigned int r1; + u8 ch, flag; bool push = up->port.state != NULL; for (;;) { @@ -355,7 +354,8 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, struct zilog_channel *channel) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char c; if (ZS_IS_CONS(up)) { unsigned char status = readb(&channel->control); @@ -398,21 +398,18 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, if (up->port.state == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; + tport = &up->port.state->port; if (uart_tx_stopped(&up->port)) goto ack_tx_int; + if (!uart_fifo_get(&up->port, &c)) + goto ack_tx_int; up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(c, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); return; @@ -425,60 +422,57 @@ ack_tx_int: static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) { - struct uart_ip22zilog_port *up = dev_id; - - while (up) { - struct zilog_channel *channel - = ZILOG_CHANNEL_FROM_PORT(&up->port); - unsigned char r3; - bool push = false; - - spin_lock(&up->port.lock); - r3 = read_zsreg(channel, R3); + struct uart_ip22zilog_port *up; + struct zilog_channel *channel; + unsigned char r3; + bool push = false; - /* Channel A */ - if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); + up = &ip22zilog_port_table[CHANNEL_A]; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - if (r3 & CHARxIP) - push = ip22zilog_receive_chars(up, channel); - if (r3 & CHAEXT) - ip22zilog_status_handle(up, channel); - if (r3 & CHATxIP) - ip22zilog_transmit_chars(up, channel); - } - spin_unlock(&up->port.lock); + uart_port_lock(&up->port); + r3 = read_zsreg(channel, R3); - if (push) - tty_flip_buffer_push(&up->port.state->port); + /* Channel A */ + if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); - /* Channel B */ - up = up->next; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - push = false; + if (r3 & CHARxIP) + push = ip22zilog_receive_chars(up, channel); + if (r3 & CHAEXT) + ip22zilog_status_handle(up, channel); + if (r3 & CHATxIP) + ip22zilog_transmit_chars(up, channel); + } + uart_port_unlock(&up->port); - spin_lock(&up->port.lock); - if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); + if (push) + tty_flip_buffer_push(&up->port.state->port); - if (r3 & CHBRxIP) - push = ip22zilog_receive_chars(up, channel); - if (r3 & CHBEXT) - ip22zilog_status_handle(up, channel); - if (r3 & CHBTxIP) - ip22zilog_transmit_chars(up, channel); - } - spin_unlock(&up->port.lock); + /* Channel B */ + up = &ip22zilog_port_table[CHANNEL_B]; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + push = false; - if (push) - tty_flip_buffer_push(&up->port.state->port); + uart_port_lock(&up->port); + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); - up = up->next; + if (r3 & CHBRxIP) + push = ip22zilog_receive_chars(up, channel); + if (r3 & CHBEXT) + ip22zilog_status_handle(up, channel); + if (r3 & CHBTxIP) + ip22zilog_transmit_chars(up, channel); } + uart_port_unlock(&up->port); + + if (push) + tty_flip_buffer_push(&up->port.state->port); return IRQ_HANDLED; } @@ -505,11 +499,11 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port) unsigned char status; unsigned int ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); status = ip22zilog_read_channel_status(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); if (status & Tx_BUF_EMP) ret = TIOCSER_TEMT; @@ -601,18 +595,16 @@ static void ip22zilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char c; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(port, &c)) return; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(c, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); } } @@ -666,7 +658,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state) else clear_bits |= SND_BRK; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; if (new_reg != up->curregs[R5]) { @@ -676,7 +668,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state) write_zsreg(channel, R5, up->curregs[R5]); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void __ip22zilog_reset(struct uart_ip22zilog_port *up) @@ -696,16 +688,16 @@ static void __ip22zilog_reset(struct uart_ip22zilog_port *up) udelay(100); } - if (!ZS_IS_CHANNEL_A(up)) { - up++; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - } + up = &ip22zilog_port_table[CHANNEL_A]; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); (void) read_zsreg(channel, R0); up->flags |= IP22ZILOG_FLAG_RESET_DONE; - up->next->flags |= IP22ZILOG_FLAG_RESET_DONE; + up = &ip22zilog_port_table[CHANNEL_B]; + up->flags |= IP22ZILOG_FLAG_RESET_DONE; } static void __ip22zilog_startup(struct uart_ip22zilog_port *up) @@ -737,9 +729,9 @@ static int ip22zilog_startup(struct uart_port *port) if (ZS_IS_CONS(up)) return 0; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); __ip22zilog_startup(up); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -777,7 +769,7 @@ static void ip22zilog_shutdown(struct uart_port *port) if (ZS_IS_CONS(up)) return; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); channel = ZILOG_CHANNEL_FROM_PORT(port); @@ -790,7 +782,7 @@ static void ip22zilog_shutdown(struct uart_port *port) up->curregs[R5] &= ~SND_BRK; ip22zilog_maybe_update_regs(up, channel); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* Shared by TTY driver and serial console setup. The port lock is held @@ -873,7 +865,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_ip22zilog_port *up = container_of(port, struct uart_ip22zilog_port, port); @@ -882,7 +874,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 1200, 76800); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); @@ -896,7 +888,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static const char *ip22zilog_type(struct uart_port *port) @@ -946,51 +938,10 @@ static const struct uart_ops ip22zilog_pops = { .verify_port = ip22zilog_verify_port, }; -static struct uart_ip22zilog_port *ip22zilog_port_table; -static struct zilog_layout **ip22zilog_chip_regs; - -static struct uart_ip22zilog_port *ip22zilog_irq_chain; -static int zilog_irq = -1; - -static void * __init alloc_one_table(unsigned long size) -{ - return kzalloc(size, GFP_KERNEL); -} - -static void __init ip22zilog_alloc_tables(void) -{ - ip22zilog_port_table = (struct uart_ip22zilog_port *) - alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port)); - ip22zilog_chip_regs = (struct zilog_layout **) - alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *)); - - if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) { - panic("IP22-Zilog: Cannot allocate IP22-Zilog tables."); - } -} - -/* Get the address of the registers for IP22-Zilog instance CHIP. */ -static struct zilog_layout * __init get_zs(int chip) -{ - unsigned long base; - - if (chip < 0 || chip >= NUM_IP22ZILOG) { - panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip); - } - - /* Not probe-able, hard code it. */ - base = (unsigned long) &sgioc->uart; - - zilog_irq = SGI_SERIAL_IRQ; - request_mem_region(base, 8, "IP22-Zilog"); - - return (struct zilog_layout *) base; -} - #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ #ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE -static void ip22zilog_put_char(struct uart_port *port, int ch) +static void ip22zilog_put_char(struct uart_port *port, unsigned char ch) { struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); int loops = ZS_PUT_CHAR_MAX_DELAY; @@ -1018,10 +969,10 @@ ip22zilog_console_write(struct console *con, const char *s, unsigned int count) struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); uart_console_write(&up->port, s, count, ip22zilog_put_char); udelay(2); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init ip22zilog_console_setup(struct console *con, char *options) @@ -1036,13 +987,13 @@ static int __init ip22zilog_console_setup(struct console *con, char *options) printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->curregs[R15] |= BRKIE; __ip22zilog_startup(up); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1074,144 +1025,123 @@ static struct uart_driver ip22zilog_reg = { #endif }; -static void __init ip22zilog_prepare(void) +static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up) { unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE); + int brg; + + spin_lock_init(&up->port.lock); + + up->port.iotype = UPIO_MEM; + up->port.uartclk = ZS_CLOCK; + up->port.fifosize = 1; + up->port.has_sysrq = sysrq_on; + up->port.ops = &ip22zilog_pops; + up->port.type = PORT_IP22ZILOG; + + /* Normal serial TTY. */ + up->parity_mask = 0xff; + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R9] = NV | MIE; + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRENAB; +} + +static int ip22zilog_probe(struct platform_device *pdev) +{ struct uart_ip22zilog_port *up; - struct zilog_layout *rp; - int channel, chip; + char __iomem *membase; + struct resource *res; + int irq; + int i; - /* - * Temporary fix. - */ - for (channel = 0; channel < NUM_CHANNELS; channel++) - spin_lock_init(&ip22zilog_port_table[channel].port.lock); - - ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1]; - up = &ip22zilog_port_table[0]; - for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--) - up[channel].next = &up[channel - 1]; - up[channel].next = NULL; - - for (chip = 0; chip < NUM_IP22ZILOG; chip++) { - if (!ip22zilog_chip_regs[chip]) { - ip22zilog_chip_regs[chip] = rp = get_zs(chip); - - up[(chip * 2) + 0].port.membase = (char *) &rp->channelB; - up[(chip * 2) + 1].port.membase = (char *) &rp->channelA; - - /* In theory mapbase is the physical address ... */ - up[(chip * 2) + 0].port.mapbase = - (unsigned long) ioremap((unsigned long) &rp->channelB, 8); - up[(chip * 2) + 1].port.mapbase = - (unsigned long) ioremap((unsigned long) &rp->channelA, 8); - } + up = &ip22zilog_port_table[CHANNEL_B]; + if (up->port.dev) + return -ENOSPC; - /* Channel A */ - up[(chip * 2) + 0].port.iotype = UPIO_MEM; - up[(chip * 2) + 0].port.irq = zilog_irq; - up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 0].port.fifosize = 1; - up[(chip * 2) + 0].port.has_sysrq = sysrq_on; - up[(chip * 2) + 0].port.ops = &ip22zilog_pops; - up[(chip * 2) + 0].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 0].port.flags = 0; - up[(chip * 2) + 0].port.line = (chip * 2) + 0; - up[(chip * 2) + 0].flags = 0; - - /* Channel B */ - up[(chip * 2) + 1].port.iotype = UPIO_MEM; - up[(chip * 2) + 1].port.irq = zilog_irq; - up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 1].port.fifosize = 1; - up[(chip * 2) + 1].port.has_sysrq = sysrq_on; - up[(chip * 2) + 1].port.ops = &ip22zilog_pops; - up[(chip * 2) + 1].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 1].port.line = (chip * 2) + 1; - up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - for (channel = 0; channel < NUM_CHANNELS; channel++) { - struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel]; - int brg; + membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(membase)) + return PTR_ERR(membase); - /* Normal serial TTY. */ - up->parity_mask = 0xff; - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRENAB; - } -} + ip22zilog_prepare(up); -static int __init ip22zilog_ports_init(void) -{ - int ret; + up->port.mapbase = res->start + offsetof(struct zilog_layout, channelB); + up->port.membase = membase + offsetof(struct zilog_layout, channelB); + up->port.line = 0; + up->port.dev = &pdev->dev; + up->port.irq = irq; - printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG); + up = &ip22zilog_port_table[CHANNEL_A]; + ip22zilog_prepare(up); - ip22zilog_prepare(); + up->port.mapbase = res->start + offsetof(struct zilog_layout, channelA); + up->port.membase = membase + offsetof(struct zilog_layout, channelA); + up->port.line = 1; + up->port.dev = &pdev->dev; + up->port.irq = irq; - if (request_irq(zilog_irq, ip22zilog_interrupt, 0, - "IP22-Zilog", ip22zilog_irq_chain)) { + if (request_irq(irq, ip22zilog_interrupt, 0, + "IP22-Zilog", NULL)) { panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); } - ret = uart_register_driver(&ip22zilog_reg); - if (ret == 0) { - int i; - - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; - - uart_add_one_port(&ip22zilog_reg, &up->port); - } - } - - return ret; -} - -static int __init ip22zilog_init(void) -{ - /* IP22 Zilog setup is hard coded, no probing to do. */ - ip22zilog_alloc_tables(); - ip22zilog_ports_init(); + for (i = 0; i < NUM_CHANNELS; i++) + uart_add_one_port(&ip22zilog_reg, + &ip22zilog_port_table[i].port); return 0; } -static void __exit ip22zilog_exit(void) +static void ip22zilog_remove(struct platform_device *pdev) { int i; - struct uart_ip22zilog_port *up; for (i = 0; i < NUM_CHANNELS; i++) { - up = &ip22zilog_port_table[i]; - - uart_remove_one_port(&ip22zilog_reg, &up->port); + uart_remove_one_port(&ip22zilog_reg, + &ip22zilog_port_table[i].port); + ip22zilog_port_table[i].port.dev = NULL; } +} - /* Free IO mem */ - up = &ip22zilog_port_table[0]; - for (i = 0; i < NUM_IP22ZILOG; i++) { - if (up[(i * 2) + 0].port.mapbase) { - iounmap((void*)up[(i * 2) + 0].port.mapbase); - up[(i * 2) + 0].port.mapbase = 0; - } - if (up[(i * 2) + 1].port.mapbase) { - iounmap((void*)up[(i * 2) + 1].port.mapbase); - up[(i * 2) + 1].port.mapbase = 0; - } +static struct platform_driver ip22zilog_driver = { + .probe = ip22zilog_probe, + .remove = ip22zilog_remove, + .driver = { + .name = "ip22zilog" } +}; + +static int __init ip22zilog_init(void) +{ + int ret; + + ret = uart_register_driver(&ip22zilog_reg); + if (ret) + return ret; + + ret = platform_driver_register(&ip22zilog_driver); + if (ret) + uart_unregister_driver(&ip22zilog_reg); + return ret; + +} + +static void __exit ip22zilog_exit(void) +{ uart_unregister_driver(&ip22zilog_reg); + platform_driver_unregister(&ip22zilog_driver); } module_init(ip22zilog_init); diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index 8489c07f4cd5..df55e5dc5afc 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -115,8 +115,6 @@ struct board_ops { void (*send_start_character)(struct jsm_channel *ch); void (*send_stop_character)(struct jsm_channel *ch); void (*copy_data_from_queue_to_uart)(struct jsm_channel *ch); - u32 (*get_uart_bytes_left)(struct jsm_channel *ch); - void (*send_immediate_char)(struct jsm_channel *ch, unsigned char); }; @@ -127,7 +125,6 @@ struct jsm_board { int boardnum; /* Board number: 0-32 */ - int type; /* Type of board */ u8 rev; /* PCI revision ID */ struct pci_dev *pci_dev; u32 maxports; /* MAX ports this board can handle */ @@ -155,8 +152,6 @@ struct jsm_board u32 bd_dividend; /* Board/UARTs specific dividend */ struct board_ops *bd_ops; - - struct list_head jsm_board_entry; }; /************************************************************************ diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index c061a7b7bd23..6e40792f92cf 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -350,7 +350,7 @@ static void cls_assert_modem_signals(struct jsm_channel *ch) static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) { int qleft = 0; - u8 linestatus = 0; + u8 linestatus; u8 error_mask = 0; u16 head; u16 tail; @@ -365,8 +365,6 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) head = ch->ch_r_head & RQUEUEMASK; tail = ch->ch_r_tail & RQUEUEMASK; - /* Get our cached LSR */ - linestatus = ch->ch_cached_lsr; ch->ch_cached_lsr = 0; /* Store how much space we have left in the queue */ @@ -397,10 +395,7 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) * which in this case is the break signal. */ if (linestatus & error_mask) { - u8 discard; - - linestatus = 0; - discard = readb(&ch->ch_cls_uart->txrx); + readb(&ch->ch_cls_uart->txrx); continue; } @@ -448,20 +443,14 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch) { - u16 tail; + struct tty_port *tport; int n; - int qlen; u32 len_written = 0; - struct circ_buf *circ; if (!ch) return; - circ = &ch->uart_port.state->xmit; - - /* No data to write to the UART */ - if (uart_circ_empty(circ)) - return; + tport = &ch->uart_port.state->port; /* If port is "stopped", don't send any data to the UART */ if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) @@ -472,29 +461,22 @@ static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch) return; n = 32; + while (n > 0) { + unsigned char c; - /* cache tail of queue */ - tail = circ->tail & (UART_XMIT_SIZE - 1); - qlen = uart_circ_chars_pending(circ); - - /* Find minimum of the FIFO space, versus queue length */ - n = min(n, qlen); + if (!kfifo_get(&tport->xmit_fifo, &c)) + break; - while (n > 0) { - writeb(circ->buf[tail], &ch->ch_cls_uart->txrx); - tail = (tail + 1) & (UART_XMIT_SIZE - 1); + writeb(c, &ch->ch_cls_uart->txrx); n--; ch->ch_txcount++; len_written++; } - /* Update the final tail */ - circ->tail = tail & (UART_XMIT_SIZE - 1); - if (len_written > ch->ch_t_tlevel) ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - if (uart_circ_empty(circ)) + if (kfifo_is_empty(&tport->xmit_fifo)) uart_write_wakeup(&ch->uart_port); } @@ -693,7 +675,7 @@ static void cls_param(struct jsm_channel *ch) /* * If baud rate is zero, flush queues, and set mval to drop DTR. */ - if ((ch->ch_c_cflag & (CBAUD)) == 0) { + if ((ch->ch_c_cflag & CBAUD) == B0) { ch->ch_r_head = 0; ch->ch_r_tail = 0; ch->ch_e_head = 0; @@ -727,33 +709,13 @@ static void cls_param(struct jsm_channel *ch) if (!(ch->ch_c_cflag & PARODD)) lcr |= UART_LCR_EPAR; - /* - * Not all platforms support mark/space parity, - * so this will hide behind an ifdef. - */ -#ifdef CMSPAR if (ch->ch_c_cflag & CMSPAR) lcr |= UART_LCR_SPAR; -#endif if (ch->ch_c_cflag & CSTOPB) lcr |= UART_LCR_STOP; - switch (ch->ch_c_cflag & CSIZE) { - case CS5: - lcr |= UART_LCR_WLEN5; - break; - case CS6: - lcr |= UART_LCR_WLEN6; - break; - case CS7: - lcr |= UART_LCR_WLEN7; - break; - case CS8: - default: - lcr |= UART_LCR_WLEN8; - break; - } + lcr |= UART_LCR_WLEN(tty_get_char_size(ch->ch_c_cflag)); ier = readb(&ch->ch_cls_uart->ier); uart_lcr = readb(&ch->ch_cls_uart->lcr); @@ -902,28 +864,6 @@ static void cls_uart_off(struct jsm_channel *ch) } /* - * cls_get_uarts_bytes_left. - * Returns 0 is nothing left in the FIFO, returns 1 otherwise. - * - * The channel lock MUST be held by the calling function. - */ -static u32 cls_get_uart_bytes_left(struct jsm_channel *ch) -{ - u8 left = 0; - u8 lsr = readb(&ch->ch_cls_uart->lsr); - - /* Determine whether the Transmitter is empty or not */ - if (!(lsr & UART_LSR_TEMT)) - left = 1; - else { - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - left = 0; - } - - return left; -} - -/* * cls_send_break. * Starts sending a break thru the UART. * @@ -940,18 +880,6 @@ static void cls_send_break(struct jsm_channel *ch) } } -/* - * cls_send_immediate_char. - * Sends a specific character as soon as possible to the UART, - * jumping over any bytes that might be in the write queue. - * - * The channel lock MUST be held by the calling function. - */ -static void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c) -{ - writeb(c, &ch->ch_cls_uart->txrx); -} - struct board_ops jsm_cls_ops = { .intr = cls_intr, .uart_init = cls_uart_init, @@ -967,7 +895,5 @@ struct board_ops jsm_cls_ops = { .send_start_character = cls_send_start_character, .send_stop_character = cls_send_stop_character, .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart, - .get_uart_bytes_left = cls_get_uart_bytes_left, - .send_immediate_char = cls_send_immediate_char }; diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 592e51d8944e..8d21373cae57 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -16,10 +16,9 @@ #include "jsm.h" -MODULE_AUTHOR("Digi International, http://www.digi.com"); +MODULE_AUTHOR("Digi International, https://www.digi.com"); MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("jsm"); #define JSM_DRIVER_NAME "jsm" #define NR_PORTS 32 @@ -212,7 +211,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) break; default: - return -ENXIO; + rc = -ENXIO; + goto out_kfree_brd; } rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd); @@ -355,7 +355,6 @@ static void jsm_io_resume(struct pci_dev *pdev) struct jsm_board *brd = pci_get_drvdata(pdev); pci_restore_state(pdev); - pci_save_state(pdev); jsm_uart_port_init(brd); } diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index bf0e2a4cb0ce..e8e13bf056e2 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -291,7 +291,8 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) ch->ch_cached_lsr = 0; /* Store how much space we have left in the queue */ - if ((qleft = tail - head - 1) < 0) + qleft = tail - head - 1; + if (qleft < 0) qleft += RQUEUEMASK + 1; /* @@ -473,21 +474,21 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) { - u16 head; - u16 tail; + struct tty_port *tport; + unsigned char *tail; + unsigned char c; int n; int s; int qlen; u32 len_written = 0; - struct circ_buf *circ; if (!ch) return; - circ = &ch->uart_port.state->xmit; + tport = &ch->uart_port.state->port; /* No data to write to the UART */ - if (uart_circ_empty(circ)) + if (kfifo_is_empty(&tport->xmit_fifo)) return; /* If port is "stopped", don't send any data to the UART */ @@ -503,10 +504,9 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) if (ch->ch_cached_lsr & UART_LSR_THRE) { ch->ch_cached_lsr &= ~(UART_LSR_THRE); - writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx); - jsm_dbg(WRITE, &ch->ch_bd->pci_dev, - "Tx data: %x\n", circ->buf[circ->tail]); - circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); + WARN_ON_ONCE(!kfifo_get(&tport->xmit_fifo, &c)); + writeb(c, &ch->ch_neo_uart->txrx); + jsm_dbg(WRITE, &ch->ch_bd->pci_dev, "Tx data: %x\n", c); ch->ch_txcount++; } return; @@ -519,38 +519,27 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) return; n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; - - /* cache head and tail of queue */ - head = circ->head & (UART_XMIT_SIZE - 1); - tail = circ->tail & (UART_XMIT_SIZE - 1); - qlen = uart_circ_chars_pending(circ); + qlen = kfifo_len(&tport->xmit_fifo); /* Find minimum of the FIFO space, versus queue length */ n = min(n, qlen); while (n > 0) { - - s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; - s = min(s, n); - + s = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, n); if (s <= 0) break; - memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s); - /* Add and flip queue if needed */ - tail = (tail + s) & (UART_XMIT_SIZE - 1); + memcpy_toio(&ch->ch_neo_uart->txrxburst, tail, s); + kfifo_skip_count(&tport->xmit_fifo, s); n -= s; ch->ch_txcount += s; len_written += s; } - /* Update the final tail */ - circ->tail = tail & (UART_XMIT_SIZE - 1); - if (len_written >= ch->ch_t_tlevel) ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - if (uart_circ_empty(circ)) + if (kfifo_is_empty(&tport->xmit_fifo)) uart_write_wakeup(&ch->uart_port); } @@ -815,7 +804,9 @@ static void neo_parse_isr(struct jsm_board *brd, u32 port) /* Parse any modem signal changes */ jsm_dbg(INTR, &ch->ch_bd->pci_dev, "MOD_STAT: sending to parse_modem_sigs\n"); + uart_port_lock_irqsave(&ch->uart_port, &lock_flags); neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); + uart_port_unlock_irqrestore(&ch->uart_port, lock_flags); } } @@ -935,7 +926,7 @@ static void neo_param(struct jsm_channel *ch) /* * If baud rate is zero, flush queues, and set mval to drop DTR. */ - if ((ch->ch_c_cflag & (CBAUD)) == 0) { + if ((ch->ch_c_cflag & CBAUD) == B0) { ch->ch_r_head = ch->ch_r_tail = 0; ch->ch_e_head = ch->ch_e_tail = 0; @@ -994,33 +985,13 @@ static void neo_param(struct jsm_channel *ch) if (!(ch->ch_c_cflag & PARODD)) lcr |= UART_LCR_EPAR; - /* - * Not all platforms support mark/space parity, - * so this will hide behind an ifdef. - */ -#ifdef CMSPAR if (ch->ch_c_cflag & CMSPAR) lcr |= UART_LCR_SPAR; -#endif if (ch->ch_c_cflag & CSTOPB) lcr |= UART_LCR_STOP; - switch (ch->ch_c_cflag & CSIZE) { - case CS5: - lcr |= UART_LCR_WLEN5; - break; - case CS6: - lcr |= UART_LCR_WLEN6; - break; - case CS7: - lcr |= UART_LCR_WLEN7; - break; - case CS8: - default: - lcr |= UART_LCR_WLEN8; - break; - } + lcr |= UART_LCR_WLEN(tty_get_char_size(ch->ch_c_cflag)); ier = readb(&ch->ch_neo_uart->ier); uart_lcr = readb(&ch->ch_neo_uart->lcr); @@ -1326,25 +1297,6 @@ static void neo_uart_off(struct jsm_channel *ch) writeb(0, &ch->ch_neo_uart->ier); } -static u32 neo_get_uart_bytes_left(struct jsm_channel *ch) -{ - u8 left = 0; - u8 lsr = readb(&ch->ch_neo_uart->lsr); - - /* We must cache the LSR as some of the bits get reset once read... */ - ch->ch_cached_lsr |= lsr; - - /* Determine whether the Transmitter is empty or not */ - if (!(lsr & UART_LSR_TEMT)) - left = 1; - else { - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - left = 0; - } - - return left; -} - /* Channel lock MUST be held by the calling function! */ static void neo_send_break(struct jsm_channel *ch) { @@ -1365,25 +1317,6 @@ static void neo_send_break(struct jsm_channel *ch) } } -/* - * neo_send_immediate_char. - * - * Sends a specific character as soon as possible to the UART, - * jumping over any bytes that might be in the write queue. - * - * The channel lock MUST be held by the calling function. - */ -static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c) -{ - if (!ch) - return; - - writeb(c, &ch->ch_neo_uart->txrx); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); -} - struct board_ops jsm_neo_ops = { .intr = neo_intr, .uart_init = neo_uart_init, @@ -1399,6 +1332,4 @@ struct board_ops jsm_neo_ops = { .send_start_character = neo_send_start_character, .send_stop_character = neo_send_stop_character, .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart, - .get_uart_bytes_left = neo_get_uart_bytes_left, - .send_immediate_char = neo_send_immediate_char }; diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 689774c073ca..be2f130696b3 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -152,14 +152,14 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) container_of(port, struct jsm_channel, uart_port); struct ktermios *termios; - spin_lock_irqsave(&port->lock, lock_flags); + uart_port_lock_irqsave(port, &lock_flags); termios = &port->state->port.tty->termios; if (ch == termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); if (ch == termios->c_cc[VSTOP]) channel->ch_bd->bd_ops->send_stop_character(channel); - spin_unlock_irqrestore(&port->lock, lock_flags); + uart_port_unlock_irqrestore(port, lock_flags); } static void jsm_tty_stop_rx(struct uart_port *port) @@ -176,17 +176,18 @@ static void jsm_tty_break(struct uart_port *port, int break_state) struct jsm_channel *channel = container_of(port, struct jsm_channel, uart_port); - spin_lock_irqsave(&port->lock, lock_flags); + uart_port_lock_irqsave(port, &lock_flags); if (break_state == -1) channel->ch_bd->bd_ops->send_break(channel); else channel->ch_bd->bd_ops->clear_break(channel); - spin_unlock_irqrestore(&port->lock, lock_flags); + uart_port_unlock_irqrestore(port, lock_flags); } static int jsm_tty_open(struct uart_port *port) { + unsigned long lock_flags; struct jsm_board *brd; struct jsm_channel *channel = container_of(port, struct jsm_channel, uart_port); @@ -240,6 +241,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; + uart_port_lock_irqsave(port, &lock_flags); termios = &port->state->port.tty->termios; channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; @@ -259,6 +261,7 @@ static int jsm_tty_open(struct uart_port *port) jsm_carrier(channel); channel->ch_open_count++; + uart_port_unlock_irqrestore(port, lock_flags); jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n"); return 0; @@ -297,14 +300,14 @@ static void jsm_tty_close(struct uart_port *port) } static void jsm_tty_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old_termios) + struct ktermios *termios, + const struct ktermios *old_termios) { unsigned long lock_flags; struct jsm_channel *channel = container_of(port, struct jsm_channel, uart_port); - spin_lock_irqsave(&port->lock, lock_flags); + uart_port_lock_irqsave(port, &lock_flags); channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; channel->ch_c_oflag = termios->c_oflag; @@ -314,7 +317,7 @@ static void jsm_tty_set_termios(struct uart_port *port, channel->ch_bd->bd_ops->param(channel); jsm_carrier(channel); - spin_unlock_irqrestore(&port->lock, lock_flags); + uart_port_unlock_irqrestore(port, lock_flags); } static const char *jsm_tty_type(struct uart_port *port) @@ -448,6 +451,7 @@ int jsm_uart_port_init(struct jsm_board *brd) if (!brd->channels[i]) continue; + brd->channels[i]->uart_port.dev = &brd->pci_dev->dev; brd->channels[i]->uart_port.irq = brd->irq; brd->channels[i]->uart_port.uartclk = 14745600; brd->channels[i]->uart_port.type = PORT_JSM; @@ -603,18 +607,22 @@ void jsm_input(struct jsm_channel *ch) if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { for (i = 0; i < s; i++) { + u8 chr = ch->ch_rqueue[tail + i]; + u8 error = ch->ch_equeue[tail + i]; + char flag = TTY_NORMAL; + /* - * Give the Linux ld the flags in the - * format it likes. + * Give the Linux ld the flags in the format it + * likes. */ - if (*(ch->ch_equeue +tail +i) & UART_LSR_BI) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_BREAK); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_PARITY); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_FRAME); - else - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_NORMAL); + if (error & UART_LSR_BI) + flag = TTY_BREAK; + else if (error & UART_LSR_PE) + flag = TTY_PARITY; + else if (error & UART_LSR_FE) + flag = TTY_FRAME; + + tty_insert_flip_char(port, chr, flag); } } else { tty_insert_flip_string(port, ch->ch_rqueue + tail, s); @@ -742,7 +750,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) int qleft; /* Store how much space we have left in the queue */ - if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) + qleft = ch->ch_r_tail - ch->ch_r_head - 1; + if (qleft < 0) qleft += RQUEUEMASK + 1; /* diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c deleted file mode 100644 index 5022447afa23..000000000000 --- a/drivers/tty/serial/kgdb_nmi.c +++ /dev/null @@ -1,383 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * KGDB NMI serial console - * - * Copyright 2010 Google, Inc. - * Arve Hjønnevåg <arve@android.com> - * Colin Cross <ccross@android.com> - * Copyright 2012 Linaro Ltd. - * Anton Vorontsov <anton.vorontsov@linaro.org> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/compiler.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/atomic.h> -#include <linux/console.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/interrupt.h> -#include <linux/hrtimer.h> -#include <linux/tick.h> -#include <linux/kfifo.h> -#include <linux/kgdb.h> -#include <linux/kdb.h> - -static int kgdb_nmi_knock = 1; -module_param_named(knock, kgdb_nmi_knock, int, 0600); -MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \ - "must be used to enter the debugger; when set to 0, " \ - "hitting return key is enough to enter the debugger; " \ - "when set to -1, the debugger is entered immediately " \ - "upon NMI"); - -static char *kgdb_nmi_magic = "$3#33"; -module_param_named(magic, kgdb_nmi_magic, charp, 0600); -MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)"); - -static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0); - -static int kgdb_nmi_console_setup(struct console *co, char *options) -{ - arch_kgdb_ops.enable_nmi(1); - - /* The NMI console uses the dbg_io_ops to issue console messages. To - * avoid duplicate messages during kdb sessions we must inform kdb's - * I/O utilities that messages sent to the console will automatically - * be displayed on the dbg_io. - */ - dbg_io_ops->is_console = true; - - return 0; -} - -static void kgdb_nmi_console_write(struct console *co, const char *s, uint c) -{ - int i; - - for (i = 0; i < c; i++) - dbg_io_ops->write_char(s[i]); -} - -static struct tty_driver *kgdb_nmi_tty_driver; - -static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx) -{ - *idx = co->index; - return kgdb_nmi_tty_driver; -} - -static struct console kgdb_nmi_console = { - .name = "ttyNMI", - .setup = kgdb_nmi_console_setup, - .write = kgdb_nmi_console_write, - .device = kgdb_nmi_console_device, - .flags = CON_PRINTBUFFER | CON_ANYTIME, - .index = -1, -}; - -/* - * This is usually the maximum rate on debug ports. We make fifo large enough - * to make copy-pasting to the terminal usable. - */ -#define KGDB_NMI_BAUD 115200 -#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ) - -struct kgdb_nmi_tty_priv { - struct tty_port port; - struct timer_list timer; - STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo; -}; - -static struct tty_port *kgdb_nmi_port; - -static void kgdb_tty_recv(int ch) -{ - struct kgdb_nmi_tty_priv *priv; - char c = ch; - - if (!kgdb_nmi_port || ch < 0) - return; - /* - * Can't use port->tty->driver_data as tty might be not there. Timer - * will check for tty and will get the ref, but here we don't have to - * do that, and actually, we can't: we're in NMI context, no locks are - * possible. - */ - priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port); - kfifo_in(&priv->fifo, &c, 1); -} - -static int kgdb_nmi_poll_one_knock(void) -{ - static int n; - int c = -1; - const char *magic = kgdb_nmi_magic; - size_t m = strlen(magic); - bool printch = false; - - c = dbg_io_ops->read_char(); - if (c == NO_POLL_CHAR) - return c; - - if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) { - return 1; - } else if (c == magic[n]) { - n = (n + 1) % m; - if (!n) - return 1; - printch = true; - } else { - n = 0; - } - - if (atomic_read(&kgdb_nmi_num_readers)) { - kgdb_tty_recv(c); - return 0; - } - - if (printch) { - kdb_printf("%c", c); - return 0; - } - - kdb_printf("\r%s %s to enter the debugger> %*s", - kgdb_nmi_knock ? "Type" : "Hit", - kgdb_nmi_knock ? magic : "<return>", (int)m, ""); - while (m--) - kdb_printf("\b"); - return 0; -} - -/** - * kgdb_nmi_poll_knock - Check if it is time to enter the debugger - * - * "Serial ports are often noisy, especially when muxed over another port (we - * often use serial over the headset connector). Noise on the async command - * line just causes characters that are ignored, on a command line that blocked - * execution noise would be catastrophic." -- Colin Cross - * - * So, this function implements KGDB/KDB knocking on the serial line: we won't - * enter the debugger until we receive a known magic phrase (which is actually - * "$3#33", known as "escape to KDB" command. There is also a relaxed variant - * of knocking, i.e. just pressing the return key is enough to enter the - * debugger. And if knocking is disabled, the function always returns 1. - */ -bool kgdb_nmi_poll_knock(void) -{ - if (kgdb_nmi_knock < 0) - return true; - - while (1) { - int ret; - - ret = kgdb_nmi_poll_one_knock(); - if (ret == NO_POLL_CHAR) - return false; - else if (ret == 1) - break; - } - return true; -} - -/* - * The tasklet is cheap, it does not cause wakeups when reschedules itself, - * instead it waits for the next tick. - */ -static void kgdb_nmi_tty_receiver(struct timer_list *t) -{ - struct kgdb_nmi_tty_priv *priv = from_timer(priv, t, timer); - char ch; - - priv->timer.expires = jiffies + (HZ/100); - add_timer(&priv->timer); - - if (likely(!atomic_read(&kgdb_nmi_num_readers) || - !kfifo_len(&priv->fifo))) - return; - - while (kfifo_out(&priv->fifo, &ch, 1)) - tty_insert_flip_char(&priv->port, ch, TTY_NORMAL); - tty_flip_buffer_push(&priv->port); -} - -static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct kgdb_nmi_tty_priv *priv = - container_of(port, struct kgdb_nmi_tty_priv, port); - - kgdb_nmi_port = port; - priv->timer.expires = jiffies + (HZ/100); - add_timer(&priv->timer); - - return 0; -} - -static void kgdb_nmi_tty_shutdown(struct tty_port *port) -{ - struct kgdb_nmi_tty_priv *priv = - container_of(port, struct kgdb_nmi_tty_priv, port); - - del_timer(&priv->timer); - kgdb_nmi_port = NULL; -} - -static const struct tty_port_operations kgdb_nmi_tty_port_ops = { - .activate = kgdb_nmi_tty_activate, - .shutdown = kgdb_nmi_tty_shutdown, -}; - -static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty) -{ - struct kgdb_nmi_tty_priv *priv; - int ret; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - INIT_KFIFO(priv->fifo); - timer_setup(&priv->timer, kgdb_nmi_tty_receiver, 0); - tty_port_init(&priv->port); - priv->port.ops = &kgdb_nmi_tty_port_ops; - tty->driver_data = priv; - - ret = tty_port_install(&priv->port, drv, tty); - if (ret) { - pr_err("%s: can't install tty port: %d\n", __func__, ret); - goto err; - } - return 0; -err: - tty_port_destroy(&priv->port); - kfree(priv); - return ret; -} - -static void kgdb_nmi_tty_cleanup(struct tty_struct *tty) -{ - struct kgdb_nmi_tty_priv *priv = tty->driver_data; - - tty->driver_data = NULL; - tty_port_destroy(&priv->port); - kfree(priv); -} - -static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file) -{ - struct kgdb_nmi_tty_priv *priv = tty->driver_data; - unsigned int mode = file->f_flags & O_ACCMODE; - int ret; - - ret = tty_port_open(&priv->port, tty, file); - if (!ret && (mode == O_RDONLY || mode == O_RDWR)) - atomic_inc(&kgdb_nmi_num_readers); - - return ret; -} - -static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file) -{ - struct kgdb_nmi_tty_priv *priv = tty->driver_data; - unsigned int mode = file->f_flags & O_ACCMODE; - - if (mode == O_RDONLY || mode == O_RDWR) - atomic_dec(&kgdb_nmi_num_readers); - - tty_port_close(&priv->port, tty, file); -} - -static void kgdb_nmi_tty_hangup(struct tty_struct *tty) -{ - struct kgdb_nmi_tty_priv *priv = tty->driver_data; - - tty_port_hangup(&priv->port); -} - -static int kgdb_nmi_tty_write_room(struct tty_struct *tty) -{ - /* Actually, we can handle any amount as we use polled writes. */ - return 2048; -} - -static int kgdb_nmi_tty_write(struct tty_struct *tty, const unchar *buf, int c) -{ - int i; - - for (i = 0; i < c; i++) - dbg_io_ops->write_char(buf[i]); - return c; -} - -static const struct tty_operations kgdb_nmi_tty_ops = { - .open = kgdb_nmi_tty_open, - .close = kgdb_nmi_tty_close, - .install = kgdb_nmi_tty_install, - .cleanup = kgdb_nmi_tty_cleanup, - .hangup = kgdb_nmi_tty_hangup, - .write_room = kgdb_nmi_tty_write_room, - .write = kgdb_nmi_tty_write, -}; - -int kgdb_register_nmi_console(void) -{ - int ret; - - if (!arch_kgdb_ops.enable_nmi) - return 0; - - kgdb_nmi_tty_driver = alloc_tty_driver(1); - if (!kgdb_nmi_tty_driver) { - pr_err("%s: cannot allocate tty\n", __func__); - return -ENOMEM; - } - kgdb_nmi_tty_driver->driver_name = "ttyNMI"; - kgdb_nmi_tty_driver->name = "ttyNMI"; - kgdb_nmi_tty_driver->num = 1; - kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL; - kgdb_nmi_tty_driver->flags = TTY_DRIVER_REAL_RAW; - kgdb_nmi_tty_driver->init_termios = tty_std_termios; - tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios, - KGDB_NMI_BAUD, KGDB_NMI_BAUD); - tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops); - - ret = tty_register_driver(kgdb_nmi_tty_driver); - if (ret) { - pr_err("%s: can't register tty driver: %d\n", __func__, ret); - goto err_drv_reg; - } - - register_console(&kgdb_nmi_console); - - return 0; -err_drv_reg: - put_tty_driver(kgdb_nmi_tty_driver); - return ret; -} -EXPORT_SYMBOL_GPL(kgdb_register_nmi_console); - -int kgdb_unregister_nmi_console(void) -{ - int ret; - - if (!arch_kgdb_ops.enable_nmi) - return 0; - arch_kgdb_ops.enable_nmi(0); - - ret = unregister_console(&kgdb_nmi_console); - if (ret) - return ret; - - ret = tty_unregister_driver(kgdb_nmi_tty_driver); - if (ret) - return ret; - put_tty_driver(kgdb_nmi_tty_driver); - - return 0; -} -EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console); diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 41396982e9e0..5a955c80a853 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -19,6 +19,7 @@ #include <linux/console.h> #include <linux/vt_kern.h> #include <linux/input.h> +#include <linux/irq_work.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/serial_core.h> @@ -45,10 +46,28 @@ static struct platform_device *kgdboc_pdev; #if IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) static struct kgdb_io kgdboc_earlycon_io_ops; -static struct console *earlycon; static int (*earlycon_orig_exit)(struct console *con); #endif /* IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) */ +/* + * When we leave the debug trap handler we need to reset the keyboard status + * (since the original keyboard state gets partially clobbered by kdb use of + * the keyboard). + * + * The path to deliver the reset is somewhat circuitous. + * + * To deliver the reset we register an input handler, reset the keyboard and + * then deregister the input handler. However, to get this done right, we do + * have to carefully manage the calling context because we can only register + * input handlers from task context. + * + * In particular we need to trigger the action from the debug trap handler with + * all its NMI and/or NMI-like oddities. To solve this the kgdboc trap exit code + * (the "post_exception" callback) uses irq_work_queue(), which is NMI-safe, to + * schedule a callback from a hardirq context. From there we have to defer the + * work again, this time using schedule_work(), to get a callback using the + * system workqueue, which runs in task context. + */ #ifdef CONFIG_KDB_KEYBOARD static int kgdboc_reset_connect(struct input_handler *handler, struct input_dev *dev, @@ -100,10 +119,17 @@ static void kgdboc_restore_input_helper(struct work_struct *dummy) static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper); +static void kgdboc_queue_restore_input_helper(struct irq_work *unused) +{ + schedule_work(&kgdboc_restore_input_work); +} + +static DEFINE_IRQ_WORK(kgdboc_restore_input_irq_work, kgdboc_queue_restore_input_helper); + static void kgdboc_restore_input(void) { if (likely(system_state == SYSTEM_RUNNING)) - schedule_work(&kgdboc_restore_input_work); + irq_work_queue(&kgdboc_restore_input_irq_work); } static int kgdboc_register_kbd(char **cptr) @@ -134,6 +160,7 @@ static void kgdboc_unregister_kbd(void) i--; } } + irq_work_sync(&kgdboc_restore_input_irq_work); flush_work(&kgdboc_restore_input_work); } #else /* ! CONFIG_KDB_KEYBOARD */ @@ -145,7 +172,7 @@ static void kgdboc_unregister_kbd(void) #if IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) static void cleanup_earlycon(void) { - if (earlycon) + if (kgdboc_earlycon_io_ops.cons) kgdb_unregister_io_module(&kgdboc_earlycon_io_ops); } #else /* !IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) */ @@ -159,8 +186,6 @@ static void cleanup_kgdboc(void) if (configured != 1) return; - if (kgdb_unregister_nmi_console()) - return; kgdboc_unregister_kbd(); kgdb_unregister_io_module(&kgdboc_io_ops); } @@ -172,13 +197,14 @@ static int configure_kgdboc(void) int err = -ENODEV; char *cptr = config; struct console *cons; + int cookie; if (!strlen(config) || isspace(config[0])) { err = 0; goto noconfig; } - kgdboc_io_ops.is_console = 0; + kgdboc_io_ops.cons = NULL; kgdb_tty_driver = NULL; kgdboc_use_kms = 0; @@ -194,14 +220,25 @@ static int configure_kgdboc(void) if (!p) goto noconfig; - for_each_console(cons) { + /* + * Take console_lock to serialize device() callback with + * other console operations. For example, fg_console is + * modified under console_lock when switching vt. + */ + console_lock(); + + cookie = console_srcu_read_lock(); + for_each_console_srcu(cons) { int idx; if (cons->device && cons->device(cons, &idx) == p && idx == tty_line) { - kgdboc_io_ops.is_console = 1; + kgdboc_io_ops.cons = cons; break; } } + console_srcu_read_unlock(cookie); + + console_unlock(); kgdb_tty_driver = p; kgdb_tty_line = tty_line; @@ -211,16 +248,10 @@ do_register: if (err) goto noconfig; - err = kgdb_register_nmi_console(); - if (err) - goto nmi_con_failed; - configured = 1; return 0; -nmi_con_failed: - kgdb_unregister_io_module(&kgdboc_io_ops); noconfig: kgdboc_unregister_kbd(); configured = 0; @@ -343,7 +374,7 @@ static int param_set_kgdboc_var(const char *kmessage, /* * Configure with the new params as long as init already ran. * Note that we can get called before init if someone loads us - * with "modprobe kgdboc kgdboc=..." or if they happen to use the + * with "modprobe kgdboc kgdboc=..." or if they happen to use * the odd syntax of "kgdboc.kgdboc=..." on the kernel command. */ if (configured >= 0) @@ -404,16 +435,16 @@ static int kgdboc_option_setup(char *opt) { if (!opt) { pr_err("config string not provided\n"); - return -EINVAL; + return 1; } if (strlen(opt) >= MAX_CONFIG_LEN) { pr_err("config string too long\n"); - return -ENOSPC; + return 1; } strcpy(config, opt); - return 0; + return 1; } __setup("kgdboc=", kgdboc_option_setup); @@ -433,7 +464,8 @@ static int kgdboc_earlycon_get_char(void) { char c; - if (!earlycon->read(earlycon, &c, 1)) + if (!kgdboc_earlycon_io_ops.cons->read(kgdboc_earlycon_io_ops.cons, + &c, 1)) return NO_POLL_CHAR; return c; @@ -441,13 +473,15 @@ static int kgdboc_earlycon_get_char(void) static void kgdboc_earlycon_put_char(u8 chr) { - earlycon->write(earlycon, &chr, 1); + kgdboc_earlycon_io_ops.cons->write(kgdboc_earlycon_io_ops.cons, &chr, + 1); } static void kgdboc_earlycon_pre_exp_handler(void) { struct console *con; static bool already_warned; + int cookie; if (already_warned) return; @@ -460,9 +494,14 @@ static void kgdboc_earlycon_pre_exp_handler(void) * serial drivers might be OK with this, print a warning once per * boot if we detect this case. */ - for_each_console(con) - if (con == earlycon) - return; + cookie = console_srcu_read_lock(); + for_each_console_srcu(con) { + if (con == kgdboc_earlycon_io_ops.cons) + break; + } + console_srcu_read_unlock(cookie); + if (con) + return; already_warned = true; pr_warn("kgdboc_earlycon is still using bootconsole\n"); @@ -484,25 +523,25 @@ static int kgdboc_earlycon_deferred_exit(struct console *con) static void kgdboc_earlycon_deinit(void) { - if (!earlycon) + if (!kgdboc_earlycon_io_ops.cons) return; - if (earlycon->exit == kgdboc_earlycon_deferred_exit) + if (kgdboc_earlycon_io_ops.cons->exit == kgdboc_earlycon_deferred_exit) /* * kgdboc_earlycon is exiting but original boot console exit * was never called (AKA kgdboc_earlycon_deferred_exit() * didn't ever run). Undo our trap. */ - earlycon->exit = earlycon_orig_exit; - else if (earlycon->exit) + kgdboc_earlycon_io_ops.cons->exit = earlycon_orig_exit; + else if (kgdboc_earlycon_io_ops.cons->exit) /* * We skipped calling the exit() routine so we could try to * keep using the boot console even after it went away. We're * finally done so call the function now. */ - earlycon->exit(earlycon); + kgdboc_earlycon_io_ops.cons->exit(kgdboc_earlycon_io_ops.cons); - earlycon = NULL; + kgdboc_earlycon_io_ops.cons = NULL; } static struct kgdb_io kgdboc_earlycon_io_ops = { @@ -511,7 +550,6 @@ static struct kgdb_io kgdboc_earlycon_io_ops = { .write_char = kgdboc_earlycon_put_char, .pre_exception = kgdboc_earlycon_pre_exp_handler, .deinit = kgdboc_earlycon_deinit, - .is_console = true, }; #define MAX_CONSOLE_NAME_LEN (sizeof((struct console *) 0)->name) @@ -528,17 +566,25 @@ static int __init kgdboc_earlycon_init(char *opt) * Look for a matching console, or if the name was left blank just * pick the first one we find. */ - console_lock(); + + /* + * Hold the console_list_lock to guarantee that no consoles are + * unregistered until the kgdboc_earlycon setup is complete. + * Trapping the exit() callback relies on exit() not being + * called until the trap is setup. This also allows safe + * traversal of the console list and race-free reading of @flags. + */ + console_list_lock(); for_each_console(con) { if (con->write && con->read && - (con->flags & (CON_BOOT | CON_ENABLED)) && (!opt || !opt[0] || strcmp(con->name, opt) == 0)) break; } if (!con) { /* - * Both earlycon and kgdboc_earlycon are initialized during * early parameter parsing. We cannot guarantee earlycon gets + * Both earlycon and kgdboc_earlycon are initialized during + * early parameter parsing. We cannot guarantee earlycon gets * in first and, in any case, on ACPI systems earlycon may * defer its own initialization (usually to somewhere within * setup_arch() ). To cope with either of these situations @@ -557,10 +603,10 @@ static int __init kgdboc_earlycon_init(char *opt) goto unlock; } - earlycon = con; + kgdboc_earlycon_io_ops.cons = con; pr_info("Going to register kgdb with earlycon '%s'\n", con->name); if (kgdb_register_io_module(&kgdboc_earlycon_io_ops) != 0) { - earlycon = NULL; + kgdboc_earlycon_io_ops.cons = NULL; pr_info("Failed to register kgdb with earlycon\n"); } else { /* Trap exit so we can keep earlycon longer if needed. */ @@ -569,7 +615,7 @@ static int __init kgdboc_earlycon_init(char *opt) } unlock: - console_unlock(); + console_list_unlock(); /* Non-zero means malformed option so we always return zero */ return 0; diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 62813e421f12..62cd9e0bb377 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -8,6 +8,7 @@ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/console.h> #include <linux/device.h> @@ -16,9 +17,8 @@ #include <linux/ioport.h> #include <linux/lantiq.h> #include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/slab.h> @@ -95,9 +95,7 @@ #define ASCFSTAT_RXFFLMASK 0x003F #define ASCFSTAT_TXFFLMASK 0x3F00 #define ASCFSTAT_TXFREEMASK 0x3F000000 -#define ASCFSTAT_TXFREEOFF 24 -static void lqasc_tx_chars(struct uart_port *port); static struct ltq_uart_port *lqasc_port[MAXPORTS]; static struct uart_driver lqasc_reg; @@ -141,14 +139,24 @@ lqasc_stop_tx(struct uart_port *port) return; } +static bool lqasc_tx_ready(struct uart_port *port) +{ + u32 fstat = __raw_readl(port->membase + LTQ_ASC_FSTAT); + + return FIELD_GET(ASCFSTAT_TXFREEMASK, fstat); +} + static void lqasc_start_tx(struct uart_port *port) { unsigned long flags; struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + u8 ch; spin_lock_irqsave(<q_port->lock, flags); - lqasc_tx_chars(port); + uart_port_tx(port, ch, + lqasc_tx_ready(port), + writeb(ch, port->membase + LTQ_ASC_TBUF)); spin_unlock_irqrestore(<q_port->lock, flags); return; } @@ -221,37 +229,6 @@ lqasc_rx_chars(struct uart_port *port) return 0; } -static void -lqasc_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - if (uart_tx_stopped(port)) { - lqasc_stop_tx(port); - return; - } - - while (((__raw_readl(port->membase + LTQ_ASC_FSTAT) & - ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { - if (port->x_char) { - writeb(port->x_char, port->membase + LTQ_ASC_TBUF); - port->icount.tx++; - port->x_char = 0; - continue; - } - - if (uart_circ_empty(xmit)) - break; - - writeb(port->state->xmit.buf[port->state->xmit.tail], - port->membase + LTQ_ASC_TBUF); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - static irqreturn_t lqasc_tx_int(int irq, void *_port) { @@ -274,6 +251,7 @@ lqasc_err_int(int irq, void *_port) struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); spin_lock_irqsave(<q_port->lock, flags); + __raw_writel(ASC_IRNCR_EIR, port->membase + LTQ_ASC_IRNCR); /* clear any pending interrupts */ asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); @@ -407,8 +385,8 @@ lqasc_shutdown(struct uart_port *port) } static void -lqasc_set_termios(struct uart_port *port, - struct ktermios *new, struct ktermios *old) +lqasc_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) { unsigned int cflag; unsigned int iflag; @@ -600,17 +578,14 @@ static const struct uart_ops lqasc_pops = { #ifdef CONFIG_SERIAL_LANTIQ_CONSOLE static void -lqasc_console_putchar(struct uart_port *port, int ch) +lqasc_console_putchar(struct uart_port *port, unsigned char ch) { - int fifofree; - if (!port->membase) return; - do { - fifofree = (__raw_readl(port->membase + LTQ_ASC_FSTAT) - & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; - } while (fifofree == 0); + while (!lqasc_tx_ready(port)) + ; + writeb(ch, port->membase + LTQ_ASC_TBUF); } @@ -728,19 +703,23 @@ static struct uart_driver lqasc_reg = { static int fetch_irq_lantiq(struct device *dev, struct ltq_uart_port *ltq_port) { struct uart_port *port = <q_port->port; - struct resource irqres[3]; - int ret; - - ret = of_irq_to_resource_table(dev->of_node, irqres, 3); - if (ret != 3) { - dev_err(dev, - "failed to get IRQs for serial port\n"); - return -ENODEV; - } - ltq_port->tx_irq = irqres[0].start; - ltq_port->rx_irq = irqres[1].start; - ltq_port->err_irq = irqres[2].start; - port->irq = irqres[0].start; + struct platform_device *pdev = to_platform_device(dev); + int irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ltq_port->tx_irq = irq; + irq = platform_get_irq(pdev, 1); + if (irq < 0) + return irq; + ltq_port->rx_irq = irq; + irq = platform_get_irq(pdev, 2); + if (irq < 0) + return irq; + ltq_port->err_irq = irq; + + port->irq = ltq_port->tx_irq; return 0; } @@ -793,11 +772,9 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port) struct uart_port *port = <q_port->port; int ret; - ret = of_irq_get(dev->of_node, 0); - if (ret < 0) { - dev_err(dev, "failed to fetch IRQ for serial port\n"); + ret = platform_get_irq(to_platform_device(dev), 0); + if (ret < 0) return ret; - } ltq_port->common_irq = ret; port->irq = ret; @@ -876,7 +853,7 @@ static int lqasc_probe(struct platform_device *pdev) port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &lqasc_pops; port->fifosize = 16; - port->type = PORT_LTQ_ASC, + port->type = PORT_LTQ_ASC; port->line = line; port->dev = &pdev->dev; /* unused, just to be backward-compatible */ @@ -908,11 +885,11 @@ static int lqasc_probe(struct platform_device *pdev) return ret; } -static int lqasc_remove(struct platform_device *pdev) +static void lqasc_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - return uart_remove_one_port(&lqasc_reg, port); + uart_remove_one_port(&lqasc_reg, port); } static const struct ltq_soc_data soc_data_lantiq = { diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c new file mode 100644 index 000000000000..6429e8f11f36 --- /dev/null +++ b/drivers/tty/serial/liteuart.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LiteUART serial controller (LiteX) Driver + * + * Copyright (C) 2019-2020 Antmicro <www.antmicro.com> + */ + +#include <linux/bits.h> +#include <linux/console.h> +#include <linux/interrupt.h> +#include <linux/litex.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/tty_flip.h> +#include <linux/xarray.h> + +/* + * CSRs definitions (base address offsets + width) + * + * The definitions below are true for LiteX SoC configured for 8-bit CSR Bus, + * 32-bit aligned. + * + * Supporting other configurations might require new definitions or a more + * generic way of indexing the LiteX CSRs. + * + * For more details on how CSRs are defined and handled in LiteX, see comments + * in the LiteX SoC Driver: drivers/soc/litex/litex_soc_ctrl.c + */ +#define OFF_RXTX 0x00 +#define OFF_TXFULL 0x04 +#define OFF_RXEMPTY 0x08 +#define OFF_EV_STATUS 0x0c +#define OFF_EV_PENDING 0x10 +#define OFF_EV_ENABLE 0x14 + +/* events */ +#define EV_TX BIT(0) +#define EV_RX BIT(1) + +struct liteuart_port { + struct uart_port port; + struct timer_list timer; + u8 irq_reg; +}; + +#define to_liteuart_port(port) container_of(port, struct liteuart_port, port) + +static DEFINE_XARRAY_FLAGS(liteuart_array, XA_FLAGS_ALLOC); + +#ifdef CONFIG_SERIAL_LITEUART_CONSOLE +static struct console liteuart_console; +#endif + +static struct uart_driver liteuart_driver = { + .owner = THIS_MODULE, + .driver_name = KBUILD_MODNAME, + .dev_name = "ttyLXU", + .major = 0, + .minor = 0, + .nr = CONFIG_SERIAL_LITEUART_MAX_PORTS, +#ifdef CONFIG_SERIAL_LITEUART_CONSOLE + .cons = &liteuart_console, +#endif +}; + +static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask) +{ + struct liteuart_port *uart = to_liteuart_port(port); + + if (set) + uart->irq_reg |= mask; + else + uart->irq_reg &= ~mask; + + if (port->irq) + litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg); +} + +static void liteuart_stop_tx(struct uart_port *port) +{ + liteuart_update_irq_reg(port, false, EV_TX); +} + +static void liteuart_start_tx(struct uart_port *port) +{ + liteuart_update_irq_reg(port, true, EV_TX); +} + +static void liteuart_stop_rx(struct uart_port *port) +{ + struct liteuart_port *uart = to_liteuart_port(port); + + /* just delete timer */ + timer_delete(&uart->timer); +} + +static void liteuart_rx_chars(struct uart_port *port) +{ + unsigned char __iomem *membase = port->membase; + u8 ch; + + while (!litex_read8(membase + OFF_RXEMPTY)) { + ch = litex_read8(membase + OFF_RXTX); + port->icount.rx++; + + /* necessary for RXEMPTY to refresh its value */ + litex_write8(membase + OFF_EV_PENDING, EV_RX); + + /* no overflow bits in status */ + if (!(uart_handle_sysrq_char(port, ch))) + uart_insert_char(port, 1, 0, ch, TTY_NORMAL); + } + + tty_flip_buffer_push(&port->state->port); +} + +static void liteuart_tx_chars(struct uart_port *port) +{ + u8 ch; + + uart_port_tx(port, ch, + !litex_read8(port->membase + OFF_TXFULL), + litex_write8(port->membase + OFF_RXTX, ch)); +} + +static irqreturn_t liteuart_interrupt(int irq, void *data) +{ + struct liteuart_port *uart = data; + struct uart_port *port = &uart->port; + unsigned long flags; + u8 isr; + + /* + * if polling, the context would be "in_serving_softirq", so use + * irq[save|restore] spin_lock variants to cover all possibilities + */ + uart_port_lock_irqsave(port, &flags); + isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg; + if (isr & EV_RX) + liteuart_rx_chars(port); + if (isr & EV_TX) + liteuart_tx_chars(port); + uart_port_unlock_irqrestore(port, flags); + + return IRQ_RETVAL(isr); +} + +static void liteuart_timer(struct timer_list *t) +{ + struct liteuart_port *uart = timer_container_of(uart, t, timer); + struct uart_port *port = &uart->port; + + liteuart_interrupt(0, port); + mod_timer(&uart->timer, jiffies + uart_poll_timeout(port)); +} + +static unsigned int liteuart_tx_empty(struct uart_port *port) +{ + /* not really tx empty, just checking if tx is not full */ + if (!litex_read8(port->membase + OFF_TXFULL)) + return TIOCSER_TEMT; + + return 0; +} + +static void liteuart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* modem control register is not present in LiteUART */ +} + +static unsigned int liteuart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static int liteuart_startup(struct uart_port *port) +{ + struct liteuart_port *uart = to_liteuart_port(port); + unsigned long flags; + int ret; + + if (port->irq) { + ret = request_irq(port->irq, liteuart_interrupt, 0, + KBUILD_MODNAME, uart); + if (ret) { + dev_warn(port->dev, + "line %d irq %d failed: switch to polling\n", + port->line, port->irq); + port->irq = 0; + } + } + + uart_port_lock_irqsave(port, &flags); + /* only enabling rx irqs during startup */ + liteuart_update_irq_reg(port, true, EV_RX); + uart_port_unlock_irqrestore(port, flags); + + if (!port->irq) { + timer_setup(&uart->timer, liteuart_timer, 0); + mod_timer(&uart->timer, jiffies + uart_poll_timeout(port)); + } + + return 0; +} + +static void liteuart_shutdown(struct uart_port *port) +{ + struct liteuart_port *uart = to_liteuart_port(port); + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + liteuart_update_irq_reg(port, false, EV_RX | EV_TX); + uart_port_unlock_irqrestore(port, flags); + + if (port->irq) + free_irq(port->irq, port); + else + timer_delete_sync(&uart->timer); +} + +static void liteuart_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) +{ + unsigned int baud; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + + /* update baudrate */ + baud = uart_get_baud_rate(port, new, old, 0, 460800); + uart_update_timeout(port, new->c_cflag, baud); + + uart_port_unlock_irqrestore(port, flags); +} + +static const char *liteuart_type(struct uart_port *port) +{ + return "liteuart"; +} + +static void liteuart_config_port(struct uart_port *port, int flags) +{ + /* + * Driver core for serial ports forces a non-zero value for port type. + * Write an arbitrary value here to accommodate the serial core driver, + * as ID part of UAPI is redundant. + */ + port->type = 1; +} + +static int liteuart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (port->type != PORT_UNKNOWN && ser->type != 1) + return -EINVAL; + + return 0; +} + +static const struct uart_ops liteuart_ops = { + .tx_empty = liteuart_tx_empty, + .set_mctrl = liteuart_set_mctrl, + .get_mctrl = liteuart_get_mctrl, + .stop_tx = liteuart_stop_tx, + .start_tx = liteuart_start_tx, + .stop_rx = liteuart_stop_rx, + .startup = liteuart_startup, + .shutdown = liteuart_shutdown, + .set_termios = liteuart_set_termios, + .type = liteuart_type, + .config_port = liteuart_config_port, + .verify_port = liteuart_verify_port, +}; + +static int liteuart_probe(struct platform_device *pdev) +{ + struct liteuart_port *uart; + struct uart_port *port; + struct xa_limit limit; + int dev_id, ret; + + uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + port = &uart->port; + + /* get membase */ + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + + ret = platform_get_irq_optional(pdev, 0); + if (ret < 0 && ret != -ENXIO) + return ret; + if (ret > 0) + port->irq = ret; + + /* look for aliases; auto-enumerate for free index if not found */ + dev_id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (dev_id < 0) + limit = XA_LIMIT(0, CONFIG_SERIAL_LITEUART_MAX_PORTS); + else + limit = XA_LIMIT(dev_id, dev_id); + + ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL); + if (ret) + return ret; + + /* values not from device tree */ + port->dev = &pdev->dev; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &liteuart_ops; + port->fifosize = 16; + port->type = PORT_UNKNOWN; + port->line = dev_id; + spin_lock_init(&port->lock); + + platform_set_drvdata(pdev, port); + + ret = uart_add_one_port(&liteuart_driver, &uart->port); + if (ret) + goto err_erase_id; + + return 0; + +err_erase_id: + xa_erase(&liteuart_array, dev_id); + + return ret; +} + +static void liteuart_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + unsigned int line = port->line; + + uart_remove_one_port(&liteuart_driver, port); + xa_erase(&liteuart_array, line); +} + +static const struct of_device_id liteuart_of_match[] = { + { .compatible = "litex,liteuart" }, + {} +}; +MODULE_DEVICE_TABLE(of, liteuart_of_match); + +static struct platform_driver liteuart_platform_driver = { + .probe = liteuart_probe, + .remove = liteuart_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = liteuart_of_match, + }, +}; + +#ifdef CONFIG_SERIAL_LITEUART_CONSOLE + +static void liteuart_putchar(struct uart_port *port, unsigned char ch) +{ + while (litex_read8(port->membase + OFF_TXFULL)) + cpu_relax(); + + litex_write8(port->membase + OFF_RXTX, ch); +} + +static void liteuart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct liteuart_port *uart; + struct uart_port *port; + unsigned long flags; + + uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index); + port = &uart->port; + + uart_port_lock_irqsave(port, &flags); + uart_console_write(port, s, count, liteuart_putchar); + uart_port_unlock_irqrestore(port, flags); +} + +static int liteuart_console_setup(struct console *co, char *options) +{ + struct liteuart_port *uart; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index); + if (!uart) + return -ENODEV; + + port = &uart->port; + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console liteuart_console = { + .name = KBUILD_MODNAME, + .write = liteuart_console_write, + .device = uart_console_device, + .setup = liteuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &liteuart_driver, +}; + +static int __init liteuart_console_init(void) +{ + register_console(&liteuart_console); + + return 0; +} +console_initcall(liteuart_console_init); + +static void early_liteuart_write(struct console *console, const char *s, + unsigned int count) +{ + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; + + uart_console_write(port, s, count, liteuart_putchar); +} + +static int __init early_liteuart_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = early_liteuart_write; + return 0; +} + +OF_EARLYCON_DECLARE(liteuart, "litex,liteuart", early_liteuart_setup); +#endif /* CONFIG_SERIAL_LITEUART_CONSOLE */ + +static int __init liteuart_init(void) +{ + int res; + + res = uart_register_driver(&liteuart_driver); + if (res) + return res; + + res = platform_driver_register(&liteuart_platform_driver); + if (res) + uart_unregister_driver(&liteuart_driver); + + return res; +} + +static void __exit liteuart_exit(void) +{ + platform_driver_unregister(&liteuart_platform_driver); + uart_unregister_driver(&liteuart_driver); +} + +module_init(liteuart_init); +module_exit(liteuart_exit); + +MODULE_AUTHOR("Antmicro <www.antmicro.com>"); +MODULE_DESCRIPTION("LiteUART serial driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:liteuart"); diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index b5898c932036..42c5f9bc18b7 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -122,7 +122,7 @@ static void wait_for_xmit_ready(struct uart_port *port) } } -static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch) +static void lpc32xx_hsuart_console_putchar(struct uart_port *port, unsigned char ch) { wait_for_xmit_ready(port); writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase)); @@ -136,20 +136,16 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s, int locked = 1; touch_nmi_watchdog(); - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&up->port.lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock(&up->port.lock); + uart_port_lock_irqsave(&up->port, &flags); uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); wait_for_xmit_empty(&up->port); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init lpc32xx_hsuart_console_setup(struct console *co, @@ -233,20 +229,17 @@ static unsigned int __serial_get_clock_div(unsigned long uartclk, hsu_rate++; } - if (hsu_rate > 0xFF) - hsu_rate = 0xFF; return goodrate; } static void __serial_uart_flush(struct uart_port *port) { - u32 tmp; int cnt = 0; while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) && (cnt++ < FIFO_READ_LIMIT)) - tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + readl(LPC32XX_HSUART_FIFO(port->membase)); } static void __serial_lpc32xx_rx(struct uart_port *port) @@ -269,51 +262,29 @@ static void __serial_lpc32xx_rx(struct uart_port *port) tty_insert_flip_char(tport, 0, TTY_FRAME); } - tty_insert_flip_char(tport, (tmp & 0xFF), flag); + if (!uart_prepare_sysrq_char(port, tmp & 0xff)) + tty_insert_flip_char(tport, (tmp & 0xFF), flag); tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } -static void __serial_lpc32xx_tx(struct uart_port *port) +static bool serial_lpc32xx_tx_ready(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int tmp; + u32 level = readl(LPC32XX_HSUART_LEVEL(port->membase)); - if (port->x_char) { - writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase)); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - goto exit_tx; - - /* Transfer data */ - while (LPC32XX_HSU_TX_LEV(readl( - LPC32XX_HSUART_LEVEL(port->membase))) < 64) { - writel((u32) xmit->buf[xmit->tail], - LPC32XX_HSUART_FIFO(port->membase)); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } + return LPC32XX_HSU_TX_LEV(level) < 64; +} - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); +static void __serial_lpc32xx_tx(struct uart_port *port) +{ + u8 ch; -exit_tx: - if (uart_circ_empty(xmit)) { - tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); - tmp &= ~LPC32XX_HSU_TX_INT_EN; - writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); - } + uart_port_tx(port, ch, + serial_lpc32xx_tx_ready(port), + writel(ch, LPC32XX_HSUART_FIFO(port->membase))); } static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) @@ -322,7 +293,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) struct tty_port *tport = &port->state->port; u32 status; - spin_lock(&port->lock); + uart_port_lock(port); /* Read UART status and clear latched interrupts */ status = readl(LPC32XX_HSUART_IIR(port->membase)); @@ -344,7 +315,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) LPC32XX_HSUART_IIR(port->membase)); port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - tty_schedule_flip(tport); + tty_flip_buffer_push(tport); } /* Data received? */ @@ -357,7 +328,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) __serial_lpc32xx_tx(port); } - spin_unlock(&port->lock); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -428,14 +399,14 @@ static void serial_lpc32xx_break_ctl(struct uart_port *port, unsigned long flags; u32 tmp; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); if (break_state != 0) tmp |= LPC32XX_HSU_BREAK; else tmp &= ~LPC32XX_HSU_BREAK; writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* port->lock is not held. */ @@ -445,7 +416,7 @@ static int serial_lpc32xx_startup(struct uart_port *port) unsigned long flags; u32 tmp; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); __serial_uart_flush(port); @@ -465,7 +436,7 @@ static int serial_lpc32xx_startup(struct uart_port *port) lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); retval = request_irq(port->irq, serial_lpc32xx_interrupt, 0, MODNAME, port); @@ -482,7 +453,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port) u32 tmp; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; @@ -490,7 +461,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port) lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */ - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); free_irq(port->irq, port); } @@ -498,7 +469,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port) /* port->lock is not held. */ static void serial_lpc32xx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, quot; @@ -515,7 +486,7 @@ static void serial_lpc32xx_set_termios(struct uart_port *port, quot = __serial_get_clock_div(port->uartclk, baud); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Ignore characters? */ tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); @@ -529,7 +500,7 @@ static void serial_lpc32xx_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) @@ -683,13 +654,11 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev) /* * Remove serial ports registered against a platform device. */ -static int serial_hs_lpc32xx_remove(struct platform_device *pdev) +static void serial_hs_lpc32xx_remove(struct platform_device *pdev) { struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); uart_remove_one_port(&lpc32xx_hs_reg, &p->port); - - return 0; } diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c new file mode 100644 index 000000000000..285b0fe41a86 --- /dev/null +++ b/drivers/tty/serial/ma35d1_serial.c @@ -0,0 +1,831 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MA35D1 serial driver + * Copyright (C) 2023 Nuvoton Technology Corp. + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/iopoll.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty_flip.h> +#include <linux/units.h> + +#define MA35_UART_NR 17 + +#define MA35_RBR_REG 0x00 +#define MA35_THR_REG 0x00 +#define MA35_IER_REG 0x04 +#define MA35_FCR_REG 0x08 +#define MA35_LCR_REG 0x0C +#define MA35_MCR_REG 0x10 +#define MA35_MSR_REG 0x14 +#define MA35_FSR_REG 0x18 +#define MA35_ISR_REG 0x1C +#define MA35_TOR_REG 0x20 +#define MA35_BAUD_REG 0x24 +#define MA35_ALTCTL_REG 0x2C +#define MA35_FUN_SEL_REG 0x30 +#define MA35_WKCTL_REG 0x40 +#define MA35_WKSTS_REG 0x44 + +/* MA35_IER_REG - Interrupt Enable Register */ +#define MA35_IER_RDA_IEN BIT(0) /* RBR Available Interrupt Enable */ +#define MA35_IER_THRE_IEN BIT(1) /* THR Empty Interrupt Enable */ +#define MA35_IER_RLS_IEN BIT(2) /* RX Line Status Interrupt Enable */ +#define MA35_IER_RTO_IEN BIT(4) /* RX Time-out Interrupt Enable */ +#define MA35_IER_BUFERR_IEN BIT(5) /* Buffer Error Interrupt Enable */ +#define MA35_IER_TIME_OUT_EN BIT(11) /* RX Buffer Time-out Counter Enable */ +#define MA35_IER_AUTO_RTS BIT(12) /* nRTS Auto-flow Control Enable */ +#define MA35_IER_AUTO_CTS BIT(13) /* nCTS Auto-flow Control Enable */ + +/* MA35_FCR_REG - FIFO Control Register */ +#define MA35_FCR_RFR BIT(1) /* RX Field Software Reset */ +#define MA35_FCR_TFR BIT(2) /* TX Field Software Reset */ +#define MA35_FCR_RFITL_MASK GENMASK(7, 4) /* RX FIFO Interrupt Trigger Level */ +#define MA35_FCR_RFITL_1BYTE FIELD_PREP(MA35_FCR_RFITL_MASK, 0) +#define MA35_FCR_RFITL_4BYTES FIELD_PREP(MA35_FCR_RFITL_MASK, 1) +#define MA35_FCR_RFITL_8BYTES FIELD_PREP(MA35_FCR_RFITL_MASK, 2) +#define MA35_FCR_RFITL_14BYTES FIELD_PREP(MA35_FCR_RFITL_MASK, 3) +#define MA35_FCR_RFITL_30BYTES FIELD_PREP(MA35_FCR_RFITL_MASK, 4) +#define MA35_FCR_RTSTL_MASK GENMASK(19, 16) /* nRTS Trigger Level */ +#define MA35_FCR_RTSTL_1BYTE FIELD_PREP(MA35_FCR_RTSTL_MASK, 0) +#define MA35_FCR_RTSTL_4BYTES FIELD_PREP(MA35_FCR_RTSTL_MASK, 1) +#define MA35_FCR_RTSTL_8BYTES FIELD_PREP(MA35_FCR_RTSTL_MASK, 2) +#define MA35_FCR_RTSTL_14BYTES FIELD_PREP(MA35_FCR_RTSTL_MASK, 3) +#define MA35_FCR_RTSTLL_30BYTES FIELD_PREP(MA35_FCR_RTSTL_MASK, 4) + +/* MA35_LCR_REG - Line Control Register */ +#define MA35_LCR_NSB BIT(2) /* Number of “STOP Bit” */ +#define MA35_LCR_PBE BIT(3) /* Parity Bit Enable */ +#define MA35_LCR_EPE BIT(4) /* Even Parity Enable */ +#define MA35_LCR_SPE BIT(5) /* Stick Parity Enable */ +#define MA35_LCR_BREAK BIT(6) /* Break Control */ +#define MA35_LCR_WLS_MASK GENMASK(1, 0) /* Word Length Selection */ +#define MA35_LCR_WLS_5BITS FIELD_PREP(MA35_LCR_WLS_MASK, 0) +#define MA35_LCR_WLS_6BITS FIELD_PREP(MA35_LCR_WLS_MASK, 1) +#define MA35_LCR_WLS_7BITS FIELD_PREP(MA35_LCR_WLS_MASK, 2) +#define MA35_LCR_WLS_8BITS FIELD_PREP(MA35_LCR_WLS_MASK, 3) + +/* MA35_MCR_REG - Modem Control Register */ +#define MA35_MCR_RTS_CTRL BIT(1) /* nRTS Signal Control */ +#define MA35_MCR_RTSACTLV BIT(9) /* nRTS Pin Active Level */ +#define MA35_MCR_RTSSTS BIT(13) /* nRTS Pin Status (Read Only) */ + +/* MA35_MSR_REG - Modem Status Register */ +#define MA35_MSR_CTSDETF BIT(0) /* Detect nCTS State Change Flag */ +#define MA35_MSR_CTSSTS BIT(4) /* nCTS Pin Status (Read Only) */ +#define MA35_MSR_CTSACTLV BIT(8) /* nCTS Pin Active Level */ + +/* MA35_FSR_REG - FIFO Status Register */ +#define MA35_FSR_RX_OVER_IF BIT(0) /* RX Overflow Error Interrupt Flag */ +#define MA35_FSR_PEF BIT(4) /* Parity Error Flag*/ +#define MA35_FSR_FEF BIT(5) /* Framing Error Flag */ +#define MA35_FSR_BIF BIT(6) /* Break Interrupt Flag */ +#define MA35_FSR_RX_EMPTY BIT(14) /* Receiver FIFO Empty (Read Only) */ +#define MA35_FSR_RX_FULL BIT(15) /* Receiver FIFO Full (Read Only) */ +#define MA35_FSR_TX_EMPTY BIT(22) /* Transmitter FIFO Empty (Read Only) */ +#define MA35_FSR_TX_FULL BIT(23) /* Transmitter FIFO Full (Read Only) */ +#define MA35_FSR_TX_OVER_IF BIT(24) /* TX Overflow Error Interrupt Flag */ +#define MA35_FSR_TE_FLAG BIT(28) /* Transmitter Empty Flag (Read Only) */ +#define MA35_FSR_RXPTR_MSK GENMASK(13, 8) /* TX FIFO Pointer mask */ +#define MA35_FSR_TXPTR_MSK GENMASK(21, 16) /* RX FIFO Pointer mask */ + +/* MA35_ISR_REG - Interrupt Status Register */ +#define MA35_ISR_RDA_IF BIT(0) /* RBR Available Interrupt Flag */ +#define MA35_ISR_THRE_IF BIT(1) /* THR Empty Interrupt Flag */ +#define MA35_ISR_RLSIF BIT(2) /* Receive Line Interrupt Flag */ +#define MA35_ISR_MODEMIF BIT(3) /* MODEM Interrupt Flag */ +#define MA35_ISR_RXTO_IF BIT(4) /* RX Time-out Interrupt Flag */ +#define MA35_ISR_BUFEIF BIT(5) /* Buffer Error Interrupt Flag */ +#define MA35_ISR_WK_IF BIT(6) /* UART Wake-up Interrupt Flag */ +#define MA35_ISR_RDAINT BIT(8) /* RBR Available Interrupt Indicator */ +#define MA35_ISR_THRE_INT BIT(9) /* THR Empty Interrupt Indicator */ +#define MA35_ISR_ALL 0xFFFFFFFF + +/* MA35_BAUD_REG - Baud Rate Divider Register */ +#define MA35_BAUD_MODE_MASK GENMASK(29, 28) +#define MA35_BAUD_MODE0 FIELD_PREP(MA35_BAUD_MODE_MASK, 0) +#define MA35_BAUD_MODE1 FIELD_PREP(MA35_BAUD_MODE_MASK, 2) +#define MA35_BAUD_MODE2 FIELD_PREP(MA35_BAUD_MODE_MASK, 3) +#define MA35_BAUD_MASK GENMASK(15, 0) + +/* MA35_ALTCTL_REG - Alternate Control/Status Register */ +#define MA35_ALTCTL_RS485AUD BIT(10) /* RS-485 Auto Direction Function */ + +/* MA35_FUN_SEL_REG - Function Select Register */ +#define MA35_FUN_SEL_MASK GENMASK(2, 0) +#define MA35_FUN_SEL_UART FIELD_PREP(MA35_FUN_SEL_MASK, 0) +#define MA35_FUN_SEL_RS485 FIELD_PREP(MA35_FUN_SEL_MASK, 3) + +/* The constrain for MA35D1 UART baud rate divider */ +#define MA35_BAUD_DIV_MAX 0xFFFF +#define MA35_BAUD_DIV_MIN 11 + +/* UART FIFO depth */ +#define MA35_UART_FIFO_DEPTH 32 +/* UART console clock */ +#define MA35_UART_CONSOLE_CLK (24 * HZ_PER_MHZ) +/* UART register ioremap size */ +#define MA35_UART_REG_SIZE 0x100 +/* Rx Timeout */ +#define MA35_UART_RX_TOUT 0x40 + +#define MA35_IER_CONFIG (MA35_IER_RTO_IEN | MA35_IER_RDA_IEN | \ + MA35_IER_TIME_OUT_EN | MA35_IER_BUFERR_IEN) + +#define MA35_ISR_IF_CHECK (MA35_ISR_RDA_IF | MA35_ISR_RXTO_IF | \ + MA35_ISR_THRE_INT | MA35_ISR_BUFEIF) + +#define MA35_FSR_TX_BOTH_EMPTY (MA35_FSR_TE_FLAG | MA35_FSR_TX_EMPTY) + +static struct uart_driver ma35d1serial_reg; + +struct uart_ma35d1_port { + struct uart_port port; + struct clk *clk; + u16 capabilities; /* port capabilities */ + u8 ier; + u8 lcr; + u8 mcr; + u32 baud_rate; + u32 console_baud_rate; + u32 console_line; + u32 console_int; +}; + +static struct uart_ma35d1_port ma35d1serial_ports[MA35_UART_NR]; + +static struct uart_ma35d1_port *to_ma35d1_uart_port(struct uart_port *uart) +{ + return container_of(uart, struct uart_ma35d1_port, port); +} + +static u32 serial_in(struct uart_ma35d1_port *p, u32 offset) +{ + return readl_relaxed(p->port.membase + offset); +} + +static void serial_out(struct uart_ma35d1_port *p, u32 offset, u32 value) +{ + writel_relaxed(value, p->port.membase + offset); +} + +static void __stop_tx(struct uart_ma35d1_port *p) +{ + u32 ier; + + ier = serial_in(p, MA35_IER_REG); + if (ier & MA35_IER_THRE_IEN) + serial_out(p, MA35_IER_REG, ier & ~MA35_IER_THRE_IEN); +} + +static void ma35d1serial_stop_tx(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + + __stop_tx(up); +} + +static void transmit_chars(struct uart_ma35d1_port *up) +{ + u32 count; + u8 ch; + + if (uart_tx_stopped(&up->port)) { + ma35d1serial_stop_tx(&up->port); + return; + } + count = MA35_UART_FIFO_DEPTH - FIELD_GET(MA35_FSR_TXPTR_MSK, + serial_in(up, MA35_FSR_REG)); + uart_port_tx_limited(&up->port, ch, count, + !(serial_in(up, MA35_FSR_REG) & MA35_FSR_TX_FULL), + serial_out(up, MA35_THR_REG, ch), + ({})); +} + +static void ma35d1serial_start_tx(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 ier; + + ier = serial_in(up, MA35_IER_REG); + serial_out(up, MA35_IER_REG, ier & ~MA35_IER_THRE_IEN); + transmit_chars(up); + serial_out(up, MA35_IER_REG, ier | MA35_IER_THRE_IEN); +} + +static void ma35d1serial_stop_rx(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 ier; + + ier = serial_in(up, MA35_IER_REG); + ier &= ~MA35_IER_RDA_IEN; + serial_out(up, MA35_IER_REG, ier); +} + +static void receive_chars(struct uart_ma35d1_port *up) +{ + int max_count = 256; + u8 ch, flag; + u32 fsr; + + fsr = serial_in(up, MA35_FSR_REG); + do { + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(fsr & (MA35_FSR_BIF | MA35_FSR_FEF | + MA35_FSR_PEF | MA35_FSR_RX_OVER_IF))) { + if (fsr & MA35_FSR_BIF) { + up->port.icount.brk++; + if (uart_handle_break(&up->port)) + continue; + } + if (fsr & MA35_FSR_FEF) + up->port.icount.frame++; + if (fsr & MA35_FSR_PEF) + up->port.icount.parity++; + if (fsr & MA35_FSR_RX_OVER_IF) + up->port.icount.overrun++; + + serial_out(up, MA35_FSR_REG, + fsr & (MA35_FSR_BIF | MA35_FSR_FEF | + MA35_FSR_PEF | MA35_FSR_RX_OVER_IF)); + if (fsr & MA35_FSR_BIF) + flag = TTY_BREAK; + else if (fsr & MA35_FSR_PEF) + flag = TTY_PARITY; + else if (fsr & MA35_FSR_FEF) + flag = TTY_FRAME; + } + + ch = serial_in(up, MA35_RBR_REG); + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + + uart_port_lock(&up->port); + uart_insert_char(&up->port, fsr, MA35_FSR_RX_OVER_IF, ch, flag); + uart_port_unlock(&up->port); + + fsr = serial_in(up, MA35_FSR_REG); + } while (!(fsr & MA35_FSR_RX_EMPTY) && (max_count-- > 0)); + + uart_port_lock(&up->port); + tty_flip_buffer_push(&up->port.state->port); + uart_port_unlock(&up->port); +} + +static irqreturn_t ma35d1serial_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 isr, fsr; + + isr = serial_in(up, MA35_ISR_REG); + fsr = serial_in(up, MA35_FSR_REG); + + if (!(isr & MA35_ISR_IF_CHECK)) + return IRQ_NONE; + + if (isr & (MA35_ISR_RDA_IF | MA35_ISR_RXTO_IF)) + receive_chars(up); + if (isr & MA35_ISR_THRE_INT) + transmit_chars(up); + if (fsr & MA35_FSR_TX_OVER_IF) + serial_out(up, MA35_FSR_REG, MA35_FSR_TX_OVER_IF); + + return IRQ_HANDLED; +} + +static u32 ma35d1serial_tx_empty(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 fsr; + + fsr = serial_in(up, MA35_FSR_REG); + if ((fsr & MA35_FSR_TX_BOTH_EMPTY) == MA35_FSR_TX_BOTH_EMPTY) + return TIOCSER_TEMT; + else + return 0; +} + +static u32 ma35d1serial_get_mctrl(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 status; + u32 ret = 0; + + status = serial_in(up, MA35_MSR_REG); + if (!(status & MA35_MSR_CTSSTS)) + ret |= TIOCM_CTS; + return ret; +} + +static void ma35d1serial_set_mctrl(struct uart_port *port, u32 mctrl) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 mcr, msr, ier; + + mcr = serial_in(up, MA35_MCR_REG); + mcr &= ~MA35_MCR_RTS_CTRL; + + if (mctrl & TIOCM_RTS) + mcr |= MA35_MCR_RTSACTLV; + else + mcr &= ~MA35_MCR_RTSACTLV; + + if (up->mcr & UART_MCR_AFE) { + ier = serial_in(up, MA35_IER_REG); + ier |= MA35_IER_AUTO_RTS | MA35_IER_AUTO_CTS; + serial_out(up, MA35_IER_REG, ier); + up->port.flags |= UPF_HARD_FLOW; + } else { + ier = serial_in(up, MA35_IER_REG); + ier &= ~(MA35_IER_AUTO_RTS | MA35_IER_AUTO_CTS); + serial_out(up, MA35_IER_REG, ier); + up->port.flags &= ~UPF_HARD_FLOW; + } + + msr = serial_in(up, MA35_MSR_REG); + msr |= MA35_MSR_CTSACTLV; + serial_out(up, MA35_MSR_REG, msr); + serial_out(up, MA35_MCR_REG, mcr); +} + +static void ma35d1serial_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + unsigned long flags; + u32 lcr; + + uart_port_lock_irqsave(&up->port, &flags); + lcr = serial_in(up, MA35_LCR_REG); + if (break_state != 0) + lcr |= MA35_LCR_BREAK; + else + lcr &= ~MA35_LCR_BREAK; + serial_out(up, MA35_LCR_REG, lcr); + uart_port_unlock_irqrestore(&up->port, flags); +} + +static int ma35d1serial_startup(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + u32 fcr; + int retval; + + /* Reset FIFO */ + serial_out(up, MA35_FCR_REG, MA35_FCR_TFR | MA35_FCR_RFR); + + /* Clear pending interrupts */ + serial_out(up, MA35_ISR_REG, MA35_ISR_ALL); + + retval = request_irq(port->irq, ma35d1serial_interrupt, 0, + dev_name(port->dev), port); + if (retval) { + dev_err(up->port.dev, "request irq failed.\n"); + return retval; + } + + fcr = serial_in(up, MA35_FCR_REG); + fcr |= MA35_FCR_RFITL_4BYTES | MA35_FCR_RTSTL_8BYTES; + serial_out(up, MA35_FCR_REG, fcr); + serial_out(up, MA35_LCR_REG, MA35_LCR_WLS_8BITS); + serial_out(up, MA35_TOR_REG, MA35_UART_RX_TOUT); + serial_out(up, MA35_IER_REG, MA35_IER_CONFIG); + return 0; +} + +static void ma35d1serial_shutdown(struct uart_port *port) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + + serial_out(up, MA35_IER_REG, 0); + free_irq(port->irq, port); +} + +static void ma35d1serial_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + unsigned long flags; + u32 baud, quot; + u32 lcr = 0; + + lcr = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); + + if (termios->c_cflag & CSTOPB) + lcr |= MA35_LCR_NSB; + if (termios->c_cflag & PARENB) + lcr |= MA35_LCR_PBE; + if (!(termios->c_cflag & PARODD)) + lcr |= MA35_LCR_EPE; + if (termios->c_cflag & CMSPAR) + lcr |= MA35_LCR_SPE; + + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / MA35_BAUD_DIV_MAX, + port->uartclk / MA35_BAUD_DIV_MIN); + + /* MA35D1 UART baud rate equation: baudrate = UART_CLK / (quot + 2) */ + quot = (port->uartclk / baud) - 2; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + uart_port_lock_irqsave(&up->port, &flags); + + up->port.read_status_mask = MA35_FSR_RX_OVER_IF; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= MA35_FSR_FEF | MA35_FSR_PEF; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= MA35_FSR_BIF; + + /* Characteres to ignore */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= MA35_FSR_FEF | MA35_FSR_PEF; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= MA35_FSR_BIF; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= MA35_FSR_RX_OVER_IF; + } + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + else + up->mcr &= ~UART_MCR_AFE; + + uart_update_timeout(port, termios->c_cflag, baud); + + ma35d1serial_set_mctrl(&up->port, up->port.mctrl); + + serial_out(up, MA35_BAUD_REG, MA35_BAUD_MODE2 | FIELD_PREP(MA35_BAUD_MASK, quot)); + + serial_out(up, MA35_LCR_REG, lcr); + + uart_port_unlock_irqrestore(&up->port, flags); +} + +static const char *ma35d1serial_type(struct uart_port *port) +{ + return "ma35d1-uart"; +} + +static void ma35d1serial_config_port(struct uart_port *port, int flags) +{ + /* + * Driver core for serial ports forces a non-zero value for port type. + * Write an arbitrary value here to accommodate the serial core driver, + * as ID part of UAPI is redundant. + */ + port->type = 1; +} + +static int ma35d1serial_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (port->type != PORT_UNKNOWN && ser->type != 1) + return -EINVAL; + + return 0; +} + +static const struct uart_ops ma35d1serial_ops = { + .tx_empty = ma35d1serial_tx_empty, + .set_mctrl = ma35d1serial_set_mctrl, + .get_mctrl = ma35d1serial_get_mctrl, + .stop_tx = ma35d1serial_stop_tx, + .start_tx = ma35d1serial_start_tx, + .stop_rx = ma35d1serial_stop_rx, + .break_ctl = ma35d1serial_break_ctl, + .startup = ma35d1serial_startup, + .shutdown = ma35d1serial_shutdown, + .set_termios = ma35d1serial_set_termios, + .type = ma35d1serial_type, + .config_port = ma35d1serial_config_port, + .verify_port = ma35d1serial_verify_port, +}; + +static const struct of_device_id ma35d1_serial_of_match[] = { + { .compatible = "nuvoton,ma35d1-uart" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ma35d1_serial_of_match); + +#ifdef CONFIG_SERIAL_NUVOTON_MA35D1_CONSOLE + +static struct device_node *ma35d1serial_uart_nodes[MA35_UART_NR]; + +static void wait_for_xmitr(struct uart_ma35d1_port *up) +{ + unsigned int reg = 0; + + read_poll_timeout_atomic(serial_in, reg, reg & MA35_FSR_TX_EMPTY, + 1, 10000, false, + up, MA35_FSR_REG); +} + +static void ma35d1serial_console_putchar(struct uart_port *port, unsigned char ch) +{ + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + + wait_for_xmitr(up); + serial_out(up, MA35_THR_REG, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void ma35d1serial_console_write(struct console *co, const char *s, u32 count) +{ + struct uart_ma35d1_port *up; + unsigned long flags; + int locked = 1; + u32 ier; + + if ((co->index < 0) || (co->index >= MA35_UART_NR)) { + pr_warn("Failed to write on console port %x, out of range\n", + co->index); + return; + } + + up = &ma35d1serial_ports[co->index]; + + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); + else + uart_port_lock_irqsave(&up->port, &flags); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, MA35_IER_REG); + serial_out(up, MA35_IER_REG, 0); + + uart_console_write(&up->port, s, count, ma35d1serial_console_putchar); + + wait_for_xmitr(up); + serial_out(up, MA35_IER_REG, ier); + + if (locked) + uart_port_unlock_irqrestore(&up->port, flags); +} + +static int __init ma35d1serial_console_setup(struct console *co, char *options) +{ + struct device_node *np; + struct uart_ma35d1_port *p; + u32 val32[4]; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if ((co->index < 0) || (co->index >= MA35_UART_NR)) { + pr_debug("Console Port%x out of range\n", co->index); + return -EINVAL; + } + + np = ma35d1serial_uart_nodes[co->index]; + p = &ma35d1serial_ports[co->index]; + if (!np || !p) + return -ENODEV; + + if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0) + return -EINVAL; + + p->port.iobase = val32[1]; + p->port.membase = ioremap(p->port.iobase, MA35_UART_REG_SIZE); + if (!p->port.membase) + return -ENOMEM; + + p->port.ops = &ma35d1serial_ops; + p->port.line = 0; + p->port.uartclk = MA35_UART_CONSOLE_CLK; + + port = &ma35d1serial_ports[co->index].port; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console ma35d1serial_console = { + .name = "ttyNVT", + .write = ma35d1serial_console_write, + .device = uart_console_device, + .setup = ma35d1serial_console_setup, + .flags = CON_PRINTBUFFER | CON_ENABLED, + .index = -1, + .data = &ma35d1serial_reg, +}; + +static void ma35d1serial_console_init_port(void) +{ + u32 i = 0; + struct device_node *np; + + for_each_matching_node(np, ma35d1_serial_of_match) { + if (ma35d1serial_uart_nodes[i] == NULL) { + of_node_get(np); + ma35d1serial_uart_nodes[i] = np; + i++; + if (i == MA35_UART_NR) + break; + } + } +} + +static int __init ma35d1serial_console_init(void) +{ + ma35d1serial_console_init_port(); + register_console(&ma35d1serial_console); + return 0; +} +console_initcall(ma35d1serial_console_init); + +#define MA35D1SERIAL_CONSOLE (&ma35d1serial_console) +#else +#define MA35D1SERIAL_CONSOLE NULL +#endif + +static struct uart_driver ma35d1serial_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyNVT", + .major = TTY_MAJOR, + .minor = 64, + .cons = MA35D1SERIAL_CONSOLE, + .nr = MA35_UART_NR, +}; + +/* + * Register a set of serial devices attached to a platform device. + * The list is terminated with a zero flags entry, which means we expect + * all entries to have at least UPF_BOOT_AUTOCONF set. + */ +static int ma35d1serial_probe(struct platform_device *pdev) +{ + struct resource *res_mem; + struct uart_ma35d1_port *up; + int ret = 0; + + if (!pdev->dev.of_node) + return -ENODEV; + + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", ret); + return ret; + } + up = &ma35d1serial_ports[ret]; + up->port.line = ret; + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -ENODEV; + + up->port.iobase = res_mem->start; + up->port.membase = ioremap(up->port.iobase, MA35_UART_REG_SIZE); + if (!up->port.membase) + return -ENOMEM; + + up->port.ops = &ma35d1serial_ops; + + spin_lock_init(&up->port.lock); + + up->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(up->clk)) { + ret = PTR_ERR(up->clk); + dev_err(&pdev->dev, "failed to get core clk: %d\n", ret); + goto err_iounmap; + } + + ret = clk_prepare_enable(up->clk); + if (ret) + goto err_iounmap; + + if (up->port.line != 0) + up->port.uartclk = clk_get_rate(up->clk); + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + goto err_clk_disable; + + up->port.irq = ret; + up->port.dev = &pdev->dev; + up->port.flags = UPF_BOOT_AUTOCONF; + + platform_set_drvdata(pdev, up); + + ret = uart_add_one_port(&ma35d1serial_reg, &up->port); + if (ret < 0) + goto err_free_irq; + + return 0; + +err_free_irq: + free_irq(up->port.irq, &up->port); + +err_clk_disable: + clk_disable_unprepare(up->clk); + +err_iounmap: + iounmap(up->port.membase); + return ret; +} + +/* + * Remove serial ports registered against a platform device. + */ +static void ma35d1serial_remove(struct platform_device *dev) +{ + struct uart_port *port = platform_get_drvdata(dev); + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + + uart_remove_one_port(&ma35d1serial_reg, port); + clk_disable_unprepare(up->clk); +} + +static int ma35d1serial_suspend(struct platform_device *dev, pm_message_t state) +{ + struct uart_port *port = platform_get_drvdata(dev); + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + + uart_suspend_port(&ma35d1serial_reg, &up->port); + if (up->port.line == 0) { + up->console_baud_rate = serial_in(up, MA35_BAUD_REG); + up->console_line = serial_in(up, MA35_LCR_REG); + up->console_int = serial_in(up, MA35_IER_REG); + } + return 0; +} + +static int ma35d1serial_resume(struct platform_device *dev) +{ + struct uart_port *port = platform_get_drvdata(dev); + struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); + + if (up->port.line == 0) { + serial_out(up, MA35_BAUD_REG, up->console_baud_rate); + serial_out(up, MA35_LCR_REG, up->console_line); + serial_out(up, MA35_IER_REG, up->console_int); + } + uart_resume_port(&ma35d1serial_reg, &up->port); + return 0; +} + +static struct platform_driver ma35d1serial_driver = { + .probe = ma35d1serial_probe, + .remove = ma35d1serial_remove, + .suspend = ma35d1serial_suspend, + .resume = ma35d1serial_resume, + .driver = { + .name = "ma35d1-uart", + .of_match_table = ma35d1_serial_of_match, + }, +}; + +static int __init ma35d1serial_init(void) +{ + int ret; + + ret = uart_register_driver(&ma35d1serial_reg); + if (ret) + return ret; + + ret = platform_driver_register(&ma35d1serial_driver); + if (ret) + uart_unregister_driver(&ma35d1serial_reg); + + return ret; +} + +static void __exit ma35d1serial_exit(void) +{ + platform_driver_unregister(&ma35d1serial_driver); + uart_unregister_driver(&ma35d1serial_reg); +} + +module_init(ma35d1serial_init); +module_exit(ma35d1serial_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MA35D1 serial driver"); diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 371569a0fd00..3faa1b6aa3ee 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * * Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org> * * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have @@ -8,24 +7,6 @@ * writing conf clears FIFO buffer and we cannot have this interrupt * always asking us for attention. * - * Example platform data: - - static struct plat_max3100 max3100_plat_data = { - .loopback = 0, - .crystal = 0, - .poll_time = 100, - }; - - static struct spi_board_info spi_board_info[] = { - { - .modalias = "max3100", - .platform_data = &max3100_plat_data, - .irq = IRQ_EINT12, - .max_speed_hz = 5*1000*1000, - .chip_select = 0, - }, - }; - * The initial minor number is 209 in the low-density serial port: * mknod /dev/ttyMAX0 c 204 209 */ @@ -35,18 +16,24 @@ /* 4 MAX3100s should be enough for everyone */ #define MAX_MAX3100 4 +#include <linux/bitops.h> +#include <linux/container_of.h> #include <linux/delay.h> -#include <linux/slab.h> #include <linux/device.h> +#include <linux/freezer.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pm.h> +#include <linux/property.h> #include <linux/serial_core.h> #include <linux/serial.h> +#include <linux/slab.h> #include <linux/spi/spi.h> -#include <linux/freezer.h> -#include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/tty.h> +#include <linux/types.h> -#include <linux/serial_max3100.h> +#include <linux/unaligned.h> #define MAX3100_C (1<<14) #define MAX3100_D (0<<14) @@ -110,10 +97,8 @@ struct max3100_port { #define MAX3100_7BIT 4 int rx_enabled; /* if we should rx chars */ - int irq; /* irq assigned to the max3100 */ - int minor; /* minor number */ - int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ + int loopback_commit; /* need to change loopback */ int loopback; /* 1 if we are in loopback mode */ /* for handling irqs: need workqueue since we do spi_sync */ @@ -124,15 +109,14 @@ struct max3100_port { /* need to know we are suspending to avoid deadlock on workqueue */ int suspending; - /* hook for suspending MAX3100 via dedicated pin */ - void (*max3100_hw_suspend) (int suspend); - - /* poll time (in ms) for ctrl lines */ - int poll_time; - /* and its timer */ struct timer_list timer; }; +static inline struct max3100_port *to_max3100_port(struct uart_port *port) +{ + return container_of(port, struct max3100_port, port); +} + static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ static DEFINE_MUTEX(max3100s_lock); /* race on probe */ @@ -150,7 +134,7 @@ static int max3100_do_parity(struct max3100_port *s, u16 c) else c &= 0xff; - parity = parity ^ (hweight8(c) & 1); + parity = parity ^ parity8(c); return parity; } @@ -170,28 +154,10 @@ static void max3100_calc_parity(struct max3100_port *s, u16 *c) *c |= max3100_do_parity(s, *c) << 8; } -static void max3100_work(struct work_struct *w); - -static void max3100_dowork(struct max3100_port *s) -{ - if (!s->force_end_work && !freezing(current) && !s->suspending) - queue_work(s->workqueue, &s->work); -} - -static void max3100_timeout(struct timer_list *t) -{ - struct max3100_port *s = from_timer(s, t, timer); - - if (s->port.state) { - max3100_dowork(s); - mod_timer(&s->timer, jiffies + s->poll_time); - } -} - static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) { struct spi_message message; - u16 etx, erx; + __be16 etx, erx; int status; struct spi_transfer tran = { .tx_buf = &etx, @@ -213,10 +179,11 @@ static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) return 0; } -static int max3100_handlerx(struct max3100_port *s, u16 rx) +static int max3100_handlerx_unlocked(struct max3100_port *s, u16 rx) { - unsigned int ch, flg, status = 0; + unsigned int status = 0; int ret = 0, cts; + u8 ch, flg; if (rx & MAX3100_R && s->rx_enabled) { dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -247,19 +214,31 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx) cts = (rx & MAX3100_CTS) > 0; if (s->cts != cts) { s->cts = cts; - uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0); + uart_handle_cts_change(&s->port, cts); } return ret; } +static int max3100_handlerx(struct max3100_port *s, u16 rx) +{ + unsigned long flags; + int ret; + + uart_port_lock_irqsave(&s->port, &flags); + ret = max3100_handlerx_unlocked(s, rx); + uart_port_unlock_irqrestore(&s->port, flags); + return ret; +} + static void max3100_work(struct work_struct *w) { struct max3100_port *s = container_of(w, struct max3100_port, work); + struct tty_port *tport = &s->port.state->port; + unsigned char ch; + int conf, cconf, cloopback, crts; int rxchars; u16 tx, rx; - int conf, cconf, crts; - struct circ_buf *xmit = &s->port.state->xmit; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -269,11 +248,15 @@ static void max3100_work(struct work_struct *w) conf = s->conf; cconf = s->conf_commit; s->conf_commit = 0; + cloopback = s->loopback_commit; + s->loopback_commit = 0; crts = s->rts_commit; s->rts_commit = 0; spin_unlock(&s->conf_lock); if (cconf) max3100_sr(s, MAX3100_WC | conf, &rx); + if (cloopback) + max3100_sr(s, 0x4001, &rx); if (crts) { max3100_sr(s, MAX3100_WD | MAX3100_TE | (s->rts ? MAX3100_RTS : 0), &rx); @@ -289,12 +272,9 @@ static void max3100_work(struct work_struct *w) tx = s->port.x_char; s->port.icount.tx++; s->port.x_char = 0; - } else if (!uart_circ_empty(xmit) && - !uart_tx_stopped(&s->port)) { - tx = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); - s->port.icount.tx++; + } else if (!uart_tx_stopped(&s->port) && + uart_fifo_get(&s->port, &ch)) { + tx = ch; } if (tx != 0xffff) { max3100_calc_parity(s, &tx); @@ -308,19 +288,33 @@ static void max3100_work(struct work_struct *w) tty_flip_buffer_push(&s->port.state->port); rxchars = 0; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&s->port); } while (!s->force_end_work && !freezing(current) && ((rx & MAX3100_R) || - (!uart_circ_empty(xmit) && + (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&s->port)))); if (rxchars > 0) tty_flip_buffer_push(&s->port.state->port); } +static void max3100_dowork(struct max3100_port *s) +{ + if (!s->force_end_work && !freezing(current) && !s->suspending) + queue_work(s->workqueue, &s->work); +} + +static void max3100_timeout(struct timer_list *t) +{ + struct max3100_port *s = timer_container_of(s, t, timer); + + max3100_dowork(s); + mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port)); +} + static irqreturn_t max3100_irq(int irqno, void *dev_id) { struct max3100_port *s = dev_id; @@ -333,20 +327,15 @@ static irqreturn_t max3100_irq(int irqno, void *dev_id) static void max3100_enable_ms(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); - if (s->poll_time > 0) - mod_timer(&s->timer, jiffies); + mod_timer(&s->timer, jiffies); dev_dbg(&s->spi->dev, "%s\n", __func__); } static void max3100_start_tx(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -355,9 +344,7 @@ static void max3100_start_tx(struct uart_port *port) static void max3100_stop_rx(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -371,9 +358,7 @@ static void max3100_stop_rx(struct uart_port *port) static unsigned int max3100_tx_empty(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -384,9 +369,7 @@ static unsigned int max3100_tx_empty(struct uart_port *port) static unsigned int max3100_get_mctrl(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -398,32 +381,35 @@ static unsigned int max3100_get_mctrl(struct uart_port *port) static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - int rts; + struct max3100_port *s = to_max3100_port(port); + int loopback, rts; dev_dbg(&s->spi->dev, "%s\n", __func__); + loopback = (mctrl & TIOCM_LOOP) > 0; rts = (mctrl & TIOCM_RTS) > 0; spin_lock(&s->conf_lock); + if (s->loopback != loopback) { + s->loopback = loopback; + s->loopback_commit = 1; + } if (s->rts != rts) { s->rts = rts; s->rts_commit = 1; - max3100_dowork(s); } + if (s->loopback_commit || s->rts_commit) + max3100_dowork(s); spin_unlock(&s->conf_lock); } static void max3100_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - int baud = 0; + struct max3100_port *s = to_max3100_port(port); + unsigned int baud = port->uartclk / 16; + unsigned int baud230400 = (baud == 230400) ? 1 : 0; unsigned cflag; u32 param_new, param_mask, parity = 0; @@ -436,40 +422,40 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, param_new = s->conf & MAX3100_BAUD; switch (baud) { case 300: - if (s->crystal) + if (baud230400) baud = s->baud; else param_new = 15; break; case 600: - param_new = 14 + s->crystal; + param_new = 14 + baud230400; break; case 1200: - param_new = 13 + s->crystal; + param_new = 13 + baud230400; break; case 2400: - param_new = 12 + s->crystal; + param_new = 12 + baud230400; break; case 4800: - param_new = 11 + s->crystal; + param_new = 11 + baud230400; break; case 9600: - param_new = 10 + s->crystal; + param_new = 10 + baud230400; break; case 19200: - param_new = 9 + s->crystal; + param_new = 9 + baud230400; break; case 38400: - param_new = 8 + s->crystal; + param_new = 8 + baud230400; break; case 57600: - param_new = 1 + s->crystal; + param_new = 1 + baud230400; break; case 115200: - param_new = 0 + s->crystal; + param_new = 0 + baud230400; break; case 230400: - if (s->crystal) + if (baud230400) param_new = 0; else baud = s->baud; @@ -521,12 +507,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, MAX3100_STATUS_PE | MAX3100_STATUS_FE | MAX3100_STATUS_OE; - /* we are sending char from a workqueue so enable */ - s->port.state->port.low_latency = 1; - - if (s->poll_time > 0) - del_timer_sync(&s->timer); - + timer_delete_sync(&s->timer); uart_update_timeout(port, termios->c_cflag, baud); spin_lock(&s->conf_lock); @@ -542,9 +523,8 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, static void max3100_shutdown(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); + u16 rx; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -553,39 +533,29 @@ static void max3100_shutdown(struct uart_port *port) s->force_end_work = 1; - if (s->poll_time > 0) - del_timer_sync(&s->timer); + timer_delete_sync(&s->timer); if (s->workqueue) { - flush_workqueue(s->workqueue); destroy_workqueue(s->workqueue); s->workqueue = NULL; } - if (s->irq) - free_irq(s->irq, s); + if (port->irq) + free_irq(port->irq, s); /* set shutdown mode to save power */ - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(1); - else { - u16 tx, rx; - - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(s, tx, &rx); - } + max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx); } static int max3100_startup(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); char b[12]; + int ret; dev_dbg(&s->spi->dev, "%s\n", __func__); s->conf = MAX3100_RM; - s->baud = s->crystal ? 230400 : 115200; + s->baud = port->uartclk / 16; s->rx_enabled = 1; if (s->suspending) @@ -603,23 +573,15 @@ static int max3100_startup(struct uart_port *port) } INIT_WORK(&s->work, max3100_work); - if (request_irq(s->irq, max3100_irq, - IRQF_TRIGGER_FALLING, "max3100", s) < 0) { - dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq); - s->irq = 0; + ret = request_irq(port->irq, max3100_irq, IRQF_TRIGGER_FALLING, "max3100", s); + if (ret < 0) { + dev_warn(&s->spi->dev, "cannot allocate irq %d\n", port->irq); + port->irq = 0; destroy_workqueue(s->workqueue); s->workqueue = NULL; return -EBUSY; } - if (s->loopback) { - u16 tx, rx; - tx = 0x4001; - max3100_sr(s, tx, &rx); - } - - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(0); s->conf_commit = 1; max3100_dowork(s); /* wait for clock to settle */ @@ -632,9 +594,7 @@ static int max3100_startup(struct uart_port *port) static const char *max3100_type(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -643,18 +603,14 @@ static const char *max3100_type(struct uart_port *port) static void max3100_release_port(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); } static void max3100_config_port(struct uart_port *port, int flags) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -665,9 +621,7 @@ static void max3100_config_port(struct uart_port *port, int flags) static int max3100_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); int ret = -EINVAL; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -679,18 +633,14 @@ static int max3100_verify_port(struct uart_port *port, static void max3100_stop_tx(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); } static int max3100_request_port(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); return 0; @@ -698,9 +648,7 @@ static int max3100_request_port(struct uart_port *port) static void max3100_break_ctl(struct uart_port *port, int break_state) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); } @@ -736,79 +684,64 @@ static int uart_driver_registered; static int max3100_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; int i, retval; - struct plat_max3100 *pdata; - u16 tx, rx; + u16 rx; mutex_lock(&max3100s_lock); if (!uart_driver_registered) { - uart_driver_registered = 1; retval = uart_register_driver(&max3100_uart_driver); if (retval) { - printk(KERN_ERR "Couldn't register max3100 uart driver\n"); mutex_unlock(&max3100s_lock); - return retval; + return dev_err_probe(dev, retval, "Couldn't register max3100 uart driver\n"); } + + uart_driver_registered = 1; } for (i = 0; i < MAX_MAX3100; i++) if (!max3100s[i]) break; if (i == MAX_MAX3100) { - dev_warn(&spi->dev, "too many MAX3100 chips\n"); mutex_unlock(&max3100s_lock); - return -ENOMEM; + return dev_err_probe(dev, -ENOSPC, "too many MAX3100 chips\n"); } max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); if (!max3100s[i]) { - dev_warn(&spi->dev, - "kmalloc for max3100 structure %d failed!\n", i); mutex_unlock(&max3100s_lock); return -ENOMEM; } max3100s[i]->spi = spi; - max3100s[i]->irq = spi->irq; spin_lock_init(&max3100s[i]->conf_lock); spi_set_drvdata(spi, max3100s[i]); - pdata = dev_get_platdata(&spi->dev); - max3100s[i]->crystal = pdata->crystal; - max3100s[i]->loopback = pdata->loopback; - max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time); - if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) - max3100s[i]->poll_time = 1; - max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; max3100s[i]->minor = i; timer_setup(&max3100s[i]->timer, max3100_timeout, 0); dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); - max3100s[i]->port.irq = max3100s[i]->irq; - max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200; + max3100s[i]->port.irq = spi->irq; max3100s[i]->port.fifosize = 16; max3100s[i]->port.ops = &max3100_ops; max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; max3100s[i]->port.line = i; max3100s[i]->port.type = PORT_MAX3100; max3100s[i]->port.dev = &spi->dev; + + /* Read clock frequency from a property, uart_add_one_port() will fail if it's not set */ + device_property_read_u32(dev, "clock-frequency", &max3100s[i]->port.uartclk); + retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); if (retval < 0) - dev_warn(&spi->dev, - "uart_add_one_port failed for line %d with error %d\n", - i, retval); + dev_err_probe(dev, retval, "uart_add_one_port failed for line %d\n", i); /* set shutdown mode to save power. Will be woken-up on open */ - if (max3100s[i]->max3100_hw_suspend) - max3100s[i]->max3100_hw_suspend(1); - else { - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(max3100s[i], tx, &rx); - } + max3100_sr(max3100s[i], MAX3100_WC | MAX3100_SHDN, &rx); mutex_unlock(&max3100s_lock); return 0; } -static int max3100_remove(struct spi_device *spi) +static void max3100_remove(struct spi_device *spi) { struct max3100_port *s = spi_get_drvdata(spi); int i; @@ -831,37 +764,29 @@ static int max3100_remove(struct spi_device *spi) for (i = 0; i < MAX_MAX3100; i++) if (max3100s[i]) { mutex_unlock(&max3100s_lock); - return 0; + return; } pr_debug("removing max3100 driver\n"); uart_unregister_driver(&max3100_uart_driver); + uart_driver_registered = 0; mutex_unlock(&max3100s_lock); - return 0; } -#ifdef CONFIG_PM_SLEEP - static int max3100_suspend(struct device *dev) { struct max3100_port *s = dev_get_drvdata(dev); + u16 rx; dev_dbg(&s->spi->dev, "%s\n", __func__); - disable_irq(s->irq); + disable_irq(s->port.irq); s->suspending = 1; uart_suspend_port(&max3100_uart_driver, &s->port); - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(1); - else { - /* no HW suspend, so do SW one */ - u16 tx, rx; - - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(s, tx, &rx); - } + /* no HW suspend, so do SW one */ + max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx); return 0; } @@ -871,12 +796,10 @@ static int max3100_resume(struct device *dev) dev_dbg(&s->spi->dev, "%s\n", __func__); - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(0); uart_resume_port(&max3100_uart_driver, &s->port); s->suspending = 0; - enable_irq(s->irq); + enable_irq(s->port.irq); s->conf_commit = 1; if (s->workqueue) @@ -885,20 +808,29 @@ static int max3100_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); -#define MAX3100_PM_OPS (&max3100_pm_ops) +static DEFINE_SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); + +static const struct spi_device_id max3100_spi_id[] = { + { "max3100" }, + { } +}; +MODULE_DEVICE_TABLE(spi, max3100_spi_id); -#else -#define MAX3100_PM_OPS NULL -#endif +static const struct of_device_id max3100_of_match[] = { + { .compatible = "maxim,max3100" }, + { } +}; +MODULE_DEVICE_TABLE(of, max3100_of_match); static struct spi_driver max3100_driver = { .driver = { .name = "max3100", - .pm = MAX3100_PM_OPS, + .of_match_table = max3100_of_match, + .pm = pm_sleep_ptr(&max3100_pm_ops), }, .probe = max3100_probe, .remove = max3100_remove, + .id_table = max3100_spi_id, }; module_spi_driver(max3100_driver); @@ -906,4 +838,3 @@ module_spi_driver(max3100_driver); MODULE_DESCRIPTION("MAX3100 driver"); MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:max3100"); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8434bd5a8ec7..ac7d3f197c3a 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -14,9 +14,10 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/gpio/driver.h> +#include <linux/i2c.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/serial_core.h> #include <linux/serial.h> @@ -29,6 +30,7 @@ #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 #define MAX310X_UART_NRMAX 16 +#define MAX310X_MAX_PORTS 4 /* Maximum number of UART ports per IC. */ /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -65,6 +67,7 @@ #define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */ #define MAX310X_CLKSRC_REG (0x1e) /* Clock source */ #define MAX310X_REG_1F (0x1f) +#define MAX310X_EXTREG_START (0x20) /* Only relevant in SPI mode. */ #define MAX310X_REVID_REG MAX310X_REG_1F /* Revision ID */ @@ -72,8 +75,9 @@ #define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */ /* Extended registers */ -#define MAX310X_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ - +#define MAX310X_REVID_EXTREG (0x25) /* Revision ID + * (extended addressing space) + */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ #define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ @@ -158,14 +162,14 @@ #define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ /* Flow control trigger level register masks */ -#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ -#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ +#define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */ +#define MAX310X_FLOWLVL_RES_MASK GENMASK(7, 4) /* Flow control resume level */ #define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f) #define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4) /* FIFO interrupt trigger level register masks */ -#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */ -#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_TX_MASK GENMASK(3, 0) /* TX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_RX_MASK GENMASK(7, 4) /* RX FIFO trigger level */ #define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f) #define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4) @@ -175,7 +179,8 @@ #define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs * are used in conjunction with * XOFF2 for definition of - * special character */ + * special character + */ #define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ #define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ #define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 @@ -212,8 +217,8 @@ */ /* PLL configuration register masks */ -#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ -#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ +#define MAX310X_PLLCFG_PREDIV_MASK GENMASK(5, 0) /* PLL predivision value */ +#define MAX310X_PLLCFG_PLLFACTOR_MASK GENMASK(7, 6) /* PLL multiplication factor */ /* Baud rate generator configuration register bits */ #define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ @@ -232,9 +237,17 @@ /* Misc definitions */ #define MAX310X_FIFO_SIZE (128) -#define MAX310x_REV_MASK (0xf8) +#define MAX310x_REV_MASK GENMASK(7, 3) #define MAX310X_WRITE_BIT 0x80 +/* Port startup definitions */ +#define MAX310X_PORT_STARTUP_WAIT_RETRIES 20 /* Number of retries */ +#define MAX310X_PORT_STARTUP_WAIT_DELAY_MS 10 /* Delay between retries */ + +/* Crystal-related definitions */ +#define MAX310X_XTAL_WAIT_RETRIES 20 /* Number of retries */ +#define MAX310X_XTAL_WAIT_DELAY_MS 10 /* Delay between retries */ + /* MAX3107 specific */ #define MAX3107_REV_ID (0xa0) @@ -245,12 +258,23 @@ #define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */ #define MAX14830_REV_ID (0xb0) +struct max310x_if_cfg { + int (*extended_reg_enable)(struct device *dev, bool enable); + u8 rev_id_offset; +}; + struct max310x_devtype { - char name[9]; + struct { + unsigned short min; + unsigned short max; + } slave_addr; /* Relevant only in I2C mode. */ int nr; + char name[9]; u8 mode1; - int (*detect)(struct device *); - void (*power)(struct uart_port *, int); + u8 rev_id_val; + u8 rev_id_reg; /* Relevant only if rev_id_val is defined. */ + u8 power_reg; /* Register address for power/sleep control. */ + u8 power_bit; /* Bit for sleep or power-off mode (active high). */ }; struct max310x_one { @@ -258,22 +282,22 @@ struct max310x_one { struct work_struct tx_work; struct work_struct md_work; struct work_struct rs_work; + struct regmap *regmap; - u8 wr_header; - u8 rd_header; u8 rx_buf[MAX310X_FIFO_SIZE]; }; #define to_max310x_port(_port) \ container_of(_port, struct max310x_one, port) struct max310x_port { - struct max310x_devtype *devtype; + const struct max310x_devtype *devtype; + const struct max310x_if_cfg *if_cfg; struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif - struct max310x_one p[0]; + struct max310x_one p[]; }; static struct uart_driver max310x_uart = { @@ -289,85 +313,74 @@ static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); static u8 max310x_port_read(struct uart_port *port, u8 reg) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); unsigned int val = 0; - regmap_read(s->regmap, port->iobase + reg, &val); + regmap_read(one->regmap, reg, &val); return val; } static void max310x_port_write(struct uart_port *port, u8 reg, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_write(s->regmap, port->iobase + reg, val); + regmap_write(one->regmap, reg, val); } static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); - - regmap_update_bits(s->regmap, port->iobase + reg, mask, val); -} - -static int max3107_detect(struct device *dev) -{ - struct max310x_port *s = dev_get_drvdata(dev); - unsigned int val = 0; - int ret; - - ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val); - if (ret) - return ret; - - if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) { - dev_err(dev, - "%s ID 0x%02x does not match\n", s->devtype->name, val); - return -ENODEV; - } + struct max310x_one *one = to_max310x_port(port); - return 0; + regmap_update_bits(one->regmap, reg, mask, val); } -static int max3108_detect(struct device *dev) +static int max310x_detect(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); unsigned int val = 0; int ret; - /* MAX3108 have not REV ID register, we just check default value - * from clocksource register to make sure everything works. - */ - ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); - if (ret) - return ret; + /* Check if variant supports REV ID register: */ + if (s->devtype->rev_id_val) { + u8 rev_id_reg = s->devtype->rev_id_reg; - if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) { - dev_err(dev, "%s not present\n", s->devtype->name); - return -ENODEV; - } + /* Check if REV ID is in extended addressing space: */ + if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) { + ret = s->if_cfg->extended_reg_enable(dev, true); + if (ret) + return ret; - return 0; -} + /* Adjust REV ID extended addressing space address: */ + if (s->if_cfg->rev_id_offset) + rev_id_reg -= s->if_cfg->rev_id_offset; + } -static int max3109_detect(struct device *dev) -{ - struct max310x_port *s = dev_get_drvdata(dev); - unsigned int val = 0; - int ret; + regmap_read(s->regmap, rev_id_reg, &val); - ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, - MAX310X_EXTREG_ENBL); - if (ret) - return ret; + if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) { + ret = s->if_cfg->extended_reg_enable(dev, false); + if (ret) + return ret; + } - regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); - regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); - if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) { - dev_err(dev, - "%s ID 0x%02x does not match\n", s->devtype->name, val); - return -ENODEV; + if (((val & MAX310x_REV_MASK) != s->devtype->rev_id_val)) + return dev_err_probe(dev, -ENODEV, + "%s ID 0x%02x does not match\n", + s->devtype->name, val); + } else { + /* + * For variant without REV ID register, just check default value + * from clocksource register to make sure everything works. + */ + ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); + if (ret) + return ret; + + if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) + return dev_err_probe(dev, -ENODEV, + "%s not present\n", + s->devtype->name); } return 0; @@ -375,40 +388,10 @@ static int max3109_detect(struct device *dev) static void max310x_power(struct uart_port *port, int on) { - max310x_port_update(port, MAX310X_MODE1_REG, - MAX310X_MODE1_FORCESLEEP_BIT, - on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT); - if (on) - msleep(50); -} - -static int max14830_detect(struct device *dev) -{ - struct max310x_port *s = dev_get_drvdata(dev); - unsigned int val = 0; - int ret; - - ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, - MAX310X_EXTREG_ENBL); - if (ret) - return ret; - - regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val); - regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL); - if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) { - dev_err(dev, - "%s ID 0x%02x does not match\n", s->devtype->name, val); - return -ENODEV; - } - - return 0; -} + struct max310x_port *s = dev_get_drvdata(port->dev); -static void max14830_power(struct uart_port *port, int on) -{ - max310x_port_update(port, MAX310X_BRGCFG_REG, - MAX14830_BRGCFG_CLKDIS_BIT, - on ? 0 : MAX14830_BRGCFG_CLKDIS_BIT); + max310x_port_update(port, s->devtype->power_reg, s->devtype->power_bit, + on ? 0 : s->devtype->power_bit); if (on) msleep(50); } @@ -417,37 +400,61 @@ static const struct max310x_devtype max3107_devtype = { .name = "MAX3107", .nr = 1, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, - .detect = max3107_detect, - .power = max310x_power, + .rev_id_val = MAX3107_REV_ID, + .rev_id_reg = MAX310X_REVID_REG, + .power_reg = MAX310X_MODE1_REG, + .power_bit = MAX310X_MODE1_FORCESLEEP_BIT, + .slave_addr = { + .min = 0x2c, + .max = 0x2f, + }, }; static const struct max310x_devtype max3108_devtype = { .name = "MAX3108", .nr = 1, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, - .detect = max3108_detect, - .power = max310x_power, + .rev_id_val = 0, /* Unsupported. */ + .rev_id_reg = 0, /* Irrelevant when rev_id_val is not defined. */ + .power_reg = MAX310X_MODE1_REG, + .power_bit = MAX310X_MODE1_FORCESLEEP_BIT, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max3109_devtype = { .name = "MAX3109", .nr = 2, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, - .detect = max3109_detect, - .power = max310x_power, + .rev_id_val = MAX3109_REV_ID, + .rev_id_reg = MAX310X_REVID_EXTREG, + .power_reg = MAX310X_MODE1_REG, + .power_bit = MAX310X_MODE1_FORCESLEEP_BIT, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max14830_devtype = { .name = "MAX14830", .nr = 4, .mode1 = MAX310X_MODE1_IRQSEL_BIT, - .detect = max14830_detect, - .power = max14830_power, + .rev_id_val = MAX14830_REV_ID, + .rev_id_reg = MAX310X_REVID_EXTREG, + .power_reg = MAX310X_BRGCFG_REG, + .power_bit = MAX14830_BRGCFG_CLKDIS_BIT, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static bool max310x_reg_writeable(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -456,15 +463,13 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg) case MAX310X_RXFIFOLVL_REG: return false; default: - break; + return true; } - - return true; } static bool max310x_reg_volatile(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: @@ -478,25 +483,26 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg) case MAX310X_REG_1F: return true; default: - break; + return false; } - - return false; } static bool max310x_reg_precious(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: case MAX310X_STS_IRQSTS_REG: return true; default: - break; + return false; } +} - return false; +static bool max310x_reg_noinc(struct device *dev, unsigned int reg) +{ + return reg == MAX310X_RHR_REG; } static int max310x_set_baud(struct uart_port *port, int baud) @@ -552,7 +558,7 @@ static int max310x_update_best_err(unsigned long f, long *besterr) return 1; } -static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, +static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, unsigned long freq, bool xtal) { unsigned int div, clksrc, pllcfg = 0; @@ -610,54 +616,48 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, /* Wait for crystal */ if (xtal) { - unsigned int val; - msleep(10); - regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val); - if (!(val & MAX310X_STS_CLKREADY_BIT)) { - dev_warn(dev, "clock is not stable yet\n"); - } + bool stable = false; + unsigned int try = 0, val = 0; + + do { + msleep(MAX310X_XTAL_WAIT_DELAY_MS); + regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val); + + if (val & MAX310X_STS_CLKREADY_BIT) + stable = true; + } while (!stable && (++try < MAX310X_XTAL_WAIT_RETRIES)); + + if (!stable) + return dev_err_probe(dev, -EAGAIN, + "clock is not stable\n"); } - return (int)bestfreq; + return bestfreq; } static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->wr_header, - .len = sizeof(one->wr_header), - }, { - .tx_buf = txbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + + regmap_noinc_write(one->regmap, MAX310X_THR_REG, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->rd_header, - .len = sizeof(one->rd_header), - }, { - .rx_buf = rxbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + + regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) { struct max310x_one *one = to_max310x_port(port); - unsigned int sts, ch, flag, i; + unsigned int sts, i; + u8 ch, flag; if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) { - /* We are just reading, happily ignoring any error conditions. + /* + * We are just reading, happily ignoring any error conditions. * Break condition, parity checking, framing errors -- they * are all ignored. That means that we can do a batch-read. * @@ -666,7 +666,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) * that the LSR register applies to the "current" character. * That's also the reason why we cannot do batched reads when * asked to check the individual statuses. - * */ + */ sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); max310x_batch_read(port, one->rx_buf, rxlen); @@ -747,8 +747,9 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) static void max310x_handle_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int txlen, to_send, until_end; + struct tty_port *tport = &port->state->port; + unsigned int txlen, to_send; + unsigned char *tail; if (unlikely(port->x_char)) { max310x_port_write(port, MAX310X_THR_REG, port->x_char); @@ -757,33 +758,26 @@ static void max310x_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; - /* Get length of data pending in circular buffer */ - to_send = uart_circ_chars_pending(xmit); - until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - if (likely(to_send)) { - /* Limit to size of TX FIFO */ + /* + * It's a circ buffer -- wrap around. + * We could do that in one SPI transaction, but meh. + */ + while (!kfifo_is_empty(&tport->xmit_fifo)) { + /* Limit to space available in TX FIFO */ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); txlen = port->fifosize - txlen; - to_send = (to_send > txlen) ? txlen : to_send; - - if (until_end < to_send) { - /* It's a circ buffer -- wrap around. - * We could do that in one SPI transaction, but meh. */ - max310x_batch_write(port, xmit->buf + xmit->tail, until_end); - max310x_batch_write(port, xmit->buf, to_send - until_end); - } else { - max310x_batch_write(port, xmit->buf + xmit->tail, to_send); - } + if (!txlen) + break; - /* Add data to send */ - port->icount.tx += to_send; - xmit->tail = (xmit->tail + to_send) & (UART_XMIT_SIZE - 1); + to_send = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen); + max310x_batch_write(port, tail, to_send); + uart_xmit_advance(port, to_send); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -812,14 +806,14 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno) if (ists & MAX310X_IRQ_CTS_BIT) { lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); - uart_handle_cts_change(port, - !!(lsr & MAX310X_LSR_CTS_BIT)); + uart_handle_cts_change(port, lsr & MAX310X_LSR_CTS_BIT); } if (rxlen) max310x_handle_rx(port, rxlen); if (ists & MAX310X_IRQ_TXEMPTY_BIT) max310x_start_tx(port); } while (1); + return res; } @@ -829,17 +823,28 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) bool handled = false; if (s->devtype->nr > 1) { + bool done; + do { unsigned int val = ~0; + unsigned long irq; + unsigned int port; + + done = true; WARN_ON_ONCE(regmap_read(s->regmap, MAX310X_GLOBALIRQ_REG, &val)); - val = ((1 << s->devtype->nr) - 1) & ~val; - if (!val) - break; - if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED) - handled = true; - } while (1); + + irq = val; + + for_each_clear_bit(port, &irq, s->devtype->nr) { + done = false; + + if (max310x_port_irq(s, port) == IRQ_HANDLED) + handled = true; + } + + } while (!done); } else { if (max310x_port_irq(s, 0) == IRQ_HANDLED) handled = true; @@ -864,7 +869,8 @@ static unsigned int max310x_tx_empty(struct uart_port *port) static unsigned int max310x_get_mctrl(struct uart_port *port) { - /* DCD and DSR are not wired and CTS/RTS is handled automatically + /* + * DCD and DSR are not wired and CTS/RTS is handled automatically * so just indicate DSR and CAR asserted */ return TIOCM_DSR | TIOCM_CAR; @@ -896,7 +902,7 @@ static void max310x_break_ctl(struct uart_port *port, int break_state) static void max310x_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int lcr = 0, flow = 0; int baud; @@ -956,7 +962,8 @@ static void max310x_set_termios(struct uart_port *port, max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]); max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]); - /* Disable transmitter before enabling AutoCTS or auto transmitter + /* + * Disable transmitter before enabling AutoCTS or auto transmitter * flow control */ if (termios->c_cflag & CRTSCTS || termios->c_iflag & IXOFF) { @@ -983,7 +990,8 @@ static void max310x_set_termios(struct uart_port *port, } max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow); - /* Enable transmitter after disabling AutoCTS and auto transmitter + /* + * Enable transmitter after disabling AutoCTS and auto transmitter * flow control */ if (!(termios->c_cflag & CRTSCTS) && !(termios->c_iflag & IXOFF)) { @@ -1026,7 +1034,7 @@ static void max310x_rs_proc(struct work_struct *ws) MAX310X_MODE2_ECHOSUPR_BIT, mode2); } -static int max310x_rs485_config(struct uart_port *port, +static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct max310x_one *one = to_max310x_port(port); @@ -1035,9 +1043,6 @@ static int max310x_rs485_config(struct uart_port *port, (rs485->delay_rts_after_send > 0x0f)) return -ERANGE; - rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX | - SER_RS485_ENABLED; - memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; schedule_work(&one->rs_work); @@ -1047,10 +1052,9 @@ static int max310x_rs485_config(struct uart_port *port, static int max310x_startup(struct uart_port *port) { - struct max310x_port *s = dev_get_drvdata(port->dev); unsigned int val; - s->devtype->power(port, 1); + max310x_power(port, 1); /* Configure MODE1 register */ max310x_port_update(port, MAX310X_MODE1_REG, @@ -1078,8 +1082,11 @@ static int max310x_startup(struct uart_port *port) MAX310X_MODE2_ECHOSUPR_BIT); } - /* Configure flow control levels */ - /* Flow control halt level 96, resume level 48 */ + /* + * Configure flow control levels: + * resume: 48 + * halt: 96 + */ max310x_port_write(port, MAX310X_FLOWLVL_REG, MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96)); @@ -1095,12 +1102,10 @@ static int max310x_startup(struct uart_port *port) static void max310x_shutdown(struct uart_port *port) { - struct max310x_port *s = dev_get_drvdata(port->dev); - /* Disable all interrupts */ max310x_port_write(port, MAX310X_IRQEN_REG, 0); - s->devtype->power(port, 0); + max310x_power(port, 0); } static const char *max310x_type(struct uart_port *port) @@ -1162,7 +1167,7 @@ static int __maybe_unused max310x_suspend(struct device *dev) for (i = 0; i < s->devtype->nr; i++) { uart_suspend_port(&max310x_uart, &s->p[i].port); - s->devtype->power(&s->p[i].port, 0); + max310x_power(&s->p[i].port, 0); } return 0; @@ -1174,7 +1179,7 @@ static int __maybe_unused max310x_resume(struct device *dev) int i; for (i = 0; i < s->devtype->nr; i++) { - s->devtype->power(&s->p[i].port, 1); + max310x_power(&s->p[i].port, 1); uart_resume_port(&max310x_uart, &s->p[i].port); } @@ -1184,7 +1189,7 @@ static int __maybe_unused max310x_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); #ifdef CONFIG_GPIOLIB -static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) +static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset) { unsigned int val; struct max310x_port *s = gpiochip_get_data(chip); @@ -1195,16 +1200,19 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) return !!((val >> 4) & (1 << (offset % 4))); } -static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4), value ? 1 << (offset % 4) : 0); + + return 0; } -static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; @@ -1215,7 +1223,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) } static int max310x_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) + unsigned int offset, int value) { struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; @@ -1250,83 +1258,110 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, } #endif -static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, - struct regmap *regmap, int irq) +static const struct serial_rs485 max310x_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + +static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, + const struct max310x_if_cfg *if_cfg, + struct regmap *regmaps[], int irq) { - int i, ret, fmin, fmax, freq, uartclk; - struct clk *clk_osc, *clk_xtal; + int i, ret, fmin, fmax, freq; struct max310x_port *s; - bool xtal = false; + s32 uartclk = 0; + bool xtal; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + for (i = 0; i < devtype->nr; i++) + if (IS_ERR(regmaps[i])) + return PTR_ERR(regmaps[i]); /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); - if (!s) { - dev_err(dev, "Error allocating port structure\n"); + if (!s) return -ENOMEM; - } - clk_osc = devm_clk_get(dev, "osc"); - clk_xtal = devm_clk_get(dev, "xtal"); - if (!IS_ERR(clk_osc)) { - s->clk = clk_osc; - fmin = 500000; - fmax = 35000000; - } else if (!IS_ERR(clk_xtal)) { - s->clk = clk_xtal; - fmin = 1000000; - fmax = 4000000; - xtal = true; - } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER || - PTR_ERR(clk_xtal) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else { - dev_err(dev, "Cannot get clock\n"); - return -EINVAL; - } + /* Always ask for fixed clock rate from a property. */ + device_property_read_u32(dev, "clock-frequency", &uartclk); + + xtal = device_property_match_string(dev, "clock-names", "osc") < 0; + if (xtal) + s->clk = devm_clk_get_optional(dev, "xtal"); + else + s->clk = devm_clk_get_optional(dev, "osc"); + if (IS_ERR(s->clk)) + return PTR_ERR(s->clk); ret = clk_prepare_enable(s->clk); if (ret) return ret; freq = clk_get_rate(s->clk); + if (freq == 0) + freq = uartclk; + if (freq == 0) { + ret = dev_err_probe(dev, -EINVAL, "Cannot get clock rate\n"); + goto out_clk; + } + + if (xtal) { + fmin = 1000000; + fmax = 4000000; + } else { + fmin = 500000; + fmax = 35000000; + } + /* Check frequency limits */ if (freq < fmin || freq > fmax) { ret = -ERANGE; goto out_clk; } - s->regmap = regmap; + s->regmap = regmaps[0]; s->devtype = devtype; + s->if_cfg = if_cfg; dev_set_drvdata(dev, s); /* Check device to ensure we are talking to what we expect */ - ret = devtype->detect(dev); + ret = max310x_detect(dev); if (ret) goto out_clk; for (i = 0; i < devtype->nr; i++) { - unsigned int offs = i << 5; + bool started = false; + unsigned int try = 0, val = 0; /* Reset port */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, + regmap_write(regmaps[i], MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); /* Clear port reset */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0); + regmap_write(regmaps[i], MAX310X_MODE2_REG, 0); /* Wait for port startup */ do { - regmap_read(s->regmap, - MAX310X_BRGDIVLSB_REG + offs, &ret); - } while (ret != 0x01); + msleep(MAX310X_PORT_STARTUP_WAIT_DELAY_MS); + regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &val); + + if (val == 0x01) + started = true; + } while (!started && (++try < MAX310X_PORT_STARTUP_WAIT_RETRIES)); - regmap_write(s->regmap, MAX310X_MODE1_REG + offs, - devtype->mode1); + if (!started) { + ret = dev_err_probe(dev, -EAGAIN, "port reset failed\n"); + goto out_uart; + } + + regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1); } uartclk = max310x_set_ref_clk(dev, s, freq, xtal); + if (uartclk < 0) { + ret = uartclk; + goto out_uart; + } + dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); for (i = 0; i < devtype->nr; i++) { @@ -1346,11 +1381,19 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->p[i].port.fifosize = MAX310X_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; - s->p[i].port.iobase = i * 0x20; + s->p[i].port.iobase = i; + /* + * Use all ones as membase to make sure uart_configure_port() in + * serial_core.c does not abort for SPI/I2C devices where the + * membase address is not applicable. + */ s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; + s->p[i].port.rs485_supported = max310x_rs485_supported; s->p[i].port.ops = &max310x_ops; + s->p[i].regmap = regmaps[i]; + /* Disable all interrupts */ max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); /* Clear IRQ status register */ @@ -1361,25 +1404,20 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); - /* Initialize SPI-transfer buffers */ - s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) | - MAX310X_WRITE_BIT; - s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG); /* Register port */ ret = uart_add_one_port(&max310x_uart, &s->p[i].port); - if (ret) { - s->p[i].port.dev = NULL; + if (ret) goto out_uart; - } + set_bit(line, max310x_lines); /* Go to suspend mode */ - devtype->power(&s->p[i].port, 0); + max310x_power(&s->p[i].port, 0); } #ifdef CONFIG_GPIOLIB - /* Setup GPIO cotroller */ + /* Setup GPIO controller */ s->gpio.owner = THIS_MODULE; s->gpio.parent = dev; s->gpio.label = devtype->name; @@ -1402,14 +1440,12 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, if (!ret) return 0; - dev_err(dev, "Unable to reguest IRQ %i\n", irq); + dev_err(dev, "Unable to request IRQ %i\n", irq); out_uart: for (i = 0; i < devtype->nr; i++) { - if (s->p[i].port.dev) { + if (test_and_clear_bit(s->p[i].port.line, max310x_lines)) uart_remove_one_port(&max310x_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, max310x_lines); - } } out_clk: @@ -1418,7 +1454,7 @@ out_clk: return ret; } -static int max310x_remove(struct device *dev) +static void max310x_remove(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); int i; @@ -1427,14 +1463,14 @@ static int max310x_remove(struct device *dev) cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].rs_work); - uart_remove_one_port(&max310x_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, max310x_lines); - s->devtype->power(&s->p[i].port, 0); + + if (test_and_clear_bit(s->p[i].port.line, max310x_lines)) + uart_remove_one_port(&max310x_uart, &s->p[i].port); + + max310x_power(&s->p[i].port, 0); } clk_disable_unprepare(s->clk); - - return 0; } static const struct of_device_id __maybe_unused max310x_dt_ids[] = { @@ -1450,17 +1486,49 @@ static struct regmap_config regcfg = { .reg_bits = 8, .val_bits = 8, .write_flag_mask = MAX310X_WRITE_BIT, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, + .max_register = MAX310X_REG_1F, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, + .writeable_noinc_reg = max310x_reg_noinc, + .readable_noinc_reg = max310x_reg_noinc, + .max_raw_read = MAX310X_FIFO_SIZE, + .max_raw_write = MAX310X_FIFO_SIZE, }; +static const char *max310x_regmap_name(u8 port_id) +{ + switch (port_id) { + case 0: return "port0"; + case 1: return "port1"; + case 2: return "port2"; + case 3: return "port3"; + default: + WARN_ON(true); + return NULL; + } +} + #ifdef CONFIG_SPI_MASTER +static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) +{ + struct max310x_port *s = dev_get_drvdata(dev); + + return regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, + enable ? MAX310X_EXTREG_ENBL : MAX310X_EXTREG_DSBL); +} + +static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = { + .extended_reg_enable = max310x_spi_extended_reg_enable, + .rev_id_offset = MAX310X_EXTREG_START, +}; + static int max310x_spi_probe(struct spi_device *spi) { - struct max310x_devtype *devtype; - struct regmap *regmap; + const struct max310x_devtype *devtype; + struct regmap *regmaps[MAX310X_MAX_PORTS]; + unsigned int i; int ret; /* Setup SPI bus */ @@ -1471,28 +1539,25 @@ static int max310x_spi_probe(struct spi_device *spi) if (ret) return ret; - if (spi->dev.of_node) { - const struct of_device_id *of_id = - of_match_device(max310x_dt_ids, &spi->dev); - if (!of_id) - return -ENODEV; + devtype = spi_get_device_match_data(spi); + if (!devtype) + return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); - devtype = (struct max310x_devtype *)of_id->data; - } else { - const struct spi_device_id *id_entry = spi_get_device_id(spi); + for (i = 0; i < devtype->nr; i++) { + u8 port_mask = i * 0x20; - devtype = (struct max310x_devtype *)id_entry->driver_data; + regcfg.name = max310x_regmap_name(i); + regcfg.read_flag_mask = port_mask; + regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT; + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); } - regcfg.max_register = devtype->nr * 0x20 - 1; - regmap = devm_regmap_init_spi(spi, ®cfg); - - return max310x_probe(&spi->dev, devtype, regmap, spi->irq); + return max310x_probe(&spi->dev, devtype, &max310x_spi_if_cfg, regmaps, spi->irq); } -static int max310x_spi_remove(struct spi_device *spi) +static void max310x_spi_remove(struct spi_device *spi) { - return max310x_remove(&spi->dev); + max310x_remove(&spi->dev); } static const struct spi_device_id max310x_id_table[] = { @@ -1507,7 +1572,7 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table); static struct spi_driver max310x_spi_driver = { .driver = { .name = MAX310X_NAME, - .of_match_table = of_match_ptr(max310x_dt_ids), + .of_match_table = max310x_dt_ids, .pm = &max310x_pm_ops, }, .probe = max310x_spi_probe, @@ -1516,6 +1581,116 @@ static struct spi_driver max310x_spi_driver = { }; #endif +#ifdef CONFIG_I2C +static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable) +{ + return 0; +} + +static struct regmap_config regcfg_i2c = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_MAPLE, + .writeable_reg = max310x_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, + .max_register = MAX310X_REVID_EXTREG, + .writeable_noinc_reg = max310x_reg_noinc, + .readable_noinc_reg = max310x_reg_noinc, + .max_raw_read = MAX310X_FIFO_SIZE, + .max_raw_write = MAX310X_FIFO_SIZE, +}; + +static const struct max310x_if_cfg max310x_i2c_if_cfg = { + .extended_reg_enable = max310x_i2c_extended_reg_enable, + .rev_id_offset = 0, /* No offset in I2C mode. */ +}; + +static unsigned short max310x_i2c_slave_addr(unsigned short addr, + unsigned int nr) +{ + /* + * For MAX14830 and MAX3109, the slave address depends on what the + * A0 and A1 pins are tied to. + * See Table I2C Address Map of the datasheet. + * Based on that table, the following formulas were determined: + * UART1 - UART0 = 0x10 + * UART2 - UART1 = 0x20 + 0x10 + * UART3 - UART2 = 0x10 + */ + + addr -= nr * 0x10; + + if (nr >= 2) + addr -= 0x20; + + return addr; +} + +static int max310x_i2c_probe(struct i2c_client *client) +{ + const struct max310x_devtype *devtype; + struct i2c_client *port_client; + struct regmap *regmaps[MAX310X_MAX_PORTS]; + unsigned int i; + u8 port_addr; + + devtype = i2c_get_match_data(client); + if (!devtype) + return dev_err_probe(&client->dev, -ENODEV, "Failed to match device\n"); + + if (client->addr < devtype->slave_addr.min || + client->addr > devtype->slave_addr.max) + return dev_err_probe(&client->dev, -EINVAL, + "Slave addr 0x%x outside of range [0x%x, 0x%x]\n", + client->addr, devtype->slave_addr.min, + devtype->slave_addr.max); + + regcfg_i2c.name = max310x_regmap_name(0); + regmaps[0] = devm_regmap_init_i2c(client, ®cfg_i2c); + + for (i = 1; i < devtype->nr; i++) { + port_addr = max310x_i2c_slave_addr(client->addr, i); + port_client = devm_i2c_new_dummy_device(&client->dev, + client->adapter, + port_addr); + if (IS_ERR(port_client)) + return PTR_ERR(port_client); + + regcfg_i2c.name = max310x_regmap_name(i); + regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c); + } + + return max310x_probe(&client->dev, devtype, &max310x_i2c_if_cfg, + regmaps, client->irq); +} + +static void max310x_i2c_remove(struct i2c_client *client) +{ + max310x_remove(&client->dev); +} + +static const struct i2c_device_id max310x_i2c_id_table[] = { + { "max3107", (kernel_ulong_t)&max3107_devtype, }, + { "max3108", (kernel_ulong_t)&max3108_devtype, }, + { "max3109", (kernel_ulong_t)&max3109_devtype, }, + { "max14830", (kernel_ulong_t)&max14830_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max310x_i2c_id_table); + +static struct i2c_driver max310x_i2c_driver = { + .driver = { + .name = MAX310X_NAME, + .of_match_table = max310x_dt_ids, + .pm = &max310x_pm_ops, + }, + .probe = max310x_i2c_probe, + .remove = max310x_i2c_remove, + .id_table = max310x_i2c_id_table, +}; +#endif + static int __init max310x_uart_init(void) { int ret; @@ -1528,14 +1703,36 @@ static int __init max310x_uart_init(void) #ifdef CONFIG_SPI_MASTER ret = spi_register_driver(&max310x_spi_driver); + if (ret) + goto err_spi_register; +#endif + +#ifdef CONFIG_I2C + ret = i2c_add_driver(&max310x_i2c_driver); + if (ret) + goto err_i2c_register; #endif + return 0; + +#ifdef CONFIG_I2C +err_i2c_register: + spi_unregister_driver(&max310x_spi_driver); +#endif + +err_spi_register: + uart_unregister_driver(&max310x_uart); + return ret; } module_init(max310x_uart_init); static void __exit max310x_uart_exit(void) { +#ifdef CONFIG_I2C + i2c_del_driver(&max310x_i2c_driver); +#endif + #ifdef CONFIG_SPI_MASTER spi_unregister_driver(&max310x_spi_driver); #endif diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 7dbfb4cde124..93e7dda4d39a 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -135,12 +135,12 @@ static void mcf_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (break_state == -1) writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR); else writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /****************************************************************************/ @@ -150,7 +150,7 @@ static int mcf_startup(struct uart_port *port) struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Reset UART, get it into known state... */ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); @@ -164,7 +164,7 @@ static int mcf_startup(struct uart_port *port) pp->imr = MCFUART_UIR_RXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -176,7 +176,7 @@ static void mcf_shutdown(struct uart_port *port) struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable all interrupts now */ pp->imr = 0; @@ -186,13 +186,13 @@ static void mcf_shutdown(struct uart_port *port) writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /****************************************************************************/ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, baudclk; @@ -252,7 +252,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, mr2 |= MCFUART_MR2_TXCTS; } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (port->rs485.flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); mr2 |= MCFUART_MR2_TXRTS; @@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, port->membase + MCFUART_UCSR); writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /****************************************************************************/ @@ -281,7 +281,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, static void mcf_rx_chars(struct mcf_uart *pp) { struct uart_port *port = &pp->port; - unsigned char status, ch, flag; + u8 status, ch, flag; while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { ch = readb(port->membase + MCFUART_URB); @@ -319,9 +319,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } /****************************************************************************/ @@ -329,35 +327,16 @@ static void mcf_rx_chars(struct mcf_uart *pp) static void mcf_tx_chars(struct mcf_uart *pp) { struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - /* Send special char - probably flow control */ - writeb(port->x_char, port->membase + MCFUART_UTB); - port->x_char = 0; - port->icount.tx++; - return; - } + bool pending; + u8 ch; - while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { - if (xmit->head == xmit->tail) - break; - writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); - port->icount.tx++; - } + pending = uart_port_tx(port, ch, + readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY, + writeb(ch, port->membase + MCFUART_UTB)); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (xmit->head == xmit->tail) { - pp->imr &= ~MCFUART_UIR_TXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); - /* Disable TX to negate RTS automatically */ - if (port->rs485.flags & SER_RS485_ENABLED) - writeb(MCFUART_UCR_TXDISABLE, - port->membase + MCFUART_UCR); - } + /* Disable TX to negate RTS automatically */ + if (!pending && (port->rs485.flags & SER_RS485_ENABLED)) + writeb(MCFUART_UCR_TXDISABLE, port->membase + MCFUART_UCR); } /****************************************************************************/ @@ -371,7 +350,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data) isr = readb(port->membase + MCFUART_UISR) & pp->imr; - spin_lock(&port->lock); + uart_port_lock(port); if (isr & MCFUART_UIR_RXREADY) { mcf_rx_chars(pp); ret = IRQ_HANDLED; @@ -380,7 +359,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data) mcf_tx_chars(pp); ret = IRQ_HANDLED; } - spin_unlock(&port->lock); + uart_port_unlock(port); return ret; } @@ -434,7 +413,8 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) /****************************************************************************/ /* Enable or disable the RS485 support */ -static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) +static int mcf_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { unsigned char mr1, mr2; @@ -451,11 +431,14 @@ static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) } writeb(mr1, port->membase + MCFUART_UMR); writeb(mr2, port->membase + MCFUART_UMR); - port->rs485 = *rs485; return 0; } +static const struct serial_rs485 mcf_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND, +}; + /****************************************************************************/ /* @@ -479,7 +462,7 @@ static const struct uart_ops mcf_uart_ops = { .verify_port = mcf_verify_port, }; -static struct mcf_uart mcf_ports[4]; +static struct mcf_uart mcf_ports[10]; #define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) @@ -487,32 +470,6 @@ static struct mcf_uart mcf_ports[4]; #if defined(CONFIG_SERIAL_MCF_CONSOLE) /****************************************************************************/ -int __init early_mcf_setup(struct mcf_platform_uart *platp) -{ - struct uart_port *port; - int i; - - for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { - port = &mcf_ports[i].port; - - port->line = i; - port->type = PORT_MCF; - port->mapbase = platp[i].mapbase; - port->membase = (platp[i].membase) ? platp[i].membase : - (unsigned char __iomem *) port->mapbase; - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = MCF_BUSCLK; - port->flags = UPF_BOOT_AUTOCONF; - port->rs485_config = mcf_config_rs485; - port->ops = &mcf_uart_ops; - } - - return 0; -} - -/****************************************************************************/ - static void mcf_console_putc(struct console *co, const char c) { struct uart_port *port = &(mcf_ports + co->index)->port; @@ -632,6 +589,8 @@ static int mcf_probe(struct platform_device *pdev) port->ops = &mcf_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->rs485_config = mcf_config_rs485; + port->rs485_supported = mcf_rs485_supported; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE); uart_add_one_port(&mcf_driver, port); } @@ -641,7 +600,7 @@ static int mcf_probe(struct platform_device *pdev) /****************************************************************************/ -static int mcf_remove(struct platform_device *pdev) +static void mcf_remove(struct platform_device *pdev) { struct uart_port *port; int i; @@ -651,8 +610,6 @@ static int mcf_remove(struct platform_device *pdev) if (port) uart_remove_one_port(&mcf_driver, port); } - - return 0; } /****************************************************************************/ diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 4f53a4caabf6..9cc15449b673 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -173,7 +173,7 @@ static void men_z135_reg_clr(struct men_z135_port *uart, /** * men_z135_handle_modem_status() - Handle change of modem status - * @port: The UART port + * @uart: The UART port * * Handle change of modem status register. This is done by reading the "delta" * versions of DCD (Data Carrier Detect) and CTS (Clear To Send). @@ -236,7 +236,7 @@ static u16 get_rx_fifo_content(struct men_z135_port *uart) /** * men_z135_handle_rx() - RX tasklet routine - * @arg: Pointer to struct men_z135_port + * @uart: Pointer to struct men_z135_port * * Copy from RX FIFO and acknowledge number of bytes copied. */ @@ -287,23 +287,20 @@ static void men_z135_handle_rx(struct men_z135_port *uart) /** * men_z135_handle_tx() - TX tasklet routine - * @arg: Pointer to struct men_z135_port + * @uart: Pointer to struct men_z135_port * */ static void men_z135_handle_tx(struct men_z135_port *uart) { struct uart_port *port = &uart->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char *tail; + unsigned int n, txfree; u32 txc; u32 wptr; int qlen; - int n; - int txfree; - int head; - int tail; - int s; - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) goto out; if (uart_tx_stopped(port)) @@ -313,7 +310,7 @@ static void men_z135_handle_tx(struct men_z135_port *uart) goto out; /* calculate bytes to copy */ - qlen = uart_circ_chars_pending(xmit); + qlen = kfifo_len(&tport->xmit_fifo); if (qlen <= 0) goto out; @@ -345,24 +342,18 @@ static void men_z135_handle_tx(struct men_z135_port *uart) if (n <= 0) goto irq_en; - head = xmit->head & (UART_XMIT_SIZE - 1); - tail = xmit->tail & (UART_XMIT_SIZE - 1); - - s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; - n = min(n, s); - - memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n); - xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1); + n = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + min_t(unsigned int, UART_XMIT_SIZE, n)); + memcpy_toio(port->membase + MEN_Z135_TX_RAM, tail, n); iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL); + uart_xmit_advance(port, n); - port->icount.tx += n; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); irq_en: - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); else men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); @@ -395,7 +386,7 @@ static irqreturn_t men_z135_intr(int irq, void *data) if (!irq_id) goto out; - spin_lock(&port->lock); + uart_port_lock(port); /* It's save to write to IIR[7:6] RXC[9:8] */ iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG); @@ -421,7 +412,7 @@ static irqreturn_t men_z135_intr(int irq, void *data) handled = true; } - spin_unlock(&port->lock); + uart_port_unlock(port); out: return IRQ_RETVAL(handled); } @@ -596,7 +587,7 @@ static void men_z135_stop_rx(struct uart_port *port) /** * men_z135_enable_ms() - Enable Modem Status - * port: + * @port: the port * * Enable Modem Status IRQ. */ @@ -646,8 +637,8 @@ static void men_z135_shutdown(struct uart_port *port) } static void men_z135_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { struct men_z135_port *uart = to_men_z135(port); unsigned int baud; @@ -711,7 +702,7 @@ static void men_z135_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16); - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -719,7 +710,7 @@ static void men_z135_set_termios(struct uart_port *port, iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG); uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } static const char *men_z135_type(struct uart_port *port) @@ -833,7 +824,6 @@ static int men_z135_probe(struct mcb_device *mdev, uart->port.iotype = UPIO_MEM; uart->port.ops = &men_z135_ops; uart->port.irq = mcb_get_irq(mdev); - uart->port.iotype = UPIO_MEM; uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; uart->port.line = line++; uart->port.dev = dev; @@ -930,4 +920,4 @@ MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); MODULE_ALIAS("mcb:16z135"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index d2c08b760f83..a6cb2a535f9d 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -68,18 +68,24 @@ #define AML_UART_BAUD_MASK 0x7fffff #define AML_UART_BAUD_USE BIT(23) #define AML_UART_BAUD_XTAL BIT(24) +#define AML_UART_BAUD_XTAL_DIV2 BIT(27) #define AML_UART_PORT_NUM 12 #define AML_UART_PORT_OFFSET 6 -#define AML_UART_DEV_NAME "ttyAML" #define AML_UART_POLL_USEC 5 #define AML_UART_TIMEOUT_USEC 10000 -static struct uart_driver meson_uart_driver; +static struct uart_driver meson_uart_driver_ttyAML; +static struct uart_driver meson_uart_driver_ttyS; static struct uart_port *meson_ports[AML_UART_PORT_NUM]; +struct meson_uart_data { + struct uart_driver *uart_driver; + bool has_xtal_div2; +}; + static void meson_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { } @@ -123,20 +129,20 @@ static void meson_uart_shutdown(struct uart_port *port) free_irq(port->irq, port); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = readl(port->membase + AML_UART_CONTROL); val &= ~AML_UART_RX_EN; val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN); writel(val, port->membase + AML_UART_CONTROL); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void meson_uart_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int ch; + struct tty_port *tport = &port->state->port; + unsigned char ch; u32 val; if (uart_tx_stopped(port)) { @@ -152,22 +158,19 @@ static void meson_uart_start_tx(struct uart_port *port) continue; } - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(port, &ch)) break; - ch = xmit->buf[xmit->tail]; writel(ch, port->membase + AML_UART_WFIFO); - xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1); - port->icount.tx++; } - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { val = readl(port->membase + AML_UART_CONTROL); val |= AML_UART_TX_INT_EN; writel(val, port->membase + AML_UART_CONTROL); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -215,7 +218,7 @@ static void meson_receive_chars(struct uart_port *port) continue; } - if (uart_handle_sysrq_char(port, ch)) + if (uart_prepare_sysrq_char(port, ch)) continue; if ((status & port->ignore_status_mask) == 0) @@ -226,16 +229,14 @@ static void meson_receive_chars(struct uart_port *port) } while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)); - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; - spin_lock(&port->lock); + uart_port_lock(port); if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)) meson_receive_chars(port); @@ -245,7 +246,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) meson_uart_start_tx(port); } - spin_unlock(&port->lock); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -255,6 +256,14 @@ static const char *meson_uart_type(struct uart_port *port) return (port->type == PORT_MESON) ? "meson_uart" : NULL; } +/* + * This function is called only from probe() using a temporary io mapping + * in order to perform a reset before setting up the device. Since the + * temporarily mapped region was successfully requested, there can be no + * console on this port at this time. Hence it is not necessary for this + * function to acquire the port->lock. (Since there is no console on this + * port at this time, the port->lock is not initialized yet.) + */ static void meson_uart_reset(struct uart_port *port) { u32 val; @@ -269,9 +278,12 @@ static void meson_uart_reset(struct uart_port *port) static int meson_uart_startup(struct uart_port *port) { + unsigned long flags; u32 val; int ret = 0; + uart_port_lock_irqsave(port, &flags); + val = readl(port->membase + AML_UART_CONTROL); val |= AML_UART_CLEAR_ERR; writel(val, port->membase + AML_UART_CONTROL); @@ -287,6 +299,8 @@ static int meson_uart_startup(struct uart_port *port) val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2)); writel(val, port->membase + AML_UART_MISC); + uart_port_unlock_irqrestore(port, flags); + ret = request_irq(port->irq, meson_uart_interrupt, 0, port->name, port); @@ -295,16 +309,23 @@ static int meson_uart_startup(struct uart_port *port) static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) { - u32 val; + const struct meson_uart_data *private_data = port->private_data; + u32 val = 0; while (!meson_uart_tx_empty(port)) cpu_relax(); if (port->uartclk == 24000000) { - val = ((port->uartclk / 3) / baud) - 1; + unsigned int xtal_div = 3; + + if (private_data && private_data->has_xtal_div2) { + xtal_div = 2; + val |= AML_UART_BAUD_XTAL_DIV2; + } + val |= DIV_ROUND_CLOSEST(port->uartclk / xtal_div, baud) - 1; val |= AML_UART_BAUD_XTAL; } else { - val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1; + val = DIV_ROUND_CLOSEST(port->uartclk / 4, baud) - 1; } val |= AML_UART_BAUD_USE; writel(val, port->membase + AML_UART_REG5); @@ -312,13 +333,13 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) static void meson_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int cflags, iflags, baud; unsigned long flags; u32 val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); cflags = termios->c_cflag; iflags = termios->c_iflag; @@ -357,10 +378,14 @@ static void meson_uart_set_termios(struct uart_port *port, else val |= AML_UART_STOP_BIT_1SB; - if (cflags & CRTSCTS) - val &= ~AML_UART_TWO_WIRE_EN; - else + if (cflags & CRTSCTS) { + if (port->flags & UPF_HARD_FLOW) + val &= ~AML_UART_TWO_WIRE_EN; + else + termios->c_cflag &= ~CRTSCTS; + } else { val |= AML_UART_TWO_WIRE_EN; + } writel(val, port->membase + AML_UART_CONTROL); @@ -378,7 +403,7 @@ static void meson_uart_set_termios(struct uart_port *port, AML_UART_FRAME_ERR; uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int meson_uart_verify_port(struct uart_port *port, @@ -437,14 +462,14 @@ static int meson_uart_poll_get_char(struct uart_port *port) u32 c; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY) c = NO_POLL_CHAR; else c = readl(port->membase + AML_UART_RFIFO); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return c; } @@ -455,7 +480,7 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c) u32 reg; int ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Wait until FIFO is empty or timeout */ ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg, @@ -479,7 +504,7 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c) dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n"); out: - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } #endif /* CONFIG_CONSOLE_POLL */ @@ -515,7 +540,7 @@ static void meson_uart_enable_tx_engine(struct uart_port *port) writel(val, port->membase + AML_UART_CONTROL); } -static void meson_console_putchar(struct uart_port *port, int ch) +static void meson_console_putchar(struct uart_port *port, unsigned char ch) { if (!port->membase) return; @@ -529,18 +554,13 @@ static void meson_serial_port_write(struct uart_port *port, const char *s, u_int count) { unsigned long flags; - int locked; + int locked = 1; u32 val, tmp; - local_irq_save(flags); - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else { - spin_lock(&port->lock); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); val = readl(port->membase + AML_UART_CONTROL); tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN); @@ -550,8 +570,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s, writel(val, port->membase + AML_UART_CONTROL); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void meson_serial_console_write(struct console *co, const char *s, @@ -589,22 +608,19 @@ static int meson_serial_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct console meson_serial_console = { - .name = AML_UART_DEV_NAME, - .write = meson_serial_console_write, - .device = uart_console_device, - .setup = meson_serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &meson_uart_driver, -}; +#define MESON_SERIAL_CONSOLE(_devname) \ + static struct console meson_serial_console_##_devname = { \ + .name = __stringify(_devname), \ + .write = meson_serial_console_write, \ + .device = uart_console_device, \ + .setup = meson_serial_console_setup, \ + .flags = CON_PRINTBUFFER, \ + .index = -1, \ + .data = &meson_uart_driver_##_devname, \ + } -static int __init meson_serial_console_init(void) -{ - register_console(&meson_serial_console); - return 0; -} -console_initcall(meson_serial_console_init); +MESON_SERIAL_CONSOLE(ttyAML); +MESON_SERIAL_CONSOLE(ttyS); static void meson_serial_early_console_write(struct console *co, const char *s, @@ -625,67 +641,26 @@ meson_serial_early_console_setup(struct earlycon_device *device, const char *opt device->con->write = meson_serial_early_console_write; return 0; } -/* Legacy bindings, should be removed when no more used */ -OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart", - meson_serial_early_console_setup); -/* Stable bindings */ -OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart", - meson_serial_early_console_setup); - -#define MESON_SERIAL_CONSOLE (&meson_serial_console) -#else -#define MESON_SERIAL_CONSOLE NULL -#endif - -static struct uart_driver meson_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "meson_uart", - .dev_name = AML_UART_DEV_NAME, - .nr = AML_UART_PORT_NUM, - .cons = MESON_SERIAL_CONSOLE, -}; -static inline struct clk *meson_uart_probe_clock(struct device *dev, - const char *id) -{ - struct clk *clk = NULL; - int ret; +OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart", meson_serial_early_console_setup); +OF_EARLYCON_DECLARE(meson, "amlogic,meson-s4-uart", meson_serial_early_console_setup); - clk = devm_clk_get(dev, id); - if (IS_ERR(clk)) - return clk; +#define MESON_SERIAL_CONSOLE_PTR(_devname) (&meson_serial_console_##_devname) +#else +#define MESON_SERIAL_CONSOLE_PTR(_devname) (NULL) +#endif - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(dev, "couldn't enable clk\n"); - return ERR_PTR(ret); +#define MESON_UART_DRIVER(_devname) \ + static struct uart_driver meson_uart_driver_##_devname = { \ + .owner = THIS_MODULE, \ + .driver_name = "meson_uart", \ + .dev_name = __stringify(_devname), \ + .nr = AML_UART_PORT_NUM, \ + .cons = MESON_SERIAL_CONSOLE_PTR(_devname), \ } - devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - clk); - - return clk; -} - -/* - * This function gets clocks in the legacy non-stable DT bindings. - * This code will be remove once all the platforms switch to the - * new DT bindings. - */ -static int meson_uart_probe_clocks_legacy(struct platform_device *pdev, - struct uart_port *port) -{ - struct clk *clk = NULL; - - clk = meson_uart_probe_clock(&pdev->dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - port->uartclk = clk_get_rate(clk); - - return 0; -} +MESON_UART_DRIVER(ttyAML); +MESON_UART_DRIVER(ttyS); static int meson_uart_probe_clocks(struct platform_device *pdev, struct uart_port *port) @@ -694,15 +669,15 @@ static int meson_uart_probe_clocks(struct platform_device *pdev, struct clk *clk_pclk = NULL; struct clk *clk_baud = NULL; - clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk"); + clk_pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); if (IS_ERR(clk_pclk)) return PTR_ERR(clk_pclk); - clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal"); + clk_xtal = devm_clk_get_enabled(&pdev->dev, "xtal"); if (IS_ERR(clk_xtal)) return PTR_ERR(clk_xtal); - clk_baud = meson_uart_probe_clock(&pdev->dev, "baud"); + clk_baud = devm_clk_get_enabled(&pdev->dev, "baud"); if (IS_ERR(clk_baud)) return PTR_ERR(clk_baud); @@ -711,17 +686,29 @@ static int meson_uart_probe_clocks(struct platform_device *pdev, return 0; } +static struct uart_driver *meson_uart_current(const struct meson_uart_data *pd) +{ + return (pd && pd->uart_driver) ? + pd->uart_driver : &meson_uart_driver_ttyAML; +} + static int meson_uart_probe(struct platform_device *pdev) { - struct resource *res_mem, *res_irq; + const struct meson_uart_data *priv_data; + struct uart_driver *uart_driver; + struct resource *res_mem; struct uart_port *port; + u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */ int ret = 0; - int id = -1; + int irq; + bool has_rtscts; if (pdev->dev.of_node) pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); if (pdev->id < 0) { + int id; + for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) { if (!meson_ports[id]) { pdev->id = id; @@ -737,40 +724,52 @@ static int meson_uart_probe(struct platform_device *pdev) if (!res_mem) return -ENODEV; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize); + has_rtscts = of_property_read_bool(pdev->dev.of_node, "uart-has-rtscts"); if (meson_ports[pdev->id]) { - dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); - return -EBUSY; + return dev_err_probe(&pdev->dev, -EBUSY, + "port %d already allocated\n", pdev->id); } port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL); if (!port) return -ENOMEM; - /* Use legacy way until all platforms switch to new bindings */ - if (of_device_is_compatible(pdev->dev.of_node, "amlogic,meson-uart")) - ret = meson_uart_probe_clocks_legacy(pdev, port); - else - ret = meson_uart_probe_clocks(pdev, port); - + ret = meson_uart_probe_clocks(pdev, port); if (ret) return ret; + priv_data = device_get_match_data(&pdev->dev); + + uart_driver = meson_uart_current(priv_data); + + if (!uart_driver->state) { + ret = uart_register_driver(uart_driver); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't register uart driver\n"); + } + port->iotype = UPIO_MEM; port->mapbase = res_mem->start; port->mapsize = resource_size(res_mem); - port->irq = res_irq->start; + port->irq = irq; port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY; + if (has_rtscts) + port->flags |= UPF_HARD_FLOW; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MESON_CONSOLE); port->dev = &pdev->dev; port->line = pdev->id; port->type = PORT_MESON; port->x_char = 0; port->ops = &meson_uart_ops; - port->fifosize = 64; + port->fifosize = fifosize; + port->private_data = (void *)priv_data; meson_ports[pdev->id] = port; platform_set_drvdata(pdev, port); @@ -781,32 +780,62 @@ static int meson_uart_probe(struct platform_device *pdev) meson_uart_release_port(port); } - ret = uart_add_one_port(&meson_uart_driver, port); + ret = uart_add_one_port(uart_driver, port); if (ret) meson_ports[pdev->id] = NULL; return ret; } -static int meson_uart_remove(struct platform_device *pdev) +static void meson_uart_remove(struct platform_device *pdev) { + struct uart_driver *uart_driver; struct uart_port *port; port = platform_get_drvdata(pdev); - uart_remove_one_port(&meson_uart_driver, port); + uart_driver = meson_uart_current(port->private_data); + uart_remove_one_port(uart_driver, port); meson_ports[pdev->id] = NULL; - return 0; + for (int id = 0; id < AML_UART_PORT_NUM; id++) + if (meson_ports[id]) + return; + + /* No more available uart ports, unregister uart driver */ + uart_unregister_driver(uart_driver); } +static struct meson_uart_data meson_g12a_uart_data = { + .has_xtal_div2 = true, +}; + +static struct meson_uart_data meson_a1_uart_data = { + .uart_driver = &meson_uart_driver_ttyS, + .has_xtal_div2 = false, +}; + +static struct meson_uart_data meson_s4_uart_data = { + .uart_driver = &meson_uart_driver_ttyS, + .has_xtal_div2 = true, +}; + static const struct of_device_id meson_uart_dt_match[] = { - /* Legacy bindings, should be removed when no more used */ - { .compatible = "amlogic,meson-uart" }, - /* Stable bindings */ { .compatible = "amlogic,meson6-uart" }, { .compatible = "amlogic,meson8-uart" }, { .compatible = "amlogic,meson8b-uart" }, { .compatible = "amlogic,meson-gx-uart" }, + { + .compatible = "amlogic,meson-g12a-uart", + .data = (void *)&meson_g12a_uart_data, + }, + { + .compatible = "amlogic,meson-s4-uart", + .data = (void *)&meson_s4_uart_data, + }, + { + .compatible = "amlogic,meson-a1-uart", + .data = (void *)&meson_a1_uart_data, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, meson_uart_dt_match); @@ -820,29 +849,7 @@ static struct platform_driver meson_uart_platform_driver = { }, }; -static int __init meson_uart_init(void) -{ - int ret; - - ret = uart_register_driver(&meson_uart_driver); - if (ret) - return ret; - - ret = platform_driver_register(&meson_uart_platform_driver); - if (ret) - uart_unregister_driver(&meson_uart_driver); - - return ret; -} - -static void __exit meson_uart_exit(void) -{ - platform_driver_unregister(&meson_uart_platform_driver); - uart_unregister_driver(&meson_uart_driver); -} - -module_init(meson_uart_init); -module_exit(meson_uart_exit); +module_platform_driver(meson_uart_platform_driver); MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); MODULE_DESCRIPTION("Amlogic Meson serial port driver"); diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index 8f2cab7f66ad..4e47dca2c4ed 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -72,7 +72,7 @@ static void mlb_usio_stop_tx(struct uart_port *port) static void mlb_usio_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int count; writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE, @@ -87,7 +87,7 @@ static void mlb_usio_tx_chars(struct uart_port *port) port->x_char = 0; return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { mlb_usio_stop_tx(port); return; } @@ -96,13 +96,13 @@ static void mlb_usio_tx_chars(struct uart_port *port) (readw(port->membase + MLB_USIO_REG_FBYTE) & 0xff); do { - writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR); + unsigned char ch; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(port, &ch)) break; + writew(ch, port->membase + MLB_USIO_REG_DR); + port->icount.tx++; } while (--count > 0); writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FDRQ, @@ -111,10 +111,10 @@ static void mlb_usio_tx_chars(struct uart_port *port) writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE, port->membase + MLB_USIO_REG_SCR); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) mlb_usio_stop_tx(port); } @@ -149,8 +149,7 @@ static void mlb_usio_enable_ms(struct uart_port *port) static void mlb_usio_rx_chars(struct uart_port *port) { struct tty_port *ttyport = &port->state->port; - unsigned long flag = 0; - char ch = 0; + u8 flag = 0, ch = 0; u8 status; int max_count = 2; @@ -209,9 +208,9 @@ static irqreturn_t mlb_usio_rx_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; - spin_lock(&port->lock); + uart_port_lock(port); mlb_usio_rx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -220,10 +219,10 @@ static irqreturn_t mlb_usio_tx_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; - spin_lock(&port->lock); + uart_port_lock(port); if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI) mlb_usio_tx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -269,7 +268,7 @@ static int mlb_usio_startup(struct uart_port *port) escr = readb(port->membase + MLB_USIO_REG_ESCR); if (of_property_read_bool(port->dev->of_node, "auto-flow-control")) escr |= MLB_USIO_ESCR_FLWEN; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); writeb(0, port->membase + MLB_USIO_REG_SCR); writeb(escr, port->membase + MLB_USIO_REG_ESCR); writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR); @@ -284,7 +283,7 @@ static int mlb_usio_startup(struct uart_port *port) writeb(MLB_USIO_SCR_TXE | MLB_USIO_SCR_RIE | MLB_USIO_SCR_TBIE | MLB_USIO_SCR_RXE, port->membase + MLB_USIO_REG_SCR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -298,7 +297,8 @@ static void mlb_usio_shutdown(struct uart_port *port) } static void mlb_usio_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { unsigned int escr, smr = MLB_USIO_SMR_SOE; unsigned long flags, baud, quot; @@ -338,7 +338,7 @@ static void mlb_usio_set_termios(struct uart_port *port, else quot = 0; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, termios->c_cflag, baud); port->read_status_mask = MLB_USIO_SSR_ORE | MLB_USIO_SSR_RDRF | MLB_USIO_SSR_TDRE; @@ -368,7 +368,7 @@ static void mlb_usio_set_termios(struct uart_port *port, writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE); writeb(MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE | MLB_USIO_SCR_TBIE | MLB_USIO_SCR_TXE, port->membase + MLB_USIO_REG_SCR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *mlb_usio_type(struct uart_port *port) @@ -400,7 +400,7 @@ static const struct uart_ops mlb_usio_ops = { #ifdef CONFIG_SERIAL_MILBEAUT_USIO_CONSOLE -static void mlb_usio_console_putchar(struct uart_port *port, int c) +static void mlb_usio_console_putchar(struct uart_port *port, unsigned char c) { while (!(readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TDRE)) cpu_relax(); @@ -523,7 +523,10 @@ static int mlb_usio_probe(struct platform_device *pdev) } port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - + if (!port->membase) { + ret = -ENOMEM; + goto failed; + } ret = platform_get_irq_byname(pdev, "rx"); mlb_usio_irq[index][RX] = ret; @@ -553,15 +556,13 @@ failed: return ret; } -static int mlb_usio_remove(struct platform_device *pdev) +static void mlb_usio_remove(struct platform_device *pdev) { struct uart_port *port = &mlb_usio_ports[pdev->id]; struct clk *clk = port->private_data; uart_remove_one_port(&mlb_usio_uart_driver, port); clk_disable_unprepare(clk); - - return 0; } static const struct of_device_id mlb_usio_dt_ids[] = { diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index af1700445251..37eb701b0b46 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -38,7 +38,9 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> #include <linux/clk.h> #include <asm/mpc52xx.h> @@ -83,11 +85,11 @@ static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); struct psc_ops { void (*fifo_init)(struct uart_port *port); - int (*raw_rx_rdy)(struct uart_port *port); - int (*raw_tx_rdy)(struct uart_port *port); - int (*rx_rdy)(struct uart_port *port); - int (*tx_rdy)(struct uart_port *port); - int (*tx_empty)(struct uart_port *port); + unsigned int (*raw_rx_rdy)(struct uart_port *port); + unsigned int (*raw_tx_rdy)(struct uart_port *port); + unsigned int (*rx_rdy)(struct uart_port *port); + unsigned int (*tx_rdy)(struct uart_port *port); + unsigned int (*tx_empty)(struct uart_port *port); void (*stop_rx)(struct uart_port *port); void (*start_tx)(struct uart_port *port); void (*stop_tx)(struct uart_port *port); @@ -99,7 +101,7 @@ struct psc_ops { void (*cw_restore_ints)(struct uart_port *port); unsigned int (*set_baudrate)(struct uart_port *port, struct ktermios *new, - struct ktermios *old); + const struct ktermios *old); int (*clock_alloc)(struct uart_port *port); void (*clock_relse)(struct uart_port *port); int (*clock)(struct uart_port *port, int enable); @@ -203,34 +205,34 @@ static void mpc52xx_psc_fifo_init(struct uart_port *port) out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); } -static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) +static unsigned int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) { return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; } -static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) +static unsigned int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) { return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY; } -static int mpc52xx_psc_rx_rdy(struct uart_port *port) +static unsigned int mpc52xx_psc_rx_rdy(struct uart_port *port) { return in_be16(&PSC(port)->mpc52xx_psc_isr) & port->read_status_mask & MPC52xx_PSC_IMR_RXRDY; } -static int mpc52xx_psc_tx_rdy(struct uart_port *port) +static unsigned int mpc52xx_psc_tx_rdy(struct uart_port *port) { return in_be16(&PSC(port)->mpc52xx_psc_isr) & port->read_status_mask & MPC52xx_PSC_IMR_TXRDY; } -static int mpc52xx_psc_tx_empty(struct uart_port *port) +static unsigned int mpc52xx_psc_tx_empty(struct uart_port *port) { u16 sts = in_be16(&PSC(port)->mpc52xx_psc_status); @@ -285,7 +287,7 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -303,7 +305,7 @@ static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -436,31 +438,31 @@ static void mpc512x_psc_fifo_init(struct uart_port *port) out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); } -static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_raw_rx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); } -static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_raw_tx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); } -static int mpc512x_psc_rx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_rx_rdy(struct uart_port *port) { return in_be32(&FIFO_512x(port)->rxsr) & in_be32(&FIFO_512x(port)->rximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc512x_psc_tx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_tx_rdy(struct uart_port *port) { return in_be32(&FIFO_512x(port)->txsr) & in_be32(&FIFO_512x(port)->tximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc512x_psc_tx_empty(struct uart_port *port) +static unsigned int mpc512x_psc_tx_empty(struct uart_port *port) { return in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_EMPTY; @@ -531,7 +533,7 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port) static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -754,9 +756,6 @@ static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) port->irqflags = IRQF_SHARED; port->irq = psc_fifoc_irq; } -#endif - -#ifdef CONFIG_PPC_MPC512x #define PSC_5125(port) ((struct mpc5125_psc __iomem *)((port)->membase)) #define FIFO_5125(port) ((struct mpc512x_psc_fifo __iomem *)(PSC_5125(port)+1)) @@ -780,29 +779,29 @@ static void mpc5125_psc_fifo_init(struct uart_port *port) out_be32(&FIFO_5125(port)->rximr, MPC512x_PSC_FIFO_ALARM); } -static int mpc5125_psc_raw_rx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_raw_rx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_5125(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); } -static int mpc5125_psc_raw_tx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_raw_tx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_FULL); } -static int mpc5125_psc_rx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_rx_rdy(struct uart_port *port) { return in_be32(&FIFO_5125(port)->rxsr) & in_be32(&FIFO_5125(port)->rximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc5125_psc_tx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_tx_rdy(struct uart_port *port) { return in_be32(&FIFO_5125(port)->txsr) & in_be32(&FIFO_5125(port)->tximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc5125_psc_tx_empty(struct uart_port *port) +static unsigned int mpc5125_psc_tx_empty(struct uart_port *port) { return in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_EMPTY; } @@ -881,7 +880,7 @@ static inline void mpc5125_set_divisor(struct mpc5125_psc __iomem *psc, static unsigned int mpc5125_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -1097,14 +1096,14 @@ static void mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (ctl == -1) psc_ops->command(port, MPC52xx_PSC_START_BRK); else psc_ops->command(port, MPC52xx_PSC_STOP_BRK); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int @@ -1168,7 +1167,7 @@ mpc52xx_uart_shutdown(struct uart_port *port) static void mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned char mr1, mr2; @@ -1215,7 +1214,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, } /* Get the lock */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Do our best to flush TX & RX, so we don't lose anything */ /* But we don't wait indefinitely ! */ @@ -1251,7 +1250,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, psc_ops->command(port, MPC52xx_PSC_RX_ENABLE); /* We're all set, release the lock */ - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char * @@ -1352,7 +1351,6 @@ static const struct uart_ops mpc52xx_uart_ops = { .startup = mpc52xx_uart_startup, .shutdown = mpc52xx_uart_shutdown, .set_termios = mpc52xx_uart_set_termios, -/* .pm = mpc52xx_uart_pm, Not supported yet */ .type = mpc52xx_uart_type, .release_port = mpc52xx_uart_release_port, .request_port = mpc52xx_uart_request_port, @@ -1365,7 +1363,7 @@ static const struct uart_ops mpc52xx_uart_ops = { /* Interrupt handling */ /* ======================================================================== */ -static inline int +static inline bool mpc52xx_uart_int_rx_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; @@ -1421,65 +1419,32 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) } } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); return psc_ops->raw_rx_rdy(port); } -static inline int +static inline bool mpc52xx_uart_int_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - - /* Process out of band chars */ - if (port->x_char) { - psc_ops->write_char(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return 1; - } - - /* Nothing to do ? */ - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mpc52xx_uart_stop_tx(port); - return 0; - } - - /* Send chars */ - while (psc_ops->raw_tx_rdy(port)) { - psc_ops->write_char(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - /* Wake up */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + u8 ch; - /* Maybe we're done after all */ - if (uart_circ_empty(xmit)) { - mpc52xx_uart_stop_tx(port); - return 0; - } - - return 1; + return uart_port_tx(port, ch, + psc_ops->raw_tx_rdy(port), + psc_ops->write_char(port, ch)); } static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port) { unsigned long pass = ISR_PASS_LIMIT; - unsigned int keepgoing; + bool keepgoing; u8 status; /* While we have stuff to do, we continue */ do { /* If we don't find anything to do, we stop */ - keepgoing = 0; + keepgoing = false; psc_ops->rx_clr_irq(port); if (psc_ops->rx_rdy(port)) @@ -1498,7 +1463,7 @@ mpc5xxx_uart_process_int(struct uart_port *port) /* Limit number of iteration */ if (!(--pass)) - keepgoing = 0; + keepgoing = false; } while (keepgoing); @@ -1511,11 +1476,11 @@ mpc52xx_uart_int(int irq, void *dev_id) struct uart_port *port = dev_id; irqreturn_t ret; - spin_lock(&port->lock); + uart_port_lock(port); ret = psc_ops->handle_irq(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return ret; } @@ -1633,7 +1598,7 @@ mpc52xx_console_setup(struct console *co, char *options) return ret; } - uartclk = mpc5xxx_get_bus_frequency(np); + uartclk = mpc5xxx_fwnode_get_bus_frequency(of_fwnode_handle(np)); if (uartclk == 0) { pr_debug("Could not find uart clock frequency!\n"); return -EINVAL; @@ -1655,7 +1620,7 @@ mpc52xx_console_setup(struct console *co, char *options) (void *)port->mapbase, port->membase, port->irq, port->uartclk); - /* Setup the port parameters accoding to options */ + /* Setup the port parameters according to options */ if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else @@ -1750,7 +1715,7 @@ static int mpc52xx_uart_of_probe(struct platform_device *op) /* set the uart clock to the input clock of the psc, the different * prescalers are taken into account in the set_baudrate() methods * of the respective chip */ - uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node); + uartclk = mpc5xxx_get_bus_frequency(&op->dev); if (uartclk == 0) { dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); return -EINVAL; @@ -1799,15 +1764,12 @@ static int mpc52xx_uart_of_probe(struct platform_device *op) return 0; } -static int -mpc52xx_uart_of_remove(struct platform_device *op) +static void mpc52xx_uart_of_remove(struct platform_device *op) { struct uart_port *port = platform_get_drvdata(op); if (port) uart_remove_one_port(&mpc52xx_uart_driver, port); - - return 0; } #ifdef CONFIG_PM diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index 587b42f754cb..2a4c09f3a834 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -16,7 +16,6 @@ #include <linux/console.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/of_device.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/serial_core.h> @@ -129,29 +128,11 @@ static void mps2_uart_stop_tx(struct uart_port *port) static void mps2_uart_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + u8 ch; - while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) { - if (port->x_char) { - mps2_uart_write8(port, port->x_char, UARTn_DATA); - port->x_char = 0; - port->icount.tx++; - continue; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - break; - - mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA); - xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - mps2_uart_stop_tx(port); + uart_port_tx(port, ch, + mps2_uart_tx_empty(port), + mps2_uart_write8(port, ch, UARTn_DATA)); } static void mps2_uart_start_tx(struct uart_port *port) @@ -207,12 +188,12 @@ static irqreturn_t mps2_uart_rxirq(int irq, void *data) if (unlikely(!(irqflag & UARTn_INT_RX))) return IRQ_NONE; - spin_lock(&port->lock); + uart_port_lock(port); mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT); mps2_uart_rx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -225,12 +206,12 @@ static irqreturn_t mps2_uart_txirq(int irq, void *data) if (unlikely(!(irqflag & UARTn_INT_TX))) return IRQ_NONE; - spin_lock(&port->lock); + uart_port_lock(port); mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT); mps2_uart_tx_chars(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -241,7 +222,7 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) struct uart_port *port = data; u8 irqflag = mps2_uart_read8(port, UARTn_INT); - spin_lock(&port->lock); + uart_port_lock(port); if (irqflag & UARTn_INT_RX_OVERRUN) { struct tty_port *tport = &port->state->port; @@ -263,7 +244,7 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) handled = IRQ_HANDLED; } - spin_unlock(&port->lock); + uart_port_unlock(port); return handled; } @@ -358,7 +339,7 @@ static void mps2_uart_shutdown(struct uart_port *port) static void mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, bauddiv; @@ -375,12 +356,12 @@ mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios, bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, termios->c_cflag, baud); mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -432,7 +413,7 @@ static const struct uart_ops mps2_uart_pops = { static DEFINE_IDR(ports_idr); #ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE -static void mps2_uart_console_putchar(struct uart_port *port, int ch) +static void mps2_uart_console_putchar(struct uart_port *port, unsigned char ch) { while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL) cpu_relax(); @@ -484,7 +465,7 @@ static struct console mps2_uart_console = { #define MPS2_SERIAL_CONSOLE (&mps2_uart_console) -static void mps2_early_putchar(struct uart_port *port, int ch) +static void mps2_early_putchar(struct uart_port *port, unsigned char ch) { while (readb(port->membase + UARTn_STATE) & UARTn_STATE_TX_FULL) cpu_relax(); @@ -557,8 +538,7 @@ static int mps2_init_port(struct platform_device *pdev, struct resource *res; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mps_port->port.membase = devm_ioremap_resource(&pdev->dev, res); + mps_port->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(mps_port->port.membase)) return PTR_ERR(mps_port->port.membase); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 60a9c53fa7cb..2e999cb9c974 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/atomic.h> +#include <linux/dma/qcom_adm.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/module.h> @@ -23,108 +24,109 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/pm_opp.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/wait.h> -#define UART_MR1 0x0000 - -#define UART_MR1_AUTO_RFR_LEVEL0 0x3F -#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 -#define UART_MR1_RX_RDY_CTL BIT(7) -#define UART_MR1_CTS_CTL BIT(6) - -#define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE BIT(6) -#define UART_MR2_BITS_PER_CHAR 0x30 -#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) -#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) -#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) -#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) -#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) -#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) -#define UART_MR2_PARITY_MODE_NONE 0x0 -#define UART_MR2_PARITY_MODE_ODD 0x1 -#define UART_MR2_PARITY_MODE_EVEN 0x2 -#define UART_MR2_PARITY_MODE_SPACE 0x3 -#define UART_MR2_PARITY_MODE 0x3 - -#define UART_CSR 0x0008 - -#define UART_TF 0x000C +#define MSM_UART_MR1 0x0000 + +#define MSM_UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define MSM_UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define MSM_UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define MSM_UART_MR1_RX_RDY_CTL BIT(7) +#define MSM_UART_MR1_CTS_CTL BIT(6) + +#define MSM_UART_MR2 0x0004 +#define MSM_UART_MR2_ERROR_MODE BIT(6) +#define MSM_UART_MR2_BITS_PER_CHAR 0x30 +#define MSM_UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define MSM_UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define MSM_UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define MSM_UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define MSM_UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define MSM_UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define MSM_UART_MR2_PARITY_MODE_NONE 0x0 +#define MSM_UART_MR2_PARITY_MODE_ODD 0x1 +#define MSM_UART_MR2_PARITY_MODE_EVEN 0x2 +#define MSM_UART_MR2_PARITY_MODE_SPACE 0x3 +#define MSM_UART_MR2_PARITY_MODE 0x3 + +#define MSM_UART_CSR 0x0008 + +#define MSM_UART_TF 0x000C #define UARTDM_TF 0x0070 -#define UART_CR 0x0010 -#define UART_CR_CMD_NULL (0 << 4) -#define UART_CR_CMD_RESET_RX (1 << 4) -#define UART_CR_CMD_RESET_TX (2 << 4) -#define UART_CR_CMD_RESET_ERR (3 << 4) -#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) -#define UART_CR_CMD_START_BREAK (5 << 4) -#define UART_CR_CMD_STOP_BREAK (6 << 4) -#define UART_CR_CMD_RESET_CTS (7 << 4) -#define UART_CR_CMD_RESET_STALE_INT (8 << 4) -#define UART_CR_CMD_PACKET_MODE (9 << 4) -#define UART_CR_CMD_MODE_RESET (12 << 4) -#define UART_CR_CMD_SET_RFR (13 << 4) -#define UART_CR_CMD_RESET_RFR (14 << 4) -#define UART_CR_CMD_PROTECTION_EN (16 << 4) -#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) -#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) -#define UART_CR_CMD_FORCE_STALE (4 << 8) -#define UART_CR_CMD_RESET_TX_READY (3 << 8) -#define UART_CR_TX_DISABLE BIT(3) -#define UART_CR_TX_ENABLE BIT(2) -#define UART_CR_RX_DISABLE BIT(1) -#define UART_CR_RX_ENABLE BIT(0) -#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) - -#define UART_IMR 0x0014 -#define UART_IMR_TXLEV BIT(0) -#define UART_IMR_RXSTALE BIT(3) -#define UART_IMR_RXLEV BIT(4) -#define UART_IMR_DELTA_CTS BIT(5) -#define UART_IMR_CURRENT_CTS BIT(6) -#define UART_IMR_RXBREAK_START BIT(10) - -#define UART_IPR_RXSTALE_LAST 0x20 -#define UART_IPR_STALE_LSB 0x1F -#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 -#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 - -#define UART_IPR 0x0018 -#define UART_TFWR 0x001C -#define UART_RFWR 0x0020 -#define UART_HCR 0x0024 - -#define UART_MREG 0x0028 -#define UART_NREG 0x002C -#define UART_DREG 0x0030 -#define UART_MNDREG 0x0034 -#define UART_IRDA 0x0038 -#define UART_MISR_MODE 0x0040 -#define UART_MISR_RESET 0x0044 -#define UART_MISR_EXPORT 0x0048 -#define UART_MISR_VAL 0x004C -#define UART_TEST_CTRL 0x0050 - -#define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR BIT(7) -#define UART_SR_RX_BREAK BIT(6) -#define UART_SR_PAR_FRAME_ERR BIT(5) -#define UART_SR_OVERRUN BIT(4) -#define UART_SR_TX_EMPTY BIT(3) -#define UART_SR_TX_READY BIT(2) -#define UART_SR_RX_FULL BIT(1) -#define UART_SR_RX_READY BIT(0) - -#define UART_RF 0x000C +#define MSM_UART_CR 0x0010 +#define MSM_UART_CR_CMD_NULL (0 << 4) +#define MSM_UART_CR_CMD_RESET_RX (1 << 4) +#define MSM_UART_CR_CMD_RESET_TX (2 << 4) +#define MSM_UART_CR_CMD_RESET_ERR (3 << 4) +#define MSM_UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define MSM_UART_CR_CMD_START_BREAK (5 << 4) +#define MSM_UART_CR_CMD_STOP_BREAK (6 << 4) +#define MSM_UART_CR_CMD_RESET_CTS (7 << 4) +#define MSM_UART_CR_CMD_RESET_STALE_INT (8 << 4) +#define MSM_UART_CR_CMD_PACKET_MODE (9 << 4) +#define MSM_UART_CR_CMD_MODE_RESET (12 << 4) +#define MSM_UART_CR_CMD_SET_RFR (13 << 4) +#define MSM_UART_CR_CMD_RESET_RFR (14 << 4) +#define MSM_UART_CR_CMD_PROTECTION_EN (16 << 4) +#define MSM_UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) +#define MSM_UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define MSM_UART_CR_CMD_FORCE_STALE (4 << 8) +#define MSM_UART_CR_CMD_RESET_TX_READY (3 << 8) +#define MSM_UART_CR_TX_DISABLE BIT(3) +#define MSM_UART_CR_TX_ENABLE BIT(2) +#define MSM_UART_CR_RX_DISABLE BIT(1) +#define MSM_UART_CR_RX_ENABLE BIT(0) +#define MSM_UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) + +#define MSM_UART_IMR 0x0014 +#define MSM_UART_IMR_TXLEV BIT(0) +#define MSM_UART_IMR_RXSTALE BIT(3) +#define MSM_UART_IMR_RXLEV BIT(4) +#define MSM_UART_IMR_DELTA_CTS BIT(5) +#define MSM_UART_IMR_CURRENT_CTS BIT(6) +#define MSM_UART_IMR_RXBREAK_START BIT(10) + +#define MSM_UART_IPR_RXSTALE_LAST 0x20 +#define MSM_UART_IPR_STALE_LSB 0x1F +#define MSM_UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define MSM_UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 + +#define MSM_UART_IPR 0x0018 +#define MSM_UART_TFWR 0x001C +#define MSM_UART_RFWR 0x0020 +#define MSM_UART_HCR 0x0024 + +#define MSM_UART_MREG 0x0028 +#define MSM_UART_NREG 0x002C +#define MSM_UART_DREG 0x0030 +#define MSM_UART_MNDREG 0x0034 +#define MSM_UART_IRDA 0x0038 +#define MSM_UART_MISR_MODE 0x0040 +#define MSM_UART_MISR_RESET 0x0044 +#define MSM_UART_MISR_EXPORT 0x0048 +#define MSM_UART_MISR_VAL 0x004C +#define MSM_UART_TEST_CTRL 0x0050 + +#define MSM_UART_SR 0x0008 +#define MSM_UART_SR_HUNT_CHAR BIT(7) +#define MSM_UART_SR_RX_BREAK BIT(6) +#define MSM_UART_SR_PAR_FRAME_ERR BIT(5) +#define MSM_UART_SR_OVERRUN BIT(4) +#define MSM_UART_SR_TX_EMPTY BIT(3) +#define MSM_UART_SR_TX_READY BIT(2) +#define MSM_UART_SR_RX_FULL BIT(1) +#define MSM_UART_SR_RX_READY BIT(0) + +#define MSM_UART_RF 0x000C #define UARTDM_RF 0x0070 -#define UART_MISR 0x0010 -#define UART_ISR 0x0014 -#define UART_ISR_TX_READY BIT(7) +#define MSM_UART_MISR 0x0010 +#define MSM_UART_ISR 0x0014 +#define MSM_UART_ISR_TX_READY BIT(7) #define UARTDM_RXFS 0x50 #define UARTDM_RXFS_BUF_SHIFT 0x7 @@ -159,11 +161,16 @@ enum { struct msm_dma { struct dma_chan *chan; enum dma_data_direction dir; - dma_addr_t phys; - unsigned char *virt; + union { + struct { + dma_addr_t phys; + unsigned char *virt; + unsigned int count; + } rx; + struct scatterlist tx_sg; + }; dma_cookie_t cookie; u32 enable_bit; - unsigned int count; struct dma_async_tx_descriptor *desc; }; @@ -180,7 +187,10 @@ struct msm_port { struct msm_dma rx_dma; }; -#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) +static inline struct msm_port *to_msm_port(struct uart_port *up) +{ + return container_of(up, struct msm_port, uart); +} static void msm_write(struct uart_port *port, unsigned int val, unsigned int off) @@ -199,10 +209,10 @@ unsigned int msm_read(struct uart_port *port, unsigned int off) */ static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) { - msm_write(port, 0x06, UART_MREG); - msm_write(port, 0xF1, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x1A, UART_MNDREG); + msm_write(port, 0x06, MSM_UART_MREG); + msm_write(port, 0xF1, MSM_UART_NREG); + msm_write(port, 0x0F, MSM_UART_DREG); + msm_write(port, 0x1A, MSM_UART_MNDREG); port->uartclk = 1843200; } @@ -211,16 +221,16 @@ static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) */ static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) { - msm_write(port, 0x18, UART_MREG); - msm_write(port, 0xF6, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x0A, UART_MNDREG); + msm_write(port, 0x18, MSM_UART_MREG); + msm_write(port, 0xF6, MSM_UART_NREG); + msm_write(port, 0x0F, MSM_UART_DREG); + msm_write(port, 0x0A, MSM_UART_MNDREG); port->uartclk = 1843200; } static void msm_serial_set_mnd_regs(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); /* * These registers don't exist so we change the clk input rate @@ -244,8 +254,12 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) unsigned int mapped; u32 val; - mapped = dma->count; - dma->count = 0; + if (dma->dir == DMA_TO_DEVICE) { + mapped = sg_dma_len(&dma->tx_sg); + } else { + mapped = dma->rx.count; + dma->rx.count = 0; + } dmaengine_terminate_all(dma->chan); @@ -260,8 +274,13 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - if (mapped) - dma_unmap_single(dev, dma->phys, mapped, dma->dir); + if (mapped) { + if (dma->dir == DMA_TO_DEVICE) { + dma_unmap_sg(dev, &dma->tx_sg, 1, dma->dir); + sg_init_table(&dma->tx_sg, 1); + } else + dma_unmap_single(dev, dma->rx.phys, mapped, dma->dir); + } } static void msm_release_dma(struct msm_port *msm_port) @@ -280,7 +299,7 @@ static void msm_release_dma(struct msm_port *msm_port) if (dma->chan) { msm_stop_dma(&msm_port->uart, dma); dma_release_channel(dma->chan); - kfree(dma->virt); + kfree(dma->rx.virt); } memset(dma, 0, sizeof(*dma)); @@ -290,6 +309,7 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) { struct device *dev = msm_port->uart.dev; struct dma_slave_config conf; + struct qcom_adm_peripheral_config periph_conf = {}; struct msm_dma *dma; u32 crci = 0; int ret; @@ -308,7 +328,11 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) conf.device_fc = true; conf.dst_addr = base + UARTDM_TF; conf.dst_maxburst = UARTDM_BURST_SIZE; - conf.slave_id = crci; + if (crci) { + conf.peripheral_config = &periph_conf; + conf.peripheral_size = sizeof(periph_conf); + periph_conf.crci = crci; + } ret = dmaengine_slave_config(dma->chan, &conf); if (ret) @@ -333,6 +357,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) { struct device *dev = msm_port->uart.dev; struct dma_slave_config conf; + struct qcom_adm_peripheral_config periph_conf = {}; struct msm_dma *dma; u32 crci = 0; int ret; @@ -346,8 +371,8 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci); - dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL); - if (!dma->virt) + dma->rx.virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL); + if (!dma->rx.virt) goto rel_rx; memset(&conf, 0, sizeof(conf)); @@ -355,7 +380,11 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) conf.device_fc = true; conf.src_addr = base + UARTDM_RF; conf.src_maxburst = UARTDM_BURST_SIZE; - conf.slave_id = crci; + if (crci) { + conf.peripheral_config = &periph_conf; + conf.peripheral_size = sizeof(periph_conf); + periph_conf.crci = crci; + } ret = dmaengine_slave_config(dma->chan, &conf); if (ret) @@ -370,7 +399,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) return; err: - kfree(dma->virt); + kfree(dma->rx.virt); rel_rx: dma_release_channel(dma->chan); no_rx: @@ -381,35 +410,35 @@ static inline void msm_wait_for_xmitr(struct uart_port *port) { unsigned int timeout = 500000; - while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) { - if (msm_read(port, UART_ISR) & UART_ISR_TX_READY) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_EMPTY)) { + if (msm_read(port, MSM_UART_ISR) & MSM_UART_ISR_TX_READY) break; udelay(1); if (!timeout--) break; } - msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_TX_READY, MSM_UART_CR); } static void msm_stop_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); } static void msm_start_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->tx_dma; /* Already started in DMA mode */ - if (dma->count) + if (sg_dma_len(&dma->tx_sg)) return; - msm_port->imr |= UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); } static void msm_reset_dm_count(struct uart_port *port, int count) @@ -423,70 +452,68 @@ static void msm_complete_tx_dma(void *args) { struct msm_port *msm_port = args; struct uart_port *port = &msm_port->uart; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; struct dma_tx_state state; - enum dma_status status; unsigned long flags; unsigned int count; u32 val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Already stopped */ - if (!dma->count) + if (!sg_dma_len(&dma->tx_sg)) goto done; - status = dmaengine_tx_status(dma->chan, dma->cookie, &state); + dmaengine_tx_status(dma->chan, dma->cookie, &state); - dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir); + dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir); val = msm_read(port, UARTDM_DMEN); val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); if (msm_port->is_uartdm > UARTDM_1P3) { - msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); - msm_write(port, UART_CR_TX_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); + msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); } - count = dma->count - state.residue; - port->icount.tx += count; - dma->count = 0; - - xmit->tail += count; - xmit->tail &= UART_XMIT_SIZE - 1; + count = sg_dma_len(&dma->tx_sg) - state.residue; + uart_xmit_advance(port, count); + sg_init_table(&dma->tx_sg, 1); /* Restore "Tx FIFO below watermark" interrupt */ - msm_port->imr |= UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); msm_handle_tx(port); done: - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) { - struct circ_buf *xmit = &msm_port->uart.state->xmit; struct uart_port *port = &msm_port->uart; + struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; - void *cpu_addr; + unsigned int mapped; int ret; u32 val; - cpu_addr = &xmit->buf[xmit->tail]; + sg_init_table(&dma->tx_sg, 1); + kfifo_dma_out_prepare(&tport->xmit_fifo, &dma->tx_sg, 1, count); - dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir); - ret = dma_mapping_error(port->dev, dma->phys); - if (ret) - return ret; + mapped = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir); + if (!mapped) { + ret = -EIO; + goto zero_sg; + } - dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys, - count, DMA_MEM_TO_DEV, + dma->desc = dmaengine_prep_slave_sg(dma->chan, &dma->tx_sg, 1, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_PREP_FENCE); if (!dma->desc) { @@ -506,10 +533,8 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) * Using DMA complete for Tx FIFO reload, no need for * "Tx FIFO below watermark" one, disable it */ - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); - - dma->count = count; + msm_port->imr &= ~MSM_UART_IMR_TXLEV; + msm_write(port, msm_port->imr, MSM_UART_IMR); val = msm_read(port, UARTDM_DMEN); val |= dma->enable_bit; @@ -525,7 +550,9 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) dma_async_issue_pending(dma->chan); return 0; unmap: - dma_unmap_single(port->dev, dma->phys, count, dma->dir); + dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir); +zero_sg: + sg_init_table(&dma->tx_sg, 1); return ret; } @@ -539,34 +566,34 @@ static void msm_complete_rx_dma(void *args) unsigned long flags; u32 val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Already stopped */ - if (!dma->count) + if (!dma->rx.count) goto done; val = msm_read(port, UARTDM_DMEN); val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { + if (msm_read(port, MSM_UART_SR) & MSM_UART_SR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); } count = msm_read(port, UARTDM_RX_TOTAL_SNAP); port->icount.rx += count; - dma->count = 0; + dma->rx.count = 0; - dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir); + dma_unmap_single(port->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir); for (i = 0; i < count; i++) { char flag = TTY_NORMAL; - if (msm_port->break_detected && dma->virt[i] == 0) { + if (msm_port->break_detected && dma->rx.virt[i] == 0) { port->icount.brk++; flag = TTY_BREAK; msm_port->break_detected = false; @@ -574,19 +601,17 @@ static void msm_complete_rx_dma(void *args) continue; } - if (!(port->read_status_mask & UART_SR_RX_BREAK)) + if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; - spin_unlock_irqrestore(&port->lock, flags); - sysrq = uart_handle_sysrq_char(port, dma->virt[i]); - spin_lock_irqsave(&port->lock, flags); + sysrq = uart_prepare_sysrq_char(port, dma->rx.virt[i]); if (!sysrq) - tty_insert_flip_char(tport, dma->virt[i], flag); + tty_insert_flip_char(tport, dma->rx.virt[i], flag); } msm_start_rx_dma(msm_port); done: - spin_unlock_irqrestore(&port->lock, flags); + uart_unlock_and_check_sysrq_irqrestore(port, flags); if (count) tty_flip_buffer_push(tport); @@ -599,16 +624,19 @@ static void msm_start_rx_dma(struct msm_port *msm_port) u32 val; int ret; + if (IS_ENABLED(CONFIG_CONSOLE_POLL)) + return; + if (!dma->chan) return; - dma->phys = dma_map_single(uart->dev, dma->virt, + dma->rx.phys = dma_map_single(uart->dev, dma->rx.virt, UARTDM_RX_SIZE, dma->dir); - ret = dma_mapping_error(uart->dev, dma->phys); + ret = dma_mapping_error(uart->dev, dma->rx.phys); if (ret) goto sw_mode; - dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys, + dma->desc = dmaengine_prep_slave_single(dma->chan, dma->rx.phys, UARTDM_RX_SIZE, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!dma->desc) @@ -625,23 +653,23 @@ static void msm_start_rx_dma(struct msm_port *msm_port) * Using DMA for FIFO off-load, no need for "Rx FIFO over * watermark" or "stale" interrupts, disable them */ - msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); + msm_port->imr &= ~(MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE); /* * Well, when DMA is ADM3 engine(implied by <= UARTDM v1.3), * we need RXSTALE to flush input DMA fifo to memory */ if (msm_port->is_uartdm < UARTDM_1P4) - msm_port->imr |= UART_IMR_RXSTALE; + msm_port->imr |= MSM_UART_IMR_RXSTALE; - msm_write(uart, msm_port->imr, UART_IMR); + msm_write(uart, msm_port->imr, MSM_UART_IMR); - dma->count = UARTDM_RX_SIZE; + dma->rx.count = UARTDM_RX_SIZE; dma_async_issue_pending(dma->chan); - msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR); - msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); + msm_write(uart, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); val = msm_read(uart, UARTDM_DMEN); val |= dma->enable_bit; @@ -656,32 +684,32 @@ static void msm_start_rx_dma(struct msm_port *msm_port) return; unmap: - dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir); + dma_unmap_single(uart->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir); sw_mode: /* * Switch from DMA to SW/FIFO mode. After clearing Rx BAM (UARTDM_DMEN), * receiver must be reset. */ - msm_write(uart, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(uart, UART_CR_RX_ENABLE, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); + msm_write(uart, MSM_UART_CR_RX_ENABLE, MSM_UART_CR); - msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(uart, 0xFFFFFF, UARTDM_DMRX); - msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(uart, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); /* Re-enable RX interrupts */ - msm_port->imr |= (UART_IMR_RXLEV | UART_IMR_RXSTALE); - msm_write(uart, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE; + msm_write(uart, msm_port->imr, MSM_UART_IMR); } static void msm_stop_rx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; - msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~(MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE); + msm_write(port, msm_port->imr, MSM_UART_IMR); if (dma->chan) msm_stop_dma(port, dma); @@ -689,31 +717,32 @@ static void msm_stop_rx(struct uart_port *port) static void msm_enable_ms(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); - msm_port->imr |= UART_IMR_DELTA_CTS; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= MSM_UART_IMR_DELTA_CTS; + msm_write(port, msm_port->imr, MSM_UART_IMR); } static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) + __must_hold(&port->lock) { struct tty_port *tport = &port->state->port; unsigned int sr; int count = 0; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { + if ((msm_read(port, MSM_UART_SR) & MSM_UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); } - if (misr & UART_IMR_RXSTALE) { + if (misr & MSM_UART_IMR_RXSTALE) { count = msm_read(port, UARTDM_RX_TOTAL_SNAP) - msm_port->old_snap_state; msm_port->old_snap_state = 0; } else { - count = 4 * (msm_read(port, UART_RFWR)); + count = 4 * (msm_read(port, MSM_UART_RFWR)); msm_port->old_snap_state += count; } @@ -725,8 +754,8 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) unsigned char buf[4]; int sysrq, r_count, i; - sr = msm_read(port, UART_SR); - if ((sr & UART_SR_RX_READY) == 0) { + sr = msm_read(port, MSM_UART_SR); + if ((sr & MSM_UART_SR_RX_READY) == 0) { msm_port->old_snap_state -= count; break; } @@ -745,32 +774,29 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) continue; } - if (!(port->read_status_mask & UART_SR_RX_BREAK)) + if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; - spin_unlock(&port->lock); - sysrq = uart_handle_sysrq_char(port, buf[i]); - spin_lock(&port->lock); + sysrq = uart_prepare_sysrq_char(port, buf[i]); if (!sysrq) tty_insert_flip_char(tport, buf[i], flag); } count -= r_count; } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); - if (misr & (UART_IMR_RXSTALE)) - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + if (misr & (MSM_UART_IMR_RXSTALE)) + msm_write(port, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); /* Try to use DMA */ msm_start_rx_dma(msm_port); } static void msm_handle_rx(struct uart_port *port) + __must_hold(&port->lock) { struct tty_port *tport = &port->state->port; unsigned int sr; @@ -779,54 +805,50 @@ static void msm_handle_rx(struct uart_port *port) * Handle overrun. My understanding of the hardware is that overrun * is not tied to the RX buffer, so we handle the case out of band. */ - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { + if ((msm_read(port, MSM_UART_SR) & MSM_UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); } /* and now the main RX loop */ - while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { + while ((sr = msm_read(port, MSM_UART_SR)) & MSM_UART_SR_RX_READY) { unsigned int c; char flag = TTY_NORMAL; int sysrq; - c = msm_read(port, UART_RF); + c = msm_read(port, MSM_UART_RF); - if (sr & UART_SR_RX_BREAK) { + if (sr & MSM_UART_SR_RX_BREAK) { port->icount.brk++; if (uart_handle_break(port)) continue; - } else if (sr & UART_SR_PAR_FRAME_ERR) { + } else if (sr & MSM_UART_SR_PAR_FRAME_ERR) { port->icount.frame++; } else { port->icount.rx++; } - /* Mask conditions we're ignorning. */ + /* Mask conditions we're ignoring. */ sr &= port->read_status_mask; - if (sr & UART_SR_RX_BREAK) + if (sr & MSM_UART_SR_RX_BREAK) flag = TTY_BREAK; - else if (sr & UART_SR_PAR_FRAME_ERR) + else if (sr & MSM_UART_SR_PAR_FRAME_ERR) flag = TTY_FRAME; - spin_unlock(&port->lock); - sysrq = uart_handle_sysrq_char(port, c); - spin_lock(&port->lock); + sysrq = uart_prepare_sysrq_char(port, c); if (!sysrq) tty_insert_flip_char(tport, c, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) { - struct circ_buf *xmit = &port->state->xmit; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); + struct tty_port *tport = &port->state->port; unsigned int num_chars; unsigned int tf_pointer = 0; void __iomem *tf; @@ -834,16 +856,15 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) if (msm_port->is_uartdm) tf = port->membase + UARTDM_TF; else - tf = port->membase + UART_TF; + tf = port->membase + MSM_UART_TF; if (tx_count && msm_port->is_uartdm) msm_reset_dm_count(port, tx_count); while (tf_pointer < tx_count) { - int i; - char buf[4] = { 0 }; + unsigned char buf[4] = { 0 }; - if (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) break; if (msm_port->is_uartdm) @@ -852,28 +873,23 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) else num_chars = 1; - for (i = 0; i < num_chars; i++) { - buf[i] = xmit->buf[xmit->tail + i]; - port->icount.tx++; - } - + num_chars = uart_fifo_out(port, buf, num_chars); iowrite32_rep(tf, buf, 1); - xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1); tf_pointer += num_chars; } /* disable tx interrupts if nothing more to send */ - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) msm_stop_tx(port); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } static void msm_handle_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); - struct circ_buf *xmit = &msm_port->uart.state->xmit; + struct msm_port *msm_port = to_msm_port(port); + struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; unsigned int pio_count, dma_count, dma_min; char buf[4] = { 0 }; @@ -884,7 +900,7 @@ static void msm_handle_tx(struct uart_port *port) if (msm_port->is_uartdm) tf = port->membase + UARTDM_TF; else - tf = port->membase + UART_TF; + tf = port->membase + MSM_UART_TF; buf[0] = port->x_char; @@ -897,13 +913,13 @@ static void msm_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { msm_stop_tx(port); return; } - pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + dma_count = pio_count = kfifo_out_linear(&tport->xmit_fifo, NULL, + UART_XMIT_SIZE); dma_min = 1; /* Always DMA */ if (msm_port->is_uartdm > UARTDM_1P3) { @@ -928,7 +944,7 @@ static void msm_handle_tx(struct uart_port *port) static void msm_handle_delta_cts(struct uart_port *port) { - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_CTS, MSM_UART_CR); port->icount.cts++; wake_up_interruptible(&port->state->port.delta_msr_wait); } @@ -936,27 +952,26 @@ static void msm_handle_delta_cts(struct uart_port *port) static irqreturn_t msm_uart_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; - unsigned long flags; unsigned int misr; u32 val; - spin_lock_irqsave(&port->lock, flags); - misr = msm_read(port, UART_MISR); - msm_write(port, 0, UART_IMR); /* disable interrupt */ + uart_port_lock(port); + misr = msm_read(port, MSM_UART_MISR); + msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */ - if (misr & UART_IMR_RXBREAK_START) { + if (misr & MSM_UART_IMR_RXBREAK_START) { msm_port->break_detected = true; - msm_write(port, UART_CR_CMD_RESET_RXBREAK_START, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_RXBREAK_START, MSM_UART_CR); } - if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { - if (dma->count) { - val = UART_CR_CMD_STALE_EVENT_DISABLE; - msm_write(port, val, UART_CR); - val = UART_CR_CMD_RESET_STALE_INT; - msm_write(port, val, UART_CR); + if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) { + if (dma->rx.count) { + val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE; + msm_write(port, val, MSM_UART_CR); + val = MSM_UART_CR_CMD_RESET_STALE_INT; + msm_write(port, val, MSM_UART_CR); /* * Flush DMA input fifo to memory, this will also * trigger DMA RX completion @@ -968,20 +983,20 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) msm_handle_rx(port); } } - if (misr & UART_IMR_TXLEV) + if (misr & MSM_UART_IMR_TXLEV) msm_handle_tx(port); - if (misr & UART_IMR_DELTA_CTS) + if (misr & MSM_UART_IMR_DELTA_CTS) msm_handle_delta_cts(port); - msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ - spin_unlock_irqrestore(&port->lock, flags); + msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */ + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } static unsigned int msm_tx_empty(struct uart_port *port) { - return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; + return (msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; } static unsigned int msm_get_mctrl(struct uart_port *port) @@ -991,19 +1006,19 @@ static unsigned int msm_get_mctrl(struct uart_port *port) static void msm_reset(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int mr; /* reset everything */ - msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); - mr = msm_read(port, UART_MR1); - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); + msm_write(port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_ERR, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_BREAK_INT, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_CTS, MSM_UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_RFR, MSM_UART_CR); + mr = msm_read(port, MSM_UART_MR1); + mr &= ~MSM_UART_MR1_RX_RDY_CTL; + msm_write(port, mr, MSM_UART_MR1); /* Disable DM modes */ if (msm_port->is_uartdm) @@ -1014,24 +1029,24 @@ static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; - mr = msm_read(port, UART_MR1); + mr = msm_read(port, MSM_UART_MR1); if (!(mctrl & TIOCM_RTS)) { - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); + mr &= ~MSM_UART_MR1_RX_RDY_CTL; + msm_write(port, mr, MSM_UART_MR1); + msm_write(port, MSM_UART_CR_CMD_RESET_RFR, MSM_UART_CR); } else { - mr |= UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); + mr |= MSM_UART_MR1_RX_RDY_CTL; + msm_write(port, mr, MSM_UART_MR1); } } static void msm_break_ctl(struct uart_port *port, int break_ctl) { if (break_ctl) - msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); + msm_write(port, MSM_UART_CR_CMD_START_BREAK, MSM_UART_CR); else - msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); + msm_write(port, MSM_UART_CR_CMD_STOP_BREAK, MSM_UART_CR); } struct msm_baud_map { @@ -1044,7 +1059,7 @@ static const struct msm_baud_map * msm_find_best_baud(struct uart_port *port, unsigned int baud, unsigned long *rate) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int divisor, result; unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX; const struct msm_baud_map *entry, *end, *best; @@ -1087,7 +1102,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud, if (result == baud) break; - } else if (entry->divisor > divisor) { + } else { old = target; target = clk_round_rate(msm_port->clk, old + 1); /* @@ -1111,62 +1126,63 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud, static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, unsigned long *saved_flags) + __must_hold(&port->lock) { unsigned int rxstale, watermark, mask; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); const struct msm_baud_map *entry; unsigned long flags, rate; flags = *saved_flags; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); entry = msm_find_best_baud(port, baud, &rate); - clk_set_rate(msm_port->clk, rate); + dev_pm_opp_set_rate(port->dev, rate); baud = rate / 16 / entry->divisor; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); *saved_flags = flags; port->uartclk = rate; - msm_write(port, entry->code, UART_CSR); + msm_write(port, entry->code, MSM_UART_CSR); /* RX stale watermark */ rxstale = entry->rxstale; - watermark = UART_IPR_STALE_LSB & rxstale; + watermark = MSM_UART_IPR_STALE_LSB & rxstale; if (msm_port->is_uartdm) { - mask = UART_DM_IPR_STALE_TIMEOUT_MSB; + mask = MSM_UART_DM_IPR_STALE_TIMEOUT_MSB; } else { - watermark |= UART_IPR_RXSTALE_LAST; - mask = UART_IPR_STALE_TIMEOUT_MSB; + watermark |= MSM_UART_IPR_RXSTALE_LAST; + mask = MSM_UART_IPR_STALE_TIMEOUT_MSB; } watermark |= mask & (rxstale << 2); - msm_write(port, watermark, UART_IPR); + msm_write(port, watermark, MSM_UART_IPR); /* set RX watermark */ watermark = (port->fifosize * 3) / 4; - msm_write(port, watermark, UART_RFWR); + msm_write(port, watermark, MSM_UART_RFWR); /* set TX watermark */ - msm_write(port, 10, UART_TFWR); + msm_write(port, 10, MSM_UART_TFWR); - msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_write(port, MSM_UART_CR_CMD_PROTECTION_EN, MSM_UART_CR); msm_reset(port); /* Enable RX and TX */ - msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_TX_ENABLE | MSM_UART_CR_RX_ENABLE, MSM_UART_CR); /* turn on RX and CTS interrupts */ - msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | - UART_IMR_CURRENT_CTS | UART_IMR_RXBREAK_START; + msm_port->imr = MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE | + MSM_UART_IMR_CURRENT_CTS | MSM_UART_IMR_RXBREAK_START; - msm_write(port, msm_port->imr, UART_IMR); + msm_write(port, msm_port->imr, MSM_UART_IMR); if (msm_port->is_uartdm) { - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); } return baud; @@ -1174,8 +1190,9 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, static void msm_init_clock(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); + dev_pm_opp_set_rate(port->dev, port->uartclk); clk_prepare_enable(msm_port->clk); clk_prepare_enable(msm_port->pclk); msm_serial_set_mnd_regs(port); @@ -1183,7 +1200,7 @@ static void msm_init_clock(struct uart_port *port) static int msm_startup(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); unsigned int data, rfr_level, mask; int ret; @@ -1198,18 +1215,18 @@ static int msm_startup(struct uart_port *port) rfr_level = port->fifosize; /* set automatic RFR level */ - data = msm_read(port, UART_MR1); + data = msm_read(port, MSM_UART_MR1); if (msm_port->is_uartdm) - mask = UART_DM_MR1_AUTO_RFR_LEVEL1; + mask = MSM_UART_DM_MR1_AUTO_RFR_LEVEL1; else - mask = UART_MR1_AUTO_RFR_LEVEL1; + mask = MSM_UART_MR1_AUTO_RFR_LEVEL1; data &= ~mask; - data &= ~UART_MR1_AUTO_RFR_LEVEL0; + data &= ~MSM_UART_MR1_AUTO_RFR_LEVEL0; data |= mask & (rfr_level << 2); - data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; - msm_write(port, data, UART_MR1); + data |= MSM_UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; + msm_write(port, data, MSM_UART_MR1); if (msm_port->is_uartdm) { msm_request_tx_dma(msm_port, msm_port->uart.mapbase); @@ -1229,34 +1246,36 @@ err_irq: clk_disable_unprepare(msm_port->pclk); clk_disable_unprepare(msm_port->clk); + dev_pm_opp_set_rate(port->dev, 0); return ret; } static void msm_shutdown(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); msm_port->imr = 0; - msm_write(port, 0, UART_IMR); /* disable interrupts */ + msm_write(port, 0, MSM_UART_IMR); /* disable interrupts */ if (msm_port->is_uartdm) msm_release_dma(msm_port); clk_disable_unprepare(msm_port->clk); + dev_pm_opp_set_rate(port->dev, 0); free_irq(port->irq, port); } static void msm_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; unsigned long flags; unsigned int baud, mr; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (dma->chan) /* Terminate if any */ msm_stop_dma(port, dma); @@ -1268,67 +1287,67 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, tty_termios_encode_baud_rate(termios, baud, baud); /* calculate parity */ - mr = msm_read(port, UART_MR2); - mr &= ~UART_MR2_PARITY_MODE; + mr = msm_read(port, MSM_UART_MR2); + mr &= ~MSM_UART_MR2_PARITY_MODE; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) - mr |= UART_MR2_PARITY_MODE_ODD; + mr |= MSM_UART_MR2_PARITY_MODE_ODD; else if (termios->c_cflag & CMSPAR) - mr |= UART_MR2_PARITY_MODE_SPACE; + mr |= MSM_UART_MR2_PARITY_MODE_SPACE; else - mr |= UART_MR2_PARITY_MODE_EVEN; + mr |= MSM_UART_MR2_PARITY_MODE_EVEN; } /* calculate bits per char */ - mr &= ~UART_MR2_BITS_PER_CHAR; + mr &= ~MSM_UART_MR2_BITS_PER_CHAR; switch (termios->c_cflag & CSIZE) { case CS5: - mr |= UART_MR2_BITS_PER_CHAR_5; + mr |= MSM_UART_MR2_BITS_PER_CHAR_5; break; case CS6: - mr |= UART_MR2_BITS_PER_CHAR_6; + mr |= MSM_UART_MR2_BITS_PER_CHAR_6; break; case CS7: - mr |= UART_MR2_BITS_PER_CHAR_7; + mr |= MSM_UART_MR2_BITS_PER_CHAR_7; break; case CS8: default: - mr |= UART_MR2_BITS_PER_CHAR_8; + mr |= MSM_UART_MR2_BITS_PER_CHAR_8; break; } /* calculate stop bits */ - mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); + mr &= ~(MSM_UART_MR2_STOP_BIT_LEN_ONE | MSM_UART_MR2_STOP_BIT_LEN_TWO); if (termios->c_cflag & CSTOPB) - mr |= UART_MR2_STOP_BIT_LEN_TWO; + mr |= MSM_UART_MR2_STOP_BIT_LEN_TWO; else - mr |= UART_MR2_STOP_BIT_LEN_ONE; + mr |= MSM_UART_MR2_STOP_BIT_LEN_ONE; /* set parity, bits per char, and stop bit */ - msm_write(port, mr, UART_MR2); + msm_write(port, mr, MSM_UART_MR2); /* calculate and set hardware flow control */ - mr = msm_read(port, UART_MR1); - mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); + mr = msm_read(port, MSM_UART_MR1); + mr &= ~(MSM_UART_MR1_CTS_CTL | MSM_UART_MR1_RX_RDY_CTL); if (termios->c_cflag & CRTSCTS) { - mr |= UART_MR1_CTS_CTL; - mr |= UART_MR1_RX_RDY_CTL; + mr |= MSM_UART_MR1_CTS_CTL; + mr |= MSM_UART_MR1_RX_RDY_CTL; } - msm_write(port, mr, UART_MR1); + msm_write(port, mr, MSM_UART_MR1); /* Configure status bits to ignore based on termio flags. */ port->read_status_mask = 0; if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_SR_PAR_FRAME_ERR; + port->read_status_mask |= MSM_UART_SR_PAR_FRAME_ERR; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART_SR_RX_BREAK; + port->read_status_mask |= MSM_UART_SR_RX_BREAK; uart_update_timeout(port, termios->c_cflag, baud); /* Try to use DMA */ msm_start_rx_dma(msm_port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *msm_type(struct uart_port *port) @@ -1405,15 +1424,17 @@ static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) static void msm_power(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); switch (state) { case 0: + dev_pm_opp_set_rate(port->dev, port->uartclk); clk_prepare_enable(msm_port->clk); clk_prepare_enable(msm_port->pclk); break; case 3: clk_disable_unprepare(msm_port->clk); + dev_pm_opp_set_rate(port->dev, 0); clk_disable_unprepare(msm_port->pclk); break; default: @@ -1424,10 +1445,10 @@ static void msm_power(struct uart_port *port, unsigned int state, #ifdef CONFIG_CONSOLE_POLL static int msm_poll_get_char_single(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); - unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; + struct msm_port *msm_port = to_msm_port(port); + unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : MSM_UART_RF; - if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) + if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_RX_READY)) return NO_POLL_CHAR; return msm_read(port, rf_reg) & 0xff; @@ -1445,7 +1466,7 @@ static int msm_poll_get_char_dm(struct uart_port *port) c = sp[sizeof(slop) - count]; count--; /* Or if FIFO is empty */ - } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { + } else if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_RX_READY)) { /* * If RX packing buffer has less than a word, force stale to * push contents into RX FIFO @@ -1453,14 +1474,13 @@ static int msm_poll_get_char_dm(struct uart_port *port) count = msm_read(port, UARTDM_RXFS); count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; if (count) { - msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + msm_write(port, MSM_UART_CR_CMD_FORCE_STALE, MSM_UART_CR); slop = msm_read(port, UARTDM_RF); c = sp[0]; count--; - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, MSM_UART_CR_CMD_RESET_STALE_INT, MSM_UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, - UART_CR); + msm_write(port, MSM_UART_CR_CMD_STALE_EVENT_ENABLE, MSM_UART_CR); } else { c = NO_POLL_CHAR; } @@ -1478,11 +1498,11 @@ static int msm_poll_get_char(struct uart_port *port) { u32 imr; int c; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); /* Disable all interrupts */ - imr = msm_read(port, UART_IMR); - msm_write(port, 0, UART_IMR); + imr = msm_read(port, MSM_UART_IMR); + msm_write(port, 0, MSM_UART_IMR); if (msm_port->is_uartdm) c = msm_poll_get_char_dm(port); @@ -1490,7 +1510,7 @@ static int msm_poll_get_char(struct uart_port *port) c = msm_poll_get_char_single(port); /* Enable interrupts */ - msm_write(port, imr, UART_IMR); + msm_write(port, imr, MSM_UART_IMR); return c; } @@ -1498,32 +1518,32 @@ static int msm_poll_get_char(struct uart_port *port) static void msm_poll_put_char(struct uart_port *port, unsigned char c) { u32 imr; - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = to_msm_port(port); /* Disable all interrupts */ - imr = msm_read(port, UART_IMR); - msm_write(port, 0, UART_IMR); + imr = msm_read(port, MSM_UART_IMR); + msm_write(port, 0, MSM_UART_IMR); if (msm_port->is_uartdm) msm_reset_dm_count(port, 1); /* Wait until FIFO is empty */ - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) cpu_relax(); /* Write a character */ - msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : MSM_UART_TF); /* Wait until FIFO is empty */ - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) cpu_relax(); /* Enable interrupts */ - msm_write(port, imr, UART_IMR); + msm_write(port, imr, MSM_UART_IMR); } #endif -static struct uart_ops msm_uart_pops = { +static const struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, .set_mctrl = msm_set_mctrl, .get_mctrl = msm_get_mctrl, @@ -1577,7 +1597,7 @@ static struct msm_port msm_uart_ports[] = { }, }; -#define UART_NR ARRAY_SIZE(msm_uart_ports) +#define MSM_UART_NR ARRAY_SIZE(msm_uart_ports) static inline struct uart_port *msm_get_port_from_line(unsigned int line) { @@ -1588,6 +1608,7 @@ static inline struct uart_port *msm_get_port_from_line(unsigned int line) static void __msm_console_write(struct uart_port *port, const char *s, unsigned int count, bool is_uartdm) { + unsigned long flags; int i; int num_newlines = 0; bool replaced = false; @@ -1597,7 +1618,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, if (is_uartdm) tf = port->membase + UARTDM_TF; else - tf = port->membase + UART_TF; + tf = port->membase + MSM_UART_TF; /* Account for newlines that will get a carriage return added */ for (i = 0; i < count; i++) @@ -1605,12 +1626,10 @@ static void __msm_console_write(struct uart_port *port, const char *s, num_newlines++; count += num_newlines; - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&port->lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock(&port->lock); + uart_port_lock_irqsave(port, &flags); if (is_uartdm) msm_reset_dm_count(port, count); @@ -1641,7 +1660,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, } } - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + while (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) cpu_relax(); iowrite32_rep(tf, buf, 1); @@ -1649,7 +1668,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, } if (locked) - spin_unlock(&port->lock); + uart_port_unlock_irqrestore(port, flags); } static void msm_console_write(struct console *co, const char *s, @@ -1658,10 +1677,10 @@ static void msm_console_write(struct console *co, const char *s, struct uart_port *port; struct msm_port *msm_port; - BUG_ON(co->index < 0 || co->index >= UART_NR); + BUG_ON(co->index < 0 || co->index >= MSM_UART_NR); port = msm_get_port_from_line(co->index); - msm_port = UART_TO_MSM(port); + msm_port = to_msm_port(port); __msm_console_write(port, s, count, msm_port->is_uartdm); } @@ -1674,7 +1693,7 @@ static int msm_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if (unlikely(co->index >= UART_NR || co->index < 0)) + if (unlikely(co->index >= MSM_UART_NR || co->index < 0)) return -ENXIO; port = msm_get_port_from_line(co->index); @@ -1727,6 +1746,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device, if (!device->port.membase) return -ENODEV; + /* Disable DM / single-character modes */ + msm_write(&device->port, 0, UARTDM_DMEN); + msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR); + msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR); + msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); + device->con->write = msm_serial_early_write_dm; return 0; } @@ -1755,7 +1780,7 @@ static struct uart_driver msm_uart_driver = { .owner = THIS_MODULE, .driver_name = "msm_serial", .dev_name = "ttyMSM", - .nr = UART_NR, + .nr = MSM_UART_NR, .cons = MSM_CONSOLE, }; @@ -1775,7 +1800,7 @@ static int msm_serial_probe(struct platform_device *pdev) struct resource *resource; struct uart_port *port; const struct of_device_id *id; - int irq, line; + int irq, line, ret; if (pdev->dev.of_node) line = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -1785,14 +1810,14 @@ static int msm_serial_probe(struct platform_device *pdev) if (line < 0) line = atomic_inc_return(&msm_uart_next_id) - 1; - if (unlikely(line < 0 || line >= UART_NR)) + if (unlikely(line < 0 || line >= MSM_UART_NR)) return -ENXIO; dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line); port = msm_get_port_from_line(line); port->dev = &pdev->dev; - msm_port = UART_TO_MSM(port); + msm_port = to_msm_port(port); id = of_match_device(msm_uartdm_table, &pdev->dev); if (id) @@ -1810,6 +1835,15 @@ static int msm_serial_probe(struct platform_device *pdev) return PTR_ERR(msm_port->pclk); } + ret = devm_pm_opp_set_clkname(&pdev->dev, "core"); + if (ret) + return ret; + + /* OPP table is optional */ + ret = devm_pm_opp_of_add_table(&pdev->dev); + if (ret && ret != -ENODEV) + return dev_err_probe(&pdev->dev, ret, "invalid OPP table\n"); + port->uartclk = clk_get_rate(msm_port->clk); dev_info(&pdev->dev, "uartclk = %d\n", port->uartclk); @@ -1829,13 +1863,11 @@ static int msm_serial_probe(struct platform_device *pdev) return uart_add_one_port(&msm_uart_driver, port); } -static int msm_serial_remove(struct platform_device *pdev) +static void msm_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&msm_uart_driver, port); - - return 0; } static const struct of_device_id msm_match_table[] = { diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 47ab280f553b..3a77a7e5c7bc 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -21,7 +21,7 @@ #include <linux/console.h> #include <linux/delay.h> /* for udelay */ #include <linux/device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/parisc-device.h> @@ -171,6 +171,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state) { } +static void mux_tx_done(struct uart_port *port) +{ + /* FIXME js: really needs to wait? */ + while (UART_GET_FIFO_CNT(port)) + udelay(1); +} + /** * mux_write - Write chars to the mux fifo. * @port: Ptr to the uart_port. @@ -180,39 +187,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state) */ static void mux_write(struct uart_port *port) { - int count; - struct circ_buf *xmit = &port->state->xmit; - - if(port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if(uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mux_stop_tx(port); - return; - } + u8 ch; - count = (port->fifosize) - UART_GET_FIFO_CNT(port); - do { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if(uart_circ_empty(xmit)) - break; - - } while(--count > 0); - - while(UART_GET_FIFO_CNT(port)) - udelay(1); - - if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - mux_stop_tx(port); + uart_port_tx_limited(port, ch, + port->fifosize - UART_GET_FIFO_CNT(port), + true, + UART_PUT_CHAR(port, ch), + mux_tx_done(port)); } /** @@ -289,7 +270,7 @@ static void mux_shutdown(struct uart_port *port) */ static void mux_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { } @@ -362,7 +343,7 @@ static int mux_verify_port(struct uart_port *port, struct serial_struct *ser) } /** - * mux_drv_poll - Mux poll function. + * mux_poll - Mux poll function. * @unused: Unused variable * * This function periodically polls the Serial MUX to check for new data. @@ -481,12 +462,6 @@ static int __init mux_probe(struct parisc_device *dev) port->line = port_cnt; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MUX_CONSOLE); - /* The port->timeout needs to match what is present in - * uart_wait_until_sent in serial_core.c. Otherwise - * the time spent in msleep_interruptable will be very - * long, causing the appearance of a console hang. - */ - port->timeout = HZ / 50; spin_lock_init(&port->lock); status = uart_add_one_port(&mux_driver, port); @@ -496,7 +471,7 @@ static int __init mux_probe(struct parisc_device *dev) return 0; } -static int __exit mux_remove(struct parisc_device *dev) +static void __exit mux_remove(struct parisc_device *dev) { int i, j; int port_count = (long)dev_get_drvdata(&dev->dev); @@ -518,7 +493,6 @@ static int __exit mux_remove(struct parisc_device *dev) } release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET); - return 0; } /* Hack. This idea was taken from the 8250_gsc.c on how to properly order @@ -589,7 +563,7 @@ static void __exit mux_exit(void) { /* Delete the Mux timer. */ if(port_cnt > 0) { - del_timer_sync(&mux_timer); + timer_delete_sync(&mux_timer); #ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console(&mux_console); #endif diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 4e9a590712cb..8e52be2b34ea 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -8,12 +8,14 @@ */ #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/console.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/init.h> #include <linux/io.h> #include <linux/iopoll.h> +#include <linux/math64.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> @@ -68,12 +70,36 @@ #define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR \ | STAT_PAR_ERR | STAT_OVR_ERR) +/* + * Marvell Armada 3700 Functional Specifications describes that bit 21 of UART + * Clock Control register controls UART1 and bit 20 controls UART2. But in + * reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be an + * error in Marvell's documentation. Hence following CLK_DIS macros are swapped. + */ + #define UART_BRDV 0x10 +/* These bits are located in UART1 address space and control UART2 */ +#define UART2_CLK_DIS BIT(21) +/* These bits are located in UART1 address space and control UART1 */ +#define UART1_CLK_DIS BIT(20) +/* These bits are located in UART1 address space and control both UARTs */ +#define CLK_NO_XTAL BIT(19) +#define CLK_TBG_DIV1_SHIFT 15 +#define CLK_TBG_DIV1_MASK 0x7 +#define CLK_TBG_DIV1_MAX 6 +#define CLK_TBG_DIV2_SHIFT 12 +#define CLK_TBG_DIV2_MASK 0x7 +#define CLK_TBG_DIV2_MAX 6 +#define CLK_TBG_SEL_SHIFT 10 +#define CLK_TBG_SEL_MASK 0x3 +/* These bits are located in both UARTs address space */ #define BRDV_BAUD_MASK 0x3FF +#define BRDV_BAUD_MAX BRDV_BAUD_MASK #define UART_OSAMP 0x14 #define OSAMP_DEFAULT_DIVISOR 16 #define OSAMP_DIVISORS_MASK 0x3F3F3F3F +#define OSAMP_MAX_DIVISOR 63 #define MVEBU_NR_UARTS 2 @@ -128,7 +154,6 @@ struct mvebu_uart { struct uart_port *port; struct clk *clk; int irq[UART_IRQ_COUNT]; - unsigned char __iomem *nb; struct mvebu_uart_driver_data *data; #if defined(CONFIG_PM) struct mvebu_uart_pm_regs pm_regs; @@ -154,17 +179,19 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port) static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS]; +static DEFINE_SPINLOCK(mvebu_uart_lock); + /* Core UART Driver Operations */ static unsigned int mvebu_uart_tx_empty(struct uart_port *port) { unsigned long flags; unsigned int st; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); st = readl(port->membase + UART_STAT); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); - return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0; + return (st & STAT_TX_EMP) ? TIOCSER_TEMT : 0; } static unsigned int mvebu_uart_get_mctrl(struct uart_port *port) @@ -192,13 +219,10 @@ static void mvebu_uart_stop_tx(struct uart_port *port) static void mvebu_uart_start_tx(struct uart_port *port) { unsigned int ctl; - struct circ_buf *xmit = &port->state->xmit; + unsigned char c; - if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) { - writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port)); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } + if (IS_EXTENDED(port) && uart_fifo_get(port, &c)) + writel(c, port->membase + UART_TSH(port)); ctl = readl(port->membase + UART_INTR(port)); ctl |= CTRL_TX_RDY_INT(port); @@ -223,14 +247,14 @@ static void mvebu_uart_break_ctl(struct uart_port *port, int brk) unsigned int ctl; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ctl = readl(port->membase + UART_CTRL(port)); if (brk == -1) ctl |= CTRL_SND_BRK_SEQ; else ctl &= ~CTRL_SND_BRK_SEQ; writel(ctl, port->membase + UART_CTRL(port)); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) @@ -238,6 +262,7 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) struct tty_port *tport = &port->state->port; unsigned char ch = 0; char flag = 0; + int ret; do { if (status & STAT_RX_RDY(port)) { @@ -250,6 +275,16 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) port->icount.parity++; } + /* + * For UART2, error bits are not cleared on buffer read. + * This causes interrupt loop and system hang. + */ + if (IS_EXTENDED(port) && (status & STAT_BRK_ERR)) { + ret = readl(port->membase + UART_STAT); + ret |= STAT_BRK_ERR; + writel(ret, port->membase + UART_STAT); + } + if (status & STAT_BRK_DET) { port->icount.brk++; status &= ~(STAT_FRM_ERR | STAT_PAR_ERR); @@ -297,40 +332,12 @@ ignore_char: static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int count; - unsigned int st; - - if (port->x_char) { - writel(port->x_char, port->membase + UART_TSH(port)); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mvebu_uart_stop_tx(port); - return; - } + u8 ch; - for (count = 0; count < port->fifosize; count++) { - writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port)); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_empty(xmit)) - break; - - st = readl(port->membase + UART_STAT); - if (st & STAT_TX_FIFO_FUL) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - mvebu_uart_stop_tx(port); + uart_port_tx_limited(port, ch, port->fifosize, + !(readl(port->membase + UART_STAT) & STAT_TX_FIFO_FUL), + writel(ch, port->membase + UART_TSH(port)), + ({})); } static irqreturn_t mvebu_uart_isr(int irq, void *dev_id) @@ -443,48 +450,95 @@ static void mvebu_uart_shutdown(struct uart_port *port) } } -static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) +static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) { - struct mvebu_uart *mvuart = to_mvuart(port); unsigned int d_divisor, m_divisor; + unsigned long flags; u32 brdv, osamp; - if (IS_ERR(mvuart->clk)) - return -PTR_ERR(mvuart->clk); + if (!port->uartclk) + return 0; /* - * The baudrate is derived from the UART clock thanks to two divisors: - * > D ("baud generator"): can divide the clock from 2 to 2^10 - 1. - * > M ("fractional divisor"): allows a better accuracy for - * baudrates higher than 230400. + * The baudrate is derived from the UART clock thanks to divisors: + * > d1 * d2 ("TBG divisors"): can divide only TBG clock from 1 to 6 + * > D ("baud generator"): can divide the clock from 1 to 1023 + * > M ("fractional divisor"): allows a better accuracy (from 1 to 63) + * + * Exact formulas for calculating baudrate: + * + * with default x16 scheme: + * baudrate = xtal / (d * 16) + * baudrate = tbg / (d1 * d2 * d * 16) + * + * with fractional divisor: + * baudrate = 10 * xtal / (d * (3 * (m1 + m2) + 2 * (m3 + m4))) + * baudrate = 10 * tbg / (d1*d2 * d * (3 * (m1 + m2) + 2 * (m3 + m4))) + * + * Oversampling value: + * osamp = (m1 << 0) | (m2 << 8) | (m3 << 16) | (m4 << 24); * - * As the derivation of M is rather complicated, the code sticks to its - * default value (x16) when all the prescalers are zeroed, and only - * makes use of D to configure the desired baudrate. + * Where m1 controls number of clock cycles per bit for bits 1,2,3; + * m2 for bits 4,5,6; m3 for bits 7,8 and m4 for bits 9,10. + * + * To simplify baudrate setup set all the M prescalers to the same + * value. For baudrates 9600 Bd and higher, it is enough to use the + * default (x16) divisor or fractional divisor with M = 63, so there + * is no need to use real fractional support (where the M prescalers + * are not equal). + * + * When all the M prescalers are zeroed then default (x16) divisor is + * used. Default x16 scheme is more stable than M (fractional divisor), + * so use M only when D divisor is not enough to derive baudrate. + * + * Member port->uartclk is either xtal clock rate or TBG clock rate + * divided by (d1 * d2). So d1 and d2 are already set by the UART clock + * driver (and UART driver itself cannot change them). Moreover they are + * shared between both UARTs. */ + m_divisor = OSAMP_DEFAULT_DIVISOR; - d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor); + d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor); + + if (d_divisor > BRDV_BAUD_MAX) { + /* + * Experiments show that small M divisors are unstable. + * Use maximal possible M = 63 and calculate D divisor. + */ + m_divisor = OSAMP_MAX_DIVISOR; + d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor); + } + if (d_divisor < 1) + d_divisor = 1; + else if (d_divisor > BRDV_BAUD_MAX) + d_divisor = BRDV_BAUD_MAX; + + spin_lock_irqsave(&mvebu_uart_lock, flags); brdv = readl(port->membase + UART_BRDV); brdv &= ~BRDV_BAUD_MASK; brdv |= d_divisor; writel(brdv, port->membase + UART_BRDV); + spin_unlock_irqrestore(&mvebu_uart_lock, flags); osamp = readl(port->membase + UART_OSAMP); osamp &= ~OSAMP_DIVISORS_MASK; + if (m_divisor != OSAMP_DEFAULT_DIVISOR) + osamp |= (m_divisor << 0) | (m_divisor << 8) | + (m_divisor << 16) | (m_divisor << 24); writel(osamp, port->membase + UART_OSAMP); - return 0; + return DIV_ROUND_CLOSEST(port->uartclk, d_divisor * m_divisor); } static void mvebu_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; - unsigned int baud; + unsigned int baud, min_baud, max_baud; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); port->read_status_mask = STAT_RX_RDY(port) | STAT_OVR_ERR | STAT_TX_RDY(port) | STAT_TX_FIFO_FUL; @@ -501,20 +555,23 @@ static void mvebu_uart_set_termios(struct uart_port *port, port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR; /* - * Maximum achievable frequency with simple baudrate divisor is 230400. - * Since the error per bit frame would be of more than 15%, achieving - * higher frequencies would require to implement the fractional divisor - * feature. + * Maximal divisor is 1023 and maximal fractional divisor is 63. And + * experiments show that baudrates above 1/80 of parent clock rate are + * not stable. So disallow baudrates above 1/80 of the parent clock + * rate. If port->uartclk is not available, then + * mvebu_uart_baud_rate_set() fails, so values min_baud and max_baud + * in this case do not matter. */ - baud = uart_get_baud_rate(port, termios, old, 0, 230400); - if (mvebu_uart_baud_rate_set(port, baud)) { - /* No clock available, baudrate cannot be changed */ - if (old) - baud = uart_get_baud_rate(port, old, NULL, 0, 230400); - } else { - tty_termios_encode_baud_rate(termios, baud, baud); - uart_update_timeout(port, termios->c_cflag, baud); - } + min_baud = DIV_ROUND_UP(port->uartclk, BRDV_BAUD_MAX * + OSAMP_MAX_DIVISOR); + max_baud = port->uartclk / 80; + + baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud); + baud = mvebu_uart_baud_rate_set(port, baud); + + /* In case baudrate cannot be changed, report previous old value */ + if (baud == 0 && old) + baud = tty_termios_baud_rate(old); /* Only the following flag changes are supported */ if (old) { @@ -525,7 +582,12 @@ static void mvebu_uart_set_termios(struct uart_port *port, termios->c_cflag |= CS8; } - spin_unlock_irqrestore(&port->lock, flags); + if (baud != 0) { + tty_termios_encode_baud_rate(termios, baud, baud); + uart_update_timeout(port, termios->c_cflag, baud); + } + + uart_port_unlock_irqrestore(port, flags); } static const char *mvebu_uart_type(struct uart_port *port) @@ -595,7 +657,7 @@ static const struct uart_ops mvebu_uart_ops = { #ifdef CONFIG_SERIAL_MVEBU_CONSOLE /* Early Console */ -static void mvebu_uart_putc(struct uart_port *port, int c) +static void mvebu_uart_putc(struct uart_port *port, unsigned char c) { unsigned int st; @@ -617,7 +679,7 @@ static void mvebu_uart_putc(struct uart_port *port, int c) static void mvebu_uart_putc_early_write(struct console *con, const char *s, - unsigned n) + unsigned int n) { struct earlycon_device *dev = con->data; @@ -648,7 +710,15 @@ static void wait_for_xmitr(struct uart_port *port) (val & STAT_TX_RDY(port)), 1, 10000); } -static void mvebu_uart_console_putchar(struct uart_port *port, int ch) +static void wait_for_xmite(struct uart_port *port) +{ + u32 val; + + readl_poll_timeout_atomic(port->membase + UART_STAT, val, + (val & STAT_TX_EMP), 1, 10000); +} + +static void mvebu_uart_console_putchar(struct uart_port *port, unsigned char ch) { wait_for_xmitr(port); writel(ch, port->membase + UART_TSH(port)); @@ -663,9 +733,9 @@ static void mvebu_uart_console_write(struct console *co, const char *s, int locked = 1; if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ier = readl(port->membase + UART_CTRL(port)) & CTRL_BRK_INT; intr = readl(port->membase + UART_INTR(port)) & @@ -675,7 +745,7 @@ static void mvebu_uart_console_write(struct console *co, const char *s, uart_console_write(port, s, count, mvebu_uart_console_putchar); - wait_for_xmitr(port); + wait_for_xmite(port); if (ier) writel(ier, port->membase + UART_CTRL(port)); @@ -686,7 +756,7 @@ static void mvebu_uart_console_write(struct console *co, const char *s, } if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int mvebu_uart_console_setup(struct console *co, char *options) @@ -751,6 +821,7 @@ static int mvebu_uart_suspend(struct device *dev) { struct mvebu_uart *mvuart = dev_get_drvdata(dev); struct uart_port *port = mvuart->port; + unsigned long flags; uart_suspend_port(&mvebu_uart_driver, port); @@ -759,7 +830,9 @@ static int mvebu_uart_suspend(struct device *dev) mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port)); mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port)); mvuart->pm_regs.stat = readl(port->membase + UART_STAT); + spin_lock_irqsave(&mvebu_uart_lock, flags); mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV); + spin_unlock_irqrestore(&mvebu_uart_lock, flags); mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP); device_set_wakeup_enable(dev, true); @@ -771,13 +844,16 @@ static int mvebu_uart_resume(struct device *dev) { struct mvebu_uart *mvuart = dev_get_drvdata(dev); struct uart_port *port = mvuart->port; + unsigned long flags; writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port)); writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port)); writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port)); writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port)); writel(mvuart->pm_regs.stat, port->membase + UART_STAT); + spin_lock_irqsave(&mvebu_uart_lock, flags); writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV); + spin_unlock_irqrestore(&mvebu_uart_lock, flags); writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP); uart_resume_port(&mvebu_uart_driver, port); @@ -798,20 +874,12 @@ static int uart_num_counter; static int mvebu_uart_probe(struct platform_device *pdev) { - struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0); const struct of_device_id *match = of_match_device(mvebu_uart_of_match, &pdev->dev); struct uart_port *port; struct mvebu_uart *mvuart; - int ret, id, irq; - - if (!reg) { - dev_err(&pdev->dev, "no registers defined\n"); - return -EINVAL; - } - - if (!match) - return -ENODEV; + struct resource *reg; + int id, irq; /* Assume that all UART ports have a DT alias or none has */ id = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -847,11 +915,11 @@ static int mvebu_uart_probe(struct platform_device *pdev) */ port->irq = 0; port->irqflags = 0; - port->mapbase = reg->start; - port->membase = devm_ioremap_resource(&pdev->dev, reg); + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, ®); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); + port->mapbase = reg->start; mvuart = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart), GFP_KERNEL); @@ -912,10 +980,7 @@ static int mvebu_uart_probe(struct platform_device *pdev) udelay(1); writel(0, port->membase + UART_CTRL(port)); - ret = uart_add_one_port(&mvebu_uart_driver, port); - if (ret) - return ret; - return 0; + return uart_add_one_port(&mvebu_uart_driver, port); } static struct mvebu_uart_driver_data uart_std_driver_data = { @@ -967,6 +1032,479 @@ static struct platform_driver mvebu_uart_platform_driver = { }, }; +/* This code is based on clk-fixed-factor.c driver and modified. */ + +struct mvebu_uart_clock { + struct clk_hw clk_hw; + int clock_idx; + u32 pm_context_reg1; + u32 pm_context_reg2; +}; + +struct mvebu_uart_clock_base { + struct mvebu_uart_clock clocks[2]; + unsigned int parent_rates[5]; + int parent_idx; + unsigned int div; + void __iomem *reg1; + void __iomem *reg2; + bool configured; +}; + +#define PARENT_CLOCK_XTAL 4 + +#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw) +#define to_uart_clock_base(uart_clock) container_of(uart_clock, \ + struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx]) + +static int mvebu_uart_clock_prepare(struct clk_hw *hw) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2; + unsigned int parent_clock_idx, parent_clock_rate; + unsigned long flags; + unsigned int d1, d2; + u64 divisor; + u32 val; + + /* + * This function just reconfigures UART Clock Control register (located + * in UART1 address space which controls both UART1 and UART2) to + * selected UART base clock and recalculates current UART1/UART2 + * divisors in their address spaces, so that final baudrate will not be + * changed by switching UART parent clock. This is required for + * otherwise kernel's boot log stops working - we need to ensure that + * UART baudrate does not change during this setup. It is a one time + * operation, it will execute only once and set `configured` to true, + * and be skipped on subsequent calls. Because this UART Clock Control + * register (UART_BRDV) is shared between UART1 baudrate function, + * UART1 clock selector and UART2 clock selector, every access to + * UART_BRDV (reg1) needs to be protected by a lock. + */ + + spin_lock_irqsave(&mvebu_uart_lock, flags); + + if (uart_clock_base->configured) { + spin_unlock_irqrestore(&mvebu_uart_lock, flags); + return 0; + } + + parent_clock_idx = uart_clock_base->parent_idx; + parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx]; + + val = readl(uart_clock_base->reg1); + + if (uart_clock_base->div > CLK_TBG_DIV1_MAX) { + d1 = CLK_TBG_DIV1_MAX; + d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX; + } else { + d1 = uart_clock_base->div; + d2 = 1; + } + + if (val & CLK_NO_XTAL) { + prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK; + prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK) * + ((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK); + } else { + prev_clock_idx = PARENT_CLOCK_XTAL; + prev_d1d2 = 1; + } + + /* Note that uart_clock_base->parent_rates[i] may not be available */ + prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx]; + + /* Recalculate UART1 divisor so UART1 baudrate does not change */ + if (prev_clock_rate) { + divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) * + parent_clock_rate * prev_d1d2, + prev_clock_rate * d1 * d2); + if (divisor < 1) + divisor = 1; + else if (divisor > BRDV_BAUD_MAX) + divisor = BRDV_BAUD_MAX; + val = (val & ~BRDV_BAUD_MASK) | divisor; + } + + if (parent_clock_idx != PARENT_CLOCK_XTAL) { + /* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */ + val |= CLK_NO_XTAL; + val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT); + val |= d1 << CLK_TBG_DIV1_SHIFT; + val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT); + val |= d2 << CLK_TBG_DIV2_SHIFT; + val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT); + val |= parent_clock_idx << CLK_TBG_SEL_SHIFT; + } else { + /* Use XTAL, TBG bits are then ignored */ + val &= ~CLK_NO_XTAL; + } + + writel(val, uart_clock_base->reg1); + + /* Recalculate UART2 divisor so UART2 baudrate does not change */ + if (prev_clock_rate) { + val = readl(uart_clock_base->reg2); + divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) * + parent_clock_rate * prev_d1d2, + prev_clock_rate * d1 * d2); + if (divisor < 1) + divisor = 1; + else if (divisor > BRDV_BAUD_MAX) + divisor = BRDV_BAUD_MAX; + val = (val & ~BRDV_BAUD_MASK) | divisor; + writel(val, uart_clock_base->reg2); + } + + uart_clock_base->configured = true; + + spin_unlock_irqrestore(&mvebu_uart_lock, flags); + + return 0; +} + +static int mvebu_uart_clock_enable(struct clk_hw *hw) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&mvebu_uart_lock, flags); + + val = readl(uart_clock_base->reg1); + + if (uart_clock->clock_idx == 0) + val &= ~UART1_CLK_DIS; + else + val &= ~UART2_CLK_DIS; + + writel(val, uart_clock_base->reg1); + + spin_unlock_irqrestore(&mvebu_uart_lock, flags); + + return 0; +} + +static void mvebu_uart_clock_disable(struct clk_hw *hw) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&mvebu_uart_lock, flags); + + val = readl(uart_clock_base->reg1); + + if (uart_clock->clock_idx == 0) + val |= UART1_CLK_DIS; + else + val |= UART2_CLK_DIS; + + writel(val, uart_clock_base->reg1); + + spin_unlock_irqrestore(&mvebu_uart_lock, flags); +} + +static int mvebu_uart_clock_is_enabled(struct clk_hw *hw) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + u32 val; + + val = readl(uart_clock_base->reg1); + + if (uart_clock->clock_idx == 0) + return !(val & UART1_CLK_DIS); + else + return !(val & UART2_CLK_DIS); +} + +static int mvebu_uart_clock_save_context(struct clk_hw *hw) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + unsigned long flags; + + spin_lock_irqsave(&mvebu_uart_lock, flags); + uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1); + uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2); + spin_unlock_irqrestore(&mvebu_uart_lock, flags); + + return 0; +} + +static void mvebu_uart_clock_restore_context(struct clk_hw *hw) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + unsigned long flags; + + spin_lock_irqsave(&mvebu_uart_lock, flags); + writel(uart_clock->pm_context_reg1, uart_clock_base->reg1); + writel(uart_clock->pm_context_reg2, uart_clock_base->reg2); + spin_unlock_irqrestore(&mvebu_uart_lock, flags); +} + +static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + + return parent_rate / uart_clock_base->div; +} + +static int mvebu_uart_clock_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); + struct mvebu_uart_clock_base *uart_clock_base = + to_uart_clock_base(uart_clock); + + req->rate = req->best_parent_rate / uart_clock_base->div; + + return 0; +} + +static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + /* + * We must report success but we can do so unconditionally because + * mvebu_uart_clock_round_rate returns values that ensure this call is a + * nop. + */ + + return 0; +} + +static const struct clk_ops mvebu_uart_clock_ops = { + .prepare = mvebu_uart_clock_prepare, + .enable = mvebu_uart_clock_enable, + .disable = mvebu_uart_clock_disable, + .is_enabled = mvebu_uart_clock_is_enabled, + .save_context = mvebu_uart_clock_save_context, + .restore_context = mvebu_uart_clock_restore_context, + .determine_rate = mvebu_uart_clock_determine_rate, + .set_rate = mvebu_uart_clock_set_rate, + .recalc_rate = mvebu_uart_clock_recalc_rate, +}; + +static int mvebu_uart_clock_register(struct device *dev, + struct mvebu_uart_clock *uart_clock, + const char *name, + const char *parent_name) +{ + struct clk_init_data init = { }; + + uart_clock->clk_hw.init = &init; + + init.name = name; + init.ops = &mvebu_uart_clock_ops; + init.flags = 0; + init.num_parents = 1; + init.parent_names = &parent_name; + + return devm_clk_hw_register(dev, &uart_clock->clk_hw); +} + +static int mvebu_uart_clock_probe(struct platform_device *pdev) +{ + static const char *const uart_clk_names[] = { "uart_1", "uart_2" }; + static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P", + "TBG-A-S", "TBG-B-S", + "xtal" }; + struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)]; + struct mvebu_uart_clock_base *uart_clock_base; + struct clk_hw_onecell_data *hw_clk_data; + struct device *dev = &pdev->dev; + int i, parent_clk_idx, ret; + unsigned long div, rate; + struct resource *res; + unsigned int d1, d2; + + BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) != + ARRAY_SIZE(uart_clock_base->clocks)); + BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) != + ARRAY_SIZE(uart_clock_base->parent_rates)); + + uart_clock_base = devm_kzalloc(dev, + sizeof(*uart_clock_base), + GFP_KERNEL); + if (!uart_clock_base) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Couldn't get first register\n"); + return -ENOENT; + } + + /* + * UART Clock Control register (reg1 / UART_BRDV) is in the address + * space of UART1 (standard UART variant), controls parent clock and + * dividers for both UART1 and UART2 and is supplied via DT as the first + * resource. Therefore use ioremap() rather than ioremap_resource() to + * avoid conflicts with UART1 driver. Access to UART_BRDV is protected + * by a lock shared between clock and UART driver. + */ + uart_clock_base->reg1 = devm_ioremap(dev, res->start, + resource_size(res)); + if (!uart_clock_base->reg1) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(dev, "Couldn't get second register\n"); + return -ENOENT; + } + + /* + * UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address + * space of UART2 (extended UART variant), controls only one UART2 + * specific divider and is supplied via DT as second resource. + * Therefore use ioremap() rather than ioremap_resource() to avoid + * conflicts with UART2 driver. Access to UART_BRDV is protected by a + * by lock shared between clock and UART driver. + */ + uart_clock_base->reg2 = devm_ioremap(dev, res->start, + resource_size(res)); + if (!uart_clock_base->reg2) + return -ENOMEM; + + hw_clk_data = devm_kzalloc(dev, + struct_size(hw_clk_data, hws, + ARRAY_SIZE(uart_clk_names)), + GFP_KERNEL); + if (!hw_clk_data) + return -ENOMEM; + + hw_clk_data->num = ARRAY_SIZE(uart_clk_names); + for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) { + hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw; + uart_clock_base->clocks[i].clock_idx = i; + } + + parent_clk_idx = -1; + + for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) { + parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]); + if (IS_ERR(parent_clks[i])) { + if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_warn(dev, "Couldn't get the parent clock %s: %ld\n", + parent_clk_names[i], PTR_ERR(parent_clks[i])); + continue; + } + + ret = clk_prepare_enable(parent_clks[i]); + if (ret) { + dev_warn(dev, "Couldn't enable parent clock %s: %d\n", + parent_clk_names[i], ret); + continue; + } + rate = clk_get_rate(parent_clks[i]); + uart_clock_base->parent_rates[i] = rate; + + if (i != PARENT_CLOCK_XTAL) { + /* + * Calculate the smallest TBG d1 and d2 divisors that + * still can provide 9600 baudrate. + */ + d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR * + BRDV_BAUD_MAX); + if (d1 < 1) + d1 = 1; + else if (d1 > CLK_TBG_DIV1_MAX) + d1 = CLK_TBG_DIV1_MAX; + + d2 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR * + BRDV_BAUD_MAX * d1); + if (d2 < 1) + d2 = 1; + else if (d2 > CLK_TBG_DIV2_MAX) + d2 = CLK_TBG_DIV2_MAX; + } else { + /* + * When UART clock uses XTAL clock as a source then it + * is not possible to use d1 and d2 divisors. + */ + d1 = d2 = 1; + } + + /* Skip clock source which cannot provide 9600 baudrate */ + if (rate > 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX * d1 * d2) + continue; + + /* + * Choose TBG clock source with the smallest divisors. Use XTAL + * clock source only in case TBG is not available as XTAL cannot + * be used for baudrates higher than 230400. + */ + if (parent_clk_idx == -1 || + (i != PARENT_CLOCK_XTAL && div > d1 * d2)) { + parent_clk_idx = i; + div = d1 * d2; + } + } + + for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) { + if (i == parent_clk_idx || IS_ERR(parent_clks[i])) + continue; + clk_disable_unprepare(parent_clks[i]); + devm_clk_put(dev, parent_clks[i]); + } + + if (parent_clk_idx == -1) { + dev_err(dev, "No usable parent clock\n"); + return -ENOENT; + } + + uart_clock_base->parent_idx = parent_clk_idx; + uart_clock_base->div = div; + + dev_notice(dev, "Using parent clock %s as base UART clock\n", + __clk_get_name(parent_clks[parent_clk_idx])); + + for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) { + ret = mvebu_uart_clock_register(dev, + &uart_clock_base->clocks[i], + uart_clk_names[i], + __clk_get_name(parent_clks[parent_clk_idx])); + if (ret) { + dev_err(dev, "Can't register UART clock %d: %d\n", + i, ret); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + hw_clk_data); +} + +static const struct of_device_id mvebu_uart_clock_of_match[] = { + { .compatible = "marvell,armada-3700-uart-clock", }, + { } +}; + +static struct platform_driver mvebu_uart_clock_platform_driver = { + .probe = mvebu_uart_clock_probe, + .driver = { + .name = "mvebu-uart-clock", + .of_match_table = mvebu_uart_clock_of_match, + }, +}; + static int __init mvebu_uart_init(void) { int ret; @@ -975,10 +1513,19 @@ static int __init mvebu_uart_init(void) if (ret) return ret; + ret = platform_driver_register(&mvebu_uart_clock_platform_driver); + if (ret) { + uart_unregister_driver(&mvebu_uart_driver); + return ret; + } + ret = platform_driver_register(&mvebu_uart_platform_driver); - if (ret) + if (ret) { + platform_driver_unregister(&mvebu_uart_clock_platform_driver); uart_unregister_driver(&mvebu_uart_driver); + return ret; + } - return ret; + return 0; } arch_initcall(mvebu_uart_init); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index b4f835e7de23..cc65c9fb6446 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -30,12 +30,10 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/io.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> -#include <asm/cacheflush.h> - #include <linux/gpio/consumer.h> #include <linux/err.h> #include <linux/irq.h> @@ -89,7 +87,7 @@ #define AUART_LINECTRL_BAUD_DIVFRAC(v) (((v) & 0x3f) << 8) #define AUART_LINECTRL_SPS (1 << 7) #define AUART_LINECTRL_WLEN_MASK 0x00000060 -#define AUART_LINECTRL_WLEN(v) (((v) & 0x3) << 5) +#define AUART_LINECTRL_WLEN(v) ((((v) - 5) & 0x3) << 5) #define AUART_LINECTRL_FEN (1 << 4) #define AUART_LINECTRL_STP2 (1 << 3) #define AUART_LINECTRL_EPS (1 << 2) @@ -443,24 +441,16 @@ struct mxs_auart_port { bool ms_irq_enabled; }; -static const struct platform_device_id mxs_auart_devtype[] = { - { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART }, - { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART }, - { .name = "as-auart-asm9260", .driver_data = ASM9260_AUART }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, mxs_auart_devtype); - static const struct of_device_id mxs_auart_dt_ids[] = { { .compatible = "fsl,imx28-auart", - .data = &mxs_auart_devtype[IMX28_AUART] + .data = (const void *)IMX28_AUART }, { .compatible = "fsl,imx23-auart", - .data = &mxs_auart_devtype[IMX23_AUART] + .data = (const void *)IMX23_AUART }, { .compatible = "alphascale,asm9260-auart", - .data = &mxs_auart_devtype[ASM9260_AUART] + .data = (const void *)ASM9260_AUART }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids); @@ -527,7 +517,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s); static void dma_tx_callback(void *param) { struct mxs_auart_port *s = param; - struct circ_buf *xmit = &s->port.state->xmit; + struct tty_port *tport = &s->port.state->port; dma_unmap_sg(s->dev, &s->tx_sgl, 1, DMA_TO_DEVICE); @@ -536,7 +526,7 @@ static void dma_tx_callback(void *param) smp_mb__after_atomic(); /* wake up the possible processes. */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&s->port); mxs_auart_tx_chars(s); @@ -578,31 +568,22 @@ static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size) static void mxs_auart_tx_chars(struct mxs_auart_port *s) { - struct circ_buf *xmit = &s->port.state->xmit; + struct tty_port *tport = &s->port.state->port; + bool pending; + u8 ch; if (auart_dma_enabled(s)) { u32 i = 0; - int size; void *buffer = s->tx_dma_buf; if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags)) return; - while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) { - size = min_t(u32, UART_XMIT_SIZE - i, - CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE)); - memcpy(buffer + i, xmit->buf + xmit->tail, size); - xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1); - - i += size; - if (i >= UART_XMIT_SIZE) - break; - } - if (uart_tx_stopped(&s->port)) mxs_auart_stop_tx(&s->port); + else + i = kfifo_out(&tport->xmit_fifo, buffer, + UART_XMIT_SIZE); if (i) { mxs_auart_dma_tx(s, i); @@ -613,38 +594,22 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) return; } - - while (!(mxs_read(s, REG_STAT) & AUART_STAT_TXFF)) { - if (s->port.x_char) { - s->port.icount.tx++; - mxs_write(s->port.x_char, s, REG_DATA); - s->port.x_char = 0; - continue; - } - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) { - s->port.icount.tx++; - mxs_write(xmit->buf[xmit->tail], s, REG_DATA); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - break; - } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&s->port); - - if (uart_circ_empty(&(s->port.state->xmit))) - mxs_clr(AUART_INTR_TXIEN, s, REG_INTR); - else + pending = uart_port_tx_flags(&s->port, ch, UART_TX_NOSTOP, + !(mxs_read(s, REG_STAT) & AUART_STAT_TXFF), + mxs_write(ch, s, REG_DATA)); + if (pending) mxs_set(AUART_INTR_TXIEN, s, REG_INTR); + else + mxs_clr(AUART_INTR_TXIEN, s, REG_INTR); if (uart_tx_stopped(&s->port)) - mxs_auart_stop_tx(&s->port); + mxs_auart_stop_tx(&s->port); } static void mxs_auart_rx_char(struct mxs_auart_port *s) { - int flag; u32 stat; - u8 c; + u8 c, flag; c = mxs_read(s, REG_DATA); stat = mxs_read(s, REG_STAT); @@ -931,21 +896,27 @@ static void mxs_auart_dma_exit(struct mxs_auart_port *s) static int mxs_auart_dma_init(struct mxs_auart_port *s) { + struct dma_chan *chan; + if (auart_dma_enabled(s)) return 0; /* init for RX */ - s->rx_dma_chan = dma_request_slave_channel(s->dev, "rx"); - if (!s->rx_dma_chan) + chan = dma_request_chan(s->dev, "rx"); + if (IS_ERR(chan)) goto err_out; + s->rx_dma_chan = chan; + s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA); if (!s->rx_dma_buf) goto err_out; /* init for TX */ - s->tx_dma_chan = dma_request_slave_channel(s->dev, "tx"); - if (!s->tx_dma_chan) + chan = dma_request_chan(s->dev, "tx"); + if (IS_ERR(chan)) goto err_out; + s->tx_dma_chan = chan; + s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA); if (!s->tx_dma_buf) goto err_out; @@ -969,10 +940,10 @@ err_out: #define CTS_AT_AUART() !mctrl_gpio_to_gpiod(s->gpios, UART_GPIO_CTS) static void mxs_auart_settermios(struct uart_port *u, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct mxs_auart_port *s = to_auart_port(u); - u32 bm, ctrl, ctrl2, div; + u32 ctrl, ctrl2, div; unsigned int cflag, baud, baud_min, baud_max; cflag = termios->c_cflag; @@ -980,25 +951,7 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl = AUART_LINECTRL_FEN; ctrl2 = mxs_read(s, REG_CTRL2); - /* byte size */ - switch (cflag & CSIZE) { - case CS5: - bm = 0; - break; - case CS6: - bm = 1; - break; - case CS7: - bm = 2; - break; - case CS8: - bm = 3; - break; - default: - return; - } - - ctrl |= AUART_LINECTRL_WLEN(bm); + ctrl |= AUART_LINECTRL_WLEN(tty_get_char_size(cflag)); /* parity */ if (cflag & PARENB) { @@ -1122,11 +1075,13 @@ static void mxs_auart_set_ldisc(struct uart_port *port, static irqreturn_t mxs_auart_irq_handle(int irq, void *context) { - u32 istat; + u32 istat, stat; struct mxs_auart_port *s = context; u32 mctrl_temp = s->mctrl_prev; - u32 stat = mxs_read(s, REG_STAT); + uart_port_lock(&s->port); + + stat = mxs_read(s, REG_STAT); istat = mxs_read(s, REG_INTR); /* ack irq */ @@ -1162,6 +1117,8 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) istat &= ~AUART_INTR_TXIS; } + uart_port_unlock(&s->port); + return IRQ_HANDLED; } @@ -1333,7 +1290,7 @@ static const struct uart_ops mxs_auart_ops = { static struct mxs_auart_port *auart_port[MXS_AUART_PORTS]; #ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE -static void mxs_auart_console_putchar(struct uart_port *port, int ch) +static void mxs_auart_console_putchar(struct uart_port *port, unsigned char ch) { struct mxs_auart_port *s = to_auart_port(port); unsigned int to = 1000; @@ -1413,7 +1370,7 @@ auart_console_get_options(struct mxs_auart_port *s, int *baud, *parity = 'o'; } - if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2)) + if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(7)) *bits = 7; else *bits = 8; @@ -1543,34 +1500,6 @@ disable_clk_ahb: return err; } -/* - * This function returns 1 if pdev isn't a device instatiated by dt, 0 if it - * could successfully get all information from dt or a negative errno. - */ -static int serial_mxs_probe_dt(struct mxs_auart_port *s, - struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - int ret; - - if (!np) - /* no device tree device */ - return 1; - - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); - return ret; - } - s->port.line = ret; - - if (of_get_property(np, "uart-has-rtscts", NULL) || - of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) - set_bit(MXS_AUART_RTSCTS, &s->flags); - - return 0; -} - static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) { enum mctrl_gpio_idx i; @@ -1639,8 +1568,7 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s) static int mxs_auart_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(mxs_auart_dt_ids, &pdev->dev); + struct device_node *np = pdev->dev.of_node; struct mxs_auart_port *s; u32 version; int ret, irq; @@ -1653,20 +1581,23 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.dev = &pdev->dev; s->dev = &pdev->dev; - ret = serial_mxs_probe_dt(s, pdev); - if (ret > 0) - s->port.line = pdev->id < 0 ? 0 : pdev->id; - else if (ret < 0) + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); return ret; + } + s->port.line = ret; + + if (of_property_read_bool(np, "uart-has-rtscts") || + of_property_read_bool(np, "fsl,uart-has-rtscts") /* deprecated */) + set_bit(MXS_AUART_RTSCTS, &s->flags); + if (s->port.line >= ARRAY_SIZE(auart_port)) { dev_err(&pdev->dev, "serial%d out of range\n", s->port.line); return -EINVAL; } - if (of_id) { - pdev->id_entry = of_id->data; - s->devtype = pdev->id_entry->driver_data; - } + s->devtype = (enum mxs_auart_type)of_device_get_match_data(&pdev->dev); ret = mxs_get_clks(s, pdev); if (ret) @@ -1698,21 +1629,21 @@ static int mxs_auart_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; - goto out_disable_clks; + goto out_iounmap; } s->port.irq = irq; ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s); if (ret) - goto out_disable_clks; + goto out_iounmap; platform_set_drvdata(pdev, s); ret = mxs_auart_init_gpios(s, &pdev->dev); if (ret) { dev_err(&pdev->dev, "Failed to initialize GPIOs.\n"); - goto out_disable_clks; + goto out_iounmap; } /* @@ -1720,7 +1651,7 @@ static int mxs_auart_probe(struct platform_device *pdev) */ ret = mxs_auart_request_gpio_irq(s); if (ret) - goto out_disable_clks; + goto out_iounmap; auart_port[s->port.line] = s; @@ -1746,6 +1677,9 @@ out_free_qpio_irq: mxs_auart_free_gpio_irq(s); auart_port[pdev->id] = NULL; +out_iounmap: + iounmap(s->port.membase); + out_disable_clks: if (is_asm9260_auart(s)) { clk_disable_unprepare(s->clk); @@ -1754,19 +1688,18 @@ out_disable_clks: return ret; } -static int mxs_auart_remove(struct platform_device *pdev) +static void mxs_auart_remove(struct platform_device *pdev) { struct mxs_auart_port *s = platform_get_drvdata(pdev); uart_remove_one_port(&auart_driver, &s->port); auart_port[pdev->id] = NULL; mxs_auart_free_gpio_irq(s); + iounmap(s->port.membase); if (is_asm9260_auart(s)) { clk_disable_unprepare(s->clk); clk_disable_unprepare(s->clk_ahb); } - - return 0; } static struct platform_driver mxs_auart_driver = { diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 8573fc9cb0cd..0b85f47ff19e 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/delay.h> #include <linux/slab.h> @@ -159,6 +160,8 @@ struct uart_omap_port { u32 calc_latency; struct work_struct qos_work; bool is_suspending; + + unsigned int rs485_tx_filter_count; }; #define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) @@ -219,16 +222,11 @@ static inline int calculate_baud_abs_diff(struct uart_port *port, unsigned int baud, unsigned int mode) { unsigned int n = port->uartclk / (mode * baud); - int abs_diff; if (n == 0) n = 1; - abs_diff = baud - (port->uartclk / (mode * n)); - if (abs_diff < 0) - abs_diff = -abs_diff; - - return abs_diff; + return abs_diff(baud, port->uartclk / (mode * n)); } /* @@ -274,11 +272,8 @@ static void serial_omap_enable_ms(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_tx(struct uart_port *port) @@ -286,8 +281,6 @@ static void serial_omap_stop_tx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); int res; - pm_runtime_get_sync(up->dev); - /* Handle RS-485 */ if (port->rs485.flags & SER_RS485_ENABLED) { if (up->scr & OMAP_UART_SCR_TX_EMPTY) { @@ -327,65 +320,34 @@ static void serial_omap_stop_tx(struct uart_port *port) up->ier &= ~UART_IER_THRI; serial_out(up, UART_IER, up->ier); } - - if ((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { - /* - * Empty the RX FIFO, we are not interested in anything - * received during the half-duplex transmission. - */ - serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR); - /* Re-enable RX interrupts */ - up->ier |= UART_IER_RLSI | UART_IER_RDI; - up->port.read_status_mask |= UART_LSR_DR; - serial_out(up, UART_IER, up->ier); - } - - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_rx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(up->dev); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } -static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) +static void serial_omap_put_char(struct uart_omap_port *up, unsigned char ch) { - struct circ_buf *xmit = &up->port.state->xmit; - int count; + serial_out(up, UART_TX, ch); - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_omap_stop_tx(&up->port); - return; - } - count = up->port.fifosize / 4; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + up->rs485_tx_filter_count++; +} - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); +static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) +{ + u8 ch; - if (uart_circ_empty(xmit)) - serial_omap_stop_tx(&up->port); + uart_port_tx_limited(&up->port, ch, up->port.fifosize / 4, + true, + serial_omap_put_char(up, ch), + ({})); } static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) @@ -401,8 +363,6 @@ static void serial_omap_start_tx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); int res; - pm_runtime_get_sync(up->dev); - /* Handle RS-485 */ if (port->rs485.flags & SER_RS485_ENABLED) { /* Fire THR interrupts when FIFO is below trigger level */ @@ -420,11 +380,9 @@ static void serial_omap_start_tx(struct uart_port *port) if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) - serial_omap_stop_rx(port); + up->rs485_tx_filter_count = 0; serial_omap_enable_ier_thri(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_throttle(struct uart_port *port) @@ -432,13 +390,10 @@ static void serial_omap_throttle(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags; - pm_runtime_get_sync(up->dev); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); serial_out(up, UART_IER, up->ier); - spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + uart_port_unlock_irqrestore(&up->port, flags); } static void serial_omap_unthrottle(struct uart_port *port) @@ -446,13 +401,10 @@ static void serial_omap_unthrottle(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags; - pm_runtime_get_sync(up->dev); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->ier |= UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); - spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + uart_port_unlock_irqrestore(&up->port, flags); } static unsigned int check_modem_status(struct uart_omap_port *up) @@ -485,14 +437,19 @@ static unsigned int check_modem_status(struct uart_omap_port *up) static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) { - unsigned int flag; + u8 flag; /* * Read one data character out to avoid stalling the receiver according * to the table 23-246 of the omap4 TRM. */ - if (likely(lsr & UART_LSR_DR)) + if (likely(lsr & UART_LSR_DR)) { serial_in(up, UART_RX); + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && + up->rs485_tx_filter_count) + up->rs485_tx_filter_count--; + } up->port.icount.rx++; flag = TTY_NORMAL; @@ -536,20 +493,25 @@ static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) { - unsigned char ch = 0; - unsigned int flag; + u8 ch; if (!(lsr & UART_LSR_DR)) return; ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && + up->rs485_tx_filter_count) { + up->rs485_tx_filter_count--; + return; + } + up->port.icount.rx++; - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) return; - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, TTY_NORMAL); } /** @@ -565,8 +527,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) irqreturn_t ret = IRQ_NONE; int max_count = 256; - spin_lock(&up->port.lock); - pm_runtime_get_sync(up->dev); + uart_port_lock(&up->port); do { iir = serial_in(up, UART_IIR); @@ -587,7 +548,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) transmit_chars(up, lsr); break; case UART_IIR_RX_TIMEOUT: - /* FALLTHROUGH */ case UART_IIR_RDI: serial_omap_rdi(up, lsr); break; @@ -598,18 +558,15 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) /* simply try again */ break; case UART_IIR_XOFF: - /* FALLTHROUGH */ default: break; } } while (max_count--); - spin_unlock(&up->port.lock); + uart_unlock_and_check_sysrq(&up->port); tty_flip_buffer_push(&up->port.state->port); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return ret; @@ -618,16 +575,14 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) static unsigned int serial_omap_tx_empty(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; unsigned int ret = 0; - pm_runtime_get_sync(up->dev); dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + uart_port_unlock_irqrestore(&up->port, flags); + return ret; } @@ -637,10 +592,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) unsigned int status; unsigned int ret = 0; - pm_runtime_get_sync(up->dev); status = check_modem_status(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line); @@ -672,7 +624,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - pm_runtime_get_sync(up->dev); old_mcr = serial_in(up, UART_MCR); old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 | UART_MCR_DTR | UART_MCR_RTS); @@ -688,33 +639,27 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) up->efr &= ~UART_EFR_RTS; serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, lcr); - - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_break_ctl(struct uart_port *port, int break_state) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + uart_port_unlock_irqrestore(&up->port, flags); } static int serial_omap_startup(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; int retval; /* @@ -756,13 +701,13 @@ static int serial_omap_startup(struct uart_port *port) * Now, initialize the UART */ serial_out(up, UART_LCR, UART_LCR_WLEN8); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Most PC uarts need OUT2 raised to enable interrupts. */ up->port.mctrl |= TIOCM_OUT2; serial_omap_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); up->msr_saved_flags = 0; /* @@ -780,8 +725,6 @@ static int serial_omap_startup(struct uart_port *port) serial_out(up, UART_OMAP_WER, up->wer); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return 0; } @@ -789,21 +732,20 @@ static int serial_omap_startup(struct uart_port *port) static void serial_omap_shutdown(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); /* * Disable interrupts from this port */ up->ier = 0; serial_out(up, UART_IER, 0); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->port.mctrl &= ~TIOCM_OUT2; serial_omap_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Disable break condition and FIFOs @@ -817,8 +759,7 @@ static void serial_omap_shutdown(struct uart_port *port) if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + pm_runtime_put_sync(up->dev); free_irq(up->port.irq, up); dev_pm_clear_wake_irq(up->dev); } @@ -833,28 +774,14 @@ static void serial_omap_uart_qos_work(struct work_struct *work) static void serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_omap_port *up = to_uart_omap_port(port); unsigned char cval = 0; - unsigned long flags = 0; + unsigned long flags; unsigned int baud, quot; - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } + cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; @@ -888,8 +815,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - pm_runtime_get_sync(up->dev); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Update the per-port timeout. @@ -1087,9 +1013,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_omap_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + uart_port_unlock_irqrestore(&up->port, flags); dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } @@ -1102,7 +1026,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, efr | UART_EFR_ECB); @@ -1112,9 +1035,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_release_port(struct uart_port *port) @@ -1155,8 +1075,6 @@ serial_omap_type(struct uart_port *port) return up->name; } -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) { unsigned int status, tmout = 10000; @@ -1171,11 +1089,10 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); @@ -1194,11 +1111,8 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) { struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(up->dev); wait_for_xmitr(up); serial_out(up, UART_TX, ch); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static int serial_omap_poll_get_char(struct uart_port *port) @@ -1206,7 +1120,6 @@ static int serial_omap_poll_get_char(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; - pm_runtime_get_sync(up->dev); status = serial_in(up, UART_LSR); if (!(status & UART_LSR_DR)) { status = NO_POLL_CHAR; @@ -1216,9 +1129,6 @@ static int serial_omap_poll_get_char(struct uart_port *port) status = serial_in(up, UART_RX); out: - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - return status; } @@ -1240,13 +1150,13 @@ static void omap_serial_early_out(struct uart_port *port, int offset, writew(value, port->membase + offset); } -static void omap_serial_early_putc(struct uart_port *port, int c) +static void omap_serial_early_putc(struct uart_port *port, unsigned char c) { unsigned int status; for (;;) { status = omap_serial_early_in(port, UART_LSR); - if ((status & BOTH_EMPTY) == BOTH_EMPTY) + if (uart_lsr_tx_empty(status)) break; cpu_relax(); } @@ -1284,7 +1194,7 @@ static struct uart_omap_port *serial_omap_console_ports[OMAP_MAX_HSUART_PORTS]; static struct uart_driver serial_omap_reg; -static void serial_omap_console_putchar(struct uart_port *port, int ch) +static void serial_omap_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_omap_port *up = to_uart_omap_port(port); @@ -1301,15 +1211,10 @@ serial_omap_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; - pm_runtime_get_sync(up->dev); - - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&up->port.lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock(&up->port.lock); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -1335,11 +1240,8 @@ serial_omap_console_write(struct console *co, const char *s, if (up->msr_saved_flags) check_modem_status(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init @@ -1389,38 +1291,23 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up) /* Enable or disable the rs485 support */ static int -serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) +serial_omap_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) { struct uart_omap_port *up = to_uart_omap_port(port); unsigned int mode; int val; - pm_runtime_get_sync(up->dev); - /* Disable interrupts from this port */ mode = up->ier; up->ier = 0; serial_out(up, UART_IER, 0); - /* Clamp the delays to [0, 100ms] */ - rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); - rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); - - /* store new config */ - port->rs485 = *rs485; - - /* - * Just as a precaution, only allow rs485 - * to be enabled if the gpio pin is valid - */ - if (up->rts_gpiod) { - /* enable / disable rts */ - val = (port->rs485.flags & SER_RS485_ENABLED) ? - SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; - val = (port->rs485.flags & val) ? 1 : 0; - gpiod_set_value(up->rts_gpiod, val); - } else - port->rs485.flags &= ~SER_RS485_ENABLED; + /* enable / disable rts */ + val = (rs485->flags & SER_RS485_ENABLED) ? + SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; + val = (rs485->flags & val) ? 1 : 0; + gpiod_set_value(up->rts_gpiod, val); /* Enable interrupts */ up->ier = mode; @@ -1429,15 +1316,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) /* If RS-485 is disabled, make sure the THR interrupt is fired when * TX FIFO is below the trigger level. */ - if (!(port->rs485.flags & SER_RS485_ENABLED) && + if (!(rs485->flags & SER_RS485_ENABLED) && (up->scr & OMAP_UART_SCR_TX_EMPTY)) { up->scr &= ~OMAP_UART_SCR_TX_EMPTY; serial_out(up, UART_OMAP_SCR, up->scr); } - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - return 0; } @@ -1594,6 +1478,13 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) return omap_up_info; } +static const struct serial_rs485 serial_omap_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int serial_omap_probe_rs485(struct uart_omap_port *up, struct device *dev) { @@ -1608,6 +1499,9 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, if (!np) return 0; + up->port.rs485_config = serial_omap_config_rs485; + up->port.rs485_supported = serial_omap_rs485_supported; + ret = uart_get_rs485_mode(&up->port); if (ret) return ret; @@ -1628,11 +1522,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, ret = PTR_ERR(up->rts_gpiod); if (ret == -EPROBE_DEFER) return ret; - /* - * FIXME: the code historically ignored any other error than - * -EPROBE_DEFER and just went on without GPIO. - */ + up->rts_gpiod = NULL; + up->port.rs485_supported = (const struct serial_rs485) { }; + if (rs485conf->flags & SER_RS485_ENABLED) { + dev_err(dev, "disabling RS-485 (rts-gpio missing in device tree)\n"); + memset(rs485conf, 0, sizeof(*rs485conf)); + } } else { gpiod_set_consumer_name(up->rts_gpiod, "omap-serial"); } @@ -1668,8 +1564,7 @@ static int serial_omap_probe(struct platform_device *pdev) if (!up) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(base)) return PTR_ERR(base); @@ -1707,16 +1602,11 @@ static int serial_omap_probe(struct platform_device *pdev) dev_info(up->port.dev, "no wakeirq for uart%d\n", up->port.line); - ret = serial_omap_probe_rs485(up, &pdev->dev); - if (ret < 0) - goto err_rs485; - sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; up->port.membase = base; up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; - up->port.rs485_config = serial_omap_config_rs485; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, @@ -1724,6 +1614,10 @@ static int serial_omap_probe(struct platform_device *pdev) DEFAULT_CLK_SPEED); } + ret = serial_omap_probe_rs485(up, &pdev->dev); + if (ret < 0) + goto err_rs485; + up->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; up->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; cpu_latency_qos_add_request(&up->pm_qos_request, up->latency); @@ -1734,11 +1628,7 @@ static int serial_omap_probe(struct platform_device *pdev) omap_up_info->autosuspend_timeout = -1; device_init_wakeup(up->dev, true); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, - omap_up_info->autosuspend_timeout); - pm_runtime_irq_safe(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); @@ -1752,12 +1642,9 @@ static int serial_omap_probe(struct platform_device *pdev) if (ret != 0) goto err_add_port; - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); return 0; err_add_port: - pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); cpu_latency_qos_remove_request(&up->pm_qos_request); @@ -1767,7 +1654,7 @@ err_port_line: return ret; } -static int serial_omap_remove(struct platform_device *dev) +static void serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); @@ -1775,13 +1662,10 @@ static int serial_omap_remove(struct platform_device *dev) uart_remove_one_port(&serial_omap_reg, &up->port); - pm_runtime_dont_use_autosuspend(up->dev); pm_runtime_put_sync(up->dev); pm_runtime_disable(up->dev); cpu_latency_qos_remove_request(&up->pm_qos_request); device_init_wakeup(&dev->dev, false); - - return 0; } /* diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index c149f8c30007..0542882cfbbe 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -12,6 +12,7 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -62,6 +63,9 @@ #define OWL_UART_STAT_TRFL_MASK GENMASK(16, 11) #define OWL_UART_STAT_UTBB BIT(17) +#define OWL_UART_POLL_USEC 5 +#define OWL_UART_TIMEOUT_USEC 10000 + static struct uart_driver owl_uart_driver; struct owl_uart_info { @@ -121,12 +125,12 @@ static unsigned int owl_uart_tx_empty(struct uart_port *port) u32 val; unsigned int ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = owl_uart_read(port, OWL_UART_STAT); ret = (val & OWL_UART_STAT_TFES) ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return ret; } @@ -177,35 +181,11 @@ static void owl_uart_start_tx(struct uart_port *port) static void owl_uart_send_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int ch; - - if (uart_tx_stopped(port)) - return; - - if (port->x_char) { - while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) - cpu_relax(); - owl_uart_write(port, port->x_char, OWL_UART_TXDAT); - port->icount.tx++; - port->x_char = 0; - } - - while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) { - if (uart_circ_empty(xmit)) - break; - - ch = xmit->buf[xmit->tail]; - owl_uart_write(port, ch, OWL_UART_TXDAT); - xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + u8 ch; - if (uart_circ_empty(xmit)) - owl_uart_stop_tx(port); + uart_port_tx(port, ch, + !(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU), + owl_uart_write(port, ch, OWL_UART_TXDAT)); } static void owl_uart_receive_chars(struct uart_port *port) @@ -219,6 +199,7 @@ static void owl_uart_receive_chars(struct uart_port *port) stat = owl_uart_read(port, OWL_UART_STAT); while (!(stat & OWL_UART_STAT_RFEM)) { char flag = TTY_NORMAL; + bool sysrq; if (stat & OWL_UART_STAT_RXER) port->icount.overrun++; @@ -237,24 +218,23 @@ static void owl_uart_receive_chars(struct uart_port *port) val = owl_uart_read(port, OWL_UART_RXDAT); val &= 0xff; - if ((stat & port->ignore_status_mask) == 0) + sysrq = uart_prepare_sysrq_char(port, val); + + if (!sysrq && (stat & port->ignore_status_mask) == 0) tty_insert_flip_char(&port->state->port, val, flag); stat = owl_uart_read(port, OWL_UART_STAT); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static irqreturn_t owl_uart_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; - unsigned long flags; u32 stat; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock(port); stat = owl_uart_read(port, OWL_UART_STAT); @@ -268,7 +248,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id) stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP; owl_uart_write(port, stat, OWL_UART_STAT); - spin_unlock_irqrestore(&port->lock, flags); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -278,14 +258,14 @@ static void owl_uart_shutdown(struct uart_port *port) u32 val; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = owl_uart_read(port, OWL_UART_CTL); val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_RXIE | OWL_UART_CTL_TXDE | OWL_UART_CTL_RXDE | OWL_UART_CTL_EN); owl_uart_write(port, val, OWL_UART_CTL); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); free_irq(port->irq, port); } @@ -301,7 +281,7 @@ static int owl_uart_startup(struct uart_port *port) if (ret) return ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = owl_uart_read(port, OWL_UART_STAT); val |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP @@ -313,7 +293,7 @@ static int owl_uart_startup(struct uart_port *port) val |= OWL_UART_CTL_EN; owl_uart_write(port, val, OWL_UART_CTL); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -326,14 +306,14 @@ static void owl_uart_change_baudrate(struct owl_uart_port *owl_port, static void owl_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct owl_uart_port *owl_port = to_owl_uart_port(port); unsigned int baud; u32 ctl; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ctl = owl_uart_read(port, OWL_UART_CTL); @@ -393,7 +373,7 @@ static void owl_uart_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void owl_uart_release_port(struct uart_port *port) @@ -461,6 +441,36 @@ static void owl_uart_config_port(struct uart_port *port, int flags) } } +#ifdef CONFIG_CONSOLE_POLL + +static int owl_uart_poll_get_char(struct uart_port *port) +{ + if (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_RFEM) + return NO_POLL_CHAR; + + return owl_uart_read(port, OWL_UART_RXDAT); +} + +static void owl_uart_poll_put_char(struct uart_port *port, unsigned char ch) +{ + u32 reg; + int ret; + + /* Wait while FIFO is full or timeout */ + ret = readl_poll_timeout_atomic(port->membase + OWL_UART_STAT, reg, + !(reg & OWL_UART_STAT_TFFU), + OWL_UART_POLL_USEC, + OWL_UART_TIMEOUT_USEC); + if (ret == -ETIMEDOUT) { + dev_err(port->dev, "Timeout waiting while UART TX FULL\n"); + return; + } + + owl_uart_write(port, ch, OWL_UART_TXDAT); +} + +#endif /* CONFIG_CONSOLE_POLL */ + static const struct uart_ops owl_uart_ops = { .set_mctrl = owl_uart_set_mctrl, .get_mctrl = owl_uart_get_mctrl, @@ -476,11 +486,15 @@ static const struct uart_ops owl_uart_ops = { .request_port = owl_uart_request_port, .release_port = owl_uart_release_port, .verify_port = owl_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = owl_uart_poll_get_char, + .poll_put_char = owl_uart_poll_put_char, +#endif }; #ifdef CONFIG_SERIAL_OWL_CONSOLE -static void owl_console_putchar(struct uart_port *port, int ch) +static void owl_console_putchar(struct uart_port *port, unsigned char ch) { if (!port->membase) return; @@ -496,18 +510,12 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, { u32 old_ctl, val; unsigned long flags; - int locked; + int locked = 1; - local_irq_save(flags); - - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&port->lock); - else { - spin_lock(&port->lock); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); old_ctl = owl_uart_read(port, OWL_UART_CTL); val = old_ctl | OWL_UART_CTL_TRFS_TX; @@ -529,9 +537,7 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, owl_uart_write(port, old_ctl, OWL_UART_CTL); if (locked) - spin_unlock(&port->lock); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void owl_uart_console_write(struct console *co, const char *s, @@ -695,6 +701,7 @@ static int owl_uart_probe(struct platform_device *pdev) owl_port->port.uartclk = clk_get_rate(owl_port->clk); if (owl_port->port.uartclk == 0) { dev_err(&pdev->dev, "clock rate is zero\n"); + clk_disable_unprepare(owl_port->clk); return -EINVAL; } owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY; @@ -712,15 +719,13 @@ static int owl_uart_probe(struct platform_device *pdev) return ret; } -static int owl_uart_remove(struct platform_device *pdev) +static void owl_uart_remove(struct platform_device *pdev) { struct owl_uart_port *owl_port = platform_get_drvdata(pdev); uart_remove_one_port(&owl_uart_driver, &owl_port->port); owl_uart_ports[pdev->id] = NULL; clk_disable_unprepare(owl_port->clk); - - return 0; } static struct platform_driver owl_uart_platform_driver = { @@ -756,4 +761,5 @@ static void __exit owl_uart_exit(void) module_init(owl_uart_init); module_exit(owl_uart_exit); +MODULE_DESCRIPTION("Actions Semi Owl family serial console"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 40fa7a27722d..884fefbfd5a1 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -3,6 +3,7 @@ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. */ #include <linux/kernel.h> +#include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/slab.h> #include <linux/module.h> @@ -189,8 +190,6 @@ enum { #define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) #define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - #define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */ #define CMITC_UARTCLK 192000000 /* 192.0000 MHz */ #define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ @@ -236,12 +235,8 @@ struct eg20t_port { void *rx_buf_virt; dma_addr_t rx_buf_dma; - struct dentry *debugfs; #define IRQ_NAME_SIZE 17 char irq_name[IRQ_NAME_SIZE]; - - /* protect the eg20t_port private structure and io access to membase */ - spinlock_t lock; }; /** @@ -292,8 +287,6 @@ static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 }; static const int trigger_level_1[4] = { 1, 1, 1, 1 }; -#ifdef CONFIG_DEBUG_FS - #define PCH_REGS_BUFSIZE 1024 @@ -353,7 +346,6 @@ static const struct file_operations port_regs_ops = { .read = port_show_regs, .llseek = default_llseek, }; -#endif /* CONFIG_DEBUG_FS */ static const struct dmi_system_id pch_uart_dmi_table[] = { { @@ -554,18 +546,6 @@ static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) return (u8)msr; } -static void pch_uart_hal_write(struct eg20t_port *priv, - const unsigned char *buf, int tx_size) -{ - int i; - unsigned int thr; - - for (i = 0; i < tx_size;) { - thr = buf[i++]; - iowrite8(thr, priv->membase + PCH_UART_THR); - } -} - static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, int rx_size) { @@ -584,7 +564,7 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, if (uart_handle_break(port)) continue; } - if (uart_handle_sysrq_char(port, rbr)) + if (uart_prepare_sysrq_char(port, rbr)) continue; buf[i++] = rbr; @@ -616,32 +596,14 @@ static void pch_uart_hal_set_break(struct eg20t_port *priv, int on) iowrite8(lcr, priv->membase + UART_LCR); } -static int push_rx(struct eg20t_port *priv, const unsigned char *buf, - int size) +static void push_rx(struct eg20t_port *priv, const unsigned char *buf, + int size) { struct uart_port *port = &priv->port; struct tty_port *tport = &port->state->port; tty_insert_flip_string(tport, buf, size); tty_flip_buffer_push(tport); - - return 0; -} - -static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) -{ - int ret = 0; - struct uart_port *port = &priv->port; - - if (port->x_char) { - dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n", - __func__, port->x_char, jiffies); - buf[0] = port->x_char; - port->x_char = 0; - ret = 1; - } - - return ret; } static int dma_push_rx(struct eg20t_port *priv, int size) @@ -727,6 +689,7 @@ static void pch_request_dma(struct uart_port *port) if (!chan) { dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n", __func__); + pci_dev_put(dma_dev); return; } priv->chan_tx = chan; @@ -743,6 +706,7 @@ static void pch_request_dma(struct uart_port *port) __func__); dma_release_channel(priv->chan_tx); priv->chan_tx = NULL; + pci_dev_put(dma_dev); return; } @@ -750,6 +714,8 @@ static void pch_request_dma(struct uart_port *port) priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize, &priv->rx_buf_dma, GFP_KERNEL); priv->chan_rx = chan; + + pci_dev_put(dma_dev); } static void pch_dma_rx_complete(void *arg) @@ -771,17 +737,14 @@ static void pch_dma_tx_complete(void *arg) { struct eg20t_port *priv = arg; struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; struct scatterlist *sg = priv->sg_tx_p; int i; - for (i = 0; i < priv->nent; i++, sg++) { - xmit->tail += sg_dma_len(sg); - port->icount.tx += sg_dma_len(sg); - } - xmit->tail &= UART_XMIT_SIZE - 1; + for (i = 0; i < priv->nent; i++, sg++) + uart_xmit_advance(port, sg_dma_len(sg)); + async_tx_ack(priv->desc_tx); - dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE); + dma_unmap_sg(port->dev, priv->sg_tx_p, priv->orig_nent, DMA_TO_DEVICE); priv->tx_dma_use = 0; priv->nent = 0; priv->orig_nent = 0; @@ -789,36 +752,11 @@ static void pch_dma_tx_complete(void *arg) pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); } -static int pop_tx(struct eg20t_port *priv, int size) -{ - int count = 0; - struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; - - if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size) - goto pop_tx_end; - - do { - int cnt_to_end = - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - int sz = min(size - count, cnt_to_end); - pch_uart_hal_write(priv, &xmit->buf[xmit->tail], sz); - xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1); - count += sz; - } while (!uart_circ_empty(xmit) && count < size); - -pop_tx_end: - dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n", - count, size - count, jiffies); - - return count; -} - static int handle_rx_to(struct eg20t_port *priv) { struct pch_uart_buffer *buf; int rx_size; - int ret; + if (!priv->start_rx) { pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | PCH_UART_HAL_RX_ERR_INT); @@ -827,19 +765,12 @@ static int handle_rx_to(struct eg20t_port *priv) buf = &priv->rxbuf; do { rx_size = pch_uart_hal_read(priv, buf->buf, buf->size); - ret = push_rx(priv, buf->buf, rx_size); - if (ret) - return 0; + push_rx(priv, buf->buf, rx_size); } while (rx_size == buf->size); return PCH_UART_HANDLED_RX_INT; } -static int handle_rx(struct eg20t_port *priv) -{ - return handle_rx_to(priv); -} - static int dma_handle_rx(struct eg20t_port *priv) { struct uart_port *port = &priv->port; @@ -877,10 +808,8 @@ static int dma_handle_rx(struct eg20t_port *priv) static unsigned int handle_tx(struct eg20t_port *priv) { struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; + unsigned char ch; int fifo_size; - int tx_size; - int size; int tx_empty; if (!priv->start_tx) { @@ -893,19 +822,18 @@ static unsigned int handle_tx(struct eg20t_port *priv) fifo_size = max(priv->fifo_size, 1); tx_empty = 1; - if (pop_tx_x(priv, xmit->buf)) { - pch_uart_hal_write(priv, xmit->buf, 1); + if (port->x_char) { + iowrite8(port->x_char, priv->membase + PCH_UART_THR); port->icount.tx++; + port->x_char = 0; tx_empty = 0; fifo_size--; } - size = min(xmit->head - xmit->tail, fifo_size); - if (size < 0) - size = fifo_size; - tx_size = pop_tx(priv, size); - if (tx_size > 0) { - port->icount.tx += tx_size; + while (!uart_tx_stopped(port) && fifo_size && + uart_fifo_get(port, &ch)) { + iowrite8(ch, priv->membase + PCH_UART_THR); + fifo_size--; tx_empty = 0; } @@ -922,14 +850,14 @@ static unsigned int handle_tx(struct eg20t_port *priv) static unsigned int dma_handle_tx(struct eg20t_port *priv) { struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct scatterlist *sg; int nent; int fifo_size; struct dma_async_tx_descriptor *desc; + unsigned int bytes, tail; int num; int i; - int bytes; int size; int rem; @@ -950,15 +878,15 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) } fifo_size = max(priv->fifo_size, 1); - if (pop_tx_x(priv, xmit->buf)) { - pch_uart_hal_write(priv, xmit->buf, 1); + + if (port->x_char) { + iowrite8(port->x_char, priv->membase + PCH_UART_THR); port->icount.tx++; + port->x_char = 0; fifo_size--; } - bytes = min((int)CIRC_CNT(xmit->head, xmit->tail, - UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, - xmit->tail, UART_XMIT_SIZE)); + bytes = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); if (!bytes) { dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__); pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); @@ -981,7 +909,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->tx_dma_use = 1; - priv->sg_tx_p = kcalloc(num, sizeof(struct scatterlist), GFP_ATOMIC); + priv->sg_tx_p = kmalloc_array(num, sizeof(struct scatterlist), GFP_ATOMIC); if (!priv->sg_tx_p) { dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__); return 0; @@ -992,10 +920,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) for (i = 0; i < num; i++, sg++) { if (i == (num - 1)) - sg_set_page(sg, virt_to_page(xmit->buf), + sg_set_page(sg, virt_to_page(tport->xmit_buf), rem, fifo_size * i); else - sg_set_page(sg, virt_to_page(xmit->buf), + sg_set_page(sg, virt_to_page(tport->xmit_buf), size, fifo_size * i); } @@ -1009,8 +937,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->nent = nent; for (i = 0; i < nent; i++, sg++) { - sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) + - fifo_size * i; + sg->offset = tail + fifo_size * i; sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + sg->offset; if (i == (nent - 1)) @@ -1027,7 +954,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) __func__); return 0; } - dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE); + dma_sync_sg_for_device(port->dev, priv->sg_tx_p, num, DMA_TO_DEVICE); priv->desc_tx = desc; desc->callback = pch_dma_tx_complete; desc->callback_param = priv; @@ -1079,11 +1006,10 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) u8 lsr; int ret = 0; unsigned char iid; - unsigned long flags; int next = 1; u8 msr; - spin_lock_irqsave(&priv->lock, flags); + uart_port_lock(&priv->port); handled = 0; while (next) { iid = pch_uart_hal_get_iid(priv); @@ -1111,7 +1037,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) PCH_UART_HAL_RX_INT | PCH_UART_HAL_RX_ERR_INT); } else { - ret = handle_rx(priv); + ret = handle_rx_to(priv); } break; case PCH_UART_IID_RDR_TO: /* Received Data Ready @@ -1143,7 +1069,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) handled |= (unsigned int)ret; } - spin_unlock_irqrestore(&priv->lock, flags); + uart_unlock_and_check_sysrq(&priv->port); return IRQ_RETVAL(handled); } @@ -1254,9 +1180,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl) unsigned long flags; priv = container_of(port, struct eg20t_port, port); - spin_lock_irqsave(&priv->lock, flags); + uart_port_lock_irqsave(&priv->port, &flags); pch_uart_hal_set_break(priv, ctl); - spin_unlock_irqrestore(&priv->lock, flags); + uart_port_unlock_irqrestore(&priv->port, flags); } /* Grab any interrupt resources and initialise any low level driver state. */ @@ -1359,7 +1285,8 @@ static void pch_uart_shutdown(struct uart_port *port) *bits. Update read_status_mask and ignore_status_mask to indicate *the types of events we are interested in receiving. */ static void pch_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { int rtn; unsigned int baud, parity, bits, stb; @@ -1405,8 +1332,7 @@ static void pch_uart_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - spin_lock_irqsave(&priv->lock, flags); - spin_lock(&port->lock); + uart_port_lock_irqsave(port, &flags); uart_update_timeout(port, termios->c_cflag, baud); rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); @@ -1419,8 +1345,7 @@ static void pch_uart_set_termios(struct uart_port *port, tty_termios_encode_baud_rate(termios, baud, baud); out: - spin_unlock(&port->lock); - spin_unlock_irqrestore(&priv->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *pch_uart_type(struct uart_port *port) @@ -1573,7 +1498,7 @@ static void pch_uart_put_poll_char(struct uart_port *port, * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(priv, BOTH_EMPTY); + wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1590,7 +1515,6 @@ static const struct uart_ops pch_uart_ops = { .startup = pch_uart_startup, .shutdown = pch_uart_shutdown, .set_termios = pch_uart_set_termios, -/* .pm = pch_uart_pm, Not supported yet */ .type = pch_uart_type, .release_port = pch_uart_release_port, .request_port = pch_uart_request_port, @@ -1604,7 +1528,7 @@ static const struct uart_ops pch_uart_ops = { #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE -static void pch_console_putchar(struct uart_port *port, int ch) +static void pch_console_putchar(struct uart_port *port, unsigned char ch) { struct eg20t_port *priv = container_of(port, struct eg20t_port, port); @@ -1624,27 +1548,17 @@ pch_console_write(struct console *co, const char *s, unsigned int count) { struct eg20t_port *priv; unsigned long flags; - int priv_locked = 1; - int port_locked = 1; + int locked = 1; u8 ier; priv = pch_uart_ports[co->index]; touch_nmi_watchdog(); - local_irq_save(flags); - if (priv->port.sysrq) { - /* call to uart_handle_sysrq_char already took the priv lock */ - priv_locked = 0; - /* serial8250_handle_port() already took the port lock */ - port_locked = 0; - } else if (oops_in_progress) { - priv_locked = spin_trylock(&priv->lock); - port_locked = spin_trylock(&priv->port.lock); - } else { - spin_lock(&priv->lock); - spin_lock(&priv->port.lock); - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&priv->port, &flags); + else + uart_port_lock_irqsave(&priv->port, &flags); /* * First save the IER then disable the interrupts @@ -1659,14 +1573,11 @@ pch_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore the IER */ - wait_for_xmitr(priv, BOTH_EMPTY); + wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); - if (port_locked) - spin_unlock(&priv->port.lock); - if (priv_locked) - spin_unlock(&priv->lock); - local_irq_restore(flags); + if (locked) + uart_port_unlock_irqrestore(&priv->port, flags); } static int __init pch_console_setup(struct console *co, char *options) @@ -1735,9 +1646,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int fifosize; int port_type; struct pch_uart_driver_data *board; -#ifdef CONFIG_DEBUG_FS - char name[32]; /* for debugfs file name */ -#endif + char name[32]; board = &drv_dat[id->driver_data]; port_type = board->port_type; @@ -1765,8 +1674,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, pci_enable_msi(pdev); pci_set_master(pdev); - spin_lock_init(&priv->lock); - iobase = pci_resource_start(pdev, 0); mapbase = pci_resource_start(pdev, 1); priv->mapbase = mapbase; @@ -1796,8 +1703,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d", priv->port.line); - spin_lock_init(&priv->port.lock); - pci_set_drvdata(pdev, priv); priv->trigger_level = 1; priv->fcr = 0; @@ -1813,11 +1718,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (ret < 0) goto init_port_hal_free; -#ifdef CONFIG_DEBUG_FS - snprintf(name, sizeof(name), "uart%d_regs", board->line_no); - priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO, - NULL, priv, &port_regs_ops); -#endif + snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); + debugfs_create_file(name, S_IFREG | S_IRUGO, NULL, priv, + &port_regs_ops); return priv; @@ -1835,10 +1738,10 @@ init_port_alloc_err: static void pch_uart_exit_port(struct eg20t_port *priv) { + char name[32]; -#ifdef CONFIG_DEBUG_FS - debugfs_remove(priv->debugfs); -#endif + snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); + debugfs_lookup_and_remove(name, NULL); uart_remove_one_port(&pch_uart_driver, &priv->port); free_page((unsigned long)priv->rxbuf.buf); } @@ -1857,41 +1760,24 @@ static void pch_uart_pci_remove(struct pci_dev *pdev) kfree(priv); return; } -#ifdef CONFIG_PM -static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state) + +static int __maybe_unused pch_uart_pci_suspend(struct device *dev) { - struct eg20t_port *priv = pci_get_drvdata(pdev); + struct eg20t_port *priv = dev_get_drvdata(dev); uart_suspend_port(&pch_uart_driver, &priv->port); - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int pch_uart_pci_resume(struct pci_dev *pdev) +static int __maybe_unused pch_uart_pci_resume(struct device *dev) { - struct eg20t_port *priv = pci_get_drvdata(pdev); - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, - "%s-pci_enable_device failed(ret=%d) ", __func__, ret); - return ret; - } + struct eg20t_port *priv = dev_get_drvdata(dev); uart_resume_port(&pch_uart_driver, &priv->port); return 0; } -#else -#define pch_uart_pci_suspend NULL -#define pch_uart_pci_resume NULL -#endif static const struct pci_device_id pch_uart_pci_id[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811), @@ -1945,13 +1831,16 @@ probe_error: return ret; } +static SIMPLE_DEV_PM_OPS(pch_uart_pci_pm_ops, + pch_uart_pci_suspend, + pch_uart_pci_resume); + static struct pci_driver pch_uart_pci_driver = { .name = "pch_uart", .id_table = pch_uart_pci_id, .probe = pch_uart_pci_probe, .remove = pch_uart_pci_remove, - .suspend = pch_uart_pci_suspend, - .resume = pch_uart_pci_resume, + .driver.pm = &pch_uart_pci_pm_ops, }; static int __init pch_uart_module_init(void) diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 0a12fb11e698..14d50bd7f1bd 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -8,12 +8,11 @@ * Sorin-Andrei Pistirica <andrei.pistirica@microchip.com> */ +#include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_irq.h> -#include <linux/of_gpio.h> #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> @@ -25,13 +24,105 @@ #include <linux/delay.h> #include <asm/mach-pic32/pic32.h> -#include "pic32_uart.h" /* UART name and device definitions */ #define PIC32_DEV_NAME "pic32-uart" #define PIC32_MAX_UARTS 6 #define PIC32_SDEV_NAME "ttyPIC" +#define PIC32_UART_DFLT_BRATE 9600 +#define PIC32_UART_TX_FIFO_DEPTH 8 +#define PIC32_UART_RX_FIFO_DEPTH 8 + +#define PIC32_UART_MODE 0x00 +#define PIC32_UART_STA 0x10 +#define PIC32_UART_TX 0x20 +#define PIC32_UART_RX 0x30 +#define PIC32_UART_BRG 0x40 + +/* struct pic32_sport - pic32 serial port descriptor + * @port: uart port descriptor + * @idx: port index + * @irq_fault: virtual fault interrupt number + * @irq_fault_name: irq fault name + * @irq_rx: virtual rx interrupt number + * @irq_rx_name: irq rx name + * @irq_tx: virtual tx interrupt number + * @irq_tx_name: irq tx name + * @cts_gpiod: clear to send GPIO + * @dev: device descriptor + **/ +struct pic32_sport { + struct uart_port port; + int idx; + + int irq_fault; + const char *irq_fault_name; + int irq_rx; + const char *irq_rx_name; + int irq_tx; + const char *irq_tx_name; + bool enable_tx_irq; + + struct gpio_desc *cts_gpiod; + + struct clk *clk; + + struct device *dev; +}; + +static inline struct pic32_sport *to_pic32_sport(struct uart_port *port) +{ + return container_of(port, struct pic32_sport, port); +} + +static inline void pic32_uart_writel(struct pic32_sport *sport, + u32 reg, u32 val) +{ + __raw_writel(val, sport->port.membase + reg); +} + +static inline u32 pic32_uart_readl(struct pic32_sport *sport, u32 reg) +{ + return __raw_readl(sport->port.membase + reg); +} + +/* pic32 uart mode register bits */ +#define PIC32_UART_MODE_ON BIT(15) +#define PIC32_UART_MODE_FRZ BIT(14) +#define PIC32_UART_MODE_SIDL BIT(13) +#define PIC32_UART_MODE_IREN BIT(12) +#define PIC32_UART_MODE_RTSMD BIT(11) +#define PIC32_UART_MODE_RESV1 BIT(10) +#define PIC32_UART_MODE_UEN1 BIT(9) +#define PIC32_UART_MODE_UEN0 BIT(8) +#define PIC32_UART_MODE_WAKE BIT(7) +#define PIC32_UART_MODE_LPBK BIT(6) +#define PIC32_UART_MODE_ABAUD BIT(5) +#define PIC32_UART_MODE_RXINV BIT(4) +#define PIC32_UART_MODE_BRGH BIT(3) +#define PIC32_UART_MODE_PDSEL1 BIT(2) +#define PIC32_UART_MODE_PDSEL0 BIT(1) +#define PIC32_UART_MODE_STSEL BIT(0) + +/* pic32 uart status register bits */ +#define PIC32_UART_STA_UTXISEL1 BIT(15) +#define PIC32_UART_STA_UTXISEL0 BIT(14) +#define PIC32_UART_STA_UTXINV BIT(13) +#define PIC32_UART_STA_URXEN BIT(12) +#define PIC32_UART_STA_UTXBRK BIT(11) +#define PIC32_UART_STA_UTXEN BIT(10) +#define PIC32_UART_STA_UTXBF BIT(9) +#define PIC32_UART_STA_TRMT BIT(8) +#define PIC32_UART_STA_URXISEL1 BIT(7) +#define PIC32_UART_STA_URXISEL0 BIT(6) +#define PIC32_UART_STA_ADDEN BIT(5) +#define PIC32_UART_STA_RIDLE BIT(4) +#define PIC32_UART_STA_PERR BIT(3) +#define PIC32_UART_STA_FERR BIT(2) +#define PIC32_UART_STA_OERR BIT(1) +#define PIC32_UART_STA_URXDA BIT(0) + /* pic32_sport pointer for console use */ static struct pic32_sport *pic32_sports[PIC32_MAX_UARTS]; @@ -42,23 +133,6 @@ static inline void pic32_wait_deplete_txbuf(struct pic32_sport *sport) udelay(1); } -static inline int pic32_enable_clock(struct pic32_sport *sport) -{ - int ret = clk_prepare_enable(sport->clk); - - if (ret) - return ret; - - sport->ref_clk++; - return 0; -} - -static inline void pic32_disable_clock(struct pic32_sport *sport) -{ - sport->ref_clk--; - clk_disable_unprepare(sport->clk); -} - /* serial core request to check if uart tx buffer is empty */ static unsigned int pic32_uart_tx_empty(struct uart_port *port) { @@ -82,25 +156,16 @@ static void pic32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) PIC32_UART_MODE_LPBK); } -/* get the state of CTS input pin for this port */ -static unsigned int get_cts_state(struct pic32_sport *sport) -{ - /* read and invert UxCTS */ - if (gpio_is_valid(sport->cts_gpio)) - return !gpio_get_value(sport->cts_gpio); - - return 1; -} - /* serial core request to return the state of misc UART input pins */ static unsigned int pic32_uart_get_mctrl(struct uart_port *port) { struct pic32_sport *sport = to_pic32_sport(port); unsigned int mctrl = 0; - if (!sport->hw_flow_ctrl) + /* get the state of CTS input pin for this port */ + if (!sport->cts_gpiod) mctrl |= TIOCM_CTS; - else if (get_cts_state(sport)) + else if (gpiod_get_value(sport->cts_gpiod)) mctrl |= TIOCM_CTS; /* DSR and CD are not supported in PIC32, so return 1 @@ -117,16 +182,16 @@ static unsigned int pic32_uart_get_mctrl(struct uart_port *port) */ static inline void pic32_uart_irqtxen(struct pic32_sport *sport, u8 en) { - if (en && !tx_irq_enabled(sport)) { + if (en && !sport->enable_tx_irq) { enable_irq(sport->irq_tx); - tx_irq_enabled(sport) = 1; - } else if (!en && tx_irq_enabled(sport)) { + sport->enable_tx_irq = true; + } else if (!en && sport->enable_tx_irq) { /* use disable_irq_nosync() and not disable_irq() to avoid self * imposed deadlock by not waiting for irq handler to end, * since this callback is called from interrupt context. */ disable_irq_nosync(sport->irq_tx); - tx_irq_enabled(sport) = 0; + sport->enable_tx_irq = false; } } @@ -178,7 +243,7 @@ static void pic32_uart_break_ctl(struct uart_port *port, int ctl) struct pic32_sport *sport = to_pic32_sport(port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (ctl) pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA), @@ -187,7 +252,7 @@ static void pic32_uart_break_ctl(struct uart_port *port, int ctl) pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), PIC32_UART_STA_UTXBRK); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* get port type in string format */ @@ -209,7 +274,7 @@ static void pic32_uart_do_rx(struct uart_port *port) */ max_count = PIC32_UART_RX_FIFO_DEPTH; - spin_lock(&port->lock); + uart_port_lock(port); tty = &port->state->port; @@ -266,7 +331,7 @@ static void pic32_uart_do_rx(struct uart_port *port) } while (--max_count); - spin_unlock(&port->lock); + uart_port_unlock(port); tty_flip_buffer_push(tty); } @@ -277,7 +342,7 @@ static void pic32_uart_do_rx(struct uart_port *port) static void pic32_uart_do_tx(struct uart_port *port) { struct pic32_sport *sport = to_pic32_sport(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH; if (port->x_char) { @@ -292,7 +357,7 @@ static void pic32_uart_do_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) goto txq_empty; /* keep stuffing chars into uart tx buffer @@ -306,22 +371,20 @@ static void pic32_uart_do_tx(struct uart_port *port) */ while (!(PIC32_UART_STA_UTXBF & pic32_uart_readl(sport, PIC32_UART_STA))) { - unsigned int c = xmit->buf[xmit->tail]; + unsigned char c; + if (!uart_fifo_get(port, &c)) + break; pic32_uart_writel(sport, PIC32_UART_TX, c); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; if (--max_count == 0) break; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) goto txq_empty; return; @@ -346,9 +409,9 @@ static irqreturn_t pic32_uart_tx_interrupt(int irq, void *dev_id) struct uart_port *port = dev_id; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); pic32_uart_do_tx(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return IRQ_HANDLED; } @@ -395,7 +458,7 @@ static int pic32_uart_startup(struct uart_port *port) local_irq_save(flags); - ret = pic32_enable_clock(sport); + ret = clk_prepare_enable(sport->clk); if (ret) { local_irq_restore(flags); goto out_done; @@ -419,7 +482,7 @@ static int pic32_uart_startup(struct uart_port *port) * For each irq request_irq() is called with interrupt disabled. * And the irq is enabled as soon as we are ready to handle them. */ - tx_irq_enabled(sport) = 0; + sport->enable_tx_irq = false; sport->irq_fault_name = kasprintf(GFP_KERNEL, "%s%d-fault", pic32_uart_type(port), @@ -427,11 +490,11 @@ static int pic32_uart_startup(struct uart_port *port) if (!sport->irq_fault_name) { dev_err(port->dev, "%s: kasprintf err!", __func__); ret = -ENOMEM; - goto out_done; + goto out_disable_clk; } irq_set_status_flags(sport->irq_fault, IRQ_NOAUTOEN); ret = request_irq(sport->irq_fault, pic32_uart_fault_interrupt, - sport->irqflags_fault, sport->irq_fault_name, port); + IRQF_NO_THREAD, sport->irq_fault_name, port); if (ret) { dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n", __func__, sport->irq_fault, ret, @@ -449,7 +512,7 @@ static int pic32_uart_startup(struct uart_port *port) } irq_set_status_flags(sport->irq_rx, IRQ_NOAUTOEN); ret = request_irq(sport->irq_rx, pic32_uart_rx_interrupt, - sport->irqflags_rx, sport->irq_rx_name, port); + IRQF_NO_THREAD, sport->irq_rx_name, port); if (ret) { dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n", __func__, sport->irq_rx, ret, @@ -467,7 +530,7 @@ static int pic32_uart_startup(struct uart_port *port) } irq_set_status_flags(sport->irq_tx, IRQ_NOAUTOEN); ret = request_irq(sport->irq_tx, pic32_uart_tx_interrupt, - sport->irqflags_tx, sport->irq_tx_name, port); + IRQF_NO_THREAD, sport->irq_tx_name, port); if (ret) { dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n", __func__, sport->irq_tx, ret, @@ -488,19 +551,23 @@ static int pic32_uart_startup(struct uart_port *port) /* enable all interrupts and eanable uart */ pic32_uart_en_and_unmask(port); + local_irq_restore(flags); + enable_irq(sport->irq_rx); return 0; out_t: - kfree(sport->irq_tx_name); free_irq(sport->irq_tx, port); + kfree(sport->irq_tx_name); out_r: - kfree(sport->irq_rx_name); free_irq(sport->irq_rx, port); + kfree(sport->irq_rx_name); out_f: - kfree(sport->irq_fault_name); free_irq(sport->irq_fault, port); + kfree(sport->irq_fault_name); +out_disable_clk: + clk_disable_unprepare(sport->clk); out_done: return ret; } @@ -512,28 +579,31 @@ static void pic32_uart_shutdown(struct uart_port *port) unsigned long flags; /* disable uart */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); pic32_uart_dsbl_and_mask(port); - spin_unlock_irqrestore(&port->lock, flags); - pic32_disable_clock(sport); + uart_port_unlock_irqrestore(port, flags); + clk_disable_unprepare(sport->clk); /* free all 3 interrupts for this UART */ free_irq(sport->irq_fault, port); + kfree(sport->irq_fault_name); free_irq(sport->irq_tx, port); + kfree(sport->irq_tx_name); free_irq(sport->irq_rx, port); + kfree(sport->irq_rx_name); } /* serial core request to change current uart setting */ static void pic32_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { struct pic32_sport *sport = to_pic32_sport(port); unsigned int baud; unsigned int quot; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* disable uart and mask all interrupts while changing speed */ pic32_uart_dsbl_and_mask(port); @@ -565,7 +635,7 @@ static void pic32_uart_set_termios(struct uart_port *port, PIC32_UART_MODE_PDSEL0); } /* if hw flow ctrl, then the pins must be specified in device tree */ - if ((new->c_cflag & CRTSCTS) && sport->hw_flow_ctrl) { + if ((new->c_cflag & CRTSCTS) && sport->cts_gpiod) { /* enable hardware flow control */ pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), PIC32_UART_MODE_UEN1); @@ -601,7 +671,7 @@ static void pic32_uart_set_termios(struct uart_port *port, /* enable uart */ pic32_uart_en_and_unmask(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* serial core request to claim uart iomem */ @@ -691,7 +761,7 @@ static const struct uart_ops pic32_uart_ops = { #ifdef CONFIG_SERIAL_PIC32_CONSOLE /* output given char */ -static void pic32_console_putchar(struct uart_port *port, int ch) +static void pic32_console_putchar(struct uart_port *port, unsigned char ch) { struct pic32_sport *sport = to_pic32_sport(port); @@ -712,10 +782,9 @@ static void pic32_console_write(struct console *co, const char *s, unsigned int count) { struct pic32_sport *sport = pic32_sports[co->index]; - struct uart_port *port = pic32_get_port(sport); /* call uart helper to deal with \r\n */ - uart_console_write(port, s, count, pic32_console_putchar); + uart_console_write(&sport->port, s, count, pic32_console_putchar); } /* console core request to setup given console, find matching uart @@ -724,7 +793,6 @@ static void pic32_console_write(struct console *co, const char *s, static int pic32_console_setup(struct console *co, char *options) { struct pic32_sport *sport; - struct uart_port *port = NULL; int baud = 115200; int bits = 8; int parity = 'n'; @@ -737,16 +805,15 @@ static int pic32_console_setup(struct console *co, char *options) sport = pic32_sports[co->index]; if (!sport) return -ENODEV; - port = pic32_get_port(sport); - ret = pic32_enable_clock(sport); + ret = clk_prepare_enable(sport->clk); if (ret) return ret; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(&sport->port, co, baud, parity, bits, flow); } static struct uart_driver pic32_uart_driver; @@ -773,7 +840,7 @@ console_initcall(pic32_console_init); */ static int __init pic32_late_console_init(void) { - if (!(pic32_console.flags & CON_ENABLED)) + if (!console_is_registered(&pic32_console)) register_console(&pic32_console); return 0; @@ -795,7 +862,8 @@ static struct uart_driver pic32_uart_driver = { static int pic32_uart_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct pic32_sport *sport; int uart_idx = 0; struct resource *res_mem; @@ -816,41 +884,23 @@ static int pic32_uart_probe(struct platform_device *pdev) sport->idx = uart_idx; sport->irq_fault = irq_of_parse_and_map(np, 0); - sport->irqflags_fault = IRQF_NO_THREAD; sport->irq_rx = irq_of_parse_and_map(np, 1); - sport->irqflags_rx = IRQF_NO_THREAD; sport->irq_tx = irq_of_parse_and_map(np, 2); - sport->irqflags_tx = IRQF_NO_THREAD; sport->clk = devm_clk_get(&pdev->dev, NULL); - sport->cts_gpio = -EINVAL; + if (IS_ERR(sport->clk)) + return PTR_ERR(sport->clk); sport->dev = &pdev->dev; /* Hardware flow control: gpios * !Note: Basically, CTS is needed for reading the status. */ - sport->hw_flow_ctrl = false; - sport->cts_gpio = of_get_named_gpio(np, "cts-gpios", 0); - if (gpio_is_valid(sport->cts_gpio)) { - sport->hw_flow_ctrl = true; - - ret = devm_gpio_request(sport->dev, - sport->cts_gpio, "CTS"); - if (ret) { - dev_err(&pdev->dev, - "error requesting CTS GPIO\n"); - goto err; - } - - ret = gpio_direction_input(sport->cts_gpio); - if (ret) { - dev_err(&pdev->dev, "error setting CTS GPIO\n"); - goto err; - } - } + sport->cts_gpiod = devm_gpiod_get_optional(dev, "cts", GPIOD_IN); + if (IS_ERR(sport->cts_gpiod)) + return dev_err_probe(dev, PTR_ERR(sport->cts_gpiod), "error requesting CTS GPIO\n"); + gpiod_set_consumer_name(sport->cts_gpiod, "CTS"); pic32_sports[uart_idx] = sport; port = &sport->port; - memset(port, 0, sizeof(*port)); port->iotype = UPIO_MEM; port->mapbase = res_mem->start; port->ops = &pic32_uart_ops; @@ -868,11 +918,11 @@ static int pic32_uart_probe(struct platform_device *pdev) } #ifdef CONFIG_SERIAL_PIC32_CONSOLE - if (uart_console(port) && (pic32_console.flags & CON_ENABLED)) { + if (uart_console_registered(port)) { /* The peripheral clock has been enabled by console_setup, * so disable it till the port is used. */ - pic32_disable_clock(sport); + clk_disable_unprepare(sport->clk); } #endif @@ -887,18 +937,15 @@ err: return ret; } -static int pic32_uart_remove(struct platform_device *pdev) +static void pic32_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct pic32_sport *sport = to_pic32_sport(port); uart_remove_one_port(&pic32_uart_driver, port); - pic32_disable_clock(sport); + clk_disable_unprepare(sport->clk); platform_set_drvdata(pdev, NULL); pic32_sports[sport->idx] = NULL; - - /* automatic unroll of sport and gpios */ - return 0; } static const struct of_device_id pic32_serial_dt_ids[] = { diff --git a/drivers/tty/serial/pic32_uart.h b/drivers/tty/serial/pic32_uart.h deleted file mode 100644 index b15639cc336b..000000000000 --- a/drivers/tty/serial/pic32_uart.h +++ /dev/null @@ -1,125 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * PIC32 Integrated Serial Driver. - * - * Copyright (C) 2015 Microchip Technology, Inc. - * - * Authors: - * Sorin-Andrei Pistirica <andrei.pistirica@microchip.com> - */ -#ifndef __DT_PIC32_UART_H__ -#define __DT_PIC32_UART_H__ - -#define PIC32_UART_DFLT_BRATE (9600) -#define PIC32_UART_TX_FIFO_DEPTH (8) -#define PIC32_UART_RX_FIFO_DEPTH (8) - -#define PIC32_UART_MODE 0x00 -#define PIC32_UART_STA 0x10 -#define PIC32_UART_TX 0x20 -#define PIC32_UART_RX 0x30 -#define PIC32_UART_BRG 0x40 - -struct pic32_console_opt { - int baud; - int parity; - int bits; - int flow; -}; - -/* struct pic32_sport - pic32 serial port descriptor - * @port: uart port descriptor - * @idx: port index - * @irq_fault: virtual fault interrupt number - * @irqflags_fault: flags related to fault irq - * @irq_fault_name: irq fault name - * @irq_rx: virtual rx interrupt number - * @irqflags_rx: flags related to rx irq - * @irq_rx_name: irq rx name - * @irq_tx: virtual tx interrupt number - * @irqflags_tx: : flags related to tx irq - * @irq_tx_name: irq tx name - * @cts_gpio: clear to send gpio - * @dev: device descriptor - **/ -struct pic32_sport { - struct uart_port port; - struct pic32_console_opt opt; - int idx; - - int irq_fault; - int irqflags_fault; - const char *irq_fault_name; - int irq_rx; - int irqflags_rx; - const char *irq_rx_name; - int irq_tx; - int irqflags_tx; - const char *irq_tx_name; - u8 enable_tx_irq; - - bool hw_flow_ctrl; - int cts_gpio; - - int ref_clk; - struct clk *clk; - - struct device *dev; -}; -#define to_pic32_sport(c) container_of(c, struct pic32_sport, port) -#define pic32_get_port(sport) (&sport->port) -#define pic32_get_opt(sport) (&sport->opt) -#define tx_irq_enabled(sport) (sport->enable_tx_irq) - -static inline void pic32_uart_writel(struct pic32_sport *sport, - u32 reg, u32 val) -{ - struct uart_port *port = pic32_get_port(sport); - - __raw_writel(val, port->membase + reg); -} - -static inline u32 pic32_uart_readl(struct pic32_sport *sport, u32 reg) -{ - struct uart_port *port = pic32_get_port(sport); - - return __raw_readl(port->membase + reg); -} - -/* pic32 uart mode register bits */ -#define PIC32_UART_MODE_ON BIT(15) -#define PIC32_UART_MODE_FRZ BIT(14) -#define PIC32_UART_MODE_SIDL BIT(13) -#define PIC32_UART_MODE_IREN BIT(12) -#define PIC32_UART_MODE_RTSMD BIT(11) -#define PIC32_UART_MODE_RESV1 BIT(10) -#define PIC32_UART_MODE_UEN1 BIT(9) -#define PIC32_UART_MODE_UEN0 BIT(8) -#define PIC32_UART_MODE_WAKE BIT(7) -#define PIC32_UART_MODE_LPBK BIT(6) -#define PIC32_UART_MODE_ABAUD BIT(5) -#define PIC32_UART_MODE_RXINV BIT(4) -#define PIC32_UART_MODE_BRGH BIT(3) -#define PIC32_UART_MODE_PDSEL1 BIT(2) -#define PIC32_UART_MODE_PDSEL0 BIT(1) -#define PIC32_UART_MODE_STSEL BIT(0) - -/* pic32 uart status register bits */ -#define PIC32_UART_STA_UTXISEL1 BIT(15) -#define PIC32_UART_STA_UTXISEL0 BIT(14) -#define PIC32_UART_STA_UTXINV BIT(13) -#define PIC32_UART_STA_URXEN BIT(12) -#define PIC32_UART_STA_UTXBRK BIT(11) -#define PIC32_UART_STA_UTXEN BIT(10) -#define PIC32_UART_STA_UTXBF BIT(9) -#define PIC32_UART_STA_TRMT BIT(8) -#define PIC32_UART_STA_URXISEL1 BIT(7) -#define PIC32_UART_STA_URXISEL0 BIT(6) -#define PIC32_UART_STA_ADDEN BIT(5) -#define PIC32_UART_STA_RIDLE BIT(4) -#define PIC32_UART_STA_PERR BIT(3) -#define PIC32_UART_STA_FERR BIT(2) -#define PIC32_UART_STA_OERR BIT(1) -#define PIC32_UART_STA_URXDA BIT(0) - -#endif /* __DT_PIC32_UART_H__ */ diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index ba65a3bbd72a..e3a919328695 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -24,7 +24,6 @@ */ #undef DEBUG -#undef DEBUG_HARD #undef USE_CTRL_O_SYSRQ #include <linux/module.h> @@ -47,14 +46,12 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <asm/sections.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #ifdef CONFIG_PPC_PMAC -#include <asm/prom.h> #include <asm/machdep.h> #include <asm/pmac_feature.h> -#include <asm/dbdma.h> #include <asm/macio.h> #else #include <linux/platform_device.h> @@ -66,10 +63,6 @@ #include "pmac_zilog.h" -/* Not yet implemented */ -#undef HAS_DBDMA - -static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports."); MODULE_LICENSE("GPL"); @@ -213,10 +206,10 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) } static bool pmz_receive_chars(struct uart_pmac_port *uap) + __must_hold(&uap->port.lock) { struct tty_port *port; unsigned char ch, r1, drop, flag; - int loops = 0; /* Sanity check, make sure the old bug is no longer happening */ if (uap->port.state == NULL) { @@ -252,9 +245,9 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) #endif /* USE_CTRL_O_SYSRQ */ if (uap->port.sysrq) { int swallow; - spin_unlock(&uap->port.lock); + uart_port_unlock(&uap->port); swallow = uart_handle_sysrq_char(&uap->port, ch); - spin_lock(&uap->port.lock); + uart_port_lock(&uap->port); if (swallow) goto next_char; } @@ -297,25 +290,12 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) if (r1 & Rx_OVR) tty_insert_flip_char(port, 0, TTY_OVERRUN); next_char: - /* We can get stuck in an infinite loop getting char 0 when the - * line is in a wrong HW state, we break that here. - * When that happens, I disable the receive side of the driver. - * Note that what I've been experiencing is a real irq loop where - * I'm getting flooded regardless of the actual port speed. - * Something strange is going on with the HW - */ - if ((++loops) > 1000) - goto flood; ch = read_zsreg(uap, R0); if (!(ch & Rx_CH_AV)) break; } return true; - flood: - pmz_interrupt_control(uap, 0); - pmz_error("pmz: rx irq flood !\n"); - return true; } static void pmz_status_handle(struct uart_pmac_port *uap) @@ -353,7 +333,8 @@ static void pmz_status_handle(struct uart_pmac_port *uap) static void pmz_transmit_chars(struct uart_pmac_port *uap) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char ch; if (ZS_IS_CONS(uap)) { unsigned char status = read_zsreg(uap, R0); @@ -404,8 +385,8 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) if (uap->port.state == NULL) goto ack_tx_int; - xmit = &uap->port.state->xmit; - if (uart_circ_empty(xmit)) { + tport = &uap->port.state->port; + if (kfifo_is_empty(&tport->xmit_fifo)) { uart_write_wakeup(&uap->port); goto ack_tx_int; } @@ -413,13 +394,11 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) goto ack_tx_int; uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(uap, xmit->buf[xmit->tail]); + WARN_ON(!uart_fifo_get(&uap->port, &ch)); + write_zsdata(uap, ch); zssync(uap); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); return; @@ -442,12 +421,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) uap_a = pmz_get_port_A(uap); uap_b = uap_a->mate; - spin_lock(&uap_a->port.lock); + uart_port_lock(&uap_a->port); r3 = read_zsreg(uap_a, R3); -#ifdef DEBUG_HARD - pmz_debug("irq, r3: %x\n", r3); -#endif /* Channel A */ push = false; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { @@ -466,14 +442,14 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) rc = IRQ_HANDLED; } skip_a: - spin_unlock(&uap_a->port.lock); + uart_port_unlock(&uap_a->port); if (push) tty_flip_buffer_push(&uap->port.state->port); if (!uap_b) goto out; - spin_lock(&uap_b->port.lock); + uart_port_lock(&uap_b->port); push = false; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { if (!ZS_IS_OPEN(uap_b)) { @@ -491,7 +467,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) rc = IRQ_HANDLED; } skip_b: - spin_unlock(&uap_b->port.lock); + uart_port_unlock(&uap_b->port); if (push) tty_flip_buffer_push(&uap->port.state->port); @@ -507,9 +483,9 @@ static inline u8 pmz_peek_status(struct uart_pmac_port *uap) unsigned long flags; u8 status; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); status = read_zsreg(uap, R0); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); return status; } @@ -612,8 +588,6 @@ static void pmz_start_tx(struct uart_port *port) struct uart_pmac_port *uap = to_pmz(port); unsigned char status; - pmz_debug("pmz: start_tx()\n"); - uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; @@ -632,20 +606,17 @@ static void pmz_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; - if (uart_circ_empty(xmit)) - goto out; - write_zsdata(uap, xmit->buf[xmit->tail]); + if (!uart_fifo_get(&uap->port, &ch)) + return; + write_zsdata(uap, ch); zssync(uap); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); } - out: - pmz_debug("pmz: start_tx() done.\n"); } /* @@ -658,13 +629,9 @@ static void pmz_stop_rx(struct uart_port *port) { struct uart_pmac_port *uap = to_pmz(port); - pmz_debug("pmz: stop_rx()()\n"); - /* Disable all RX interrupts. */ uap->curregs[R1] &= ~RxINT_MASK; pmz_maybe_update_regs(uap); - - pmz_debug("pmz: stop_rx() done.\n"); } /* @@ -704,7 +671,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) else clear_bits |= SND_BRK; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; if (new_reg != uap->curregs[R5]) { @@ -712,7 +679,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) write_zsreg(uap, R5, uap->curregs[R5]); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } #ifdef CONFIG_PPC_PMAC @@ -884,18 +851,18 @@ static void pmz_irda_reset(struct uart_pmac_port *uap) { unsigned long flags; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); uap->curregs[R5] |= DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); msleep(110); - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); uap->curregs[R5] &= ~DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); msleep(10); } @@ -909,17 +876,15 @@ static int pmz_startup(struct uart_port *port) unsigned long flags; int pwr_delay = 0; - pmz_debug("pmz: startup()\n"); - uap->flags |= PMACZILOG_FLAG_IS_OPEN; /* A console is never powered down. Else, power up and * initialize the chip */ if (!ZS_IS_CONS(uap)) { - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); pwr_delay = __pmz_startup(uap); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } sprintf(uap->irq_name, PMACZILOG_NAME"%d", uap->port.line); if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, @@ -942,11 +907,9 @@ static int pmz_startup(struct uart_port *port) pmz_irda_reset(uap); /* Enable interrupt requests for the channel */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); pmz_interrupt_control(uap, 1); - spin_unlock_irqrestore(&port->lock, flags); - - pmz_debug("pmz: startup() done.\n"); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -956,9 +919,7 @@ static void pmz_shutdown(struct uart_port *port) struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; - pmz_debug("pmz: shutdown()\n"); - - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable interrupt requests for the channel */ pmz_interrupt_control(uap, 0); @@ -973,21 +934,19 @@ static void pmz_shutdown(struct uart_port *port) pmz_maybe_update_regs(uap); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Release interrupt handler */ free_irq(uap->port.irq, uap); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; if (!ZS_IS_CONS(uap)) pmz_set_scc_power(uap, 0); /* Shut the chip down */ - spin_unlock_irqrestore(&port->lock, flags); - - pmz_debug("pmz: shutdown() done.\n"); + uart_port_unlock_irqrestore(port, flags); } /* Shared by TTY driver and serial console setup. The port lock is held @@ -1227,15 +1186,11 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long baud; - pmz_debug("pmz: set_termios()\n"); - - memcpy(&uap->termios_cache, termios, sizeof(struct ktermios)); - /* XXX Check which revs of machines actually allow 1 and 4Mb speeds * on the IR dongle. Note that the IRTTY driver currently doesn't know * about the FIR mode and high speed modes. So these are unused. For @@ -1269,18 +1224,16 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, pmz_maybe_update_regs(uap); } uart_update_timeout(port, termios->c_cflag, baud); - - pmz_debug("pmz: set_termios() done.\n"); } /* The port lock is not held. */ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable IRQs on the port */ pmz_interrupt_control(uap, 0); @@ -1292,7 +1245,7 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, if (ZS_IS_OPEN(uap)) pmz_interrupt_control(uap, 1); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *pmz_type(struct uart_port *port) @@ -1399,7 +1352,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) char name[1]; } *slots; int len; - struct resource r_ports, r_rxdma, r_txdma; + struct resource r_ports; /* * Request & map chip registers @@ -1411,35 +1364,6 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) uap->control_reg = uap->port.membase; uap->data_reg = uap->control_reg + 0x10; - - /* - * Request & map DBDMA registers - */ -#ifdef HAS_DBDMA - if (of_address_to_resource(np, 1, &r_txdma) == 0 && - of_address_to_resource(np, 2, &r_rxdma) == 0) - uap->flags |= PMACZILOG_FLAG_HAS_DMA; -#else - memset(&r_txdma, 0, sizeof(struct resource)); - memset(&r_rxdma, 0, sizeof(struct resource)); -#endif - if (ZS_HAS_DMA(uap)) { - uap->tx_dma_regs = ioremap(r_txdma.start, 0x100); - if (uap->tx_dma_regs == NULL) { - uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; - goto no_dma; - } - uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100); - if (uap->rx_dma_regs == NULL) { - iounmap(uap->tx_dma_regs); - uap->tx_dma_regs = NULL; - uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; - goto no_dma; - } - uap->tx_dma_irq = irq_of_parse_and_map(np, 1); - uap->rx_dma_irq = irq_of_parse_and_map(np, 2); - } -no_dma: /* * Detect port type @@ -1505,8 +1429,6 @@ no_dma: of_device_is_compatible(np->parent->parent, "gatwick")) { /* IRQs on gatwick are offset by 64 */ uap->port.irq = irq_create_mapping(NULL, 64 + 15); - uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4); - uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5); } /* Setup some valid baud rate information in the register @@ -1526,8 +1448,6 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) struct device_node *np; np = uap->node; - iounmap(uap->rx_dma_regs); - iounmap(uap->tx_dma_regs); iounmap(uap->control_reg); uap->node = NULL; of_node_put(np); @@ -1573,12 +1493,12 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) * That one should not be called, macio isn't really a hotswap device, * we don't expect one of those serial ports to go away... */ -static int pmz_detach(struct macio_dev *mdev) +static void pmz_detach(struct macio_dev *mdev) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); if (!uap) - return -ENODEV; + return; uart_remove_one_port(&pmz_uart_reg, &uap->port); @@ -1589,11 +1509,8 @@ static int pmz_detach(struct macio_dev *mdev) dev_set_drvdata(&mdev->ofdev.dev, NULL); uap->dev = NULL; uap->port.dev = NULL; - - return 0; } - static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) { struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); @@ -1643,7 +1560,7 @@ static int __init pmz_probe(void) * TODO: Add routines with proper locking to do that... */ node_a = node_b = NULL; - for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) { + for_each_child_of_node(node_p, np) { if (of_node_name_prefix(np, "ch-a")) node_a = of_node_get(np); else if (of_node_name_prefix(np, "ch-b")) @@ -1692,6 +1609,11 @@ static int __init pmz_probe(void) #else +/* On PCI PowerMacs, pmz_probe() does an explicit search of the OpenFirmware + * tree to obtain the device_nodes needed to start the console before the + * macio driver. On Macs without OpenFirmware, global platform_devices take + * the place of those device_nodes. + */ extern struct platform_device scc_a_pdev, scc_b_pdev; static int __init pmz_init_port(struct uart_pmac_port *uap) @@ -1700,10 +1622,13 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) int irq; r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(uap->pdev, 0); - if (!r_ports || irq <= 0) + if (!r_ports) return -ENODEV; + irq = platform_get_irq(uap->pdev, 0); + if (irq < 0) + return irq; + uap->port.mapbase = r_ports->start; uap->port.membase = (unsigned char __iomem *) r_ports->start; uap->port.iotype = UPIO_MEM; @@ -1756,7 +1681,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) memset(uap, 0, sizeof(struct uart_pmac_port)); } -static int __init pmz_attach(struct platform_device *pdev) +static int pmz_attach(struct platform_device *pdev) { struct uart_pmac_port *uap; int i; @@ -1775,18 +1700,13 @@ static int __init pmz_attach(struct platform_device *pdev) return uart_add_one_port(&pmz_uart_reg, &uap->port); } -static int __exit pmz_detach(struct platform_device *pdev) +static void pmz_detach(struct platform_device *pdev) { struct uart_pmac_port *uap = platform_get_drvdata(pdev); - if (!uap) - return -ENODEV; - uart_remove_one_port(&pmz_uart_reg, &uap->port); uap->port.dev = NULL; - - return 0; } #endif /* !CONFIG_PPC_PMAC */ @@ -1855,7 +1775,8 @@ static struct macio_driver pmz_driver = { #else static struct platform_driver pmz_driver = { - .remove = __exit_p(pmz_detach), + .probe = pmz_attach, + .remove = pmz_detach, .driver = { .name = "scc", }, @@ -1866,7 +1787,6 @@ static struct platform_driver pmz_driver = { static int __init init_pmz(void) { int rc, i; - printk(KERN_INFO "%s\n", version); /* * First, we need to do a direct OF-based probe pass. We @@ -1904,7 +1824,7 @@ static int __init init_pmz(void) #ifdef CONFIG_PPC_PMAC return macio_register_driver(&pmz_driver); #else - return platform_driver_probe(&pmz_driver, pmz_attach); + return platform_driver_register(&pmz_driver); #endif } @@ -1935,7 +1855,7 @@ static void __exit exit_pmz(void) #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE -static void pmz_console_putchar(struct uart_port *port, int ch) +static void pmz_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_pmac_port *uap = container_of(port, struct uart_pmac_port, port); @@ -1955,7 +1875,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c struct uart_pmac_port *uap = &pmz_ports[con->index]; unsigned long flags; - spin_lock_irqsave(&uap->port.lock, flags); + uart_port_lock_irqsave(&uap->port, &flags); /* Turn of interrupts and enable the transmitter. */ write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB); @@ -1967,7 +1887,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c write_zsreg(uap, R1, uap->curregs[1]); /* Don't disable the transmitter. */ - spin_unlock_irqrestore(&uap->port.lock, flags); + uart_port_unlock_irqrestore(&uap->port, flags); } /* diff --git a/drivers/tty/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h index bb874e76810e..837b97ca0a90 100644 --- a/drivers/tty/serial/pmac_zilog.h +++ b/drivers/tty/serial/pmac_zilog.h @@ -43,7 +43,6 @@ struct uart_pmac_port { #define PMACZILOG_FLAG_TX_ACTIVE 0x00000040 #define PMACZILOG_FLAG_IS_IRDA 0x00000100 #define PMACZILOG_FLAG_IS_INTMODEM 0x00000200 -#define PMACZILOG_FLAG_HAS_DMA 0x00000400 #define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800 #define PMACZILOG_FLAG_IS_OPEN 0x00002000 #define PMACZILOG_FLAG_IS_EXTCLK 0x00008000 @@ -55,16 +54,7 @@ struct uart_pmac_port { volatile u8 __iomem *control_reg; volatile u8 __iomem *data_reg; -#ifdef CONFIG_PPC_PMAC - unsigned int tx_dma_irq; - unsigned int rx_dma_irq; - volatile struct dbdma_regs __iomem *tx_dma_regs; - volatile struct dbdma_regs __iomem *rx_dma_regs; -#endif - unsigned char irq_name[8]; - - struct ktermios termios_cache; }; #define to_pmz(p) ((struct uart_pmac_port *)(p)) @@ -362,10 +352,10 @@ static inline void zssync(struct uart_pmac_port *port) /* Misc macros */ #define ZS_CLEARERR(port) (write_zsreg(port, 0, ERR_RES)) -#define ZS_CLEARFIFO(port) do { volatile unsigned char garbage; \ - garbage = read_zsdata(port); \ - garbage = read_zsdata(port); \ - garbage = read_zsdata(port); \ +#define ZS_CLEARFIFO(port) do { \ + read_zsdata(port); \ + read_zsdata(port); \ + read_zsdata(port); \ } while(0) #define ZS_IS_CONS(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CONS) @@ -377,7 +367,6 @@ static inline void zssync(struct uart_pmac_port *port) #define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS) #define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA) #define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM) -#define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA) #define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN) #define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK) diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c deleted file mode 100644 index 972d94e8d32b..000000000000 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ /dev/null @@ -1,858 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * UART driver for PNX8XXX SoCs - * - * Author: Per Hallsmark per.hallsmark@mvista.com - * Ported to 2.6 kernel by EmbeddedAlley - * Reworked by Vitaly Wool <vitalywool@gmail.com> - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Copyright (C) 2000 Deep Blue Solutions Ltd. - */ - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/serial_pnx8xxx.h> - -#include <asm/io.h> -#include <asm/irq.h> - -/* We'll be using StrongARM sa1100 serial port major/minor */ -#define SERIAL_PNX8XXX_MAJOR 204 -#define MINOR_START 5 - -#define NR_PORTS 2 - -#define PNX8XXX_ISR_PASS_LIMIT 256 - -/* - * Convert from ignore_status_mask or read_status_mask to FIFO - * and interrupt status bits - */ -#define SM_TO_FIFO(x) ((x) >> 10) -#define SM_TO_ISTAT(x) ((x) & 0x000001ff) -#define FIFO_TO_SM(x) ((x) << 10) -#define ISTAT_TO_SM(x) ((x) & 0x000001ff) - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x1000 - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo incase CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -extern struct pnx8xxx_port pnx8xxx_ports[]; - -static inline int serial_in(struct pnx8xxx_port *sport, int offset) -{ - return (__raw_readl(sport->port.membase + offset)); -} - -static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value) -{ - __raw_writel(value, sport->port.membase + offset); -} - -/* - * Handle any change of modem status signal since we were last called. - */ -static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void pnx8xxx_timeout(struct timer_list *t) -{ - struct pnx8xxx_port *sport = from_timer(sport, t, timer); - unsigned long flags; - - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - pnx8xxx_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } -} - -/* - * interrupts disabled on entry - */ -static void pnx8xxx_stop_tx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - u32 ien; - - /* Disable TX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX); - - /* Clear all pending TX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); -} - -/* - * interrupts may not be disabled on entry - */ -static void pnx8xxx_start_tx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - u32 ien; - - /* Clear all pending TX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); - - /* Enable TX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX); -} - -/* - * Interrupts enabled - */ -static void pnx8xxx_stop_rx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - u32 ien; - - /* Disable RX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX); - - /* Clear all pending RX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX); -} - -/* - * Set the modem control timer to fire immediately. - */ -static void pnx8xxx_enable_ms(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - mod_timer(&sport->timer, jiffies); -} - -static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) -{ - unsigned int status, ch, flg; - - status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | - ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); - while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) { - ch = serial_in(sport, PNX8XXX_FIFO) & 0xff; - - sport->port.icount.rx++; - - flg = TTY_NORMAL; - - /* - * note that the error handling code is - * out of the main execution path - */ - if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE | - PNX8XXX_UART_FIFO_RXPAR | - PNX8XXX_UART_FIFO_RXBRK) | - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) { - if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) { - status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)); - sport->port.icount.brk++; - if (uart_handle_break(&sport->port)) - goto ignore_char; - } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) - sport->port.icount.parity++; - else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) - sport->port.icount.frame++; - if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN)) - sport->port.icount.overrun++; - - status &= sport->port.read_status_mask; - - if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) - flg = TTY_PARITY; - else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) - flg = TTY_FRAME; - - sport->port.sysrq = 0; - } - - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char; - - uart_insert_char(&sport->port, status, - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg); - - ignore_char: - serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) | - PNX8XXX_UART_LCR_RX_NEXT); - status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | - ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); - } - - spin_unlock(&sport->port.lock); - tty_flip_buffer_push(&sport->port.state->port); - spin_lock(&sport->port.lock); -} - -static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - - if (sport->port.x_char) { - serial_out(sport, PNX8XXX_FIFO, sport->port.x_char); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - /* - * Check the modem control lines before - * transmitting anything. - */ - pnx8xxx_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - pnx8xxx_stop_tx(&sport->port); - return; - } - - /* - * TX while bytes available - */ - while (((serial_in(sport, PNX8XXX_FIFO) & - PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) { - serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - pnx8xxx_stop_tx(&sport->port); -} - -static irqreturn_t pnx8xxx_int(int irq, void *dev_id) -{ - struct pnx8xxx_port *sport = dev_id; - unsigned int status; - - spin_lock(&sport->port.lock); - /* Get the interrupts */ - status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN); - - /* Byte or break signal received */ - if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK)) - pnx8xxx_rx_chars(sport); - - /* TX holding register empty - transmit a byte */ - if (status & PNX8XXX_UART_INT_TX) - pnx8xxx_tx_chars(sport); - - /* Clear the ISTAT register */ - serial_out(sport, PNX8XXX_ICLR, status); - - spin_unlock(&sport->port.lock); - return IRQ_HANDLED; -} - -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int pnx8xxx_tx_empty(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT; -} - -static unsigned int pnx8xxx_get_mctrl(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - unsigned int mctrl = TIOCM_DSR; - unsigned int msr; - - /* REVISIT */ - - msr = serial_in(sport, PNX8XXX_MCR); - - mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0; - mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0; - - return mctrl; -} - -static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -#if 0 /* FIXME */ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - unsigned int msr; -#endif -} - -/* - * Interrupts always disabled. - */ -static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - unsigned long flags; - unsigned int lcr; - - spin_lock_irqsave(&sport->port.lock, flags); - lcr = serial_in(sport, PNX8XXX_LCR); - if (break_state == -1) - lcr |= PNX8XXX_UART_LCR_TXBREAK; - else - lcr &= ~PNX8XXX_UART_LCR_TXBREAK; - serial_out(sport, PNX8XXX_LCR, lcr); - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static int pnx8xxx_startup(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int retval; - - /* - * Allocate the IRQ - */ - retval = request_irq(sport->port.irq, pnx8xxx_int, 0, - "pnx8xxx-uart", sport); - if (retval) - return retval; - - /* - * Finally, clear and enable interrupts - */ - - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) | - PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - /* - * Enable modem status interrupts - */ - spin_lock_irq(&sport->port.lock); - pnx8xxx_enable_ms(&sport->port); - spin_unlock_irq(&sport->port.lock); - - return 0; -} - -static void pnx8xxx_shutdown(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int lcr; - - /* - * Stop our timer. - */ - del_timer_sync(&sport->timer); - - /* - * Disable all interrupts - */ - serial_out(sport, PNX8XXX_IEN, 0); - - /* - * Reset the Tx and Rx FIFOS, disable the break condition - */ - lcr = serial_in(sport, PNX8XXX_LCR); - lcr &= ~PNX8XXX_UART_LCR_TXBREAK; - lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST; - serial_out(sport, PNX8XXX_LCR, lcr); - - /* - * Clear all interrupts - */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - /* - * Free the interrupt - */ - free_irq(sport->port.irq, sport); -} - -static void -pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - unsigned long flags; - unsigned int lcr_fcr, old_ien, baud, quot; - unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - - /* - * We only support CS7 and CS8. - */ - while ((termios->c_cflag & CSIZE) != CS7 && - (termios->c_cflag & CSIZE) != CS8) { - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= old_csize; - old_csize = CS8; - } - - if ((termios->c_cflag & CSIZE) == CS8) - lcr_fcr = PNX8XXX_UART_LCR_8BIT; - else - lcr_fcr = 0; - - if (termios->c_cflag & CSTOPB) - lcr_fcr |= PNX8XXX_UART_LCR_2STOPB; - if (termios->c_cflag & PARENB) { - lcr_fcr |= PNX8XXX_UART_LCR_PAREN; - if (!(termios->c_cflag & PARODD)) - lcr_fcr |= PNX8XXX_UART_LCR_PAREVN; - } - - /* - * Ask the core to calculate the divisor for us. - */ - 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); - - sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) | - ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) | - ISTAT_TO_SM(PNX8XXX_UART_INT_RX); - if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - sport->port.read_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); - - /* - * Characters to ignore - */ - sport->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN); - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_RX); - - del_timer_sync(&sport->timer); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * disable interrupts and drain transmitter - */ - old_ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | - PNX8XXX_UART_INT_ALLRX)); - - while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA) - barrier(); - - /* then, disable everything */ - serial_out(sport, PNX8XXX_IEN, 0); - - /* Reset the Rx and Tx FIFOs too */ - lcr_fcr |= PNX8XXX_UART_LCR_TX_RST; - lcr_fcr |= PNX8XXX_UART_LCR_RX_RST; - - /* set the parity, stop bits and data size */ - serial_out(sport, PNX8XXX_LCR, lcr_fcr); - - /* set the baud rate */ - quot -= 1; - serial_out(sport, PNX8XXX_BAUD, quot); - - serial_out(sport, PNX8XXX_ICLR, -1); - - serial_out(sport, PNX8XXX_IEN, old_ien); - - if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - pnx8xxx_enable_ms(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *pnx8xxx_type(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void pnx8xxx_release_port(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int pnx8xxx_request_port(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, - "pnx8xxx-uart") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void pnx8xxx_config_port(struct uart_port *port, int flags) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - if (flags & UART_CONFIG_TYPE && - pnx8xxx_request_port(&sport->port) == 0) - sport->port.type = PORT_PNX8XXX; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_PNX8XXX and PORT_UNKNOWN - */ -static int -pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -static const struct uart_ops pnx8xxx_pops = { - .tx_empty = pnx8xxx_tx_empty, - .set_mctrl = pnx8xxx_set_mctrl, - .get_mctrl = pnx8xxx_get_mctrl, - .stop_tx = pnx8xxx_stop_tx, - .start_tx = pnx8xxx_start_tx, - .stop_rx = pnx8xxx_stop_rx, - .enable_ms = pnx8xxx_enable_ms, - .break_ctl = pnx8xxx_break_ctl, - .startup = pnx8xxx_startup, - .shutdown = pnx8xxx_shutdown, - .set_termios = pnx8xxx_set_termios, - .type = pnx8xxx_type, - .release_port = pnx8xxx_release_port, - .request_port = pnx8xxx_request_port, - .config_port = pnx8xxx_config_port, - .verify_port = pnx8xxx_verify_port, -}; - - -/* - * Setup the PNX8XXX serial ports. - * - * Note also that we support "console=ttySx" where "x" is either 0 or 1. - */ -static void __init pnx8xxx_init_ports(void) -{ - static int first = 1; - int i; - - if (!first) - return; - first = 0; - - for (i = 0; i < NR_PORTS; i++) { - timer_setup(&pnx8xxx_ports[i].timer, pnx8xxx_timeout, 0); - pnx8xxx_ports[i].port.ops = &pnx8xxx_pops; - } -} - -#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE - -static void pnx8xxx_console_putchar(struct uart_port *port, int ch) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int status; - - do { - /* Wait for UART_TX register to empty */ - status = serial_in(sport, PNX8XXX_FIFO); - } while (status & PNX8XXX_UART_FIFO_TXFIFO); - serial_out(sport, PNX8XXX_FIFO, ch); -} - -/* - * Interrupts are disabled on entering - */static void -pnx8xxx_console_write(struct console *co, const char *s, unsigned int count) -{ - struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index]; - unsigned int old_ien, status; - - /* - * First, save IEN and then disable interrupts - */ - old_ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | - PNX8XXX_UART_INT_ALLRX)); - - uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore IEN - */ - do { - /* Wait for UART_TX register to empty */ - status = serial_in(sport, PNX8XXX_FIFO); - } while (status & PNX8XXX_UART_FIFO_TXFIFO); - - /* Clear TX and EMPTY interrupt */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX | - PNX8XXX_UART_INT_EMPTY); - - serial_out(sport, PNX8XXX_IEN, old_ien); -} - -static int __init -pnx8xxx_console_setup(struct console *co, char *options) -{ - struct pnx8xxx_port *sport; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= NR_PORTS) - co->index = 0; - sport = &pnx8xxx_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver pnx8xxx_reg; -static struct console pnx8xxx_console = { - .name = "ttyS", - .write = pnx8xxx_console_write, - .device = uart_console_device, - .setup = pnx8xxx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &pnx8xxx_reg, -}; - -static int __init pnx8xxx_rs_console_init(void) -{ - pnx8xxx_init_ports(); - register_console(&pnx8xxx_console); - return 0; -} -console_initcall(pnx8xxx_rs_console_init); - -#define PNX8XXX_CONSOLE &pnx8xxx_console -#else -#define PNX8XXX_CONSOLE NULL -#endif - -static struct uart_driver pnx8xxx_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyS", - .dev_name = "ttyS", - .major = SERIAL_PNX8XXX_MAJOR, - .minor = MINOR_START, - .nr = NR_PORTS, - .cons = PNX8XXX_CONSOLE, -}; - -static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - return uart_suspend_port(&pnx8xxx_reg, &sport->port); -} - -static int pnx8xxx_serial_resume(struct platform_device *pdev) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - return uart_resume_port(&pnx8xxx_reg, &sport->port); -} - -static int pnx8xxx_serial_probe(struct platform_device *pdev) -{ - struct resource *res = pdev->resource; - int i; - - for (i = 0; i < pdev->num_resources; i++, res++) { - if (!(res->flags & IORESOURCE_MEM)) - continue; - - for (i = 0; i < NR_PORTS; i++) { - if (pnx8xxx_ports[i].port.mapbase != res->start) - continue; - - pnx8xxx_ports[i].port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_PNX8XXX_CONSOLE); - pnx8xxx_ports[i].port.dev = &pdev->dev; - uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port); - platform_set_drvdata(pdev, &pnx8xxx_ports[i]); - break; - } - } - - return 0; -} - -static int pnx8xxx_serial_remove(struct platform_device *pdev) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - if (sport) - uart_remove_one_port(&pnx8xxx_reg, &sport->port); - - return 0; -} - -static struct platform_driver pnx8xxx_serial_driver = { - .driver = { - .name = "pnx8xxx-uart", - }, - .probe = pnx8xxx_serial_probe, - .remove = pnx8xxx_serial_remove, - .suspend = pnx8xxx_serial_suspend, - .resume = pnx8xxx_serial_resume, -}; - -static int __init pnx8xxx_serial_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: PNX8XXX driver\n"); - - pnx8xxx_init_ports(); - - ret = uart_register_driver(&pnx8xxx_reg); - if (ret == 0) { - ret = platform_driver_register(&pnx8xxx_serial_driver); - if (ret) - uart_unregister_driver(&pnx8xxx_reg); - } - return ret; -} - -static void __exit pnx8xxx_serial_exit(void) -{ - platform_driver_unregister(&pnx8xxx_serial_driver); - uart_unregister_driver(&pnx8xxx_reg); -} - -module_init(pnx8xxx_serial_init); -module_exit(pnx8xxx_serial_exit); - -MODULE_AUTHOR("Embedded Alley Solutions, Inc."); -MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR); -MODULE_ALIAS("platform:pnx8xxx-uart"); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 41319ef96fa6..e395ff29c1a2 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/console.h> #include <linux/sysrq.h> +#include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/circ_buf.h> #include <linux/delay.h> @@ -89,7 +90,7 @@ static void serial_pxa_stop_rx(struct uart_port *port) static inline void receive_chars(struct uart_pxa_port *up, int *status) { - unsigned int ch, flag; + u8 ch, flag; int max_count = 256; do { @@ -150,7 +151,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); @@ -173,35 +174,12 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) static void transmit_chars(struct uart_pxa_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; - int count; + u8 ch; - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_pxa_stop_tx(&up->port); - return; - } - - count = up->port.fifosize / 2; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - - if (uart_circ_empty(xmit)) - serial_pxa_stop_tx(&up->port); + uart_port_tx_limited(&up->port, ch, up->port.fifosize / 2, + true, + serial_out(up, UART_TX, ch), + ({})); } static void serial_pxa_start_tx(struct uart_port *port) @@ -247,14 +225,14 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) return IRQ_NONE; - spin_lock(&up->port.lock); + uart_port_lock(&up->port); lsr = serial_in(up, UART_LSR); if (lsr & UART_LSR_DR) receive_chars(up, &lsr); check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); - spin_unlock(&up->port.lock); + uart_unlock_and_check_sysrq(&up->port); return IRQ_HANDLED; } @@ -264,9 +242,9 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port) unsigned long flags; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return ret; } @@ -317,13 +295,13 @@ static void serial_pxa_break_ctl(struct uart_port *port, int break_state) struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int serial_pxa_startup(struct uart_port *port) @@ -368,10 +346,10 @@ static int serial_pxa_startup(struct uart_port *port) */ serial_out(up, UART_LCR, UART_LCR_WLEN8); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->port.mctrl |= TIOCM_OUT2; serial_pxa_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Finally, enable interrupts. Note: Modem status interrupts @@ -405,10 +383,10 @@ static void serial_pxa_shutdown(struct uart_port *port) up->ier = 0; serial_out(up, UART_IER, 0); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->port.mctrl &= ~TIOCM_OUT2; serial_pxa_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Disable break condition and FIFOs @@ -422,7 +400,7 @@ static void serial_pxa_shutdown(struct uart_port *port) static void serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned char cval, fcr = 0; @@ -430,21 +408,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int baud, quot; unsigned int dll; - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } + cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; @@ -470,7 +434,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Ensure the port will be enabled. @@ -540,7 +504,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, up->lcr = cval; /* Save LCR */ serial_pxa_set_mctrl(&up->port, up->port.mctrl); serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static void @@ -589,8 +553,6 @@ static struct uart_driver serial_pxa_reg; #ifdef CONFIG_SERIAL_PXA_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Wait for transmitter & holding register to empty */ @@ -608,7 +570,7 @@ static void wait_for_xmitr(struct uart_pxa_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { @@ -619,7 +581,7 @@ static void wait_for_xmitr(struct uart_pxa_port *up) } } -static void serial_pxa_console_putchar(struct uart_port *port, int ch) +static void serial_pxa_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; @@ -642,13 +604,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) int locked = 1; clk_enable(up->clk); - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&up->port.lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock(&up->port.lock); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -666,10 +625,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) serial_out(up, UART_IER, ier); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); clk_disable(up->clk); - } #ifdef CONFIG_CONSOLE_POLL @@ -842,14 +799,18 @@ static int serial_pxa_probe_dt(struct platform_device *pdev, static int serial_pxa_probe(struct platform_device *dev) { struct uart_pxa_port *sport; - struct resource *mmres, *irqres; + struct resource *mmres; int ret; + int irq; mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) + if (!mmres) return -ENODEV; + irq = platform_get_irq(dev, 0); + if (irq < 0) + return irq; + sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); if (!sport) return -ENOMEM; @@ -869,7 +830,7 @@ static int serial_pxa_probe(struct platform_device *dev) sport->port.type = PORT_PXA; sport->port.iotype = UPIO_MEM; sport->port.mapbase = mmres->start; - sport->port.irq = irqres->start; + sport->port.irq = irq; sport->port.fifosize = 64; sport->port.ops = &serial_pxa_pops; sport->port.dev = &dev->dev; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 457c0bf8cbf8..6ce6528f5c10 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1,5 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. +/* + * Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */ +#define __DISABLE_TRACE_MMIO__ #include <linux/clk.h> #include <linux/console.h> @@ -8,16 +14,18 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/pm_wakeirq.h> -#include <linux/qcom-geni-se.h> +#include <linux/soc/qcom/geni-se.h> #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <dt-bindings/interconnect/qcom,icc.h> /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG 0x22c @@ -34,79 +42,88 @@ #define SE_UART_MANUAL_RFR 0x2ac /* SE_UART_TRANS_CFG */ -#define UART_TX_PAR_EN BIT(0) -#define UART_CTS_MASK BIT(1) - -/* SE_UART_TX_WORD_LEN */ -#define TX_WORD_LEN_MSK GENMASK(9, 0) +#define UART_TX_PAR_EN BIT(0) +#define UART_CTS_MASK BIT(1) /* SE_UART_TX_STOP_BIT_LEN */ -#define TX_STOP_BIT_LEN_MSK GENMASK(23, 0) -#define TX_STOP_BIT_LEN_1 0 -#define TX_STOP_BIT_LEN_1_5 1 -#define TX_STOP_BIT_LEN_2 2 - -/* SE_UART_TX_TRANS_LEN */ -#define TX_TRANS_LEN_MSK GENMASK(23, 0) +#define TX_STOP_BIT_LEN_1 0 +#define TX_STOP_BIT_LEN_2 2 /* SE_UART_RX_TRANS_CFG */ -#define UART_RX_INS_STATUS_BIT BIT(2) -#define UART_RX_PAR_EN BIT(3) +#define UART_RX_PAR_EN BIT(3) /* SE_UART_RX_WORD_LEN */ -#define RX_WORD_LEN_MASK GENMASK(9, 0) +#define RX_WORD_LEN_MASK GENMASK(9, 0) /* SE_UART_RX_STALE_CNT */ -#define RX_STALE_CNT GENMASK(23, 0) +#define RX_STALE_CNT GENMASK(23, 0) /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */ -#define PAR_CALC_EN BIT(0) -#define PAR_MODE_MSK GENMASK(2, 1) -#define PAR_MODE_SHFT 1 -#define PAR_EVEN 0x00 -#define PAR_ODD 0x01 -#define PAR_SPACE 0x10 -#define PAR_MARK 0x11 +#define PAR_CALC_EN BIT(0) +#define PAR_EVEN 0x00 +#define PAR_ODD 0x01 +#define PAR_SPACE 0x10 /* SE_UART_MANUAL_RFR register fields */ -#define UART_MANUAL_RFR_EN BIT(31) -#define UART_RFR_NOT_READY BIT(1) -#define UART_RFR_READY BIT(0) +#define UART_MANUAL_RFR_EN BIT(31) +#define UART_RFR_NOT_READY BIT(1) +#define UART_RFR_READY BIT(0) /* UART M_CMD OP codes */ -#define UART_START_TX 0x1 -#define UART_START_BREAK 0x4 -#define UART_STOP_BREAK 0x5 +#define UART_START_TX 0x1 /* UART S_CMD OP codes */ -#define UART_START_READ 0x1 -#define UART_PARAM 0x1 - -#define UART_OVERSAMPLING 32 -#define STALE_TIMEOUT 16 -#define DEFAULT_BITS_PER_CHAR 10 -#define GENI_UART_CONS_PORTS 1 -#define GENI_UART_PORTS 3 -#define DEF_FIFO_DEPTH_WORDS 16 -#define DEF_TX_WM 2 -#define DEF_FIFO_WIDTH_BITS 32 -#define UART_RX_WM 2 +#define UART_START_READ 0x1 +#define UART_PARAM 0x1 +#define UART_PARAM_RFR_OPEN BIT(7) + +#define UART_OVERSAMPLING 32 +#define STALE_TIMEOUT 16 +#define DEFAULT_BITS_PER_CHAR 10 +#define GENI_UART_CONS_PORTS 1 +#define DEF_FIFO_DEPTH_WORDS 16 +#define DEF_TX_WM 2 +#define DEF_FIFO_WIDTH_BITS 32 +#define UART_RX_WM 2 /* SE_UART_LOOPBACK_CFG */ -#define RX_TX_SORTED BIT(0) -#define CTS_RTS_SORTED BIT(1) -#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED) +#define RX_TX_SORTED BIT(0) +#define CTS_RTS_SORTED BIT(1) +#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED) /* UART pin swap value */ -#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0) +#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0) #define IO_MACRO_IO0_SEL 0x3 -#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4) +#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4) #define IO_MACRO_IO2_IO3_SWAP 0x4640 -#ifdef CONFIG_CONSOLE_POLL -#define CONSOLE_RX_BYTES_PW 1 -#else -#define CONSOLE_RX_BYTES_PW 4 -#endif +/* We always configure 4 bytes per FIFO word */ +#define BYTES_PER_FIFO_WORD 4U + +#define DMA_RX_BUF_SIZE 2048 + +static DEFINE_IDA(port_ida); +#define DOMAIN_IDX_POWER 0 +#define DOMAIN_IDX_PERF 1 + +struct qcom_geni_device_data { + bool console; + enum geni_se_xfer_mode mode; + struct dev_pm_domain_attach_data pd_data; + int (*resources_init)(struct uart_port *uport); + int (*set_rate)(struct uart_port *uport, unsigned int baud); + int (*power_state)(struct uart_port *uport, bool state); +}; + +struct qcom_geni_private_data { + /* NOTE: earlycon port will have NULL here */ + struct uart_driver *drv; + + u32 poll_cached_bytes; + unsigned int poll_cached_bytes_cnt; + + u32 write_cached_bytes; + unsigned int write_cached_bytes_cnt; +}; struct qcom_geni_serial_port { struct uart_port uport; @@ -115,66 +132,39 @@ struct qcom_geni_serial_port { u32 tx_fifo_depth; u32 tx_fifo_width; u32 rx_fifo_depth; + dma_addr_t tx_dma_addr; + dma_addr_t rx_dma_addr; bool setup; - int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); - unsigned int baud; - unsigned int tx_bytes_pw; - unsigned int rx_bytes_pw; - void *rx_fifo; + unsigned long poll_timeout_us; + unsigned long clk_rate; + void *rx_buf; u32 loopback; bool brk; unsigned int tx_remaining; + unsigned int tx_queued; int wakeup_irq; bool rx_tx_swap; bool cts_rts_swap; + + struct qcom_geni_private_data private_data; + const struct qcom_geni_device_data *dev_data; + struct dev_pm_domain_list *pd_list; }; static const struct uart_ops qcom_geni_console_pops; static const struct uart_ops qcom_geni_uart_pops; static struct uart_driver qcom_geni_console_driver; static struct uart_driver qcom_geni_uart_driver; -static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop); -static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop); -static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port); -static void qcom_geni_serial_stop_rx(struct uart_port *uport); -static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop); - -static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, - 32000000, 48000000, 51200000, 64000000, - 80000000, 96000000, 100000000, - 102400000, 112000000, 120000000, - 128000000}; - -#define to_dev_port(ptr, member) \ - container_of(ptr, struct qcom_geni_serial_port, member) - -static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = { - [0] = { - .uport = { - .iotype = UPIO_MEM, - .ops = &qcom_geni_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - [1] = { - .uport = { - .iotype = UPIO_MEM, - .ops = &qcom_geni_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - [2] = { - .uport = { - .iotype = UPIO_MEM, - .ops = &qcom_geni_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, -}; + +static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport); +static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport); +static int qcom_geni_serial_port_setup(struct uart_port *uport); + +static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport) +{ + return container_of(uport, struct qcom_geni_serial_port, uport); +} static struct qcom_geni_serial_port qcom_geni_console_port = { .uport = { @@ -185,10 +175,37 @@ static struct qcom_geni_serial_port qcom_geni_console_port = { }, }; +static const struct serial_rs485 qcom_geni_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RTS_ON_SEND, +}; + +/** + * qcom_geni_set_rs485_mode - Set RTS pin state for RS485 mode + * @uport: UART port + * @flag: RS485 flag to determine RTS polarity + * + * Enables manual RTS control for RS485. Sets RTS to READY or NOT_READY + * based on the specified flag if RS485 mode is enabled. + */ +static void qcom_geni_set_rs485_mode(struct uart_port *uport, u32 flag) +{ + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + return; + + u32 rfr = UART_MANUAL_RFR_EN; + + if (uport->rs485.flags & flag) + rfr |= UART_RFR_NOT_READY; + else + rfr |= UART_RFR_READY; + + writel(rfr, uport->membase + SE_UART_MANUAL_RFR); +} + static int qcom_geni_serial_request_port(struct uart_port *uport) { struct platform_device *pdev = to_platform_device(uport->dev); - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); uport->membase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(uport->membase)) @@ -225,7 +242,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, unsigned int mctrl) { u32 uart_manual_rfr = 0; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); if (uart_console(uport)) return; @@ -233,7 +250,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, if (mctrl & TIOCM_LOOP) port->loopback = RX_TX_CTS_RTS_SORTED; - if (!(mctrl & TIOCM_RTS)) + if (!(mctrl & TIOCM_RTS) && !uport->suspended) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); } @@ -243,38 +260,63 @@ static const char *qcom_geni_serial_get_type(struct uart_port *uport) return "MSM"; } -static struct qcom_geni_serial_port *get_port_from_line(int line, bool console) +static struct qcom_geni_serial_port *get_port_from_line(int line, bool console, struct device *dev) { struct qcom_geni_serial_port *port; - int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS; + int nr_ports = console ? GENI_UART_CONS_PORTS : CONFIG_SERIAL_QCOM_GENI_UART_PORTS; - if (line < 0 || line >= nr_ports) - return ERR_PTR(-ENXIO); + if (console) { + if (line < 0 || line >= nr_ports) + return ERR_PTR(-ENXIO); - port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line]; + port = &qcom_geni_console_port; + } else { + int max_alias_num = of_alias_get_highest_id("serial"); + + if (line < 0 || line >= nr_ports) + line = ida_alloc_range(&port_ida, max_alias_num + 1, + nr_ports - 1, GFP_KERNEL); + else + line = ida_alloc_range(&port_ida, line, + nr_ports - 1, GFP_KERNEL); + + if (line < 0) + return ERR_PTR(-ENXIO); + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + port->uport.iotype = UPIO_MEM; + port->uport.ops = &qcom_geni_uart_pops; + port->uport.flags = UPF_BOOT_AUTOCONF; + port->uport.line = line; + } return port; } -static bool qcom_geni_serial_poll_bit(struct uart_port *uport, - int offset, int field, bool set) +static bool qcom_geni_serial_main_active(struct uart_port *uport) +{ + return readl(uport->membase + SE_GENI_STATUS) & M_GENI_CMD_ACTIVE; +} + +static bool qcom_geni_serial_secondary_active(struct uart_port *uport) +{ + return readl(uport->membase + SE_GENI_STATUS) & S_GENI_CMD_ACTIVE; +} + +static bool qcom_geni_serial_poll_bitfield(struct uart_port *uport, + unsigned int offset, u32 field, u32 val) { u32 reg; struct qcom_geni_serial_port *port; - unsigned int baud; - unsigned int fifo_bits; unsigned long timeout_us = 20000; + struct qcom_geni_private_data *private_data = uport->private_data; - if (uport->private_data) { - port = to_dev_port(uport, uport); - baud = port->baud; - if (!baud) - baud = 115200; - fifo_bits = port->tx_fifo_depth * port->tx_fifo_width; - /* - * Total polling iterations based on FIFO worth of bytes to be - * sent at current baud. Add a little fluff to the wait. - */ - timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500; + if (private_data->drv) { + port = to_dev_port(uport); + if (port->poll_timeout_us) + timeout_us = port->poll_timeout_us; } /* @@ -284,7 +326,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10; while (timeout_us) { reg = readl(uport->membase + offset); - if ((bool)(reg & field) == set) + if ((reg & field) == val) return true; udelay(10); timeout_us -= 10; @@ -292,6 +334,12 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, return false; } +static bool qcom_geni_serial_poll_bit(struct uart_port *uport, + unsigned int offset, u32 field, bool set) +{ + return qcom_geni_serial_poll_bitfield(uport, offset, field, set ? field : 0); +} + static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) { u32 m_cmd; @@ -304,18 +352,16 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) static void qcom_geni_serial_poll_tx_done(struct uart_port *uport) { int done; - u32 irq_clear = M_CMD_DONE_EN; done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { writel(M_GENI_CMD_ABORT, uport->membase + SE_GENI_M_CMD_CTRL_REG); - irq_clear |= M_CMD_ABORT_EN; qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_abort_rx(struct uart_port *uport) @@ -332,46 +378,108 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport) #ifdef CONFIG_CONSOLE_POLL static int qcom_geni_serial_get_char(struct uart_port *uport) { - u32 rx_fifo; + struct qcom_geni_private_data *private_data = uport->private_data; u32 status; + u32 word_cnt; + int ret; + + if (!private_data->poll_cached_bytes_cnt) { + status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); - status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); - writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); - status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); - writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); + word_cnt = status & RX_FIFO_WC_MSK; + if (!word_cnt) + return NO_POLL_CHAR; + + if (word_cnt == 1 && (status & RX_LAST)) + /* + * NOTE: If RX_LAST_BYTE_VALID is 0 it needs to be + * treated as if it was BYTES_PER_FIFO_WORD. + */ + private_data->poll_cached_bytes_cnt = + (status & RX_LAST_BYTE_VALID_MSK) >> + RX_LAST_BYTE_VALID_SHFT; + + if (private_data->poll_cached_bytes_cnt == 0) + private_data->poll_cached_bytes_cnt = BYTES_PER_FIFO_WORD; + + private_data->poll_cached_bytes = + readl(uport->membase + SE_GENI_RX_FIFOn); + } - status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); - if (!(status & RX_FIFO_WC_MSK)) - return NO_POLL_CHAR; + private_data->poll_cached_bytes_cnt--; + ret = private_data->poll_cached_bytes & 0xff; + private_data->poll_cached_bytes >>= 8; - rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn); - return rx_fifo & 0xff; + return ret; } static void qcom_geni_serial_poll_put_char(struct uart_port *uport, unsigned char c) { - writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + if (qcom_geni_serial_main_active(uport)) { + qcom_geni_serial_poll_tx_done(uport); + __qcom_geni_serial_cancel_tx_cmd(uport); + } + + writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_setup_tx(uport, 1); - WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_TX_FIFO_WATERMARK_EN, true)); writel(c, uport->membase + SE_GENI_TX_FIFOn); - writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_poll_tx_done(uport); } + +static int qcom_geni_serial_poll_init(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + int ret; + + if (!port->setup) { + ret = qcom_geni_serial_port_setup(uport); + if (ret) + return ret; + } + + if (!qcom_geni_serial_secondary_active(uport)) + geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); + + return 0; +} #endif #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE -static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch) +static void qcom_geni_serial_drain_fifo(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + + qcom_geni_serial_poll_bitfield(uport, SE_GENI_M_GP_LENGTH, GP_LENGTH, + port->tx_queued); +} + +static void qcom_geni_serial_wr_char(struct uart_port *uport, unsigned char ch) { - writel(ch, uport->membase + SE_GENI_TX_FIFOn); + struct qcom_geni_private_data *private_data = uport->private_data; + + private_data->write_cached_bytes = + (private_data->write_cached_bytes >> 8) | (ch << 24); + private_data->write_cached_bytes_cnt++; + + if (private_data->write_cached_bytes_cnt == BYTES_PER_FIFO_WORD) { + writel(private_data->write_cached_bytes, + uport->membase + SE_GENI_TX_FIFOn); + private_data->write_cached_bytes_cnt = 0; + } } static void __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, unsigned int count) { + struct qcom_geni_private_data *private_data = uport->private_data; + int i; u32 bytes_to_send = count; @@ -385,6 +493,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, } writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_setup_tx(uport, bytes_to_send); for (i = 0; i < count; ) { size_t chars_to_write = 0; @@ -406,6 +515,15 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, SE_GENI_M_IRQ_CLEAR); i += chars_to_write; } + + if (private_data->write_cached_bytes_cnt) { + private_data->write_cached_bytes >>= BITS_PER_BYTE * + (BYTES_PER_FIFO_WORD - private_data->write_cached_bytes_cnt); + writel(private_data->write_cached_bytes, + uport->membase + SE_GENI_TX_FIFOn); + private_data->write_cached_bytes_cnt = 0; + } + qcom_geni_serial_poll_tx_done(uport); } @@ -414,71 +532,57 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, { struct uart_port *uport; struct qcom_geni_serial_port *port; + u32 m_irq_en, s_irq_en; bool locked = true; unsigned long flags; - u32 geni_status; - u32 irq_en; WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); - port = get_port_from_line(co->index, true); + port = get_port_from_line(co->index, true, NULL); if (IS_ERR(port)) return; uport = &port->uport; if (oops_in_progress) - locked = spin_trylock_irqsave(&uport->lock, flags); + locked = uart_port_trylock_irqsave(uport, &flags); else - spin_lock_irqsave(&uport->lock, flags); - - geni_status = readl(uport->membase + SE_GENI_STATUS); - - /* Cancel the current write to log the fault */ - if (!locked) { - geni_se_cancel_m_cmd(&port->se); - if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_CANCEL_EN, true)) { - geni_se_abort_m_cmd(&port->se); - qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_ABORT_EN, true); - writel(M_CMD_ABORT_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); - } - writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); - } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) { - /* - * It seems we can't interrupt existing transfers if all data - * has been sent, in which case we need to look for done first. - */ - qcom_geni_serial_poll_tx_done(uport); + uart_port_lock_irqsave(uport, &flags); - if (uart_circ_chars_pending(&uport->state->xmit)) { - irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); - writel(irq_en | M_TX_FIFO_WATERMARK_EN, - uport->membase + SE_GENI_M_IRQ_EN); - } + m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + s_irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + writel(0, uport->membase + SE_GENI_M_IRQ_EN); + writel(0, uport->membase + SE_GENI_S_IRQ_EN); + + if (qcom_geni_serial_main_active(uport)) { + /* Wait for completion or drain FIFO */ + if (!locked || port->tx_remaining == 0) + qcom_geni_serial_poll_tx_done(uport); + else + qcom_geni_serial_drain_fifo(uport); + + qcom_geni_serial_cancel_tx_cmd(uport); } __qcom_geni_serial_console_write(uport, s, count); - if (port->tx_remaining) - qcom_geni_serial_setup_tx(uport, port->tx_remaining); + writel(m_irq_en, uport->membase + SE_GENI_M_IRQ_EN); + writel(s_irq_en, uport->membase + SE_GENI_S_IRQ_EN); if (locked) - spin_unlock_irqrestore(&uport->lock, flags); + uart_port_unlock_irqrestore(uport, flags); } -static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) +static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) { u32 i; unsigned char buf[sizeof(u32)]; struct tty_port *tport; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); tport = &uport->state->port; for (i = 0; i < bytes; ) { int c; - int chunk = min_t(int, bytes - i, port->rx_bytes_pw); + int chunk = min_t(int, bytes - i, BYTES_PER_FIFO_WORD); ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1); i += chunk; @@ -503,73 +607,135 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) } if (!drop) tty_flip_buffer_push(tport); - return 0; } #else -static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) +static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) { - return -EPERM; -} +} #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */ -static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop) +static void handle_rx_uart(struct uart_port *uport, u32 bytes) { - struct tty_port *tport; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - u32 num_bytes_pw = port->tx_fifo_width / BITS_PER_BYTE; - u32 words = ALIGN(bytes, num_bytes_pw) / num_bytes_pw; + struct qcom_geni_serial_port *port = to_dev_port(uport); + struct tty_port *tport = &uport->state->port; int ret; - tport = &uport->state->port; - ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, port->rx_fifo, words); - if (drop) - return 0; - - ret = tty_insert_flip_string(tport, port->rx_fifo, bytes); + ret = tty_insert_flip_string(tport, port->rx_buf, bytes); if (ret != bytes) { - dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n", - __func__, ret, bytes); - WARN_ON_ONCE(1); + dev_err_ratelimited(uport->dev, "failed to push data (%d < %u)\n", + ret, bytes); } uport->icount.rx += ret; tty_flip_buffer_push(tport); - return ret; } -static void qcom_geni_serial_start_tx(struct uart_port *uport) +static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) { - u32 irq_en; - u32 status; + return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS); +} + +static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + bool done; + + if (!qcom_geni_serial_main_active(uport)) + return; + + if (port->tx_dma_addr) { + geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, + port->tx_remaining); + port->tx_dma_addr = 0; + port->tx_remaining = 0; + } + + geni_se_cancel_m_cmd(&port->se); + + done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, + M_CMD_CANCEL_EN, true); + if (!done) { + geni_se_abort_m_cmd(&port->se); + done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, + M_CMD_ABORT_EN, true); + if (!done) + dev_err_ratelimited(uport->dev, "M_CMD_ABORT_EN not set"); + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + } + + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); +} - status = readl(uport->membase + SE_GENI_STATUS); - if (status & M_GENI_CMD_ACTIVE) +static void qcom_geni_serial_start_tx_dma(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + struct tty_port *tport = &uport->state->port; + unsigned int xmit_size; + u8 *tail; + int ret; + + if (port->tx_dma_addr) return; - if (!qcom_geni_serial_tx_empty(uport)) + if (kfifo_is_empty(&tport->xmit_fifo)) + return; + + xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); + + qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_ON_SEND); + + qcom_geni_serial_setup_tx(uport, xmit_size); + + ret = geni_se_tx_dma_prep(&port->se, tail, xmit_size, + &port->tx_dma_addr); + if (ret) { + dev_err(uport->dev, "unable to start TX SE DMA: %d\n", ret); + qcom_geni_serial_stop_tx_dma(uport); return; + } + + port->tx_remaining = xmit_size; +} + +static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport) +{ + unsigned char c; + u32 irq_en; + + /* + * Start a new transfer in case the previous command was cancelled and + * left data in the FIFO which may prevent the watermark interrupt + * from triggering. Note that the stale data is discarded. + */ + if (!qcom_geni_serial_main_active(uport) && + !qcom_geni_serial_tx_empty(uport)) { + if (uart_fifo_out(uport, &c, 1) == 1) { + writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + qcom_geni_serial_setup_tx(uport, 1); + writel(c, uport->membase + SE_GENI_TX_FIFOn); + } + } irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; - writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } -static void qcom_geni_serial_stop_tx(struct uart_port *uport) +static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport) { u32 irq_en; - u32 status; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN); writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG); writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl(uport->membase + SE_GENI_STATUS); - /* Possible stop tx is called multiple times. */ - if (!(status & M_GENI_CMD_ACTIVE)) - return; +} + +static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); geni_se_cancel_m_cmd(&port->se); if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, @@ -582,32 +748,47 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport) writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } -static void qcom_geni_serial_start_rx(struct uart_port *uport) +static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport) { - u32 irq_en; - u32 status; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); - status = readl(uport->membase + SE_GENI_STATUS); - if (status & S_GENI_CMD_ACTIVE) - qcom_geni_serial_stop_rx(uport); + if (!qcom_geni_serial_main_active(uport)) + return; - geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); + __qcom_geni_serial_cancel_tx_cmd(uport); - irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); - irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; - writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + port->tx_remaining = 0; + port->tx_queued = 0; +} - irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; - writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); +static void qcom_geni_serial_handle_rx_fifo(struct uart_port *uport, bool drop) +{ + u32 status; + u32 word_cnt; + u32 last_word_byte_cnt; + u32 last_word_partial; + u32 total_bytes; + + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); + word_cnt = status & RX_FIFO_WC_MSK; + last_word_partial = status & RX_LAST; + last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> + RX_LAST_BYTE_VALID_SHFT; + + if (!word_cnt) + return; + total_bytes = BYTES_PER_FIFO_WORD * (word_cnt - 1); + if (last_word_partial && last_word_byte_cnt) + total_bytes += last_word_byte_cnt; + else + total_bytes += BYTES_PER_FIFO_WORD; + handle_rx_console(uport, total_bytes, drop); } -static void qcom_geni_serial_stop_rx(struct uart_port *uport) +static void qcom_geni_serial_stop_rx_fifo(struct uart_port *uport) { u32 irq_en; - u32 status; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); u32 s_irq_status; irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); @@ -618,9 +799,7 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl(uport->membase + SE_GENI_STATUS); - /* Possible stop rx is called multiple times. */ - if (!(status & S_GENI_CMD_ACTIVE)) + if (!qcom_geni_serial_secondary_active(uport)) return; geni_se_cancel_s_cmd(&port->se); @@ -633,52 +812,160 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); /* Flush the Rx buffer */ if (s_irq_status & S_RX_FIFO_LAST_EN) - qcom_geni_serial_handle_rx(uport, true); + qcom_geni_serial_handle_rx_fifo(uport, true); writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); - status = readl(uport->membase + SE_GENI_STATUS); - if (status & S_GENI_CMD_ACTIVE) + if (qcom_geni_serial_secondary_active(uport)) qcom_geni_serial_abort_rx(uport); } -static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) +static void qcom_geni_serial_start_rx_fifo(struct uart_port *uport) { - u32 status; - u32 word_cnt; - u32 last_word_byte_cnt; - u32 last_word_partial; - u32 total_bytes; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + u32 irq_en; + struct qcom_geni_serial_port *port = to_dev_port(uport); - status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); - word_cnt = status & RX_FIFO_WC_MSK; - last_word_partial = status & RX_LAST; - last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> - RX_LAST_BYTE_VALID_SHFT; + if (qcom_geni_serial_secondary_active(uport)) + qcom_geni_serial_stop_rx_fifo(uport); - if (!word_cnt) + geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); + + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); +} + +static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + bool done; + + if (!qcom_geni_serial_secondary_active(uport)) return; - total_bytes = port->rx_bytes_pw * (word_cnt - 1); - if (last_word_partial && last_word_byte_cnt) - total_bytes += last_word_byte_cnt; - else - total_bytes += port->rx_bytes_pw; - port->handle_rx(uport, total_bytes, drop); + + geni_se_cancel_s_cmd(&port->se); + done = qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT, + RX_EOT, true); + if (done) { + writel(RX_EOT | RX_DMA_DONE, + uport->membase + SE_DMA_RX_IRQ_CLR); + } else { + qcom_geni_serial_abort_rx(uport); + + writel(1, uport->membase + SE_DMA_RX_FSM_RST); + qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT, + RX_RESET_DONE, true); + writel(RX_RESET_DONE | RX_DMA_DONE, + uport->membase + SE_DMA_RX_IRQ_CLR); + } + + if (port->rx_dma_addr) { + geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr, + DMA_RX_BUF_SIZE); + port->rx_dma_addr = 0; + } +} + +static void qcom_geni_serial_start_rx_dma(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + int ret; + + if (qcom_geni_serial_secondary_active(uport)) + qcom_geni_serial_stop_rx_dma(uport); + + geni_se_setup_s_cmd(&port->se, UART_START_READ, UART_PARAM_RFR_OPEN); + + ret = geni_se_rx_dma_prep(&port->se, port->rx_buf, + DMA_RX_BUF_SIZE, + &port->rx_dma_addr); + if (ret) { + dev_err(uport->dev, "unable to start RX SE DMA: %d\n", ret); + qcom_geni_serial_stop_rx_dma(uport); + } +} + +static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + u32 rx_in; + int ret; + + if (!qcom_geni_serial_secondary_active(uport)) + return; + + if (!port->rx_dma_addr) + return; + + geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr, DMA_RX_BUF_SIZE); + port->rx_dma_addr = 0; + + rx_in = readl(uport->membase + SE_DMA_RX_LEN_IN); + if (!rx_in) { + dev_warn(uport->dev, "serial engine reports 0 RX bytes in!\n"); + return; + } + + if (!drop) + handle_rx_uart(uport, rx_in); + + ret = geni_se_rx_dma_prep(&port->se, port->rx_buf, + DMA_RX_BUF_SIZE, + &port->rx_dma_addr); + if (ret) { + dev_err(uport->dev, "unable to start RX SE DMA: %d\n", ret); + qcom_geni_serial_stop_rx_dma(uport); + } } -static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, - bool active) +static void qcom_geni_serial_start_rx(struct uart_port *uport) { - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - struct circ_buf *xmit = &uport->state->xmit; + uport->ops->start_rx(uport); +} + +static void qcom_geni_serial_stop_rx(struct uart_port *uport) +{ + uport->ops->stop_rx(uport); +} + +static void qcom_geni_serial_stop_tx(struct uart_port *uport) +{ + uport->ops->stop_tx(uport); +} + +static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport, + unsigned int chunk) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + unsigned int tx_bytes, remaining = chunk; + u8 buf[BYTES_PER_FIFO_WORD]; + + while (remaining) { + memset(buf, 0, sizeof(buf)); + tx_bytes = min(remaining, BYTES_PER_FIFO_WORD); + + uart_fifo_out(uport, buf, tx_bytes); + + iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); + + remaining -= tx_bytes; + port->tx_remaining -= tx_bytes; + } +} + +static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport, + bool done, bool active) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + struct tty_port *tport = &uport->state->port; size_t avail; - size_t remaining; size_t pending; - int i; u32 status; u32 irq_en; unsigned int chunk; - int tail; status = readl(uport->membase + SE_GENI_TX_FIFO_STATUS); @@ -686,25 +973,29 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, if (active) pending = port->tx_remaining; else - pending = uart_circ_chars_pending(xmit); + pending = kfifo_len(&tport->xmit_fifo); - /* All data has been transmitted and acknowledged as received */ - if (!pending && !status && done) { - qcom_geni_serial_stop_tx(uport); + /* All data has been transmitted or command has been cancelled */ + if (!pending && done) { + qcom_geni_serial_stop_tx_fifo(uport); goto out_write_wakeup; } - avail = port->tx_fifo_depth - (status & TX_FIFO_WC); - avail *= port->tx_bytes_pw; + if (active) + avail = port->tx_fifo_depth - (status & TX_FIFO_WC); + else + avail = port->tx_fifo_depth; + + avail *= BYTES_PER_FIFO_WORD; - tail = xmit->tail; chunk = min(avail, pending); if (!chunk) goto out_write_wakeup; - if (!port->tx_remaining) { + if (!active) { qcom_geni_serial_setup_tx(uport, pending); port->tx_remaining = pending; + port->tx_queued = 0; irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); if (!(irq_en & M_TX_FIFO_WATERMARK_EN)) @@ -712,29 +1003,8 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, uport->membase + SE_GENI_M_IRQ_EN); } - remaining = chunk; - for (i = 0; i < chunk; ) { - unsigned int tx_bytes; - u8 buf[sizeof(u32)]; - int c; - - memset(buf, 0, ARRAY_SIZE(buf)); - tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw); - - for (c = 0; c < tx_bytes ; c++) { - buf[c] = xmit->buf[tail++]; - tail &= UART_XMIT_SIZE - 1; - } - - iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); - - i += tx_bytes; - uport->icount.tx += tx_bytes; - remaining -= tx_bytes; - port->tx_remaining -= tx_bytes; - } - - xmit->tail = tail; + qcom_geni_serial_send_chunk_fifo(uport, chunk); + port->tx_queued += chunk; /* * The tx fifo watermark is level triggered and latched. Though we had @@ -752,7 +1022,24 @@ out_write_wakeup: uport->membase + SE_GENI_M_IRQ_EN); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(uport); +} + +static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + struct tty_port *tport = &uport->state->port; + + uart_xmit_advance(uport, port->tx_remaining); + geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining); + port->tx_dma_addr = 0; + port->tx_remaining = 0; + + if (!kfifo_is_empty(&tport->xmit_fifo)) + qcom_geni_serial_start_tx_dma(uport); + + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(uport); } @@ -762,22 +1049,30 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) u32 m_irq_status; u32 s_irq_status; u32 geni_status; + u32 dma; + u32 dma_tx_status; + u32 dma_rx_status; struct uart_port *uport = dev; - unsigned long flags; bool drop_rx = false; struct tty_port *tport = &uport->state->port; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); if (uport->suspended) return IRQ_NONE; - spin_lock_irqsave(&uport->lock, flags); + uart_port_lock(uport); + m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + dma_tx_status = readl(uport->membase + SE_DMA_TX_IRQ_STAT); + dma_rx_status = readl(uport->membase + SE_DMA_RX_IRQ_STAT); geni_status = readl(uport->membase + SE_GENI_STATUS); + dma = readl(uport->membase + SE_GENI_DMA_MODE_EN); m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); + writel(dma_tx_status, uport->membase + SE_DMA_TX_IRQ_CLR); + writel(dma_rx_status, uport->membase + SE_DMA_RX_IRQ_CLR); if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN)) goto out_unlock; @@ -787,33 +1082,57 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) tty_insert_flip_char(tport, 0, TTY_OVERRUN); } - if (m_irq_status & m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) - qcom_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN, - geni_status & M_GENI_CMD_ACTIVE); - - if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) { + if (s_irq_status & (S_GP_IRQ_0_EN | S_GP_IRQ_1_EN)) { if (s_irq_status & S_GP_IRQ_0_EN) uport->icount.parity++; drop_rx = true; - } else if (s_irq_status & S_GP_IRQ_2_EN || - s_irq_status & S_GP_IRQ_3_EN) { + } else if (s_irq_status & (S_GP_IRQ_2_EN | S_GP_IRQ_3_EN)) { uport->icount.brk++; port->brk = true; } - if (s_irq_status & S_RX_FIFO_WATERMARK_EN || - s_irq_status & S_RX_FIFO_LAST_EN) - qcom_geni_serial_handle_rx(uport, drop_rx); + if (dma) { + if (dma_tx_status & TX_DMA_DONE) { + qcom_geni_serial_handle_tx_dma(uport); + qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_AFTER_SEND); + } + + if (dma_rx_status) { + if (dma_rx_status & RX_RESET_DONE) + goto out_unlock; + + if (dma_rx_status & RX_DMA_PARITY_ERR) { + uport->icount.parity++; + drop_rx = true; + } + + if (dma_rx_status & RX_DMA_BREAK) + uport->icount.brk++; + + if (dma_rx_status & (RX_DMA_DONE | RX_EOT)) + qcom_geni_serial_handle_rx_dma(uport, drop_rx); + } + } else { + if (m_irq_status & m_irq_en & + (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) + qcom_geni_serial_handle_tx_fifo(uport, + m_irq_status & M_CMD_DONE_EN, + geni_status & M_GENI_CMD_ACTIVE); + + if (s_irq_status & (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN)) + qcom_geni_serial_handle_rx_fifo(uport, drop_rx); + } out_unlock: - uart_unlock_and_check_sysrq(uport, flags); + uart_unlock_and_check_sysrq(uport); return IRQ_HANDLED; } -static void get_tx_fifo_size(struct qcom_geni_serial_port *port) +static int setup_fifos(struct qcom_geni_serial_port *port) { struct uart_port *uport; + u32 old_rx_fifo_depth = port->rx_fifo_depth; uport = &port->uport; port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se); @@ -821,38 +1140,66 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se); uport->fifosize = (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; + + if (port->rx_buf && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) { + /* + * Use krealloc rather than krealloc_array because rx_buf is + * accessed as 1 byte entries as well as 4 byte entries so it's + * not necessarily an array. + */ + port->rx_buf = devm_krealloc(uport->dev, port->rx_buf, + port->rx_fifo_depth * sizeof(u32), + GFP_KERNEL); + if (!port->rx_buf) + return -ENOMEM; + } + + return 0; } static void qcom_geni_serial_shutdown(struct uart_port *uport) { disable_irq(uport->irq); + + uart_port_lock_irq(uport); + qcom_geni_serial_stop_tx(uport); + qcom_geni_serial_stop_rx(uport); + + qcom_geni_serial_cancel_tx_cmd(uport); + uart_port_unlock_irq(uport); +} + +static void qcom_geni_serial_flush_buffer(struct uart_port *uport) +{ + qcom_geni_serial_cancel_tx_cmd(uport); } static int qcom_geni_serial_port_setup(struct uart_port *uport) { - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; u32 proto; u32 pin_swap; - - if (uart_console(uport)) { - port->tx_bytes_pw = 1; - port->rx_bytes_pw = CONSOLE_RX_BYTES_PW; - } else { - port->tx_bytes_pw = 4; - port->rx_bytes_pw = 4; - } + int ret; proto = geni_se_read_proto(&port->se); - if (proto != GENI_SE_UART) { + if (proto == GENI_SE_INVALID_PROTO) { + ret = geni_load_se_firmware(&port->se, GENI_SE_UART); + if (ret) { + dev_err(uport->dev, "UART firmware load failed ret: %d\n", ret); + return ret; + } + } else if (proto != GENI_SE_UART) { dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto); return -ENXIO; } qcom_geni_serial_stop_rx(uport); - get_tx_fifo_size(port); + ret = setup_fifos(port); + if (ret) + return ret; writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); @@ -875,12 +1222,10 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) */ if (uart_console(uport)) qcom_geni_serial_poll_tx_done(uport); - geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw, - false, true, false); - geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw, - false, false, true); + geni_se_config_packing(&port->se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD, + false, true, true); geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2); - geni_se_select_mode(&port->se, GENI_SE_FIFO); + geni_se_select_mode(&port->se, port->dev_data->mode); port->setup = true; return 0; @@ -889,82 +1234,136 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) static int qcom_geni_serial_startup(struct uart_port *uport) { int ret; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct qcom_geni_serial_port *port = to_dev_port(uport); if (!port->setup) { ret = qcom_geni_serial_port_setup(uport); if (ret) return ret; } + + uart_port_lock_irq(uport); + qcom_geni_serial_start_rx(uport); + uart_port_unlock_irq(uport); + enable_irq(uport->irq); return 0; } -static unsigned long get_clk_cfg(unsigned long clk_freq) +static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) { - int i; + struct qcom_geni_serial_port *port = to_dev_port(uport); + unsigned long clk_rate; + unsigned int avg_bw_core, clk_idx; + unsigned int clk_div; + u32 ver, sampling_rate; + u32 ser_clk_cfg; + int ret; + + sampling_rate = UART_OVERSAMPLING; + /* Sampling rate is halved for IP versions >= 2.5 */ + ver = geni_se_get_qup_hw_version(&port->se); + if (ver >= QUP_SE_VERSION_2_5) + sampling_rate /= 2; + + ret = geni_se_clk_freq_match(&port->se, baud * sampling_rate, &clk_idx, &clk_rate, false); + if (ret) { + dev_err(port->se.dev, "Failed to find src clk for baud rate: %d ret: %d\n", + baud, ret); + return ret; + } - for (i = 0; i < ARRAY_SIZE(root_freq); i++) { - if (!(root_freq[i] % clk_freq)) - return root_freq[i]; + clk_div = DIV_ROUND_UP(clk_rate, baud * sampling_rate); + /* Check if calculated divider exceeds maximum allowed value */ + if (clk_div > (CLK_DIV_MSK >> CLK_DIV_SHFT)) { + dev_err(port->se.dev, "Calculated clock divider %u exceeds maximum\n", clk_div); + return -EINVAL; } + + dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n, clk_idx = %u\n", + baud * sampling_rate, clk_rate, clk_div, clk_idx); + + uport->uartclk = clk_rate; + port->clk_rate = clk_rate; + dev_pm_opp_set_rate(uport->dev, clk_rate); + ser_clk_cfg = SER_CLK_EN; + ser_clk_cfg |= clk_div << CLK_DIV_SHFT; + + /* + * Bump up BW vote on CPU and CORE path as driver supports FIFO mode + * only. + */ + avg_bw_core = (baud > 115200) ? Bps_to_icc(CORE_2X_50_MHZ) + : GENI_DEFAULT_BW; + port->se.icc_paths[GENI_TO_CORE].avg_bw = avg_bw_core; + port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud); + geni_icc_set_bw(&port->se); + + writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); + writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); + /* Configure clock selection register with the selected clock index */ + writel(clk_idx & CLK_SEL_MSK, uport->membase + SE_GENI_CLK_SEL); return 0; } -static unsigned long get_clk_div_rate(unsigned int baud, - unsigned int sampling_rate, unsigned int *clk_div) +static int geni_serial_set_level(struct uart_port *uport, unsigned int baud) { - unsigned long ser_clk; - unsigned long desired_clk; + struct qcom_geni_serial_port *port = to_dev_port(uport); + struct device *perf_dev = port->pd_list->pd_devs[DOMAIN_IDX_PERF]; - desired_clk = baud * sampling_rate; - ser_clk = get_clk_cfg(desired_clk); - if (!ser_clk) { - pr_err("%s: Can't find matching DFS entry for baud %d\n", - __func__, baud); - return ser_clk; - } + /* + * The performance protocol sets UART communication + * speeds by selecting different performance levels + * through the OPP framework. + * + * Supported perf levels for baudrates in firmware are below + * +---------------------+--------------------+ + * | Perf level value | Baudrate values | + * +---------------------+--------------------+ + * | 300 | 300 | + * | 1200 | 1200 | + * | 2400 | 2400 | + * | 4800 | 4800 | + * | 9600 | 9600 | + * | 19200 | 19200 | + * | 38400 | 38400 | + * | 57600 | 57600 | + * | 115200 | 115200 | + * | 230400 | 230400 | + * | 460800 | 460800 | + * | 921600 | 921600 | + * | 2000000 | 2000000 | + * | 3000000 | 3000000 | + * | 3200000 | 3200000 | + * | 4000000 | 4000000 | + * +---------------------+--------------------+ + */ - *clk_div = ser_clk / desired_clk; - return ser_clk; + return dev_pm_opp_set_level(perf_dev, baud); } static void qcom_geni_serial_set_termios(struct uart_port *uport, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { + struct qcom_geni_serial_port *port = to_dev_port(uport); unsigned int baud; + unsigned long timeout; u32 bits_per_char; u32 tx_trans_cfg; u32 tx_parity_cfg; u32 rx_trans_cfg; u32 rx_parity_cfg; u32 stop_bit_len; - unsigned int clk_div; - u32 ser_clk_cfg; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - unsigned long clk_rate; - u32 ver, sampling_rate; + int ret = 0; - qcom_geni_serial_stop_rx(uport); /* baud rate */ - baud = uart_get_baud_rate(uport, termios, old, 300, 4000000); - port->baud = baud; + baud = uart_get_baud_rate(uport, termios, old, 300, 8000000); - sampling_rate = UART_OVERSAMPLING; - /* Sampling rate is halved for IP versions >= 2.5 */ - ver = geni_se_get_qup_hw_version(&port->se); - if (GENI_SE_VERSION_MAJOR(ver) >= 2 && GENI_SE_VERSION_MINOR(ver) >= 5) - sampling_rate /= 2; - - clk_rate = get_clk_div_rate(baud, sampling_rate, &clk_div); - if (!clk_rate) - goto out_restart_rx; - - uport->uartclk = clk_rate; - clk_set_rate(port->se.clk, clk_rate); - ser_clk_cfg = SER_CLK_EN; - ser_clk_cfg |= clk_div << CLK_DIV_SHFT; + ret = port->dev_data->set_rate(uport, baud); + if (ret) + return; /* parity */ tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG); @@ -994,21 +1393,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, } /* bits per char */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits_per_char = 5; - break; - case CS6: - bits_per_char = 6; - break; - case CS7: - bits_per_char = 7; - break; - case CS8: - default: - bits_per_char = 8; - break; - } + bits_per_char = tty_get_char_size(termios->c_cflag); /* stop bits */ if (termios->c_cflag & CSTOPB) @@ -1022,9 +1407,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, else tx_trans_cfg |= UART_CTS_MASK; - if (baud) + if (baud) { uart_update_timeout(uport, termios->c_cflag, baud); + /* + * Make sure that qcom_geni_serial_poll_bitfield() waits for + * the FIFO, two-word intermediate transfer register and shift + * register to clear. + * + * Note that uart_fifo_timeout() also adds a 20 ms margin. + */ + timeout = jiffies_to_usecs(uart_fifo_timeout(uport)); + timeout += 3 * timeout / port->tx_fifo_depth; + WRITE_ONCE(port->poll_timeout_us, timeout); + } + if (!uart_console(uport)) writel(port->loopback, uport->membase + SE_UART_LOOPBACK_CFG); @@ -1035,23 +1432,14 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); - writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); - writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); -out_restart_rx: - qcom_geni_serial_start_rx(uport); -} - -static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) -{ - return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS); } #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE -static int __init qcom_geni_console_setup(struct console *co, char *options) +static int qcom_geni_console_setup(struct console *co, char *options) { struct uart_port *uport; struct qcom_geni_serial_port *port; - int baud = 9600; + int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; @@ -1060,7 +1448,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) if (co->index >= GENI_UART_CONS_PORTS || co->index < 0) return -ENXIO; - port = get_port_from_line(co->index, true); + port = get_port_from_line(co->index, true, NULL); if (IS_ERR(port)) { pr_err("Invalid line %d\n", co->index); return PTR_ERR(port); @@ -1121,6 +1509,8 @@ static inline void qcom_geni_serial_enable_early_read(struct geni_se *se, struct console *con) { } #endif +static struct qcom_geni_private_data earlycon_private_data; + static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, const char *opt) { @@ -1136,6 +1526,8 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, if (!uport->membase) return -EINVAL; + uport->private_data = &earlycon_private_data; + memset(&se, 0, sizeof(se)); se.base = uport->membase; if (geni_se_read_proto(&se) != GENI_SE_UART) @@ -1153,7 +1545,8 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, */ qcom_geni_serial_poll_tx_done(uport); qcom_geni_serial_abort_rx(uport); - geni_se_config_packing(&se, BITS_PER_BYTE, 1, false, true, false); + geni_se_config_packing(&se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD, + false, true, true); geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2); geni_se_select_mode(&se, GENI_SE_FIFO); @@ -1216,50 +1609,164 @@ static struct uart_driver qcom_geni_uart_driver = { .owner = THIS_MODULE, .driver_name = "qcom_geni_uart", .dev_name = "ttyHS", - .nr = GENI_UART_PORTS, + .nr = CONFIG_SERIAL_QCOM_GENI_UART_PORTS, }; +static int geni_serial_resources_on(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + int ret; + + ret = geni_icc_enable(&port->se); + if (ret) + return ret; + + ret = geni_se_resources_on(&port->se); + if (ret) { + geni_icc_disable(&port->se); + return ret; + } + + if (port->clk_rate) + dev_pm_opp_set_rate(uport->dev, port->clk_rate); + + return 0; +} + +static int geni_serial_resources_off(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + int ret; + + dev_pm_opp_set_rate(uport->dev, 0); + ret = geni_se_resources_off(&port->se); + if (ret) + return ret; + + geni_icc_disable(&port->se); + + return 0; +} + +static int geni_serial_resource_state(struct uart_port *uport, bool power_on) +{ + return power_on ? geni_serial_resources_on(uport) : geni_serial_resources_off(uport); +} + +static int geni_serial_pwr_init(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + int ret; + + ret = dev_pm_domain_attach_list(port->se.dev, + &port->dev_data->pd_data, &port->pd_list); + if (ret <= 0) + return -EINVAL; + + return 0; +} + +static int geni_serial_resource_init(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + int ret; + + port->se.clk = devm_clk_get(port->se.dev, "se"); + if (IS_ERR(port->se.clk)) { + ret = PTR_ERR(port->se.clk); + dev_err(port->se.dev, "Err getting SE Core clk %d\n", ret); + return ret; + } + + ret = geni_icc_get(&port->se, NULL); + if (ret) + return ret; + + port->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW; + port->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; + + /* Set BW for register access */ + ret = geni_icc_set_bw(&port->se); + if (ret) + return ret; + + ret = devm_pm_opp_set_clkname(port->se.dev, "se"); + if (ret) + return ret; + + /* OPP table is optional */ + ret = devm_pm_opp_of_add_table(port->se.dev); + if (ret && ret != -ENODEV) { + dev_err(port->se.dev, "invalid OPP table in device tree\n"); + return ret; + } + + return 0; +} + static void qcom_geni_serial_pm(struct uart_port *uport, unsigned int new_state, unsigned int old_state) { - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); /* If we've never been called, treat it as off */ if (old_state == UART_PM_STATE_UNDEFINED) old_state = UART_PM_STATE_OFF; if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) - geni_se_resources_on(&port->se); + pm_runtime_resume_and_get(uport->dev); else if (new_state == UART_PM_STATE_OFF && - old_state == UART_PM_STATE_ON) - geni_se_resources_off(&port->se); + old_state == UART_PM_STATE_ON) + pm_runtime_put_sync(uport->dev); + +} + +/** + * qcom_geni_rs485_config - Configure RS485 settings for the UART port + * @uport: Pointer to the UART port structure + * @termios: Pointer to the termios structure + * @rs485: Pointer to the RS485 configuration structure + * This function configures the RTS (Request to Send) pin behavior for RS485 mode. + * When RS485 mode is enabled, the RTS pin is kept in default ACTIVE HIGH state. + * Return: Always returns 0. + */ + +static int qcom_geni_rs485_config(struct uart_port *uport, + struct ktermios *termios, struct serial_rs485 *rs485) +{ + qcom_geni_set_rs485_mode(uport, SER_RS485_ENABLED); + + return 0; } static const struct uart_ops qcom_geni_console_pops = { .tx_empty = qcom_geni_serial_tx_empty, - .stop_tx = qcom_geni_serial_stop_tx, - .start_tx = qcom_geni_serial_start_tx, - .stop_rx = qcom_geni_serial_stop_rx, + .stop_tx = qcom_geni_serial_stop_tx_fifo, + .start_tx = qcom_geni_serial_start_tx_fifo, + .stop_rx = qcom_geni_serial_stop_rx_fifo, + .start_rx = qcom_geni_serial_start_rx_fifo, .set_termios = qcom_geni_serial_set_termios, .startup = qcom_geni_serial_startup, .request_port = qcom_geni_serial_request_port, .config_port = qcom_geni_serial_config_port, .shutdown = qcom_geni_serial_shutdown, + .flush_buffer = qcom_geni_serial_flush_buffer, .type = qcom_geni_serial_get_type, .set_mctrl = qcom_geni_serial_set_mctrl, .get_mctrl = qcom_geni_serial_get_mctrl, #ifdef CONFIG_CONSOLE_POLL .poll_get_char = qcom_geni_serial_get_char, .poll_put_char = qcom_geni_serial_poll_put_char, + .poll_init = qcom_geni_serial_poll_init, #endif .pm = qcom_geni_serial_pm, }; static const struct uart_ops qcom_geni_uart_pops = { .tx_empty = qcom_geni_serial_tx_empty, - .stop_tx = qcom_geni_serial_stop_tx, - .start_tx = qcom_geni_serial_start_tx, - .stop_rx = qcom_geni_serial_stop_rx, + .stop_tx = qcom_geni_serial_stop_tx_dma, + .start_tx = qcom_geni_serial_start_tx_dma, + .start_rx = qcom_geni_serial_start_rx_dma, + .stop_rx = qcom_geni_serial_stop_rx_dma, .set_termios = qcom_geni_serial_set_termios, .startup = qcom_geni_serial_startup, .request_port = qcom_geni_serial_request_port, @@ -1274,26 +1781,29 @@ static const struct uart_ops qcom_geni_uart_pops = { static int qcom_geni_serial_probe(struct platform_device *pdev) { int ret = 0; - int line = -1; + int line; struct qcom_geni_serial_port *port; struct uart_port *uport; struct resource *res; int irq; - bool console = false; struct uart_driver *drv; + const struct qcom_geni_device_data *data; - if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart")) - console = true; + data = of_device_get_match_data(&pdev->dev); + if (!data) + return -EINVAL; - if (console) { + if (data->console) { drv = &qcom_geni_console_driver; line = of_alias_get_id(pdev->dev.of_node, "serial"); } else { drv = &qcom_geni_uart_driver; - line = of_alias_get_id(pdev->dev.of_node, "hsuart"); + line = of_alias_get_id(pdev->dev.of_node, "serial"); + if (line == -ENODEV) /* compat with non-standard aliases */ + line = of_alias_get_id(pdev->dev.of_node, "hsuart"); } - port = get_port_from_line(line, console); + port = get_port_from_line(line, data->console, &pdev->dev); if (IS_ERR(port)) { dev_err(&pdev->dev, "Invalid line %d\n", line); return PTR_ERR(port); @@ -1305,44 +1815,55 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) return -ENODEV; uport->dev = &pdev->dev; + port->dev_data = data; port->se.dev = &pdev->dev; port->se.wrapper = dev_get_drvdata(pdev->dev.parent); - port->se.clk = devm_clk_get(&pdev->dev, "se"); - if (IS_ERR(port->se.clk)) { - ret = PTR_ERR(port->se.clk); - dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); + + ret = port->dev_data->resources_init(uport); + if (ret) return ret; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; + if (!res) { + ret = -EINVAL; + goto error; + } + uport->mapbase = res->start; + uport->rs485_config = qcom_geni_rs485_config; + uport->rs485_supported = qcom_geni_rs485_supported; port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS; port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS; port->tx_fifo_width = DEF_FIFO_WIDTH_BITS; - if (!console) { - port->rx_fifo = devm_kcalloc(uport->dev, - port->rx_fifo_depth, sizeof(u32), GFP_KERNEL); - if (!port->rx_fifo) - return -ENOMEM; + if (!data->console) { + port->rx_buf = devm_kzalloc(uport->dev, + DMA_RX_BUF_SIZE, GFP_KERNEL); + if (!port->rx_buf) { + ret = -ENOMEM; + goto error; + } } port->name = devm_kasprintf(uport->dev, GFP_KERNEL, "qcom_geni_serial_%s%d", uart_console(uport) ? "console" : "uart", uport->line); - if (!port->name) - return -ENOMEM; + if (!port->name) { + ret = -ENOMEM; + goto error; + } irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto error; + } + uport->irq = irq; uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE); - if (!console) + if (!data->console) port->wakeup_irq = platform_get_irq_optional(pdev, 1); if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap")) @@ -1351,29 +1872,27 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap")) port->cts_rts_swap = true; - uport->private_data = drv; + port->private_data.drv = drv; + uport->private_data = &port->private_data; platform_set_drvdata(pdev, port); - port->handle_rx = console ? handle_rx_console : handle_rx_uart; - - ret = uart_add_one_port(drv, uport); - if (ret) - return ret; irq_set_status_flags(uport->irq, IRQ_NOAUTOEN); ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH, port->name, uport); if (ret) { dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); - uart_remove_one_port(drv, uport); - return ret; + goto error; } - /* - * Set pm_runtime status as ACTIVE so that wakeup_irq gets - * enabled/disabled from dev_pm_arm_wake_irq during system - * suspend/resume respectively. - */ - pm_runtime_set_active(&pdev->dev); + ret = uart_get_rs485_mode(uport); + if (ret) + goto error; + + devm_pm_runtime_enable(port->se.dev); + + ret = uart_add_one_port(drv, uport); + if (ret) + goto error; if (port->wakeup_irq > 0) { device_init_wakeup(&pdev->dev, true); @@ -1381,50 +1900,151 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) port->wakeup_irq); if (ret) { device_init_wakeup(&pdev->dev, false); + ida_free(&port_ida, uport->line); uart_remove_one_port(drv, uport); - return ret; + goto error; } } return 0; + +error: + dev_pm_domain_detach_list(port->pd_list); + return ret; } -static int qcom_geni_serial_remove(struct platform_device *pdev) +static void qcom_geni_serial_remove(struct platform_device *pdev) { struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); - struct uart_driver *drv = port->uport.private_data; + struct uart_port *uport = &port->uport; + struct uart_driver *drv = port->private_data.drv; dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); + ida_free(&port_ida, uport->line); uart_remove_one_port(drv, &port->uport); + dev_pm_domain_detach_list(port->pd_list); +} - return 0; +static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev) +{ + struct qcom_geni_serial_port *port = dev_get_drvdata(dev); + struct uart_port *uport = &port->uport; + int ret = 0; + + if (port->dev_data->power_state) + ret = port->dev_data->power_state(uport, false); + + return ret; } -static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) +static int __maybe_unused qcom_geni_serial_runtime_resume(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = &port->uport; + int ret = 0; + + if (port->dev_data->power_state) + ret = port->dev_data->power_state(uport, true); - return uart_suspend_port(uport->private_data, uport); + return ret; } -static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) +static int qcom_geni_serial_suspend(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = &port->uport; + struct qcom_geni_private_data *private_data = uport->private_data; + + /* + * This is done so we can hit the lowest possible state in suspend + * even with no_console_suspend + */ + if (uart_console(uport)) { + geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ACTIVE_ONLY); + geni_icc_set_bw(&port->se); + } + return uart_suspend_port(private_data->drv, uport); +} + +static int qcom_geni_serial_resume(struct device *dev) +{ + int ret; + struct qcom_geni_serial_port *port = dev_get_drvdata(dev); + struct uart_port *uport = &port->uport; + struct qcom_geni_private_data *private_data = uport->private_data; - return uart_resume_port(uport->private_data, uport); + ret = uart_resume_port(private_data->drv, uport); + if (uart_console(uport)) { + geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS); + geni_icc_set_bw(&port->se); + } + return ret; } +static const struct qcom_geni_device_data qcom_geni_console_data = { + .console = true, + .mode = GENI_SE_FIFO, + .resources_init = geni_serial_resource_init, + .set_rate = geni_serial_set_rate, + .power_state = geni_serial_resource_state, +}; + +static const struct qcom_geni_device_data qcom_geni_uart_data = { + .console = false, + .mode = GENI_SE_DMA, + .resources_init = geni_serial_resource_init, + .set_rate = geni_serial_set_rate, + .power_state = geni_serial_resource_state, +}; + +static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = { + .console = true, + .mode = GENI_SE_FIFO, + .pd_data = { + .pd_flags = PD_FLAG_DEV_LINK_ON, + .pd_names = (const char*[]) { "power", "perf" }, + .num_pd_names = 2, + }, + .resources_init = geni_serial_pwr_init, + .set_rate = geni_serial_set_level, +}; + +static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = { + .console = false, + .mode = GENI_SE_DMA, + .pd_data = { + .pd_flags = PD_FLAG_DEV_LINK_ON, + .pd_names = (const char*[]) { "power", "perf" }, + .num_pd_names = 2, + }, + .resources_init = geni_serial_pwr_init, + .set_rate = geni_serial_set_level, +}; + static const struct dev_pm_ops qcom_geni_serial_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend, - qcom_geni_serial_sys_resume) + SET_RUNTIME_PM_OPS(qcom_geni_serial_runtime_suspend, + qcom_geni_serial_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume) }; static const struct of_device_id qcom_geni_serial_match_table[] = { - { .compatible = "qcom,geni-debug-uart", }, - { .compatible = "qcom,geni-uart", }, + { + .compatible = "qcom,geni-debug-uart", + .data = &qcom_geni_console_data, + }, + { + .compatible = "qcom,sa8255p-geni-debug-uart", + .data = &sa8255p_qcom_geni_console_data, + }, + { + .compatible = "qcom,geni-uart", + .data = &qcom_geni_uart_data, + }, + { + .compatible = "qcom,sa8255p-geni-uart", + .data = &sa8255p_qcom_geni_uart_data, + }, {} }; MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index b5ef86ae2746..87fa30d68687 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -139,12 +139,12 @@ static unsigned int rda_uart_tx_empty(struct uart_port *port) unsigned int ret; u32 val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = rda_uart_read(port, RDA_UART_STATUS); ret = (val & RDA_UART_TX_FIFO_MASK) ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return ret; } @@ -238,7 +238,7 @@ static void rda_uart_change_baudrate(struct rda_uart_port *rda_port, static void rda_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct rda_uart_port *rda_port = to_rda_uart_port(port); unsigned long flags; @@ -246,7 +246,7 @@ static void rda_uart_set_termios(struct uart_port *port, unsigned int baud; u32 irq_mask; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); baud = uart_get_baud_rate(port, termios, old, 9600, port->uartclk / 4); rda_uart_change_baudrate(rda_port, baud); @@ -259,9 +259,11 @@ static void rda_uart_set_termios(struct uart_port *port, case CS5: case CS6: dev_warn(port->dev, "bit size not supported, using 7 bits\n"); - /* Fall through */ + fallthrough; case CS7: ctrl &= ~RDA_UART_DBITS_8; + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS7; break; default: ctrl |= RDA_UART_DBITS_8; @@ -323,13 +325,13 @@ static void rda_uart_set_termios(struct uart_port *port, /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void rda_uart_send_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int ch; + struct tty_port *tport = &port->state->port; + unsigned char ch; u32 val; if (uart_tx_stopped(port)) @@ -345,20 +347,14 @@ static void rda_uart_send_chars(struct uart_port *port) port->x_char = 0; } - while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) { - if (uart_circ_empty(xmit)) - break; - - ch = xmit->buf[xmit->tail]; + while ((rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) && + uart_fifo_get(port, &ch)) rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER); - xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1); - port->icount.tx++; - } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { /* Re-enable Tx FIFO interrupt */ val = rda_uart_read(port, RDA_UART_IRQ_MASK); val |= RDA_UART_TX_DATA_NEEDED; @@ -393,23 +389,21 @@ static void rda_uart_receive_chars(struct uart_port *port) val &= 0xff; port->icount.rx++; - tty_insert_flip_char(&port->state->port, val, flag); + if (!uart_prepare_sysrq_char(port, val)) + tty_insert_flip_char(&port->state->port, val, flag); status = rda_uart_read(port, RDA_UART_STATUS); } - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static irqreturn_t rda_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; - unsigned long flags; u32 val, irq_mask; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock(port); /* Clear IRQ cause */ val = rda_uart_read(port, RDA_UART_IRQ_CAUSE); @@ -426,7 +420,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id) rda_uart_send_chars(port); } - spin_unlock_irqrestore(&port->lock, flags); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -437,16 +431,16 @@ static int rda_uart_startup(struct uart_port *port) int ret; u32 val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); rda_uart_write(port, 0, RDA_UART_IRQ_MASK); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); ret = request_irq(port->irq, rda_interrupt, IRQF_NO_SUSPEND, "rda-uart", port); if (ret) return ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); val = rda_uart_read(port, RDA_UART_CTRL); val |= RDA_UART_ENABLE; @@ -457,7 +451,7 @@ static int rda_uart_startup(struct uart_port *port) val |= (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT); rda_uart_write(port, val, RDA_UART_IRQ_MASK); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -467,7 +461,7 @@ static void rda_uart_shutdown(struct uart_port *port) unsigned long flags; u32 val; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); rda_uart_stop_tx(port); rda_uart_stop_rx(port); @@ -476,7 +470,7 @@ static void rda_uart_shutdown(struct uart_port *port) val &= ~RDA_UART_ENABLE; rda_uart_write(port, val, RDA_UART_CTRL); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *rda_uart_type(struct uart_port *port) @@ -516,7 +510,7 @@ static void rda_uart_config_port(struct uart_port *port, int flags) rda_uart_request_port(port); } - spin_lock_irqsave(&port->lock, irq_flags); + uart_port_lock_irqsave(port, &irq_flags); /* Clear mask, so no surprise interrupts. */ rda_uart_write(port, 0, RDA_UART_IRQ_MASK); @@ -524,7 +518,7 @@ static void rda_uart_config_port(struct uart_port *port, int flags) /* Clear status register */ rda_uart_write(port, 0, RDA_UART_STATUS); - spin_unlock_irqrestore(&port->lock, irq_flags); + uart_port_unlock_irqrestore(port, irq_flags); } static void rda_uart_release_port(struct uart_port *port) @@ -575,7 +569,7 @@ static const struct uart_ops rda_uart_ops = { #ifdef CONFIG_SERIAL_RDA_CONSOLE -static void rda_console_putchar(struct uart_port *port, int ch) +static void rda_console_putchar(struct uart_port *port, unsigned char ch) { if (!port->membase) return; @@ -591,18 +585,12 @@ static void rda_uart_port_write(struct uart_port *port, const char *s, { u32 old_irq_mask; unsigned long flags; - int locked; - - local_irq_save(flags); + int locked = 1; - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else { - spin_lock(&port->lock); - locked = 1; - } + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); + else + uart_port_lock_irqsave(port, &flags); old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK); rda_uart_write(port, 0, RDA_UART_IRQ_MASK); @@ -616,9 +604,7 @@ static void rda_uart_port_write(struct uart_port *port, const char *s, rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK); if (locked) - spin_unlock(&port->lock); - - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } static void rda_uart_console_write(struct console *co, const char *s, @@ -781,14 +767,12 @@ static int rda_uart_probe(struct platform_device *pdev) return ret; } -static int rda_uart_remove(struct platform_device *pdev) +static void rda_uart_remove(struct platform_device *pdev) { struct rda_uart_port *rda_port = platform_get_drvdata(pdev); uart_remove_one_port(&rda_uart_driver, &rda_port->port); rda_uart_ports[pdev->id] = NULL; - - return 0; } static struct platform_driver rda_uart_platform_driver = { diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 5690c09cc041..6d99a02dd439 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -178,7 +178,6 @@ struct rp2_card; struct rp2_uart_port { struct uart_port port; int idx; - int ignore_rx; struct rp2_card *card; void __iomem *asic_base; void __iomem *base; @@ -195,7 +194,6 @@ struct rp2_card { void __iomem *bar0; void __iomem *bar1; spinlock_t card_lock; - struct completion fw_loaded; }; #define RP_ID(prod) PCI_VDEVICE(RP, (prod)) @@ -277,9 +275,9 @@ static unsigned int rp2_uart_tx_empty(struct uart_port *port) * But the TXEMPTY bit doesn't seem to work unless the TX IRQ is * enabled. */ - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); tx_fifo_bytes = readw(up->base + RP2_TX_FIFO_COUNT); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return tx_fifo_bytes ? 0 : TIOCSER_TEMT; } @@ -324,10 +322,10 @@ static void rp2_uart_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); rp2_rmw(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_BREAK_m, break_state ? RP2_TXRX_CTL_BREAK_m : 0); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void rp2_uart_enable_ms(struct uart_port *port) @@ -371,9 +369,8 @@ static void __rp2_uart_set_termios(struct rp2_uart_port *up, up->ucode + RP2_RX_SWFLOW); } -static void rp2_uart_set_termios(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) +static void rp2_uart_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) { struct rp2_uart_port *up = port_to_up(port); unsigned long flags; @@ -385,7 +382,7 @@ static void rp2_uart_set_termios(struct uart_port *port, if (tty_termios_baud_rate(new)) tty_termios_encode_baud_rate(new, baud, baud); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* ignore all characters if CREAD is not set */ port->ignore_status_mask = (new->c_cflag & CREAD) ? 0 : RP2_DUMMY_READ; @@ -393,7 +390,7 @@ static void rp2_uart_set_termios(struct uart_port *port, __rp2_uart_set_termios(up, new->c_cflag, new->c_iflag, baud_div); uart_update_timeout(port, new->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void rp2_rx_chars(struct rp2_uart_port *up) @@ -403,14 +400,14 @@ static void rp2_rx_chars(struct rp2_uart_port *up) for (; bytes != 0; bytes--) { u32 byte = readw(up->base + RP2_DATA_BYTE) | RP2_DUMMY_READ; - char ch = byte & 0xff; + u8 ch = byte & 0xff; if (likely(!(byte & RP2_DATA_BYTE_EXCEPTION_MASK))) { if (!uart_handle_sysrq_char(&up->port, ch)) uart_insert_char(&up->port, byte, 0, ch, TTY_NORMAL); } else { - char flag = TTY_NORMAL; + u8 flag = TTY_NORMAL; if (byte & RP2_DATA_BYTE_BREAK_m) flag = TTY_BREAK; @@ -424,46 +421,25 @@ static void rp2_rx_chars(struct rp2_uart_port *up) up->port.icount.rx++; } - spin_unlock(&up->port.lock); tty_flip_buffer_push(port); - spin_lock(&up->port.lock); } static void rp2_tx_chars(struct rp2_uart_port *up) { - u16 max_tx = FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT); - struct circ_buf *xmit = &up->port.state->xmit; + u8 ch; - if (uart_tx_stopped(&up->port)) { - rp2_uart_stop_tx(&up->port); - return; - } - - for (; max_tx != 0; max_tx--) { - if (up->port.x_char) { - writeb(up->port.x_char, up->base + RP2_DATA_BYTE); - up->port.x_char = 0; - up->port.icount.tx++; - continue; - } - if (uart_circ_empty(xmit)) { - rp2_uart_stop_tx(&up->port); - break; - } - writeb(xmit->buf[xmit->tail], up->base + RP2_DATA_BYTE); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); + uart_port_tx_limited(&up->port, ch, + FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT), + true, + writeb(ch, up->base + RP2_DATA_BYTE), + ({})); } static void rp2_ch_interrupt(struct rp2_uart_port *up) { u32 status; - spin_lock(&up->port.lock); + uart_port_lock(&up->port); /* * The IRQ status bits are clear-on-write. Other status bits in @@ -479,7 +455,7 @@ static void rp2_ch_interrupt(struct rp2_uart_port *up) if (status & RP2_CHAN_STAT_MS_CHANGED_MASK) wake_up_interruptible(&up->port.state->port.delta_msr_wait); - spin_unlock(&up->port.lock); + uart_port_unlock(&up->port); } static int rp2_asic_interrupt(struct rp2_card *card, unsigned int asic_id) @@ -539,10 +515,10 @@ static void rp2_uart_shutdown(struct uart_port *port) rp2_uart_break_ctl(port, 0); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); rp2_mask_ch_irq(up, up->idx, 0); rp2_rmw(up, RP2_CHAN_STAT, 0, 0); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *rp2_uart_type(struct uart_port *port) @@ -601,8 +577,8 @@ static void rp2_reset_asic(struct rp2_card *card, unsigned int asic_id) u32 clk_cfg; writew(1, base + RP2_GLOBAL_CMD); - readw(base + RP2_GLOBAL_CMD); msleep(100); + readw(base + RP2_GLOBAL_CMD); writel(0, base + RP2_CLK_PRESCALER); /* TDM clock configuration */ @@ -664,17 +640,10 @@ static void rp2_remove_ports(struct rp2_card *card) card->initialized_ports = 0; } -static void rp2_fw_cb(const struct firmware *fw, void *context) +static int rp2_load_firmware(struct rp2_card *card, const struct firmware *fw) { - struct rp2_card *card = context; resource_size_t phys_base; - int i, rc = -ENOENT; - - if (!fw) { - dev_err(&card->pdev->dev, "cannot find '%s' firmware image\n", - RP2_FW_NAME); - goto no_fw; - } + int i, rc = 0; phys_base = pci_resource_start(card->pdev, 1); @@ -720,26 +689,15 @@ static void rp2_fw_cb(const struct firmware *fw, void *context) card->initialized_ports++; } - release_firmware(fw); -no_fw: - /* - * rp2_fw_cb() is called from a workqueue long after rp2_probe() - * has already returned success. So if something failed here, - * we'll just leave the now-dormant device in place until somebody - * unbinds it. - */ - if (rc) - dev_warn(&card->pdev->dev, "driver initialization failed\n"); - - complete(&card->fw_loaded); + return rc; } static int rp2_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + const struct firmware *fw; struct rp2_card *card; struct rp2_uart_port *ports; - void __iomem * const *bars; int rc; card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); @@ -747,19 +705,21 @@ static int rp2_probe(struct pci_dev *pdev, return -ENOMEM; pci_set_drvdata(pdev, card); spin_lock_init(&card->card_lock); - init_completion(&card->fw_loaded); rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pcim_iomap_regions_request_all(pdev, 0x03, DRV_NAME); + rc = pcim_request_all_regions(pdev, DRV_NAME); if (rc) return rc; - bars = pcim_iomap_table(pdev); - card->bar0 = bars[0]; - card->bar1 = bars[1]; + card->bar0 = pcim_iomap(pdev, 0, 0); + if (!card->bar0) + return -ENOMEM; + card->bar1 = pcim_iomap(pdev, 1, 0); + if (!card->bar1) + return -ENOMEM; card->pdev = pdev; rp2_decode_cap(id, &card->n_ports, &card->smpte); @@ -780,21 +740,23 @@ static int rp2_probe(struct pci_dev *pdev, return -ENOMEM; card->ports = ports; - rc = devm_request_irq(&pdev->dev, pdev->irq, rp2_uart_interrupt, - IRQF_SHARED, DRV_NAME, card); - if (rc) + rc = request_firmware(&fw, RP2_FW_NAME, &pdev->dev); + if (rc < 0) { + dev_err(&pdev->dev, "cannot find '%s' firmware image\n", + RP2_FW_NAME); + return rc; + } + + rc = rp2_load_firmware(card, fw); + + release_firmware(fw); + if (rc < 0) return rc; - /* - * Only catastrophic errors (e.g. ENOMEM) are reported here. - * If the FW image is missing, we'll find out in rp2_fw_cb() - * and print an error message. - */ - rc = request_firmware_nowait(THIS_MODULE, 1, RP2_FW_NAME, &pdev->dev, - GFP_KERNEL, card, rp2_fw_cb); + rc = devm_request_irq(&pdev->dev, pdev->irq, rp2_uart_interrupt, + IRQF_SHARED, DRV_NAME, card); if (rc) return rc; - dev_dbg(&pdev->dev, "waiting for firmware blob...\n"); return 0; } @@ -803,7 +765,6 @@ static void rp2_remove(struct pci_dev *pdev) { struct rp2_card *card = pci_get_drvdata(pdev); - wait_for_completion(&card->fw_loaded); rp2_remove_ports(card); } diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c new file mode 100644 index 000000000000..b3c48dc1e07d --- /dev/null +++ b/drivers/tty/serial/rsci.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/serial_core.h> +#include <linux/serial_sci.h> +#include <linux/tty_flip.h> +#include "rsci.h" + +MODULE_IMPORT_NS("SH_SCI"); + +/* RSCI registers */ +#define RDR 0x00 +#define TDR 0x04 +#define CCR0 0x08 +#define CCR1 0x0C +#define CCR2 0x10 +#define CCR3 0x14 +#define CCR4 0x18 +#define FCR 0x24 +#define DCR 0x30 +#define CSR 0x48 +#define FRSR 0x50 +#define FTSR 0x54 +#define CFCLR 0x68 +#define FFCLR 0x70 + +/* RDR (Receive Data Register) */ +#define RDR_FFER BIT(12) /* FIFO Framing Error */ +#define RDR_FPER BIT(11) /* FIFO Parity Error */ +#define RDR_RDAT_MSK GENMASK(8, 0) + +/* TDR (Transmit Data Register) */ +#define TDR_MPBT BIT(9) /* Multiprocessor Transfer */ +#define TDR_TDAT_9BIT_LSHIFT 0 +#define TDR_TDAT_9BIT_VAL 0x1FF +#define TDR_TDAT_9BIT_MSK (TDR_TDAT_9BIT_VAL << TDR_TDAT_9BIT_LSHIFT) + +/* CCR0 (Common Control Register 0) */ +#define CCR0_SSE BIT(24) /* SSn# Pin Function Enable */ +#define CCR0_TEIE BIT(21) /* Transmit End Interrupt Enable */ +#define CCR0_TIE BIT(20) /* Transmit Interrupt Enable */ +#define CCR0_RIE BIT(16) /* Receive Interrupt Enable */ +#define CCR0_IDSEL BIT(10) /* ID Frame Select */ +#define CCR0_DCME BIT(9) /* Data Compare Match Enable */ +#define CCR0_MPIE BIT(8) /* Multiprocessor Interrupt Enable */ +#define CCR0_TE BIT(4) /* Transmit Enable */ +#define CCR0_RE BIT(0) /* Receive Enable */ + +/* CCR1 (Common Control Register 1) */ +#define CCR1_NFEN BIT(28) /* Digital Noise Filter Function */ +#define CCR1_SHARPS BIT(20) /* Half -duplex Communication Select */ +#define CCR1_SPLP BIT(16) /* Loopback Control */ +#define CCR1_RINV BIT(13) /* RxD invert */ +#define CCR1_TINV BIT(12) /* TxD invert */ +#define CCR1_PM BIT(9) /* Parity Mode */ +#define CCR1_PE BIT(8) /* Parity Enable */ +#define CCR1_SPB2IO BIT(5) /* Serial Port Break I/O */ +#define CCR1_SPB2DT BIT(4) /* Serial Port Break Data Select */ +#define CCR1_CTSPEN BIT(1) /* CTS External Pin Enable */ +#define CCR1_CTSE BIT(0) /* CTS Enable */ + +/* FCR (FIFO Control Register) */ +#define FCR_RFRST BIT(23) /* Receive FIFO Data Register Reset */ +#define FCR_TFRST BIT(15) /* Transmit FIFO Data Register Reset */ +#define FCR_DRES BIT(0) /* Incoming Data Ready Error Select */ +#define FCR_RTRG4_0 GENMASK(20, 16) +#define FCR_TTRG GENMASK(12, 8) + +/* CSR (Common Status Register) */ +#define CSR_RDRF BIT(31) /* Receive Data Full */ +#define CSR_TEND BIT(30) /* Transmit End Flag */ +#define CSR_TDRE BIT(29) /* Transmit Data Empty */ +#define CSR_FER BIT(28) /* Framing Error */ +#define CSR_PER BIT(27) /* Parity Error */ +#define CSR_MFF BIT(26) /* Mode Fault Error */ +#define CSR_ORER BIT(24) /* Overrun Error */ +#define CSR_DFER BIT(18) /* Data Compare Match Framing Error */ +#define CSR_DPER BIT(17) /* Data Compare Match Parity Error */ +#define CSR_DCMF BIT(16) /* Data Compare Match */ +#define CSR_RXDMON BIT(15) /* Serial Input Data Monitor */ +#define CSR_ERS BIT(4) /* Error Signal Status */ + +#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask) +#define SCxSR_ERROR_CLEAR(port) (to_sci_port(port)->params->error_clear) + +#define RSCI_DEFAULT_ERROR_MASK (CSR_PER | CSR_FER) + +#define RSCI_RDxF_CLEAR (CFCLR_RDRFC) +#define RSCI_ERROR_CLEAR (CFCLR_PERC | CFCLR_FERC) +#define RSCI_TDxE_CLEAR (CFCLR_TDREC) +#define RSCI_BREAK_CLEAR (CFCLR_PERC | CFCLR_FERC | CFCLR_ORERC) + +/* FRSR (FIFO Receive Status Register) */ +#define FRSR_R5_0 GENMASK(13, 8) /* Receive FIFO Data Count */ +#define FRSR_DR BIT(0) /* Receive Data Ready */ + +/* CFCLR (Common Flag CLear Register) */ +#define CFCLR_RDRFC BIT(31) /* RDRF Clear */ +#define CFCLR_TDREC BIT(29) /* TDRE Clear */ +#define CFCLR_FERC BIT(28) /* FER Clear */ +#define CFCLR_PERC BIT(27) /* PER Clear */ +#define CFCLR_MFFC BIT(26) /* MFF Clear */ +#define CFCLR_ORERC BIT(24) /* ORER Clear */ +#define CFCLR_DFERC BIT(18) /* DFER Clear */ +#define CFCLR_DPERC BIT(17) /* DPER Clear */ +#define CFCLR_DCMFC BIT(16) /* DCMF Clear */ +#define CFCLR_ERSC BIT(4) /* ERS Clear */ +#define CFCLR_CLRFLAG (CFCLR_RDRFC | CFCLR_FERC | CFCLR_PERC | \ + CFCLR_MFFC | CFCLR_ORERC | CFCLR_DFERC | \ + CFCLR_DPERC | CFCLR_DCMFC | CFCLR_ERSC) + +/* FFCLR (FIFO Flag CLear Register) */ +#define FFCLR_DRC BIT(0) /* DR Clear */ + +#define DCR_DEPOL BIT(0) + +static u32 rsci_serial_in(struct uart_port *p, int offset) +{ + return readl(p->membase + offset); +} + +static void rsci_serial_out(struct uart_port *p, int offset, int value) +{ + writel(value, p->membase + offset); +} + +static void rsci_clear_DRxC(struct uart_port *port) +{ + rsci_serial_out(port, CFCLR, CFCLR_RDRFC); + rsci_serial_out(port, FFCLR, FFCLR_DRC); +} + +static void rsci_clear_SCxSR(struct uart_port *port, unsigned int mask) +{ + rsci_serial_out(port, CFCLR, mask); +} + +static void rsci_start_rx(struct uart_port *port) +{ + unsigned int ctrl; + + ctrl = rsci_serial_in(port, CCR0); + ctrl |= CCR0_RIE; + rsci_serial_out(port, CCR0, ctrl); +} + +static void rsci_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old) +{ + struct sci_port *s = to_sci_port(port); + unsigned long flags; + + sci_port_enable(s); + uart_port_lock_irqsave(port, &flags); + + /* For now, only RX enabling is supported */ + if (termios->c_cflag & CREAD) + rsci_start_rx(port); + + uart_port_unlock_irqrestore(port, flags); + sci_port_disable(s); +} + +static int rsci_txfill(struct uart_port *port) +{ + return rsci_serial_in(port, FTSR); +} + +static int rsci_rxfill(struct uart_port *port) +{ + u32 val = rsci_serial_in(port, FRSR); + + return FIELD_GET(FRSR_R5_0, val); +} + +static unsigned int rsci_tx_empty(struct uart_port *port) +{ + unsigned int status = rsci_serial_in(port, CSR); + unsigned int in_tx_fifo = rsci_txfill(port); + + return (status & CSR_TEND) && !in_tx_fifo ? TIOCSER_TEMT : 0; +} + +static void rsci_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* Not supported yet */ +} + +static unsigned int rsci_get_mctrl(struct uart_port *port) +{ + /* Not supported yet */ + return 0; +} + +static void rsci_clear_CFC(struct uart_port *port, unsigned int mask) +{ + rsci_serial_out(port, CFCLR, mask); +} + +static void rsci_start_tx(struct uart_port *port) +{ + struct sci_port *sp = to_sci_port(port); + u32 ctrl; + + if (sp->chan_tx) + return; + + /* + * TE (Transmit Enable) must be set after setting TIE + * (Transmit Interrupt Enable) or in the same instruction + * to start the transmit process. + */ + ctrl = rsci_serial_in(port, CCR0); + ctrl |= CCR0_TIE | CCR0_TE; + rsci_serial_out(port, CCR0, ctrl); +} + +static void rsci_stop_tx(struct uart_port *port) +{ + u32 ctrl; + + ctrl = rsci_serial_in(port, CCR0); + ctrl &= ~CCR0_TIE; + rsci_serial_out(port, CCR0, ctrl); +} + +static void rsci_stop_rx(struct uart_port *port) +{ + u32 ctrl; + + ctrl = rsci_serial_in(port, CCR0); + ctrl &= ~CCR0_RIE; + rsci_serial_out(port, CCR0, ctrl); +} + +static int rsci_txroom(struct uart_port *port) +{ + return port->fifosize - rsci_txfill(port); +} + +static void rsci_transmit_chars(struct uart_port *port) +{ + unsigned int stopped = uart_tx_stopped(port); + struct tty_port *tport = &port->state->port; + u32 status, ctrl; + int count; + + status = rsci_serial_in(port, CSR); + if (!(status & CSR_TDRE)) { + ctrl = rsci_serial_in(port, CCR0); + if (kfifo_is_empty(&tport->xmit_fifo)) + ctrl &= ~CCR0_TIE; + else + ctrl |= CCR0_TIE; + rsci_serial_out(port, CCR0, ctrl); + return; + } + + count = rsci_txroom(port); + + do { + unsigned char c; + + if (port->x_char) { + c = port->x_char; + port->x_char = 0; + } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) { + break; + } + + rsci_clear_CFC(port, CFCLR_TDREC); + rsci_serial_out(port, TDR, c); + + port->icount.tx++; + } while (--count > 0); + + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (kfifo_is_empty(&tport->xmit_fifo)) { + ctrl = rsci_serial_in(port, CCR0); + ctrl &= ~CCR0_TIE; + ctrl |= CCR0_TEIE; + rsci_serial_out(port, CCR0, ctrl); + } +} + +static void rsci_receive_chars(struct uart_port *port) +{ + struct tty_port *tport = &port->state->port; + u32 rdat, status, frsr_status = 0; + int i, count, copied = 0; + unsigned char flag; + + status = rsci_serial_in(port, CSR); + frsr_status = rsci_serial_in(port, FRSR); + + if (!(status & CSR_RDRF) && !(frsr_status & FRSR_DR)) + return; + + while (1) { + /* Don't copy more bytes than there is room for in the buffer */ + count = tty_buffer_request_room(tport, rsci_rxfill(port)); + + /* If for any reason we can't copy more data, we're done! */ + if (count == 0) + break; + + for (i = 0; i < count; i++) { + char c; + + rdat = rsci_serial_in(port, RDR); + /* 9-bits data is not supported yet */ + c = rdat & RDR_RDAT_MSK; + + if (uart_handle_sysrq_char(port, c)) { + count--; + i--; + continue; + } + + /* Store data and status. + * Non FIFO mode is not supported + */ + if (rdat & RDR_FFER) { + flag = TTY_FRAME; + port->icount.frame++; + } else if (rdat & RDR_FPER) { + flag = TTY_PARITY; + port->icount.parity++; + } else { + flag = TTY_NORMAL; + } + + tty_insert_flip_char(tport, c, flag); + } + + rsci_serial_in(port, CSR); /* dummy read */ + rsci_clear_DRxC(port); + + copied += count; + port->icount.rx += count; + } + + if (copied) { + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tport); + } else { + /* TTY buffers full; read from RX reg to prevent lockup */ + rsci_serial_in(port, RDR); + rsci_serial_in(port, CSR); /* dummy read */ + rsci_clear_DRxC(port); + } +} + +static void rsci_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 status; + int ret; + + ret = readl_relaxed_poll_timeout_atomic(port->membase + CSR, status, + (status & CSR_TDRE), 100, + USEC_PER_SEC); + if (ret != 0) { + dev_err(port->dev, + "Error while sending data in UART TX : %d\n", ret); + goto done; + } + rsci_serial_out(port, TDR, c); +done: + rsci_clear_SCxSR(port, CFCLR_TDREC); +} + +static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl) +{ + struct sci_port *s = to_sci_port(port); + u32 ctrl_temp = + s->params->param_bits->rxtx_enable | CCR0_TIE | + s->hscif_tot; + rsci_serial_out(port, CCR0, ctrl_temp); +} + +static const char *rsci_type(struct uart_port *port) +{ + return "rsci"; +} + +static size_t rsci_suspend_regs_size(void) +{ + return 0; +} + +static void rsci_shutdown_complete(struct uart_port *port) +{ + /* + * Stop RX and TX, disable related interrupts, keep clock source + */ + rsci_serial_out(port, CCR0, 0); +} + +static const struct sci_common_regs rsci_common_regs = { + .status = CSR, + .control = CCR0, +}; + +static const struct sci_port_params_bits rsci_port_param_bits = { + .rxtx_enable = CCR0_RE | CCR0_TE, + .te_clear = CCR0_TE | CCR0_TEIE, + .poll_sent_bits = CSR_TDRE | CSR_TEND, +}; + +static const struct sci_port_params rsci_port_params = { + .fifosize = 16, + .overrun_reg = CSR, + .overrun_mask = CSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = RSCI_DEFAULT_ERROR_MASK, + .error_clear = RSCI_ERROR_CLEAR, + .param_bits = &rsci_port_param_bits, + .common_regs = &rsci_common_regs, +}; + +static const struct uart_ops rsci_uart_ops = { + .tx_empty = rsci_tx_empty, + .set_mctrl = rsci_set_mctrl, + .get_mctrl = rsci_get_mctrl, + .start_tx = rsci_start_tx, + .stop_tx = rsci_stop_tx, + .stop_rx = rsci_stop_rx, + .startup = sci_startup, + .shutdown = sci_shutdown, + .set_termios = rsci_set_termios, + .pm = sci_pm, + .type = rsci_type, + .release_port = sci_release_port, + .request_port = sci_request_port, + .config_port = sci_config_port, + .verify_port = sci_verify_port, +}; + +static const struct sci_port_ops rsci_port_ops = { + .read_reg = rsci_serial_in, + .write_reg = rsci_serial_out, + .clear_SCxSR = rsci_clear_SCxSR, + .transmit_chars = rsci_transmit_chars, + .receive_chars = rsci_receive_chars, + .poll_put_char = rsci_poll_put_char, + .prepare_console_write = rsci_prepare_console_write, + .suspend_regs_size = rsci_suspend_regs_size, + .shutdown_complete = rsci_shutdown_complete, +}; + +struct sci_of_data of_sci_rsci_data = { + .type = SCI_PORT_RSCI, + .ops = &rsci_port_ops, + .uart_ops = &rsci_uart_ops, + .params = &rsci_port_params, +}; + +#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON + +static int __init rsci_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return scix_early_console_setup(device, &of_sci_rsci_data); +} + +OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_early_console_setup); + +#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */ + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RSCI serial driver"); diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h new file mode 100644 index 000000000000..2af3f28b465a --- /dev/null +++ b/drivers/tty/serial/rsci.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __RSCI_H__ +#define __RSCI_H__ + +#include "sh-sci-common.h" + +extern struct sci_of_data of_sci_rsci_data; + +#endif /* __RSCI_H__ */ diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 75c2a22895f9..72b1bb76415c 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -111,13 +111,13 @@ static void sa1100_mctrl_check(struct sa1100_port *sport) */ static void sa1100_timeout(struct timer_list *t) { - struct sa1100_port *sport = from_timer(sport, t, timer); + struct sa1100_port *sport = timer_container_of(sport, t, timer); unsigned long flags; if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); sa1100_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); } @@ -180,7 +180,8 @@ static void sa1100_enable_ms(struct uart_port *port) static void sa1100_rx_chars(struct sa1100_port *sport) { - unsigned int status, ch, flg; + unsigned int status; + u8 ch, flg; status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | UTSR0_TO_SM(UART_GET_UTSR0(sport)); @@ -223,21 +224,12 @@ sa1100_rx_chars(struct sa1100_port *sport) UTSR0_TO_SM(UART_GET_UTSR0(sport)); } - spin_unlock(&sport->port.lock); tty_flip_buffer_push(&sport->port.state->port); - spin_lock(&sport->port.lock); } static void sa1100_tx_chars(struct sa1100_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; - - if (sport->port.x_char) { - UART_PUT_CHAR(sport, sport->port.x_char); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } + u8 ch; /* * Check the modem control lines before @@ -245,28 +237,9 @@ static void sa1100_tx_chars(struct sa1100_port *sport) */ sa1100_mctrl_check(sport); - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - sa1100_stop_tx(&sport->port); - return; - } - - /* - * Tried using FIFO (not checking TNF) for fifo fill: - * still had the '4 bytes repeated' problem. - */ - while (UART_GET_UTSR1(sport) & UTSR1_TNF) { - UART_PUT_CHAR(sport, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - sa1100_stop_tx(&sport->port); + uart_port_tx(&sport->port, ch, + UART_GET_UTSR1(sport) & UTSR1_TNF, + UART_PUT_CHAR(sport, ch)); } static irqreturn_t sa1100_int(int irq, void *dev_id) @@ -274,7 +247,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id) struct sa1100_port *sport = dev_id; unsigned int status, pass_counter = 0; - spin_lock(&sport->port.lock); + uart_port_lock(&sport->port); status = UART_GET_UTSR0(sport); status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; do { @@ -303,7 +276,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id) status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); - spin_unlock(&sport->port.lock); + uart_port_unlock(&sport->port); return IRQ_HANDLED; } @@ -348,14 +321,14 @@ static void sa1100_break_ctl(struct uart_port *port, int break_state) unsigned long flags; unsigned int utcr3; - spin_lock_irqsave(&sport->port.lock, flags); + uart_port_lock_irqsave(&sport->port, &flags); utcr3 = UART_GET_UTCR3(sport); if (break_state == -1) utcr3 |= UTCR3_BRK; else utcr3 &= ~UTCR3_BRK; UART_PUT_UTCR3(sport, utcr3); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } static int sa1100_startup(struct uart_port *port) @@ -381,9 +354,9 @@ static int sa1100_startup(struct uart_port *port) /* * Enable modem status interrupts */ - spin_lock_irq(&sport->port.lock); + uart_port_lock_irq(&sport->port); sa1100_enable_ms(&sport->port); - spin_unlock_irq(&sport->port.lock); + uart_port_unlock_irq(&sport->port); return 0; } @@ -396,7 +369,7 @@ static void sa1100_shutdown(struct uart_port *port) /* * Stop our timer. */ - del_timer_sync(&sport->timer); + timer_delete_sync(&sport->timer); /* * Free the interrupt @@ -411,7 +384,7 @@ static void sa1100_shutdown(struct uart_port *port) static void sa1100_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct sa1100_port *sport = container_of(port, struct sa1100_port, port); @@ -448,7 +421,9 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios, 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); + timer_delete_sync(&sport->timer); + + uart_port_lock_irqsave(&sport->port, &flags); sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS); sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); @@ -478,8 +453,6 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios, UTSR1_TO_SM(UTSR1_ROR); } - del_timer_sync(&sport->timer); - /* * Update the per-port timeout. */ @@ -512,7 +485,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios, if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) sa1100_enable_ms(&sport->port); - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_port_unlock_irqrestore(&sport->port, flags); } static const char *sa1100_type(struct uart_port *port) @@ -697,7 +670,7 @@ void __init sa1100_register_uart(int idx, int port) #ifdef CONFIG_SERIAL_SA1100_CONSOLE -static void sa1100_console_putchar(struct uart_port *port, int ch) +static void sa1100_console_putchar(struct uart_port *port, unsigned char ch) { struct sa1100_port *sport = container_of(port, struct sa1100_port, port); @@ -879,34 +852,30 @@ static int sa1100_serial_add_one_port(struct sa1100_port *sport, struct platform static int sa1100_serial_probe(struct platform_device *dev) { - struct resource *res = dev->resource; + struct resource *res; int i; - for (i = 0; i < dev->num_resources; i++, res++) - if (res->flags & IORESOURCE_MEM) - break; - - if (i < dev->num_resources) { - for (i = 0; i < NR_PORTS; i++) { - if (sa1100_ports[i].port.mapbase != res->start) - continue; + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; - sa1100_serial_add_one_port(&sa1100_ports[i], dev); + for (i = 0; i < NR_PORTS; i++) + if (sa1100_ports[i].port.mapbase == res->start) break; - } - } + if (i == NR_PORTS) + return -ENODEV; + + sa1100_serial_add_one_port(&sa1100_ports[i], dev); return 0; } -static int sa1100_serial_remove(struct platform_device *pdev) +static void sa1100_serial_remove(struct platform_device *pdev) { struct sa1100_port *sport = platform_get_drvdata(pdev); if (sport) uart_remove_one_port(&sa1100_reg, &sport->port); - - return 0; } static struct platform_driver sa11x0_serial_driver = { diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index d913d9b2762a..c1fabad6ba1f 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -6,7 +6,7 @@ * http://armlinux.simtec.co.uk/ */ -/* Hote on 2410 error handling +/* Note on 2410 error handling * * The s3c2410 manual has a love/hate affair with the contents of the * UERSTAT register in the UART blocks, and keeps marking some of the @@ -21,25 +21,28 @@ * BJD, 04-Nov-2004 */ -#include <linux/dmaengine.h> +#include <linux/console.h> +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/ioport.h> +#include <linux/dmaengine.h> +#include <linux/init.h> #include <linux/io.h> +#include <linux/ioport.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> -#include <linux/init.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/slab.h> #include <linux/sysrq.h> -#include <linux/console.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/serial_s3c.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/cpufreq.h> -#include <linux/of.h> +#include <linux/types.h> + #include <asm/irq.h> /* UART name and device definitions */ @@ -48,6 +51,12 @@ #define S3C24XX_SERIAL_MAJOR 204 #define S3C24XX_SERIAL_MINOR 64 +#ifdef CONFIG_ARM64 +#define UART_NR 18 +#else +#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS +#endif + #define S3C24XX_TX_PIO 1 #define S3C24XX_TX_DMA 2 #define S3C24XX_RX_PIO 1 @@ -56,30 +65,37 @@ /* flag to ignore all characters coming in */ #define RXSTAT_DUMMY_READ (0x10000000) +enum s3c24xx_port_type { + TYPE_S3C6400, + TYPE_APPLE_S5L, +}; + struct s3c24xx_uart_info { - char *name; - unsigned int type; + const char *name; + enum s3c24xx_port_type type; + unsigned int port_type; unsigned int fifosize; - unsigned long rx_fifomask; - unsigned long rx_fifoshift; - unsigned long rx_fifofull; - unsigned long tx_fifomask; - unsigned long tx_fifoshift; - unsigned long tx_fifofull; - unsigned int def_clk_sel; - unsigned long num_clks; - unsigned long clksel_mask; - unsigned long clksel_shift; + u32 rx_fifomask; + u32 rx_fifoshift; + u32 rx_fifofull; + u32 tx_fifomask; + u32 tx_fifoshift; + u32 tx_fifofull; + u32 clksel_mask; + u32 clksel_shift; + u32 ucon_mask; + u8 def_clk_sel; + u8 num_clks; + u8 iotype; /* uart port features */ - - unsigned int has_divslot:1; + bool has_divslot; }; struct s3c24xx_serial_drv_data { - struct s3c24xx_uart_info *info; - struct s3c2410_uartcfg *def_cfg; - unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS]; + const struct s3c24xx_uart_info info; + const struct s3c2410_uartcfg def_cfg; + const unsigned int fifosize[UART_NR]; }; struct s3c24xx_uart_dma { @@ -113,8 +129,6 @@ struct s3c24xx_uart_dma { }; struct s3c24xx_uart_port { - unsigned char rx_claimed; - unsigned char tx_claimed; unsigned char rx_enabled; unsigned char tx_enabled; unsigned int pm_level; @@ -128,22 +142,20 @@ struct s3c24xx_uart_port { unsigned int tx_mode; unsigned int rx_mode; - struct s3c24xx_uart_info *info; + const struct s3c24xx_uart_info *info; struct clk *clk; struct clk *baudclk; struct uart_port port; - struct s3c24xx_serial_drv_data *drv_data; + const struct s3c24xx_serial_drv_data *drv_data; /* reference to platform data */ - struct s3c2410_uartcfg *cfg; + const struct s3c2410_uartcfg *cfg; struct s3c24xx_uart_dma *dma; - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - struct notifier_block freq_transition; -#endif }; +static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport); + /* conversion functions */ #define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev) @@ -154,7 +166,7 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -static u32 rd_reg(struct uart_port *port, u32 reg) +static u32 rd_reg(const struct uart_port *port, u32 reg) { switch (port->iotype) { case UPIO_MEM: @@ -169,7 +181,7 @@ static u32 rd_reg(struct uart_port *port, u32 reg) #define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -static void wr_reg(struct uart_port *port, u32 reg, u32 val) +static void wr_reg(const struct uart_port *port, u32 reg, u32 val) { switch (port->iotype) { case UPIO_MEM: @@ -178,6 +190,8 @@ static void wr_reg(struct uart_port *port, u32 reg, u32 val) case UPIO_MEM32: writel_relaxed(val, portaddr(port, reg)); break; + default: + break; } } @@ -185,8 +199,8 @@ static void wr_reg(struct uart_port *port, u32 reg, u32 val) /* Byte-order aware bit setting/clearing functions. */ -static inline void s3c24xx_set_bit(struct uart_port *port, int idx, - unsigned int reg) +static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, + u32 reg) { unsigned long flags; u32 val; @@ -198,8 +212,8 @@ static inline void s3c24xx_set_bit(struct uart_port *port, int idx, local_irq_restore(flags); } -static inline void s3c24xx_clear_bit(struct uart_port *port, int idx, - unsigned int reg) +static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx, + u32 reg) { unsigned long flags; u32 val; @@ -218,34 +232,24 @@ static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port) /* translate a port to the device name */ -static inline const char *s3c24xx_serial_portname(struct uart_port *port) +static inline const char *s3c24xx_serial_portname(const struct uart_port *port) { return to_platform_device(port->dev)->name; } -static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) +static bool s3c24xx_serial_txempty_nofifo(const struct uart_port *port) { return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } -/* - * s3c64xx and later SoC's include the interrupt mask and status registers in - * the controller itself, unlike the s3c24xx SoC's which have these registers - * in the interrupt controller. Check if the port type is s3c64xx or higher. - */ -static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port) -{ - return to_ourport(port)->info->type == PORT_S3C6400; -} - static void s3c24xx_serial_rx_enable(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ucon, ufcon; int count = 10000; + u32 ucon, ufcon; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); while (--count && !s3c24xx_serial_txempty_nofifo(port)) udelay(100); @@ -259,51 +263,57 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port) wr_regl(port, S3C2410_UCON, ucon); ourport->rx_enabled = 1; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void s3c24xx_serial_rx_disable(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ucon; + u32 ucon; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ucon = rd_regl(port, S3C2410_UCON); ucon &= ~S3C2410_UCON_RXIRQMODE; wr_regl(port, S3C2410_UCON, ucon); ourport->rx_enabled = 0; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void s3c24xx_serial_stop_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_dma *dma = ourport->dma; - struct circ_buf *xmit = &port->state->xmit; struct dma_tx_state state; int count; if (!ourport->tx_enabled) return; - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + s3c24xx_clear_bit(port, APPLE_S5L_UCON_TXTHRESH_ENA, S3C2410_UCON); + break; + default: disable_irq_nosync(ourport->tx_irq); + break; + } if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) { dmaengine_pause(dma->tx_chan); dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state); dmaengine_terminate_all(dma->tx_chan); - dma_sync_single_for_cpu(ourport->port.dev, - dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE); + dma_sync_single_for_cpu(dma->tx_chan->device->dev, + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); async_tx_ack(dma->tx_desc); count = dma->tx_bytes_requested - state.residue; - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - port->icount.tx += count; + uart_xmit_advance(port, count); } ourport->tx_enabled = 0; @@ -321,49 +331,54 @@ static void s3c24xx_serial_tx_dma_complete(void *args) { struct s3c24xx_uart_port *ourport = args; struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct s3c24xx_uart_dma *dma = ourport->dma; struct dma_tx_state state; unsigned long flags; int count; - dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state); count = dma->tx_bytes_requested - state.residue; async_tx_ack(dma->tx_desc); - dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr, - dma->tx_size, DMA_TO_DEVICE); + dma_sync_single_for_cpu(dma->tx_chan->device->dev, + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - port->icount.tx += count; + uart_xmit_advance(port, count); ourport->tx_in_progress = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); s3c24xx_serial_start_next_tx(ourport); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void enable_tx_dma(struct s3c24xx_uart_port *ourport) { - struct uart_port *port = &ourport->port; + const struct uart_port *port = &ourport->port; u32 ucon; /* Mask Tx interrupt */ - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + WARN_ON(1); // No DMA + break; + default: disable_irq_nosync(ourport->tx_irq); + break; + } /* Enable tx dma mode */ ucon = rd_regl(port, S3C2410_UCON); ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK); - ucon |= (dma_get_cache_alignment() >= 16) ? - S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1; + ucon |= S3C64XX_UCON_TXBURST_1; ucon |= S3C64XX_UCON_TXMODE_DMA; wr_regl(port, S3C2410_UCON, ucon); @@ -372,7 +387,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) static void enable_tx_pio(struct s3c24xx_uart_port *ourport) { - struct uart_port *port = &ourport->port; + const struct uart_port *port = &ourport->port; u32 ucon, ufcon; /* Set ufcon txtrig */ @@ -387,13 +402,28 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport) wr_regl(port, S3C2410_UCON, ucon); /* Unmask Tx interrupt */ - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK; + wr_regl(port, S3C2410_UCON, ucon); + break; + default: enable_irq(ourport->tx_irq); + break; + } ourport->tx_mode = S3C24XX_TX_PIO; + + /* + * The Apple version only has edge triggered TX IRQs, so we need + * to kick off the process by sending some characters here. + */ + if (ourport->info->type == TYPE_APPLE_S5L) + s3c24xx_serial_tx_chars(ourport); } static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport) @@ -403,21 +433,19 @@ static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport) } static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport, - unsigned int count) + unsigned int count, unsigned int tail) { - struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; struct s3c24xx_uart_dma *dma = ourport->dma; - if (ourport->tx_mode != S3C24XX_TX_DMA) enable_tx_dma(ourport); dma->tx_size = count & ~(dma_get_cache_alignment() - 1); - dma->tx_transfer_addr = dma->tx_addr + xmit->tail; + dma->tx_transfer_addr = dma->tx_addr + tail; - dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr, - dma->tx_size, DMA_TO_DEVICE); + dma_sync_single_for_device(dma->tx_chan->device->dev, + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan, dma->tx_transfer_addr, dma->tx_size, @@ -440,11 +468,11 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport, static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned long count; + struct tty_port *tport = &port->state->port; + unsigned int count, tail; /* Get data size up to the end of buffer */ - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); if (!count) { s3c24xx_serial_stop_tx(port); @@ -453,16 +481,16 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) if (!ourport->dma || !ourport->dma->tx_chan || count < ourport->min_dma_size || - xmit->tail & (dma_get_cache_alignment() - 1)) + tail & (dma_get_cache_alignment() - 1)) s3c24xx_serial_start_tx_pio(ourport); else - s3c24xx_serial_start_tx_dma(ourport, count); + s3c24xx_serial_start_tx_dma(ourport, count, tail); } static void s3c24xx_serial_start_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; if (!ourport->tx_enabled) { if (port->flags & UPF_CONS_FLOW) @@ -474,7 +502,8 @@ static void s3c24xx_serial_start_tx(struct uart_port *port) } if (ourport->dma && ourport->dma->tx_chan) { - if (!uart_circ_empty(xmit) && !ourport->tx_in_progress) + if (!kfifo_is_empty(&tport->xmit_fifo) && + !ourport->tx_in_progress) s3c24xx_serial_start_next_tx(ourport); } } @@ -488,7 +517,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport, if (!count) return; - dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr, + dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); ourport->port.icount.rx += count; @@ -515,11 +544,20 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (ourport->rx_enabled) { dev_dbg(port->dev, "stopping rx\n"); - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); - else + break; + case TYPE_APPLE_S5L: + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON); + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_LEGACY_ENA, S3C2410_UCON); + break; + default: disable_irq_nosync(ourport->rx_irq); + break; + } ourport->rx_enabled = 0; } if (dma && dma->rx_chan) { @@ -535,16 +573,16 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) } } -static inline struct s3c24xx_uart_info +static inline const struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port) { return to_ourport(port)->info; } -static inline struct s3c2410_uartcfg - *s3c24xx_port_to_cfg(struct uart_port *port) +static inline const struct s3c2410_uartcfg + *s3c24xx_port_to_cfg(const struct uart_port *port) { - struct s3c24xx_uart_port *ourport; + const struct s3c24xx_uart_port *ourport; if (port->dev == NULL) return NULL; @@ -553,10 +591,10 @@ static inline struct s3c2410_uartcfg return ourport->cfg; } -static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, - unsigned long ufstat) +static unsigned int +s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, u32 ufstat) { - struct s3c24xx_uart_info *info = ourport->info; + const struct s3c24xx_uart_info *info = ourport->info; if (ufstat & info->rx_fifofull) return ourport->port.fifosize; @@ -582,7 +620,7 @@ static void s3c24xx_serial_rx_dma_complete(void *args) received = dma->rx_bytes_requested - state.residue; async_tx_ack(dma->rx_desc); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (received) s3c24xx_uart_copy_rx_to_tty(ourport, t, received); @@ -594,15 +632,15 @@ static void s3c24xx_serial_rx_dma_complete(void *args) s3c64xx_start_rx_dma(ourport); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) { struct s3c24xx_uart_dma *dma = ourport->dma; - dma_sync_single_for_device(ourport->port.dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); + dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, @@ -626,7 +664,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) static void enable_rx_dma(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - unsigned int ucon; + u32 ucon; /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); @@ -636,7 +674,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport) S3C64XX_UCON_DMASUS_EN | S3C64XX_UCON_TIMEOUT_EN | S3C64XX_UCON_RXMODE_MASK); - ucon |= S3C64XX_UCON_RXBURST_16 | + ucon |= S3C64XX_UCON_RXBURST_1 | 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | S3C64XX_UCON_EMPTYINT_EN | S3C64XX_UCON_TIMEOUT_EN | @@ -649,18 +687,22 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport) static void enable_rx_pio(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - unsigned int ucon; + u32 ucon; /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); - ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | - S3C64XX_UCON_EMPTYINT_EN | - S3C64XX_UCON_DMASUS_EN | - S3C64XX_UCON_TIMEOUT_EN | - S3C64XX_UCON_RXMODE_MASK); - ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | - S3C64XX_UCON_TIMEOUT_EN | - S3C64XX_UCON_RXMODE_CPU; + ucon &= ~S3C64XX_UCON_RXMODE_MASK; + ucon |= S3C64XX_UCON_RXMODE_CPU; + + /* Apple types use these bits for IRQ masks */ + if (ourport->info->type != TYPE_APPLE_S5L) { + ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | + S3C64XX_UCON_EMPTYINT_EN | + S3C64XX_UCON_DMASUS_EN | + S3C64XX_UCON_TIMEOUT_EN); + ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | + S3C64XX_UCON_TIMEOUT_EN; + } wr_regl(port, S3C2410_UCON, ucon); ourport->rx_mode = S3C24XX_RX_PIO; @@ -668,21 +710,20 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport) static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport); -static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) +static irqreturn_t s3c24xx_serial_rx_chars_dma(struct s3c24xx_uart_port *ourport) { - unsigned int utrstat, received; - struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; struct s3c24xx_uart_dma *dma = ourport->dma; struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port); struct tty_port *t = &port->state->port; - unsigned long flags; struct dma_tx_state state; + unsigned int received; + u32 utrstat; utrstat = rd_regl(port, S3C2410_UTRSTAT); rd_regl(port, S3C2410_UFSTAT); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock(port); if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) { s3c64xx_start_rx_dma(ourport); @@ -711,7 +752,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT); finish: - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -719,9 +760,10 @@ finish: static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - unsigned int ufcon, ch, flag, ufstat, uerstat; + unsigned int max_count = port->fifosize; unsigned int fifocnt = 0; - int max_count = port->fifosize; + u32 ufcon, ufstat, uerstat; + u8 ch, flag; while (max_count-- > 0) { /* @@ -740,7 +782,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) ch = rd_reg(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { - int txe = s3c24xx_serial_txempty_nofifo(port); + bool txe = s3c24xx_serial_txempty_nofifo(port); if (ourport->rx_enabled) { if (!txe) { @@ -803,48 +845,40 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) tty_flip_buffer_push(&port->state->port); } -static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id) +static irqreturn_t s3c24xx_serial_rx_chars_pio(struct s3c24xx_uart_port *ourport) { - struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock(port); s3c24xx_serial_rx_drain_fifo(ourport); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock(port); return IRQ_HANDLED; } - -static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) +static irqreturn_t s3c24xx_serial_rx_irq(struct s3c24xx_uart_port *ourport) { - struct s3c24xx_uart_port *ourport = dev_id; - if (ourport->dma && ourport->dma->rx_chan) - return s3c24xx_serial_rx_chars_dma(dev_id); - return s3c24xx_serial_rx_chars_pio(dev_id); + return s3c24xx_serial_rx_chars_dma(ourport); + return s3c24xx_serial_rx_chars_pio(ourport); } -static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) +static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) { - struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned long flags; - int count, dma_count = 0; + struct tty_port *tport = &port->state->port; + unsigned int count, dma_count = 0, tail; - spin_lock_irqsave(&port->lock, flags); - - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); if (ourport->dma && ourport->dma->tx_chan && count >= ourport->min_dma_size) { int align = dma_get_cache_alignment() - - (xmit->tail & (dma_get_cache_alignment() - 1)); - if (count-align >= ourport->min_dma_size) { - dma_count = count-align; + (tail & (dma_get_cache_alignment() - 1)); + if (count - align >= ourport->min_dma_size) { + dma_count = count - align; count = align; + tail += align; } } @@ -852,16 +886,16 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) wr_reg(port, S3C2410_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; - goto out; + return; } /* if there isn't anything more to transmit, or the uart is now * stopped, disable the uart and exit */ - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { s3c24xx_serial_stop_tx(port); - goto out; + return; } /* try and drain the buffer... */ @@ -871,32 +905,37 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) dma_count = 0; } - while (!uart_circ_empty(xmit) && count > 0) { - if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) + while (!(rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)) { + unsigned char ch; + + if (!uart_fifo_get(port, &ch)) break; - wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + wr_reg(port, S3C2410_UTXH, ch); count--; } if (!count && dma_count) { - s3c24xx_serial_start_tx_dma(ourport, dma_count); - goto out; + s3c24xx_serial_start_tx_dma(ourport, dma_count, tail); + return; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { - spin_unlock(&port->lock); + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - spin_lock(&port->lock); - } - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) s3c24xx_serial_stop_tx(port); +} + +static irqreturn_t s3c24xx_serial_tx_irq(struct s3c24xx_uart_port *ourport) +{ + struct uart_port *port = &ourport->port; + + uart_port_lock(port); -out: - spin_unlock_irqrestore(&port->lock, flags); + s3c24xx_serial_tx_chars(ourport); + + uart_port_unlock(port); return IRQ_HANDLED; } @@ -904,42 +943,64 @@ out: static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) { struct s3c24xx_uart_port *ourport = id; - struct uart_port *port = &ourport->port; - unsigned int pend = rd_regl(port, S3C64XX_UINTP); + const struct uart_port *port = &ourport->port; + u32 pend = rd_regl(port, S3C64XX_UINTP); irqreturn_t ret = IRQ_HANDLED; if (pend & S3C64XX_UINTM_RXD_MSK) { - ret = s3c24xx_serial_rx_chars(irq, id); + ret = s3c24xx_serial_rx_irq(ourport); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); } if (pend & S3C64XX_UINTM_TXD_MSK) { - ret = s3c24xx_serial_tx_chars(irq, id); + ret = s3c24xx_serial_tx_irq(ourport); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); } return ret; } +/* interrupt handler for Apple SoC's.*/ +static irqreturn_t apple_serial_handle_irq(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; + u32 pend = rd_regl(port, S3C2410_UTRSTAT); + irqreturn_t ret = IRQ_NONE; + + if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO | + APPLE_S5L_UTRSTAT_RXTO_LEGACY)) { + wr_regl(port, S3C2410_UTRSTAT, + APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO | + APPLE_S5L_UTRSTAT_RXTO_LEGACY); + ret = s3c24xx_serial_rx_irq(ourport); + } + if (pend & APPLE_S5L_UTRSTAT_TXTHRESH) { + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_TXTHRESH); + ret = s3c24xx_serial_tx_irq(ourport); + } + + return ret; +} + static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); - unsigned long ufcon = rd_regl(port, S3C2410_UFCON); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + u32 ufstat = rd_regl(port, S3C2410_UFSTAT); + u32 ufcon = rd_regl(port, S3C2410_UFCON); if (ufcon & S3C2410_UFCON_FIFOMODE) { - if ((ufstat & info->tx_fifomask) != 0 || + if ((ufstat & info->tx_fifomask) || (ufstat & info->tx_fifofull)) return 0; - - return 1; + return TIOCSER_TEMT; } - return s3c24xx_serial_txempty_nofifo(port); + return s3c24xx_serial_txempty_nofifo(port) ? TIOCSER_TEMT : 0; } /* no modem control lines */ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) { - unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); + u32 umstat = rd_reg(port, S3C2410_UMSTAT); if (umstat & S3C2410_UMSTAT_CTS) return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; @@ -949,7 +1010,8 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { - unsigned int umcon = rd_regl(port, S3C2410_UMCON); + u32 umcon = rd_regl(port, S3C2410_UMCON); + u32 ucon = rd_regl(port, S3C2410_UCON); if (mctrl & TIOCM_RTS) umcon |= S3C2410_UMCOM_RTS_LOW; @@ -957,14 +1019,21 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) umcon &= ~S3C2410_UMCOM_RTS_LOW; wr_regl(port, S3C2410_UMCON, umcon); + + if (mctrl & TIOCM_LOOP) + ucon |= S3C2410_UCON_LOOPBACK; + else + ucon &= ~S3C2410_UCON_LOOPBACK; + + wr_regl(port, S3C2410_UCON, ucon); } static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; - unsigned int ucon; + u32 ucon; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ucon = rd_regl(port, S3C2410_UCON); @@ -975,7 +1044,7 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) wr_regl(port, S3C2410_UCON, ucon); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) @@ -1040,18 +1109,20 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) goto err_release_tx; } - dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf, - dma->rx_size, DMA_FROM_DEVICE); - if (dma_mapping_error(p->port.dev, dma->rx_addr)) { + dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf, + dma->rx_size, DMA_FROM_DEVICE); + if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) { reason = "DMA mapping error for RX buffer"; ret = -EIO; goto err_free_rx; } /* TX buffer */ - dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf, - UART_XMIT_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(p->port.dev, dma->tx_addr)) { + dma->tx_addr = dma_map_single(dma->tx_chan->device->dev, + p->port.state->port.xmit_buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) { reason = "DMA mapping error for TX buffer"; ret = -EIO; goto err_unmap_rx; @@ -1060,8 +1131,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) return 0; err_unmap_rx: - dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size, - DMA_FROM_DEVICE); + dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); err_free_rx: kfree(dma->rx_buf); err_release_tx: @@ -1080,8 +1151,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p) if (dma->rx_chan) { dmaengine_terminate_all(dma->rx_chan); - dma_unmap_single(p->port.dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); + dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); kfree(dma->rx_buf); dma_release_channel(dma->rx_chan); dma->rx_chan = NULL; @@ -1089,39 +1160,25 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p) if (dma->tx_chan) { dmaengine_terminate_all(dma->tx_chan); - dma_unmap_single(p->port.dev, dma->tx_addr, - UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); dma_release_channel(dma->tx_chan); dma->tx_chan = NULL; } } -static void s3c24xx_serial_shutdown(struct uart_port *port) +static void s3c64xx_serial_shutdown(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); - if (ourport->tx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->tx_irq, ourport); - ourport->tx_enabled = 0; - ourport->tx_claimed = 0; - ourport->tx_mode = 0; - } - - if (ourport->rx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->rx_irq, ourport); - ourport->rx_claimed = 0; - ourport->rx_enabled = 0; - } + ourport->tx_enabled = 0; + ourport->tx_mode = 0; + ourport->rx_enabled = 0; - /* Clear pending interrupts and mask all interrupts */ - if (s3c24xx_serial_has_interrupt_mask(port)) { - free_irq(port->irq, ourport); + free_irq(port->irq, ourport); - wr_regl(port, S3C64XX_UINTP, 0xf); - wr_regl(port, S3C64XX_UINTM, 0xf); - } + wr_regl(port, S3C64XX_UINTP, 0xf); + wr_regl(port, S3C64XX_UINTM, 0xf); if (ourport->dma) s3c24xx_serial_release_dma(ourport); @@ -1129,53 +1186,38 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) ourport->tx_in_progress = 0; } -static int s3c24xx_serial_startup(struct uart_port *port) +static void apple_s5l_serial_shutdown(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); - int ret; - - ourport->rx_enabled = 1; - - ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, - s3c24xx_serial_portname(port), ourport); - - if (ret != 0) { - dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq); - return ret; - } - - ourport->rx_claimed = 1; - dev_dbg(port->dev, "requesting tx irq...\n"); - - ourport->tx_enabled = 1; + u32 ucon; - ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, - s3c24xx_serial_portname(port), ourport); + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK | + APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK); + wr_regl(port, S3C2410_UCON, ucon); - if (ret) { - dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq); - goto err; - } + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); - ourport->tx_claimed = 1; + free_irq(port->irq, ourport); - /* the port reset code should have done the correct - * register setup for the port controls - */ + ourport->tx_enabled = 0; + ourport->tx_mode = 0; + ourport->rx_enabled = 0; - return ret; + if (ourport->dma) + s3c24xx_serial_release_dma(ourport); -err: - s3c24xx_serial_shutdown(port); - return ret; + ourport->tx_in_progress = 0; } static int s3c64xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long flags; - unsigned int ufcon; + u32 ufcon; int ret; wr_regl(port, S3C64XX_UINTM, 0xf); @@ -1196,11 +1238,9 @@ static int s3c64xx_serial_startup(struct uart_port *port) /* For compatibility with s3c24xx Soc's */ ourport->rx_enabled = 1; - ourport->rx_claimed = 1; ourport->tx_enabled = 0; - ourport->tx_claimed = 1; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ufcon = rd_regl(port, S3C2410_UFCON); ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; @@ -1210,7 +1250,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) enable_rx_pio(ourport); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Enable Rx Interrupt */ s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); @@ -1218,7 +1258,45 @@ static int s3c64xx_serial_startup(struct uart_port *port) return ret; } -/* power power management control */ +static int apple_s5l_serial_startup(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; + u32 ufcon; + int ret; + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + + ret = request_irq(port->irq, apple_serial_handle_irq, 0, + s3c24xx_serial_portname(port), ourport); + if (ret) { + dev_err(port->dev, "cannot get irq %d\n", port->irq); + return ret; + } + + /* For compatibility with s3c24xx Soc's */ + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + + uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; + if (!uart_console(port)) + ufcon |= S3C2410_UFCON_RESETTX; + wr_regl(port, S3C2410_UFCON, ufcon); + + enable_rx_pio(ourport); + + uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON); + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_LEGACY_ENA, S3C2410_UCON); + + return ret; +} static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) @@ -1244,7 +1322,6 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, if (!IS_ERR(ourport->baudclk)) clk_prepare_enable(ourport->baudclk); - break; default: dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level); @@ -1266,10 +1343,10 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, #define MAX_CLK_NAME_LENGTH 15 -static inline int s3c24xx_serial_getsource(struct uart_port *port) +static inline u8 s3c24xx_serial_getsource(struct uart_port *port) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned int ucon; + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + u32 ucon; if (info->num_clks == 1) return 0; @@ -1279,11 +1356,10 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port) return ucon >> info->clksel_shift; } -static void s3c24xx_serial_setsource(struct uart_port *port, - unsigned int clk_sel) +static void s3c24xx_serial_setsource(struct uart_port *port, u8 clk_sel) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned int ucon; + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + u32 ucon; if (info->num_clks == 1) return; @@ -1299,14 +1375,15 @@ static void s3c24xx_serial_setsource(struct uart_port *port, static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, unsigned int req_baud, struct clk **best_clk, - unsigned int *clk_num) + u8 *clk_num) { - struct s3c24xx_uart_info *info = ourport->info; + const struct s3c24xx_uart_info *info = ourport->info; struct clk *clk; unsigned long rate; - unsigned int cnt, baud, quot, best_quot = 0; + unsigned int baud, quot, best_quot = 0; char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; + u8 cnt; for (cnt = 0; cnt < info->num_clks; cnt++) { /* Keep selected clock if provided */ @@ -1320,8 +1397,12 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, continue; rate = clk_get_rate(clk); - if (!rate) + if (!rate) { + dev_err(ourport->port.dev, + "Failed to get clock rate for %s.\n", clkname); + clk_put(clk); continue; + } if (ourport->info->has_divslot) { unsigned long div = rate / req_baud; @@ -1342,15 +1423,21 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, } quot--; - calc_deviation = req_baud - baud; - if (calc_deviation < 0) - calc_deviation = -calc_deviation; + calc_deviation = abs(req_baud - baud); if (calc_deviation < deviation) { + /* + * If we find a better clk, release the previous one, if + * any. + */ + if (!IS_ERR(*best_clk)) + clk_put(*best_clk); *best_clk = clk; best_quot = quot; *clk_num = cnt; deviation = calc_deviation; + } else { + clk_put(clk); } } @@ -1362,7 +1449,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, * This table takes the fractional value of the baud divisor and gives * the recommended setting for the UDIVSLOT register. */ -static u16 udivslot_table[16] = { +static const u16 udivslot_table[16] = { [0] = 0x0000, [1] = 0x0080, [2] = 0x0808, @@ -1383,16 +1470,16 @@ static u16 udivslot_table[16] = { static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); + const struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); struct clk *clk = ERR_PTR(-EINVAL); unsigned long flags; - unsigned int baud, quot, clk_sel = 0; - unsigned int ulcon; - unsigned int umcon; + unsigned int baud, quot; unsigned int udivslot = 0; + u32 ulcon, umcon; + u8 clk_sel = 0; /* * We don't support modem control lines. @@ -1475,7 +1562,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, ulcon |= S3C2410_LCON_PNONE; } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); dev_dbg(port->dev, "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", @@ -1533,46 +1620,29 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= RXSTAT_DUMMY_READ; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *s3c24xx_serial_type(struct uart_port *port) { - switch (port->type) { - case PORT_S3C2410: - return "S3C2410"; - case PORT_S3C2440: - return "S3C2440"; - case PORT_S3C2412: - return "S3C2412"; - case PORT_S3C6400: + const struct s3c24xx_uart_port *ourport = to_ourport(port); + + switch (ourport->info->type) { + case TYPE_S3C6400: return "S3C6400/10"; + case TYPE_APPLE_S5L: + return "APPLE S5L"; default: return NULL; } } -#define MAP_SIZE (0x100) - -static void s3c24xx_serial_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, MAP_SIZE); -} - -static int s3c24xx_serial_request_port(struct uart_port *port) -{ - const char *name = s3c24xx_serial_portname(port); - - return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY; -} - static void s3c24xx_serial_config_port(struct uart_port *port, int flags) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - if (flags & UART_CONFIG_TYPE && - s3c24xx_serial_request_port(port) == 0) - port->type = info->type; + if (flags & UART_CONFIG_TYPE) + port->type = info->port_type; } /* @@ -1581,28 +1651,33 @@ static void s3c24xx_serial_config_port(struct uart_port *port, int flags) static int s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - if (ser->type != PORT_UNKNOWN && ser->type != info->type) + if (ser->type != PORT_UNKNOWN && ser->type != info->port_type) return -EINVAL; return 0; } - #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE static struct console s3c24xx_serial_console; -static int __init s3c24xx_serial_console_init(void) +static void __init s3c24xx_serial_register_console(void) { register_console(&s3c24xx_serial_console); - return 0; } -console_initcall(s3c24xx_serial_console_init); + +static void s3c24xx_serial_unregister_console(void) +{ + if (console_is_registered(&s3c24xx_serial_console)) + unregister_console(&s3c24xx_serial_console); +} #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console #else +static inline void s3c24xx_serial_register_console(void) { } +static inline void s3c24xx_serial_unregister_console(void) { } #define S3C24XX_SERIAL_CONSOLE NULL #endif @@ -1612,7 +1687,28 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, unsigned char c); #endif -static struct uart_ops s3c24xx_serial_ops = { +static const struct uart_ops s3c64xx_serial_ops = { + .pm = s3c24xx_serial_pm, + .tx_empty = s3c24xx_serial_tx_empty, + .get_mctrl = s3c24xx_serial_get_mctrl, + .set_mctrl = s3c24xx_serial_set_mctrl, + .stop_tx = s3c24xx_serial_stop_tx, + .start_tx = s3c24xx_serial_start_tx, + .stop_rx = s3c24xx_serial_stop_rx, + .break_ctl = s3c24xx_serial_break_ctl, + .startup = s3c64xx_serial_startup, + .shutdown = s3c64xx_serial_shutdown, + .set_termios = s3c24xx_serial_set_termios, + .type = s3c24xx_serial_type, + .config_port = s3c24xx_serial_config_port, + .verify_port = s3c24xx_serial_verify_port, +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) + .poll_get_char = s3c24xx_serial_get_poll_char, + .poll_put_char = s3c24xx_serial_put_poll_char, +#endif +}; + +static const struct uart_ops apple_s5l_serial_ops = { .pm = s3c24xx_serial_pm, .tx_empty = s3c24xx_serial_tx_empty, .get_mctrl = s3c24xx_serial_get_mctrl, @@ -1621,12 +1717,10 @@ static struct uart_ops s3c24xx_serial_ops = { .start_tx = s3c24xx_serial_start_tx, .stop_rx = s3c24xx_serial_stop_rx, .break_ctl = s3c24xx_serial_break_ctl, - .startup = s3c24xx_serial_startup, - .shutdown = s3c24xx_serial_shutdown, + .startup = apple_s5l_serial_startup, + .shutdown = apple_s5l_serial_shutdown, .set_termios = s3c24xx_serial_set_termios, .type = s3c24xx_serial_type, - .release_port = s3c24xx_serial_release_port, - .request_port = s3c24xx_serial_request_port, .config_port = s3c24xx_serial_config_port, .verify_port = s3c24xx_serial_verify_port, #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) @@ -1638,68 +1732,26 @@ static struct uart_ops s3c24xx_serial_ops = { static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .driver_name = "s3c2410_serial", - .nr = CONFIG_SERIAL_SAMSUNG_UARTS, + .nr = UART_NR, .cons = S3C24XX_SERIAL_CONSOLE, .dev_name = S3C24XX_SERIAL_NAME, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, }; -#define __PORT_LOCK_UNLOCKED(i) \ - __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock) -static struct s3c24xx_uart_port -s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { - [0] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(0), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - } - }, - [1] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(1), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - } - }, -#if CONFIG_SERIAL_SAMSUNG_UARTS > 2 - - [2] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(2), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - } - }, -#endif -#if CONFIG_SERIAL_SAMSUNG_UARTS > 3 - [3] = { - .port = { - .lock = __PORT_LOCK_UNLOCKED(3), - .iotype = UPIO_MEM, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 3, - } - } -#endif -}; -#undef __PORT_LOCK_UNLOCKED +static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR]; + +static void s3c24xx_serial_init_port_default(int index) +{ + struct uart_port *port = &s3c24xx_serial_ports[index].port; + + spin_lock_init(&port->lock); + + port->uartclk = 0; + port->fifosize = 16; + port->flags = UPF_BOOT_AUTOCONF; + port->line = index; +} /* s3c24xx_serial_resetport * @@ -1707,18 +1759,13 @@ s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { */ static void s3c24xx_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) + const struct s3c2410_uartcfg *cfg) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ucon = rd_regl(port, S3C2410_UCON); - unsigned int ucon_mask; + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + u32 ucon = rd_regl(port, S3C2410_UCON); - ucon_mask = info->clksel_mask; - if (info->type == PORT_S3C2440) - ucon_mask |= S3C2440_UCON0_DIVMASK; - - ucon &= ucon_mask; - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + ucon &= (info->clksel_mask | info->ucon_mask); + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); @@ -1728,103 +1775,14 @@ static void s3c24xx_serial_resetport(struct uart_port *port, udelay(1); } - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - -static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c24xx_uart_port *port; - struct uart_port *uport; - - port = container_of(nb, struct s3c24xx_uart_port, freq_transition); - uport = &port->port; - - /* check to see if port is enabled */ - - if (port->pm_level != 0) - return 0; - - /* try and work out if the baudrate is changing, we can detect - * a change in rate, but we do not have support for detecting - * a disturbance in the clock-rate over the change. - */ - - if (IS_ERR(port->baudclk)) - goto exit; - - if (port->baudclk_rate == clk_get_rate(port->baudclk)) - goto exit; - - if (val == CPUFREQ_PRECHANGE) { - /* we should really shut the port down whilst the - * frequency change is in progress. - */ - - } else if (val == CPUFREQ_POSTCHANGE) { - struct ktermios *termios; - struct tty_struct *tty; - - if (uport->state == NULL) - goto exit; - - tty = uport->state->port.tty; - - if (tty == NULL) - goto exit; - - termios = &tty->termios; - - if (termios == NULL) { - dev_warn(uport->dev, "%s: no termios?\n", __func__); - goto exit; - } - - s3c24xx_serial_set_termios(uport, termios, NULL); - } - -exit: - return 0; -} - -static inline int -s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) -{ - port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition; - - return cpufreq_register_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void -s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) -{ - cpufreq_unregister_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int -s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) -{ - return 0; -} - -static inline void -s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) -{ -} -#endif - static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport) { struct device *dev = ourport->port.dev; - struct s3c24xx_uart_info *info = ourport->info; + const struct s3c24xx_uart_info *info = ourport->info; char clk_name[MAX_CLK_NAME_LENGTH]; - unsigned int clk_sel; struct clk *clk; - int clk_num; int ret; + u8 clk_sel, clk_num; clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel; for (clk_num = 0; clk_num < info->num_clks; clk_num++) { @@ -1861,7 +1819,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, struct platform_device *platdev) { struct uart_port *port = &ourport->port; - struct s3c2410_uartcfg *cfg = ourport->cfg; + const struct s3c2410_uartcfg *cfg = ourport->cfg; struct resource *res; int ret; @@ -1874,10 +1832,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* setup info for port */ port->dev = &platdev->dev; - /* Startup sequence is different for s3c64xx and higher SoC's */ - if (s3c24xx_serial_has_interrupt_mask(port)) - s3c24xx_serial_ops.startup = s3c64xx_serial_startup; - port->uartclk = 1; if (cfg->uart_flags & UPF_CONS_FLOW) { @@ -1895,25 +1849,22 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, dev_dbg(port->dev, "resource %pR)\n", res); - port->membase = devm_ioremap(port->dev, res->start, resource_size(res)); - if (!port->membase) { + port->membase = devm_ioremap_resource(port->dev, res); + if (IS_ERR(port->membase)) { dev_err(port->dev, "failed to remap controller address\n"); return -EBUSY; } port->mapbase = res->start; ret = platform_get_irq(platdev, 0); - if (ret < 0) + if (ret < 0) { port->irq = 0; - else { + } else { port->irq = ret; ourport->rx_irq = ret; ourport->tx_irq = ret + 1; } - ret = platform_get_irq(platdev, 1); - if (ret > 0) - ourport->tx_irq = ret; /* * DMA is currently supported only on DT platforms, if DMA properties * are specified. @@ -1949,10 +1900,26 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, pr_warn("uart: failed to enable baudclk\n"); /* Keep all interrupts masked and cleared */ - if (s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C6400: wr_regl(port, S3C64XX_UINTM, 0xf); wr_regl(port, S3C64XX_UINTP, 0xf); wr_regl(port, S3C64XX_UINTSP, 0xf); + break; + case TYPE_APPLE_S5L: { + u32 ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + wr_regl(port, S3C2410_UCON, ucon); + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + break; + } + default: + break; } dev_dbg(port->dev, "port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n", @@ -1971,23 +1938,14 @@ err: /* Device driver serial port probe */ -#ifdef CONFIG_OF -static const struct of_device_id s3c24xx_uart_dt_match[]; -#endif - static int probe_index; -static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data( - struct platform_device *pdev) +static inline const struct s3c24xx_serial_drv_data * +s3c24xx_get_driver_data(struct platform_device *pdev) { -#ifdef CONFIG_OF - if (pdev->dev.of_node) { - const struct of_device_id *match; + if (dev_of_node(&pdev->dev)) + return of_device_get_match_data(&pdev->dev); - match = of_match_node(s3c24xx_uart_dt_match, pdev->dev.of_node); - return (struct s3c24xx_serial_drv_data *)match->data; - } -#endif return (struct s3c24xx_serial_drv_data *) platform_get_device_id(pdev)->driver_data; } @@ -1997,7 +1955,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct s3c24xx_uart_port *ourport; int index = probe_index; - int ret, prop = 0; + int ret, prop = 0, fifosize_prop = 1; if (np) { ret = of_alias_get_id(np, "serial"); @@ -2011,6 +1969,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) } ourport = &s3c24xx_serial_ports[index]; + s3c24xx_serial_init_port_default(index); + ourport->drv_data = s3c24xx_get_driver_data(pdev); if (!ourport->drv_data) { dev_err(&pdev->dev, "could not find driver data\n"); @@ -2018,14 +1978,25 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) } ourport->baudclk = ERR_PTR(-EINVAL); - ourport->info = ourport->drv_data->info; + ourport->info = &ourport->drv_data->info; ourport->cfg = (dev_get_platdata(&pdev->dev)) ? dev_get_platdata(&pdev->dev) : - ourport->drv_data->def_cfg; + &ourport->drv_data->def_cfg; + + switch (ourport->info->type) { + case TYPE_S3C6400: + ourport->port.ops = &s3c64xx_serial_ops; + break; + case TYPE_APPLE_S5L: + ourport->port.ops = &apple_s5l_serial_ops; + break; + } + + ourport->port.iotype = ourport->info->iotype; if (np) { - of_property_read_u32(np, - "samsung,uart-fifosize", &ourport->port.fifosize); + fifosize_prop = of_property_read_u32(np, "samsung,uart-fifosize", + &ourport->port.fifosize); if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { switch (prop) { @@ -2038,16 +2009,18 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) default: dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n", prop); - ret = -EINVAL; - break; + return -EINVAL; } } } - if (ourport->drv_data->fifosize[index]) - ourport->port.fifosize = ourport->drv_data->fifosize[index]; - else if (ourport->info->fifosize) - ourport->port.fifosize = ourport->info->fifosize; + if (fifosize_prop) { + if (ourport->drv_data->fifosize[index]) + ourport->port.fifosize = ourport->drv_data->fifosize[index]; + else if (ourport->info->fifosize) + ourport->port.fifosize = ourport->info->fifosize; + } + ourport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SAMSUNG_CONSOLE); /* @@ -2084,27 +2057,19 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); - ret = s3c24xx_serial_cpufreq_register(ourport); - if (ret < 0) - dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); - probe_index++; return 0; } -static int s3c24xx_serial_remove(struct platform_device *dev) +static void s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); - if (port) { - s3c24xx_serial_cpufreq_deregister(to_ourport(port)); + if (port) uart_remove_one_port(&s3c24xx_uart_drv, port); - } uart_unregister_driver(&s3c24xx_uart_drv); - - return 0; } /* UART power management code */ @@ -2146,8 +2111,9 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (port) { /* restore IRQ mask */ - if (s3c24xx_serial_has_interrupt_mask(port)) { - unsigned int uintm = 0xf; + switch (ourport->info->type) { + case TYPE_S3C6400: { + u32 uintm = 0xf; if (ourport->tx_enabled) uintm &= ~S3C64XX_UINTM_TXD_MSK; @@ -2160,6 +2126,49 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); clk_disable_unprepare(ourport->clk); + break; + } + case TYPE_APPLE_S5L: { + u32 ucon; + int ret; + + ret = clk_prepare_enable(ourport->clk); + if (ret) { + dev_err(dev, "clk_enable clk failed: %d\n", ret); + return ret; + } + if (!IS_ERR(ourport->baudclk)) { + ret = clk_prepare_enable(ourport->baudclk); + if (ret) { + dev_err(dev, "clk_enable baudclk failed: %d\n", ret); + clk_disable_unprepare(ourport->clk); + return ret; + } + } + + ucon = rd_regl(port, S3C2410_UCON); + + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK | + APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK); + + if (ourport->tx_enabled) + ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK; + if (ourport->rx_enabled) + ucon |= APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK | + APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK; + + wr_regl(port, S3C2410_UCON, ucon); + + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); + clk_disable_unprepare(ourport->clk); + break; + } + default: + break; } } @@ -2167,9 +2176,8 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) } static const struct dev_pm_ops s3c24xx_serial_pm_ops = { - .suspend = s3c24xx_serial_suspend, - .resume = s3c24xx_serial_resume, - .resume_noirq = s3c24xx_serial_resume_noirq, + SET_SYSTEM_SLEEP_PM_OPS(s3c24xx_serial_suspend, s3c24xx_serial_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, s3c24xx_serial_resume_noirq) }; #define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops) @@ -2184,27 +2192,27 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = { static struct uart_port *cons_uart; -static int -s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) +static bool +s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ufstat, utrstat; + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + u32 ufstat, utrstat; if (ufcon & S3C2410_UFCON_FIFOMODE) { /* fifo mode - check amount of data in fifo registers... */ ufstat = rd_regl(port, S3C2410_UFSTAT); - return (ufstat & info->tx_fifofull) ? 0 : 1; + return !(ufstat & info->tx_fifofull); } /* in non-fifo mode, we go and use the tx buffer empty */ utrstat = rd_regl(port, S3C2410_UTRSTAT); - return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0; + return utrstat & S3C2410_UTRSTAT_TXE; } static bool -s3c24xx_port_configured(unsigned int ucon) +s3c24xx_port_configured(u32 ucon) { /* consider the serial port configured if the tx/rx mode set */ return (ucon & 0xf) != 0; @@ -2218,8 +2226,8 @@ s3c24xx_port_configured(unsigned int ucon) static int s3c24xx_serial_get_poll_char(struct uart_port *port) { - struct s3c24xx_uart_port *ourport = to_ourport(port); - unsigned int ufstat; + const struct s3c24xx_uart_port *ourport = to_ourport(port); + u32 ufstat; ufstat = rd_regl(port, S3C2410_UFSTAT); if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) @@ -2231,8 +2239,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port) static void s3c24xx_serial_put_poll_char(struct uart_port *port, unsigned char c) { - unsigned int ufcon = rd_regl(port, S3C2410_UFCON); - unsigned int ucon = rd_regl(port, S3C2410_UCON); + u32 ufcon = rd_regl(port, S3C2410_UFCON); + u32 ucon = rd_regl(port, S3C2410_UCON); /* not possible to xmit on unconfigured port */ if (!s3c24xx_port_configured(ucon)) @@ -2246,9 +2254,9 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, #endif /* CONFIG_CONSOLE_POLL */ static void -s3c24xx_serial_console_putchar(struct uart_port *port, int ch) +s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch) { - unsigned int ufcon = rd_regl(port, S3C2410_UFCON); + u32 ufcon = rd_regl(port, S3C2410_UFCON); while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); @@ -2259,26 +2267,37 @@ static void s3c24xx_serial_console_write(struct console *co, const char *s, unsigned int count) { - unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + u32 ucon = rd_regl(cons_uart, S3C2410_UCON); + unsigned long flags; + bool locked = true; /* not possible to xmit on unconfigured port */ if (!s3c24xx_port_configured(ucon)) return; + if (cons_uart->sysrq) + locked = false; + else if (oops_in_progress) + locked = uart_port_trylock_irqsave(cons_uart, &flags); + else + uart_port_lock_irqsave(cons_uart, &flags); + uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); + + if (locked) + uart_port_unlock_irqrestore(cons_uart, flags); } -static void __init +/* Shouldn't be __init, as it can be instantiated from other module */ +static void s3c24xx_serial_get_options(struct uart_port *port, int *baud, int *parity, int *bits) { struct clk *clk; - unsigned int ulcon; - unsigned int ucon; - unsigned int ubrdiv; unsigned long rate; - unsigned int clk_sel; + u32 ulcon, ucon, ubrdiv; char clk_name[MAX_CLK_NAME_LENGTH]; + u8 clk_sel; ulcon = rd_regl(port, S3C2410_ULCON); ucon = rd_regl(port, S3C2410_UCON); @@ -2329,10 +2348,10 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, *baud = rate / (16 * (ubrdiv + 1)); dev_dbg(port->dev, "calculated baud %d\n", *baud); } - } -static int __init +/* Shouldn't be __init, as it can be instantiated from other module */ +static int s3c24xx_serial_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -2343,7 +2362,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options) /* is this a valid port */ - if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS) + if (co->index == -1 || co->index >= UART_NR) co->index = 0; port = &s3c24xx_serial_ports[co->index].port; @@ -2381,97 +2400,15 @@ static struct console s3c24xx_serial_console = { }; #endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */ -#ifdef CONFIG_CPU_S3C2410 -static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { - .name = "Samsung S3C2410 UART", - .type = PORT_S3C2410, - .fifosize = 16, - .rx_fifomask = S3C2410_UFSTAT_RXMASK, - .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2410_UFSTAT_RXFULL, - .tx_fifofull = S3C2410_UFSTAT_TXFULL, - .tx_fifomask = S3C2410_UFSTAT_TXMASK, - .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, - .def_clk_sel = S3C2410_UCON_CLKSEL0, - .num_clks = 2, - .clksel_mask = S3C2410_UCON_CLKMASK, - .clksel_shift = S3C2410_UCON_CLKSHIFT, - }, - .def_cfg = &(struct s3c2410_uartcfg) { - .ucon = S3C2410_UCON_DEFAULT, - .ufcon = S3C2410_UFCON_DEFAULT, - }, -}; -#define S3C2410_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2410_serial_drv_data) -#else -#define S3C2410_SERIAL_DRV_DATA (kernel_ulong_t)NULL -#endif - -#ifdef CONFIG_CPU_S3C2412 -static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { - .name = "Samsung S3C2412 UART", - .type = PORT_S3C2412, - .fifosize = 64, - .has_divslot = 1, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .def_clk_sel = S3C2410_UCON_CLKSEL2, - .num_clks = 4, - .clksel_mask = S3C2412_UCON_CLKMASK, - .clksel_shift = S3C2412_UCON_CLKSHIFT, - }, - .def_cfg = &(struct s3c2410_uartcfg) { - .ucon = S3C2410_UCON_DEFAULT, - .ufcon = S3C2410_UFCON_DEFAULT, - }, -}; -#define S3C2412_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2412_serial_drv_data) -#else -#define S3C2412_SERIAL_DRV_DATA (kernel_ulong_t)NULL -#endif - -#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \ - defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442) -static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { - .name = "Samsung S3C2440 UART", - .type = PORT_S3C2440, - .fifosize = 64, - .has_divslot = 1, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .def_clk_sel = S3C2410_UCON_CLKSEL2, - .num_clks = 4, - .clksel_mask = S3C2412_UCON_CLKMASK, - .clksel_shift = S3C2412_UCON_CLKSHIFT, - }, - .def_cfg = &(struct s3c2410_uartcfg) { - .ucon = S3C2410_UCON_DEFAULT, - .ufcon = S3C2410_UFCON_DEFAULT, - }, -}; -#define S3C2440_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2440_serial_drv_data) -#else -#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL -#endif - #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) -static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { +static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { + .info = { .name = "Samsung S3C6400 UART", - .type = PORT_S3C6400, + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, + .iotype = UPIO_MEM, .fifosize = 64, - .has_divslot = 1, + .has_divslot = true, .rx_fifomask = S3C2440_UFSTAT_RXMASK, .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, .rx_fifofull = S3C2440_UFSTAT_RXFULL, @@ -2483,22 +2420,24 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .clksel_mask = S3C6400_UCON_CLKMASK, .clksel_shift = S3C6400_UCON_CLKSHIFT, }, - .def_cfg = &(struct s3c2410_uartcfg) { + .def_cfg = { .ucon = S3C2410_UCON_DEFAULT, .ufcon = S3C2410_UFCON_DEFAULT, }, }; -#define S3C6400_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c6400_serial_drv_data) +#define S3C6400_SERIAL_DRV_DATA (&s3c6400_serial_drv_data) #else -#define S3C6400_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define S3C6400_SERIAL_DRV_DATA NULL #endif #ifdef CONFIG_CPU_S5PV210 -static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { +static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { + .info = { .name = "Samsung S5PV210 UART", - .type = PORT_S3C6400, - .has_divslot = 1, + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, + .iotype = UPIO_MEM, + .has_divslot = true, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, .rx_fifofull = S5PV210_UFSTAT_RXFULL, @@ -2510,23 +2449,25 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .clksel_mask = S5PV210_UCON_CLKMASK, .clksel_shift = S5PV210_UCON_CLKSHIFT, }, - .def_cfg = &(struct s3c2410_uartcfg) { + .def_cfg = { .ucon = S5PV210_UCON_DEFAULT, .ufcon = S5PV210_UFCON_DEFAULT, }, .fifosize = { 256, 64, 16, 16 }, }; -#define S5PV210_SERIAL_DRV_DATA ((kernel_ulong_t)&s5pv210_serial_drv_data) +#define S5PV210_SERIAL_DRV_DATA (&s5pv210_serial_drv_data) #else -#define S5PV210_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define S5PV210_SERIAL_DRV_DATA NULL #endif #if defined(CONFIG_ARCH_EXYNOS) #define EXYNOS_COMMON_SERIAL_DRV_DATA \ - .info = &(struct s3c24xx_uart_info) { \ + .info = { \ .name = "Samsung Exynos UART", \ - .type = PORT_S3C6400, \ - .has_divslot = 1, \ + .type = TYPE_S3C6400, \ + .port_type = PORT_S3C6400, \ + .iotype = UPIO_MEM, \ + .has_divslot = true, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ .rx_fifofull = S5PV210_UFSTAT_RXFULL, \ @@ -2538,51 +2479,163 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .clksel_mask = 0, \ .clksel_shift = 0, \ }, \ - .def_cfg = &(struct s3c2410_uartcfg) { \ + .def_cfg = { \ .ucon = S5PV210_UCON_DEFAULT, \ .ufcon = S5PV210_UFCON_DEFAULT, \ .has_fracval = 1, \ } \ -static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { +static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { EXYNOS_COMMON_SERIAL_DRV_DATA, .fifosize = { 256, 64, 16, 16 }, }; -static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { +static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { EXYNOS_COMMON_SERIAL_DRV_DATA, .fifosize = { 64, 256, 16, 256 }, }; -#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data) -#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data) +static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { + EXYNOS_COMMON_SERIAL_DRV_DATA, + .fifosize = { 256, 64, 64, 64 }, +}; + +static const struct s3c24xx_serial_drv_data exynos8895_serial_drv_data = { + EXYNOS_COMMON_SERIAL_DRV_DATA, + /* samsung,uart-fifosize must be specified in the device tree. */ + .fifosize = { 0 }, +}; + +static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = { + .info = { + .name = "Google GS101 UART", + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, + .iotype = UPIO_MEM32, + .has_divslot = true, + .rx_fifomask = S5PV210_UFSTAT_RXMASK, + .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, + .rx_fifofull = S5PV210_UFSTAT_RXFULL, + .tx_fifofull = S5PV210_UFSTAT_TXFULL, + .tx_fifomask = S5PV210_UFSTAT_TXMASK, + .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, + .def_clk_sel = S3C2410_UCON_CLKSEL0, + .num_clks = 1, + .clksel_mask = 0, + .clksel_shift = 0, + }, + .def_cfg = { + .ucon = S5PV210_UCON_DEFAULT, + .ufcon = S5PV210_UFCON_DEFAULT, + .has_fracval = 1, + }, + /* samsung,uart-fifosize must be specified in the device tree. */ + .fifosize = { 0 }, +}; + +#define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data) +#define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data) +#define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data) +#define EXYNOS8895_SERIAL_DRV_DATA (&exynos8895_serial_drv_data) +#define GS101_SERIAL_DRV_DATA (&gs101_serial_drv_data) + +#else +#define EXYNOS4210_SERIAL_DRV_DATA NULL +#define EXYNOS5433_SERIAL_DRV_DATA NULL +#define EXYNOS850_SERIAL_DRV_DATA NULL +#define EXYNOS8895_SERIAL_DRV_DATA NULL +#define GS101_SERIAL_DRV_DATA NULL +#endif + +#ifdef CONFIG_ARCH_APPLE +static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = { + .info = { + .name = "Apple S5L UART", + .type = TYPE_APPLE_S5L, + .port_type = PORT_8250, + .iotype = UPIO_MEM32, + .fifosize = 16, + .rx_fifomask = S3C2410_UFSTAT_RXMASK, + .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2410_UFSTAT_RXFULL, + .tx_fifofull = S3C2410_UFSTAT_TXFULL, + .tx_fifomask = S3C2410_UFSTAT_TXMASK, + .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, + .def_clk_sel = S3C2410_UCON_CLKSEL0, + .num_clks = 1, + .clksel_mask = 0, + .clksel_shift = 0, + .ucon_mask = APPLE_S5L_UCON_MASK, + }, + .def_cfg = { + .ucon = APPLE_S5L_UCON_DEFAULT, + .ufcon = S3C2410_UFCON_DEFAULT, + }, +}; +#define S5L_SERIAL_DRV_DATA (&s5l_serial_drv_data) #else -#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL -#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define S5L_SERIAL_DRV_DATA NULL +#endif + +#if defined(CONFIG_ARCH_ARTPEC) +static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = { + .info = { + .name = "Axis ARTPEC-8 UART", + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, + .iotype = UPIO_MEM, + .fifosize = 64, + .has_divslot = true, + .rx_fifomask = S5PV210_UFSTAT_RXMASK, + .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, + .rx_fifofull = S5PV210_UFSTAT_RXFULL, + .tx_fifofull = S5PV210_UFSTAT_TXFULL, + .tx_fifomask = S5PV210_UFSTAT_TXMASK, + .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, + .def_clk_sel = S3C2410_UCON_CLKSEL0, + .num_clks = 1, + .clksel_mask = 0, + .clksel_shift = 0, + }, + .def_cfg = { + .ucon = S5PV210_UCON_DEFAULT, + .ufcon = S5PV210_UFCON_DEFAULT, + .has_fracval = 1, + } +}; +#define ARTPEC8_SERIAL_DRV_DATA (&artpec8_serial_drv_data) +#else +#define ARTPEC8_SERIAL_DRV_DATA (NULL) #endif static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { - .name = "s3c2410-uart", - .driver_data = S3C2410_SERIAL_DRV_DATA, - }, { - .name = "s3c2412-uart", - .driver_data = S3C2412_SERIAL_DRV_DATA, - }, { - .name = "s3c2440-uart", - .driver_data = S3C2440_SERIAL_DRV_DATA, - }, { .name = "s3c6400-uart", - .driver_data = S3C6400_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)S3C6400_SERIAL_DRV_DATA, }, { .name = "s5pv210-uart", - .driver_data = S5PV210_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)S5PV210_SERIAL_DRV_DATA, }, { .name = "exynos4210-uart", - .driver_data = EXYNOS4210_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)EXYNOS4210_SERIAL_DRV_DATA, }, { .name = "exynos5433-uart", - .driver_data = EXYNOS5433_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)EXYNOS5433_SERIAL_DRV_DATA, + }, { + .name = "s5l-uart", + .driver_data = (kernel_ulong_t)S5L_SERIAL_DRV_DATA, + }, { + .name = "exynos850-uart", + .driver_data = (kernel_ulong_t)EXYNOS850_SERIAL_DRV_DATA, + }, { + .name = "artpec8-uart", + .driver_data = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA, + }, { + .name = "gs101-uart", + .driver_data = (kernel_ulong_t)GS101_SERIAL_DRV_DATA, + }, { + .name = "exynos8895-uart", + .driver_data = (kernel_ulong_t)EXYNOS8895_SERIAL_DRV_DATA, }, { }, }; @@ -2590,20 +2643,24 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids); #ifdef CONFIG_OF static const struct of_device_id s3c24xx_uart_dt_match[] = { - { .compatible = "samsung,s3c2410-uart", - .data = (void *)S3C2410_SERIAL_DRV_DATA }, - { .compatible = "samsung,s3c2412-uart", - .data = (void *)S3C2412_SERIAL_DRV_DATA }, - { .compatible = "samsung,s3c2440-uart", - .data = (void *)S3C2440_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c6400-uart", - .data = (void *)S3C6400_SERIAL_DRV_DATA }, + .data = S3C6400_SERIAL_DRV_DATA }, { .compatible = "samsung,s5pv210-uart", - .data = (void *)S5PV210_SERIAL_DRV_DATA }, + .data = S5PV210_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos4210-uart", - .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, + .data = EXYNOS4210_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos5433-uart", - .data = (void *)EXYNOS5433_SERIAL_DRV_DATA }, + .data = EXYNOS5433_SERIAL_DRV_DATA }, + { .compatible = "apple,s5l-uart", + .data = S5L_SERIAL_DRV_DATA }, + { .compatible = "samsung,exynos850-uart", + .data = EXYNOS850_SERIAL_DRV_DATA }, + { .compatible = "axis,artpec8-uart", + .data = ARTPEC8_SERIAL_DRV_DATA }, + { .compatible = "google,gs101-uart", + .data = GS101_SERIAL_DRV_DATA }, + { .compatible = "samsung,exynos8895-uart", + .data = EXYNOS8895_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); @@ -2620,14 +2677,36 @@ static struct platform_driver samsung_serial_driver = { }, }; -module_platform_driver(samsung_serial_driver); +static int __init samsung_serial_init(void) +{ + int ret; + + s3c24xx_serial_register_console(); + + ret = platform_driver_register(&samsung_serial_driver); + if (ret) { + s3c24xx_serial_unregister_console(); + return ret; + } + + return 0; +} + +static void __exit samsung_serial_exit(void) +{ + platform_driver_unregister(&samsung_serial_driver); + s3c24xx_serial_unregister_console(); +} + +module_init(samsung_serial_init); +module_exit(samsung_serial_exit); #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE /* * Early console. */ -static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val) +static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val) { switch (port->iotype) { case UPIO_MEM: @@ -2636,28 +2715,31 @@ static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val) case UPIO_MEM32: writel(val, portaddr(port, reg)); break; + default: + break; } } struct samsung_early_console_data { u32 txfull_mask; + u32 rxfifo_mask; }; -static void samsung_early_busyuart(struct uart_port *port) +static void samsung_early_busyuart(const struct uart_port *port) { while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE)) ; } -static void samsung_early_busyuart_fifo(struct uart_port *port) +static void samsung_early_busyuart_fifo(const struct uart_port *port) { - struct samsung_early_console_data *data = port->private_data; + const struct samsung_early_console_data *data = port->private_data; while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask) ; } -static void samsung_early_putc(struct uart_port *port, int c) +static void samsung_early_putc(struct uart_port *port, unsigned char c) { if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) samsung_early_busyuart_fifo(port); @@ -2675,6 +2757,27 @@ static void samsung_early_write(struct console *con, const char *s, uart_console_write(&dev->port, s, n, samsung_early_putc); } +static int samsung_early_read(struct console *con, char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + const struct samsung_early_console_data *data = dev->port.private_data; + int num_read = 0; + u32 ch, ufstat; + + while (num_read < n) { + ufstat = rd_regl(&dev->port, S3C2410_UFSTAT); + if (!(ufstat & data->rxfifo_mask)) + break; + ch = rd_reg(&dev->port, S3C2410_URXH); + if (ch == NO_POLL_CHAR) + break; + + s[num_read++] = ch; + } + + return num_read; +} + static int __init samsung_early_console_setup(struct earlycon_device *device, const char *opt) { @@ -2682,26 +2785,20 @@ static int __init samsung_early_console_setup(struct earlycon_device *device, return -ENODEV; device->con->write = samsung_early_write; + device->con->read = samsung_early_read; return 0; } /* S3C2410 */ static struct samsung_early_console_data s3c2410_early_console_data = { .txfull_mask = S3C2410_UFSTAT_TXFULL, + .rxfifo_mask = S3C2410_UFSTAT_RXFULL | S3C2410_UFSTAT_RXMASK, }; -static int __init s3c2410_early_console_setup(struct earlycon_device *device, - const char *opt) -{ - device->port.private_data = &s3c2410_early_console_data; - return samsung_early_console_setup(device, opt); -} -OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart", - s3c2410_early_console_setup); - -/* S3C2412, S3C2440, S3C64xx */ +/* S3C64xx */ static struct samsung_early_console_data s3c2440_early_console_data = { .txfull_mask = S3C2440_UFSTAT_TXFULL, + .rxfifo_mask = S3C2440_UFSTAT_RXFULL | S3C2440_UFSTAT_RXMASK, }; static int __init s3c2440_early_console_setup(struct earlycon_device *device, @@ -2710,16 +2807,14 @@ static int __init s3c2440_early_console_setup(struct earlycon_device *device, device->port.private_data = &s3c2440_early_console_data; return samsung_early_console_setup(device, opt); } -OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart", - s3c2440_early_console_setup); -OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart", - s3c2440_early_console_setup); + OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart", s3c2440_early_console_setup); /* S5PV210, Exynos */ static struct samsung_early_console_data s5pv210_early_console_data = { .txfull_mask = S5PV210_UFSTAT_TXFULL, + .rxfifo_mask = S5PV210_UFSTAT_RXFULL | S5PV210_UFSTAT_RXMASK, }; static int __init s5pv210_early_console_setup(struct earlycon_device *device, @@ -2728,10 +2823,46 @@ static int __init s5pv210_early_console_setup(struct earlycon_device *device, device->port.private_data = &s5pv210_early_console_data; return samsung_early_console_setup(device, opt); } + OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart", s5pv210_early_console_setup); OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart", s5pv210_early_console_setup); +OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart", + s5pv210_early_console_setup); +OF_EARLYCON_DECLARE(exynos850, "samsung,exynos850-uart", + s5pv210_early_console_setup); + +static int __init gs101_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + /* gs101 always expects MMIO32 register accesses. */ + device->port.iotype = UPIO_MEM32; + + return s5pv210_early_console_setup(device, opt); +} + +OF_EARLYCON_DECLARE(gs101, "google,gs101-uart", gs101_early_console_setup); + +/* Apple S5L */ +static int __init apple_s5l_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + /* Apple A7-A11 requires MMIO32 register accesses. */ + device->port.iotype = UPIO_MEM32; + + /* Close enough to S3C2410 for earlycon... */ + device->port.private_data = &s3c2410_early_console_data; + +#ifdef CONFIG_ARM64 + /* ... but we need to override the existing fixmap entry as nGnRnE */ + __set_fixmap(FIX_EARLYCON_MEM_BASE, device->port.mapbase, + __pgprot(PROT_DEVICE_nGnRnE)); +#endif + return samsung_early_console_setup(device, opt); +} + +OF_EARLYCON_DECLARE(s5l, "apple,s5l-uart", apple_s5l_early_console_setup); #endif MODULE_ALIAS("platform:samsung-uart"); diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index bd5e7e9938ce..b4e1b90e5960 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -34,15 +34,14 @@ #include <linux/types.h> #include <linux/refcount.h> -#include <asm/io.h> -#include <asm/war.h> +#include <linux/io.h> #include <asm/sibyte/sb1250.h> #include <asm/sibyte/sb1250_uart.h> #include <asm/sibyte/swarm.h> -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#if defined(CONFIG_SIBYTE_BCM1x80) #include <asm/sibyte/bcm1480_regs.h> #include <asm/sibyte/bcm1480_int.h> @@ -157,7 +156,7 @@ static unsigned char read_sbdchn(struct sbd_port *sport, int reg) unsigned char retval; retval = __read_sbdchn(sport, reg); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); return retval; } @@ -167,7 +166,7 @@ static unsigned char read_sbdshr(struct sbd_port *sport, int reg) unsigned char retval; retval = __read_sbdshr(sport, reg); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); return retval; } @@ -175,14 +174,14 @@ static unsigned char read_sbdshr(struct sbd_port *sport, int reg) static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value) { __write_sbdchn(sport, reg, value); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); } static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value) { __write_sbdshr(sport, reg, value); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); } @@ -332,8 +331,9 @@ static void sbd_receive_chars(struct sbd_port *sport) { struct uart_port *uport = &sport->port; struct uart_icount *icount; - unsigned int status, ch, flag; + unsigned int status; int count; + u8 ch, flag; for (count = 16; count; count--) { status = read_sbdchn(sport, R_DUART_STATUS); @@ -382,7 +382,8 @@ static void sbd_receive_chars(struct sbd_port *sport) static void sbd_transmit_chars(struct sbd_port *sport) { struct uart_port *uport = &sport->port; - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; + unsigned char ch; unsigned int mask; int stop_tx; @@ -395,20 +396,19 @@ static void sbd_transmit_chars(struct sbd_port *sport) } /* If nothing to do or stopped or hardware stopped. */ - stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)); + stop_tx = uart_tx_stopped(&sport->port) || + !uart_fifo_get(&sport->port, &ch); /* Send char. */ if (!stop_tx) { - write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; + write_sbdchn(sport, R_DUART_TX_HOLD, ch); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); } /* Are we are done? */ - if (stop_tx || uart_circ_empty(xmit)) { + if (stop_tx || kfifo_is_empty(&tport->xmit_fifo)) { /* Disable tx interrupts. */ mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); mask &= ~M_DUART_IMR_TX; @@ -532,7 +532,7 @@ static void sbd_init_port(struct sbd_port *sport) } static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct sbd_port *sport = to_sport(uport); unsigned int mode1 = 0, mode2 = 0, aux = 0; @@ -611,7 +611,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, else aux &= ~M_DUART_CTS_CHNG_ENA; - spin_lock(&uport->lock); + uart_port_lock(uport); if (sport->tx_stopped) command |= M_DUART_TX_DIS; @@ -633,7 +633,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, write_sbdchn(sport, R_DUART_CMD, command); - spin_unlock(&uport->lock); + uart_port_unlock(uport); } @@ -821,7 +821,7 @@ static void __init sbd_probe_duarts(void) * console output. The console_lock is held by the caller, so we * shouldn't be interrupted for more console activity. */ -static void sbd_console_putchar(struct uart_port *uport, int ch) +static void sbd_console_putchar(struct uart_port *uport, unsigned char ch) { struct sbd_port *sport = to_sport(uport); @@ -840,22 +840,22 @@ static void sbd_console_write(struct console *co, const char *s, unsigned int mask; /* Disable transmit interrupts and enable the transmitter. */ - spin_lock_irqsave(&uport->lock, flags); + uart_port_lock_irqsave(uport, &flags); mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask & ~M_DUART_IMR_TX); write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); - spin_unlock_irqrestore(&uport->lock, flags); + uart_port_unlock_irqrestore(uport, flags); uart_console_write(&sport->port, s, count, sbd_console_putchar); /* Restore transmit interrupts and the transmitter enable. */ - spin_lock_irqsave(&uport->lock, flags); + uart_port_lock_irqsave(uport, &flags); sbd_line_drain(sport); if (sport->tx_stopped) write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS); write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); - spin_unlock_irqrestore(&uport->lock, flags); + uart_port_unlock_irqrestore(uport, flags); } static int __init sbd_console_setup(struct console *co, char *options) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index d2e5c6c86643..1fd64a47341d 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1,32 +1,40 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint - * Author: Jon Ringle <jringle@gridpoint.com> + * SC16IS7xx tty serial driver - common code * - * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru> + * Copyright (C) 2014 GridPoint + * Author: Jon Ringle <jringle@gridpoint.com> + * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru> */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#undef DEFAULT_SYMBOL_NAMESPACE +#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX" -#include <linux/bitops.h> +#include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/export.h> +#include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> -#include <linux/i2c.h> +#include <linux/idr.h> +#include <linux/kthread.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/regmap.h> +#include <linux/sched.h> #include <linux/serial_core.h> #include <linux/serial.h> +#include <linux/string.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/spi/spi.h> #include <linux/uaccess.h> -#include <uapi/linux/sched/types.h> +#include <linux/units.h> + +#include "sc16is7xx.h" -#define SC16IS7XX_NAME "sc16is7xx" #define SC16IS7XX_MAX_DEVS 8 /* SC16IS7XX register definitions */ @@ -42,18 +50,10 @@ #define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */ #define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */ #define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */ -#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction - * - only on 75x/76x - */ -#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State - * - only on 75x/76x - */ -#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable - * - only on 75x/76x - */ -#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control - * - only on 75x/76x - */ +#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction - only on 75x/76x */ +#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State - only on 75x/76x */ +#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable - only on 75x/76x */ +#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control - only on 75x/76x */ #define SC16IS7XX_EFCR_REG (0x0f) /* Extra Features Control */ /* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */ @@ -72,52 +72,48 @@ #define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */ /* IER register bits */ -#define SC16IS7XX_IER_RDI_BIT (1 << 0) /* Enable RX data interrupt */ -#define SC16IS7XX_IER_THRI_BIT (1 << 1) /* Enable TX holding register - * interrupt */ -#define SC16IS7XX_IER_RLSI_BIT (1 << 2) /* Enable RX line status - * interrupt */ -#define SC16IS7XX_IER_MSI_BIT (1 << 3) /* Enable Modem status - * interrupt */ +#define SC16IS7XX_IER_RDI_BIT BIT(0) /* Enable RX data interrupt */ +#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register interrupt */ +#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status interrupt */ +#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status interrupt */ /* IER register bits - write only if (EFR[4] == 1) */ -#define SC16IS7XX_IER_SLEEP_BIT (1 << 4) /* Enable Sleep mode */ -#define SC16IS7XX_IER_XOFFI_BIT (1 << 5) /* Enable Xoff interrupt */ -#define SC16IS7XX_IER_RTSI_BIT (1 << 6) /* Enable nRTS interrupt */ -#define SC16IS7XX_IER_CTSI_BIT (1 << 7) /* Enable nCTS interrupt */ +#define SC16IS7XX_IER_SLEEP_BIT BIT(4) /* Enable Sleep mode */ +#define SC16IS7XX_IER_XOFFI_BIT BIT(5) /* Enable Xoff interrupt */ +#define SC16IS7XX_IER_RTSI_BIT BIT(6) /* Enable nRTS interrupt */ +#define SC16IS7XX_IER_CTSI_BIT BIT(7) /* Enable nCTS interrupt */ /* FCR register bits */ -#define SC16IS7XX_FCR_FIFO_BIT (1 << 0) /* Enable FIFO */ -#define SC16IS7XX_FCR_RXRESET_BIT (1 << 1) /* Reset RX FIFO */ -#define SC16IS7XX_FCR_TXRESET_BIT (1 << 2) /* Reset TX FIFO */ -#define SC16IS7XX_FCR_RXLVLL_BIT (1 << 6) /* RX Trigger level LSB */ -#define SC16IS7XX_FCR_RXLVLH_BIT (1 << 7) /* RX Trigger level MSB */ +#define SC16IS7XX_FCR_FIFO_BIT BIT(0) /* Enable FIFO */ +#define SC16IS7XX_FCR_RXRESET_BIT BIT(1) /* Reset RX FIFO */ +#define SC16IS7XX_FCR_TXRESET_BIT BIT(2) /* Reset TX FIFO */ +#define SC16IS7XX_FCR_RXLVLL_BIT BIT(6) /* RX Trigger level LSB */ +#define SC16IS7XX_FCR_RXLVLH_BIT BIT(7) /* RX Trigger level MSB */ /* FCR register bits - write only if (EFR[4] == 1) */ -#define SC16IS7XX_FCR_TXLVLL_BIT (1 << 4) /* TX Trigger level LSB */ -#define SC16IS7XX_FCR_TXLVLH_BIT (1 << 5) /* TX Trigger level MSB */ +#define SC16IS7XX_FCR_TXLVLL_BIT BIT(4) /* TX Trigger level LSB */ +#define SC16IS7XX_FCR_TXLVLH_BIT BIT(5) /* TX Trigger level MSB */ /* IIR register bits */ -#define SC16IS7XX_IIR_NO_INT_BIT (1 << 0) /* No interrupts pending */ -#define SC16IS7XX_IIR_ID_MASK 0x3e /* Mask for the interrupt ID */ -#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */ -#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */ -#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */ -#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */ -#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt - * - only on 75x/76x - */ -#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state - * - only on 75x/76x - */ -#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */ -#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state - * from active (LOW) - * to inactive (HIGH) - */ +#define SC16IS7XX_IIR_NO_INT_BIT 0x01 /* No interrupts pending */ +#define SC16IS7XX_IIR_ID_MASK GENMASK(5, 1) /* Mask for the interrupt ID */ +#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */ +#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */ +#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */ +#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */ +#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt + * - only on 75x/76x + */ +#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state + * - only on 75x/76x + */ +#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */ +#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state from active + * (LOW) to inactive (HIGH) + */ /* LCR register bits */ -#define SC16IS7XX_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ -#define SC16IS7XX_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 +#define SC16IS7XX_LCR_LENGTH0_BIT BIT(0) /* Word length bit 0 */ +#define SC16IS7XX_LCR_LENGTH1_BIT BIT(1) /* Word length bit 1 * * Word length bits table: * 00 -> 5 bit words @@ -125,84 +121,71 @@ * 10 -> 7 bit words * 11 -> 8 bit words */ -#define SC16IS7XX_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit +#define SC16IS7XX_LCR_STOPLEN_BIT BIT(2) /* STOP length bit * * STOP length bit table: * 0 -> 1 stop bit - * 1 -> 1-1.5 stop bits if - * word length is 5, + * 1 -> 1-1.5 stop bits if word length is 5, * 2 stop bits otherwise */ -#define SC16IS7XX_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ -#define SC16IS7XX_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ -#define SC16IS7XX_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ -#define SC16IS7XX_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ -#define SC16IS7XX_LCR_DLAB_BIT (1 << 7) /* Divisor Latch enable */ +#define SC16IS7XX_LCR_PARITY_BIT BIT(3) /* Parity bit enable */ +#define SC16IS7XX_LCR_EVENPARITY_BIT BIT(4) /* Even parity bit enable */ +#define SC16IS7XX_LCR_FORCEPARITY_BIT BIT(5) /* 9-bit multidrop parity */ +#define SC16IS7XX_LCR_TXBREAK_BIT BIT(6) /* TX break enable */ +#define SC16IS7XX_LCR_DLAB_BIT BIT(7) /* Divisor Latch enable */ #define SC16IS7XX_LCR_WORD_LEN_5 (0x00) #define SC16IS7XX_LCR_WORD_LEN_6 (0x01) #define SC16IS7XX_LCR_WORD_LEN_7 (0x02) #define SC16IS7XX_LCR_WORD_LEN_8 (0x03) -#define SC16IS7XX_LCR_CONF_MODE_A SC16IS7XX_LCR_DLAB_BIT /* Special - * reg set */ -#define SC16IS7XX_LCR_CONF_MODE_B 0xBF /* Enhanced - * reg set */ +#define SC16IS7XX_LCR_REG_SET_SPECIAL SC16IS7XX_LCR_DLAB_BIT /* Special reg set */ +#define SC16IS7XX_LCR_REG_SET_ENHANCED 0xBF /* Enhanced reg set */ /* MCR register bits */ -#define SC16IS7XX_MCR_DTR_BIT (1 << 0) /* DTR complement - * - only on 75x/76x - */ -#define SC16IS7XX_MCR_RTS_BIT (1 << 1) /* RTS complement */ -#define SC16IS7XX_MCR_TCRTLR_BIT (1 << 2) /* TCR/TLR register enable */ -#define SC16IS7XX_MCR_LOOP_BIT (1 << 4) /* Enable loopback test mode */ -#define SC16IS7XX_MCR_XONANY_BIT (1 << 5) /* Enable Xon Any - * - write enabled - * if (EFR[4] == 1) +#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement - only on 75x/76x */ +#define SC16IS7XX_MCR_RTS_BIT BIT(1) /* RTS complement */ +#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR registers enable */ +#define SC16IS7XX_MCR_LOOP_BIT BIT(4) /* Enable loopback test mode */ +#define SC16IS7XX_MCR_XONANY_BIT BIT(5) /* Enable Xon Any + * - write enabled if (EFR[4] == 1) */ -#define SC16IS7XX_MCR_IRDA_BIT (1 << 6) /* Enable IrDA mode - * - write enabled - * if (EFR[4] == 1) +#define SC16IS7XX_MCR_IRDA_BIT BIT(6) /* Enable IrDA mode + * - write enabled if (EFR[4] == 1) */ -#define SC16IS7XX_MCR_CLKSEL_BIT (1 << 7) /* Divide clock by 4 - * - write enabled - * if (EFR[4] == 1) +#define SC16IS7XX_MCR_CLKSEL_BIT BIT(7) /* Divide clock by 4 + * - write enabled if (EFR[4] == 1) */ /* LSR register bits */ -#define SC16IS7XX_LSR_DR_BIT (1 << 0) /* Receiver data ready */ -#define SC16IS7XX_LSR_OE_BIT (1 << 1) /* Overrun Error */ -#define SC16IS7XX_LSR_PE_BIT (1 << 2) /* Parity Error */ -#define SC16IS7XX_LSR_FE_BIT (1 << 3) /* Frame Error */ -#define SC16IS7XX_LSR_BI_BIT (1 << 4) /* Break Interrupt */ -#define SC16IS7XX_LSR_BRK_ERROR_MASK 0x1E /* BI, FE, PE, OE bits */ -#define SC16IS7XX_LSR_THRE_BIT (1 << 5) /* TX holding register empty */ -#define SC16IS7XX_LSR_TEMT_BIT (1 << 6) /* Transmitter empty */ -#define SC16IS7XX_LSR_FIFOE_BIT (1 << 7) /* Fifo Error */ +#define SC16IS7XX_LSR_DR_BIT BIT(0) /* Receiver data ready */ +#define SC16IS7XX_LSR_OE_BIT BIT(1) /* Overrun Error */ +#define SC16IS7XX_LSR_PE_BIT BIT(2) /* Parity Error */ +#define SC16IS7XX_LSR_FE_BIT BIT(3) /* Frame Error */ +#define SC16IS7XX_LSR_BI_BIT BIT(4) /* Break Interrupt */ +#define SC16IS7XX_LSR_BRK_ERROR_MASK \ + (SC16IS7XX_LSR_OE_BIT | \ + SC16IS7XX_LSR_PE_BIT | \ + SC16IS7XX_LSR_FE_BIT | \ + SC16IS7XX_LSR_BI_BIT) + +#define SC16IS7XX_LSR_THRE_BIT BIT(5) /* TX holding register empty */ +#define SC16IS7XX_LSR_TEMT_BIT BIT(6) /* Transmitter empty */ +#define SC16IS7XX_LSR_FIFOE_BIT BIT(7) /* Fifo Error */ /* MSR register bits */ -#define SC16IS7XX_MSR_DCTS_BIT (1 << 0) /* Delta CTS Clear To Send */ -#define SC16IS7XX_MSR_DDSR_BIT (1 << 1) /* Delta DSR Data Set Ready - * or (IO4) - * - only on 75x/76x - */ -#define SC16IS7XX_MSR_DRI_BIT (1 << 2) /* Delta RI Ring Indicator - * or (IO7) - * - only on 75x/76x - */ -#define SC16IS7XX_MSR_DCD_BIT (1 << 3) /* Delta CD Carrier Detect - * or (IO6) - * - only on 75x/76x - */ -#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */ -#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4) +#define SC16IS7XX_MSR_DCTS_BIT BIT(0) /* Delta CTS Clear To Send */ +#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready or (IO4) * - only on 75x/76x */ -#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7) +#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator or (IO7) * - only on 75x/76x */ -#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6) +#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect or (IO6) * - only on 75x/76x */ -#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */ +#define SC16IS7XX_MSR_CTS_BIT BIT(4) /* CTS */ +#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4) - only on 75x/76x */ +#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7) - only on 75x/76x */ +#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6) - only on 75x/76x */ /* * TCR register bits @@ -223,7 +206,7 @@ * trigger levels. Trigger levels from 4 characters to 60 characters are * available with a granularity of four. * - * When the trigger level setting in TLR is zero, the SC16IS740/750/760 uses the + * When the trigger level setting in TLR is zero, the SC16IS74x/75x/76x uses the * trigger level setting defined in FCR. If TLR has non-zero trigger level value * the trigger level defined in FCR is discarded. This applies to both transmit * FIFO and receive FIFO trigger level setting. @@ -234,157 +217,141 @@ #define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0) #define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4) -/* IOControl register bits (Only 750/760) */ -#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */ -#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */ -#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */ +/* IOControl register bits (Only 75x/76x) */ +#define SC16IS7XX_IOCONTROL_LATCH_BIT BIT(0) /* Enable input latching */ +#define SC16IS7XX_IOCONTROL_MODEM_A_BIT BIT(1) /* Enable GPIO[7:4] as modem A pins */ +#define SC16IS7XX_IOCONTROL_MODEM_B_BIT BIT(2) /* Enable GPIO[3:0] as modem B pins */ +#define SC16IS7XX_IOCONTROL_SRESET_BIT BIT(3) /* Software Reset */ /* EFCR register bits */ -#define SC16IS7XX_EFCR_9BIT_MODE_BIT (1 << 0) /* Enable 9-bit or Multidrop - * mode (RS485) */ -#define SC16IS7XX_EFCR_RXDISABLE_BIT (1 << 1) /* Disable receiver */ -#define SC16IS7XX_EFCR_TXDISABLE_BIT (1 << 2) /* Disable transmitter */ -#define SC16IS7XX_EFCR_AUTO_RS485_BIT (1 << 4) /* Auto RS485 RTS direction */ -#define SC16IS7XX_EFCR_RTS_INVERT_BIT (1 << 5) /* RTS output inversion */ -#define SC16IS7XX_EFCR_IRDA_MODE_BIT (1 << 7) /* IrDA mode - * 0 = rate upto 115.2 kbit/s - * - Only 750/760 - * 1 = rate upto 1.152 Mbit/s - * - Only 760 +#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop mode (RS485) */ +#define SC16IS7XX_EFCR_RXDISABLE_BIT BIT(1) /* Disable receiver */ +#define SC16IS7XX_EFCR_TXDISABLE_BIT BIT(2) /* Disable transmitter */ +#define SC16IS7XX_EFCR_AUTO_RS485_BIT BIT(4) /* Auto RS485 RTS direction */ +#define SC16IS7XX_EFCR_RTS_INVERT_BIT BIT(5) /* RTS output inversion */ +#define SC16IS7XX_EFCR_IRDA_MODE_BIT BIT(7) /* IrDA mode + * 0 = rate up to 115.2 kbit/s - Only 75x/76x + * 1 = rate up to 1.152 Mbit/s - Only 76x */ /* EFR register bits */ -#define SC16IS7XX_EFR_AUTORTS_BIT (1 << 6) /* Auto RTS flow ctrl enable */ -#define SC16IS7XX_EFR_AUTOCTS_BIT (1 << 7) /* Auto CTS flow ctrl enable */ -#define SC16IS7XX_EFR_XOFF2_DETECT_BIT (1 << 5) /* Enable Xoff2 detection */ -#define SC16IS7XX_EFR_ENABLE_BIT (1 << 4) /* Enable enhanced functions - * and writing to IER[7:4], - * FCR[5:4], MCR[7:5] +#define SC16IS7XX_EFR_AUTORTS_BIT BIT(6) /* Auto RTS flow ctrl enable */ +#define SC16IS7XX_EFR_AUTOCTS_BIT BIT(7) /* Auto CTS flow ctrl enable */ +#define SC16IS7XX_EFR_XOFF2_DETECT_BIT BIT(5) /* Enable Xoff2 detection */ +#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions and writing to + * IER[7:4], FCR[5:4], MCR[7:5] */ -#define SC16IS7XX_EFR_SWFLOW3_BIT (1 << 3) /* SWFLOW bit 3 */ -#define SC16IS7XX_EFR_SWFLOW2_BIT (1 << 2) /* SWFLOW bit 2 - * +#define SC16IS7XX_EFR_SWFLOW3_BIT BIT(3) +#define SC16IS7XX_EFR_SWFLOW2_BIT BIT(2) + /* * SWFLOW bits 3 & 2 table: - * 00 -> no transmitter flow - * control - * 01 -> transmitter generates - * XON2 and XOFF2 - * 10 -> transmitter generates - * XON1 and XOFF1 - * 11 -> transmitter generates - * XON1, XON2, XOFF1 and - * XOFF2 + * 00 -> no transmitter flow control + * 01 -> transmitter generates XON2 and XOFF2 + * 10 -> transmitter generates XON1 and XOFF1 + * 11 -> transmitter generates XON1, XON2, + * XOFF1 and XOFF2 */ -#define SC16IS7XX_EFR_SWFLOW1_BIT (1 << 1) /* SWFLOW bit 2 */ -#define SC16IS7XX_EFR_SWFLOW0_BIT (1 << 0) /* SWFLOW bit 3 - * - * SWFLOW bits 3 & 2 table: - * 00 -> no received flow - * control - * 01 -> receiver compares - * XON2 and XOFF2 - * 10 -> receiver compares - * XON1 and XOFF1 - * 11 -> receiver compares - * XON1, XON2, XOFF1 and - * XOFF2 +#define SC16IS7XX_EFR_SWFLOW1_BIT BIT(1) +#define SC16IS7XX_EFR_SWFLOW0_BIT BIT(0) + /* + * SWFLOW bits 1 & 0 table: + * 00 -> no received flow control + * 01 -> receiver compares XON2 and XOFF2 + * 10 -> receiver compares XON1 and XOFF1 + * 11 -> receiver compares XON1, XON2, + * XOFF1 and XOFF2 */ +#define SC16IS7XX_EFR_FLOWCTRL_BITS (SC16IS7XX_EFR_AUTORTS_BIT | \ + SC16IS7XX_EFR_AUTOCTS_BIT | \ + SC16IS7XX_EFR_XOFF2_DETECT_BIT | \ + SC16IS7XX_EFR_SWFLOW3_BIT | \ + SC16IS7XX_EFR_SWFLOW2_BIT | \ + SC16IS7XX_EFR_SWFLOW1_BIT | \ + SC16IS7XX_EFR_SWFLOW0_BIT) + /* Misc definitions */ #define SC16IS7XX_FIFO_SIZE (64) -#define SC16IS7XX_REG_SHIFT 2 +#define SC16IS7XX_GPIOS_PER_BANK 4 -struct sc16is7xx_devtype { - char name[10]; - int nr_gpio; - int nr_uart; -}; - -#define SC16IS7XX_RECONF_MD (1 << 0) -#define SC16IS7XX_RECONF_IER (1 << 1) -#define SC16IS7XX_RECONF_RS485 (1 << 2) +#define SC16IS7XX_POLL_PERIOD_MS 10 +#define SC16IS7XX_RECONF_MD BIT(0) +#define SC16IS7XX_RECONF_IER BIT(1) +#define SC16IS7XX_RECONF_RS485 BIT(2) struct sc16is7xx_one_config { unsigned int flags; - u8 ier_clear; + u8 ier_mask; + u8 ier_val; }; struct sc16is7xx_one { struct uart_port port; - u8 line; + struct regmap *regmap; + struct mutex lock; /* For registers sharing same address space. */ struct kthread_work tx_work; struct kthread_work reg_work; + struct kthread_delayed_work ms_work; struct sc16is7xx_one_config config; + unsigned char buf[SC16IS7XX_FIFO_SIZE]; /* Rx buffer. */ + unsigned int old_mctrl; + u8 old_lcr; /* Value before EFR access. */ bool irda_mode; }; struct sc16is7xx_port { const struct sc16is7xx_devtype *devtype; - struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; + unsigned long gpio_valid_mask; #endif - unsigned char buf[SC16IS7XX_FIFO_SIZE]; + u8 mctrl_mask; struct kthread_worker kworker; struct task_struct *kworker_task; - struct mutex efr_lock; + struct kthread_delayed_work poll_work; + bool polling; struct sc16is7xx_one p[]; }; -static unsigned long sc16is7xx_lines; +static DEFINE_IDA(sc16is7xx_lines); static struct uart_driver sc16is7xx_uart = { .owner = THIS_MODULE, + .driver_name = KBUILD_MODNAME, .dev_name = "ttySC", .nr = SC16IS7XX_MAX_DEVS, }; -#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) -#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) - -static int sc16is7xx_line(struct uart_port *port) -{ - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - - return one->line; -} +#define to_sc16is7xx_one(p) container_of((p), struct sc16is7xx_one, port) static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); unsigned int val = 0; - const u8 line = sc16is7xx_line(port); - regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, &val); + regmap_read(one->regmap, reg, &val); return val; } static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); - regmap_write(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, val); + regmap_write(one->regmap, reg, val); } -static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen) +static void sc16is7xx_fifo_read(struct uart_port *port, u8 *rxbuf, unsigned int rxlen) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); - u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line; + struct sc16is7xx_one *one = to_sc16is7xx_one(port); - regcache_cache_bypass(s->regmap, true); - regmap_raw_read(s->regmap, addr, s->buf, rxlen); - regcache_cache_bypass(s->regmap, false); + regmap_noinc_read(one->regmap, SC16IS7XX_RHR_REG, rxbuf, rxlen); } -static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) +static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); - u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line; + struct sc16is7xx_one *one = to_sc16is7xx_one(port); /* * Don't send zero-length data, at least on SPI it confuses the chip @@ -393,179 +360,230 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) if (unlikely(!to_send)) return; - regcache_cache_bypass(s->regmap, true); - regmap_raw_write(s->regmap, addr, s->buf, to_send); - regcache_cache_bypass(s->regmap, false); + regmap_noinc_write(one->regmap, SC16IS7XX_THR_REG, txbuf, to_send); } static void sc16is7xx_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + regmap_update_bits(one->regmap, reg, mask, val); +} + +static void sc16is7xx_power(struct uart_port *port, int on) +{ + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_IER_SLEEP_BIT, + on ? 0 : SC16IS7XX_IER_SLEEP_BIT); +} + +/* + * In an amazing feat of design, the enhanced register set shares the + * addresses 0x02 and 0x04-0x07 with the general register set. + * The special register set also shares the addresses 0x00-0x01 with the + * general register set. + * + * Access to the enhanced or special register set is enabled by writing a magic + * value to the Line Control Register (LCR). When enhanced register set access + * is enabled, for example, any interrupt firing during this time will see the + * EFR where it expects the IIR to be, leading to + * "Unexpected interrupt" messages. + * + * Prevent this possibility by claiming a mutex when access to the enhanced + * or special register set is enabled, and claiming the same mutex from within + * the interrupt handler. This is similar to disabling the interrupt, but that + * doesn't work because the bulk of the interrupt processing is run as a + * workqueue job in thread context. + */ +static void sc16is7xx_regs_lock(struct uart_port *port, u8 register_set) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + mutex_lock(&one->lock); + + /* Backup content of LCR. */ + one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + + /* Enable access to the desired register set */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, register_set); + + /* Disable cache updates when writing to non-general registers */ + regcache_cache_bypass(one->regmap, true); +} + +static void sc16is7xx_regs_unlock(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + /* Re-enable cache updates when writing to general registers */ + regcache_cache_bypass(one->regmap, false); + + /* Restore original content of LCR */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, one->old_lcr); + + mutex_unlock(&one->lock); +} + +static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) +{ struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); - regmap_update_bits(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, - mask, val); + lockdep_assert_held_once(&port->lock); + + one->config.flags |= SC16IS7XX_RECONF_IER; + one->config.ier_mask |= bit; + one->config.ier_val &= ~bit; + kthread_queue_work(&s->kworker, &one->reg_work); } -static int sc16is7xx_alloc_line(void) +static void sc16is7xx_ier_set(struct uart_port *port, u8 bit) { - int i; + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); - BUILD_BUG_ON(SC16IS7XX_MAX_DEVS > BITS_PER_LONG); + lockdep_assert_held_once(&port->lock); - for (i = 0; i < SC16IS7XX_MAX_DEVS; i++) - if (!test_and_set_bit(i, &sc16is7xx_lines)) - break; + one->config.flags |= SC16IS7XX_RECONF_IER; + one->config.ier_mask |= bit; + one->config.ier_val |= bit; + kthread_queue_work(&s->kworker, &one->reg_work); +} - return i; +static void sc16is7xx_stop_tx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT); } -static void sc16is7xx_power(struct uart_port *port, int on) +static void sc16is7xx_stop_rx(struct uart_port *port) { - sc16is7xx_port_update(port, SC16IS7XX_IER_REG, - SC16IS7XX_IER_SLEEP_BIT, - on ? 0 : SC16IS7XX_IER_SLEEP_BIT); + sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); } -static const struct sc16is7xx_devtype sc16is74x_devtype = { +const struct sc16is7xx_devtype sc16is74x_devtype = { .name = "SC16IS74X", .nr_gpio = 0, .nr_uart = 1, }; +EXPORT_SYMBOL_GPL(sc16is74x_devtype); -static const struct sc16is7xx_devtype sc16is750_devtype = { +const struct sc16is7xx_devtype sc16is750_devtype = { .name = "SC16IS750", .nr_gpio = 8, .nr_uart = 1, }; +EXPORT_SYMBOL_GPL(sc16is750_devtype); -static const struct sc16is7xx_devtype sc16is752_devtype = { +const struct sc16is7xx_devtype sc16is752_devtype = { .name = "SC16IS752", .nr_gpio = 8, .nr_uart = 2, }; +EXPORT_SYMBOL_GPL(sc16is752_devtype); -static const struct sc16is7xx_devtype sc16is760_devtype = { +const struct sc16is7xx_devtype sc16is760_devtype = { .name = "SC16IS760", .nr_gpio = 8, .nr_uart = 1, }; +EXPORT_SYMBOL_GPL(sc16is760_devtype); -static const struct sc16is7xx_devtype sc16is762_devtype = { +const struct sc16is7xx_devtype sc16is762_devtype = { .name = "SC16IS762", .nr_gpio = 8, .nr_uart = 2, }; +EXPORT_SYMBOL_GPL(sc16is762_devtype); static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) { - switch (reg >> SC16IS7XX_REG_SHIFT) { - case SC16IS7XX_RHR_REG: - case SC16IS7XX_IIR_REG: - case SC16IS7XX_LSR_REG: - case SC16IS7XX_MSR_REG: + switch (reg) { + case SC16IS7XX_RHR_REG: /* Shared address space with THR & DLL */ + case SC16IS7XX_IIR_REG: /* Shared address space with FCR & EFR */ + case SC16IS7XX_LSR_REG: /* Shared address space with XON2 */ + case SC16IS7XX_MSR_REG: /* Shared address space with TCR & XOFF1 */ + case SC16IS7XX_SPR_REG: /* Shared address space with TLR & XOFF2 */ case SC16IS7XX_TXLVL_REG: case SC16IS7XX_RXLVL_REG: case SC16IS7XX_IOSTATE_REG: + case SC16IS7XX_IOCONTROL_REG: return true; default: - break; + return false; } - - return false; } static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg) { - switch (reg >> SC16IS7XX_REG_SHIFT) { + switch (reg) { case SC16IS7XX_RHR_REG: return true; default: - break; + return false; } +} - return false; +static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) +{ + return reg == SC16IS7XX_RHR_REG; } +/* + * Configure programmable baud rate generator (divisor) according to the + * desired baud rate. + * + * From the datasheet, the divisor is computed according to: + * + * XTAL1 input frequency + * ----------------------- + * prescaler + * divisor = --------------------------- + * baud-rate x sampling-rate + */ static int sc16is7xx_set_baud(struct uart_port *port, int baud) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - u8 lcr; - u8 prescaler = 0; + unsigned int prescaler = 1; unsigned long clk = port->uartclk, div = clk / 16 / baud; - if (div > 0xffff) { - prescaler = SC16IS7XX_MCR_CLKSEL_BIT; - div /= 4; + if (div >= BIT(16)) { + prescaler = 4; + div /= prescaler; } - /* In an amazing feat of design, the Enhanced Features Register shares - * the address of the Interrupt Identification Register, and is - * switched in by writing a magic value (0xbf) to the Line Control - * Register. Any interrupt firing during this time will see the EFR - * where it expects the IIR to be, leading to "Unexpected interrupt" - * messages. - * - * Prevent this possibility by claiming a mutex while accessing the - * EFR, and claiming the same mutex from within the interrupt handler. - * This is similar to disabling the interrupt, but that doesn't work - * because the bulk of the interrupt processing is run as a workqueue - * job in thread context. - */ - mutex_lock(&s->efr_lock); - - lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); - - /* Open the LCR divisors for configuration */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_B); - - /* Enable enhanced features */ - regcache_cache_bypass(s->regmap, true); - sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, - SC16IS7XX_EFR_ENABLE_BIT); - regcache_cache_bypass(s->regmap, false); - - /* Put LCR back to the normal mode */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); - - mutex_unlock(&s->efr_lock); - + /* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_CLKSEL_BIT, - prescaler); + prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT); - /* Open the LCR divisors for configuration */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_A); + /* Access special register set (DLL/DLH) */ + sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_SPECIAL); /* Write the new divisor */ - regcache_cache_bypass(s->regmap, true); sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); - regcache_cache_bypass(s->regmap, false); - /* Put LCR back to the normal mode */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + /* Restore access to general register set */ + sc16is7xx_regs_unlock(port); - return DIV_ROUND_CLOSEST(clk / 16, div); + return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div); } static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, unsigned int iir) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - unsigned int lsr = 0, ch, flag, bytes_read, i; - bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false; + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + unsigned int lsr = 0, bytes_read, i; + bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC); + u8 ch, flag; - if (unlikely(rxlen >= sizeof(s->buf))) { + if (unlikely(rxlen >= sizeof(one->buf))) { dev_warn_ratelimited(port->dev, "ttySC%i: Possible RX FIFO overrun: %d\n", port->line, rxlen); port->icount.buf_overrun++; /* Ensure sanity of RX level */ - rxlen = sizeof(s->buf); + rxlen = sizeof(one->buf); } while (rxlen) { @@ -578,10 +596,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, lsr = 0; if (read_lsr) { - s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); + one->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); bytes_read = 1; } else { - sc16is7xx_fifo_read(port, rxlen); + sc16is7xx_fifo_read(port, one->buf, rxlen); bytes_read = rxlen; } @@ -614,7 +632,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, } for (i = 0; i < bytes_read; ++i) { - ch = s->buf[i]; + ch = one->buf[i]; if (uart_handle_sysrq_char(port, ch)) continue; @@ -632,9 +650,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, static void sc16is7xx_handle_tx(struct uart_port *port) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct circ_buf *xmit = &port->state->xmit; - unsigned int txlen, to_send, i; + struct tty_port *tport = &port->state->port; + unsigned long flags; + unsigned int txlen; + unsigned char *tail; if (unlikely(port->x_char)) { sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); @@ -643,102 +662,172 @@ static void sc16is7xx_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { + uart_port_lock_irqsave(port, &flags); + sc16is7xx_stop_tx(port); + uart_port_unlock_irqrestore(port, flags); return; + } - /* Get length of data pending in circular buffer */ - to_send = uart_circ_chars_pending(xmit); - if (likely(to_send)) { - /* Limit to size of TX FIFO */ - txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); - if (txlen > SC16IS7XX_FIFO_SIZE) { - dev_err_ratelimited(port->dev, - "chip reports %d free bytes in TX fifo, but it only has %d", - txlen, SC16IS7XX_FIFO_SIZE); - txlen = 0; - } - to_send = (to_send > txlen) ? txlen : to_send; + /* Limit to space available in TX FIFO */ + txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + if (txlen > SC16IS7XX_FIFO_SIZE) { + dev_err_ratelimited(port->dev, + "chip reports %d free bytes in TX fifo, but it only has %d", + txlen, SC16IS7XX_FIFO_SIZE); + txlen = 0; + } - /* Add data to send */ - port->icount.tx += to_send; + txlen = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen); + sc16is7xx_fifo_write(port, tail, txlen); + uart_xmit_advance(port, txlen); - /* Convert to linear buffer */ - for (i = 0; i < to_send; ++i) { - s->buf[i] = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } + uart_port_lock_irqsave(port, &flags); + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); - sc16is7xx_fifo_write(port, to_send); - } + if (kfifo_is_empty(&tport->xmit_fifo)) + sc16is7xx_stop_tx(port); + else + sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); + uart_port_unlock_irqrestore(port, flags); +} - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); +static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port) +{ + u8 msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG); + unsigned int mctrl = 0; + + mctrl |= (msr & SC16IS7XX_MSR_CTS_BIT) ? TIOCM_CTS : 0; + mctrl |= (msr & SC16IS7XX_MSR_DSR_BIT) ? TIOCM_DSR : 0; + mctrl |= (msr & SC16IS7XX_MSR_CD_BIT) ? TIOCM_CAR : 0; + mctrl |= (msr & SC16IS7XX_MSR_RI_BIT) ? TIOCM_RNG : 0; + return mctrl; +} + +static void sc16is7xx_update_mlines(struct sc16is7xx_one *one) +{ + struct uart_port *port = &one->port; + unsigned long flags; + unsigned int status, changed; + + /* Lock required as MSR address is shared with TCR and XOFF1. */ + lockdep_assert_held_once(&one->lock); + + status = sc16is7xx_get_hwmctrl(port); + changed = status ^ one->old_mctrl; + + if (changed == 0) + return; + + one->old_mctrl = status; + + uart_port_lock_irqsave(port, &flags); + if ((changed & TIOCM_RNG) && (status & TIOCM_RNG)) + port->icount.rng++; + if (changed & TIOCM_DSR) + port->icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(port, status & TIOCM_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + uart_port_unlock_irqrestore(port, flags); } static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) { + unsigned int iir, rxlen; struct uart_port *port = &s->p[portno].port; + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + guard(mutex)(&one->lock); + + iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); + if (iir & SC16IS7XX_IIR_NO_INT_BIT) + return false; + + iir &= SC16IS7XX_IIR_ID_MASK; + + switch (iir) { + case SC16IS7XX_IIR_RDI_SRC: + case SC16IS7XX_IIR_RLSE_SRC: + case SC16IS7XX_IIR_RTOI_SRC: + case SC16IS7XX_IIR_XOFFI_SRC: + rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); + + /* + * There is a silicon bug that makes the chip report a + * time-out interrupt but no data in the FIFO. This is + * described in errata section 18.1.4. + * + * When this happens, read one byte from the FIFO to + * clear the interrupt. + */ + if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen) + rxlen = 1; + + if (rxlen) + sc16is7xx_handle_rx(port, rxlen, iir); + break; + /* CTSRTS interrupt comes only when CTS goes inactive */ + case SC16IS7XX_IIR_CTSRTS_SRC: + case SC16IS7XX_IIR_MSI_SRC: + sc16is7xx_update_mlines(one); + break; + case SC16IS7XX_IIR_THRI_SRC: + sc16is7xx_handle_tx(port); + break; + default: + dev_err_ratelimited(port->dev, + "ttySC%i: Unexpected interrupt: %x", + port->line, iir); + break; + } - do { - unsigned int iir, rxlen; - - iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); - if (iir & SC16IS7XX_IIR_NO_INT_BIT) - return false; - - iir &= SC16IS7XX_IIR_ID_MASK; - - switch (iir) { - case SC16IS7XX_IIR_RDI_SRC: - case SC16IS7XX_IIR_RLSE_SRC: - case SC16IS7XX_IIR_RTOI_SRC: - case SC16IS7XX_IIR_XOFFI_SRC: - rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); - if (rxlen) - sc16is7xx_handle_rx(port, rxlen, iir); - break; - case SC16IS7XX_IIR_THRI_SRC: - sc16is7xx_handle_tx(port); - break; - default: - dev_err_ratelimited(port->dev, - "ttySC%i: Unexpected interrupt: %x", - port->line, iir); - break; - } - } while (0); return true; } static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) { - struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; - - mutex_lock(&s->efr_lock); + struct sc16is7xx_port *s = dev_id; + bool keep_polling; - while (1) { - bool keep_polling = false; + do { int i; + keep_polling = false; + for (i = 0; i < s->devtype->nr_uart; ++i) keep_polling |= sc16is7xx_port_irq(s, i); - if (!keep_polling) - break; - } - - mutex_unlock(&s->efr_lock); + } while (keep_polling); return IRQ_HANDLED; } +static void sc16is7xx_poll_proc(struct kthread_work *ws) +{ + struct sc16is7xx_port *s = container_of(ws, struct sc16is7xx_port, poll_work.work); + + /* Reuse standard IRQ handler. Interrupt ID is unused in this context. */ + sc16is7xx_irq(0, s); + + /* Setup delay based on SC16IS7XX_POLL_PERIOD_MS */ + kthread_queue_delayed_work(&s->kworker, &s->poll_work, + msecs_to_jiffies(SC16IS7XX_POLL_PERIOD_MS)); +} + static void sc16is7xx_tx_proc(struct kthread_work *ws) { - struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); + struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, tx_work); + struct uart_port *port = &one->port; if ((port->rs485.flags & SER_RS485_ENABLED) && (port->rs485.delay_rts_before_send > 0)) msleep(port->rs485.delay_rts_before_send); + guard(mutex)(&one->lock); sc16is7xx_handle_tx(port); } @@ -750,77 +839,108 @@ static void sc16is7xx_reconf_rs485(struct uart_port *port) struct serial_rs485 *rs485 = &port->rs485; unsigned long irqflags; - spin_lock_irqsave(&port->lock, irqflags); + uart_port_lock_irqsave(port, &irqflags); if (rs485->flags & SER_RS485_ENABLED) { efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; if (rs485->flags & SER_RS485_RTS_AFTER_SEND) efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; } - spin_unlock_irqrestore(&port->lock, irqflags); + uart_port_unlock_irqrestore(port, irqflags); sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); } static void sc16is7xx_reg_proc(struct kthread_work *ws) { - struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work); + struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, reg_work); struct sc16is7xx_one_config config; unsigned long irqflags; - spin_lock_irqsave(&one->port.lock, irqflags); + uart_port_lock_irqsave(&one->port, &irqflags); config = one->config; memset(&one->config, 0, sizeof(one->config)); - spin_unlock_irqrestore(&one->port.lock, irqflags); + uart_port_unlock_irqrestore(&one->port, irqflags); if (config.flags & SC16IS7XX_RECONF_MD) { + u8 mcr = 0; + + /* Device ignores RTS setting when hardware flow is enabled */ + if (one->port.mctrl & TIOCM_RTS) + mcr |= SC16IS7XX_MCR_RTS_BIT; + + if (one->port.mctrl & TIOCM_DTR) + mcr |= SC16IS7XX_MCR_DTR_BIT; + + if (one->port.mctrl & TIOCM_LOOP) + mcr |= SC16IS7XX_MCR_LOOP_BIT; sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_RTS_BIT | + SC16IS7XX_MCR_DTR_BIT | SC16IS7XX_MCR_LOOP_BIT, - (one->port.mctrl & TIOCM_LOOP) ? - SC16IS7XX_MCR_LOOP_BIT : 0); - sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, - SC16IS7XX_MCR_RTS_BIT, - (one->port.mctrl & TIOCM_RTS) ? - SC16IS7XX_MCR_RTS_BIT : 0); - sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, - SC16IS7XX_MCR_DTR_BIT, - (one->port.mctrl & TIOCM_DTR) ? - SC16IS7XX_MCR_DTR_BIT : 0); + mcr); } + if (config.flags & SC16IS7XX_RECONF_IER) sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG, - config.ier_clear, 0); + config.ier_mask, config.ier_val); if (config.flags & SC16IS7XX_RECONF_RS485) sc16is7xx_reconf_rs485(&one->port); } -static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) +static void sc16is7xx_ms_proc(struct kthread_work *ws) { + struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, ms_work.work); + struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + + if (one->port.state) { + scoped_guard(mutex, &one->lock) + sc16is7xx_update_mlines(one); + + kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ); + } +} + +static void sc16is7xx_enable_ms(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port); struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - one->config.flags |= SC16IS7XX_RECONF_IER; - one->config.ier_clear |= bit; - kthread_queue_work(&s->kworker, &one->reg_work); + lockdep_assert_held_once(&port->lock); + + kthread_queue_delayed_work(&s->kworker, &one->ms_work, 0); } -static void sc16is7xx_stop_tx(struct uart_port *port) +static void sc16is7xx_start_tx(struct uart_port *port) { - sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT); + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + kthread_queue_work(&s->kworker, &one->tx_work); } -static void sc16is7xx_stop_rx(struct uart_port *port) +static void sc16is7xx_throttle(struct uart_port *port) { + unsigned long flags; + + /* + * Hardware flow control is enabled and thus the device ignores RTS + * value set in MCR register. Stop reading data from RX FIFO so the + * AutoRTS feature will de-activate RTS output. + */ + uart_port_lock_irqsave(port, &flags); sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); + uart_port_unlock_irqrestore(port, flags); } -static void sc16is7xx_start_tx(struct uart_port *port) +static void sc16is7xx_unthrottle(struct uart_port *port) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + unsigned long flags; - kthread_queue_work(&s->kworker, &one->tx_work); + uart_port_lock_irqsave(port, &flags); + sc16is7xx_ier_set(port, SC16IS7XX_IER_RDI_BIT); + uart_port_unlock_irqrestore(port, flags); } static unsigned int sc16is7xx_tx_empty(struct uart_port *port) @@ -834,16 +954,16 @@ static unsigned int sc16is7xx_tx_empty(struct uart_port *port) static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) { - /* DCD and DSR are not wired and CTS/RTS is handled automatically - * so just indicate DSR and CAR asserted - */ - return TIOCM_DSR | TIOCM_CAR; + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + /* Called with port lock taken so we can only return cached value */ + return one->old_mctrl; } static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); one->config.flags |= SC16IS7XX_RECONF_MD; kthread_queue_work(&s->kworker, &one->reg_work); @@ -858,11 +978,14 @@ static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) static void sc16is7xx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); unsigned int lcr, flow = 0; int baud; + unsigned long flags; + + kthread_cancel_delayed_work_sync(&one->ms_work); /* Mask termios capabilities we don't support */ termios->c_cflag &= ~CMSPAR; @@ -914,31 +1037,28 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; - /* As above, claim the mutex while accessing the EFR. */ - mutex_lock(&s->efr_lock); - - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_B); - /* Configure flow control */ - regcache_cache_bypass(s->regmap, true); - sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); - sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); - if (termios->c_cflag & CRTSCTS) + port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); + if (termios->c_cflag & CRTSCTS) { flow |= SC16IS7XX_EFR_AUTOCTS_BIT | SC16IS7XX_EFR_AUTORTS_BIT; + port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; + } if (termios->c_iflag & IXON) flow |= SC16IS7XX_EFR_SWFLOW3_BIT; if (termios->c_iflag & IXOFF) flow |= SC16IS7XX_EFR_SWFLOW1_BIT; - sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); - regcache_cache_bypass(s->regmap, false); - /* Update LCR register */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); - mutex_unlock(&s->efr_lock); + /* Update EFR registers */ + sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED); + sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); + sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); + sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_FLOWCTRL_BITS, flow); + sc16is7xx_regs_unlock(port); /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, @@ -948,27 +1068,24 @@ static void sc16is7xx_set_termios(struct uart_port *port, /* Setup baudrate generator */ baud = sc16is7xx_set_baud(port, baud); + uart_port_lock_irqsave(port, &flags); + /* Update timeout according to new baud rate */ uart_update_timeout(port, termios->c_cflag, baud); + + if (UART_ENABLE_MS(port, termios->c_cflag)) + sc16is7xx_enable_ms(port); + + uart_port_unlock_irqrestore(port, flags); } -static int sc16is7xx_config_rs485(struct uart_port *port, +static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); if (rs485->flags & SER_RS485_ENABLED) { - bool rts_during_rx, rts_during_tx; - - rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND; - rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND; - - if (rts_during_rx == rts_during_tx) - dev_err(port->dev, - "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n", - rts_during_tx, rts_during_rx); - /* * RTS signal is handled by HW, it's timing can't be influenced. * However, it's sometimes useful to delay TX even without RTS @@ -978,7 +1095,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port, return -EINVAL; } - port->rs485 = *rs485; one->config.flags |= SC16IS7XX_RECONF_RS485; kthread_queue_work(&s->kworker, &one->reg_work); @@ -987,29 +1103,20 @@ static int sc16is7xx_config_rs485(struct uart_port *port, static int sc16is7xx_startup(struct uart_port *port) { - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val; + unsigned long flags; sc16is7xx_power(port, 1); - /* Reset FIFOs*/ + /* Reset FIFOs */ val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT; sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val); udelay(5); sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, SC16IS7XX_FCR_FIFO_BIT); - /* Enable EFR */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_B); - - regcache_cache_bypass(s->regmap, true); - - /* Enable write access to enhanced features and internal clock div */ - sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, - SC16IS7XX_EFR_ENABLE_BIT); - /* Enable TCR/TLR */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, @@ -1021,7 +1128,8 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_TCR_RX_RESUME(24) | SC16IS7XX_TCR_RX_HALT(48)); - regcache_cache_bypass(s->regmap, false); + /* Disable TCR/TLR access */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, 0); /* Now, initialize the UART */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); @@ -1030,8 +1138,7 @@ static int sc16is7xx_startup(struct uart_port *port) /* This bit must be written with LCR[7] = 0 */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_IRDA_BIT, - one->irda_mode ? - SC16IS7XX_MCR_IRDA_BIT : 0); + one->irda_mode ? SC16IS7XX_MCR_IRDA_BIT : 0); /* Enable the Rx and Tx FIFO */ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, @@ -1039,16 +1146,29 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_EFCR_TXDISABLE_BIT, 0); - /* Enable RX, TX interrupts */ - val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT; + /* Enable RX, CTS change and modem lines interrupts */ + val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_CTSI_BIT | + SC16IS7XX_IER_MSI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + /* Enable modem status polling */ + uart_port_lock_irqsave(port, &flags); + sc16is7xx_enable_ms(port); + uart_port_unlock_irqrestore(port, flags); + + if (s->polling) + kthread_queue_delayed_work(&s->kworker, &s->poll_work, + msecs_to_jiffies(SC16IS7XX_POLL_PERIOD_MS)); + return 0; } static void sc16is7xx_shutdown(struct uart_port *port) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port); + + kthread_cancel_delayed_work_sync(&one->ms_work); /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); @@ -1061,6 +1181,9 @@ static void sc16is7xx_shutdown(struct uart_port *port) sc16is7xx_power(port, 0); + if (s->polling) + kthread_cancel_delayed_work_sync(&s->poll_work); + kthread_flush_worker(&s->kworker); } @@ -1111,7 +1234,10 @@ static const struct uart_ops sc16is7xx_ops = { .get_mctrl = sc16is7xx_get_mctrl, .stop_tx = sc16is7xx_stop_tx, .start_tx = sc16is7xx_start_tx, + .throttle = sc16is7xx_throttle, + .unthrottle = sc16is7xx_unthrottle, .stop_rx = sc16is7xx_stop_rx, + .enable_ms = sc16is7xx_enable_ms, .break_ctl = sc16is7xx_break_ctl, .startup = sc16is7xx_startup, .shutdown = sc16is7xx_shutdown, @@ -1136,13 +1262,16 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(val & BIT(offset)); } -static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset, + int val) { struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), val ? BIT(offset) : 0); + + return 0; } static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, @@ -1167,50 +1296,285 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, state |= BIT(offset); else state &= ~BIT(offset); - sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state); + + /* + * If we write IOSTATE first, and then IODIR, the output value is not + * transferred to the corresponding I/O pin. + * The datasheet states that each register bit will be transferred to + * the corresponding I/O pin programmed as output when writing to + * IOSTATE. Therefore, configure direction first with IODIR, and then + * set value after with IOSTATE. + */ sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), BIT(offset)); + sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state); + + return 0; +} + +static int sc16is7xx_gpio_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct sc16is7xx_port *s = gpiochip_get_data(chip); + + *valid_mask = s->gpio_valid_mask; return 0; } + +static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s) +{ + struct device *dev = s->p[0].port.dev; + + if (!s->devtype->nr_gpio) + return 0; + + switch (s->mctrl_mask) { + case 0: + s->gpio_valid_mask = GENMASK(7, 0); + break; + case SC16IS7XX_IOCONTROL_MODEM_A_BIT: + s->gpio_valid_mask = GENMASK(3, 0); + break; + case SC16IS7XX_IOCONTROL_MODEM_B_BIT: + s->gpio_valid_mask = GENMASK(7, 4); + break; + default: + break; + } + + if (s->gpio_valid_mask == 0) + return 0; + + s->gpio.owner = THIS_MODULE; + s->gpio.parent = dev; + s->gpio.label = dev_name(dev); + s->gpio.init_valid_mask = sc16is7xx_gpio_init_valid_mask; + s->gpio.direction_input = sc16is7xx_gpio_direction_input; + s->gpio.get = sc16is7xx_gpio_get; + s->gpio.direction_output = sc16is7xx_gpio_direction_output; + s->gpio.set = sc16is7xx_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = s->devtype->nr_gpio; + s->gpio.can_sleep = 1; + + return gpiochip_add_data(&s->gpio, s); +} #endif -static int sc16is7xx_probe(struct device *dev, - const struct sc16is7xx_devtype *devtype, - struct regmap *regmap, int irq) +static void sc16is7xx_setup_irda_ports(struct sc16is7xx_port *s) +{ + int i; + int ret; + int count; + u32 irda_port[SC16IS7XX_MAX_PORTS]; + struct device *dev = s->p[0].port.dev; + + count = device_property_count_u32(dev, "irda-mode-ports"); + if (count < 0 || count > ARRAY_SIZE(irda_port)) + return; + + ret = device_property_read_u32_array(dev, "irda-mode-ports", + irda_port, count); + if (ret) + return; + + for (i = 0; i < count; i++) { + if (irda_port[i] < s->devtype->nr_uart) + s->p[irda_port[i]].irda_mode = true; + } +} + +/* + * Configure ports designated to operate as modem control lines. + */ +static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s, + struct regmap *regmap) +{ + int i; + int ret; + int count; + u32 mctrl_port[SC16IS7XX_MAX_PORTS]; + struct device *dev = s->p[0].port.dev; + + count = device_property_count_u32(dev, "nxp,modem-control-line-ports"); + if (count < 0 || count > ARRAY_SIZE(mctrl_port)) + return 0; + + ret = device_property_read_u32_array(dev, "nxp,modem-control-line-ports", + mctrl_port, count); + if (ret) + return ret; + + s->mctrl_mask = 0; + + for (i = 0; i < count; i++) { + /* Use GPIO lines as modem control lines */ + if (mctrl_port[i] == 0) + s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_A_BIT; + else if (mctrl_port[i] == 1) + s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_B_BIT; + } + + if (s->mctrl_mask) + regmap_update_bits( + regmap, + SC16IS7XX_IOCONTROL_REG, + SC16IS7XX_IOCONTROL_MODEM_A_BIT | + SC16IS7XX_IOCONTROL_MODEM_B_BIT, s->mctrl_mask); + + return 0; +} + +static const struct serial_rs485 sc16is7xx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */ +}; + +/* Reset device, purging any pending irq / data */ +static int sc16is7xx_reset(struct device *dev, struct regmap *regmap) +{ + struct gpio_desc *reset_gpio; + + /* Assert reset GPIO if defined and valid. */ + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return dev_err_probe(dev, PTR_ERR(reset_gpio), "Failed to get reset GPIO\n"); + + if (reset_gpio) { + /* The minimum reset pulse width is 3 us. */ + fsleep(5); + gpiod_set_value_cansleep(reset_gpio, 0); /* Deassert GPIO */ + } else { + /* Software reset */ + regmap_write(regmap, SC16IS7XX_IOCONTROL_REG, + SC16IS7XX_IOCONTROL_SRESET_BIT); + } + + return 0; +} + +static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i, + bool *port_registered) +{ + struct uart_port *port = &one->port; + int ret; + + ret = ida_alloc_max(&sc16is7xx_lines, SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL); + if (ret < 0) + return ret; + + port->line = ret; + + /* Initialize port data */ + port->type = PORT_SC16IS7XX; + port->fifosize = SC16IS7XX_FIFO_SIZE; + port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; + port->iobase = i; + /* + * Use all ones as membase to make sure uart_configure_port() in + * serial_core.c does not abort for SPI/I2C devices where the + * membase address is not applicable. + */ + port->membase = (void __iomem *)~0; + port->iotype = UPIO_PORT; + port->rs485_config = sc16is7xx_config_rs485; + port->rs485_supported = sc16is7xx_rs485_supported; + port->ops = &sc16is7xx_ops; + one->old_mctrl = 0; + + mutex_init(&one->lock); + + ret = uart_get_rs485_mode(port); + if (ret) + return ret; + + /* Enable access to general register set */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, 0x00); + + /* Disable all interrupts */ + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); + /* Disable TX/RX */ + sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + + /* Initialize kthread work structs */ + kthread_init_work(&one->tx_work, sc16is7xx_tx_proc); + kthread_init_work(&one->reg_work, sc16is7xx_reg_proc); + kthread_init_delayed_work(&one->ms_work, sc16is7xx_ms_proc); + + /* Register port */ + ret = uart_add_one_port(&sc16is7xx_uart, port); + if (ret) + return ret; + + *port_registered = true; + + sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED); + /* Enable write access to enhanced features */ + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + sc16is7xx_regs_unlock(port); + + /* Go to suspend mode */ + sc16is7xx_power(port, 0); + + return 0; +} + +int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, + struct regmap *regmaps[], int irq) { - struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq = 0, *pfreq = dev_get_platdata(dev); unsigned int val; u32 uartclk = 0; int i, ret; struct sc16is7xx_port *s; + bool port_registered[SC16IS7XX_MAX_PORTS]; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + for (i = 0; i < devtype->nr_uart; i++) + if (IS_ERR(regmaps[i])) + return PTR_ERR(regmaps[i]); /* * This device does not have an identification register that would * tell us if we are really connected to the correct device. * The best we can do is to check if communication is at all possible. + * + * Note: regmap[0] is used in the probe function to access registers + * common to all channels/ports, as it is guaranteed to be present on + * all variants. */ - ret = regmap_read(regmap, - SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val); + ret = regmap_read(regmaps[0], SC16IS7XX_LSR_REG, &val); if (ret < 0) - return ret; + return -EPROBE_DEFER; /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); - if (!s) { - dev_err(dev, "Error allocating port structure\n"); + if (!s) return -ENOMEM; - } /* Always ask for fixed clock rate from a property. */ device_property_read_u32(dev, "clock-frequency", &uartclk); - s->clk = devm_clk_get(dev, NULL); - if (IS_ERR(s->clk)) { + s->polling = (irq <= 0); + if (s->polling) + dev_dbg(dev, + "No interrupt pin definition, falling back to polling mode\n"); + + s->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(s->clk)) + return PTR_ERR(s->clk); + + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; + + freq = clk_get_rate(s->clk); + if (freq == 0) { if (uartclk) freq = uartclk; if (pfreq) @@ -1218,19 +1582,11 @@ static int sc16is7xx_probe(struct device *dev, if (freq) dev_dbg(dev, "Clock frequency: %luHz\n", freq); else - return PTR_ERR(s->clk); - } else { - ret = clk_prepare_enable(s->clk); - if (ret) - return ret; - - freq = clk_get_rate(s->clk); + return -EINVAL; } - s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); - mutex_init(&s->efr_lock); kthread_init_worker(&s->kworker); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, @@ -1239,89 +1595,45 @@ static int sc16is7xx_probe(struct device *dev, ret = PTR_ERR(s->kworker_task); goto out_clk; } - sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param); + sched_set_fifo(s->kworker_task); -#ifdef CONFIG_GPIOLIB - if (devtype->nr_gpio) { - /* Setup GPIO cotroller */ - s->gpio.owner = THIS_MODULE; - s->gpio.parent = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = sc16is7xx_gpio_direction_input; - s->gpio.get = sc16is7xx_gpio_get; - s->gpio.direction_output = sc16is7xx_gpio_direction_output; - s->gpio.set = sc16is7xx_gpio_set; - s->gpio.base = -1; - s->gpio.ngpio = devtype->nr_gpio; - s->gpio.can_sleep = 1; - ret = gpiochip_add_data(&s->gpio, s); - if (ret) - goto out_thread; - } -#endif + ret = sc16is7xx_reset(dev, regmaps[0]); + if (ret) + goto out_kthread; - /* reset device, purging any pending irq / data */ - regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, - SC16IS7XX_IOCONTROL_SRESET_BIT); + /* Mark each port line and status as uninitialised. */ + for (i = 0; i < devtype->nr_uart; ++i) { + s->p[i].port.line = SC16IS7XX_MAX_DEVS; + port_registered[i] = false; + } for (i = 0; i < devtype->nr_uart; ++i) { - s->p[i].line = i; - /* Initialize port data */ s->p[i].port.dev = dev; s->p[i].port.irq = irq; - s->p[i].port.type = PORT_SC16IS7XX; - s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE; - s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; - s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; - s->p[i].port.rs485_config = sc16is7xx_config_rs485; - s->p[i].port.ops = &sc16is7xx_ops; - s->p[i].port.line = sc16is7xx_alloc_line(); - if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { - ret = -ENOMEM; - goto out_ports; - } - - /* Disable all interrupts */ - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); - /* Disable TX/RX */ - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_RXDISABLE_BIT | - SC16IS7XX_EFCR_TXDISABLE_BIT); - /* Initialize kthread work structs */ - kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc); - kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc); - /* Register port */ - uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); - - /* Enable EFR */ - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_B); - - regcache_cache_bypass(s->regmap, true); - - /* Enable write access to enhanced features */ - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG, - SC16IS7XX_EFR_ENABLE_BIT); + s->p[i].regmap = regmaps[i]; - regcache_cache_bypass(s->regmap, false); + ret = sc16is7xx_setup_channel(&s->p[i], i, &port_registered[i]); + if (ret) + goto out_ports; + } - /* Restore access to general registers */ - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00); + sc16is7xx_setup_irda_ports(s); - /* Go to suspend mode */ - sc16is7xx_power(&s->p[i].port, 0); - } + ret = sc16is7xx_setup_mctrl_ports(s, regmaps[0]); + if (ret) + goto out_ports; - if (dev->of_node) { - struct property *prop; - const __be32 *p; - u32 u; +#ifdef CONFIG_GPIOLIB + ret = sc16is7xx_setup_gpio_chip(s); + if (ret) + goto out_ports; +#endif - of_property_for_each_u32(dev->of_node, "irda-mode-ports", - prop, p, u) - if (u < devtype->nr_uart) - s->p[u].irda_mode = true; + if (s->polling) { + /* Initialize kernel thread for polling */ + kthread_init_delayed_work(&s->poll_work, sc16is7xx_poll_proc); + return 0; } /* @@ -1343,53 +1655,57 @@ static int sc16is7xx_probe(struct device *dev, if (!ret) return 0; -out_ports: - for (i--; i >= 0; i--) { - uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, &sc16is7xx_lines); - } - #ifdef CONFIG_GPIOLIB - if (devtype->nr_gpio) + if (s->gpio_valid_mask) gpiochip_remove(&s->gpio); - -out_thread: #endif + +out_ports: + for (i = 0; i < devtype->nr_uart; i++) { + if (s->p[i].port.line < SC16IS7XX_MAX_DEVS) + ida_free(&sc16is7xx_lines, s->p[i].port.line); + if (port_registered[i]) + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + } + +out_kthread: kthread_stop(s->kworker_task); out_clk: - if (!IS_ERR(s->clk)) - clk_disable_unprepare(s->clk); + clk_disable_unprepare(s->clk); return ret; } +EXPORT_SYMBOL_GPL(sc16is7xx_probe); -static int sc16is7xx_remove(struct device *dev) +void sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); int i; #ifdef CONFIG_GPIOLIB - if (s->devtype->nr_gpio) + if (s->gpio_valid_mask) gpiochip_remove(&s->gpio); #endif for (i = 0; i < s->devtype->nr_uart; i++) { + kthread_cancel_delayed_work_sync(&s->p[i].ms_work); + ida_free(&sc16is7xx_lines, s->p[i].port.line); uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, &sc16is7xx_lines); sc16is7xx_power(&s->p[i].port, 0); } + if (s->polling) + kthread_cancel_delayed_work_sync(&s->poll_work); + kthread_flush_worker(&s->kworker); kthread_stop(s->kworker_task); - if (!IS_ERR(s->clk)) - clk_disable_unprepare(s->clk); - - return 0; + clk_disable_unprepare(s->clk); } +EXPORT_SYMBOL_GPL(sc16is7xx_remove); -static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { +const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { { .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, }, { .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, }, { .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, }, @@ -1398,184 +1714,55 @@ static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { { .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, }, { } }; +EXPORT_SYMBOL_GPL(sc16is7xx_dt_ids); MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); -static struct regmap_config regcfg = { - .reg_bits = 7, - .pad_bits = 1, +const struct regmap_config sc16is7xx_regcfg = { + .reg_bits = 5, + .pad_bits = 3, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = sc16is7xx_regmap_volatile, .precious_reg = sc16is7xx_regmap_precious, + .writeable_noinc_reg = sc16is7xx_regmap_noinc, + .readable_noinc_reg = sc16is7xx_regmap_noinc, + .max_raw_read = SC16IS7XX_FIFO_SIZE, + .max_raw_write = SC16IS7XX_FIFO_SIZE, + .max_register = SC16IS7XX_EFCR_REG, }; +EXPORT_SYMBOL_GPL(sc16is7xx_regcfg); -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI -static int sc16is7xx_spi_probe(struct spi_device *spi) -{ - const struct sc16is7xx_devtype *devtype; - struct regmap *regmap; - int ret; - - /* Setup SPI bus */ - spi->bits_per_word = 8; - /* only supports mode 0 on SC16IS762 */ - spi->mode = spi->mode ? : SPI_MODE_0; - spi->max_speed_hz = spi->max_speed_hz ? : 15000000; - ret = spi_setup(spi); - if (ret) - return ret; - - if (spi->dev.of_node) { - devtype = device_get_match_data(&spi->dev); - if (!devtype) - return -ENODEV; - } else { - const struct spi_device_id *id_entry = spi_get_device_id(spi); - - devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; - } - - regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | - (devtype->nr_uart - 1); - regmap = devm_regmap_init_spi(spi, ®cfg); - - return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq); -} - -static int sc16is7xx_spi_remove(struct spi_device *spi) -{ - return sc16is7xx_remove(&spi->dev); -} - -static const struct spi_device_id sc16is7xx_spi_id_table[] = { - { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, - { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, - { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, - { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, - { } -}; - -MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table); - -static struct spi_driver sc16is7xx_spi_uart_driver = { - .driver = { - .name = SC16IS7XX_NAME, - .of_match_table = sc16is7xx_dt_ids, - }, - .probe = sc16is7xx_spi_probe, - .remove = sc16is7xx_spi_remove, - .id_table = sc16is7xx_spi_id_table, -}; - -MODULE_ALIAS("spi:sc16is7xx"); -#endif - -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C -static int sc16is7xx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +const char *sc16is7xx_regmap_name(u8 port_id) { - const struct sc16is7xx_devtype *devtype; - struct regmap *regmap; - - if (i2c->dev.of_node) { - devtype = device_get_match_data(&i2c->dev); - if (!devtype) - return -ENODEV; - } else { - devtype = (struct sc16is7xx_devtype *)id->driver_data; + switch (port_id) { + case 0: return "port0"; + case 1: return "port1"; + default: + WARN_ON(true); + return NULL; } - - regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | - (devtype->nr_uart - 1); - regmap = devm_regmap_init_i2c(i2c, ®cfg); - - return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq); } +EXPORT_SYMBOL_GPL(sc16is7xx_regmap_name); -static int sc16is7xx_i2c_remove(struct i2c_client *client) +unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id) { - return sc16is7xx_remove(&client->dev); + /* CH1,CH0 are at bits 2:1. */ + return port_id << 1; } - -static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { - { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, - { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, - { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, - { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, - { } -}; -MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); - -static struct i2c_driver sc16is7xx_i2c_uart_driver = { - .driver = { - .name = SC16IS7XX_NAME, - .of_match_table = sc16is7xx_dt_ids, - }, - .probe = sc16is7xx_i2c_probe, - .remove = sc16is7xx_i2c_remove, - .id_table = sc16is7xx_i2c_id_table, -}; - -#endif +EXPORT_SYMBOL_GPL(sc16is7xx_regmap_port_mask); static int __init sc16is7xx_init(void) { - int ret; - - ret = uart_register_driver(&sc16is7xx_uart); - if (ret) { - pr_err("Registering UART driver failed\n"); - return ret; - } - -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C - ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); - if (ret < 0) { - pr_err("failed to init sc16is7xx i2c --> %d\n", ret); - goto err_i2c; - } -#endif - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI - ret = spi_register_driver(&sc16is7xx_spi_uart_driver); - if (ret < 0) { - pr_err("failed to init sc16is7xx spi --> %d\n", ret); - goto err_spi; - } -#endif - return ret; - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI -err_spi: -#endif -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C - i2c_del_driver(&sc16is7xx_i2c_uart_driver); -err_i2c: -#endif - uart_unregister_driver(&sc16is7xx_uart); - return ret; + return uart_register_driver(&sc16is7xx_uart); } module_init(sc16is7xx_init); static void __exit sc16is7xx_exit(void) { -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C - i2c_del_driver(&sc16is7xx_i2c_uart_driver); -#endif - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI - spi_unregister_driver(&sc16is7xx_spi_uart_driver); -#endif uart_unregister_driver(&sc16is7xx_uart); } module_exit(sc16is7xx_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>"); -MODULE_DESCRIPTION("SC16IS7XX serial driver"); +MODULE_DESCRIPTION(KBUILD_MODNAME " tty serial core driver"); diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h new file mode 100644 index 000000000000..9c584d6d3593 --- /dev/null +++ b/drivers/tty/serial/sc16is7xx.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* SC16IS7xx SPI/I2C tty serial driver */ + +#ifndef _SC16IS7XX_H_ +#define _SC16IS7XX_H_ + +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */ + +struct device; + +struct sc16is7xx_devtype { + char name[10]; + int nr_gpio; + int nr_uart; +}; + +extern const struct regmap_config sc16is7xx_regcfg; + +extern const struct of_device_id sc16is7xx_dt_ids[]; + +extern const struct sc16is7xx_devtype sc16is74x_devtype; +extern const struct sc16is7xx_devtype sc16is750_devtype; +extern const struct sc16is7xx_devtype sc16is752_devtype; +extern const struct sc16is7xx_devtype sc16is760_devtype; +extern const struct sc16is7xx_devtype sc16is762_devtype; + +const char *sc16is7xx_regmap_name(u8 port_id); + +unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id); + +int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, + struct regmap *regmaps[], int irq); + +void sc16is7xx_remove(struct device *dev); + +#endif /* _SC16IS7XX_H_ */ diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c new file mode 100644 index 000000000000..699376c3b3a5 --- /dev/null +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* SC16IS7xx I2C interface driver */ + +#include <linux/dev_printk.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/string.h> + +#include "sc16is7xx.h" + +static int sc16is7xx_i2c_probe(struct i2c_client *i2c) +{ + const struct sc16is7xx_devtype *devtype; + struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + struct regmap_config regcfg; + unsigned int i; + + devtype = i2c_get_match_data(i2c); + if (!devtype) + return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n"); + + memcpy(®cfg, &sc16is7xx_regcfg, sizeof(struct regmap_config)); + + for (i = 0; i < devtype->nr_uart; i++) { + regcfg.name = sc16is7xx_regmap_name(i); + regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); + regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg); + } + + return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq); +} + +static void sc16is7xx_i2c_remove(struct i2c_client *client) +{ + sc16is7xx_remove(&client->dev); +} + +static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); + +static struct i2c_driver sc16is7xx_i2c_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = sc16is7xx_dt_ids, + }, + .probe = sc16is7xx_i2c_probe, + .remove = sc16is7xx_i2c_remove, + .id_table = sc16is7xx_i2c_id_table, +}; + +module_i2c_driver(sc16is7xx_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(KBUILD_MODNAME " interface driver"); +MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX"); diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c new file mode 100644 index 000000000000..7e76d0e38da7 --- /dev/null +++ b/drivers/tty/serial/sc16is7xx_spi.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* SC16IS7xx SPI interface driver */ + +#include <linux/dev_printk.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/string.h> +#include <linux/units.h> + +#include "sc16is7xx.h" + +/* SPI definitions */ +#define SC16IS7XX_SPI_READ_BIT BIT(7) + +static int sc16is7xx_spi_probe(struct spi_device *spi) +{ + const struct sc16is7xx_devtype *devtype; + struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + struct regmap_config regcfg; + unsigned int i; + int ret; + + /* Setup SPI bus */ + spi->bits_per_word = 8; + /* For all variants, only mode 0 is supported */ + if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0) + return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n"); + + spi->mode = spi->mode ? : SPI_MODE_0; + spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ; + ret = spi_setup(spi); + if (ret) + return ret; + + devtype = spi_get_device_match_data(spi); + if (!devtype) + return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); + + memcpy(®cfg, &sc16is7xx_regcfg, sizeof(struct regmap_config)); + + for (i = 0; i < devtype->nr_uart; i++) { + regcfg.name = sc16is7xx_regmap_name(i); + /* + * If read_flag_mask is 0, the regmap code sets it to a default + * of 0x80. Since we specify our own mask, we must add the READ + * bit ourselves: + */ + regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | + SC16IS7XX_SPI_READ_BIT; + regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); + } + + return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq); +} + +static void sc16is7xx_spi_remove(struct spi_device *spi) +{ + sc16is7xx_remove(&spi->dev); +} + +static const struct spi_device_id sc16is7xx_spi_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table); + +static struct spi_driver sc16is7xx_spi_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = sc16is7xx_dt_ids, + }, + .probe = sc16is7xx_spi_probe, + .remove = sc16is7xx_spi_remove, + .id_table = sc16is7xx_spi_id_table, +}; + +module_spi_driver(sc16is7xx_spi_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(KBUILD_MODNAME " interface driver"); +MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX"); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 10cc16a71f26..4ceca11ce600 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -383,8 +383,7 @@ static void sccnxp_set_bit(struct uart_port *port, int sig, int state) static void sccnxp_handle_rx(struct uart_port *port) { - u8 sr; - unsigned int ch, flag; + u8 sr, ch, flag; for (;;) { sr = sccnxp_port_read(port, SCCNXP_SR_REG); @@ -440,7 +439,7 @@ static void sccnxp_handle_rx(struct uart_port *port) static void sccnxp_handle_tx(struct uart_port *port) { u8 sr; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct sccnxp_port *s = dev_get_drvdata(port->dev); if (unlikely(port->x_char)) { @@ -450,7 +449,7 @@ static void sccnxp_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable TX if FIFO is empty */ if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) { sccnxp_disable_irq(port, IMR_TXRDY); @@ -462,17 +461,20 @@ static void sccnxp_handle_tx(struct uart_port *port) return; } - while (!uart_circ_empty(xmit)) { + while (1) { + unsigned char ch; + sr = sccnxp_port_read(port, SCCNXP_SR_REG); if (!(sr & SR_TXRDY)) break; - sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + if (!uart_fifo_get(port, &ch)) + break; + + sccnxp_port_write(port, SCCNXP_THR_REG, ch); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -498,7 +500,7 @@ static void sccnxp_handle_events(struct sccnxp_port *s) static void sccnxp_timer(struct timer_list *t) { - struct sccnxp_port *s = from_timer(s, t, timer); + struct sccnxp_port *s = timer_container_of(s, t, timer); unsigned long flags; spin_lock_irqsave(&s->lock, flags); @@ -636,7 +638,8 @@ static void sccnxp_break_ctl(struct uart_port *port, int break_state) } static void sccnxp_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { struct sccnxp_port *s = dev_get_drvdata(port->dev); unsigned long flags; @@ -828,7 +831,7 @@ static const struct uart_ops sccnxp_ops = { }; #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE -static void sccnxp_console_putchar(struct uart_port *port, int c) +static void sccnxp_console_putchar(struct uart_port *port, unsigned char c) { int tryes = 100000; @@ -880,14 +883,14 @@ MODULE_DEVICE_TABLE(platform, sccnxp_id_table); static int sccnxp_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); + struct resource *res; int i, ret, uartclk; struct sccnxp_port *s; void __iomem *membase; struct clk *clk; - membase = devm_ioremap_resource(&pdev->dev, res); + membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(membase)) return PTR_ERR(membase); @@ -913,23 +916,13 @@ static int sccnxp_probe(struct platform_device *pdev) } else if (PTR_ERR(s->regulator) == -EPROBE_DEFER) return -EPROBE_DEFER; - clk = devm_clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) { ret = PTR_ERR(clk); if (ret == -EPROBE_DEFER) goto err_out; uartclk = 0; } else { - ret = clk_prepare_enable(clk); - if (ret) - goto err_out; - - ret = devm_add_action_or_reset(&pdev->dev, - (void(*)(void *))clk_disable_unprepare, - clk); - if (ret) - goto err_out; - uartclk = clk_get_rate(clk); } @@ -1032,7 +1025,7 @@ err_out: return ret; } -static int sccnxp_remove(struct platform_device *pdev) +static void sccnxp_remove(struct platform_device *pdev) { int i; struct sccnxp_port *s = platform_get_drvdata(pdev); @@ -1040,17 +1033,18 @@ static int sccnxp_remove(struct platform_device *pdev) if (!s->poll) devm_free_irq(&pdev->dev, s->irq, s); else - del_timer_sync(&s->timer); + timer_delete_sync(&s->timer); for (i = 0; i < s->uart.nr; i++) uart_remove_one_port(&s->uart, &s->port[i]); uart_unregister_driver(&s->uart); - if (!IS_ERR(s->regulator)) - return regulator_disable(s->regulator); - - return 0; + if (!IS_ERR(s->regulator)) { + int ret = regulator_disable(s->regulator); + if (ret) + dev_err(&pdev->dev, "Failed to disable regulator\n"); + } } static struct platform_driver sccnxp_uart_driver = { diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 8de8bac9c6c7..8004fc00fb9c 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -20,7 +20,6 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pagemap.h> #include <linux/platform_device.h> #include <linux/reset.h> @@ -75,12 +74,17 @@ #define TEGRA_UART_FCR_IIR_FIFO_EN 0x40 /** - * tegra_uart_chip_data: SOC specific data. + * struct tegra_uart_chip_data: SOC specific data. * * @tx_fifo_full_status: Status flag available for checking tx fifo full. * @allow_txfifo_reset_fifo_mode: allow_tx fifo reset with fifo mode or not. * Tegra30 does not allow this. * @support_clk_src_div: Clock source support the clock divider. + * @fifo_mode_enable_status: Is FIFO mode enabled? + * @uart_max_port: Maximum number of UART ports + * @max_dma_burst_bytes: Maximum size of DMA bursts + * @error_tolerance_low_range: Lowest number in the error tolerance range + * @error_tolerance_high_range: Highest number in the error tolerance range */ struct tegra_uart_chip_data { bool tx_fifo_full_status; @@ -333,7 +337,7 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) do { lsr = tegra_uart_read(tup, UART_LSR); - if ((lsr | UART_LSR_TEMT) && !(lsr & UART_LSR_DR)) + if ((lsr & UART_LSR_TEMT) && !(lsr & UART_LSR_DR)) break; udelay(1); } while (--tmout); @@ -407,7 +411,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) divisor = DIV_ROUND_CLOSEST(rate, baud * 16); } - spin_lock_irqsave(&tup->uport.lock, flags); + uart_port_lock_irqsave(&tup->uport, &flags); lcr = tup->lcr_shadow; lcr |= UART_LCR_DLAB; tegra_uart_write(tup, lcr, UART_LCR); @@ -420,7 +424,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) /* Dummy read to ensure the write is posted */ tegra_uart_read(tup, UART_SCR); - spin_unlock_irqrestore(&tup->uport.lock, flags); + uart_port_unlock_irqrestore(&tup->uport, flags); tup->current_baud = baud; @@ -429,26 +433,26 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) return 0; } -static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup, +static u8 tegra_uart_decode_rx_error(struct tegra_uart_port *tup, unsigned long lsr) { - char flag = TTY_NORMAL; + u8 flag = TTY_NORMAL; if (unlikely(lsr & TEGRA_UART_LSR_ANY)) { if (lsr & UART_LSR_OE) { - /* Overrrun error */ + /* Overrun error */ flag = TTY_OVERRUN; tup->uport.icount.overrun++; - dev_err(tup->uport.dev, "Got overrun errors\n"); + dev_dbg(tup->uport.dev, "Got overrun errors\n"); } else if (lsr & UART_LSR_PE) { /* Parity error */ flag = TTY_PARITY; tup->uport.icount.parity++; - dev_err(tup->uport.dev, "Got Parity errors\n"); + dev_dbg(tup->uport.dev, "Got Parity errors\n"); } else if (lsr & UART_LSR_FE) { flag = TTY_FRAME; tup->uport.icount.frame++; - dev_err(tup->uport.dev, "Got frame errors\n"); + dev_dbg(tup->uport.dev, "Got frame errors\n"); } else if (lsr & UART_LSR_BI) { /* * Break error @@ -480,19 +484,18 @@ static void tegra_uart_release_port(struct uart_port *u) static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes) { - struct circ_buf *xmit = &tup->uport.state->xmit; + unsigned char ch; int i; for (i = 0; i < max_bytes; i++) { - BUG_ON(uart_circ_empty(xmit)); if (tup->cdata->tx_fifo_full_status) { unsigned long lsr = tegra_uart_read(tup, UART_LSR); if ((lsr & TEGRA_UART_LSR_TXFIFO_FULL)) break; } - tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - tup->uport.icount.tx++; + if (WARN_ON_ONCE(!uart_fifo_get(&tup->uport, &ch))) + break; + tegra_uart_write(tup, ch, UART_TX); } } @@ -511,7 +514,7 @@ static void tegra_uart_start_pio_tx(struct tegra_uart_port *tup, static void tegra_uart_tx_dma_complete(void *args) { struct tegra_uart_port *tup = args; - struct circ_buf *xmit = &tup->uport.state->xmit; + struct tty_port *tport = &tup->uport.state->port; struct dma_tx_state state; unsigned long flags; unsigned int count; @@ -519,23 +522,26 @@ static void tegra_uart_tx_dma_complete(void *args) dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); count = tup->tx_bytes_requested - state.residue; async_tx_ack(tup->tx_dma_desc); - spin_lock_irqsave(&tup->uport.lock, flags); - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + uart_port_lock_irqsave(&tup->uport, &flags); + uart_xmit_advance(&tup->uport, count); tup->tx_in_progress = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&tup->uport); tegra_uart_start_next_tx(tup); - spin_unlock_irqrestore(&tup->uport.lock, flags); + uart_port_unlock_irqrestore(&tup->uport, flags); } static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup, unsigned long count) { - struct circ_buf *xmit = &tup->uport.state->xmit; + struct tty_port *tport = &tup->uport.state->port; dma_addr_t tx_phys_addr; + unsigned int tail; tup->tx_bytes = count & ~(0xF); - tx_phys_addr = tup->tx_dma_buf_phys + xmit->tail; + WARN_ON_ONCE(kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE) < count); + tx_phys_addr = tup->tx_dma_buf_phys + tail; dma_sync_single_for_device(tup->uport.dev, tx_phys_addr, tup->tx_bytes, DMA_TO_DEVICE); @@ -559,18 +565,21 @@ static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup, static void tegra_uart_start_next_tx(struct tegra_uart_port *tup) { + struct tty_port *tport = &tup->uport.state->port; + unsigned char *tail_ptr; unsigned long tail; - unsigned long count; - struct circ_buf *xmit = &tup->uport.state->xmit; + unsigned int count; if (!tup->current_baud) return; - tail = (unsigned long)&xmit->buf[xmit->tail]; - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail_ptr, + UART_XMIT_SIZE); if (!count) return; + tail = (unsigned long)tail_ptr; + if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA) tegra_uart_start_pio_tx(tup, count); else if (BYTES_TO_ALIGN(tail) > 0) @@ -583,9 +592,9 @@ static void tegra_uart_start_next_tx(struct tegra_uart_port *tup) static void tegra_uart_start_tx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); - struct circ_buf *xmit = &u->state->xmit; + struct tty_port *tport = &u->state->port; - if (!uart_circ_empty(xmit) && !tup->tx_in_progress) + if (!kfifo_is_empty(&tport->xmit_fifo) && !tup->tx_in_progress) tegra_uart_start_next_tx(tup); } @@ -595,52 +604,51 @@ static unsigned int tegra_uart_tx_empty(struct uart_port *u) unsigned int ret = 0; unsigned long flags; - spin_lock_irqsave(&u->lock, flags); + uart_port_lock_irqsave(u, &flags); if (!tup->tx_in_progress) { unsigned long lsr = tegra_uart_read(tup, UART_LSR); if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS) ret = TIOCSER_TEMT; } - spin_unlock_irqrestore(&u->lock, flags); + uart_port_unlock_irqrestore(u, flags); return ret; } static void tegra_uart_stop_tx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); - struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; unsigned int count; if (tup->tx_in_progress != TEGRA_UART_TX_DMA) return; - dmaengine_terminate_all(tup->tx_dma_chan); + dmaengine_pause(tup->tx_dma_chan); dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); + dmaengine_terminate_all(tup->tx_dma_chan); count = tup->tx_bytes_requested - state.residue; async_tx_ack(tup->tx_dma_desc); - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + uart_xmit_advance(&tup->uport, count); tup->tx_in_progress = 0; } static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) { - struct circ_buf *xmit = &tup->uport.state->xmit; + struct tty_port *tport = &tup->uport.state->port; tegra_uart_fill_tx_fifo(tup, tup->tx_bytes); tup->tx_in_progress = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&tup->uport); tegra_uart_start_next_tx(tup); } static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, - struct tty_port *tty) + struct tty_port *port) { do { - char flag = TTY_NORMAL; unsigned long lsr = 0; - unsigned char ch; + u8 ch, flag = TTY_NORMAL; lsr = tegra_uart_read(tup, UART_LSR); if (!(lsr & UART_LSR_DR)) @@ -653,16 +661,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, ch = (unsigned char) tegra_uart_read(tup, UART_RX); tup->uport.icount.rx++; - if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) - tty_insert_flip_char(tty, ch, flag); + if (uart_handle_sysrq_char(&tup->uport, ch)) + continue; if (tup->uport.ignore_status_mask & UART_LSR_DR) continue; + + tty_insert_flip_char(port, ch, flag); } while (1); } static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, - struct tty_port *tty, + struct tty_port *port, unsigned int count) { int copied; @@ -672,17 +682,13 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, return; tup->uport.icount.rx += count; - if (!tty) { - dev_err(tup->uport.dev, "No tty port\n"); - return; - } if (tup->uport.ignore_status_mask & UART_LSR_DR) return; dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys, count, DMA_FROM_DEVICE); - copied = tty_insert_flip_string(tty, + copied = tty_insert_flip_string(port, ((unsigned char *)(tup->rx_dma_buf_virt)), count); if (copied != count) { WARN_ON(1); @@ -727,7 +733,7 @@ static void tegra_uart_rx_dma_complete(void *args) struct dma_tx_state state; enum dma_status status; - spin_lock_irqsave(&u->lock, flags); + uart_port_lock_irqsave(u, &flags); status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); @@ -749,7 +755,7 @@ static void tegra_uart_rx_dma_complete(void *args) set_rts(tup, true); done: - spin_unlock_irqrestore(&u->lock, flags); + uart_port_unlock_irqrestore(u, flags); } static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup) @@ -761,8 +767,9 @@ static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup) return; } - dmaengine_terminate_all(tup->rx_dma_chan); + dmaengine_pause(tup->rx_dma_chan); dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + dmaengine_terminate_all(tup->rx_dma_chan); tegra_uart_rx_buffer_push(tup, state.residue); tup->rx_dma_active = false; @@ -835,7 +842,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) bool is_rx_int = false; unsigned long flags; - spin_lock_irqsave(&u->lock, flags); + uart_port_lock_irqsave(u, &flags); while (1) { iir = tegra_uart_read(tup, UART_IIR); if (iir & UART_IIR_NO_INT) { @@ -851,7 +858,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) } else if (is_rx_start) { tegra_uart_start_rx_dma(tup); } - spin_unlock_irqrestore(&u->lock, flags); + uart_port_unlock_irqrestore(u, flags); return IRQ_HANDLED; } @@ -878,7 +885,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) tegra_uart_write(tup, ier, UART_IER); break; } - /* Fall through */ + fallthrough; case 2: /* Receive */ if (!tup->use_rx_pio) { is_rx_start = tup->rx_in_progress; @@ -968,11 +975,11 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) } } - spin_lock_irqsave(&tup->uport.lock, flags); + uart_port_lock_irqsave(&tup->uport, &flags); /* Reset the Rx and Tx FIFOs */ tegra_uart_fifo_reset(tup, UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); tup->current_baud = 0; - spin_unlock_irqrestore(&tup->uport.lock, flags); + uart_port_unlock_irqrestore(&tup->uport, flags); tup->rx_in_progress = 0; tup->tx_in_progress = 0; @@ -995,7 +1002,11 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->ier_shadow = 0; tup->current_baud = 0; - clk_prepare_enable(tup->uart_clk); + ret = clk_prepare_enable(tup->uart_clk); + if (ret) { + dev_err(tup->uport.dev, "could not enable clk\n"); + return ret; + } /* Reset the UART controller to clear all previous status.*/ reset_control_assert(tup->rst); @@ -1042,9 +1053,12 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) if (tup->cdata->fifo_mode_enable_status) { ret = tegra_uart_wait_fifo_mode_enabled(tup); - dev_err(tup->uport.dev, "FIFO mode not enabled\n"); - if (ret < 0) + if (ret < 0) { + clk_disable_unprepare(tup->uart_clk); + dev_err(tup->uport.dev, + "Failed to enable FIFO mode: %d\n", ret); return ret; + } } else { /* * For all tegra devices (up to t210), there is a hardware @@ -1062,6 +1076,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) */ ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD); if (ret < 0) { + clk_disable_unprepare(tup->uart_clk); dev_err(tup->uport.dev, "Failed to set baud rate\n"); return ret; } @@ -1075,7 +1090,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->rx_in_progress = 1; /* - * Enable IE_RXS for the receive status interrupts like line errros. + * Enable IE_RXS for the receive status interrupts like line errors. * Enable IE_RX_TIMEOUT to get the bytes which cannot be DMA'd. * * EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when @@ -1160,15 +1175,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, tup->rx_dma_buf_virt = dma_buf; tup->rx_dma_buf_phys = dma_phys; } else { + dma_buf = tup->uport.state->port.xmit_buf; dma_phys = dma_map_single(tup->uport.dev, - tup->uport.state->xmit.buf, UART_XMIT_SIZE, - DMA_TO_DEVICE); + dma_buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(tup->uport.dev, dma_phys)) { dev_err(tup->uport.dev, "dma_map_single tx failed\n"); dma_release_channel(dma_chan); return -ENOMEM; } - dma_buf = tup->uport.state->xmit.buf; dma_sconfig.dst_addr = tup->uport.mapbase; dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.dst_maxburst = 16; @@ -1221,10 +1235,13 @@ static int tegra_uart_startup(struct uart_port *u) dev_name(u->dev), tup); if (ret < 0) { dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); - goto fail_hw_init; + goto fail_request_irq; } return 0; +fail_request_irq: + /* tup->uart_clk is already enabled in tegra_uart_hw_init */ + clk_disable_unprepare(tup->uart_clk); fail_hw_init: if (!tup->use_rx_pio) tegra_uart_dma_channel_free(tup, true); @@ -1266,20 +1283,21 @@ static void tegra_uart_enable_ms(struct uart_port *u) } static void tegra_uart_set_termios(struct uart_port *u, - struct ktermios *termios, struct ktermios *oldtermios) + struct ktermios *termios, + const struct ktermios *oldtermios) { struct tegra_uart_port *tup = to_tegra_uport(u); unsigned int baud; unsigned long flags; unsigned int lcr; - int symb_bit = 1; + unsigned char char_bits; struct clk *parent_clk = clk_get_parent(tup->uart_clk); unsigned long parent_clk_rate = clk_get_rate(parent_clk); int max_divider = (tup->cdata->support_clk_src_div) ? 0x7FFF : 0xFFFF; int ret; max_divider *= 16; - spin_lock_irqsave(&u->lock, flags); + uart_port_lock_irqsave(u, &flags); /* Changing configuration, it is safe to stop any rx now */ if (tup->rts_active) @@ -1299,7 +1317,6 @@ static void tegra_uart_set_termios(struct uart_port *u, termios->c_cflag &= ~CMSPAR; if ((termios->c_cflag & PARENB) == PARENB) { - symb_bit++; if (termios->c_cflag & PARODD) { lcr |= UART_LCR_PARITY; lcr &= ~UART_LCR_EPAR; @@ -1311,44 +1328,25 @@ static void tegra_uart_set_termios(struct uart_port *u, } } + char_bits = tty_get_char_size(termios->c_cflag); lcr &= ~UART_LCR_WLEN8; - switch (termios->c_cflag & CSIZE) { - case CS5: - lcr |= UART_LCR_WLEN5; - symb_bit += 5; - break; - case CS6: - lcr |= UART_LCR_WLEN6; - symb_bit += 6; - break; - case CS7: - lcr |= UART_LCR_WLEN7; - symb_bit += 7; - break; - default: - lcr |= UART_LCR_WLEN8; - symb_bit += 8; - break; - } + lcr |= UART_LCR_WLEN(char_bits); /* Stop bits */ - if (termios->c_cflag & CSTOPB) { + if (termios->c_cflag & CSTOPB) lcr |= UART_LCR_STOP; - symb_bit += 2; - } else { + else lcr &= ~UART_LCR_STOP; - symb_bit++; - } tegra_uart_write(tup, lcr, UART_LCR); tup->lcr_shadow = lcr; - tup->symb_bit = symb_bit; + tup->symb_bit = tty_get_frame_size(termios->c_cflag); /* Baud rate. */ baud = uart_get_baud_rate(u, termios, oldtermios, parent_clk_rate/max_divider, parent_clk_rate/16); - spin_unlock_irqrestore(&u->lock, flags); + uart_port_unlock_irqrestore(u, flags); ret = tegra_set_baudrate(tup, baud); if (ret < 0) { dev_err(tup->uport.dev, "Failed to set baud rate\n"); @@ -1356,7 +1354,7 @@ static void tegra_uart_set_termios(struct uart_port *u, } if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); - spin_lock_irqsave(&u->lock, flags); + uart_port_lock_irqsave(u, &flags); /* Flow control */ if (termios->c_cflag & CRTSCTS) { @@ -1389,7 +1387,7 @@ static void tegra_uart_set_termios(struct uart_port *u, if (termios->c_iflag & IGNBRK) tup->uport.ignore_status_mask |= UART_LSR_BI; - spin_unlock_irqrestore(&u->lock, flags); + uart_port_unlock_irqrestore(u, flags); } static const char *tegra_uart_type(struct uart_port *u) @@ -1501,7 +1499,7 @@ static struct tegra_uart_chip_data tegra20_uart_chip_data = { .fifo_mode_enable_status = false, .uart_max_port = 5, .max_dma_burst_bytes = 4, - .error_tolerance_low_range = 0, + .error_tolerance_low_range = -4, .error_tolerance_high_range = 4, }; @@ -1512,7 +1510,7 @@ static struct tegra_uart_chip_data tegra30_uart_chip_data = { .fifo_mode_enable_status = false, .uart_max_port = 5, .max_dma_burst_bytes = 4, - .error_tolerance_low_range = 0, + .error_tolerance_low_range = -4, .error_tolerance_high_range = 4, }; @@ -1563,14 +1561,12 @@ static int tegra_uart_probe(struct platform_device *pdev) struct resource *resource; int ret; const struct tegra_uart_chip_data *cdata; - const struct of_device_id *match; - match = of_match_device(tegra_uart_of_match, &pdev->dev); - if (!match) { + cdata = of_device_get_match_data(&pdev->dev); + if (!cdata) { dev_err(&pdev->dev, "Error: No device match found\n"); return -ENODEV; } - cdata = match->data; tup = devm_kzalloc(&pdev->dev, sizeof(*tup), GFP_KERNEL); if (!tup) { @@ -1590,22 +1586,15 @@ static int tegra_uart_probe(struct platform_device *pdev) tup->cdata = cdata; platform_set_drvdata(pdev, tup); - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!resource) { - dev_err(&pdev->dev, "No IO memory resource\n"); - return -ENODEV; - } - u->mapbase = resource->start; - u->membase = devm_ioremap_resource(&pdev->dev, resource); + u->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &resource); if (IS_ERR(u->membase)) return PTR_ERR(u->membase); + u->mapbase = resource->start; tup->uart_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(tup->uart_clk)) { - dev_err(&pdev->dev, "Couldn't get the clock\n"); - return PTR_ERR(tup->uart_clk); - } + if (IS_ERR(tup->uart_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(tup->uart_clk), "Couldn't get the clock"); tup->rst = devm_reset_control_get_exclusive(&pdev->dev, "serial"); if (IS_ERR(tup->rst)) { @@ -1627,13 +1616,12 @@ static int tegra_uart_probe(struct platform_device *pdev) return ret; } -static int tegra_uart_remove(struct platform_device *pdev) +static void tegra_uart_remove(struct platform_device *pdev) { struct tegra_uart_port *tup = platform_get_drvdata(pdev); struct uart_port *u = &tup->uport; uart_remove_one_port(&tegra_uart_driver, u); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1678,6 +1666,7 @@ static int __init tegra_uart_init(void) node = of_find_matching_node(NULL, tegra_uart_of_match); if (node) match = of_match_node(tegra_uart_of_match, node); + of_node_put(node); if (match) cdata = match->data; if (cdata) diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h new file mode 100644 index 000000000000..0d50db5b660b --- /dev/null +++ b/drivers/tty/serial/serial_base.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Serial core related functions, serial port device drivers do not need this. + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Tony Lindgren <tony@atomide.com> + */ + +#define to_serial_base_ctrl_device(d) container_of((d), struct serial_ctrl_device, dev) +#define to_serial_base_port_device(d) container_of((d), struct serial_port_device, dev) + +struct uart_driver; +struct uart_port; +struct device_driver; +struct device; + +struct serial_ctrl_device { + struct device dev; + struct ida port_ida; +}; + +struct serial_port_device { + struct device dev; + struct uart_port *port; + unsigned int tx_enabled:1; +}; + +int serial_base_ctrl_init(void); +void serial_base_ctrl_exit(void); + +int serial_base_port_init(void); +void serial_base_port_exit(void); + +void serial_base_port_startup(struct uart_port *port); +void serial_base_port_shutdown(struct uart_port *port); + +int serial_base_driver_register(struct device_driver *driver); +void serial_base_driver_unregister(struct device_driver *driver); + +struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port, + struct device *parent); +struct serial_port_device *serial_base_port_add(struct uart_port *port, + struct serial_ctrl_device *parent); +void serial_base_ctrl_device_remove(struct serial_ctrl_device *ctrl_dev); +void serial_base_port_device_remove(struct serial_port_device *port_dev); + +int serial_ctrl_register_port(struct uart_driver *drv, struct uart_port *port); +void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port); + +int serial_core_register_port(struct uart_driver *drv, struct uart_port *port); +void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port); + +#ifdef CONFIG_SERIAL_CORE_CONSOLE + +int serial_base_match_and_update_preferred_console(struct uart_driver *drv, + struct uart_port *port); + +#else + +static inline +int serial_base_match_and_update_preferred_console(struct uart_driver *drv, + struct uart_port *port) +{ + return 0; +} + +#endif diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c new file mode 100644 index 000000000000..22749ab0428a --- /dev/null +++ b/drivers/tty/serial/serial_base_bus.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Serial base bus layer for controllers + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Tony Lindgren <tony@atomide.com> + * + * The serial core bus manages the serial core controller instances. + */ + +#include <linux/cleanup.h> +#include <linux/container_of.h> +#include <linux/device.h> +#include <linux/idr.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include "serial_base.h" + +static bool serial_base_initialized; + +static const struct device_type serial_ctrl_type = { + .name = "ctrl", +}; + +static const struct device_type serial_port_type = { + .name = "port", +}; + +static int serial_base_match(struct device *dev, const struct device_driver *drv) +{ + if (dev->type == &serial_ctrl_type && + str_has_prefix(drv->name, serial_ctrl_type.name)) + return 1; + + if (dev->type == &serial_port_type && + str_has_prefix(drv->name, serial_port_type.name)) + return 1; + + return 0; +} + +static const struct bus_type serial_base_bus_type = { + .name = "serial-base", + .match = serial_base_match, +}; + +int serial_base_driver_register(struct device_driver *driver) +{ + driver->bus = &serial_base_bus_type; + + return driver_register(driver); +} + +void serial_base_driver_unregister(struct device_driver *driver) +{ + driver_unregister(driver); +} + +static int serial_base_device_init(struct uart_port *port, + struct device *dev, + struct device *parent_dev, + const struct device_type *type, + void (*release)(struct device *dev), + unsigned int ctrl_id, + unsigned int port_id) +{ + device_initialize(dev); + dev->type = type; + dev->parent = parent_dev; + dev->bus = &serial_base_bus_type; + dev->release = release; + device_set_of_node_from_dev(dev, parent_dev); + + if (!serial_base_initialized) { + dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n"); + return -EPROBE_DEFER; + } + + if (type == &serial_ctrl_type) + return dev_set_name(dev, "%s:%d", dev_name(port->dev), ctrl_id); + + if (type == &serial_port_type) + return dev_set_name(dev, "%s:%d.%d", dev_name(port->dev), + ctrl_id, port_id); + + return -EINVAL; +} + +static void serial_base_ctrl_release(struct device *dev) +{ + struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev); + + of_node_put(dev->of_node); + kfree(ctrl_dev); +} + +void serial_base_ctrl_device_remove(struct serial_ctrl_device *ctrl_dev) +{ + if (!ctrl_dev) + return; + + device_del(&ctrl_dev->dev); + put_device(&ctrl_dev->dev); +} + +struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port, + struct device *parent) +{ + struct serial_ctrl_device *ctrl_dev; + int err; + + ctrl_dev = kzalloc(sizeof(*ctrl_dev), GFP_KERNEL); + if (!ctrl_dev) + return ERR_PTR(-ENOMEM); + + ida_init(&ctrl_dev->port_ida); + + err = serial_base_device_init(port, &ctrl_dev->dev, + parent, &serial_ctrl_type, + serial_base_ctrl_release, + port->ctrl_id, 0); + if (err) + goto err_put_device; + + err = device_add(&ctrl_dev->dev); + if (err) + goto err_put_device; + + return ctrl_dev; + +err_put_device: + put_device(&ctrl_dev->dev); + + return ERR_PTR(err); +} + +static void serial_base_port_release(struct device *dev) +{ + struct serial_port_device *port_dev = to_serial_base_port_device(dev); + + of_node_put(dev->of_node); + kfree(port_dev); +} + +struct serial_port_device *serial_base_port_add(struct uart_port *port, + struct serial_ctrl_device *ctrl_dev) +{ + struct serial_port_device *port_dev; + int min = 0, max = -1; /* Use -1 for max to apply IDA defaults */ + int err; + + port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); + if (!port_dev) + return ERR_PTR(-ENOMEM); + + /* Device driver specified port_id vs automatic assignment? */ + if (port->port_id) { + min = port->port_id; + max = port->port_id; + } + + err = ida_alloc_range(&ctrl_dev->port_ida, min, max, GFP_KERNEL); + if (err < 0) { + kfree(port_dev); + return ERR_PTR(err); + } + + port->port_id = err; + + err = serial_base_device_init(port, &port_dev->dev, + &ctrl_dev->dev, &serial_port_type, + serial_base_port_release, + port->ctrl_id, port->port_id); + if (err) + goto err_put_device; + + port_dev->port = port; + + err = device_add(&port_dev->dev); + if (err) + goto err_put_device; + + return port_dev; + +err_put_device: + put_device(&port_dev->dev); + ida_free(&ctrl_dev->port_ida, port->port_id); + + return ERR_PTR(err); +} + +void serial_base_port_device_remove(struct serial_port_device *port_dev) +{ + struct serial_ctrl_device *ctrl_dev; + struct device *parent; + + if (!port_dev) + return; + + parent = port_dev->dev.parent; + ctrl_dev = to_serial_base_ctrl_device(parent); + + device_del(&port_dev->dev); + ida_free(&ctrl_dev->port_ida, port_dev->port->port_id); + put_device(&port_dev->dev); +} + +#ifdef CONFIG_SERIAL_CORE_CONSOLE + +/** + * serial_base_match_and_update_preferred_console - Match and update a preferred console + * @drv: Serial port device driver + * @port: Serial port instance + * + * Tries to match and update the preferred console for a serial port for + * the kernel command line option console=DEVNAME:0.0. + * + * Cannot be called early for ISA ports, depends on struct device. + * + * Return: 0 on success, negative error code on failure. + */ +int serial_base_match_and_update_preferred_console(struct uart_driver *drv, + struct uart_port *port) +{ + const char *port_match __free(kfree) = NULL; + int ret; + + port_match = kasprintf(GFP_KERNEL, "%s:%d.%d", dev_name(port->dev), + port->ctrl_id, port->port_id); + if (!port_match) + return -ENOMEM; + + ret = match_devname_and_update_preferred_console(port_match, + drv->dev_name, + port->line); + if (ret == -ENOENT) + return 0; + + return ret; +} + +#endif + +static int serial_base_init(void) +{ + int ret; + + ret = bus_register(&serial_base_bus_type); + if (ret) + return ret; + + ret = serial_base_ctrl_init(); + if (ret) + goto err_bus_unregister; + + ret = serial_base_port_init(); + if (ret) + goto err_ctrl_exit; + + serial_base_initialized = true; + + return 0; + +err_ctrl_exit: + serial_base_ctrl_exit(); + +err_bus_unregister: + bus_unregister(&serial_base_bus_type); + + return ret; +} +arch_initcall(serial_base_init); + +static void serial_base_exit(void) +{ + serial_base_port_exit(); + serial_base_ctrl_exit(); + bus_unregister(&serial_base_bus_type); +} +module_exit(serial_base_exit); + +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_DESCRIPTION("Serial core bus"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 57840cf90388..9930023e924c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -14,7 +14,10 @@ #include <linux/sched/signal.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/gpio/consumer.h> +#include <linux/kernel.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/device.h> @@ -23,11 +26,14 @@ #include <linux/sysrq.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/math64.h> #include <linux/security.h> #include <linux/irq.h> #include <linux/uaccess.h> +#include "serial_base.h" + /* * This is used to lock changes in serial line configuration. */ @@ -41,11 +47,11 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#define SYSRQ_TIMEOUT (HZ * 5) +/* + * Max time with active RTS before/after data is sent. + */ +#define RS485_MAX_RTS_DELAY 100 /* msecs */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - struct ktermios *old_termios); -static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state); @@ -69,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport) wake_up(&uport->state->remove_wait); } -#define uart_port_lock(state, flags) \ - ({ \ - struct uart_port *__uport = uart_port_ref(state); \ - if (__uport) \ - spin_lock_irqsave(&__uport->lock, flags); \ - __uport; \ - }) +static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags) +{ + struct uart_port *uport = uart_port_ref(state); + + if (uport) + uart_port_lock_irqsave(uport, flags); + + return uport; +} -#define uart_port_unlock(uport, flags) \ - ({ \ - struct uart_port *__uport = uport; \ - if (__uport) { \ - spin_unlock_irqrestore(&__uport->lock, flags); \ - uart_port_deref(__uport); \ - } \ - }) +static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags) +{ + if (uport) { + uart_port_unlock_irqrestore(uport, flags); + uart_port_deref(uport); + } +} static inline struct uart_port *uart_port_check(struct uart_state *state) { @@ -92,9 +99,16 @@ static inline struct uart_port *uart_port_check(struct uart_state *state) return state->uart_port; } -/* - * This routine is used by the interrupt handler to schedule processing in - * the software interrupt portion of the driver. +/** + * uart_write_wakeup - schedule write processing + * @port: port to be processed + * + * This routine is used by the interrupt handler to schedule processing in the + * software interrupt portion of the driver. A driver is expected to call this + * function when the number of characters in the transmit buffer have dropped + * below a threshold. + * + * Locking: @port->lock should be held */ void uart_write_wakeup(struct uart_port *port) { @@ -106,6 +120,7 @@ void uart_write_wakeup(struct uart_port *port) BUG_ON(!state); tty_port_tty_wakeup(&state->port); } +EXPORT_SYMBOL(uart_write_wakeup); static void uart_stop(struct tty_struct *tty) { @@ -113,19 +128,39 @@ static void uart_stop(struct tty_struct *tty) struct uart_port *port; unsigned long flags; - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); if (port) port->ops->stop_tx(port); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); } -static void __uart_start(struct tty_struct *tty) +static void __uart_start(struct uart_state *state) { - struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; + struct serial_port_device *port_dev; + int err; - if (port && !uart_tx_stopped(port)) + if (!port || port->flags & UPF_DEAD || uart_tx_stopped(port)) + return; + + port_dev = port->port_dev; + + /* Increment the runtime PM usage count for the active check below */ + err = pm_runtime_get(&port_dev->dev); + if (err < 0 && err != -EINPROGRESS) { + pm_runtime_put_noidle(&port_dev->dev); + return; + } + + /* + * Start TX if enabled, and kick runtime PM. If the device is not + * enabled, serial_port_runtime_resume() calls start_tx() again + * after enabling the device. + */ + if (!pm_runtime_enabled(port->dev) || pm_runtime_active(&port_dev->dev)) port->ops->start_tx(port); + pm_runtime_mark_last_busy(&port_dev->dev); + pm_runtime_put_autosuspend(&port_dev->dev); } static void uart_start(struct tty_struct *tty) @@ -134,68 +169,84 @@ static void uart_start(struct tty_struct *tty) struct uart_port *port; unsigned long flags; - port = uart_port_lock(state, flags); - __uart_start(tty); - uart_port_unlock(port, flags); + port = uart_port_ref_lock(state, &flags); + __uart_start(state); + uart_port_unlock_deref(port, flags); } static void uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) { - unsigned long flags; unsigned int old; - spin_lock_irqsave(&port->lock, flags); + guard(uart_port_lock_irqsave)(port); old = port->mctrl; port->mctrl = (old & ~clear) | set; - if (old != port->mctrl) + if (old != port->mctrl && !(port->rs485.flags & SER_RS485_ENABLED)) port->ops->set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); } #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) #define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) -static void uart_port_dtr_rts(struct uart_port *uport, int raise) +static void uart_port_dtr_rts(struct uart_port *uport, bool active) { - int rs485_on = uport->rs485_config && - (uport->rs485.flags & SER_RS485_ENABLED); - int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND); - - if (raise) { - if (rs485_on && !RTS_after_send) { - uart_set_mctrl(uport, TIOCM_DTR); - uart_clear_mctrl(uport, TIOCM_RTS); - } else { - uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); - } - } else { - unsigned int clear = TIOCM_DTR; - - clear |= (!rs485_on || !RTS_after_send) ? TIOCM_RTS : 0; - uart_clear_mctrl(uport, clear); - } + if (active) + uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + else + uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); } -/* - * Startup the port. This will be called once per open. All calls - * will be serialised by the per-port mutex. - */ -static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, - int init_hw) +/* Caller holds port mutex */ +static void uart_change_line_settings(struct tty_struct *tty, struct uart_state *state, + const struct ktermios *old_termios) { struct uart_port *uport = uart_port_check(state); - unsigned long page; - unsigned long flags = 0; - int retval = 0; + struct ktermios *termios; + bool old_hw_stopped; - if (uport->type == PORT_UNKNOWN) - return 1; + /* + * If we have no tty, termios, or the port does not exist, + * then we can't set the parameters for this port. + */ + if (!tty || uport->type == PORT_UNKNOWN) + return; + + termios = &tty->termios; + uport->ops->set_termios(uport, termios, old_termios); /* - * Make sure the device is in D0 state. + * Set modem status enables based on termios cflag */ - uart_change_pm(state, UART_PM_STATE_ON); + guard(uart_port_lock_irq)(uport); + if (termios->c_cflag & CRTSCTS) + uport->status |= UPSTAT_CTS_ENABLE; + else + uport->status &= ~UPSTAT_CTS_ENABLE; + + if (termios->c_cflag & CLOCAL) + uport->status &= ~UPSTAT_DCD_ENABLE; + else + uport->status |= UPSTAT_DCD_ENABLE; + + /* reset sw-assisted CTS flow control based on (possibly) new mode */ + old_hw_stopped = uport->hw_stopped; + uport->hw_stopped = uart_softcts_mode(uport) && + !(uport->ops->get_mctrl(uport) & TIOCM_CTS); + if (uport->hw_stopped != old_hw_stopped) { + if (!old_hw_stopped) + uport->ops->stop_tx(uport); + else + __uart_start(state); + } +} + +static int uart_alloc_xmit_buf(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + unsigned long flags; + unsigned long page; /* * Initialise and allocate the transmit and temporary @@ -205,37 +256,89 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (!page) return -ENOMEM; - uart_port_lock(state, flags); - if (!state->xmit.buf) { - state->xmit.buf = (unsigned char *) page; - uart_circ_clear(&state->xmit); - uart_port_unlock(uport, flags); + uport = uart_port_ref_lock(state, &flags); + if (!state->port.xmit_buf) { + state->port.xmit_buf = (unsigned char *)page; + kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf, + PAGE_SIZE); + uart_port_unlock_deref(uport, flags); } else { - uart_port_unlock(uport, flags); + uart_port_unlock_deref(uport, flags); /* * Do not free() the page under the port lock, see - * uart_shutdown(). + * uart_free_xmit_buf(). */ free_page(page); } + return 0; +} + +static void uart_free_xmit_buf(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + unsigned long flags; + char *xmit_buf; + + /* + * Do not free() the transmit buffer page under the port lock since + * this can create various circular locking scenarios. For instance, + * console driver may need to allocate/free a debug object, which + * can end up in printk() recursion. + */ + uport = uart_port_ref_lock(state, &flags); + xmit_buf = port->xmit_buf; + port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); + uart_port_unlock_deref(uport, flags); + + free_page((unsigned long)xmit_buf); +} + +/* + * Startup the port. This will be called once per open. All calls + * will be serialised by the per-port mutex. + */ +static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, + bool init_hw) +{ + struct uart_port *uport = uart_port_check(state); + int retval; + + if (uport->type == PORT_UNKNOWN) + return 1; + + /* + * Make sure the device is in D0 state. + */ + uart_change_pm(state, UART_PM_STATE_ON); + + retval = uart_alloc_xmit_buf(&state->port); + if (retval) + return retval; + retval = uport->ops->startup(uport); if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { tty->termios.c_cflag = uport->cons->cflag; + tty->termios.c_ispeed = uport->cons->ispeed; + tty->termios.c_ospeed = uport->cons->ospeed; uport->cons->cflag = 0; + uport->cons->ispeed = 0; + uport->cons->ospeed = 0; } /* * Initialise the hardware port settings. */ - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); /* * Setup the RTS and DTR signals once the * port is open and ready to respond. */ if (init_hw && C_BAUD(tty)) - uart_port_dtr_rts(uport, 1); + uart_port_dtr_rts(uport, true); } /* @@ -250,19 +353,29 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, } static int uart_startup(struct tty_struct *tty, struct uart_state *state, - int init_hw) + bool init_hw) { struct tty_port *port = &state->port; + struct uart_port *uport; int retval; if (tty_port_initialized(port)) - return 0; + goto out_base_port_startup; retval = uart_port_startup(tty, state, init_hw); - if (retval) + if (retval) { set_bit(TTY_IO_ERROR, &tty->flags); + return retval; + } - return retval; +out_base_port_startup: + uport = uart_port_check(state); + if (!uport) + return -EIO; + + serial_base_port_startup(uport); + + return 0; } /* @@ -276,8 +389,6 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) { struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port; - unsigned long flags = 0; - char *xmit_buf = NULL; /* * Set the TTY IO error marker @@ -285,17 +396,25 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) if (tty) set_bit(TTY_IO_ERROR, &tty->flags); + if (uport) + serial_base_port_shutdown(uport); + if (tty_port_initialized(port)) { - tty_port_set_initialized(port, 0); + tty_port_set_initialized(port, false); /* * Turn off DTR and RTS early. */ - if (uport && uart_console(uport) && tty) - uport->cons->cflag = tty->termios.c_cflag; + if (uport) { + if (uart_console(uport) && tty) { + uport->cons->cflag = tty->termios.c_cflag; + uport->cons->ispeed = tty->termios.c_ispeed; + uport->cons->ospeed = tty->termios.c_ospeed; + } - if (!tty || C_HUPCL(tty)) - uart_port_dtr_rts(uport, 0); + if (!tty || C_HUPCL(tty)) + uart_port_dtr_rts(uport, false); + } uart_port_shutdown(port); } @@ -305,95 +424,58 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) * a DCD drop (hangup) at just the right time. Clear suspended bit so * we don't try to resume a port that has been shutdown. */ - tty_port_set_suspended(port, 0); + tty_port_set_suspended(port, false); - /* - * Do not free() the transmit buffer page under the port lock since - * this can create various circular locking scenarios. For instance, - * console driver may need to allocate/free a debug object, which - * can endup in printk() recursion. - */ - uart_port_lock(state, flags); - xmit_buf = state->xmit.buf; - state->xmit.buf = NULL; - uart_port_unlock(uport, flags); - - if (xmit_buf) - free_page((unsigned long)xmit_buf); + uart_free_xmit_buf(port); } /** - * uart_update_timeout - update per-port FIFO timeout. - * @port: uart_port structure describing the port - * @cflag: termios cflag value - * @baud: speed of the port + * uart_update_timeout - update per-port frame timing information + * @port: uart_port structure describing the port + * @cflag: termios cflag value + * @baud: speed of the port + * + * Set the @port frame timing information from which the FIFO timeout value is + * derived. The @cflag value should reflect the actual hardware settings as + * number of bits, parity, stop bits and baud rate is taken into account here. * - * Set the port FIFO timeout value. The @cflag value should - * reflect the actual hardware settings. + * Locking: caller is expected to take @port->lock */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud) { - unsigned int bits; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: - bits = 7; - break; - case CS6: - bits = 8; - break; - case CS7: - bits = 9; - break; - default: - bits = 10; - break; /* CS8 */ - } - - if (cflag & CSTOPB) - bits++; - if (cflag & PARENB) - bits++; - - /* - * The total number of bits to be transmitted in the fifo. - */ - bits = bits * port->fifosize; + u64 temp = tty_get_frame_size(cflag); - /* - * Figure the timeout to send the above number of bits. - * Add .02 seconds of slop - */ - port->timeout = (HZ * bits) / baud + HZ/50; + temp *= NSEC_PER_SEC; + port->frame_time = (unsigned int)DIV64_U64_ROUND_UP(temp, baud); } - EXPORT_SYMBOL(uart_update_timeout); /** - * uart_get_baud_rate - return baud rate for a particular port - * @port: uart_port structure describing the port in question. - * @termios: desired termios settings. - * @old: old termios (or NULL) - * @min: minimum acceptable baud rate - * @max: maximum acceptable baud rate + * uart_get_baud_rate - return baud rate for a particular port + * @port: uart_port structure describing the port in question. + * @termios: desired termios settings + * @old: old termios (or %NULL) + * @min: minimum acceptable baud rate + * @max: maximum acceptable baud rate + * + * 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. * - * 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. If that is also invalid 0 is returned. * - * If the new baud rate is invalid, try the old termios setting. - * If it's still invalid, we try 9600 baud. + * The @termios structure is updated to reflect the baud rate we're actually + * going to be using. Don't do this for the case where B0 is requested ("hang + * up"). * - * Update the @termios structure to reflect the baud rate - * we're actually going to be using. Don't do this for the case - * where B0 is requested ("hang up"). + * Locking: caller dependent */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old, unsigned int min, unsigned int max) + const struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try; unsigned int baud; @@ -467,19 +549,22 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, max - 1, max - 1); } } - /* Should never happen */ - WARN_ON(1); return 0; } - EXPORT_SYMBOL(uart_get_baud_rate); /** - * uart_get_divisor - return uart clock divisor - * @port: uart_port structure describing the port. - * @baud: desired baud rate + * uart_get_divisor - return uart clock divisor + * @port: uart_port structure describing the port + * @baud: desired baud rate * - * Calculate the uart clock divisor for the port. + * Calculate the divisor (baud_base / baud) for the specified @baud, + * appropriately rounded. + * + * If 38400 baud and custom divisor is selected, return the custom divisor + * instead. + * + * Locking: caller dependent */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud) @@ -496,76 +581,24 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) return quot; } - EXPORT_SYMBOL(uart_get_divisor); -/* Caller holds port mutex */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - struct ktermios *old_termios) -{ - struct uart_port *uport = uart_port_check(state); - struct ktermios *termios; - int hw_stopped; - - /* - * If we have no tty, termios, or the port does not exist, - * then we can't set the parameters for this port. - */ - if (!tty || uport->type == PORT_UNKNOWN) - return; - - termios = &tty->termios; - uport->ops->set_termios(uport, termios, old_termios); - - /* - * Set modem status enables based on termios cflag - */ - spin_lock_irq(&uport->lock); - if (termios->c_cflag & CRTSCTS) - uport->status |= UPSTAT_CTS_ENABLE; - else - uport->status &= ~UPSTAT_CTS_ENABLE; - - if (termios->c_cflag & CLOCAL) - uport->status &= ~UPSTAT_DCD_ENABLE; - else - uport->status |= UPSTAT_DCD_ENABLE; - - /* reset sw-assisted CTS flow control based on (possibly) new mode */ - hw_stopped = uport->hw_stopped; - uport->hw_stopped = uart_softcts_mode(uport) && - !(uport->ops->get_mctrl(uport) & TIOCM_CTS); - if (uport->hw_stopped) { - if (!hw_stopped) - uport->ops->stop_tx(uport); - } else { - if (hw_stopped) - __uart_start(tty); - } - spin_unlock_irq(&uport->lock); -} - -static int uart_put_char(struct tty_struct *tty, unsigned char c) +static int uart_put_char(struct tty_struct *tty, u8 c) { struct uart_state *state = tty->driver_data; struct uart_port *port; - struct circ_buf *circ; unsigned long flags; int ret = 0; - circ = &state->xmit; - port = uart_port_lock(state, flags); - if (!circ->buf) { - uart_port_unlock(port, flags); + port = uart_port_ref_lock(state, &flags); + if (!state->port.xmit_buf) { + uart_port_unlock_deref(port, flags); return 0; } - if (port && uart_circ_chars_free(circ) != 0) { - circ->buf[circ->head] = c; - circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); - ret = 1; - } - uart_port_unlock(port, flags); + if (port) + ret = kfifo_put(&state->port.xmit_fifo, c); + uart_port_unlock_deref(port, flags); return ret; } @@ -574,72 +607,57 @@ static void uart_flush_chars(struct tty_struct *tty) uart_start(tty); } -static int uart_write(struct tty_struct *tty, - const unsigned char *buf, int count) +static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count) { struct uart_state *state = tty->driver_data; struct uart_port *port; - struct circ_buf *circ; unsigned long flags; - int c, ret = 0; + int ret = 0; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ - if (!state) { - WARN_ON(1); + if (WARN_ON(!state)) return -EL3HLT; - } - port = uart_port_lock(state, flags); - circ = &state->xmit; - if (!circ->buf) { - uart_port_unlock(port, flags); + port = uart_port_ref_lock(state, &flags); + if (!state->port.xmit_buf) { + uart_port_unlock_deref(port, flags); return 0; } - while (port) { - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(circ->buf + circ->head, buf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } + if (port) + ret = kfifo_in(&state->port.xmit_fifo, buf, count); - __uart_start(tty); - uart_port_unlock(port, flags); + __uart_start(state); + uart_port_unlock_deref(port, flags); return ret; } -static int uart_write_room(struct tty_struct *tty) +static unsigned int uart_write_room(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port; unsigned long flags; - int ret; + unsigned int ret; - port = uart_port_lock(state, flags); - ret = uart_circ_chars_free(&state->xmit); - uart_port_unlock(port, flags); + port = uart_port_ref_lock(state, &flags); + ret = kfifo_avail(&state->port.xmit_fifo); + uart_port_unlock_deref(port, flags); return ret; } -static int uart_chars_in_buffer(struct tty_struct *tty) +static unsigned int uart_chars_in_buffer(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port; unsigned long flags; - int ret; + unsigned int ret; - port = uart_port_lock(state, flags); - ret = uart_circ_chars_pending(&state->xmit); - uart_port_unlock(port, flags); + port = uart_port_ref_lock(state, &flags); + ret = kfifo_len(&state->port.xmit_fifo); + uart_port_unlock_deref(port, flags); return ret; } @@ -653,32 +671,43 @@ static void uart_flush_buffer(struct tty_struct *tty) * This means you called this function _after_ the port was * closed. No cookie for you. */ - if (!state) { - WARN_ON(1); + if (WARN_ON(!state)) return; - } pr_debug("uart_flush_buffer(%d) called\n", tty->index); - port = uart_port_lock(state, flags); + port = uart_port_ref_lock(state, &flags); if (!port) return; - uart_circ_clear(&state->xmit); + kfifo_reset(&state->port.xmit_fifo); if (port->ops->flush_buffer) port->ops->flush_buffer(port); - uart_port_unlock(port, flags); + uart_port_unlock_deref(port, flags); tty_port_tty_wakeup(&state->port); } /* + * This function performs low-level write of high-priority XON/XOFF + * character and accounting for it. + * + * Requires uart_port to implement .serial_out(). + */ +void uart_xchar_out(struct uart_port *uport, int offset) +{ + serial_port_out(uport, offset, uport->x_char); + uport->icount.tx++; + uport->x_char = 0; +} +EXPORT_SYMBOL_GPL(uart_xchar_out); + +/* * This function is used to send a high-priority XON/XOFF character to * the device */ -static void uart_send_xchar(struct tty_struct *tty, char ch) +static void uart_send_xchar(struct tty_struct *tty, u8 ch) { struct uart_state *state = tty->driver_data; struct uart_port *port; - unsigned long flags; port = uart_port_ref(state); if (!port) @@ -687,11 +716,10 @@ static void uart_send_xchar(struct tty_struct *tty, char ch) if (port->ops->send_xchar) port->ops->send_xchar(port, ch); else { - spin_lock_irqsave(&port->lock, flags); + guard(uart_port_lock_irqsave)(port); port->x_char = ch; if (ch) port->ops->start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); } uart_port_deref(port); } @@ -758,18 +786,18 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport; - int ret = -ENODEV; - memset(retinfo, 0, sizeof(*retinfo)); + /* Initialize structure in case we error out later to prevent any stack info leakage. */ + *retinfo = (struct serial_struct){}; /* * Ensure the state we copy is consistent and no hardware changes * occur as we go */ - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); uport = uart_port_check(state); if (!uport) - goto out; + return -ENODEV; retinfo->type = uport->type; retinfo->line = uport->line; @@ -790,10 +818,7 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo) retinfo->iomem_reg_shift = uport->regshift; retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; - ret = 0; -out: - mutex_unlock(&port->mutex); - return ret; + return 0; } static int uart_get_info_user(struct tty_struct *tty, @@ -805,16 +830,71 @@ static int uart_get_info_user(struct tty_struct *tty, return uart_get_info(port, ss) < 0 ? -EIO : 0; } +static int uart_change_port(struct uart_port *uport, + const struct serial_struct *new_info, + unsigned long new_port) +{ + unsigned long old_iobase, old_mapbase; + unsigned int old_type, old_iotype, old_hub6, old_shift; + int retval; + + old_iobase = uport->iobase; + old_mapbase = uport->mapbase; + old_type = uport->type; + old_hub6 = uport->hub6; + old_iotype = uport->iotype; + old_shift = uport->regshift; + + if (old_type != PORT_UNKNOWN && uport->ops->release_port) + uport->ops->release_port(uport); + + uport->iobase = new_port; + uport->type = new_info->type; + uport->hub6 = new_info->hub6; + uport->iotype = new_info->io_type; + uport->regshift = new_info->iomem_reg_shift; + uport->mapbase = (unsigned long)new_info->iomem_base; + + if (uport->type == PORT_UNKNOWN || !uport->ops->request_port) + return 0; + + retval = uport->ops->request_port(uport); + if (retval == 0) + return 0; /* succeeded => done */ + + /* + * If we fail to request resources for the new port, try to restore the + * old settings. + */ + uport->iobase = old_iobase; + uport->type = old_type; + uport->hub6 = old_hub6; + uport->iotype = old_iotype; + uport->regshift = old_shift; + uport->mapbase = old_mapbase; + + if (old_type == PORT_UNKNOWN) + return retval; + + retval = uport->ops->request_port(uport); + /* If we failed to restore the old settings, we fail like this. */ + if (retval) + uport->type = PORT_UNKNOWN; + + /* We failed anyway. */ + return -EBUSY; +} + static int uart_set_info(struct tty_struct *tty, struct tty_port *port, struct uart_state *state, struct serial_struct *new_info) { struct uart_port *uport = uart_port_check(state); unsigned long new_port; - unsigned int change_irq, change_port, closing_wait; - unsigned int old_custom_divisor, close_delay; + unsigned int old_custom_divisor, close_delay, closing_wait; + bool change_irq, change_port; upf_t old_flags, new_flags; - int retval = 0; + int retval; if (!uport) return -EIO; @@ -850,8 +930,13 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, new_flags = (__force upf_t)new_info->flags; old_custom_divisor = uport->custom_divisor; + if (!(uport->flags & UPF_FIXED_PORT)) { + unsigned int uartclk = new_info->baud_base * 16; + /* check needs to be done here before other settings made */ + if (uartclk == 0) + return -EINVAL; + } if (!capable(CAP_SYS_ADMIN)) { - retval = -EPERM; if (change_irq || change_port || (new_info->baud_base != uport->uartclk / 16) || (close_delay != port->close_delay) || @@ -859,38 +944,34 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, (new_info->xmit_fifo_size && new_info->xmit_fifo_size != uport->fifosize) || (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) - goto exit; + return -EPERM; uport->flags = ((uport->flags & ~UPF_USR_MASK) | (new_flags & UPF_USR_MASK)); uport->custom_divisor = new_info->custom_divisor; goto check_and_exit; } - retval = security_locked_down(LOCKDOWN_TIOCSSERIAL); - if (retval && (change_irq || change_port)) - goto exit; + if (change_irq || change_port) { + retval = security_locked_down(LOCKDOWN_TIOCSSERIAL); + if (retval) + return retval; + } - /* - * Ask the low level driver to verify the settings. - */ - if (uport->ops->verify_port) + /* Ask the low level driver to verify the settings. */ + if (uport->ops->verify_port) { retval = uport->ops->verify_port(uport, new_info); + if (retval) + return retval; + } - if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) || + if ((new_info->irq >= irq_get_nr_irqs()) || (new_info->irq < 0) || (new_info->baud_base < 9600)) - retval = -EINVAL; - - if (retval) - goto exit; + return -EINVAL; if (change_port || change_irq) { - retval = -EBUSY; - - /* - * Make sure that we are the sole user of this port. - */ + /* Make sure that we are the sole user of this port. */ if (tty_port_users(port) > 1) - goto exit; + return -EBUSY; /* * We need to shutdown the serial port at the old @@ -900,69 +981,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, } if (change_port) { - unsigned long old_iobase, old_mapbase; - unsigned int old_type, old_iotype, old_hub6, old_shift; - - old_iobase = uport->iobase; - old_mapbase = uport->mapbase; - old_type = uport->type; - old_hub6 = uport->hub6; - old_iotype = uport->iotype; - old_shift = uport->regshift; - - /* - * Free and release old regions - */ - if (old_type != PORT_UNKNOWN && uport->ops->release_port) - uport->ops->release_port(uport); - - uport->iobase = new_port; - uport->type = new_info->type; - uport->hub6 = new_info->hub6; - uport->iotype = new_info->io_type; - uport->regshift = new_info->iomem_reg_shift; - uport->mapbase = (unsigned long)new_info->iomem_base; - - /* - * Claim and map the new regions - */ - if (uport->type != PORT_UNKNOWN && uport->ops->request_port) { - retval = uport->ops->request_port(uport); - } else { - /* Always success - Jean II */ - retval = 0; - } - - /* - * If we fail to request resources for the - * new port, try to restore the old settings. - */ - if (retval) { - uport->iobase = old_iobase; - uport->type = old_type; - uport->hub6 = old_hub6; - uport->iotype = old_iotype; - uport->regshift = old_shift; - uport->mapbase = old_mapbase; - - if (old_type != PORT_UNKNOWN) { - retval = uport->ops->request_port(uport); - /* - * If we failed to restore the old settings, - * we fail like this. - */ - if (retval) - uport->type = PORT_UNKNOWN; - - /* - * We failed anyway. - */ - retval = -EBUSY; - } - - /* Added to return the correct error -Ram Gupta */ - goto exit; - } + retval = uart_change_port(uport, new_info, new_port); + if (retval) + return retval; } if (change_irq) @@ -976,12 +997,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, port->closing_wait = closing_wait; if (new_info->xmit_fifo_size) uport->fifosize = new_info->xmit_fifo_size; - port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; check_and_exit: - retval = 0; if (uport->type == PORT_UNKNOWN) - goto exit; + return 0; + if (tty_port_initialized(port)) { if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || old_custom_divisor != uport->custom_divisor) { @@ -995,26 +1015,27 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, current->comm, tty_name(port->tty)); } - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); } - } else { - retval = uart_startup(tty, state, 1); - if (retval == 0) - tty_port_set_initialized(port, true); - if (retval > 0) - retval = 0; + + return 0; } - exit: - return retval; + + retval = uart_startup(tty, state, true); + if (retval < 0) + return retval; + if (retval == 0) + tty_port_set_initialized(port, true); + + return 0; } static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss) { struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; - int retval; - down_write(&tty->termios_rwsem); + guard(rwsem_write)(&tty->termios_rwsem); /* * This semaphore protects port->count. It is also * very useful to prevent opens. Also, take the @@ -1022,18 +1043,15 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss) * module insertion/removal doesn't change anything * under us. */ - mutex_lock(&port->mutex); - retval = uart_set_info(tty, port, state, ss); - mutex_unlock(&port->mutex); - up_write(&tty->termios_rwsem); - return retval; + guard(mutex)(&port->mutex); + return uart_set_info(tty, port, state, ss); } /** - * uart_get_lsr_info - get line status register info - * @tty: tty associated with the UART - * @state: UART being queried - * @value: returned modem value + * uart_get_lsr_info - get line status register info + * @tty: tty associated with the UART + * @state: UART being queried + * @value: returned modem value */ static int uart_get_lsr_info(struct tty_struct *tty, struct uart_state *state, unsigned int __user *value) @@ -1050,7 +1068,7 @@ static int uart_get_lsr_info(struct tty_struct *tty, * interrupt happens). */ if (uport->x_char || - ((uart_circ_chars_pending(&state->xmit) > 0) && + (!kfifo_is_empty(&state->port.xmit_fifo) && !uart_tx_stopped(uport))) result &= ~TIOCSER_TEMT; @@ -1062,22 +1080,16 @@ static int uart_tiocmget(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; - int result = -EIO; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); + uport = uart_port_check(state); - if (!uport) - goto out; + if (!uport || tty_io_error(tty)) + return -EIO; - if (!tty_io_error(tty)) { - result = uport->mctrl; - spin_lock_irq(&uport->lock); - result |= uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); - } -out: - mutex_unlock(&port->mutex); - return result; + guard(uart_port_lock_irq)(uport); + + return uport->mctrl | uport->ops->get_mctrl(uport); } static int @@ -1086,20 +1098,16 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; - int ret = -EIO; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); + uport = uart_port_check(state); - if (!uport) - goto out; + if (!uport || tty_io_error(tty)) + return -EIO; - if (!tty_io_error(tty)) { - uart_update_mctrl(uport, set, clear); - ret = 0; - } -out: - mutex_unlock(&port->mutex); - return ret; + uart_update_mctrl(uport, set, clear); + + return 0; } static int uart_break_ctl(struct tty_struct *tty, int break_state) @@ -1107,22 +1115,20 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state) struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; - int ret = -EIO; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); + uport = uart_port_check(state); if (!uport) - goto out; + return -EIO; if (uport->type != PORT_UNKNOWN && uport->ops->break_ctl) uport->ops->break_ctl(uport, break_state); - ret = 0; -out: - mutex_unlock(&port->mutex); - return ret; + + return 0; } -static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) +static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state) { struct tty_port *port = &state->port; struct uart_port *uport; @@ -1136,17 +1142,14 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) * changing, and hence any extra opens of the port while * we're auto-configuring. */ - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; + scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) { + uport = uart_port_check(state); + if (!uport) + return -EIO; - uport = uart_port_check(state); - if (!uport) { - ret = -EIO; - goto out; - } + if (tty_port_users(port) != 1) + return -EBUSY; - ret = -EBUSY; - if (tty_port_users(port) == 1) { uart_shutdown(tty, state); /* @@ -1166,15 +1169,16 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) */ uport->ops->config_port(uport, flags); - ret = uart_startup(tty, state, 1); - if (ret == 0) - tty_port_set_initialized(port, true); + ret = uart_startup(tty, state, true); + if (ret < 0) + return ret; if (ret > 0) - ret = 0; + return 0; + + tty_port_set_initialized(port, true); } -out: - mutex_unlock(&port->mutex); - return ret; + + return 0; } static void uart_enable_ms(struct uart_port *uport) @@ -1209,16 +1213,15 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) uport = uart_port_ref(state); if (!uport) return -EIO; - spin_lock_irq(&uport->lock); - memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - uart_enable_ms(uport); - spin_unlock_irq(&uport->lock); + scoped_guard(uart_port_lock_irq, uport) { + memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); + uart_enable_ms(uport); + } add_wait_queue(&port->delta_msr_wait, &wait); for (;;) { - spin_lock_irq(&uport->lock); - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&uport->lock); + scoped_guard(uart_port_lock_irq, uport) + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); set_current_state(TASK_INTERRUPTIBLE); @@ -1259,14 +1262,13 @@ static int uart_get_icount(struct tty_struct *tty, struct uart_state *state = tty->driver_data; struct uart_icount cnow; struct uart_port *uport; + unsigned long flags; - uport = uart_port_ref(state); + uport = uart_port_ref_lock(state, &flags); if (!uport) return -EIO; - spin_lock_irq(&uport->lock); memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&uport->lock); - uart_port_deref(uport); + uart_port_unlock_deref(uport, flags); icount->cts = cnow.cts; icount->dsr = cnow.dsr; @@ -1283,15 +1285,165 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +#define SER_RS485_LEGACY_FLAGS (SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | \ + SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX | \ + SER_RS485_TERMINATE_BUS) + +static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *rs485) +{ + u32 flags = rs485->flags; + + /* Don't return -EINVAL for unsupported legacy flags */ + flags &= ~SER_RS485_LEGACY_FLAGS; + + /* + * For any bit outside of the legacy ones that is not supported by + * the driver, return -EINVAL. + */ + if (flags & ~port->rs485_supported.flags) + return -EINVAL; + + /* Asking for address w/o addressing mode? */ + if (!(rs485->flags & SER_RS485_ADDRB) && + (rs485->flags & (SER_RS485_ADDR_RECV|SER_RS485_ADDR_DEST))) + return -EINVAL; + + /* Address given but not enabled? */ + if (!(rs485->flags & SER_RS485_ADDR_RECV) && rs485->addr_recv) + return -EINVAL; + if (!(rs485->flags & SER_RS485_ADDR_DEST) && rs485->addr_dest) + return -EINVAL; + + return 0; +} + +static void uart_sanitize_serial_rs485_delays(struct uart_port *port, + struct serial_rs485 *rs485) +{ + if (!port->rs485_supported.delay_rts_before_send) { + if (rs485->delay_rts_before_send) { + dev_warn_ratelimited(port->dev, + "%s (%u): RTS delay before sending not supported\n", + port->name, port->line); + } + rs485->delay_rts_before_send = 0; + } else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) { + rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%u): RTS delay before sending clamped to %u ms\n", + port->name, port->line, rs485->delay_rts_before_send); + } + + if (!port->rs485_supported.delay_rts_after_send) { + if (rs485->delay_rts_after_send) { + dev_warn_ratelimited(port->dev, + "%s (%u): RTS delay after sending not supported\n", + port->name, port->line); + } + rs485->delay_rts_after_send = 0; + } else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) { + rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%u): RTS delay after sending clamped to %u ms\n", + port->name, port->line, rs485->delay_rts_after_send); + } +} + +static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485) +{ + u32 supported_flags = port->rs485_supported.flags; + + if (!(rs485->flags & SER_RS485_ENABLED)) { + memset(rs485, 0, sizeof(*rs485)); + return; + } + + /* Clear other RS485 flags but SER_RS485_TERMINATE_BUS and return if enabling RS422 */ + if (rs485->flags & SER_RS485_MODE_RS422) { + rs485->flags &= (SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_TERMINATE_BUS); + return; + } + + rs485->flags &= supported_flags; + + /* Pick sane settings if the user hasn't */ + if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == + !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { + if (supported_flags & SER_RS485_RTS_ON_SEND) { + rs485->flags |= SER_RS485_RTS_ON_SEND; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + dev_warn_ratelimited(port->dev, + "%s (%u): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + } else { + rs485->flags |= SER_RS485_RTS_AFTER_SEND; + rs485->flags &= ~SER_RS485_RTS_ON_SEND; + + dev_warn_ratelimited(port->dev, + "%s (%u): invalid RTS setting, using RTS_AFTER_SEND instead\n", + port->name, port->line); + } + } + + uart_sanitize_serial_rs485_delays(port, rs485); + + /* Return clean padding area to userspace */ + memset(rs485->padding0, 0, sizeof(rs485->padding0)); + memset(rs485->padding1, 0, sizeof(rs485->padding1)); +} + +static void uart_set_rs485_termination(struct uart_port *port, + const struct serial_rs485 *rs485) +{ + if (!(rs485->flags & SER_RS485_ENABLED)) + return; + + gpiod_set_value_cansleep(port->rs485_term_gpio, + !!(rs485->flags & SER_RS485_TERMINATE_BUS)); +} + +static void uart_set_rs485_rx_during_tx(struct uart_port *port, + const struct serial_rs485 *rs485) +{ + if (!(rs485->flags & SER_RS485_ENABLED)) + return; + + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, + !!(rs485->flags & SER_RS485_RX_DURING_TX)); +} + +static int uart_rs485_config(struct uart_port *port) +{ + struct serial_rs485 *rs485 = &port->rs485; + int ret; + + if (!(rs485->flags & SER_RS485_ENABLED)) + return 0; + + uart_sanitize_serial_rs485(port, rs485); + uart_set_rs485_termination(port, rs485); + uart_set_rs485_rx_during_tx(port, rs485); + + scoped_guard(uart_port_lock_irqsave, port) + ret = port->rs485_config(port, NULL, rs485); + if (ret) { + memset(rs485, 0, sizeof(*rs485)); + /* unset GPIOs */ + gpiod_set_value_cansleep(port->rs485_term_gpio, 0); + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, 0); + } + + return ret; +} + static int uart_get_rs485_config(struct uart_port *port, struct serial_rs485 __user *rs485) { - unsigned long flags; struct serial_rs485 aux; - spin_lock_irqsave(&port->lock, flags); - aux = port->rs485; - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(uart_port_lock_irqsave, port) + aux = port->rs485; if (copy_to_user(rs485, &aux, sizeof(aux))) return -EFAULT; @@ -1299,24 +1451,43 @@ static int uart_get_rs485_config(struct uart_port *port, return 0; } -static int uart_set_rs485_config(struct uart_port *port, +static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, struct serial_rs485 __user *rs485_user) { struct serial_rs485 rs485; int ret; - unsigned long flags; - if (!port->rs485_config) - return -ENOIOCTLCMD; + if (!(port->rs485_supported.flags & SER_RS485_ENABLED)) + return -ENOTTY; if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT; - spin_lock_irqsave(&port->lock, flags); - ret = port->rs485_config(port, &rs485); - spin_unlock_irqrestore(&port->lock, flags); + ret = uart_check_rs485_flags(port, &rs485); if (ret) return ret; + uart_sanitize_serial_rs485(port, &rs485); + uart_set_rs485_termination(port, &rs485); + uart_set_rs485_rx_during_tx(port, &rs485); + + scoped_guard(uart_port_lock_irqsave, port) { + ret = port->rs485_config(port, &tty->termios, &rs485); + if (!ret) { + port->rs485 = rs485; + + /* Reset RTS and other mctrl lines when disabling RS485 */ + if (!(rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } + } + if (ret) { + /* restore old GPIO settings */ + gpiod_set_value_cansleep(port->rs485_term_gpio, + !!(port->rs485.flags & SER_RS485_TERMINATE_BUS)); + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, + !!(port->rs485.flags & SER_RS485_RX_DURING_TX)); + return ret; + } if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) return -EFAULT; @@ -1327,15 +1498,13 @@ static int uart_set_rs485_config(struct uart_port *port, static int uart_get_iso7816_config(struct uart_port *port, struct serial_iso7816 __user *iso7816) { - unsigned long flags; struct serial_iso7816 aux; if (!port->iso7816_config) - return -ENOIOCTLCMD; + return -ENOTTY; - spin_lock_irqsave(&port->lock, flags); - aux = port->iso7816; - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(uart_port_lock_irqsave, port) + aux = port->iso7816; if (copy_to_user(iso7816, &aux, sizeof(aux))) return -EFAULT; @@ -1347,11 +1516,10 @@ static int uart_set_iso7816_config(struct uart_port *port, struct serial_iso7816 __user *iso7816_user) { struct serial_iso7816 iso7816; - int i, ret; - unsigned long flags; + int i; if (!port->iso7816_config) - return -ENOIOCTLCMD; + return -ENOTTY; if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user))) return -EFAULT; @@ -1360,15 +1528,15 @@ static int uart_set_iso7816_config(struct uart_port *port, * There are 5 words reserved for future use. Check that userspace * doesn't put stuff in there to prevent breakages in the future. */ - for (i = 0; i < 5; i++) + for (i = 0; i < ARRAY_SIZE(iso7816.reserved); i++) if (iso7816.reserved[i]) return -EINVAL; - spin_lock_irqsave(&port->lock, flags); - ret = port->iso7816_config(port, &iso7816); - spin_unlock_irqrestore(&port->lock, flags); - if (ret) - return ret; + scoped_guard(uart_port_lock_irqsave, port) { + int ret = port->iso7816_config(port, &iso7816); + if (ret) + return ret; + } if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816))) return -EFAULT; @@ -1388,79 +1556,66 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD; - - /* - * These ioctls don't rely on the hardware to be present. - */ - switch (cmd) { - case TIOCSERCONFIG: - down_write(&tty->termios_rwsem); - ret = uart_do_autoconfig(tty, state); - up_write(&tty->termios_rwsem); - break; + /* This ioctl doesn't rely on the hardware to be present. */ + if (cmd == TIOCSERCONFIG) { + guard(rwsem_write)(&tty->termios_rwsem); + return uart_do_autoconfig(tty, state); } - if (ret != -ENOIOCTLCMD) - goto out; + if (tty_io_error(tty)) + return -EIO; - if (tty_io_error(tty)) { - ret = -EIO; - goto out; - } + /* This should only be used when the hardware is present. */ + if (cmd == TIOCMIWAIT) + return uart_wait_modem_status(state, arg); - /* - * The following should only be used when hardware is present. - */ - switch (cmd) { - case TIOCMIWAIT: - ret = uart_wait_modem_status(state, arg); - break; - } - - if (ret != -ENOIOCTLCMD) - goto out; + /* rs485_config requires more locking than others */ + if (cmd == TIOCSRS485) + down_write(&tty->termios_rwsem); - mutex_lock(&port->mutex); - uport = uart_port_check(state); + scoped_guard(mutex, &port->mutex) { + uport = uart_port_check(state); - if (!uport || tty_io_error(tty)) { - ret = -EIO; - goto out_up; - } + if (!uport || tty_io_error(tty)) { + ret = -EIO; + break; + } - /* - * All these rely on hardware being present and need to be - * protected against the tty being hung up. - */ + /* + * All these rely on hardware being present and need to be + * protected against the tty being hung up. + */ - switch (cmd) { - case TIOCSERGETLSR: /* Get line status register */ - ret = uart_get_lsr_info(tty, state, uarg); - break; + switch (cmd) { + case TIOCSERGETLSR: /* Get line status register */ + ret = uart_get_lsr_info(tty, state, uarg); + break; - case TIOCGRS485: - ret = uart_get_rs485_config(uport, uarg); - break; + case TIOCGRS485: + ret = uart_get_rs485_config(uport, uarg); + break; - case TIOCSRS485: - ret = uart_set_rs485_config(uport, uarg); - break; + case TIOCSRS485: + ret = uart_set_rs485_config(tty, uport, uarg); + break; - case TIOCSISO7816: - ret = uart_set_iso7816_config(state->uart_port, uarg); - break; + case TIOCSISO7816: + ret = uart_set_iso7816_config(state->uart_port, uarg); + break; - case TIOCGISO7816: - ret = uart_get_iso7816_config(state->uart_port, uarg); - break; - default: - if (uport->ops->ioctl) - ret = uport->ops->ioctl(uport, cmd, arg); - break; + case TIOCGISO7816: + ret = uart_get_iso7816_config(state->uart_port, uarg); + break; + default: + if (uport->ops->ioctl) + ret = uport->ops->ioctl(uport, cmd, arg); + break; + } } -out_up: - mutex_unlock(&port->mutex); -out: + + if (cmd == TIOCSRS485) + up_write(&tty->termios_rwsem); + return ret; } @@ -1468,16 +1623,19 @@ static void uart_set_ldisc(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *uport; + struct tty_port *port = &state->port; + + if (!tty_port_initialized(port)) + return; - mutex_lock(&state->port.mutex); + guard(mutex)(&state->port.mutex); uport = uart_port_check(state); if (uport && uport->ops->set_ldisc) uport->ops->set_ldisc(uport, &tty->termios); - mutex_unlock(&state->port.mutex); } static void uart_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; struct uart_port *uport; @@ -1485,10 +1643,11 @@ static void uart_set_termios(struct tty_struct *tty, unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK; bool sw_changed = false; - mutex_lock(&state->port.mutex); + guard(mutex)(&state->port.mutex); + uport = uart_port_check(state); if (!uport) - goto out; + return; /* * Drivers doing software flow control also need to know @@ -1511,26 +1670,24 @@ static void uart_set_termios(struct tty_struct *tty, tty->termios.c_ospeed == old_termios->c_ospeed && tty->termios.c_ispeed == old_termios->c_ispeed && ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 && - !sw_changed) { - goto out; - } + !sw_changed) + return; - uart_change_speed(tty, state, old_termios); + uart_change_line_settings(tty, state, old_termios); /* reload cflag from termios; port driver may have overridden flags */ cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + if (((old_termios->c_cflag & CBAUD) != B0) && ((cflag & CBAUD) == B0)) uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR); /* Handle transition away from B0 status */ - else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + else if (((old_termios->c_cflag & CBAUD) == B0) && ((cflag & CBAUD) != B0)) { unsigned int mask = TIOCM_DTR; + if (!(cflag & CRTSCTS) || !tty_throttled(tty)) mask |= TIOCM_RTS; uart_set_mctrl(uport, mask); } -out: - mutex_unlock(&state->port.mutex); } /* @@ -1548,9 +1705,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) state = drv->state + tty->index; port = &state->port; - spin_lock_irq(&port->lock); + guard(spinlock_irq)(&port->lock); --port->count; - spin_unlock_irq(&port->lock); return; } @@ -1571,10 +1727,10 @@ static void uart_tty_port_shutdown(struct tty_port *port) if (WARN(!uport, "detached port still initialized!\n")) return; - spin_lock_irq(&uport->lock); - uport->ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); + scoped_guard(uart_port_lock_irq, uport) + uport->ops->stop_rx(uport); + serial_base_port_shutdown(uport); uart_port_shutdown(port); /* @@ -1582,17 +1738,18 @@ static void uart_tty_port_shutdown(struct tty_port *port) * a DCD drop (hangup) at just the right time. Clear suspended bit so * we don't try to resume a port that has been shutdown. */ - tty_port_set_suspended(port, 0); + tty_port_set_suspended(port, false); - uart_change_pm(state, UART_PM_STATE_OFF); + uart_free_xmit_buf(port); + uart_change_pm(state, UART_PM_STATE_OFF); } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) { struct uart_state *state = tty->driver_data; struct uart_port *port; - unsigned long char_time, expire; + unsigned long char_time, expire, fifo_timeout; port = uart_port_ref(state); if (!port) @@ -1611,28 +1768,29 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ - char_time = (port->timeout - HZ/50) / port->fifosize; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; + char_time = max(nsecs_to_jiffies(port->frame_time / 5), 1UL); + if (timeout && timeout < char_time) char_time = timeout; - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than port->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*port->timeout. - */ - if (timeout == 0 || timeout > 2 * port->timeout) - timeout = 2 * port->timeout; + if (!uart_cts_enabled(port)) { + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than FIFO timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2 * FIFO timeout. + */ + fifo_timeout = uart_fifo_timeout(port); + if (timeout == 0 || timeout > 2 * fifo_timeout) + timeout = 2 * fifo_timeout; + } expire = jiffies + timeout; - pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", + pr_debug("uart_wait_until_sent(%u), jiffies=%lu, expire=%lu...\n", port->line, jiffies, expire); /* @@ -1644,7 +1802,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; - if (time_after(jiffies, expire)) + if (timeout && time_after(jiffies, expire)) break; } uart_port_deref(port); @@ -1660,28 +1818,25 @@ static void uart_hangup(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; - unsigned long flags; pr_debug("uart_hangup(%d)\n", tty->index); - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); uport = uart_port_check(state); WARN(!uport, "hangup of detached port!\n"); if (tty_port_active(port)) { uart_flush_buffer(tty); uart_shutdown(tty, state); - spin_lock_irqsave(&port->lock, flags); - port->count = 0; - spin_unlock_irqrestore(&port->lock, flags); - tty_port_set_active(port, 0); + scoped_guard(spinlock_irqsave, &port->lock) + port->count = 0; + tty_port_set_active(port, false); tty_port_tty_set(port, NULL); if (uport && !uart_console(uport)) uart_change_pm(state, UART_PM_STATE_OFF); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->delta_msr_wait); } - mutex_unlock(&port->mutex); } /* uport == NULL if uart_port has already been removed */ @@ -1699,26 +1854,23 @@ static void uart_port_shutdown(struct tty_port *port) */ wake_up_interruptible(&port->delta_msr_wait); - /* - * Free the IRQ and disable the port. - */ - if (uport) + if (uport) { + /* Free the IRQ and disable the port. */ uport->ops->shutdown(uport); - /* - * Ensure that the IRQ handler isn't running on another CPU. - */ - if (uport) + /* Ensure that the IRQ handler isn't running on another CPU. */ synchronize_irq(uport->irq); + } } -static int uart_carrier_raised(struct tty_port *port) +static bool uart_carrier_raised(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport; + unsigned long flags; int mctrl; - uport = uart_port_ref(state); + uport = uart_port_ref_lock(state, &flags); /* * Should never observe uport == NULL since checks for hangup should * abort the tty_port_block_til_ready() loop before checking for carrier @@ -1726,18 +1878,15 @@ static int uart_carrier_raised(struct tty_port *port) * continue and not sleep */ if (WARN_ON(!uport)) - return 1; - spin_lock_irq(&uport->lock); + return true; uart_enable_ms(uport); mctrl = uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); - uart_port_deref(uport); - if (mctrl & TIOCM_CAR) - return 1; - return 0; + uart_port_unlock_deref(uport, flags); + + return mctrl & TIOCM_CAR; } -static void uart_dtr_rts(struct tty_port *port, int raise) +static void uart_dtr_rts(struct tty_port *port, bool active) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport; @@ -1745,7 +1894,7 @@ static void uart_dtr_rts(struct tty_port *port, int raise) uport = uart_port_ref(state); if (!uport) return; - uart_port_dtr_rts(uport, raise); + uart_port_dtr_rts(uport, active); uart_port_deref(uport); } @@ -1791,14 +1940,12 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty) if (!uport || uport->flags & UPF_DEAD) return -ENXIO; - port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; - /* * Start up the serial port. */ - ret = uart_startup(tty, state, 0); + ret = uart_startup(tty, state, false); if (ret > 0) - tty_port_set_active(port, 1); + tty_port_set_active(port, true); return ret; } @@ -1818,9 +1965,8 @@ static const char *uart_type(struct uart_port *port) #ifdef CONFIG_PROC_FS -static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) +static void uart_line_info(struct seq_file *m, struct uart_state *state) { - struct uart_state *state = drv->state + i; struct tty_port *port = &state->port; enum uart_pm_state pm_state; struct uart_port *uport; @@ -1828,13 +1974,14 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) unsigned int status; int mmio; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); + uport = uart_port_check(state); if (!uport) - goto out; + return; mmio = uport->iotype >= UPIO_MEM; - seq_printf(m, "%d: uart:%s %s%08llX irq:%d", + seq_printf(m, "%u: uart:%s %s%08llX irq:%u", uport->line, uart_type(uport), mmio ? "mmio:0x" : "port:", mmio ? (unsigned long long)uport->mapbase @@ -1843,31 +1990,30 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) if (uport->type == PORT_UNKNOWN) { seq_putc(m, '\n'); - goto out; + return; } if (capable(CAP_SYS_ADMIN)) { pm_state = state->pm_state; if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, UART_PM_STATE_ON); - spin_lock_irq(&uport->lock); - status = uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); + scoped_guard(uart_port_lock_irq, uport) + status = uport->ops->get_mctrl(uport); if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, pm_state); - seq_printf(m, " tx:%d rx:%d", + seq_printf(m, " tx:%u rx:%u", uport->icount.tx, uport->icount.rx); if (uport->icount.frame) - seq_printf(m, " fe:%d", uport->icount.frame); + seq_printf(m, " fe:%u", uport->icount.frame); if (uport->icount.parity) - seq_printf(m, " pe:%d", uport->icount.parity); + seq_printf(m, " pe:%u", uport->icount.parity); if (uport->icount.brk) - seq_printf(m, " brk:%d", uport->icount.brk); + seq_printf(m, " brk:%u", uport->icount.brk); if (uport->icount.overrun) - seq_printf(m, " oe:%d", uport->icount.overrun); + seq_printf(m, " oe:%u", uport->icount.overrun); if (uport->icount.buf_overrun) - seq_printf(m, " bo:%d", uport->icount.buf_overrun); + seq_printf(m, " bo:%u", uport->icount.buf_overrun); #define INFOBIT(bit, str) \ if (uport->mctrl & (bit)) \ @@ -1894,8 +2040,6 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) seq_putc(m, '\n'); #undef STATBIT #undef INFOBIT -out: - mutex_unlock(&port->mutex); } static int uart_proc_show(struct seq_file *m, void *v) @@ -1906,40 +2050,28 @@ static int uart_proc_show(struct seq_file *m, void *v) seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", ""); for (i = 0; i < drv->nr; i++) - uart_line_info(m, drv, i); + uart_line_info(m, drv->state + i); return 0; } #endif -static inline bool uart_console_enabled(struct uart_port *port) -{ - return uart_console(port) && (port->cons->flags & CON_ENABLED); -} - -/* - * Ensure that the serial console lock is initialised early. - * If this port is a console, then the spinlock is already initialised. - */ -static inline void uart_port_spin_lock_init(struct uart_port *port) +static void uart_port_spin_lock_init(struct uart_port *port) { - if (uart_console(port)) - return; - spin_lock_init(&port->lock); lockdep_set_class(&port->lock, &port_lock_key); } #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** - * uart_console_write - write a console message to a serial port - * @port: the port to write the message - * @s: array of characters - * @count: number of characters in string to write - * @putchar: function to write character to port + * uart_console_write - write a console message to a serial port + * @port: the port to write the message + * @s: array of characters + * @count: number of characters in string to write + * @putchar: function to write character to port */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, - void (*putchar)(struct uart_port *, int)) + void (*putchar)(struct uart_port *, unsigned char)) { unsigned int i; @@ -1951,50 +2083,27 @@ void uart_console_write(struct uart_port *port, const char *s, } EXPORT_SYMBOL_GPL(uart_console_write); -/* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ -struct uart_port * __init -uart_get_console(struct uart_port *ports, int nr, struct console *co) -{ - int idx = co->index; - - if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && - ports[idx].membase == NULL)) - for (idx = 0; idx < nr; idx++) - if (ports[idx].iobase != 0 || - ports[idx].membase != NULL) - break; - - co->index = idx; - - return ports + idx; -} - /** - * uart_parse_earlycon - Parse earlycon options - * @p: ptr to 2nd field (ie., just beyond '<name>,') - * @iotype: ptr for decoded iotype (out) - * @addr: ptr for decoded mapbase/iobase (out) - * @options: ptr for <options> field; NULL if not present (out) + * uart_parse_earlycon - Parse earlycon options + * @p: ptr to 2nd field (ie., just beyond '<name>,') + * @iotype: ptr for decoded iotype (out) + * @addr: ptr for decoded mapbase/iobase (out) + * @options: ptr for <options> field; %NULL if not present (out) * - * Decodes earlycon kernel command line parameters of the form - * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> - * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> + * Decodes earlycon kernel command line parameters of the form: + * * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> + * * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> * - * The optional form + * The optional form: + * * earlycon=<name>,0x<addr>,<options> + * * console=<name>,0x<addr>,<options> * - * earlycon=<name>,0x<addr>,<options> - * console=<name>,0x<addr>,<options> + * is also accepted; the returned @iotype will be %UPIO_MEM. * - * is also accepted; the returned @iotype will be UPIO_MEM. - * - * Returns 0 on success or -EINVAL on failure + * Returns: 0 on success or -%EINVAL on failure */ -int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, - char **options) +int uart_parse_earlycon(char *p, enum uart_iotype *iotype, + resource_size_t *addr, char **options) { if (strncmp(p, "mmio,", 5) == 0) { *iotype = UPIO_MEM; @@ -2036,16 +2145,16 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, EXPORT_SYMBOL_GPL(uart_parse_earlycon); /** - * uart_parse_options - Parse serial port baud/parity/bits/flow control. - * @options: pointer to option string - * @baud: pointer to an 'int' variable for the baud rate. - * @parity: pointer to an 'int' variable for the parity. - * @bits: pointer to an 'int' variable for the number of data bits. - * @flow: pointer to an 'int' variable for the flow control character. + * uart_parse_options - Parse serial port baud/parity/bits/flow control. + * @options: pointer to option string + * @baud: pointer to an 'int' variable for the baud rate. + * @parity: pointer to an 'int' variable for the parity. + * @bits: pointer to an 'int' variable for the number of data bits. + * @flow: pointer to an 'int' variable for the flow control character. * - * uart_parse_options decodes a string containing the serial console - * options. The format of the string is <baud><parity><bits><flow>, - * eg: 115200n8r + * uart_parse_options() decodes a string containing the serial console + * options. The format of the string is <baud><parity><bits><flow>, + * eg: 115200n8r */ void uart_parse_options(const char *options, int *baud, int *parity, @@ -2066,13 +2175,16 @@ uart_parse_options(const char *options, int *baud, int *parity, EXPORT_SYMBOL_GPL(uart_parse_options); /** - * uart_set_options - setup the serial console parameters - * @port: pointer to the serial ports uart_port structure - * @co: console pointer - * @baud: baud rate - * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) - * @bits: number of data bits - * @flow: flow control character - 'r' (rts) + * uart_set_options - setup the serial console parameters + * @port: pointer to the serial ports uart_port structure + * @co: console pointer + * @baud: baud rate + * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) + * @bits: number of data bits + * @flow: flow control character - 'r' (rts) + * + * Locking: Caller must hold console_list_lock in order to serialize + * early initialization of the serial-console lock. */ int uart_set_options(struct uart_port *port, struct console *co, @@ -2081,7 +2193,15 @@ uart_set_options(struct uart_port *port, struct console *co, struct ktermios termios; static struct ktermios dummy; - uart_port_spin_lock_init(port); + /* + * Ensure that the serial-console lock is initialised early. + * + * Note that the console-registered check is needed because + * kgdboc can call uart_set_options() for an already registered + * console via tty_find_polling_driver() and uart_poll_init(). + */ + if (!uart_console_registered_locked(port) && !port->console_reinit) + uart_port_spin_lock_init(port); memset(&termios, 0, sizeof(struct ktermios)); @@ -2096,7 +2216,7 @@ uart_set_options(struct uart_port *port, struct console *co, switch (parity) { case 'o': case 'O': termios.c_cflag |= PARODD; - /*fall through*/ + fallthrough; case 'e': case 'E': termios.c_cflag |= PARENB; break; @@ -2116,8 +2236,11 @@ uart_set_options(struct uart_port *port, struct console *co, * Allow the setting of the UART parameters with a NULL console * too: */ - if (co) + if (co) { co->cflag = termios.c_cflag; + co->ispeed = termios.c_ispeed; + co->ospeed = termios.c_ospeed; + } return 0; } @@ -2149,9 +2272,9 @@ struct uart_match { struct uart_driver *driver; }; -static int serial_match_port(struct device *dev, void *data) +static int serial_match_port(struct device *dev, const void *data) { - struct uart_match *match = data; + const struct uart_match *match = data; struct tty_driver *tty_drv = match->driver->tty_driver; dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + match->port->line; @@ -2166,35 +2289,50 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) struct device *tty_dev; struct uart_match match = {uport, drv}; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); - tty_dev = device_find_child(uport->dev, &match, serial_match_port); + tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port); if (tty_dev && device_may_wakeup(tty_dev)) { enable_irq_wake(uport->irq); put_device(tty_dev); - mutex_unlock(&port->mutex); return 0; } put_device(tty_dev); - /* Nothing to do if the console is not suspending */ - if (!console_suspend_enabled && uart_console(uport)) - goto unlock; + /* + * Nothing to do if the console is not suspending + * except stop_rx to prevent any asynchronous data + * over RX line. However ensure that we will be + * able to Re-start_rx later. + */ + if (!console_suspend_enabled && uart_console(uport)) { + if (uport->ops->start_rx) { + guard(uart_port_lock_irq)(uport); + uport->ops->stop_rx(uport); + } + device_set_awake_path(uport->dev); + return 0; + } uport->suspended = 1; if (tty_port_initialized(port)) { const struct uart_ops *ops = uport->ops; int tries; - - tty_port_set_suspended(port, 1); - tty_port_set_initialized(port, 0); - - spin_lock_irq(&uport->lock); - ops->stop_tx(uport); - ops->set_mctrl(uport, 0); - ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); + unsigned int mctrl; + + tty_port_set_suspended(port, true); + tty_port_set_initialized(port, false); + + scoped_guard(uart_port_lock_irq, uport) { + ops->stop_tx(uport); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); + /* save mctrl so it can be restored on resume */ + mctrl = uport->mctrl; + uport->mctrl = 0; + ops->stop_rx(uport); + } /* * Wait for the transmitter to empty. @@ -2206,20 +2344,20 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) uport->name); ops->shutdown(uport); + uport->mctrl = mctrl; } /* - * Disable the console device before suspending. + * Suspend the console device before suspending the port. */ if (uart_console(uport)) - console_stop(uport->cons); + console_suspend(uport->cons); uart_change_pm(state, UART_PM_STATE_OFF); -unlock: - mutex_unlock(&port->mutex); return 0; } +EXPORT_SYMBOL(uart_suspend_port); int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) { @@ -2229,14 +2367,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) struct uart_match match = {uport, drv}; struct ktermios termios; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); - tty_dev = device_find_child(uport->dev, &match, serial_match_port); + tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port); if (!uport->suspended && device_may_wakeup(tty_dev)) { if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq)))) disable_irq_wake(uport->irq); put_device(tty_dev); - mutex_unlock(&port->mutex); return 0; } put_device(tty_dev); @@ -2251,6 +2388,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) */ memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = uport->cons->cflag; + termios.c_ispeed = uport->cons->ispeed; + termios.c_ospeed = uport->cons->ospeed; /* * If that's unset, use the tty termios setting. @@ -2261,8 +2400,12 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) if (console_suspend_enabled) uart_change_pm(state, UART_PM_STATE_ON); uport->ops->set_termios(uport, &termios, NULL); + if (!console_suspend_enabled && uport->ops->start_rx) { + guard(uart_port_lock_irq)(uport); + uport->ops->start_rx(uport); + } if (console_suspend_enabled) - console_start(uport->cons); + console_resume(uport->cons); } if (tty_port_suspended(port)) { @@ -2270,21 +2413,24 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) int ret; uart_change_pm(state, UART_PM_STATE_ON); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, 0); - spin_unlock_irq(&uport->lock); + scoped_guard(uart_port_lock_irq, uport) + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); if (console_suspend_enabled || !uart_console(uport)) { /* Protected by port mutex for now */ struct tty_struct *tty = port->tty; + ret = ops->startup(uport); if (ret == 0) { if (tty) - uart_change_speed(tty, state, NULL); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, uport->mctrl); - ops->start_tx(uport); - spin_unlock_irq(&uport->lock); - tty_port_set_initialized(port, 1); + uart_change_line_settings(tty, state, NULL); + uart_rs485_config(uport); + scoped_guard(uart_port_lock_irq, uport) { + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, uport->mctrl); + ops->start_tx(uport); + } + tty_port_set_initialized(port, true); } else { /* * Failed to resume - maybe hardware went away? @@ -2295,13 +2441,12 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) } } - tty_port_set_suspended(port, 0); + tty_port_set_suspended(port, false); } - mutex_unlock(&port->mutex); - return 0; } +EXPORT_SYMBOL(uart_resume_port); static inline void uart_report_port(struct uart_driver *drv, struct uart_port *port) @@ -2326,15 +2471,23 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) "MMIO 0x%llx", (unsigned long long)port->mapbase); break; default: - strlcpy(address, "*unknown*", sizeof(address)); + strscpy(address, "*unknown*", sizeof(address)); break; } - pr_info("%s%s%s at %s (irq = %d, base_baud = %d) is a %s\n", + pr_info("%s%s%s at %s (irq = %u, base_baud = %u) is a %s\n", port->dev ? dev_name(port->dev) : "", port->dev ? ": " : "", port->name, address, port->irq, port->uartclk / 16, uart_type(port)); + + /* The magic multiplier feature is a bit obscure, so report it too. */ + if (port->flags & UPF_MAGIC_MULTIPLIER) + pr_info("%s%s%s extra baud rates supported: %u, %u", + port->dev ? dev_name(port->dev) : "", + port->dev ? ": " : "", + port->name, + port->uartclk / 8, port->uartclk / 4); } static void @@ -2361,14 +2514,21 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, port->type = PORT_UNKNOWN; flags |= UART_CONFIG_TYPE; } + /* Synchronize with possible boot console. */ + if (uart_console(port)) + console_lock(); port->ops->config_port(port, flags); + if (uart_console(port)) + console_unlock(); } if (port->type != PORT_UNKNOWN) { - unsigned long flags; - uart_report_port(drv, port); + /* Synchronize with possible boot console. */ + if (uart_console(port)) + console_lock(); + /* Power up port for set_mctrl() */ uart_change_pm(state, UART_PM_STATE_ON); @@ -2377,16 +2537,23 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, * keep the DTR setting that is set in uart_set_options() * We probably don't need a spinlock around this, but */ - spin_lock_irqsave(&port->lock, flags); - port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(uart_port_lock_irqsave, port) { + port->mctrl &= TIOCM_DTR; + if (!(port->rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } + + uart_rs485_config(port); + + if (uart_console(port)) + console_unlock(); /* * If this driver supports console, and it hasn't been * successfully registered yet, try to re-register it. * It may be that the port was not available. */ - if (port->cons && !(port->cons->flags & CON_ENABLED)) + if (port->cons && !console_is_registered(port->cons)) register_console(port->cons); /* @@ -2404,6 +2571,7 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) { struct uart_driver *drv = driver->driver_state; struct uart_state *state = drv->state + line; + enum uart_pm_state pm_state; struct tty_port *tport; struct uart_port *port; int baud = 9600; @@ -2413,13 +2581,16 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) int ret = 0; tport = &state->port; - mutex_lock(&tport->mutex); + + guard(mutex)(&tport->mutex); port = uart_port_check(state); - if (!port || !(port->ops->poll_get_char && port->ops->poll_put_char)) { - ret = -1; - goto out; - } + if (!port || port->type == PORT_UNKNOWN || + !(port->ops->poll_get_char && port->ops->poll_put_char)) + return -1; + + pm_state = state->pm_state; + uart_change_pm(state, UART_PM_STATE_ON); if (port->ops->poll_init) { /* @@ -2432,10 +2603,14 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) if (!ret && options) { uart_parse_options(options, &baud, &parity, &bits, &flow); + console_list_lock(); ret = uart_set_options(port, NULL, baud, parity, bits, flow); + console_list_unlock(); } -out: - mutex_unlock(&tport->mutex); + + if (ret) + uart_change_pm(state, pm_state); + return ret; } @@ -2516,17 +2691,19 @@ static const struct tty_port_operations uart_port_ops = { }; /** - * uart_register_driver - register a driver with the uart core layer - * @drv: low level driver structure + * uart_register_driver - register a driver with the uart core layer + * @drv: low level driver structure + * + * Register a uart driver with the core driver. We in turn register with the + * tty layer, and initialise the core driver per-port state. * - * Register a uart driver with the core driver. We in turn register - * with the tty layer, and initialise the core driver per-port state. + * We have a proc file in /proc/tty/driver which is named after the normal + * driver. * - * We have a proc file in /proc/tty/driver which is named after the - * normal driver. + * @drv->port should be %NULL, and the per-port structures should be registered + * using uart_add_one_port() after this call has succeeded. * - * drv->port should be NULL, and the per-port structures should be - * registered using uart_add_one_port after this call has succeeded. + * Locking: none, Interrupts: enabled */ int uart_register_driver(struct uart_driver *drv) { @@ -2543,9 +2720,12 @@ int uart_register_driver(struct uart_driver *drv) if (!drv->state) goto out; - normal = alloc_tty_driver(drv->nr); - if (!normal) + normal = tty_alloc_driver(drv->nr, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(normal)) { + retval = PTR_ERR(normal); goto out_kfree; + } drv->tty_driver = normal; @@ -2558,7 +2738,6 @@ int uart_register_driver(struct uart_driver *drv) normal->init_termios = tty_std_termios; normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; - normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; normal->driver_state = drv; tty_set_operations(normal, &uart_ops); @@ -2579,21 +2758,23 @@ int uart_register_driver(struct uart_driver *drv) for (i = 0; i < drv->nr; i++) tty_port_destroy(&drv->state[i].port); - put_tty_driver(normal); + tty_driver_kref_put(normal); out_kfree: kfree(drv->state); out: return retval; } +EXPORT_SYMBOL(uart_register_driver); /** - * uart_unregister_driver - remove a driver from the uart core layer - * @drv: low level driver structure + * uart_unregister_driver - remove a driver from the uart core layer + * @drv: low level driver structure + * + * Remove all references to a driver from the core driver. The low level + * driver must have removed all its ports via the uart_remove_one_port() if it + * registered them with uart_add_one_port(). (I.e. @drv->port is %NULL.) * - * Remove all references to a driver from the core driver. The low - * level driver must have removed all its ports via the - * uart_remove_one_port() if it registered them with uart_add_one_port(). - * (ie, drv->port == NULL) + * Locking: none, Interrupts: enabled */ void uart_unregister_driver(struct uart_driver *drv) { @@ -2601,13 +2782,14 @@ void uart_unregister_driver(struct uart_driver *drv) unsigned int i; tty_unregister_driver(p); - put_tty_driver(p); + tty_driver_kref_put(p); for (i = 0; i < drv->nr; i++) tty_port_destroy(&drv->state[i].port); kfree(drv->state); drv->state = NULL; drv->tty_driver = NULL; } +EXPORT_SYMBOL(uart_unregister_driver); struct tty_driver *uart_console_device(struct console *co, int *index) { @@ -2624,7 +2806,7 @@ static ssize_t uartclk_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16); + return sprintf(buf, "%d\n", tmp.baud_base * 16); } static ssize_t type_show(struct device *dev, @@ -2634,7 +2816,7 @@ static ssize_t type_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type); + return sprintf(buf, "%d\n", tmp.type); } static ssize_t line_show(struct device *dev, @@ -2644,7 +2826,7 @@ static ssize_t line_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line); + return sprintf(buf, "%d\n", tmp.line); } static ssize_t port_show(struct device *dev, @@ -2658,7 +2840,7 @@ static ssize_t port_show(struct device *dev, ioaddr = tmp.port; if (HIGH_BITS_OFFSET) ioaddr |= (unsigned long)tmp.port_high << HIGH_BITS_OFFSET; - return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr); + return sprintf(buf, "0x%lX\n", ioaddr); } static ssize_t irq_show(struct device *dev, @@ -2668,7 +2850,7 @@ static ssize_t irq_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq); + return sprintf(buf, "%d\n", tmp.irq); } static ssize_t flags_show(struct device *dev, @@ -2678,7 +2860,7 @@ static ssize_t flags_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags); + return sprintf(buf, "0x%X\n", tmp.flags); } static ssize_t xmit_fifo_size_show(struct device *dev, @@ -2688,7 +2870,7 @@ static ssize_t xmit_fifo_size_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size); + return sprintf(buf, "%d\n", tmp.xmit_fifo_size); } static ssize_t close_delay_show(struct device *dev, @@ -2698,7 +2880,7 @@ static ssize_t close_delay_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay); + return sprintf(buf, "%u\n", tmp.close_delay); } static ssize_t closing_wait_show(struct device *dev, @@ -2708,7 +2890,7 @@ static ssize_t closing_wait_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait); + return sprintf(buf, "%u\n", tmp.closing_wait); } static ssize_t custom_divisor_show(struct device *dev, @@ -2718,7 +2900,7 @@ static ssize_t custom_divisor_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor); + return sprintf(buf, "%d\n", tmp.custom_divisor); } static ssize_t io_type_show(struct device *dev, @@ -2728,7 +2910,7 @@ static ssize_t io_type_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type); + return sprintf(buf, "%u\n", tmp.io_type); } static ssize_t iomem_base_show(struct device *dev, @@ -2738,7 +2920,7 @@ static ssize_t iomem_base_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base); + return sprintf(buf, "0x%lX\n", (unsigned long)tmp.iomem_base); } static ssize_t iomem_reg_shift_show(struct device *dev, @@ -2748,7 +2930,7 @@ static ssize_t iomem_reg_shift_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); + return sprintf(buf, "%u\n", tmp.iomem_reg_shift); } static ssize_t console_show(struct device *dev, @@ -2759,11 +2941,11 @@ static ssize_t console_show(struct device *dev, struct uart_port *uport; bool console = false; - mutex_lock(&port->mutex); - uport = uart_port_check(state); - if (uport) - console = uart_console_enabled(uport); - mutex_unlock(&port->mutex); + scoped_guard(mutex, &port->mutex) { + uport = uart_port_check(state); + if (uport) + console = uart_console_registered(uport); + } return sprintf(buf, "%c\n", console ? 'Y' : 'N'); } @@ -2781,24 +2963,25 @@ static ssize_t console_store(struct device *dev, if (ret) return ret; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); uport = uart_port_check(state); - if (uport) { - oldconsole = uart_console_enabled(uport); - if (oldconsole && !newconsole) { - ret = unregister_console(uport->cons); - } else if (!oldconsole && newconsole) { - if (uart_console(uport)) - register_console(uport->cons); - else - ret = -ENOENT; - } - } else { - ret = -ENXIO; + if (!uport) + return -ENXIO; + + oldconsole = uart_console_registered(uport); + if (oldconsole && !newconsole) { + ret = unregister_console(uport->cons); + if (ret < 0) + return ret; + } else if (!oldconsole && newconsole) { + if (!uart_console(uport)) + return -ENOENT; + + uport->console_reinit = 1; + register_console(uport->cons); } - mutex_unlock(&port->mutex); - return ret < 0 ? ret : count; + return count; } static DEVICE_ATTR_RO(uartclk); @@ -2839,37 +3022,33 @@ static const struct attribute_group tty_dev_attr_group = { }; /** - * uart_add_one_port - attach a driver-defined port structure - * @drv: pointer to the uart low level driver structure for this port - * @uport: uart port structure to use for this port. + * serial_core_add_one_port - attach a driver-defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @uport: uart port structure to use for this port. + * + * Context: task context, might sleep * - * This allows the driver to register its own uart_port structure - * with the core driver. The main purpose is to allow the low - * level uart drivers to expand uart_port, rather than having yet - * more levels of structures. + * This allows the driver @drv to register its own uart_port structure with the + * core driver. The main purpose is to allow the low level uart drivers to + * expand uart_port, rather than having yet more levels of structures. + * Caller must hold port_mutex. */ -int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) +static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state; struct tty_port *port; - int ret = 0; struct device *tty_dev; int num_groups; - BUG_ON(in_interrupt()); - if (uport->line >= drv->nr) return -EINVAL; state = drv->state + uport->line; port = &state->port; - mutex_lock(&port_mutex); - mutex_lock(&port->mutex); - if (state->uart_port) { - ret = -EINVAL; - goto out; - } + guard(mutex)(&port->mutex); + if (state->uart_port) + return -EINVAL; /* Link the port to the driver state table and vice versa */ atomic_set(&state->refcount, 1); @@ -2877,22 +3056,24 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) state->uart_port = uport; uport->state = state; + /* + * If this port is in use as a console then the spinlock is already + * initialised. + */ + if (!uart_console_registered(uport)) + uart_port_spin_lock_init(uport); + state->pm_state = UART_PM_STATE_UNDEFINED; - uport->cons = drv->cons; + uart_port_set_cons(uport, drv->cons); uport->minor = drv->tty_driver->minor_start + uport->line; - uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name, + uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name, drv->tty_driver->name_base + uport->line); - if (!uport->name) { - ret = -ENOMEM; - goto out; - } - - uart_port_spin_lock_init(uport); + if (!uport->name) + return -ENOMEM; if (uport->cons && uport->dev) of_console_check(uport->dev->of_node, uport->cons->name, uport->line); - tty_port_link_device(port, drv->tty_driver, uport->line); uart_configure_port(drv, state, uport); port->console = uart_console(uport); @@ -2903,88 +3084,67 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups), GFP_KERNEL); - if (!uport->tty_groups) { - ret = -ENOMEM; - goto out; - } + if (!uport->tty_groups) + return -ENOMEM; + uport->tty_groups[0] = &tty_dev_attr_group; if (uport->attr_group) uport->tty_groups[1] = uport->attr_group; + /* Ensure serdev drivers can call serdev_device_open() right away */ + uport->flags &= ~UPF_DEAD; + /* * Register the port whether it's detected or not. This allows * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver, - uport->line, uport->dev, port, uport->tty_groups); + uport->line, uport->dev, &uport->port_dev->dev, port, + uport->tty_groups); if (!IS_ERR(tty_dev)) { device_set_wakeup_capable(tty_dev, 1); } else { - dev_err(uport->dev, "Cannot register tty device on line %d\n", + uport->flags |= UPF_DEAD; + dev_err(uport->dev, "Cannot register tty device on line %u\n", uport->line); } - /* - * Ensure UPF_DEAD is not set. - */ - uport->flags &= ~UPF_DEAD; - - out: - mutex_unlock(&port->mutex); - mutex_unlock(&port_mutex); - - return ret; + return 0; } /** - * uart_remove_one_port - detach a driver defined port structure - * @drv: pointer to the uart low level driver structure for this port - * @uport: uart port structure for this port + * serial_core_remove_one_port - detach a driver defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @uport: uart port structure for this port + * + * Context: task context, might sleep * - * This unhooks (and hangs up) the specified port structure from the - * core driver. No further calls will be made to the low-level code - * for this port. + * This unhooks (and hangs up) the specified port structure from the core + * driver. No further calls will be made to the low-level code for this port. + * Caller must hold port_mutex. */ -int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) +static void serial_core_remove_one_port(struct uart_driver *drv, + struct uart_port *uport) { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; struct uart_port *uart_port; - struct tty_struct *tty; - int ret = 0; - - BUG_ON(in_interrupt()); - mutex_lock(&port_mutex); + scoped_guard(mutex, &port->mutex) { + uart_port = uart_port_check(state); + if (uart_port != uport) + dev_alert(uport->dev, "Removing wrong port: %p != %p\n", uart_port, uport); - /* - * Mark the port "dead" - this prevents any opens from - * succeeding while we shut down the port. - */ - mutex_lock(&port->mutex); - uart_port = uart_port_check(state); - if (uart_port != uport) - dev_alert(uport->dev, "Removing wrong port: %p != %p\n", - uart_port, uport); - - if (!uart_port) { - mutex_unlock(&port->mutex); - ret = -EINVAL; - goto out; + if (!uart_port) + return; } - uport->flags |= UPF_DEAD; - mutex_unlock(&port->mutex); /* * Remove the devices from the tty layer */ tty_port_unregister_device(port, drv->tty_driver, uport->line); - tty = tty_port_tty_get(port); - if (tty) { - tty_vhangup(port->tty); - tty_kref_put(tty); - } + tty_port_tty_vhangup(port); /* * If the port is used as a console, unregister it @@ -3004,52 +3164,186 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) * Indicate that there isn't a port here anymore. */ uport->type = PORT_UNKNOWN; + uport->port_dev = NULL; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); WARN_ON(atomic_dec_return(&state->refcount) < 0); wait_event(state->remove_wait, !atomic_read(&state->refcount)); state->uart_port = NULL; - mutex_unlock(&port->mutex); -out: - mutex_unlock(&port_mutex); - - return ret; } -/* - * Are the two ports equivalent? +/** + * uart_match_port - are the two ports equivalent? + * @port1: first port + * @port2: second port + * + * This utility function can be used to determine whether two uart_port + * structures describe the same port. */ -int uart_match_port(struct uart_port *port1, struct uart_port *port2) +bool uart_match_port(const struct uart_port *port1, + const struct uart_port *port2) { if (port1->iotype != port2->iotype) - return 0; + return false; switch (port1->iotype) { case UPIO_PORT: - return (port1->iobase == port2->iobase); + return port1->iobase == port2->iobase; case UPIO_HUB6: - return (port1->iobase == port2->iobase) && - (port1->hub6 == port2->hub6); + return port1->iobase == port2->iobase && + port1->hub6 == port2->hub6; case UPIO_MEM: case UPIO_MEM16: case UPIO_MEM32: case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: - return (port1->mapbase == port2->mapbase); + return port1->mapbase == port2->mapbase; + default: + return false; } - return 0; } EXPORT_SYMBOL(uart_match_port); +static struct serial_ctrl_device * +serial_core_get_ctrl_dev(struct serial_port_device *port_dev) +{ + struct device *dev = &port_dev->dev; + + return to_serial_base_ctrl_device(dev->parent); +} + +/* + * Find a registered serial core controller device if one exists. Returns + * the first device matching the ctrl_id. Caller must hold port_mutex. + */ +static struct serial_ctrl_device *serial_core_ctrl_find(struct uart_driver *drv, + struct device *phys_dev, + int ctrl_id) +{ + struct uart_state *state; + int i; + + lockdep_assert_held(&port_mutex); + + for (i = 0; i < drv->nr; i++) { + state = drv->state + i; + if (!state->uart_port || !state->uart_port->port_dev) + continue; + + if (state->uart_port->dev == phys_dev && + state->uart_port->ctrl_id == ctrl_id) + return serial_core_get_ctrl_dev(state->uart_port->port_dev); + } + + return NULL; +} + +static struct serial_ctrl_device *serial_core_ctrl_device_add(struct uart_port *port) +{ + return serial_base_ctrl_add(port, port->dev); +} + +static int serial_core_port_device_add(struct serial_ctrl_device *ctrl_dev, + struct uart_port *port) +{ + struct serial_port_device *port_dev; + + port_dev = serial_base_port_add(port, ctrl_dev); + if (IS_ERR(port_dev)) + return PTR_ERR(port_dev); + + port->port_dev = port_dev; + + return 0; +} + +/* + * Initialize a serial core port device, and a controller device if needed. + */ +int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) +{ + struct serial_ctrl_device *ctrl_dev, *new_ctrl_dev = NULL; + int ret; + + guard(mutex)(&port_mutex); + + /* + * Prevent serial_port_runtime_resume() from trying to use the port + * until serial_core_add_one_port() has completed + */ + port->flags |= UPF_DEAD; + + /* Inititalize a serial core controller device if needed */ + ctrl_dev = serial_core_ctrl_find(drv, port->dev, port->ctrl_id); + if (!ctrl_dev) { + new_ctrl_dev = serial_core_ctrl_device_add(port); + if (IS_ERR(new_ctrl_dev)) + return PTR_ERR(new_ctrl_dev); + ctrl_dev = new_ctrl_dev; + } + + /* + * Initialize a serial core port device. Tag the port dead to prevent + * serial_port_runtime_resume() trying to do anything until port has + * been registered. It gets cleared by serial_core_add_one_port(). + */ + ret = serial_core_port_device_add(ctrl_dev, port); + if (ret) + goto err_unregister_ctrl_dev; + + ret = serial_base_match_and_update_preferred_console(drv, port); + if (ret) + goto err_unregister_port_dev; + + ret = serial_core_add_one_port(drv, port); + if (ret) + goto err_unregister_port_dev; + + return 0; + +err_unregister_port_dev: + serial_base_port_device_remove(port->port_dev); + +err_unregister_ctrl_dev: + serial_base_ctrl_device_remove(new_ctrl_dev); + + return ret; +} + +/* + * Removes a serial core port device, and the related serial core controller + * device if the last instance. + */ +void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port) +{ + struct device *phys_dev = port->dev; + struct serial_port_device *port_dev = port->port_dev; + struct serial_ctrl_device *ctrl_dev = serial_core_get_ctrl_dev(port_dev); + int ctrl_id = port->ctrl_id; + + guard(mutex)(&port_mutex); + + port->flags |= UPF_DEAD; + + serial_core_remove_one_port(drv, port); + + /* Note that struct uart_port *port is no longer valid at this point */ + serial_base_port_device_remove(port_dev); + + /* Drop the serial core controller device if no ports are using it */ + if (!serial_core_ctrl_find(drv, phys_dev, ctrl_id)) + serial_base_ctrl_device_remove(ctrl_dev); +} + /** - * uart_handle_dcd_change - handle a change of carrier detect state - * @uport: uart_port structure for the open port - * @status: new carrier detect status, nonzero if active + * uart_handle_dcd_change - handle a change of carrier detect state + * @uport: uart_port structure for the open port + * @active: new carrier detect status * - * Caller must hold uport->lock + * Caller must hold uport->lock. */ -void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) +void uart_handle_dcd_change(struct uart_port *uport, bool active) { struct tty_port *port = &uport->state->port; struct tty_struct *tty = port->tty; @@ -3061,7 +3355,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) ld = tty_ldisc_ref(tty); if (ld) { if (ld->ops->dcd_change) - ld->ops->dcd_change(tty, status); + ld->ops->dcd_change(tty, active); tty_ldisc_deref(ld); } } @@ -3069,7 +3363,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) uport->icount.dcd++; if (uart_dcd_enabled(uport)) { - if (status) + if (active) wake_up_interruptible(&port->open_wait); else if (tty) tty_hangup(tty); @@ -3078,13 +3372,13 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) EXPORT_SYMBOL_GPL(uart_handle_dcd_change); /** - * uart_handle_cts_change - handle a change of clear-to-send state - * @uport: uart_port structure for the open port - * @status: new clear to send status, nonzero if active + * uart_handle_cts_change - handle a change of clear-to-send state + * @uport: uart_port structure for the open port + * @active: new clear-to-send status * - * Caller must hold uport->lock + * Caller must hold uport->lock. */ -void uart_handle_cts_change(struct uart_port *uport, unsigned int status) +void uart_handle_cts_change(struct uart_port *uport, bool active) { lockdep_assert_held_once(&uport->lock); @@ -3092,14 +3386,14 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) if (uart_softcts_mode(uport)) { if (uport->hw_stopped) { - if (status) { - uport->hw_stopped = 0; + if (active) { + uport->hw_stopped = false; uport->ops->start_tx(uport); uart_write_wakeup(uport); } } else { - if (!status) { - uport->hw_stopped = 1; + if (!active) { + uport->hw_stopped = true; uport->ops->stop_tx(uport); } } @@ -3121,7 +3415,7 @@ EXPORT_SYMBOL_GPL(uart_handle_cts_change); * @flag: flag for the character (see TTY_NORMAL and friends) */ void uart_insert_char(struct uart_port *port, unsigned int status, - unsigned int overrun, unsigned int ch, unsigned int flag) + unsigned int overrun, u8 ch, u8 flag) { struct tty_port *tport = &port->state->port; @@ -3140,7 +3434,7 @@ void uart_insert_char(struct uart_port *port, unsigned int status, EXPORT_SYMBOL_GPL(uart_insert_char); #ifdef CONFIG_MAGIC_SYSRQ_SERIAL -static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE; +static const u8 sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE; static void uart_sysrq_on(struct work_struct *w) { @@ -3153,17 +3447,17 @@ static void uart_sysrq_on(struct work_struct *w) static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); /** - * uart_try_toggle_sysrq - Enables SysRq from serial line - * @port: uart_port structure where char(s) after BREAK met - * @ch: new character in the sequence after received BREAK + * uart_try_toggle_sysrq - Enables SysRq from serial line + * @port: uart_port structure where char(s) after BREAK met + * @ch: new character in the sequence after received BREAK * - * Enables magic SysRq when the required sequence is met on port - * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE). + * Enables magic SysRq when the required sequence is met on port + * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE). * - * Returns false if @ch is out of enabling sequence and should be - * handled some other way, true if @ch was consumed. + * Returns: %false if @ch is out of enabling sequence and should be + * handled some other way, %true if @ch was consumed. */ -static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) +bool uart_try_toggle_sysrq(struct uart_port *port, u8 ch) { int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq); @@ -3186,111 +3480,12 @@ static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) port->sysrq = 0; return true; } -#else -static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) -{ - return false; -} +EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq); #endif -int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) -{ - if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL)) - return 0; - - if (!port->has_sysrq || !port->sysrq) - return 0; - - if (ch && time_before(jiffies, port->sysrq)) { - if (sysrq_mask()) { - handle_sysrq(ch); - port->sysrq = 0; - return 1; - } - if (uart_try_toggle_sysrq(port, ch)) - return 1; - } - port->sysrq = 0; - - return 0; -} -EXPORT_SYMBOL_GPL(uart_handle_sysrq_char); - -int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) -{ - if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL)) - return 0; - - if (!port->has_sysrq || !port->sysrq) - return 0; - - if (ch && time_before(jiffies, port->sysrq)) { - if (sysrq_mask()) { - port->sysrq_ch = ch; - port->sysrq = 0; - return 1; - } - if (uart_try_toggle_sysrq(port, ch)) - return 1; - } - port->sysrq = 0; - - return 0; -} -EXPORT_SYMBOL_GPL(uart_prepare_sysrq_char); - -void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long flags) -__releases(&port->lock) -{ - if (port->has_sysrq) { - int sysrq_ch = port->sysrq_ch; - - port->sysrq_ch = 0; - spin_unlock_irqrestore(&port->lock, flags); - if (sysrq_ch) - handle_sysrq(sysrq_ch); - } else { - spin_unlock_irqrestore(&port->lock, flags); - } -} -EXPORT_SYMBOL_GPL(uart_unlock_and_check_sysrq); - -/* - * We do the SysRQ and SAK checking like this... - */ -int uart_handle_break(struct uart_port *port) -{ - struct uart_state *state = port->state; - - if (port->handle_break) - port->handle_break(port); - - if (port->has_sysrq && uart_console(port)) { - if (!port->sysrq) { - port->sysrq = jiffies + SYSRQ_TIMEOUT; - return 1; - } - port->sysrq = 0; - } - - if (port->flags & UPF_SAK) - do_SAK(state->port.tty); - return 0; -} -EXPORT_SYMBOL_GPL(uart_handle_break); - -EXPORT_SYMBOL(uart_write_wakeup); -EXPORT_SYMBOL(uart_register_driver); -EXPORT_SYMBOL(uart_unregister_driver); -EXPORT_SYMBOL(uart_suspend_port); -EXPORT_SYMBOL(uart_resume_port); -EXPORT_SYMBOL(uart_add_one_port); -EXPORT_SYMBOL(uart_remove_one_port); - /** * uart_get_rs485_mode() - retrieve rs485 properties for given uart - * @dev: uart device - * @rs485conf: output parameter + * @port: uart device's target port * * This function implements the device tree binding described in * Documentation/devicetree/bindings/serial/rs485.txt. @@ -3299,9 +3494,22 @@ int uart_get_rs485_mode(struct uart_port *port) { struct serial_rs485 *rs485conf = &port->rs485; struct device *dev = port->dev; + enum gpiod_flags dflags; + struct gpio_desc *desc; u32 rs485_delay[2]; int ret; + if (!(port->rs485_supported.flags & SER_RS485_ENABLED)) + return 0; + + /* + * Retrieve properties only if a firmware node exists. If no firmware + * node exists, then don't touch rs485 config and keep initial rs485 + * properties set by driver. + */ + if (!dev_fwnode(dev)) + return 0; + ret = device_property_read_u32_array(dev, "rs485-rts-delay", rs485_delay, 2); if (!ret) { @@ -3312,6 +3520,8 @@ int uart_get_rs485_mode(struct uart_port *port) rs485conf->delay_rts_after_send = 0; } + uart_sanitize_serial_rs485_delays(port, rs485conf); + /* * Clear full-duplex and enabled flags, set RTS polarity to active high * to get to a defined state with the following properties: @@ -3337,19 +3547,33 @@ int uart_get_rs485_mode(struct uart_port *port) * bus participants enable it, no communication is possible at all. * Works fine for short cables and users may enable for longer cables. */ - port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term", - GPIOD_OUT_LOW); - if (IS_ERR(port->rs485_term_gpio)) { - ret = PTR_ERR(port->rs485_term_gpio); - port->rs485_term_gpio = NULL; - if (ret != -EPROBE_DEFER) - dev_err(dev, "Cannot get rs485-term-gpios\n"); - return ret; - } + desc = devm_gpiod_get_optional(dev, "rs485-term", GPIOD_OUT_LOW); + if (IS_ERR(desc)) + return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-term-gpios\n"); + port->rs485_term_gpio = desc; + if (port->rs485_term_gpio) + port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS; + + dflags = (rs485conf->flags & SER_RS485_RX_DURING_TX) ? + GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + desc = devm_gpiod_get_optional(dev, "rs485-rx-during-tx", dflags); + if (IS_ERR(desc)) + return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n"); + port->rs485_rx_during_tx_gpio = desc; + if (port->rs485_rx_during_tx_gpio) + port->rs485_supported.flags |= SER_RS485_RX_DURING_TX; return 0; } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); +/* Compile-time assertions for serial_rs485 layout */ +static_assert(offsetof(struct serial_rs485, padding) == + (offsetof(struct serial_rs485, delay_rts_after_send) + sizeof(__u32))); +static_assert(offsetof(struct serial_rs485, padding1) == + offsetof(struct serial_rs485, padding[1])); +static_assert((offsetof(struct serial_rs485, padding[4]) + sizeof(__u32)) == + sizeof(struct serial_rs485)); + MODULE_DESCRIPTION("Serial driver core"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_ctrl.c b/drivers/tty/serial/serial_ctrl.c new file mode 100644 index 000000000000..6fcf634425dc --- /dev/null +++ b/drivers/tty/serial/serial_ctrl.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Serial core controller driver + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Tony Lindgren <tony@atomide.com> + * + * This driver manages the serial core controller struct device instances. + * The serial core controller devices are children of the physical serial + * port device. + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/serial_core.h> +#include <linux/spinlock.h> + +#include "serial_base.h" + +static int serial_ctrl_probe(struct device *dev) +{ + pm_runtime_enable(dev); + + return 0; +} + +static int serial_ctrl_remove(struct device *dev) +{ + pm_runtime_disable(dev); + + return 0; +} + +/* + * Serial core controller device init functions. Note that the physical + * serial port device driver may not have completed probe at this point. + */ +int serial_ctrl_register_port(struct uart_driver *drv, struct uart_port *port) +{ + return serial_core_register_port(drv, port); +} + +void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port) +{ + serial_core_unregister_port(drv, port); +} + +static struct device_driver serial_ctrl_driver = { + .name = "ctrl", + .suppress_bind_attrs = true, + .probe = serial_ctrl_probe, + .remove = serial_ctrl_remove, +}; + +int serial_base_ctrl_init(void) +{ + return serial_base_driver_register(&serial_ctrl_driver); +} + +void serial_base_ctrl_exit(void) +{ + serial_base_driver_unregister(&serial_ctrl_driver); +} + +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_DESCRIPTION("Serial core controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index fb4781292d40..7b02c5ca4afd 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -42,6 +42,13 @@ static bool mctrl_gpio_flags_is_dir_out(unsigned int idx) return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT; } +/** + * mctrl_gpio_set - set gpios according to mctrl state + * @gpios: gpios to set + * @mctrl: state to set + * + * Set the gpios according to the mctrl state. + */ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) { enum mctrl_gpio_idx i; @@ -63,6 +70,12 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) } EXPORT_SYMBOL_GPL(mctrl_gpio_set); +/** + * mctrl_gpio_to_gpiod - obtain gpio_desc of modem line index + * @gpios: gpios to look into + * @gidx: index of the modem line + * Returns: the gpio_desc structure associated to the modem line index + */ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) { @@ -73,6 +86,14 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, } EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); +/** + * mctrl_gpio_get - update mctrl with the gpios values. + * @gpios: gpios to get the info from + * @mctrl: mctrl to set + * Returns: modified mctrl (the same value as in @mctrl) + * + * Update mctrl with the gpios values. + */ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; @@ -163,7 +184,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) mctrl_gpio_get(gpios, &mctrl); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); mctrl_diff = mctrl ^ gpios->mctrl_prev; gpios->mctrl_prev = mctrl; @@ -184,11 +205,22 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) wake_up_interruptible(&port->state->port.delta_msr_wait); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return IRQ_HANDLED; } +/** + * mctrl_gpio_init - initialize uart gpios + * @port: port to initialize gpios for + * @idx: index of the gpio in the @port's device + * + * This will get the {cts,rts,...}-gpios from device tree if they are present + * and request them, set direction etc, and return an allocated structure. + * `devm_*` functions are used, so there's no need to explicitly free. + * As this sets up the irq handling, make sure to not handle changes to the + * gpio input lines in your driver, too. + */ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) { struct mctrl_gpios *gpios; @@ -207,7 +239,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) continue; ret = gpiod_to_irq(gpios->gpio[i]); - if (ret <= 0) { + if (ret < 0) { dev_err(port->dev, "failed to find corresponding irq for %s (idx=%d, err=%d)\n", mctrl_gpios_desc[i].name, idx, ret); @@ -235,24 +267,10 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) } EXPORT_SYMBOL_GPL(mctrl_gpio_init); -void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) -{ - enum mctrl_gpio_idx i; - - if (gpios == NULL) - return; - - for (i = 0; i < UART_GPIO_MAX; i++) { - if (gpios->irq[i]) - devm_free_irq(gpios->port->dev, gpios->irq[i], gpios); - - if (gpios->gpio[i]) - devm_gpiod_put(dev, gpios->gpio[i]); - } - devm_kfree(dev, gpios); -} -EXPORT_SYMBOL_GPL(mctrl_gpio_free); - +/** + * mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines + * @gpios: gpios to enable + */ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; @@ -278,7 +296,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) } EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms); -void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) +static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync) { enum mctrl_gpio_idx i; @@ -294,9 +312,72 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) if (!gpios->irq[i]) continue; - disable_irq(gpios->irq[i]); + if (sync) + disable_irq(gpios->irq[i]); + else + disable_irq_nosync(gpios->irq[i]); + } +} + +/** + * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms + * lines, and wait for any pending IRQ to be processed + * @gpios: gpios to disable + */ +void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios) +{ + mctrl_gpio_disable_ms(gpios, true); +} +EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync); + +/** + * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the + * ms lines, and return immediately + * @gpios: gpios to disable + */ +void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios) +{ + mctrl_gpio_disable_ms(gpios, false); +} +EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync); + +void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios) + return; + + if (!gpios->mctrl_on) + return; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + enable_irq_wake(gpios->irq[i]); + } +} +EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake); + +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios) + return; + + if (!gpios->mctrl_on) + return; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + disable_irq_wake(gpios->irq[i]); } } -EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); +EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake); +MODULE_DESCRIPTION("Helpers for controlling modem lines via GPIO"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index b134a0ffc894..961e4ba0c6f8 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -59,7 +59,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, /* * Request and set direction of modem control line GPIOs and set up irq * handling. - * devm_* functions are used, so there's no need to call mctrl_gpio_free(). + * devm_* functions are used, so there's no need to explicitly free. * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on * allocation error. */ @@ -67,7 +67,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx); /* * Request and set direction of modem control line GPIOs. - * devm_* functions are used, so there's no need to call mctrl_gpio_free(). + * devm_* functions are used, so there's no need to explicitly free. * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on * allocation error. */ @@ -75,21 +75,31 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx); /* - * Free the mctrl_gpios structure. - * Normally, this function will not be called, as the GPIOs will - * be disposed of by the resource management code. + * Enable gpio interrupts to report status line changes. */ -void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios); +void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); /* - * Enable gpio interrupts to report status line changes. + * Disable gpio interrupts to report status line changes, and block until + * any corresponding IRQ is processed */ -void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); +void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios); + +/* + * Disable gpio interrupts to report status line changes, and return + * immediately + */ +void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios); + +/* + * Enable gpio wakeup interrupts to enable wake up source. + */ +void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios); /* - * Disable gpio interrupts to report status line changes. + * Disable gpio wakeup interrupts to enable wake up source. */ -void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios); #else /* GPIOLIB */ @@ -129,16 +139,23 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) return NULL; } -static inline -void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) +static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) { } -static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) +static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios) +{ +} + +static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios) +{ +} + +static inline void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) { } -static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) +static inline void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) { } diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c new file mode 100644 index 000000000000..2fc48cd63f6c --- /dev/null +++ b/drivers/tty/serial/serial_port.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Serial core port device driver + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Tony Lindgren <tony@atomide.com> + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/pnp.h> +#include <linux/property.h> +#include <linux/serial_core.h> +#include <linux/spinlock.h> + +#include "serial_base.h" + +#define SERIAL_PORT_AUTOSUSPEND_DELAY_MS 500 + +/* Only considers pending TX for now. Caller must take care of locking */ +static int __serial_port_busy(struct uart_port *port) +{ + return !uart_tx_stopped(port) && + !kfifo_is_empty(&port->state->port.xmit_fifo); +} + +static int serial_port_runtime_resume(struct device *dev) +{ + struct serial_port_device *port_dev = to_serial_base_port_device(dev); + struct uart_port *port; + unsigned long flags; + + port = port_dev->port; + + if (port->flags & UPF_DEAD) + goto out; + + /* Flush any pending TX for the port */ + uart_port_lock_irqsave(port, &flags); + if (!port_dev->tx_enabled) + goto unlock; + if (__serial_port_busy(port)) + port->ops->start_tx(port); + +unlock: + uart_port_unlock_irqrestore(port, flags); + +out: + pm_runtime_mark_last_busy(dev); + + return 0; +} + +static int serial_port_runtime_suspend(struct device *dev) +{ + struct serial_port_device *port_dev = to_serial_base_port_device(dev); + struct uart_port *port = port_dev->port; + unsigned long flags; + bool busy; + + if (port->flags & UPF_DEAD) + return 0; + + /* + * Nothing to do on pm_runtime_force_suspend(), see + * DEFINE_RUNTIME_DEV_PM_OPS. + */ + if (!pm_runtime_enabled(dev)) + return 0; + + uart_port_lock_irqsave(port, &flags); + if (!port_dev->tx_enabled) { + uart_port_unlock_irqrestore(port, flags); + return 0; + } + + busy = __serial_port_busy(port); + if (busy) + port->ops->start_tx(port); + uart_port_unlock_irqrestore(port, flags); + + if (busy) + pm_runtime_mark_last_busy(dev); + + return busy ? -EBUSY : 0; +} + +static void serial_base_port_set_tx(struct uart_port *port, + struct serial_port_device *port_dev, + bool enabled) +{ + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + port_dev->tx_enabled = enabled; + uart_port_unlock_irqrestore(port, flags); +} + +void serial_base_port_startup(struct uart_port *port) +{ + struct serial_port_device *port_dev = port->port_dev; + + serial_base_port_set_tx(port, port_dev, true); +} + +void serial_base_port_shutdown(struct uart_port *port) +{ + struct serial_port_device *port_dev = port->port_dev; + + serial_base_port_set_tx(port, port_dev, false); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm, + serial_port_runtime_suspend, + serial_port_runtime_resume, NULL); + +static int serial_port_probe(struct device *dev) +{ + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, SERIAL_PORT_AUTOSUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + return 0; +} + +static int serial_port_remove(struct device *dev) +{ + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_disable(dev); + + return 0; +} + +/* + * Serial core port device init functions. Note that the physical serial + * port device driver may not have completed probe at this point. + */ +int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) +{ + return serial_ctrl_register_port(drv, port); +} +EXPORT_SYMBOL(uart_add_one_port); + +void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) +{ + serial_ctrl_unregister_port(drv, port); +} +EXPORT_SYMBOL(uart_remove_one_port); + +/** + * __uart_read_properties - read firmware properties of the given UART port + * @port: corresponding port + * @use_defaults: apply defaults (when %true) or validate the values (when %false) + * + * The following device properties are supported: + * - clock-frequency (optional) + * - fifo-size (optional) + * - no-loopback-test (optional) + * - reg-shift (defaults may apply) + * - reg-offset (value may be validated) + * - reg-io-width (defaults may apply or value may be validated) + * - interrupts (OF only) + * - serial [alias ID] (OF only) + * + * If the port->dev is of struct platform_device type the interrupt line + * will be retrieved via platform_get_irq() call against that device. + * Otherwise it will be assigned by fwnode_irq_get() call. In both cases + * the index 0 of the resource is used. + * + * The caller is responsible to initialize the following fields of the @port + * ->dev (must be valid) + * ->flags + * ->iobase + * ->mapbase + * ->mapsize + * ->regshift (if @use_defaults is false) + * before calling this function. Alternatively the above mentioned fields + * may be zeroed, in such case the only ones, that have associated properties + * found, will be set to the respective values. + * + * If no error happened, the ->irq, ->mapbase, ->mapsize will be altered. + * The ->iotype is always altered. + * + * When @use_defaults is true and the respective property is not found + * the following values will be applied: + * ->regshift = 0 + * In this case IRQ must be provided, otherwise an error will be returned. + * + * When @use_defaults is false and the respective property is found + * the following values will be validated: + * - reg-io-width (->iotype) + * - reg-offset (->mapsize against ->mapbase) + * + * Returns: 0 on success or negative errno on failure + */ +static int __uart_read_properties(struct uart_port *port, bool use_defaults) +{ + struct device *dev = port->dev; + u32 value; + int ret; + + /* Read optional UART functional clock frequency */ + device_property_read_u32(dev, "clock-frequency", &port->uartclk); + + /* Read the registers alignment (default: 8-bit) */ + ret = device_property_read_u32(dev, "reg-shift", &value); + if (ret) + port->regshift = use_defaults ? 0 : port->regshift; + else + port->regshift = value; + + /* Read the registers I/O access type (default: MMIO 8-bit) */ + ret = device_property_read_u32(dev, "reg-io-width", &value); + if (ret) { + port->iotype = port->iobase ? UPIO_PORT : UPIO_MEM; + } else { + switch (value) { + case 1: + port->iotype = UPIO_MEM; + break; + case 2: + port->iotype = UPIO_MEM16; + break; + case 4: + port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32; + break; + default: + port->iotype = UPIO_UNKNOWN; + break; + } + } + + if (!use_defaults && port->iotype == UPIO_UNKNOWN) { + dev_err(dev, "Unsupported reg-io-width (%u)\n", value); + return -EINVAL; + } + + /* Read the address mapping base offset (default: no offset) */ + ret = device_property_read_u32(dev, "reg-offset", &value); + if (ret) + value = 0; + + /* Check for shifted address mapping overflow */ + if (!use_defaults && port->mapsize < value) { + dev_err(dev, "reg-offset %u exceeds region size %pa\n", value, &port->mapsize); + return -EINVAL; + } + + port->mapbase += value; + port->mapsize -= value; + + /* Read optional FIFO size */ + device_property_read_u32(dev, "fifo-size", &port->fifosize); + + if (device_property_read_bool(dev, "no-loopback-test")) + port->flags |= UPF_SKIP_TEST; + + /* Get index of serial line, if found in DT aliases */ + ret = of_alias_get_id(dev_of_node(dev), "serial"); + if (ret >= 0) + port->line = ret; + + if (dev_is_platform(dev)) + ret = platform_get_irq(to_platform_device(dev), 0); + else if (dev_is_pnp(dev)) { + ret = pnp_irq(to_pnp_dev(dev), 0); + if (ret < 0) + ret = -ENXIO; + } else + ret = fwnode_irq_get(dev_fwnode(dev), 0); + if (ret == -EPROBE_DEFER) + return ret; + if (ret > 0) + port->irq = ret; + else if (use_defaults) + /* By default IRQ support is mandatory */ + return ret; + else + port->irq = 0; + + port->flags |= UPF_SHARE_IRQ; + + return 0; +} + +int uart_read_port_properties(struct uart_port *port) +{ + return __uart_read_properties(port, true); +} +EXPORT_SYMBOL_GPL(uart_read_port_properties); + +int uart_read_and_validate_port_properties(struct uart_port *port) +{ + return __uart_read_properties(port, false); +} +EXPORT_SYMBOL_GPL(uart_read_and_validate_port_properties); + +static struct device_driver serial_port_driver = { + .name = "port", + .suppress_bind_attrs = true, + .probe = serial_port_probe, + .remove = serial_port_remove, + .pm = pm_ptr(&serial_port_pm), +}; + +int serial_base_port_init(void) +{ + return serial_base_driver_register(&serial_port_driver); +} + +void serial_base_port_exit(void) +{ + serial_base_driver_unregister(&serial_port_driver); +} + +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_DESCRIPTION("Serial controller port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index b4d89e31730e..436a559234df 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -23,11 +23,9 @@ #include <linux/serial.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/io.h> -#include <asm/io.h> - -static char *serial_version = "1.11"; -static char *serial_name = "TX39/49 Serial driver"; +#include <asm/txx9/generic.h> #define PASS_LIMIT 256 @@ -57,11 +55,6 @@ static char *serial_name = "TX39/49 Serial driver"; */ #define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS -struct uart_txx9_port { - struct uart_port port; - /* No additional info for now */ -}; - #define TXX9_REGION_SIZE 0x24 /* TXX9 Serial Registers */ @@ -163,42 +156,42 @@ struct uart_txx9_port { #define TXX9_SIBGR_BCLK_T6 0x00000300 #define TXX9_SIBGR_BRD_MASK 0x000000ff -static inline unsigned int sio_in(struct uart_txx9_port *up, int offset) +static inline unsigned int sio_in(struct uart_port *up, int offset) { - switch (up->port.iotype) { + switch (up->iotype) { default: - return __raw_readl(up->port.membase + offset); + return __raw_readl(up->membase + offset); case UPIO_PORT: - return inl(up->port.iobase + offset); + return inl(up->iobase + offset); } } static inline void -sio_out(struct uart_txx9_port *up, int offset, int value) +sio_out(struct uart_port *up, int offset, int value) { - switch (up->port.iotype) { + switch (up->iotype) { default: - __raw_writel(value, up->port.membase + offset); + __raw_writel(value, up->membase + offset); break; case UPIO_PORT: - outl(value, up->port.iobase + offset); + outl(value, up->iobase + offset); break; } } static inline void -sio_mask(struct uart_txx9_port *up, int offset, unsigned int value) +sio_mask(struct uart_port *up, int offset, unsigned int value) { sio_out(up, offset, sio_in(up, offset) & ~value); } static inline void -sio_set(struct uart_txx9_port *up, int offset, unsigned int value) +sio_set(struct uart_port *up, int offset, unsigned int value) { sio_out(up, offset, sio_in(up, offset) | value); } static inline void -sio_quot_set(struct uart_txx9_port *up, int quot) +sio_quot_set(struct uart_port *up, int quot) { quot >>= 1; if (quot < 256) @@ -213,32 +206,23 @@ sio_quot_set(struct uart_txx9_port *up, int quot) sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6); } -static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port) -{ - return container_of(port, struct uart_txx9_port, port); -} - -static void serial_txx9_stop_tx(struct uart_port *port) +static void serial_txx9_stop_tx(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); } -static void serial_txx9_start_tx(struct uart_port *port) +static void serial_txx9_start_tx(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); } -static void serial_txx9_stop_rx(struct uart_port *port) +static void serial_txx9_stop_rx(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); - up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; + up->read_status_mask &= ~TXX9_SIDISR_RDIS; } -static void serial_txx9_initialize(struct uart_port *port) +static void serial_txx9_initialize(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned int tmout = 10000; sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); @@ -253,30 +237,29 @@ static void serial_txx9_initialize(struct uart_port *port) /* initial settings */ sio_out(up, TXX9_SILCR, TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | - ((up->port.flags & UPF_TXX9_USE_SCLK) ? + ((up->flags & UPF_TXX9_USE_SCLK) ? TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); - sio_quot_set(up, uart_get_divisor(port, 9600)); + sio_quot_set(up, uart_get_divisor(up, 9600)); sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); sio_out(up, TXX9_SIDICR, 0); } static inline void -receive_chars(struct uart_txx9_port *up, unsigned int *status) +receive_chars(struct uart_port *up, unsigned int *status) { - unsigned char ch; unsigned int disr = *status; int max_count = 256; - char flag; unsigned int next_ignore_status_mask; + u8 ch, flag; do { ch = sio_in(up, TXX9_SIRFIFO); flag = TTY_NORMAL; - up->port.icount.rx++; + up->icount.rx++; /* mask out RFDN_MASK bit added by previous overrun */ next_ignore_status_mask = - up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK; + up->ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK; if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER | TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { /* @@ -284,21 +267,21 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) */ if (disr & TXX9_SIDISR_UBRK) { disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER); - up->port.icount.brk++; + up->icount.brk++; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ - if (uart_handle_break(&up->port)) + if (uart_handle_break(up)) goto ignore_char; } else if (disr & TXX9_SIDISR_UPER) - up->port.icount.parity++; + up->icount.parity++; else if (disr & TXX9_SIDISR_UFER) - up->port.icount.frame++; + up->icount.frame++; if (disr & TXX9_SIDISR_UOER) { - up->port.icount.overrun++; + up->icount.overrun++; /* * The receiver read buffer still hold * a char which caused overrun. @@ -312,7 +295,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) /* * Mask off conditions which should be ingored. */ - disr &= up->port.read_status_mask; + disr &= up->read_status_mask; if (disr & TXX9_SIDISR_UBRK) { flag = TTY_BREAK; @@ -321,67 +304,45 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) else if (disr & TXX9_SIDISR_UFER) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_handle_sysrq_char(up, ch)) goto ignore_char; - uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); + uart_insert_char(up, disr, TXX9_SIDISR_UOER, ch, flag); ignore_char: - up->port.ignore_status_mask = next_ignore_status_mask; + up->ignore_status_mask = next_ignore_status_mask; disr = sio_in(up, TXX9_SIDISR); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); - spin_unlock(&up->port.lock); - tty_flip_buffer_push(&up->port.state->port); - spin_lock(&up->port.lock); + + tty_flip_buffer_push(&up->state->port); + *status = disr; } -static inline void transmit_chars(struct uart_txx9_port *up) +static inline void transmit_chars(struct uart_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; - int count; + u8 ch; - if (up->port.x_char) { - sio_out(up, TXX9_SITFIFO, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_txx9_stop_tx(&up->port); - return; - } - - count = TXX9_SIO_TX_FIFO; - do { - sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_txx9_stop_tx(&up->port); + uart_port_tx_limited(up, ch, TXX9_SIO_TX_FIFO, + true, + sio_out(up, TXX9_SITFIFO, ch), + ({})); } static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) { int pass_counter = 0; - struct uart_txx9_port *up = dev_id; + struct uart_port *up = dev_id; unsigned int status; while (1) { - spin_lock(&up->port.lock); + uart_port_lock(up); status = sio_in(up, TXX9_SIDISR); if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE)) status &= ~TXX9_SIDISR_TDIS; if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | TXX9_SIDISR_TOUT))) { - spin_unlock(&up->port.lock); + uart_port_unlock(up); break; } @@ -393,7 +354,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | TXX9_SIDISR_TOUT); - spin_unlock(&up->port.lock); + uart_port_unlock(up); if (pass_counter++ > PASS_LIMIT) break; @@ -402,22 +363,20 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) return pass_counter ? IRQ_HANDLED : IRQ_NONE; } -static unsigned int serial_txx9_tx_empty(struct uart_port *port) +static unsigned int serial_txx9_tx_empty(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(up, &flags); ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(up, flags); return ret; } -static unsigned int serial_txx9_get_mctrl(struct uart_port *port) +static unsigned int serial_txx9_get_mctrl(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned int ret; /* no modem control lines */ @@ -428,9 +387,8 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port) return ret; } -static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void serial_txx9_set_mctrl(struct uart_port *up, unsigned int mctrl) { - struct uart_txx9_port *up = to_uart_txx9_port(port); if (mctrl & TIOCM_RTS) sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); @@ -438,24 +396,23 @@ static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); } -static void serial_txx9_break_ctl(struct uart_port *port, int break_state) +static void serial_txx9_break_ctl(struct uart_port *up, int break_state) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(up, &flags); if (break_state == -1) sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); else sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(up, flags); } #if defined(CONFIG_SERIAL_TXX9_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /* * Wait for transmitter & holding register to empty */ -static void wait_for_xmitr(struct uart_txx9_port *up) +static void wait_for_xmitr(struct uart_port *up) { unsigned int tmout = 10000; @@ -465,7 +422,7 @@ static void wait_for_xmitr(struct uart_txx9_port *up) udelay(1); /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { + if (up->flags & UPF_CONS_FLOW) { tmout = 1000000; while (--tmout && (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) @@ -480,11 +437,10 @@ static void wait_for_xmitr(struct uart_txx9_port *up) * in an interrupt or debug context. */ -static int serial_txx9_get_poll_char(struct uart_port *port) +static int serial_txx9_get_poll_char(struct uart_port *up) { unsigned int ier; unsigned char c; - struct uart_txx9_port *up = to_uart_txx9_port(port); /* * First save the IER then disable the interrupts @@ -507,10 +463,9 @@ static int serial_txx9_get_poll_char(struct uart_port *port) } -static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) +static void serial_txx9_put_poll_char(struct uart_port *up, unsigned char c) { unsigned int ier; - struct uart_txx9_port *up = to_uart_txx9_port(port); /* * First save the IER then disable the interrupts @@ -534,9 +489,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) #endif /* CONFIG_CONSOLE_POLL */ -static int serial_txx9_startup(struct uart_port *port) +static int serial_txx9_startup(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; int retval; @@ -556,7 +510,7 @@ static int serial_txx9_startup(struct uart_port *port) */ sio_out(up, TXX9_SIDISR, 0); - retval = request_irq(up->port.irq, serial_txx9_interrupt, + retval = request_irq(up->irq, serial_txx9_interrupt, IRQF_SHARED, "serial_txx9", up); if (retval) return retval; @@ -564,9 +518,9 @@ static int serial_txx9_startup(struct uart_port *port) /* * Now, initialize the UART */ - spin_lock_irqsave(&up->port.lock, flags); - serial_txx9_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_lock_irqsave(up, &flags); + serial_txx9_set_mctrl(up, up->mctrl); + uart_port_unlock_irqrestore(up, flags); /* Enable RX/TX */ sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); @@ -579,9 +533,8 @@ static int serial_txx9_startup(struct uart_port *port) return 0; } -static void serial_txx9_shutdown(struct uart_port *port) +static void serial_txx9_shutdown(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; /* @@ -589,9 +542,9 @@ static void serial_txx9_shutdown(struct uart_port *port) */ sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */ - spin_lock_irqsave(&up->port.lock, flags); - serial_txx9_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_lock_irqsave(up, &flags); + serial_txx9_set_mctrl(up, up->mctrl); + uart_port_unlock_irqrestore(up, flags); /* * Disable break condition @@ -599,8 +552,8 @@ static void serial_txx9_shutdown(struct uart_port *port) sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); #ifdef CONFIG_SERIAL_TXX9_CONSOLE - if (up->port.cons && up->port.line == up->port.cons->index) { - free_irq(up->port.irq, up); + if (up->cons && up->line == up->cons->index) { + free_irq(up->irq, up); return; } #endif @@ -614,14 +567,13 @@ static void serial_txx9_shutdown(struct uart_port *port) /* Disable RX/TX */ sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); - free_irq(up->port.irq, up); + free_irq(up->irq, up); } static void -serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios, + const struct ktermios *old) { - struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned int cval, fcr = 0; unsigned long flags; unsigned int baud, quot; @@ -644,6 +596,8 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, case CS6: /* not supported */ case CS8: cval |= TXX9_SILCR_UMODE_8BIT; + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; break; } @@ -661,8 +615,8 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2); - quot = uart_get_divisor(port, baud); + baud = uart_get_baud_rate(up, termios, old, 0, up->uartclk/16/2); + quot = uart_get_divisor(up, baud); /* Set up FIFOs */ /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ @@ -672,45 +626,45 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(up, &flags); /* * Update the per-port timeout. */ - uart_update_timeout(port, termios->c_cflag, baud); + uart_update_timeout(up, termios->c_cflag, baud); - up->port.read_status_mask = TXX9_SIDISR_UOER | + up->read_status_mask = TXX9_SIDISR_UOER | TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; if (termios->c_iflag & INPCK) - up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; + up->read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - up->port.read_status_mask |= TXX9_SIDISR_UBRK; + up->read_status_mask |= TXX9_SIDISR_UBRK; /* * Characteres to ignore */ - up->port.ignore_status_mask = 0; + up->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER; + up->ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER; if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= TXX9_SIDISR_UBRK; + up->ignore_status_mask |= TXX9_SIDISR_UBRK; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= TXX9_SIDISR_UOER; + up->ignore_status_mask |= TXX9_SIDISR_UOER; } /* * ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= TXX9_SIDISR_RDIS; + up->ignore_status_mask |= TXX9_SIDISR_RDIS; /* CTS flow control flag */ if ((termios->c_cflag & CRTSCTS) && - (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) { + (up->flags & UPF_TXX9_HAVE_CTS_LINE)) { sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); } else { @@ -722,8 +676,8 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, sio_quot_set(up, quot); sio_out(up, TXX9_SIFCR, fcr); - serial_txx9_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + serial_txx9_set_mctrl(up, up->mctrl); + uart_port_unlock_irqrestore(up, flags); } static void @@ -742,76 +696,73 @@ serial_txx9_pm(struct uart_port *port, unsigned int state, serial_txx9_initialize(port); } -static int serial_txx9_request_resource(struct uart_txx9_port *up) +static int serial_txx9_request_resource(struct uart_port *up) { unsigned int size = TXX9_REGION_SIZE; int ret = 0; - switch (up->port.iotype) { + switch (up->iotype) { default: - if (!up->port.mapbase) + if (!up->mapbase) break; - if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) { + if (!request_mem_region(up->mapbase, size, "serial_txx9")) { ret = -EBUSY; break; } - if (up->port.flags & UPF_IOREMAP) { - up->port.membase = ioremap(up->port.mapbase, size); - if (!up->port.membase) { - release_mem_region(up->port.mapbase, size); + if (up->flags & UPF_IOREMAP) { + up->membase = ioremap(up->mapbase, size); + if (!up->membase) { + release_mem_region(up->mapbase, size); ret = -ENOMEM; } } break; case UPIO_PORT: - if (!request_region(up->port.iobase, size, "serial_txx9")) + if (!request_region(up->iobase, size, "serial_txx9")) ret = -EBUSY; break; } return ret; } -static void serial_txx9_release_resource(struct uart_txx9_port *up) +static void serial_txx9_release_resource(struct uart_port *up) { unsigned int size = TXX9_REGION_SIZE; - switch (up->port.iotype) { + switch (up->iotype) { default: - if (!up->port.mapbase) + if (!up->mapbase) break; - if (up->port.flags & UPF_IOREMAP) { - iounmap(up->port.membase); - up->port.membase = NULL; + if (up->flags & UPF_IOREMAP) { + iounmap(up->membase); + up->membase = NULL; } - release_mem_region(up->port.mapbase, size); + release_mem_region(up->mapbase, size); break; case UPIO_PORT: - release_region(up->port.iobase, size); + release_region(up->iobase, size); break; } } -static void serial_txx9_release_port(struct uart_port *port) +static void serial_txx9_release_port(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); serial_txx9_release_resource(up); } -static int serial_txx9_request_port(struct uart_port *port) +static int serial_txx9_request_port(struct uart_port *up) { - struct uart_txx9_port *up = to_uart_txx9_port(port); return serial_txx9_request_resource(up); } -static void serial_txx9_config_port(struct uart_port *port, int uflags) +static void serial_txx9_config_port(struct uart_port *up, int uflags) { - struct uart_txx9_port *up = to_uart_txx9_port(port); int ret; /* @@ -821,14 +772,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags) ret = serial_txx9_request_resource(up); if (ret < 0) return; - port->type = PORT_TXX9; - up->port.fifosize = TXX9_SIO_TX_FIFO; + up->type = PORT_TXX9; + up->fifosize = TXX9_SIO_TX_FIFO; #ifdef CONFIG_SERIAL_TXX9_CONSOLE - if (up->port.line == up->port.cons->index) + if (up->line == up->cons->index) return; #endif - serial_txx9_initialize(port); + serial_txx9_initialize(up); } static const char * @@ -859,7 +810,7 @@ static const struct uart_ops serial_txx9_pops = { #endif }; -static struct uart_txx9_port serial_txx9_ports[UART_NR]; +static struct uart_port serial_txx9_ports[UART_NR]; static void __init serial_txx9_register_ports(struct uart_driver *drv, struct device *dev) @@ -867,22 +818,20 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv, int i; for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; + struct uart_port *up = &serial_txx9_ports[i]; - up->port.line = i; - up->port.ops = &serial_txx9_pops; - up->port.dev = dev; - if (up->port.iobase || up->port.mapbase) - uart_add_one_port(drv, &up->port); + up->line = i; + up->ops = &serial_txx9_pops; + up->dev = dev; + if (up->iobase || up->mapbase) + uart_add_one_port(drv, up); } } #ifdef CONFIG_SERIAL_TXX9_CONSOLE -static void serial_txx9_console_putchar(struct uart_port *port, int ch) +static void serial_txx9_console_putchar(struct uart_port *up, unsigned char ch) { - struct uart_txx9_port *up = to_uart_txx9_port(port); - wait_for_xmitr(up); sio_out(up, TXX9_SITFIFO, ch); } @@ -896,7 +845,7 @@ static void serial_txx9_console_putchar(struct uart_port *port, int ch) static void serial_txx9_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_txx9_port *up = &serial_txx9_ports[co->index]; + struct uart_port *up = &serial_txx9_ports[co->index]; unsigned int ier, flcr; /* @@ -908,10 +857,10 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) * Disable flow-control if enabled (and unnecessary) */ flcr = sio_in(up, TXX9_SIFLCR); - if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) + if (!(up->flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES); - uart_console_write(&up->port, s, count, serial_txx9_console_putchar); + uart_console_write(up, s, count, serial_txx9_console_putchar); /* * Finally, wait for transmitter to become empty @@ -924,8 +873,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) static int __init serial_txx9_console_setup(struct console *co, char *options) { - struct uart_port *port; - struct uart_txx9_port *up; + struct uart_port *up; int baud = 9600; int bits = 8; int parity = 'n'; @@ -939,16 +887,15 @@ static int __init serial_txx9_console_setup(struct console *co, char *options) if (co->index >= UART_NR) co->index = 0; up = &serial_txx9_ports[co->index]; - port = &up->port; - if (!port->ops) + if (!up->ops) return -ENODEV; - serial_txx9_initialize(&up->port); + serial_txx9_initialize(up); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(up, co, baud, parity, bits, flow); } static struct uart_driver serial_txx9_reg; @@ -989,9 +936,9 @@ int __init early_serial_txx9_setup(struct uart_port *port) if (port->line >= ARRAY_SIZE(serial_txx9_ports)) return -ENODEV; - serial_txx9_ports[port->line].port = *port; - serial_txx9_ports[port->line].port.ops = &serial_txx9_pops; - serial_txx9_ports[port->line].port.flags |= + serial_txx9_ports[port->line] = *port; + serial_txx9_ports[port->line].ops = &serial_txx9_pops; + serial_txx9_ports[port->line].flags |= UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; return 0; } @@ -1012,14 +959,14 @@ static DEFINE_MUTEX(serial_txx9_mutex); static int serial_txx9_register_port(struct uart_port *port) { int i; - struct uart_txx9_port *uart; + struct uart_port *uart; int ret = -ENOSPC; mutex_lock(&serial_txx9_mutex); for (i = 0; i < UART_NR; i++) { uart = &serial_txx9_ports[i]; - if (uart_match_port(&uart->port, port)) { - uart_remove_one_port(&serial_txx9_reg, &uart->port); + if (uart_match_port(uart, port)) { + uart_remove_one_port(&serial_txx9_reg, uart); break; } } @@ -1027,24 +974,24 @@ static int serial_txx9_register_port(struct uart_port *port) /* Find unused port */ for (i = 0; i < UART_NR; i++) { uart = &serial_txx9_ports[i]; - if (!(uart->port.iobase || uart->port.mapbase)) + if (!(uart->iobase || uart->mapbase)) break; } } if (i < UART_NR) { - uart->port.iobase = port->iobase; - uart->port.membase = port->membase; - uart->port.irq = port->irq; - uart->port.uartclk = port->uartclk; - uart->port.iotype = port->iotype; - uart->port.flags = port->flags + uart->iobase = port->iobase; + uart->membase = port->membase; + uart->irq = port->irq; + uart->uartclk = port->uartclk; + uart->iotype = port->iotype; + uart->flags = port->flags | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; - uart->port.mapbase = port->mapbase; + uart->mapbase = port->mapbase; if (port->dev) - uart->port.dev = port->dev; - ret = uart_add_one_port(&serial_txx9_reg, &uart->port); + uart->dev = port->dev; + ret = uart_add_one_port(&serial_txx9_reg, uart); if (ret == 0) - ret = uart->port.line; + ret = uart->line; } mutex_unlock(&serial_txx9_mutex); return ret; @@ -1059,16 +1006,16 @@ static int serial_txx9_register_port(struct uart_port *port) */ static void serial_txx9_unregister_port(int line) { - struct uart_txx9_port *uart = &serial_txx9_ports[line]; + struct uart_port *uart = &serial_txx9_ports[line]; mutex_lock(&serial_txx9_mutex); - uart_remove_one_port(&serial_txx9_reg, &uart->port); - uart->port.flags = 0; - uart->port.type = PORT_UNKNOWN; - uart->port.iobase = 0; - uart->port.mapbase = 0; - uart->port.membase = NULL; - uart->port.dev = NULL; + uart_remove_one_port(&serial_txx9_reg, uart); + uart->flags = 0; + uart->type = PORT_UNKNOWN; + uart->iobase = 0; + uart->mapbase = 0; + uart->membase = NULL; + uart->dev = NULL; mutex_unlock(&serial_txx9_mutex); } @@ -1106,17 +1053,16 @@ static int serial_txx9_probe(struct platform_device *dev) /* * Remove serial ports registered against a platform device. */ -static int serial_txx9_remove(struct platform_device *dev) +static void serial_txx9_remove(struct platform_device *dev) { int i; for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; + struct uart_port *up = &serial_txx9_ports[i]; - if (up->port.dev == &dev->dev) + if (up->dev == &dev->dev) serial_txx9_unregister_port(i); } - return 0; } #ifdef CONFIG_PM @@ -1125,10 +1071,10 @@ static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state) int i; for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; + struct uart_port *up = &serial_txx9_ports[i]; - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_suspend_port(&serial_txx9_reg, &up->port); + if (up->type != PORT_UNKNOWN && up->dev == &dev->dev) + uart_suspend_port(&serial_txx9_reg, up); } return 0; @@ -1139,10 +1085,10 @@ static int serial_txx9_resume(struct platform_device *dev) int i; for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; + struct uart_port *up = &serial_txx9_ports[i]; - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_resume_port(&serial_txx9_reg, &up->port); + if (up->type != PORT_UNKNOWN && up->dev == &dev->dev) + uart_resume_port(&serial_txx9_reg, up); } return 0; @@ -1198,10 +1144,10 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) static void pciserial_txx9_remove_one(struct pci_dev *dev) { - struct uart_txx9_port *up = pci_get_drvdata(dev); + struct uart_port *up = pci_get_drvdata(dev); if (up) { - serial_txx9_unregister_port(up->port.line); + serial_txx9_unregister_port(up->line); pci_disable_device(dev); } } @@ -1209,10 +1155,10 @@ static void pciserial_txx9_remove_one(struct pci_dev *dev) #ifdef CONFIG_PM static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) { - struct uart_txx9_port *up = pci_get_drvdata(dev); + struct uart_port *up = pci_get_drvdata(dev); if (up) - uart_suspend_port(&serial_txx9_reg, &up->port); + uart_suspend_port(&serial_txx9_reg, up); pci_save_state(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; @@ -1220,12 +1166,12 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) static int pciserial_txx9_resume_one(struct pci_dev *dev) { - struct uart_txx9_port *up = pci_get_drvdata(dev); + struct uart_port *up = pci_get_drvdata(dev); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); if (up) - uart_resume_port(&serial_txx9_reg, &up->port); + uart_resume_port(&serial_txx9_reg, up); return 0; } #endif @@ -1255,8 +1201,6 @@ static int __init serial_txx9_init(void) { int ret; - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); - ret = uart_register_driver(&serial_txx9_reg); if (ret) goto out; @@ -1280,6 +1224,9 @@ static int __init serial_txx9_init(void) #ifdef ENABLE_SERIAL_TXX9_PCI ret = pci_register_driver(&serial_txx9_pci_driver); + if (ret) { + platform_driver_unregister(&serial_txx9_plat_driver); + } #endif if (ret == 0) goto out; @@ -1304,9 +1251,9 @@ static void __exit serial_txx9_exit(void) platform_driver_unregister(&serial_txx9_plat_driver); platform_device_unregister(serial_txx9_plat_devs); for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; - if (up->port.iobase || up->port.mapbase) - uart_remove_one_port(&serial_txx9_reg, &up->port); + struct uart_port *up = &serial_txx9_ports[i]; + if (up->iobase || up->mapbase) + uart_remove_one_port(&serial_txx9_reg, up); } uart_unregister_driver(&serial_txx9_reg); diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h new file mode 100644 index 000000000000..e3c028df14f1 --- /dev/null +++ b/drivers/tty/serial/sh-sci-common.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __SH_SCI_COMMON_H__ +#define __SH_SCI_COMMON_H__ + +#include <linux/serial_core.h> + +/* Private port IDs */ +enum SCI_PORT_TYPE { + SCI_PORT_RSCI = BIT(7) | 0, +}; + +enum SCI_CLKS { + SCI_FCK, /* Functional Clock */ + SCI_SCK, /* Optional External Clock */ + SCI_BRG_INT, /* Optional BRG Internal Clock Source */ + SCI_SCIF_CLK, /* Optional BRG External Clock Source */ + SCI_NUM_CLKS +}; + +/* Offsets into the sci_port->irqs array */ +enum { + SCIx_ERI_IRQ, + SCIx_RXI_IRQ, + SCIx_TXI_IRQ, + SCIx_BRI_IRQ, + SCIx_DRI_IRQ, + SCIx_TEI_IRQ, + SCIx_NR_IRQS, + + SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ +}; + +/* Bit x set means sampling rate x + 1 is supported */ +#define SCI_SR(x) BIT((x) - 1) +#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1) + +void sci_release_port(struct uart_port *port); +int sci_request_port(struct uart_port *port); +void sci_config_port(struct uart_port *port, int flags); +int sci_verify_port(struct uart_port *port, struct serial_struct *ser); +void sci_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate); + +struct plat_sci_reg { + u8 offset; + u8 size; +}; + +struct sci_port_params_bits { + unsigned int rxtx_enable; + unsigned int te_clear; + unsigned int poll_sent_bits; +}; + +struct sci_common_regs { + unsigned int status; + unsigned int control; +}; + +/* The actual number of needed registers. This is used by sci only */ +#define SCI_NR_REGS 20 + +struct sci_port_params { + const struct plat_sci_reg regs[SCI_NR_REGS]; + const struct sci_common_regs *common_regs; + const struct sci_port_params_bits *param_bits; + unsigned int fifosize; + unsigned int overrun_reg; + unsigned int overrun_mask; + unsigned int sampling_rate_mask; + unsigned int error_mask; + unsigned int error_clear; +}; + +struct sci_port_ops { + u32 (*read_reg)(struct uart_port *port, int reg); + void (*write_reg)(struct uart_port *port, int reg, int value); + void (*clear_SCxSR)(struct uart_port *port, unsigned int mask); + + void (*transmit_chars)(struct uart_port *port); + void (*receive_chars)(struct uart_port *port); + + void (*poll_put_char)(struct uart_port *port, unsigned char c); + + int (*set_rtrg)(struct uart_port *port, int rx_trig); + int (*rtrg_enabled)(struct uart_port *port); + + void (*shutdown_complete)(struct uart_port *port); + + void (*prepare_console_write)(struct uart_port *port, u32 ctrl); + void (*console_save)(struct uart_port *port); + void (*console_restore)(struct uart_port *port); + size_t (*suspend_regs_size)(void); +}; + +struct sci_of_data { + const struct sci_port_params *params; + const struct uart_ops *uart_ops; + const struct sci_port_ops *ops; + unsigned short regtype; + unsigned short type; +}; + +struct sci_port { + struct uart_port port; + + /* Platform configuration */ + const struct sci_port_params *params; + const struct plat_sci_port *cfg; + + unsigned int sampling_rate_mask; + resource_size_t reg_size; + struct mctrl_gpios *gpios; + + /* Clocks */ + struct clk *clks[SCI_NUM_CLKS]; + unsigned long clk_rates[SCI_NUM_CLKS]; + + int irqs[SCIx_NR_IRQS]; + char *irqstr[SCIx_NR_IRQS]; + + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + + struct reset_control *rstc; + struct sci_suspend_regs *suspend_regs; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct dma_chan *chan_tx_saved; + struct dma_chan *chan_rx_saved; + dma_cookie_t cookie_tx; + dma_cookie_t cookie_rx[2]; + dma_cookie_t active_rx; + dma_addr_t tx_dma_addr; + unsigned int tx_dma_len; + struct scatterlist sg_rx[2]; + void *rx_buf[2]; + size_t buf_len_rx; + struct work_struct work_tx; + struct hrtimer rx_timer; + unsigned int rx_timeout; /* microseconds */ +#endif + unsigned int rx_frame; + int rx_trigger; + struct timer_list rx_fifo_timer; + int rx_fifo_timeout; + u16 hscif_tot; + + u8 type; + u8 regtype; + + const struct sci_port_ops *ops; + + bool has_rtscts; + bool autorts; + bool tx_occurred; +}; + +#define to_sci_port(uart) container_of((uart), struct sci_port, port) + +void sci_port_disable(struct sci_port *sci_port); +void sci_port_enable(struct sci_port *sci_port); + +int sci_startup(struct uart_port *port); +void sci_shutdown(struct uart_port *port); + +#define min_sr(_port) ffs((_port)->sampling_rate_mask) +#define max_sr(_port) fls((_port)->sampling_rate_mask) + +#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON +int __init scix_early_console_setup(struct earlycon_device *device, const struct sci_of_data *data); +#endif + +#endif /* __SH_SCI_COMMON_H__ */ diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e1179e74a2b8..53edbf1d8963 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -17,28 +17,32 @@ */ #undef DEBUG +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/console.h> -#include <linux/ctype.h> #include <linux/cpufreq.h> +#include <linux/ctype.h> #include <linux/delay.h> -#include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/ioport.h> #include <linux/ktime.h> #include <linux/major.h> -#include <linux/module.h> +#include <linux/minmax.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/scatterlist.h> #include <linux/serial.h> +#include <linux/serial_core.h> #include <linux/serial_sci.h> #include <linux/sh_dma.h> #include <linux/slab.h> @@ -49,125 +53,245 @@ #include <linux/tty_flip.h> #ifdef CONFIG_SUPERH -#include <asm/sh_bios.h> #include <asm/platform_early.h> +#include <asm/sh_bios.h> #endif +#include "rsci.h" #include "serial_mctrl_gpio.h" -#include "sh-sci.h" +#include "sh-sci-common.h" + +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 -/* Offsets into the sci_port->irqs array */ +/* + * SCI register subset common for all port types. + * Not all registers will exist on all parts. + */ enum { - SCIx_ERI_IRQ, - SCIx_RXI_IRQ, - SCIx_TXI_IRQ, - SCIx_BRI_IRQ, - SCIx_DRI_IRQ, - SCIx_TEI_IRQ, - SCIx_NR_IRQS, - - SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ + SCSMR, /* Serial Mode Register */ + SCBRR, /* Bit Rate Register */ + SCSCR, /* Serial Control Register */ + SCxSR, /* Serial Status Register */ + SCFCR, /* FIFO Control Register */ + SCFDR, /* FIFO Data Count Register */ + SCxTDR, /* Transmit (FIFO) Data Register */ + SCxRDR, /* Receive (FIFO) Data Register */ + SCLSR, /* Line Status Register */ + SCTFDR, /* Transmit FIFO Data Count Register */ + SCRFDR, /* Receive FIFO Data Count Register */ + SCSPTR, /* Serial Port Register */ + HSSRR, /* Sampling Rate Register */ + SCPCR, /* Serial Port Control Register */ + SCPDR, /* Serial Port Data Register */ + SCDL, /* BRG Frequency Division Register */ + SCCKS, /* BRG Clock Select Register */ + HSRTRGR, /* Rx FIFO Data Count Trigger Register */ + HSTTRGR, /* Tx FIFO Data Count Trigger Register */ + SEMR, /* Serial extended mode register */ }; +/* SCSMR (Serial Mode Register) */ +#define SCSMR_C_A BIT(7) /* Communication Mode */ +#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */ +#define SCSMR_ASYNC 0 /* - Asynchronous mode */ +#define SCSMR_CHR BIT(6) /* 7-bit Character Length */ +#define SCSMR_PE BIT(5) /* Parity Enable */ +#define SCSMR_ODD BIT(4) /* Odd Parity */ +#define SCSMR_STOP BIT(3) /* Stop Bit Length */ +#define SCSMR_CKS 0x0003 /* Clock Select */ + +/* Serial Mode Register, SCIFA/SCIFB only bits */ +#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */ +#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */ +#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */ +#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */ +#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */ +#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */ +#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */ +#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */ +#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */ +#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */ + +/* Serial Control Register, SCI only bits */ +#define SCSCR_TEIE BIT(2) /* Transmit End Interrupt Enable */ + +/* Serial Control Register, SCIFA/SCIFB only bits */ +#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ +#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ + +/* Serial Control Register, HSCIF-only bits */ +#define HSSCR_TOT_SHIFT 14 + +/* SCxSR (Serial Status Register) on SCI */ +#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */ +#define SCI_RDRF BIT(6) /* Receive Data Register Full */ +#define SCI_ORER BIT(5) /* Overrun Error */ +#define SCI_FER BIT(4) /* Framing Error */ +#define SCI_PER BIT(3) /* Parity Error */ +#define SCI_TEND BIT(2) /* Transmit End */ +#define SCI_RESERVED 0x03 /* All reserved bits */ + +#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER) + +#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF)) +#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)) +#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE)) +#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)) + +/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */ +#define SCIF_ER BIT(7) /* Receive Error */ +#define SCIF_TEND BIT(6) /* Transmission End */ +#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */ +#define SCIF_BRK BIT(4) /* Break Detect */ +#define SCIF_FER BIT(3) /* Framing Error */ +#define SCIF_PER BIT(2) /* Parity Error */ +#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */ +#define SCIF_DR BIT(0) /* Receive Data Ready */ +/* SCIF only (optional) */ +#define SCIF_PERC 0xf000 /* Number of Parity Errors */ +#define SCIF_FERC 0x0f00 /* Number of Framing Errors */ +/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */ +#define SCIFA_ORER BIT(9) /* Overrun Error */ + +#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER) + +#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF)) +#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER)) +#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE)) +#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK)) + +/* SCFCR (FIFO Control Register) */ +#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger */ +#define SCFCR_RTRG0 BIT(6) +#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger */ +#define SCFCR_TTRG0 BIT(4) +#define SCFCR_MCE BIT(3) /* Modem Control Enable */ +#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */ +#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */ +#define SCFCR_LOOP BIT(0) /* Loopback Test */ + +/* SCLSR (Line Status Register) on (H)SCIF */ +#define SCLSR_TO BIT(2) /* Timeout */ +#define SCLSR_ORER BIT(0) /* Overrun Error */ + +/* SCSPTR (Serial Port Register), optional */ +#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */ +#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */ +#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */ +#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */ +#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */ +#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */ +#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ +#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ + +/* HSSRR HSCIF */ +#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ +#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */ + +#define HSCIF_SRHP_SHIFT 8 +#define HSCIF_SRHP_MASK 0x0f00 + +/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ +#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */ +#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */ +#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */ +#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */ +#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */ + +/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ +#define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */ +#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */ +#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */ +#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */ +#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */ + +/* + * BRG Clock Select Register (Some SCIF and HSCIF) + * The Baud Rate Generator for external clock can provide a clock source for + * the sampling clock. It outputs either its frequency divided clock, or the + * (undivided) (H)SCK external clock. + */ +#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */ +#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */ + +#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) +#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_DR | SCIF_RDF) +#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) +#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) +#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) + +#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask) + +#define SCxSR_RDxF_CLEAR(port) \ + (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) +#define SCxSR_ERROR_CLEAR(port) \ + (to_sci_port(port)->params->error_clear) +#define SCxSR_TDxE_CLEAR(port) \ + (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) +#define SCxSR_BREAK_CLEAR(port) \ + (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) + #define SCIx_IRQ_IS_MUXED(port) \ ((port)->irqs[SCIx_ERI_IRQ] == \ (port)->irqs[SCIx_RXI_IRQ]) || \ ((port)->irqs[SCIx_ERI_IRQ] && \ ((port)->irqs[SCIx_RXI_IRQ] < 0)) -enum SCI_CLKS { - SCI_FCK, /* Functional Clock */ - SCI_SCK, /* Optional External Clock */ - SCI_BRG_INT, /* Optional BRG Internal Clock Source */ - SCI_SCIF_CLK, /* Optional BRG External Clock Source */ - SCI_NUM_CLKS -}; - -/* Bit x set means sampling rate x + 1 is supported */ -#define SCI_SR(x) BIT((x) - 1) -#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1) - #define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \ SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \ SCI_SR(19) | SCI_SR(27) -#define min_sr(_port) ffs((_port)->sampling_rate_mask) -#define max_sr(_port) fls((_port)->sampling_rate_mask) - /* Iterate over all supported sampling rates, from high to low */ #define for_each_sr(_sr, _port) \ for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \ if ((_port)->sampling_rate_mask & SCI_SR((_sr))) -struct plat_sci_reg { - u8 offset, size; -}; - -struct sci_port_params { - const struct plat_sci_reg regs[SCIx_NR_REGS]; - unsigned int fifosize; - unsigned int overrun_reg; - unsigned int overrun_mask; - unsigned int sampling_rate_mask; - unsigned int error_mask; - unsigned int error_clear; -}; - -struct sci_port { - struct uart_port port; - - /* Platform configuration */ - const struct sci_port_params *params; - const struct plat_sci_port *cfg; - unsigned int sampling_rate_mask; - resource_size_t reg_size; - struct mctrl_gpios *gpios; +#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS - /* Clocks */ - struct clk *clks[SCI_NUM_CLKS]; - unsigned long clk_rates[SCI_NUM_CLKS]; +#define SCI_PUBLIC_PORT_ID(port) (((port) & BIT(7)) ? PORT_GENERIC : (port)) - int irqs[SCIx_NR_IRQS]; - char *irqstr[SCIx_NR_IRQS]; +static struct sci_port sci_ports[SCI_NPORTS]; +static unsigned long sci_ports_in_use; +static struct uart_driver sci_uart_driver; +static bool sci_uart_earlycon; +static bool sci_uart_earlycon_dev_probing; - struct dma_chan *chan_tx; - struct dma_chan *chan_rx; +static const struct sci_port_params_bits sci_sci_port_params_bits = { + .rxtx_enable = SCSCR_RE | SCSCR_TE, + .te_clear = SCSCR_TE | SCSCR_TEIE, + .poll_sent_bits = SCI_TDRE | SCI_TEND +}; -#ifdef CONFIG_SERIAL_SH_SCI_DMA - struct dma_chan *chan_tx_saved; - struct dma_chan *chan_rx_saved; - dma_cookie_t cookie_tx; - dma_cookie_t cookie_rx[2]; - dma_cookie_t active_rx; - dma_addr_t tx_dma_addr; - unsigned int tx_dma_len; - struct scatterlist sg_rx[2]; - void *rx_buf[2]; - size_t buf_len_rx; - struct work_struct work_tx; - struct hrtimer rx_timer; - unsigned int rx_timeout; /* microseconds */ -#endif - unsigned int rx_frame; - int rx_trigger; - struct timer_list rx_fifo_timer; - int rx_fifo_timeout; - u16 hscif_tot; - - bool has_rtscts; - bool autorts; +static const struct sci_port_params_bits sci_scif_port_params_bits = { + .rxtx_enable = SCSCR_RE | SCSCR_TE, + .te_clear = SCSCR_TE | SCSCR_TEIE, + .poll_sent_bits = SCIF_TDFE | SCIF_TEND }; -#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS +static const struct sci_common_regs sci_common_regs = { + .status = SCxSR, + .control = SCSCR, +}; -static struct sci_port sci_ports[SCI_NPORTS]; -static unsigned long sci_ports_in_use; -static struct uart_driver sci_uart_driver; +struct sci_suspend_regs { + u16 scdl; + u16 sccks; + u16 scsmr; + u16 scscr; + u16 scfcr; + u16 scsptr; + u16 hssrr; + u16 scpcr; + u16 scpdr; + u8 scbrr; + u8 semr; +}; -static inline struct sci_port * -to_sci_port(struct uart_port *uart) +static size_t sci_suspend_regs_size(void) { - return container_of(uart, struct sci_port, port); + return sizeof(struct sci_suspend_regs); } static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { @@ -190,6 +314,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER, .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER, + .param_bits = &sci_sci_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -212,6 +338,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER, .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -236,6 +364,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR_SCIFAB, .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -261,6 +391,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR_SCIFAB, .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -286,10 +418,12 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* - * The "SCIFA" that is in RZ/T and RZ/A2. + * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T1. * It looks like a normal SCIF with FIFO data, but with a * compressed address space. Also, the break out of interrupts * are different: ERI/BRI, RXI, TXI, TEI, DRI. @@ -306,6 +440,7 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { [SCFDR] = { 0x0E, 16 }, [SCSPTR] = { 0x10, 16 }, [SCLSR] = { 0x12, 16 }, + [SEMR] = { 0x14, 8 }, }, .fifosize = 16, .overrun_reg = SCLSR, @@ -313,6 +448,41 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, + }, + + /* + * The "SCIF" that is in RZ/V2H(P) SoC is similar to one found on RZ/G2L SoC + * with below differences, + * - Break out of interrupts are different: ERI, BRI, RXI, TXI, TEI, DRI, + * TEI-DRI, RXI-EDGE and TXI-EDGE. + * - SCSMR register does not have CM bit (BIT(7)) ie it does not support synchronous mode. + * - SCFCR register does not have SCFCR_MCE bit. + * - SCSPTR register has only bits SCSPTR_SPB2DT and SCSPTR_SPB2IO. + */ + [SCIx_RZV2H_SCIF_REGTYPE] = { + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x02, 8 }, + [SCSCR] = { 0x04, 16 }, + [SCxTDR] = { 0x06, 8 }, + [SCxSR] = { 0x08, 16 }, + [SCxRDR] = { 0x0a, 8 }, + [SCFCR] = { 0x0c, 16 }, + [SCFDR] = { 0x0e, 16 }, + [SCSPTR] = { 0x10, 16 }, + [SCLSR] = { 0x12, 16 }, + [SEMR] = { 0x14, 8 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -335,6 +505,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -359,6 +531,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -386,6 +560,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -415,6 +591,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR_RANGE(8, 32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -439,6 +617,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -466,6 +646,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(32), .error_mask = SCIF_DEFAULT_ERROR_MASK, .error_clear = SCIF_ERROR_CLEAR, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, /* @@ -489,6 +671,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { .sampling_rate_mask = SCI_SR(16), .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, + .param_bits = &sci_scif_port_params_bits, + .common_regs = &sci_common_regs, }, }; @@ -526,7 +710,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value) WARN(1, "Invalid register access\n"); } -static void sci_port_enable(struct sci_port *sci_port) +void sci_port_enable(struct sci_port *sci_port) { unsigned int i; @@ -541,8 +725,9 @@ static void sci_port_enable(struct sci_port *sci_port) } sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK]; } +EXPORT_SYMBOL_NS_GPL(sci_port_enable, "SH_SCI"); -static void sci_port_disable(struct sci_port *sci_port) +void sci_port_disable(struct sci_port *sci_port) { unsigned int i; @@ -554,6 +739,7 @@ static void sci_port_disable(struct sci_port *sci_port) pm_runtime_put_sync(sci_port->port.dev); } +EXPORT_SYMBOL_NS_GPL(sci_port_disable, "SH_SCI"); static inline unsigned long port_rx_irq_mask(struct uart_port *port) { @@ -573,84 +759,110 @@ static void sci_start_tx(struct uart_port *port) unsigned short ctrl; #ifdef CONFIG_SERIAL_SH_SCI_DMA - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = serial_port_in(port, SCSCR); + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) { + u16 new, scr = sci_serial_in(port, SCSCR); if (s->chan_tx) new = scr | SCSCR_TDRQE; else new = scr & ~SCSCR_TDRQE; if (new != scr) - serial_port_out(port, SCSCR, new); + sci_serial_out(port, SCSCR, new); } - if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) && dma_submit_error(s->cookie_tx)) { + if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) + /* Switch irq from SCIF to DMA */ + disable_irq_nosync(s->irqs[SCIx_TXI_IRQ]); + s->cookie_tx = 0; schedule_work(&s->work_tx); } #endif - if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + if (!s->chan_tx || s->regtype == SCIx_RZ_SCIFA_REGTYPE || + s->type == PORT_SCIFA || s->type == PORT_SCIFB) { /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); + ctrl = sci_serial_in(port, SCSCR); + + /* + * For SCI, TE (transmit enable) must be set after setting TIE + * (transmit interrupt enable) or in the same instruction to start + * the transmit process. + */ + if (s->type == PORT_SCI) + ctrl |= SCSCR_TE; + + sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE); } } static void sci_stop_tx(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) ctrl &= ~SCSCR_TDRQE; ctrl &= ~SCSCR_TIE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (s->chan_tx && + !dma_submit_error(s->cookie_tx)) { + dmaengine_terminate_async(s->chan_tx); + s->cookie_tx = -EINVAL; + } +#endif } static void sci_start_rx(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); unsigned short ctrl; - ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); + ctrl = sci_serial_in(port, SCSCR) | port_rx_irq_mask(port); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) ctrl &= ~SCSCR_RDRQE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); } static void sci_stop_rx(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); unsigned short ctrl; - ctrl = serial_port_in(port, SCSCR); + ctrl = sci_serial_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) ctrl &= ~SCSCR_RDRQE; ctrl &= ~port_rx_irq_mask(port); - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); } static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) { - if (port->type == PORT_SCI) { + struct sci_port *s = to_sci_port(port); + + if (s->type == PORT_SCI) { /* Just store the mask */ - serial_port_out(port, SCxSR, mask); - } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) { + sci_serial_out(port, SCxSR, mask); + } else if (s->params->overrun_mask == SCIFA_ORER) { /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */ /* Only clear the status bits we want to clear */ - serial_port_out(port, SCxSR, - serial_port_in(port, SCxSR) & mask); + sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask); } else { /* Store the mask, clear parity/framing errors */ - serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); + sci_serial_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); } } @@ -661,12 +873,13 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) static int sci_poll_get_char(struct uart_port *port) { unsigned short status; + struct sci_port *s = to_sci_port(port); int c; do { - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { - sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); continue; } break; @@ -675,11 +888,11 @@ static int sci_poll_get_char(struct uart_port *port) if (!(status & SCxSR_RDxF(port))) return NO_POLL_CHAR; - c = serial_port_in(port, SCxRDR); + c = sci_serial_in(port, SCxRDR); /* Dummy read */ - serial_port_in(port, SCxSR); - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + sci_serial_in(port, SCxSR); + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); return c; } @@ -687,14 +900,16 @@ static int sci_poll_get_char(struct uart_port *port) static void sci_poll_put_char(struct uart_port *port, unsigned char c) { - unsigned short status; + struct sci_port *s = to_sci_port(port); + const struct sci_common_regs *regs = s->params->common_regs; + unsigned int status; do { - status = serial_port_in(port, SCxSR); + status = s->ops->read_reg(port, regs->status); } while (!(status & SCxSR_TDxE(port))); - serial_port_out(port, SCxTDR, c); - sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); + sci_serial_out(port, SCxTDR, c); + s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */ @@ -711,13 +926,13 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) return; } - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 data = serial_port_in(port, SCPDR); - u16 ctrl = serial_port_in(port, SCPCR); + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) { + u16 data = sci_serial_in(port, SCPDR); + u16 ctrl = sci_serial_in(port, SCPCR); /* Enable RXD and TXD pin functions */ ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); - if (to_sci_port(port)->has_rtscts) { + if (s->has_rtscts) { /* RTS# is output, active low, unless autorts */ if (!(port->mctrl & TIOCM_RTS)) { ctrl |= SCPCR_RTSC; @@ -732,10 +947,10 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) /* Enable CTS# pin function */ ctrl &= ~SCPCR_CTSC; } - serial_port_out(port, SCPDR, data); - serial_port_out(port, SCPCR, ctrl); - } else if (sci_getreg(port, SCSPTR)->size) { - u16 status = serial_port_in(port, SCSPTR); + sci_serial_out(port, SCPDR, data); + sci_serial_out(port, SCPCR, ctrl); + } else if (sci_getreg(port, SCSPTR)->size && s->regtype != SCIx_RZV2H_SCIF_REGTYPE) { + u16 status = sci_serial_in(port, SCSPTR); /* RTS# is always output; and active low, unless autorts */ status |= SCSPTR_RTSIO; @@ -745,7 +960,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) status &= ~SCSPTR_RTSDT; /* CTS# and SCK are inputs */ status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO); - serial_port_out(port, SCSPTR, status); + sci_serial_out(port, SCSPTR, status); } } @@ -757,13 +972,13 @@ static int sci_txfill(struct uart_port *port) reg = sci_getreg(port, SCTFDR); if (reg->size) - return serial_port_in(port, SCTFDR) & fifo_mask; + return sci_serial_in(port, SCTFDR) & fifo_mask; reg = sci_getreg(port, SCFDR); if (reg->size) - return serial_port_in(port, SCFDR) >> 8; + return sci_serial_in(port, SCFDR) >> 8; - return !(serial_port_in(port, SCxSR) & SCI_TDRE); + return !(sci_serial_in(port, SCxSR) & SCI_TDRE); } static int sci_txroom(struct uart_port *port) @@ -779,13 +994,13 @@ static int sci_rxfill(struct uart_port *port) reg = sci_getreg(port, SCRFDR); if (reg->size) - return serial_port_in(port, SCRFDR) & fifo_mask; + return sci_serial_in(port, SCRFDR) & fifo_mask; reg = sci_getreg(port, SCFDR); if (reg->size) - return serial_port_in(port, SCFDR) & fifo_mask; + return sci_serial_in(port, SCFDR) & fifo_mask; - return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; + return (sci_serial_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; } /* ********************************************************************** * @@ -794,20 +1009,21 @@ static int sci_rxfill(struct uart_port *port) static void sci_transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned int stopped = uart_tx_stopped(port); + struct sci_port *s = to_sci_port(port); unsigned short status; unsigned short ctrl; int count; - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { - ctrl = serial_port_in(port, SCSCR); - if (uart_circ_empty(xmit)) + ctrl = sci_serial_in(port, SCSCR); + if (kfifo_is_empty(&tport->xmit_fifo)) ctrl &= ~SCSCR_TIE; else ctrl |= SCSCR_TIE; - serial_port_out(port, SCSCR, ctrl); + sci_serial_out(port, SCSCR, ctrl); return; } @@ -819,38 +1035,48 @@ static void sci_transmit_chars(struct uart_port *port) if (port->x_char) { c = port->x_char; port->x_char = 0; - } else if (!uart_circ_empty(xmit) && !stopped) { - c = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else { + } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) { + if (s->type == PORT_SCI && + kfifo_is_empty(&tport->xmit_fifo)) { + ctrl = sci_serial_in(port, SCSCR); + ctrl &= ~SCSCR_TE; + sci_serial_out(port, SCSCR, ctrl); + return; + } break; } - serial_port_out(port, SCxTDR, c); + sci_serial_out(port, SCxTDR, c); + s->tx_occurred = true; port->icount.tx++; } while (--count > 0); - sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - sci_stop_tx(port); + if (kfifo_is_empty(&tport->xmit_fifo)) { + if (s->type == PORT_SCI) { + ctrl = sci_serial_in(port, SCSCR); + ctrl &= ~SCSCR_TIE; + ctrl |= SCSCR_TEIE; + sci_serial_out(port, SCSCR, ctrl); + } + sci_stop_tx(port); + } } -/* On SH3, SCIF may read end-of-break as a space->mark char */ -#define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); }) - static void sci_receive_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; + struct sci_port *s = to_sci_port(port); int i, count, copied = 0; unsigned short status; unsigned char flag; - status = serial_port_in(port, SCxSR); + status = sci_serial_in(port, SCxSR); if (!(status & SCxSR_RDxF(port))) return; @@ -862,8 +1088,8 @@ static void sci_receive_chars(struct uart_port *port) if (count == 0) break; - if (port->type == PORT_SCI) { - char c = serial_port_in(port, SCxRDR); + if (s->type == PORT_SCI) { + char c = sci_serial_in(port, SCxRDR); if (uart_handle_sysrq_char(port, c)) count = 0; else @@ -872,13 +1098,13 @@ static void sci_receive_chars(struct uart_port *port) for (i = 0; i < count; i++) { char c; - if (port->type == PORT_SCIF || - port->type == PORT_HSCIF) { - status = serial_port_in(port, SCxSR); - c = serial_port_in(port, SCxRDR); + if (s->type == PORT_SCIF || + s->type == PORT_HSCIF) { + status = sci_serial_in(port, SCxSR); + c = sci_serial_in(port, SCxRDR); } else { - c = serial_port_in(port, SCxRDR); - status = serial_port_in(port, SCxSR); + c = sci_serial_in(port, SCxRDR); + status = sci_serial_in(port, SCxSR); } if (uart_handle_sysrq_char(port, c)) { count--; i--; @@ -889,11 +1115,9 @@ static void sci_receive_chars(struct uart_port *port) if (status & SCxSR_FER(port)) { flag = TTY_FRAME; port->icount.frame++; - dev_notice(port->dev, "frame error\n"); } else if (status & SCxSR_PER(port)) { flag = TTY_PARITY; port->icount.parity++; - dev_notice(port->dev, "parity error\n"); } else flag = TTY_NORMAL; @@ -901,8 +1125,8 @@ static void sci_receive_chars(struct uart_port *port) } } - serial_port_in(port, SCxSR); /* dummy read */ - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + sci_serial_in(port, SCxSR); /* dummy read */ + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); copied += count; port->icount.rx += count; @@ -913,18 +1137,19 @@ static void sci_receive_chars(struct uart_port *port) tty_flip_buffer_push(tport); } else { /* TTY buffers full; read from RX reg to prevent lockup */ - serial_port_in(port, SCxRDR); - serial_port_in(port, SCxSR); /* dummy read */ - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + sci_serial_in(port, SCxRDR); + sci_serial_in(port, SCxSR); /* dummy read */ + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } static int sci_handle_errors(struct uart_port *port) { int copied = 0; - unsigned short status = serial_port_in(port, SCxSR); - struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); + const struct sci_common_regs *regs = s->params->common_regs; + unsigned int status = s->ops->read_reg(port, regs->status); + struct tty_port *tport = &port->state->port; /* Handle overruns */ if (status & s->params->overrun_mask) { @@ -933,8 +1158,6 @@ static int sci_handle_errors(struct uart_port *port) /* overrun error */ if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) copied++; - - dev_notice(port->dev, "overrun error\n"); } if (status & SCxSR_FER(port)) { @@ -943,8 +1166,6 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_FRAME)) copied++; - - dev_notice(port->dev, "frame error\n"); } if (status & SCxSR_PER(port)) { @@ -953,8 +1174,6 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_PARITY)) copied++; - - dev_notice(port->dev, "parity error\n"); } if (copied) @@ -969,23 +1188,31 @@ static int sci_handle_fifo_overrun(struct uart_port *port) struct sci_port *s = to_sci_port(port); const struct plat_sci_reg *reg; int copied = 0; - u16 status; + u32 status; - reg = sci_getreg(port, s->params->overrun_reg); - if (!reg->size) - return 0; + if (s->type != SCI_PORT_RSCI) { + reg = sci_getreg(port, s->params->overrun_reg); + if (!reg->size) + return 0; + } - status = serial_port_in(port, s->params->overrun_reg); + status = s->ops->read_reg(port, s->params->overrun_reg); if (status & s->params->overrun_mask) { - status &= ~s->params->overrun_mask; - serial_port_out(port, s->params->overrun_reg, status); + if (s->type == SCI_PORT_RSCI) { + /* + * All of the CFCLR_*C clearing bits match the corresponding + * CSR_*status bits. So, reuse the overrun mask for clearing. + */ + s->ops->clear_SCxSR(port, s->params->overrun_mask); + } else { + status &= ~s->params->overrun_mask; + s->ops->write_reg(port, s->params->overrun_reg, status); + } port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); tty_flip_buffer_push(tport); - - dev_dbg(port->dev, "overrun error\n"); copied++; } @@ -995,7 +1222,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) static int sci_handle_breaks(struct uart_port *port) { int copied = 0; - unsigned short status = serial_port_in(port, SCxSR); + unsigned short status = sci_serial_in(port, SCxSR); struct tty_port *tport = &port->state->port; if (uart_handle_break(port)) @@ -1007,8 +1234,6 @@ static int sci_handle_breaks(struct uart_port *port) /* Notify of BREAK */ if (tty_insert_flip_char(tport, 0, TTY_BREAK)) copied++; - - dev_dbg(port->dev, "BREAK detected\n"); } if (copied) @@ -1021,20 +1246,21 @@ static int sci_handle_breaks(struct uart_port *port) static int scif_set_rtrg(struct uart_port *port, int rx_trig) { + struct sci_port *s = to_sci_port(port); unsigned int bits; + if (rx_trig >= port->fifosize) + rx_trig = port->fifosize - 1; if (rx_trig < 1) rx_trig = 1; - if (rx_trig >= port->fifosize) - rx_trig = port->fifosize; /* HSCIF can be set to an arbitrary level. */ if (sci_getreg(port, HSRTRGR)->size) { - serial_port_out(port, HSRTRGR, rx_trig); + sci_serial_out(port, HSRTRGR, rx_trig); return rx_trig; } - switch (port->type) { + switch (s->type) { case PORT_SCIF: if (rx_trig < 4) { bits = 0; @@ -1071,9 +1297,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig) return 1; } - serial_port_out(port, SCFCR, - (serial_port_in(port, SCFCR) & - ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits); + sci_serial_out(port, SCFCR, + (sci_serial_in(port, SCFCR) & + ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits); return rx_trig; } @@ -1081,19 +1307,19 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig) static int scif_rtrg_enabled(struct uart_port *port) { if (sci_getreg(port, HSRTRGR)->size) - return serial_port_in(port, HSRTRGR) != 0; + return sci_serial_in(port, HSRTRGR) != 0; else - return (serial_port_in(port, SCFCR) & + return (sci_serial_in(port, SCFCR) & (SCFCR_RTRG0 | SCFCR_RTRG1)) != 0; } static void rx_fifo_timer_fn(struct timer_list *t) { - struct sci_port *s = from_timer(s, t, rx_fifo_timer); + struct sci_port *s = timer_container_of(s, t, rx_fifo_timer); struct uart_port *port = &s->port; dev_dbg(port->dev, "Rx timed out\n"); - scif_set_rtrg(port, 1); + s->ops->set_rtrg(port, 1); } static ssize_t rx_fifo_trigger_show(struct device *dev, @@ -1118,9 +1344,9 @@ static ssize_t rx_fifo_trigger_store(struct device *dev, if (ret) return ret; - sci->rx_trigger = scif_set_rtrg(port, r); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - scif_set_rtrg(port, 1); + sci->rx_trigger = sci->ops->set_rtrg(port, r); + if (sci->type == PORT_SCIFA || sci->type == PORT_SCIFB) + sci->ops->set_rtrg(port, 1); return count; } @@ -1135,7 +1361,7 @@ static ssize_t rx_fifo_timeout_show(struct device *dev, struct sci_port *sci = to_sci_port(port); int v; - if (port->type == PORT_HSCIF) + if (sci->type == PORT_HSCIF) v = sci->hscif_tot >> HSSCR_TOT_SHIFT; else v = sci->rx_fifo_timeout; @@ -1157,13 +1383,13 @@ static ssize_t rx_fifo_timeout_store(struct device *dev, if (ret) return ret; - if (port->type == PORT_HSCIF) { + if (sci->type == PORT_HSCIF) { if (r < 0 || r > 3) return -EINVAL; sci->hscif_tot = r << HSSCR_TOT_SHIFT; } else { sci->rx_fifo_timeout = r; - scif_set_rtrg(port, 1); + sci->ops->set_rtrg(port, 1); if (r > 0) timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0); } @@ -1179,33 +1405,38 @@ static void sci_dma_tx_complete(void *arg) { struct sci_port *s = arg; struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); - xmit->tail += s->tx_dma_len; - xmit->tail &= UART_XMIT_SIZE - 1; + uart_xmit_advance(port, s->tx_dma_len); - port->icount.tx += s->tx_dma_len; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (!uart_circ_empty(xmit)) { + s->tx_occurred = true; + + if (!kfifo_is_empty(&tport->xmit_fifo)) { s->cookie_tx = 0; schedule_work(&s->work_tx); } else { s->cookie_tx = -EINVAL; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB || + s->regtype == SCIx_RZ_SCIFA_REGTYPE) { + u16 ctrl = sci_serial_in(port, SCSCR); + sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE); + if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) { + /* Switch irq from DMA to SCIF */ + dmaengine_pause(s->chan_tx_saved); + enable_irq(s->irqs[SCIx_TXI_IRQ]); + } } } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* Locking: called with port lock held */ @@ -1235,6 +1466,7 @@ static int sci_dma_rx_find_active(struct sci_port *s) return -1; } +/* Must only be called with uart_port_lock taken */ static void sci_dma_rx_chan_invalidate(struct sci_port *s) { unsigned int i; @@ -1248,9 +1480,14 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s) static void sci_dma_rx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_rx_saved; + struct uart_port *port = &s->port; + unsigned long flags; + uart_port_lock_irqsave(port, &flags); s->chan_rx_saved = NULL; sci_dma_rx_chan_invalidate(s); + uart_port_unlock_irqrestore(port, flags); + dmaengine_terminate_sync(chan); dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], sg_dma_address(&s->sg_rx[0])); @@ -1272,12 +1509,16 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s) u16 scr; /* Direct new serial port interrupts back to CPU */ - scr = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; + scr = sci_serial_in(port, SCSCR); + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB || + s->regtype == SCIx_RZ_SCIFA_REGTYPE) { enable_irq(s->irqs[SCIx_RXI_IRQ]); + if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) + s->ops->set_rtrg(port, s->rx_trigger); + else + scr &= ~SCSCR_RDRQE; } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); + sci_serial_out(port, SCSCR, scr | SCSCR_RIE); } static void sci_dma_rx_complete(void *arg) @@ -1292,14 +1533,14 @@ static void sci_dma_rx_complete(void *arg) dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line, s->active_rx); - spin_lock_irqsave(&port->lock, flags); + hrtimer_cancel(&s->rx_timer); + + uart_port_lock_irqsave(port, &flags); active = sci_dma_rx_find_active(s); if (active >= 0) count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx); - start_hrtimer_us(&s->rx_timer, s->rx_timeout); - if (count) tty_flip_buffer_push(&port->state->port); @@ -1319,20 +1560,21 @@ static void sci_dma_rx_complete(void *arg) dma_async_issue_pending(chan); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", __func__, s->cookie_rx[active], active, s->active_rx); + + start_hrtimer_us(&s->rx_timer, s->rx_timeout); + return; fail: - spin_unlock_irqrestore(&port->lock, flags); - dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); /* Switch to PIO */ - spin_lock_irqsave(&port->lock, flags); dmaengine_terminate_async(chan); sci_dma_rx_chan_invalidate(s); sci_dma_rx_reenable_irq(s); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); } static void sci_dma_tx_release(struct sci_port *s) @@ -1381,13 +1623,13 @@ static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held) fail: /* Switch to PIO */ if (!port_lock_held) - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (i) dmaengine_terminate_async(chan); sci_dma_rx_chan_invalidate(s); sci_start_rx(port); if (!port_lock_held) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return -EAGAIN; } @@ -1397,10 +1639,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work) struct dma_async_tx_descriptor *desc; struct dma_chan *chan = s->chan_tx; struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; + unsigned int tail; dma_addr_t buf; - int head, tail; /* * DMA is idle now. @@ -1409,16 +1651,13 @@ static void sci_dma_tx_work_fn(struct work_struct *work) * transmit till the end, and then the rest. Take the port lock to get a * consistent xmit buffer state. */ - spin_lock_irq(&port->lock); - head = xmit->head; - tail = xmit->tail; - buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1)); - s->tx_dma_len = min_t(unsigned int, - CIRC_CNT(head, tail, UART_XMIT_SIZE), - CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE)); + uart_port_lock_irq(port); + s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); + buf = s->tx_dma_addr + tail; if (!s->tx_dma_len) { /* Transmit buffer has been flushed */ - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); return; } @@ -1426,7 +1665,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work) DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n"); goto switch_to_pio; } @@ -1438,23 +1677,23 @@ static void sci_dma_tx_work_fn(struct work_struct *work) desc->callback_param = s; s->cookie_tx = dmaengine_submit(desc); if (dma_submit_error(s->cookie_tx)) { - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); goto switch_to_pio; } - spin_unlock_irq(&port->lock); - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", - __func__, xmit->buf, tail, head, s->cookie_tx); + uart_port_unlock_irq(port); + dev_dbg(port->dev, "%s: %p: %u, cookie %d\n", + __func__, tport->xmit_buf, tail, s->cookie_tx); dma_async_issue_pending(chan); return; switch_to_pio: - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); s->chan_tx = NULL; sci_start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return; } @@ -1471,17 +1710,17 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) dev_dbg(port->dev, "DMA Rx timed out\n"); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); active = sci_dma_rx_find_active(s); if (active < 0) { - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return HRTIMER_NORESTART; } status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); if (status == DMA_COMPLETE) { - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); dev_dbg(port->dev, "Cookie %d #%d has already completed\n", s->active_rx, active); @@ -1499,7 +1738,7 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) */ status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); if (status == DMA_COMPLETE) { - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); dev_dbg(port->dev, "Transaction complete after DMA engine was stopped"); return HRTIMER_NORESTART; } @@ -1514,12 +1753,13 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) tty_flip_buffer_push(&port->state->port); } - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB || + s->regtype == SCIx_RZ_SCIFA_REGTYPE) sci_dma_rx_submit(s, true); sci_dma_rx_reenable_irq(s); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return HRTIMER_NORESTART; } @@ -1531,24 +1771,20 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port, struct dma_slave_config cfg; int ret; - chan = dma_request_slave_channel(port->dev, - dir == DMA_MEM_TO_DEV ? "tx" : "rx"); - if (!chan) { - dev_dbg(port->dev, "dma_request_slave_channel failed\n"); + chan = dma_request_chan(port->dev, dir == DMA_MEM_TO_DEV ? "tx" : "rx"); + if (IS_ERR(chan)) { + dev_dbg(port->dev, "dma_request_chan failed\n"); return NULL; } memset(&cfg, 0, sizeof(cfg)); cfg.direction = dir; - if (dir == DMA_MEM_TO_DEV) { - cfg.dst_addr = port->mapbase + - (sci_getreg(port, SCxTDR)->offset << port->regshift); - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - } else { - cfg.src_addr = port->mapbase + - (sci_getreg(port, SCxRDR)->offset << port->regshift); - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - } + cfg.dst_addr = port->mapbase + + (sci_getreg(port, SCxTDR)->offset << port->regshift); + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + cfg.src_addr = port->mapbase + + (sci_getreg(port, SCxRDR)->offset << port->regshift); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ret = dmaengine_slave_config(chan, &cfg); if (ret) { @@ -1563,6 +1799,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port, static void sci_request_dma(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + struct tty_port *tport = &port->state->port; struct dma_chan *chan; dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); @@ -1583,7 +1820,7 @@ static void sci_request_dma(struct uart_port *port) * Don't request a dma channel if no channel was specified * in the device tree. */ - if (!of_find_property(port->dev->of_node, "dmas", NULL)) + if (!of_property_present(port->dev->of_node, "dmas")) return; chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV); @@ -1591,7 +1828,7 @@ static void sci_request_dma(struct uart_port *port) if (chan) { /* UART circular tx buffer is an aligned page. */ s->tx_dma_addr = dma_map_single(chan->device->dev, - port->state->xmit.buf, + tport->xmit_buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) { @@ -1600,7 +1837,7 @@ static void sci_request_dma(struct uart_port *port) } else { dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__, UART_XMIT_SIZE, - port->state->xmit.buf, &s->tx_dma_addr); + tport->xmit_buf, &s->tx_dma_addr); INIT_WORK(&s->work_tx, sci_dma_tx_work_fn); s->chan_tx_saved = s->chan_tx = chan; @@ -1636,12 +1873,12 @@ static void sci_request_dma(struct uart_port *port) dma += s->buf_len_rx; } - hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - s->rx_timer.function = sci_dma_rx_timer_fn; + hrtimer_setup(&s->rx_timer, sci_dma_rx_timer_fn, CLOCK_MONOTONIC, HRTIMER_MODE_REL); s->chan_rx_saved = s->chan_rx = chan; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB || + s->regtype == SCIx_RZ_SCIFA_REGTYPE) sci_dma_rx_submit(s, false); } } @@ -1671,6 +1908,19 @@ static void sci_flush_buffer(struct uart_port *port) s->cookie_tx = -EINVAL; } } + +static void sci_dma_check_tx_occurred(struct sci_port *s) +{ + struct dma_tx_state state; + enum dma_status status; + + if (!s->chan_tx) + return; + + status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state); + if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS) + s->tx_occurred = true; +} #else /* !CONFIG_SERIAL_SH_SCI_DMA */ static inline void sci_request_dma(struct uart_port *port) { @@ -1680,6 +1930,10 @@ static inline void sci_free_dma(struct uart_port *port) { } +static void sci_dma_check_tx_occurred(struct sci_port *s) +{ +} + #define sci_flush_buffer NULL #endif /* !CONFIG_SERIAL_SH_SCI_DMA */ @@ -1690,23 +1944,29 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) #ifdef CONFIG_SERIAL_SH_SCI_DMA if (s->chan_rx) { - u16 scr = serial_port_in(port, SCSCR); - u16 ssr = serial_port_in(port, SCxSR); + u16 scr = sci_serial_in(port, SCSCR); + u16 ssr = sci_serial_in(port, SCxSR); /* Disable future Rx interrupts */ - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - disable_irq_nosync(irq); - scr |= SCSCR_RDRQE; + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB || + s->regtype == SCIx_RZ_SCIFA_REGTYPE) { + disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]); + if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) { + s->ops->set_rtrg(port, 1); + scr |= SCSCR_RIE; + } else { + scr |= SCSCR_RDRQE; + } } else { if (sci_dma_rx_submit(s, false) < 0) goto handle_pio; scr &= ~SCSCR_RIE; } - serial_port_out(port, SCSCR, scr); + sci_serial_out(port, SCSCR, scr); /* Clear current interrupt */ - serial_port_out(port, SCxSR, - ssr & ~(SCIF_DR | SCxSR_RDxF(port))); + sci_serial_out(port, SCxSR, + ssr & ~(SCIF_DR | SCxSR_RDxF(port))); dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n", jiffies, s->rx_timeout); start_hrtimer_us(&s->rx_timer, s->rx_timeout); @@ -1718,8 +1978,8 @@ handle_pio: #endif if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) { - if (!scif_rtrg_enabled(port)) - scif_set_rtrg(port, s->rx_trigger); + if (!s->ops->rtrg_enabled(port)) + s->ops->set_rtrg(port, s->rx_trigger); mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP( s->rx_frame * HZ * s->rx_fifo_timeout, 1000000)); @@ -1729,7 +1989,7 @@ handle_pio: * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? */ - sci_receive_chars(port); + s->ops->receive_chars(port); return IRQ_HANDLED; } @@ -1738,10 +1998,31 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; unsigned long flags; + struct sci_port *s = to_sci_port(port); + + uart_port_lock_irqsave(port, &flags); + s->ops->transmit_chars(port); + uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + const struct sci_common_regs *regs = s->params->common_regs; + unsigned long flags; + u32 ctrl; + + if (s->type != PORT_SCI && s->type != SCI_PORT_RSCI) + return sci_tx_interrupt(irq, ptr); - spin_lock_irqsave(&port->lock, flags); - sci_transmit_chars(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); + ctrl = s->ops->read_reg(port, regs->control) & + ~(s->params->param_bits->te_clear); + s->ops->write_reg(port, regs->control, ctrl); + uart_port_unlock_irqrestore(port, flags); return IRQ_HANDLED; } @@ -1749,10 +2030,15 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) static irqreturn_t sci_br_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); /* Handle BREAKs */ sci_handle_breaks(port); - sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); + + /* drop invalid character received before break was detected */ + sci_serial_in(port, SCxRDR); + + s->ops->clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; } @@ -1764,7 +2050,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) { /* Break and Error interrupts are muxed */ - unsigned short ssr_status = serial_port_in(port, SCxSR); + unsigned short ssr_status = sci_serial_in(port, SCxSR); /* Break Interrupt */ if (ssr_status & SCxSR_BRK(port)) @@ -1776,19 +2062,19 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) } /* Handle errors */ - if (port->type == PORT_SCI) { + if (s->type == PORT_SCI) { if (sci_handle_errors(port)) { /* discard character in rx buffer */ - serial_port_in(port, SCxSR); - sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); + sci_serial_in(port, SCxSR); + s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } else { sci_handle_fifo_overrun(port); if (!s->chan_rx) - sci_receive_chars(port); + s->ops->receive_chars(port); } - sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); + s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ if (!s->chan_tx) @@ -1804,12 +2090,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; - ssr_status = serial_port_in(port, SCxSR); - scr_status = serial_port_in(port, SCSCR); + ssr_status = sci_serial_in(port, SCxSR); + scr_status = sci_serial_in(port, SCSCR); if (s->params->overrun_reg == SCxSR) orer_status = ssr_status; else if (sci_getreg(port, s->params->overrun_reg)->size) - orer_status = serial_port_in(port, s->params->overrun_reg); + orer_status = sci_serial_in(port, s->params->overrun_reg); err_enabled = scr_status & port_rx_irq_mask(port); @@ -1831,7 +2117,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_er_interrupt(irq, ptr); /* Break Interrupt */ - if ((ssr_status & SCxSR_BRK(port)) && err_enabled) + if (s->irqs[SCIx_ERI_IRQ] != s->irqs[SCIx_BRI_IRQ] && + (ssr_status & SCxSR_BRK(port)) && err_enabled) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ @@ -1877,7 +2164,7 @@ static const struct sci_irq_desc { [SCIx_TEI_IRQ] = { .desc = "tx end", - .handler = sci_tx_interrupt, + .handler = sci_tx_end_interrupt, }, /* @@ -1985,47 +2272,57 @@ static void sci_free_irq(struct sci_port *port) static unsigned int sci_tx_empty(struct uart_port *port) { - unsigned short status = serial_port_in(port, SCxSR); + unsigned short status = sci_serial_in(port, SCxSR); unsigned short in_tx_fifo = sci_txfill(port); + struct sci_port *s = to_sci_port(port); + + sci_dma_check_tx_occurred(s); + + if (!s->tx_occurred) + return TIOCSER_TEMT; return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; } static void sci_set_rts(struct uart_port *port, bool state) { - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 data = serial_port_in(port, SCPDR); + struct sci_port *s = to_sci_port(port); + + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) { + u16 data = sci_serial_in(port, SCPDR); /* Active low */ if (state) data &= ~SCPDR_RTSD; else data |= SCPDR_RTSD; - serial_port_out(port, SCPDR, data); + sci_serial_out(port, SCPDR, data); /* RTS# is output */ - serial_port_out(port, SCPCR, - serial_port_in(port, SCPCR) | SCPCR_RTSC); + sci_serial_out(port, SCPCR, + sci_serial_in(port, SCPCR) | SCPCR_RTSC); } else if (sci_getreg(port, SCSPTR)->size) { - u16 ctrl = serial_port_in(port, SCSPTR); + u16 ctrl = sci_serial_in(port, SCSPTR); /* Active low */ if (state) ctrl &= ~SCSPTR_RTSDT; else ctrl |= SCSPTR_RTSDT; - serial_port_out(port, SCSPTR, ctrl); + sci_serial_out(port, SCSPTR, ctrl); } } static bool sci_get_cts(struct uart_port *port) { - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + struct sci_port *s = to_sci_port(port); + + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) { /* Active low */ - return !(serial_port_in(port, SCPDR) & SCPDR_CTSD); + return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD); } else if (sci_getreg(port, SCSPTR)->size) { /* Active low */ - return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT); + return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT); } return true; @@ -2055,9 +2352,8 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, - serial_port_in(port, SCFCR) | - SCFCR_LOOP); + sci_serial_out(port, SCFCR, + sci_serial_in(port, SCFCR) | SCFCR_LOOP); } mctrl_gpio_set(s->gpios, mctrl); @@ -2067,21 +2363,23 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) if (!(mctrl & TIOCM_RTS)) { /* Disable Auto RTS */ - serial_port_out(port, SCFCR, - serial_port_in(port, SCFCR) & ~SCFCR_MCE); + if (s->regtype != SCIx_RZV2H_SCIF_REGTYPE) + sci_serial_out(port, SCFCR, + sci_serial_in(port, SCFCR) & ~SCFCR_MCE); /* Clear RTS */ sci_set_rts(port, 0); } else if (s->autorts) { - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) { /* Enable RTS# pin function */ - serial_port_out(port, SCPCR, - serial_port_in(port, SCPCR) & ~SCPCR_RTSC); + sci_serial_out(port, SCPCR, + sci_serial_in(port, SCPCR) & ~SCPCR_RTSC); } /* Enable Auto RTS */ - serial_port_out(port, SCFCR, - serial_port_in(port, SCFCR) | SCFCR_MCE); + if (s->regtype != SCIx_RZV2H_SCIF_REGTYPE) + sci_serial_out(port, SCFCR, + sci_serial_in(port, SCFCR) | SCFCR_MCE); } else { /* Set RTS */ sci_set_rts(port, 1); @@ -2124,7 +2422,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state) unsigned short scscr, scsptr; unsigned long flags; - /* check wheter the port has SCSPTR */ + /* check whether the port has SCSPTR */ if (!sci_getreg(port, SCSPTR)->size) { /* * Not supported by hardware. Most parts couple break and rx @@ -2133,9 +2431,9 @@ static void sci_break_ctl(struct uart_port *port, int break_state) return; } - spin_lock_irqsave(&port->lock, flags); - scsptr = serial_port_in(port, SCSPTR); - scscr = serial_port_in(port, SCSCR); + uart_port_lock_irqsave(port, &flags); + scsptr = sci_serial_in(port, SCSPTR); + scscr = sci_serial_in(port, SCSCR); if (break_state == -1) { scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT; @@ -2145,18 +2443,29 @@ static void sci_break_ctl(struct uart_port *port, int break_state) scscr |= SCSCR_TE; } - serial_port_out(port, SCSPTR, scsptr); - serial_port_out(port, SCSCR, scscr); - spin_unlock_irqrestore(&port->lock, flags); + sci_serial_out(port, SCSPTR, scsptr); + sci_serial_out(port, SCSCR, scscr); + uart_port_unlock_irqrestore(port, flags); +} + +static void sci_shutdown_complete(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + u16 scr; + + scr = sci_serial_in(port, SCSCR); + sci_serial_out(port, SCSCR, + scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); } -static int sci_startup(struct uart_port *port) +int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); int ret; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + s->tx_occurred = false; sci_request_dma(port); ret = sci_request_irq(s); @@ -2167,29 +2476,23 @@ static int sci_startup(struct uart_port *port) return 0; } +EXPORT_SYMBOL_NS_GPL(sci_startup, "SH_SCI"); -static void sci_shutdown(struct uart_port *port) +void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); unsigned long flags; - u16 scr; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); s->autorts = false; - mctrl_gpio_disable_ms(to_sci_port(port)->gpios); + mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios); - spin_lock_irqsave(&port->lock, flags); - sci_stop_rx(port); - sci_stop_tx(port); - /* - * Stop RX and TX, disable related interrupts, keep clock source - * and HSCIF TOT bits - */ - scr = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, scr & - (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); + s->port.ops->stop_rx(port); + s->port.ops->stop_tx(port); + s->ops->shutdown_complete(port); + uart_port_unlock_irqrestore(port, flags); #ifdef CONFIG_SERIAL_SH_SCI_DMA if (s->chan_rx_saved) { @@ -2200,10 +2503,11 @@ static void sci_shutdown(struct uart_port *port) #endif if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) - del_timer_sync(&s->rx_fifo_timer); + timer_delete_sync(&s->rx_fifo_timer); sci_free_irq(s); sci_free_dma(port); } +EXPORT_SYMBOL_NS_GPL(sci_shutdown, "SH_SCI"); static int sci_sck_calc(struct sci_port *s, unsigned int bps, unsigned int *srr) @@ -2212,7 +2516,7 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps, int err, min_err = INT_MAX; unsigned int sr; - if (s->port.type != PORT_HSCIF) + if (s->type != PORT_HSCIF) freq *= 2; for_each_sr(sr, s) { @@ -2239,7 +2543,7 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps, int err, min_err = INT_MAX; unsigned int sr, dl; - if (s->port.type != PORT_HSCIF) + if (s->type != PORT_HSCIF) freq *= 2; for_each_sr(sr, s) { @@ -2265,14 +2569,14 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps, /* calculate sample rate, BRR, and clock select */ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, - unsigned int *brr, unsigned int *srr, - unsigned int *cks) + unsigned int *brr, unsigned int *srr, + unsigned int *cks) { unsigned long freq = s->clk_rates[SCI_FCK]; unsigned int sr, br, prediv, scrate, c; int err, min_err = INT_MAX; - if (s->port.type != PORT_HSCIF) + if (s->type != PORT_HSCIF) freq *= 2; /* @@ -2293,7 +2597,7 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, for_each_sr(sr, s) { for (c = 0; c <= 3; c++) { /* integerized formulas from HSCIF documentation */ - prediv = sr * (1 << (2 * c + 1)); + prediv = sr << (2 * c + 1); /* * We need to calculate: @@ -2337,37 +2641,37 @@ static void sci_reset(struct uart_port *port) unsigned int status; struct sci_port *s = to_sci_port(port); - serial_port_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */ + sci_serial_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); - sci_clear_SCxSR(port, - SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & - SCxSR_BREAK_CLEAR(port)); + s->ops->clear_SCxSR(port, + SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & + SCxSR_BREAK_CLEAR(port)); if (sci_getreg(port, SCLSR)->size) { - status = serial_port_in(port, SCLSR); + status = sci_serial_in(port, SCLSR); status &= ~(SCLSR_TO | SCLSR_ORER); - serial_port_out(port, SCLSR, status); + sci_serial_out(port, SCLSR, status); } if (s->rx_trigger > 1) { if (s->rx_fifo_timeout) { - scif_set_rtrg(port, 1); + s->ops->set_rtrg(port, 1); timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0); } else { - if (port->type == PORT_SCIFA || - port->type == PORT_SCIFB) - scif_set_rtrg(port, 1); + if (s->type == PORT_SCIFA || + s->type == PORT_SCIFB) + s->ops->set_rtrg(port, 1); else - scif_set_rtrg(port, s->rx_trigger); + s->ops->set_rtrg(port, s->rx_trigger); } } } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i, bits; unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0; @@ -2379,8 +2683,12 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, int best_clk = -1; unsigned long flags; - if ((termios->c_cflag & CSIZE) == CS7) + if ((termios->c_cflag & CSIZE) == CS7) { smr_val |= SCSMR_CHR; + } else { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + } if (termios->c_cflag & PARENB) smr_val |= SCSMR_PE; if (termios->c_cflag & PARODD) @@ -2414,8 +2722,8 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, */ /* Optional Undivided External Clock */ - if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA && - port->type != PORT_SCIFB) { + if (s->clk_rates[SCI_SCK] && s->type != PORT_SCIFA && + s->type != PORT_SCIFB) { err = sci_sck_calc(s, baud, &srr1); if (abs(err) < abs(min_err)) { best_clk = SCI_SCK; @@ -2483,39 +2791,24 @@ done: * It controls the mux to select (H)SCK or frequency divided clock. */ if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) { - serial_port_out(port, SCDL, dl); - serial_port_out(port, SCCKS, sccks); + sci_serial_out(port, SCDL, dl); + sci_serial_out(port, SCCKS, sccks); } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); sci_reset(port); uart_update_timeout(port, termios->c_cflag, baud); /* byte size and parity */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = 7; - break; - case CS6: - bits = 8; - break; - case CS7: - bits = 9; - break; - default: - bits = 10; - break; - } + bits = tty_get_frame_size(termios->c_cflag); - if (termios->c_cflag & CSTOPB) - bits++; - if (termios->c_cflag & PARENB) - bits++; + if (sci_getreg(port, SEMR)->size) + sci_serial_out(port, SEMR, 0); if (best_clk >= 0) { - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) switch (srr + 1) { case 5: smr_val |= SCSMR_SRC_5; break; case 7: smr_val |= SCSMR_SRC_7; break; @@ -2527,9 +2820,9 @@ done: case 27: smr_val |= SCSMR_SRC_27; break; } smr_val |= cks; - serial_port_out(port, SCSCR, scr_val | s->hscif_tot); - serial_port_out(port, SCSMR, smr_val); - serial_port_out(port, SCBRR, brr); + sci_serial_out(port, SCSCR, scr_val | s->hscif_tot); + sci_serial_out(port, SCSMR, smr_val); + sci_serial_out(port, SCBRR, brr); if (sci_getreg(port, HSSRR)->size) { unsigned int hssrr = srr | HSCIF_SRE; /* Calculate deviation from intended rate at the @@ -2551,7 +2844,7 @@ done: HSCIF_SRHP_MASK; hssrr |= HSCIF_SRDE; } - serial_port_out(port, HSSRR, hssrr); + sci_serial_out(port, HSSRR, hssrr); } /* Wait one bit interval */ @@ -2559,10 +2852,10 @@ done: } else { /* Don't touch the bit rate configuration */ scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0); - smr_val |= serial_port_in(port, SCSMR) & + smr_val |= sci_serial_in(port, SCSMR) & (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS); - serial_port_out(port, SCSCR, scr_val | s->hscif_tot); - serial_port_out(port, SCSMR, smr_val); + sci_serial_out(port, SCSCR, scr_val | s->hscif_tot); + sci_serial_out(port, SCSMR, smr_val); } sci_init_pins(port, termios->c_cflag); @@ -2571,7 +2864,7 @@ done: s->autorts = false; reg = sci_getreg(port, SCFCR); if (reg->size) { - unsigned short ctrl = serial_port_in(port, SCFCR); + unsigned short ctrl = sci_serial_in(port, SCFCR); if ((port->flags & UPF_HARD_FLOW) && (termios->c_cflag & CRTSCTS)) { @@ -2588,18 +2881,24 @@ done: */ ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST); - serial_port_out(port, SCFCR, ctrl); + sci_serial_out(port, SCFCR, ctrl); } if (port->flags & UPF_HARD_FLOW) { /* Refresh (Auto) RTS */ sci_set_mctrl(port, port->mctrl); } - scr_val |= SCSCR_RE | SCSCR_TE | - (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)); - serial_port_out(port, SCSCR, scr_val | s->hscif_tot); + /* + * For SCI, TE (transmit enable) must be set after setting TIE + * (transmit interrupt enable) or in the same instruction to + * start the transmitting process. So skip setting TE here for SCI. + */ + if (s->type != PORT_SCI) + scr_val |= SCSCR_TE; + scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)); + sci_serial_out(port, SCSCR, scr_val | s->hscif_tot); if ((srr + 1 == 5) && - (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) { + (s->type == PORT_SCIFA || s->type == PORT_SCIFB)) { /* * In asynchronous mode, when the sampling rate is 1/5, first * received data may become invalid on some SCIFA and SCIFB. @@ -2609,27 +2908,16 @@ done: udelay(DIV_ROUND_UP(10 * 1000000, baud)); } - /* - * Calculate delay for 2 DMA buffers (4 FIFO). - * See serial_core.c::uart_update_timeout(). - * With 10 bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above - * function calculates 1 jiffie for the data plus 5 jiffies for the - * "slop(e)." Then below we calculate 5 jiffies (20ms) for 2 DMA - * buffers (4 FIFO sizes), but when performing a faster transfer, the - * value obtained by this formula is too small. Therefore, if the value - * is smaller than 20ms, use 20ms as the timeout value for DMA. - */ + /* Calculate delay for 2 DMA buffers (4 FIFO). */ s->rx_frame = (10000 * bits) / (baud / 100); #ifdef CONFIG_SERIAL_SH_SCI_DMA s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; - if (s->rx_timeout < 20) - s->rx_timeout = 20; #endif if ((termios->c_cflag & CREAD) != 0) sci_start_rx(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); sci_port_disable(s); @@ -2637,7 +2925,7 @@ done: sci_enable_ms(port); } -static void sci_pm(struct uart_port *port, unsigned int state, +void sci_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sci_port *sci_port = to_sci_port(port); @@ -2651,10 +2939,13 @@ static void sci_pm(struct uart_port *port, unsigned int state, break; } } +EXPORT_SYMBOL_NS_GPL(sci_pm, "SH_SCI"); static const char *sci_type(struct uart_port *port) { - switch (port->type) { + struct sci_port *s = to_sci_port(port); + + switch (s->type) { case PORT_IRDA: return "irda"; case PORT_SCI: @@ -2700,7 +2991,7 @@ static int sci_remap_port(struct uart_port *port) return 0; } -static void sci_release_port(struct uart_port *port) +void sci_release_port(struct uart_port *port) { struct sci_port *sport = to_sci_port(port); @@ -2711,8 +3002,9 @@ static void sci_release_port(struct uart_port *port) release_mem_region(port->mapbase, sport->reg_size); } +EXPORT_SYMBOL_NS_GPL(sci_release_port, "SH_SCI"); -static int sci_request_port(struct uart_port *port) +int sci_request_port(struct uart_port *port) { struct resource *res; struct sci_port *sport = to_sci_port(port); @@ -2733,18 +3025,19 @@ static int sci_request_port(struct uart_port *port) return 0; } +EXPORT_SYMBOL_NS_GPL(sci_request_port, "SH_SCI"); -static void sci_config_port(struct uart_port *port, int flags) +void sci_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { struct sci_port *sport = to_sci_port(port); - - port->type = sport->cfg->type; + port->type = SCI_PUBLIC_PORT_ID(sport->type); sci_request_port(port); } } +EXPORT_SYMBOL_NS_GPL(sci_config_port, "SH_SCI"); -static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) +int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ @@ -2752,6 +3045,76 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } +EXPORT_SYMBOL_NS_GPL(sci_verify_port, "SH_SCI"); + +static void sci_prepare_console_write(struct uart_port *port, u32 ctrl) +{ + struct sci_port *s = to_sci_port(port); + u32 ctrl_temp = + s->params->param_bits->rxtx_enable | + (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | + (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)) | + s->hscif_tot; + sci_serial_out(port, SCSCR, ctrl_temp); +} + +static void sci_console_save(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sci_suspend_regs *regs = s->suspend_regs; + + if (sci_getreg(port, SCDL)->size) + regs->scdl = sci_serial_in(port, SCDL); + if (sci_getreg(port, SCCKS)->size) + regs->sccks = sci_serial_in(port, SCCKS); + if (sci_getreg(port, SCSMR)->size) + regs->scsmr = sci_serial_in(port, SCSMR); + if (sci_getreg(port, SCSCR)->size) + regs->scscr = sci_serial_in(port, SCSCR); + if (sci_getreg(port, SCFCR)->size) + regs->scfcr = sci_serial_in(port, SCFCR); + if (sci_getreg(port, SCSPTR)->size) + regs->scsptr = sci_serial_in(port, SCSPTR); + if (sci_getreg(port, SCBRR)->size) + regs->scbrr = sci_serial_in(port, SCBRR); + if (sci_getreg(port, HSSRR)->size) + regs->hssrr = sci_serial_in(port, HSSRR); + if (sci_getreg(port, SCPCR)->size) + regs->scpcr = sci_serial_in(port, SCPCR); + if (sci_getreg(port, SCPDR)->size) + regs->scpdr = sci_serial_in(port, SCPDR); + if (sci_getreg(port, SEMR)->size) + regs->semr = sci_serial_in(port, SEMR); +} + +static void sci_console_restore(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sci_suspend_regs *regs = s->suspend_regs; + + if (sci_getreg(port, SCDL)->size) + sci_serial_out(port, SCDL, regs->scdl); + if (sci_getreg(port, SCCKS)->size) + sci_serial_out(port, SCCKS, regs->sccks); + if (sci_getreg(port, SCSMR)->size) + sci_serial_out(port, SCSMR, regs->scsmr); + if (sci_getreg(port, SCSCR)->size) + sci_serial_out(port, SCSCR, regs->scscr); + if (sci_getreg(port, SCFCR)->size) + sci_serial_out(port, SCFCR, regs->scfcr); + if (sci_getreg(port, SCSPTR)->size) + sci_serial_out(port, SCSPTR, regs->scsptr); + if (sci_getreg(port, SCBRR)->size) + sci_serial_out(port, SCBRR, regs->scbrr); + if (sci_getreg(port, HSSRR)->size) + sci_serial_out(port, HSSRR, regs->hssrr); + if (sci_getreg(port, SCPCR)->size) + sci_serial_out(port, SCPCR, regs->scpcr); + if (sci_getreg(port, SCPDR)->size) + sci_serial_out(port, SCPDR, regs->scpdr); + if (sci_getreg(port, SEMR)->size) + sci_serial_out(port, SEMR, regs->semr); +} static const struct uart_ops sci_uart_ops = { .tx_empty = sci_tx_empty, @@ -2778,6 +3141,25 @@ static const struct uart_ops sci_uart_ops = { #endif }; +static const struct sci_port_ops sci_port_ops = { + .read_reg = sci_serial_in, + .write_reg = sci_serial_out, + .clear_SCxSR = sci_clear_SCxSR, + .transmit_chars = sci_transmit_chars, + .receive_chars = sci_receive_chars, +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \ + defined(CONFIG_SERIAL_SH_SCI_EARLYCON) + .poll_put_char = sci_poll_put_char, +#endif + .set_rtrg = scif_set_rtrg, + .rtrg_enabled = scif_rtrg_enabled, + .shutdown_complete = sci_shutdown_complete, + .prepare_console_write = sci_prepare_console_write, + .console_save = sci_console_save, + .console_restore = sci_console_restore, + .suspend_regs_size = sci_suspend_regs_size, +}; + static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) { const char *clk_names[] = { @@ -2789,57 +3171,58 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) struct clk *clk; unsigned int i; - if (sci_port->cfg->type == PORT_HSCIF) + if (sci_port->type == PORT_HSCIF) { clk_names[SCI_SCK] = "hsck"; + } else if (sci_port->type == SCI_PORT_RSCI) { + clk_names[SCI_FCK] = "operation"; + clk_names[SCI_BRG_INT] = "bus"; + } for (i = 0; i < SCI_NUM_CLKS; i++) { - clk = devm_clk_get(dev, clk_names[i]); - if (PTR_ERR(clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + const char *name = clk_names[i]; - if (IS_ERR(clk) && i == SCI_FCK) { - /* - * "fck" used to be called "sci_ick", and we need to - * maintain DT backward compatibility. - */ - clk = devm_clk_get(dev, "sci_ick"); - if (PTR_ERR(clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + clk = devm_clk_get_optional(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); - if (!IS_ERR(clk)) - goto found; + if (!clk && sci_port->type == SCI_PORT_RSCI && + (i == SCI_FCK || i == SCI_BRG_INT)) { + return dev_err_probe(dev, -ENODEV, + "failed to get %s\n", + name); + } + if (!clk && i == SCI_FCK) { /* * Not all SH platforms declare a clock lookup entry * for SCI devices, in which case we need to get the * global "peripheral_clk" clock. */ clk = devm_clk_get(dev, "peripheral_clk"); - if (!IS_ERR(clk)) - goto found; - - dev_err(dev, "failed to get %s (%ld)\n", clk_names[i], - PTR_ERR(clk)); - return PTR_ERR(clk); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get %s\n", + name); } -found: - if (IS_ERR(clk)) - dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i], - PTR_ERR(clk)); + if (!clk) + dev_dbg(dev, "failed to get %s\n", name); else - dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i], + dev_dbg(dev, "clk %s is %pC rate %lu\n", name, clk, clk_get_rate(clk)); - sci_port->clks[i] = IS_ERR(clk) ? NULL : clk; + sci_port->clks[i] = clk; } return 0; } static const struct sci_port_params * -sci_probe_regmap(const struct plat_sci_port *cfg) +sci_probe_regmap(const struct plat_sci_port *cfg, struct sci_port *sci_port) { unsigned int regtype; + sci_port->ops = &sci_port_ops; + sci_port->port.ops = &sci_uart_ops; + if (cfg->regtype != SCIx_PROBE_REGTYPE) return &sci_port_params[cfg->regtype]; @@ -2887,7 +3270,9 @@ static int sci_init_single(struct platform_device *dev, sci_port->cfg = p; - port->ops = &sci_uart_ops; + sci_port->type = p->type; + sci_port->regtype = p->regtype; + port->iotype = UPIO_MEM; port->line = index; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE); @@ -2906,6 +3291,13 @@ static int sci_init_single(struct platform_device *dev, sci_port->irqs[i] = platform_get_irq(dev, i); } + /* + * The fourth interrupt on SCI and RSCI port is transmit end interrupt, so + * shuffle the interrupts. + */ + if (p->type == PORT_SCI || p->type == SCI_PORT_RSCI) + swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]); + /* The SCI generates several interrupts. They can be muxed together or * connected to different interrupt lines. In the muxed case only one * interrupt resource is specified as there is only one interrupt ID. @@ -2920,10 +3312,6 @@ static int sci_init_single(struct platform_device *dev, for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++) sci_port->irqs[i] = sci_port->irqs[0]; - sci_port->params = sci_probe_regmap(p); - if (unlikely(sci_port->params == NULL)) - return -EINVAL; - switch (p->type) { case PORT_SCIFB: sci_port->rx_trigger = 48; @@ -2941,6 +3329,9 @@ static int sci_init_single(struct platform_device *dev, else sci_port->rx_trigger = 8; break; + case SCI_PORT_RSCI: + sci_port->rx_trigger = 15; + break; default: sci_port->rx_trigger = 1; break; @@ -2961,17 +3352,13 @@ static int sci_init_single(struct platform_device *dev, ret = sci_init_clocks(sci_port, &dev->dev); if (ret < 0) return ret; - - port->dev = &dev->dev; - - pm_runtime_enable(&dev->dev); } - port->type = p->type; + port->type = SCI_PUBLIC_PORT_ID(p->type); port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags; port->fifosize = sci_port->params->fifosize; - if (port->type == PORT_SCI) { + if (p->type == PORT_SCI && !dev->dev.of_node) { if (sci_port->reg_size >= 0x20) port->regshift = 2; else @@ -2988,22 +3375,14 @@ static int sci_init_single(struct platform_device *dev, port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irqflags = 0; - port->serial_in = sci_serial_in; - port->serial_out = sci_serial_out; - return 0; } -static void sci_cleanup_single(struct sci_port *port) -{ - pm_runtime_disable(port->port.dev); -} - #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \ defined(CONFIG_SERIAL_SH_SCI_EARLYCON) -static void serial_console_putchar(struct uart_port *port, int ch) +static void serial_console_putchar(struct uart_port *port, unsigned char ch) { - sci_poll_put_char(port, ch); + to_sci_port(port)->ops->poll_put_char(port, ch); } /* @@ -3015,36 +3394,38 @@ static void serial_console_write(struct console *co, const char *s, { struct sci_port *sci_port = &sci_ports[co->index]; struct uart_port *port = &sci_port->port; - unsigned short bits, ctrl, ctrl_temp; + const struct sci_common_regs *regs = sci_port->params->common_regs; + unsigned int bits; + u32 ctrl; unsigned long flags; int locked = 1; if (port->sysrq) locked = 0; else if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* first save SCSCR then disable interrupts, keep clock source */ - ctrl = serial_port_in(port, SCSCR); - ctrl_temp = SCSCR_RE | SCSCR_TE | - (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | - (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)); - serial_port_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot); + + ctrl = sci_port->ops->read_reg(port, regs->control); + sci_port->ops->prepare_console_write(port, ctrl); uart_console_write(port, s, count, serial_console_putchar); /* wait until fifo is empty and last bit has been transmitted */ - bits = SCxSR_TDxE(port) | SCxSR_TEND(port); - while ((serial_port_in(port, SCxSR) & bits) != bits) + + bits = sci_port->params->param_bits->poll_sent_bits; + + while ((sci_port->ops->read_reg(port, regs->status) & bits) != bits) cpu_relax(); /* restore the SCSCR */ - serial_port_out(port, SCSCR, ctrl); + sci_port->ops->write_reg(port, regs->control, ctrl); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int serial_console_setup(struct console *co, char *options) @@ -3093,27 +3474,44 @@ static struct console serial_console = { }; #ifdef CONFIG_SUPERH +static char early_serial_buf[32]; + +static int early_serial_console_setup(struct console *co, char *options) +{ + /* + * This early console is always registered using the earlyprintk= + * parameter, which does not call add_preferred_console(). Thus + * @options is always NULL and the options for this early console + * are passed using a custom buffer. + */ + WARN_ON(options); + + return serial_console_setup(co, early_serial_buf); +} + static struct console early_serial_console = { .name = "early_ttySC", .write = serial_console_write, + .setup = early_serial_console_setup, .flags = CON_PRINTBUFFER, .index = -1, }; -static char early_serial_buf[32]; - static int sci_probe_earlyprintk(struct platform_device *pdev) { const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev); + struct sci_port *sp = &sci_ports[pdev->id]; if (early_serial_console.data) return -EEXIST; early_serial_console.index = pdev->id; - sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); + sp->params = sci_probe_regmap(cfg, sp); + if (!sp->params) + return -ENODEV; - serial_console_setup(&early_serial_console, early_serial_buf); + sci_init_single(pdev, sp, pdev->id, cfg, true); if (!strstr(early_serial_buf, "keep")) early_serial_console.flags |= CON_BOOT; @@ -3148,89 +3546,197 @@ static struct uart_driver sci_uart_driver = { .cons = SCI_CONSOLE, }; -static int sci_remove(struct platform_device *dev) +static void sci_remove(struct platform_device *dev) { - struct sci_port *port = platform_get_drvdata(dev); - unsigned int type = port->port.type; /* uart_remove_... clears it */ - - sci_ports_in_use &= ~BIT(port->port.line); - uart_remove_one_port(&sci_uart_driver, &port->port); + struct sci_port *s = platform_get_drvdata(dev); + unsigned int type = s->type; /* uart_remove_... clears it */ - sci_cleanup_single(port); + sci_ports_in_use &= ~BIT(s->port.line); + uart_remove_one_port(&sci_uart_driver, &s->port); - if (port->port.fifosize > 1) + if (s->port.fifosize > 1) device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger); - if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF) + if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF || + type == SCI_PORT_RSCI) device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout); - - return 0; } +static const struct sci_of_data of_sci_scif_sh2 = { + .type = PORT_SCIF, + .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SH2_SCIF_FIFODATA_REGTYPE], +}; + +static const struct sci_of_data of_sci_scif_rz_scifa = { + .type = PORT_SCIF, + .regtype = SCIx_RZ_SCIFA_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_RZ_SCIFA_REGTYPE], +}; + +static const struct sci_of_data of_sci_scif_rzv2h = { + .type = PORT_SCIF, + .regtype = SCIx_RZV2H_SCIF_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_RZV2H_SCIF_REGTYPE], +}; + +static const struct sci_of_data of_sci_rcar_scif = { + .type = PORT_SCIF, + .regtype = SCIx_SH4_SCIF_BRG_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SH4_SCIF_BRG_REGTYPE], +}; + +static const struct sci_of_data of_sci_scif_sh4 = { + .type = PORT_SCIF, + .regtype = SCIx_SH4_SCIF_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SH4_SCIF_REGTYPE], +}; -#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype)) -#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16) -#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff) +static const struct sci_of_data of_sci_scifa = { + .type = PORT_SCIFA, + .regtype = SCIx_SCIFA_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SCIFA_REGTYPE], +}; + +static const struct sci_of_data of_sci_scifb = { + .type = PORT_SCIFB, + .regtype = SCIx_SCIFB_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SCIFB_REGTYPE], +}; -static const struct of_device_id of_sci_match[] = { +static const struct sci_of_data of_sci_hscif = { + .type = PORT_HSCIF, + .regtype = SCIx_HSCIF_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_HSCIF_REGTYPE], +}; + +static const struct sci_of_data of_sci_sci = { + .type = PORT_SCI, + .regtype = SCIx_SCI_REGTYPE, + .ops = &sci_port_ops, + .uart_ops = &sci_uart_ops, + .params = &sci_port_params[SCIx_SCI_REGTYPE], +}; + +static const struct of_device_id of_sci_match[] __maybe_unused = { /* SoC-specific types */ { .compatible = "renesas,scif-r7s72100", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE), + .data = &of_sci_scif_sh2, }, { .compatible = "renesas,scif-r7s9210", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), + .data = &of_sci_scif_rz_scifa, + }, + { + .compatible = "renesas,scif-r9a07g044", + .data = &of_sci_scif_rz_scifa, + }, + { + .compatible = "renesas,scif-r9a09g057", + .data = &of_sci_scif_rzv2h, }, +#ifdef CONFIG_SERIAL_RSCI + { + .compatible = "renesas,r9a09g077-rsci", + .data = &of_sci_rsci_data, + }, +#endif /* CONFIG_SERIAL_RSCI */ /* Family-specific types */ { .compatible = "renesas,rcar-gen1-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif, }, { .compatible = "renesas,rcar-gen2-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif, }, { .compatible = "renesas,rcar-gen3-scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + .data = &of_sci_rcar_scif + }, { + .compatible = "renesas,rcar-gen4-scif", + .data = &of_sci_rcar_scif + }, { + .compatible = "renesas,rcar-gen5-scif", + .data = &of_sci_rcar_scif }, /* Generic types */ { .compatible = "renesas,scif", - .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE), + .data = &of_sci_scif_sh4, }, { .compatible = "renesas,scifa", - .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE), + .data = &of_sci_scifa, }, { .compatible = "renesas,scifb", - .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE), + .data = &of_sci_scifb, }, { .compatible = "renesas,hscif", - .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE), + .data = &of_sci_hscif, }, { .compatible = "renesas,sci", - .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE), + .data = &of_sci_sci, }, { /* Terminator */ }, }; MODULE_DEVICE_TABLE(of, of_sci_match); +static void sci_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) { struct device_node *np = pdev->dev.of_node; + struct reset_control *rstc; struct plat_sci_port *p; struct sci_port *sp; - const void *data; - int id; + const struct sci_of_data *data; + int id, ret; if (!IS_ENABLED(CONFIG_OF) || !np) - return NULL; + return ERR_PTR(-EINVAL); data = of_device_get_match_data(&pdev->dev); + rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + if (IS_ERR(rstc)) + return ERR_PTR(dev_err_probe(&pdev->dev, PTR_ERR(rstc), + "failed to get reset ctrl\n")); + + ret = reset_control_deassert(rstc); + if (ret) { + dev_err(&pdev->dev, "failed to deassert reset %d\n", ret); + return ERR_PTR(ret); + } + + ret = devm_add_action_or_reset(&pdev->dev, sci_reset_control_assert, rstc); + if (ret) { + dev_err(&pdev->dev, "failed to register assert devm action, %d\n", + ret); + return ERR_PTR(ret); + } + p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); if (!p) - return NULL; + return ERR_PTR(-ENOMEM); /* Get the line number from the aliases node. */ id = of_alias_get_id(np, "serial"); @@ -3238,18 +3744,23 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, id = ffz(sci_ports_in_use); if (id < 0) { dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); - return NULL; + return ERR_PTR(-EINVAL); } if (id >= ARRAY_SIZE(sci_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", id); - return NULL; + return ERR_PTR(-EINVAL); } sp = &sci_ports[id]; + sp->rstc = rstc; *dev_id = id; - p->type = SCI_OF_TYPE(data); - p->regtype = SCI_OF_REGTYPE(data); + p->type = data->type; + p->regtype = data->regtype; + + sp->ops = data->ops; + sp->port.ops = data->uart_ops; + sp->params = data->params; sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts"); @@ -3259,7 +3770,8 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, static int sci_probe_single(struct platform_device *dev, unsigned int index, struct plat_sci_port *p, - struct sci_port *sciport) + struct sci_port *sciport, + struct resource *sci_res) { int ret; @@ -3288,6 +3800,11 @@ static int sci_probe_single(struct platform_device *dev, if (ret) return ret; + sciport->port.dev = &dev->dev; + ret = devm_pm_runtime_enable(&dev->dev); + if (ret) + return ret; + sciport->gpios = mctrl_gpio_init(&sciport->port, 0); if (IS_ERR(sciport->gpios)) return PTR_ERR(sciport->gpios); @@ -3301,18 +3818,37 @@ static int sci_probe_single(struct platform_device *dev, sciport->port.flags |= UPF_HARD_FLOW; } - ret = uart_add_one_port(&sci_uart_driver, &sciport->port); - if (ret) { - sci_cleanup_single(sciport); - return ret; + if (sci_uart_earlycon && sci_ports[0].port.mapbase == sci_res->start) { + /* + * In case: + * - this is the earlycon port (mapped on index 0 in sci_ports[]) and + * - it now maps to an alias other than zero and + * - the earlycon is still alive (e.g., "earlycon keep_bootcon" is + * available in bootargs) + * + * we need to avoid disabling clocks and PM domains through the runtime + * PM APIs called in __device_attach(). For this, increment the runtime + * PM reference counter (the clocks and PM domains were already enabled + * by the bootloader). Otherwise the earlycon may access the HW when it + * has no clocks enabled leading to failures (infinite loop in + * sci_poll_put_char()). + */ + pm_runtime_get_noresume(&dev->dev); + + /* + * Skip cleanup the sci_port[0] in early_console_exit(), this + * port is the same as the earlycon one. + */ + sci_uart_earlycon_dev_probing = true; } - return 0; + return uart_add_one_port(&sci_uart_driver, &sciport->port); } static int sci_probe(struct platform_device *dev) { struct plat_sci_port *p; + struct resource *res; struct sci_port *sp; unsigned int dev_id; int ret; @@ -3329,8 +3865,9 @@ static int sci_probe(struct platform_device *dev) if (dev->dev.of_node) { p = sci_parse_dt(dev, &dev_id); - if (p == NULL) - return -EINVAL; + if (IS_ERR(p)) + return PTR_ERR(p); + sp = &sci_ports[dev_id]; } else { p = dev->dev.platform_data; if (p == NULL) { @@ -3339,12 +3876,40 @@ static int sci_probe(struct platform_device *dev) } dev_id = dev->id; + sp = &sci_ports[dev_id]; + sp->params = sci_probe_regmap(p, sp); + if (!sp->params) + return -ENODEV; } - sp = &sci_ports[dev_id]; + sp->suspend_regs = devm_kzalloc(&dev->dev, + sp->ops->suspend_regs_size(), + GFP_KERNEL); + if (!sp->suspend_regs) + return -ENOMEM; + + /* + * In case: + * - the probed port alias is zero (as the one used by earlycon), and + * - the earlycon is still active (e.g., "earlycon keep_bootcon" in + * bootargs) + * + * defer the probe of this serial. This is a debug scenario and the user + * must be aware of it. + * + * Except when the probed port is the same as the earlycon port. + */ + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + if (sci_uart_earlycon && sp == &sci_ports[0] && sp->port.mapbase != res->start) + return dev_err_probe(&dev->dev, -EBUSY, "sci_port[0] is used by earlycon!\n"); + platform_set_drvdata(dev, sp); - ret = sci_probe_single(dev, dev_id, p, sp); + ret = sci_probe_single(dev, dev_id, p, sp, res); if (ret) return ret; @@ -3353,8 +3918,8 @@ static int sci_probe(struct platform_device *dev) if (ret) return ret; } - if (sp->port.type == PORT_SCIFA || sp->port.type == PORT_SCIFB || - sp->port.type == PORT_HSCIF) { + if (sp->type == PORT_SCIFA || sp->type == PORT_SCIFB || + sp->type == PORT_HSCIF || sp->type == SCI_PORT_RSCI) { ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout); if (ret) { if (sp->port.fifosize > 1) { @@ -3373,34 +3938,53 @@ static int sci_probe(struct platform_device *dev) return 0; } -static __maybe_unused int sci_suspend(struct device *dev) +static int sci_suspend(struct device *dev) { struct sci_port *sport = dev_get_drvdata(dev); - if (sport) + if (sport) { uart_suspend_port(&sci_uart_driver, &sport->port); + if (!console_suspend_enabled && uart_console(&sport->port)) { + if (sport->ops->console_save) + sport->ops->console_save(&sport->port); + } + else + return reset_control_assert(sport->rstc); + } + return 0; } -static __maybe_unused int sci_resume(struct device *dev) +static int sci_resume(struct device *dev) { struct sci_port *sport = dev_get_drvdata(dev); - if (sport) + if (sport) { + if (!console_suspend_enabled && uart_console(&sport->port)) { + if (sport->ops->console_restore) + sport->ops->console_restore(&sport->port); + } else { + int ret = reset_control_deassert(sport->rstc); + + if (ret) + return ret; + } + uart_resume_port(&sci_uart_driver, &sport->port); + } return 0; } -static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume); static struct platform_driver sci_driver = { .probe = sci_probe, .remove = sci_remove, .driver = { .name = "sh-sci", - .pm = &sci_dev_pm_ops, + .pm = pm_sleep_ptr(&sci_dev_pm_ops), .of_match_table = of_match_ptr(of_sci_match), }, }; @@ -3425,63 +4009,101 @@ sh_early_platform_init_buffer("earlyprintk", &sci_driver, early_serial_buf, ARRAY_SIZE(early_serial_buf)); #endif #ifdef CONFIG_SERIAL_SH_SCI_EARLYCON -static struct plat_sci_port port_cfg __initdata; +static struct plat_sci_port port_cfg; + +static int early_console_exit(struct console *co) +{ + struct sci_port *sci_port = &sci_ports[0]; + + /* + * Clean the slot used by earlycon. A new SCI device might + * map to this slot. + */ + if (!sci_uart_earlycon_dev_probing) { + memset(sci_port, 0, sizeof(*sci_port)); + sci_uart_earlycon = false; + } + + return 0; +} -static int __init early_console_setup(struct earlycon_device *device, - int type) +int __init scix_early_console_setup(struct earlycon_device *device, + const struct sci_of_data *data) { + const struct sci_common_regs *regs; + if (!device->port.membase) return -ENODEV; - device->port.serial_in = sci_serial_in; - device->port.serial_out = sci_serial_out; - device->port.type = type; - memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port)); - port_cfg.type = type; + device->port.type = SCI_PUBLIC_PORT_ID(data->type); + + sci_ports[0].port = device->port; + sci_ports[0].type = data->type; + sci_ports[0].regtype = data->regtype; + + port_cfg.type = data->type; + port_cfg.regtype = data->regtype; + sci_ports[0].cfg = &port_cfg; - sci_ports[0].params = sci_probe_regmap(&port_cfg); - port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR); - sci_serial_out(&sci_ports[0].port, SCSCR, - SCSCR_RE | SCSCR_TE | port_cfg.scscr); + sci_ports[0].params = data->params; + sci_ports[0].ops = data->ops; + sci_ports[0].port.ops = data->uart_ops; + sci_uart_earlycon = true; + regs = sci_ports[0].params->common_regs; + + port_cfg.scscr = sci_ports[0].ops->read_reg(&sci_ports[0].port, regs->control); + sci_ports[0].ops->write_reg(&sci_ports[0].port, + regs->control, + sci_ports[0].params->param_bits->rxtx_enable | port_cfg.scscr); device->con->write = serial_console_write; + device->con->exit = early_console_exit; + return 0; } static int __init sci_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCI); + return scix_early_console_setup(device, &of_sci_sci); } static int __init scif_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCIF); + return scix_early_console_setup(device, &of_sci_scif_sh4); } static int __init rzscifa_early_console_setup(struct earlycon_device *device, const char *opt) { - port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE; - return early_console_setup(device, PORT_SCIF); + return scix_early_console_setup(device, &of_sci_scif_rz_scifa); } + +static int __init rzv2hscif_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return scix_early_console_setup(device, &of_sci_scif_rzv2h); +} + static int __init scifa_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCIFA); + return scix_early_console_setup(device, &of_sci_scifa); } static int __init scifb_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_SCIFB); + return scix_early_console_setup(device, &of_sci_scifb); } static int __init hscif_early_console_setup(struct earlycon_device *device, const char *opt) { - return early_console_setup(device, PORT_HSCIF); + return scix_early_console_setup(device, &of_sci_hscif); } OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup); +OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup); +OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a09g057", rzv2hscif_early_console_setup); OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup); OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup); OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup); diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h deleted file mode 100644 index c0dfe4382898..000000000000 --- a/drivers/tty/serial/sh-sci.h +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include <linux/bitops.h> -#include <linux/serial_core.h> -#include <linux/io.h> - -#define SCI_MAJOR 204 -#define SCI_MINOR_START 8 - - -/* - * SCI register subset common for all port types. - * Not all registers will exist on all parts. - */ -enum { - SCSMR, /* Serial Mode Register */ - SCBRR, /* Bit Rate Register */ - SCSCR, /* Serial Control Register */ - SCxSR, /* Serial Status Register */ - SCFCR, /* FIFO Control Register */ - SCFDR, /* FIFO Data Count Register */ - SCxTDR, /* Transmit (FIFO) Data Register */ - SCxRDR, /* Receive (FIFO) Data Register */ - SCLSR, /* Line Status Register */ - SCTFDR, /* Transmit FIFO Data Count Register */ - SCRFDR, /* Receive FIFO Data Count Register */ - SCSPTR, /* Serial Port Register */ - HSSRR, /* Sampling Rate Register */ - SCPCR, /* Serial Port Control Register */ - SCPDR, /* Serial Port Data Register */ - SCDL, /* BRG Frequency Division Register */ - SCCKS, /* BRG Clock Select Register */ - HSRTRGR, /* Rx FIFO Data Count Trigger Register */ - HSTTRGR, /* Tx FIFO Data Count Trigger Register */ - - SCIx_NR_REGS, -}; - - -/* SCSMR (Serial Mode Register) */ -#define SCSMR_C_A BIT(7) /* Communication Mode */ -#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */ -#define SCSMR_ASYNC 0 /* - Asynchronous mode */ -#define SCSMR_CHR BIT(6) /* 7-bit Character Length */ -#define SCSMR_PE BIT(5) /* Parity Enable */ -#define SCSMR_ODD BIT(4) /* Odd Parity */ -#define SCSMR_STOP BIT(3) /* Stop Bit Length */ -#define SCSMR_CKS 0x0003 /* Clock Select */ - -/* Serial Mode Register, SCIFA/SCIFB only bits */ -#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */ -#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */ -#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */ -#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */ -#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */ -#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */ -#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */ -#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */ -#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */ -#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */ - -/* Serial Control Register, SCIFA/SCIFB only bits */ -#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ -#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ - -/* Serial Control Register, HSCIF-only bits */ -#define HSSCR_TOT_SHIFT 14 - -/* SCxSR (Serial Status Register) on SCI */ -#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */ -#define SCI_RDRF BIT(6) /* Receive Data Register Full */ -#define SCI_ORER BIT(5) /* Overrun Error */ -#define SCI_FER BIT(4) /* Framing Error */ -#define SCI_PER BIT(3) /* Parity Error */ -#define SCI_TEND BIT(2) /* Transmit End */ -#define SCI_RESERVED 0x03 /* All reserved bits */ - -#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER) - -#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF)) -#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)) -#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE)) -#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)) - -/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */ -#define SCIF_ER BIT(7) /* Receive Error */ -#define SCIF_TEND BIT(6) /* Transmission End */ -#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */ -#define SCIF_BRK BIT(4) /* Break Detect */ -#define SCIF_FER BIT(3) /* Framing Error */ -#define SCIF_PER BIT(2) /* Parity Error */ -#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */ -#define SCIF_DR BIT(0) /* Receive Data Ready */ -/* SCIF only (optional) */ -#define SCIF_PERC 0xf000 /* Number of Parity Errors */ -#define SCIF_FERC 0x0f00 /* Number of Framing Errors */ -/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */ -#define SCIFA_ORER BIT(9) /* Overrun Error */ - -#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER) - -#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF)) -#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER)) -#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE)) -#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK)) - -/* SCFCR (FIFO Control Register) */ -#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger */ -#define SCFCR_RTRG0 BIT(6) -#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger */ -#define SCFCR_TTRG0 BIT(4) -#define SCFCR_MCE BIT(3) /* Modem Control Enable */ -#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */ -#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */ -#define SCFCR_LOOP BIT(0) /* Loopback Test */ - -/* SCLSR (Line Status Register) on (H)SCIF */ -#define SCLSR_TO BIT(2) /* Timeout */ -#define SCLSR_ORER BIT(0) /* Overrun Error */ - -/* SCSPTR (Serial Port Register), optional */ -#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */ -#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */ -#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */ -#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */ -#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */ -#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */ -#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ -#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ - -/* HSSRR HSCIF */ -#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ -#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */ - -#define HSCIF_SRHP_SHIFT 8 -#define HSCIF_SRHP_MASK 0x0f00 - -/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ -#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */ -#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */ -#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */ -#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */ -#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */ - -/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ -#define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */ -#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */ -#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */ -#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */ -#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */ - -/* - * BRG Clock Select Register (Some SCIF and HSCIF) - * The Baud Rate Generator for external clock can provide a clock source for - * the sampling clock. It outputs either its frequency divided clock, or the - * (undivided) (H)SCK external clock. - */ -#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */ -#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */ - -#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) -#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_DR | SCIF_RDF) -#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) -#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) -#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) -#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) - -#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask) - -#define SCxSR_RDxF_CLEAR(port) \ - (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) -#define SCxSR_ERROR_CLEAR(port) \ - (to_sci_port(port)->params->error_clear) -#define SCxSR_TDxE_CLEAR(port) \ - (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) -#define SCxSR_BREAK_CLEAR(port) \ - (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 0b5110dad051..110d67613192 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -4,16 +4,6 @@ * Copyright (C) 2018 Paul Walmsley <paul@pwsan.com> * Copyright (C) 2018-2019 SiFive * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * Based partially on: * - drivers/tty/serial/pxa.c * - drivers/tty/serial/amba-pl011.c @@ -144,13 +134,14 @@ */ /** - * sifive_serial_port - driver-specific data extension to struct uart_port + * struct sifive_serial_port - driver-specific data extension to struct uart_port * @port: struct uart_port embedded in this struct * @dev: struct device * * @ier: shadowed copy of the interrupt enable register - * @clkin_rate: input clock to the UART IP block. * @baud_rate: UART serial line rate (e.g., 115200 baud) + * @clk: reference to this device's clock * @clk_notifier: clock rate change notifier for upstream clock changes + * @console_line_ended: indicate that the console line is fully written * * Configuration data specific to this SiFive UART. */ @@ -158,10 +149,10 @@ struct sifive_serial_port { struct uart_port port; struct device *dev; unsigned char ier; - unsigned long clkin_rate; unsigned long baud_rate; struct clk *clk; struct notifier_block clk_notifier; + bool console_line_ended; }; /* @@ -299,33 +290,12 @@ static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch) */ static void __ssp_transmit_chars(struct sifive_serial_port *ssp) { - struct circ_buf *xmit = &ssp->port.state->xmit; - int count; - - if (ssp->port.x_char) { - __ssp_transmit_char(ssp, ssp->port.x_char); - ssp->port.icount.tx++; - ssp->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&ssp->port)) { - sifive_serial_stop_tx(&ssp->port); - return; - } - count = SIFIVE_TX_FIFO_DEPTH; - do { - __ssp_transmit_char(ssp, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - ssp->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&ssp->port); + u8 ch; - if (uart_circ_empty(xmit)) - sifive_serial_stop_tx(&ssp->port); + uart_port_tx_limited(&ssp->port, ch, SIFIVE_TX_FIFO_DEPTH, + true, + __ssp_transmit_char(ssp, ch), + ({})); } /** @@ -434,9 +404,9 @@ static char __ssp_receive_char(struct sifive_serial_port *ssp, char *is_empty) */ static void __ssp_receive_chars(struct sifive_serial_port *ssp) { - unsigned char ch; char is_empty; int c; + u8 ch; for (c = SIFIVE_RX_FIFO_DEPTH; c > 0; --c) { ch = __ssp_receive_char(ssp, &is_empty); @@ -444,12 +414,11 @@ static void __ssp_receive_chars(struct sifive_serial_port *ssp) break; ssp->port.icount.rx++; - uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); + if (!uart_prepare_sysrq_char(&ssp->port, ch)) + uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); } - spin_unlock(&ssp->port.lock); tty_flip_buffer_push(&ssp->port.state->port); - spin_lock(&ssp->port.lock); } /** @@ -464,7 +433,7 @@ static void __ssp_update_div(struct sifive_serial_port *ssp) { u16 div; - div = DIV_ROUND_UP(ssp->clkin_rate, ssp->baud_rate) - 1; + div = DIV_ROUND_UP(ssp->port.uartclk, ssp->baud_rate) - 1; __ssp_writel(div, SIFIVE_SERIAL_DIV_OFFS, ssp); } @@ -555,11 +524,11 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id) struct sifive_serial_port *ssp = dev_id; u32 ip; - spin_lock(&ssp->port.lock); + uart_port_lock(&ssp->port); ip = __ssp_readl(ssp, SIFIVE_SERIAL_IP_OFFS); if (!ip) { - spin_unlock(&ssp->port.lock); + uart_port_unlock(&ssp->port); return IRQ_NONE; } @@ -568,7 +537,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id) if (ip & SIFIVE_SERIAL_IP_TXWM_MASK) __ssp_transmit_chars(ssp); - spin_unlock(&ssp->port.lock); + uart_unlock_and_check_sysrq(&ssp->port); return IRQ_HANDLED; } @@ -596,8 +565,11 @@ static void sifive_serial_break_ctl(struct uart_port *port, int break_state) static int sifive_serial_startup(struct uart_port *port) { struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); + unsigned long flags; + uart_port_lock_irqsave(&ssp->port, &flags); __ssp_enable_rxwm(ssp); + uart_port_unlock_irqrestore(&ssp->port, flags); return 0; } @@ -605,9 +577,12 @@ static int sifive_serial_startup(struct uart_port *port) static void sifive_serial_shutdown(struct uart_port *port) { struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); + unsigned long flags; + uart_port_lock_irqsave(&ssp->port, &flags); __ssp_disable_rxwm(ssp); __ssp_disable_txwm(ssp); + uart_port_unlock_irqrestore(&ssp->port, flags); } /** @@ -649,8 +624,8 @@ static int sifive_serial_clk_notifier(struct notifier_block *nb, udelay(DIV_ROUND_UP(12 * 1000 * 1000, ssp->baud_rate)); } - if (event == POST_RATE_CHANGE && ssp->clkin_rate != cnd->new_rate) { - ssp->clkin_rate = cnd->new_rate; + if (event == POST_RATE_CHANGE && ssp->port.uartclk != cnd->new_rate) { + ssp->port.uartclk = cnd->new_rate; __ssp_update_div(ssp); } @@ -659,7 +634,7 @@ static int sifive_serial_clk_notifier(struct notifier_block *nb, static void sifive_serial_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); unsigned long flags; @@ -667,22 +642,27 @@ static void sifive_serial_set_termios(struct uart_port *port, int rate; char nstop; - if ((termios->c_cflag & CSIZE) != CS8) + if ((termios->c_cflag & CSIZE) != CS8) { dev_err_once(ssp->port.dev, "only 8-bit words supported\n"); + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + } if (termios->c_iflag & (INPCK | PARMRK)) dev_err_once(ssp->port.dev, "parity checking not supported\n"); if (termios->c_iflag & BRKINT) dev_err_once(ssp->port.dev, "BREAK detection not supported\n"); + termios->c_iflag &= ~(INPCK|PARMRK|BRKINT); /* Set number of stop bits */ nstop = (termios->c_cflag & CSTOPB) ? 2 : 1; __ssp_set_stop_bits(ssp, nstop); /* Set line rate */ - rate = uart_get_baud_rate(port, termios, old, 0, ssp->clkin_rate / 16); + rate = uart_get_baud_rate(port, termios, old, 0, + ssp->port.uartclk / 16); __ssp_update_baud_rate(ssp, rate); - spin_lock_irqsave(&ssp->port.lock, flags); + uart_port_lock_irqsave(&ssp->port, &flags); /* Update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, rate); @@ -699,7 +679,7 @@ static void sifive_serial_set_termios(struct uart_port *port, if (v != old_v) __ssp_writel(v, SIFIVE_SERIAL_RXCTRL_OFFS, ssp); - spin_unlock_irqrestore(&ssp->port.lock, flags); + uart_port_unlock_irqrestore(&ssp->port, flags); } static void sifive_serial_release_port(struct uart_port *port) @@ -757,7 +737,7 @@ static void sifive_serial_poll_put_char(struct uart_port *port, */ #ifdef CONFIG_SERIAL_EARLYCON -static void early_sifive_serial_putc(struct uart_port *port, int c) +static void early_sifive_serial_putc(struct uart_port *port, unsigned char c) { while (__ssp_early_readl(port, SIFIVE_SERIAL_TXDATA_OFFS) & SIFIVE_SERIAL_TXDATA_FULL_MASK) @@ -789,7 +769,7 @@ static int __init early_sifive_serial_setup(struct earlycon_device *dev, } OF_EARLYCON_DECLARE(sifive, "sifive,uart0", early_sifive_serial_setup); -OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0", +OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart", early_sifive_serial_setup); #endif /* CONFIG_SERIAL_EARLYCON */ @@ -801,46 +781,97 @@ OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0", static struct sifive_serial_port *sifive_serial_console_ports[SIFIVE_SERIAL_MAX_PORTS]; -static void sifive_serial_console_putchar(struct uart_port *port, int ch) +static void sifive_serial_console_putchar(struct uart_port *port, unsigned char ch) { struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); __ssp_wait_for_xmitr(ssp); __ssp_transmit_char(ssp, ch); + + ssp->console_line_ended = (ch == '\n'); } -static void sifive_serial_console_write(struct console *co, const char *s, - unsigned int count) +static void sifive_serial_device_lock(struct console *co, unsigned long *flags) +{ + struct uart_port *up = &sifive_serial_console_ports[co->index]->port; + + __uart_port_lock_irqsave(up, flags); +} + +static void sifive_serial_device_unlock(struct console *co, unsigned long flags) +{ + struct uart_port *up = &sifive_serial_console_ports[co->index]->port; + + __uart_port_unlock_irqrestore(up, flags); +} + +static void sifive_serial_console_write_atomic(struct console *co, + struct nbcon_write_context *wctxt) { struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; - unsigned long flags; + struct uart_port *port = &ssp->port; unsigned int ier; - int locked = 1; if (!ssp) return; - local_irq_save(flags); - if (ssp->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&ssp->port.lock); - else - spin_lock(&ssp->port.lock); + if (!nbcon_enter_unsafe(wctxt)) + return; ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); - uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar); + if (!ssp->console_line_ended) + uart_console_write(port, "\n", 1, sifive_serial_console_putchar); + uart_console_write(port, wctxt->outbuf, wctxt->len, + sifive_serial_console_putchar); __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); - if (locked) - spin_unlock(&ssp->port.lock); - local_irq_restore(flags); + nbcon_exit_unsafe(wctxt); } -static int __init sifive_serial_console_setup(struct console *co, char *options) +static void sifive_serial_console_write_thread(struct console *co, + struct nbcon_write_context *wctxt) +{ + struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; + struct uart_port *port = &ssp->port; + unsigned int ier; + + if (!ssp) + return; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); + __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); + + if (nbcon_exit_unsafe(wctxt)) { + int len = READ_ONCE(wctxt->len); + int i; + + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + + uart_console_write(port, wctxt->outbuf + i, 1, + sifive_serial_console_putchar); + + if (!nbcon_exit_unsafe(wctxt)) + break; + } + } + + while (!nbcon_enter_unsafe(wctxt)) + nbcon_reacquire_nobuf(wctxt); + + __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); + + nbcon_exit_unsafe(wctxt); +} + +static int sifive_serial_console_setup(struct console *co, char *options) { struct sifive_serial_port *ssp; int baud = SIFIVE_DEFAULT_BAUD_RATE; @@ -855,6 +886,8 @@ static int __init sifive_serial_console_setup(struct console *co, char *options) if (!ssp) return -ENODEV; + ssp->console_line_ended = true; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -865,10 +898,13 @@ static struct uart_driver sifive_serial_uart_driver; static struct console sifive_serial_console = { .name = SIFIVE_TTY_PREFIX, - .write = sifive_serial_console_write, + .write_atomic = sifive_serial_console_write_atomic, + .write_thread = sifive_serial_console_write_thread, + .device_lock = sifive_serial_device_lock, + .device_unlock = sifive_serial_device_unlock, .device = uart_console_device, .setup = sifive_serial_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER | CON_NBCON, .index = -1, .data = &sifive_serial_uart_driver, }; @@ -883,13 +919,12 @@ console_initcall(sifive_console_init); static void __ssp_add_console_port(struct sifive_serial_port *ssp) { - spin_lock_init(&ssp->port.lock); sifive_serial_console_ports[ssp->port.line] = ssp; } static void __ssp_remove_console_port(struct sifive_serial_port *ssp) { - sifive_serial_console_ports[ssp->port.line] = 0; + sifive_serial_console_ports[ssp->port.line] = NULL; } #define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console) @@ -947,14 +982,11 @@ static int sifive_serial_probe(struct platform_device *pdev) if (irq < 0) return -EPROBE_DEFER; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(base)) { - dev_err(&pdev->dev, "could not acquire device memory\n"); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); + if (IS_ERR(base)) return PTR_ERR(base); - } - clk = devm_clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "unable to find controller clock\n"); return PTR_ERR(clk); @@ -998,7 +1030,7 @@ static int sifive_serial_probe(struct platform_device *pdev) } /* Set up clock divider */ - ssp->clkin_rate = clk_get_rate(ssp->clk); + ssp->port.uartclk = clk_get_rate(ssp->clk); ssp->baud_rate = SIFIVE_DEFAULT_BAUD_RATE; __ssp_update_div(ssp); @@ -1040,7 +1072,7 @@ probe_out1: return r; } -static int sifive_serial_remove(struct platform_device *dev) +static void sifive_serial_remove(struct platform_device *dev) { struct sifive_serial_port *ssp = platform_get_drvdata(dev); @@ -1048,12 +1080,27 @@ static int sifive_serial_remove(struct platform_device *dev) uart_remove_one_port(&sifive_serial_uart_driver, &ssp->port); free_irq(ssp->port.irq, ssp); clk_notifier_unregister(ssp->clk, &ssp->clk_notifier); +} - return 0; +static int sifive_serial_suspend(struct device *dev) +{ + struct sifive_serial_port *ssp = dev_get_drvdata(dev); + + return uart_suspend_port(&sifive_serial_uart_driver, &ssp->port); } +static int sifive_serial_resume(struct device *dev) +{ + struct sifive_serial_port *ssp = dev_get_drvdata(dev); + + return uart_resume_port(&sifive_serial_uart_driver, &ssp->port); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend, + sifive_serial_resume); + static const struct of_device_id sifive_serial_of_match[] = { - { .compatible = "sifive,fu540-c000-uart0" }, + { .compatible = "sifive,fu540-c000-uart" }, { .compatible = "sifive,uart0" }, {}, }; @@ -1064,7 +1111,8 @@ static struct platform_driver sifive_serial_platform_driver = { .remove = sifive_serial_remove, .driver = { .name = SIFIVE_SERIAL_NAME, - .of_match_table = of_match_ptr(sifive_serial_of_match), + .pm = pm_sleep_ptr(&sifive_uart_pm_ops), + .of_match_table = sifive_serial_of_match, }, }; diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c deleted file mode 100644 index 38622f2a30a9..000000000000 --- a/drivers/tty/serial/sirfsoc_uart.c +++ /dev/null @@ -1,1503 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for CSR SiRFprimaII onboard UARTs. - * - * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - */ - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/init.h> -#include <linux/sysrq.h> -#include <linux/console.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/clk.h> -#include <linux/of.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/of_gpio.h> -#include <linux/dmaengine.h> -#include <linux/dma-direction.h> -#include <linux/dma-mapping.h> -#include <asm/irq.h> -#include <asm/mach/irq.h> - -#include "sirfsoc_uart.h" - -static unsigned int -sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count); -static unsigned int -sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count); -static struct uart_driver sirfsoc_uart_drv; - -static void sirfsoc_uart_tx_dma_complete_callback(void *param); -static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = { - {4000000, 2359296}, - {3500000, 1310721}, - {3000000, 1572865}, - {2500000, 1245186}, - {2000000, 1572866}, - {1500000, 1245188}, - {1152000, 1638404}, - {1000000, 1572869}, - {921600, 1114120}, - {576000, 1245196}, - {500000, 1245198}, - {460800, 1572876}, - {230400, 1310750}, - {115200, 1310781}, - {57600, 1310843}, - {38400, 1114328}, - {19200, 1114545}, - {9600, 1114979}, -}; - -static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR]; - -static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port) -{ - return container_of(port, struct sirfsoc_uart_port, port); -} - -static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port) -{ - unsigned long reg; - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status); - return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0; -} - -static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled) - goto cts_asserted; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - if (!(rd_regl(port, ureg->sirfsoc_afc_ctrl) & - SIRFUART_AFC_CTS_STATUS)) - goto cts_asserted; - else - goto cts_deasserted; - } else { - if (!gpio_get_value(sirfport->cts_gpio)) - goto cts_asserted; - else - goto cts_deasserted; - } -cts_deasserted: - return TIOCM_CAR | TIOCM_DSR; -cts_asserted: - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; -} - -static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - unsigned int assert = mctrl & TIOCM_RTS; - unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0; - unsigned int current_val; - - if (mctrl & TIOCM_LOOP) { - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) - wr_regl(port, ureg->sirfsoc_line_ctrl, - rd_regl(port, ureg->sirfsoc_line_ctrl) | - SIRFUART_LOOP_BACK); - else - wr_regl(port, ureg->sirfsoc_mode1, - rd_regl(port, ureg->sirfsoc_mode1) | - SIRFSOC_USP_LOOP_BACK_CTRL); - } else { - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) - wr_regl(port, ureg->sirfsoc_line_ctrl, - rd_regl(port, ureg->sirfsoc_line_ctrl) & - ~SIRFUART_LOOP_BACK); - else - wr_regl(port, ureg->sirfsoc_mode1, - rd_regl(port, ureg->sirfsoc_mode1) & - ~SIRFSOC_USP_LOOP_BACK_CTRL); - } - - if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled) - return; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF; - val |= current_val; - wr_regl(port, ureg->sirfsoc_afc_ctrl, val); - } else { - if (!val) - gpio_set_value(sirfport->rts_gpio, 1); - else - gpio_set_value(sirfport->rts_gpio, 0); - } -} - -static void sirfsoc_uart_stop_tx(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - - if (sirfport->tx_dma_chan) { - if (sirfport->tx_dma_state == TX_DMA_RUNNING) { - dmaengine_pause(sirfport->tx_dma_chan); - sirfport->tx_dma_state = TX_DMA_PAUSE; - } else { - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~uint_en->sirfsoc_txfifo_empty_en); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - uint_en->sirfsoc_txfifo_empty_en); - } - } else { - if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, - ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~uint_en->sirfsoc_txfifo_empty_en); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - uint_en->sirfsoc_txfifo_empty_en); - } -} - -static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport) -{ - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct circ_buf *xmit = &port->state->xmit; - unsigned long tran_size; - unsigned long tran_start; - unsigned long pio_tx_size; - - tran_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - tran_start = (unsigned long)(xmit->buf + xmit->tail); - if (uart_circ_empty(xmit) || uart_tx_stopped(port) || - !tran_size) - return; - if (sirfport->tx_dma_state == TX_DMA_PAUSE) { - dmaengine_resume(sirfport->tx_dma_chan); - return; - } - if (sirfport->tx_dma_state == TX_DMA_RUNNING) - return; - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg)& - ~(uint_en->sirfsoc_txfifo_empty_en)); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - uint_en->sirfsoc_txfifo_empty_en); - /* - * DMA requires buffer address and buffer length are both aligned with - * 4 bytes, so we use PIO for - * 1. if address is not aligned with 4bytes, use PIO for the first 1~3 - * bytes, and move to DMA for the left part aligned with 4bytes - * 2. if buffer length is not aligned with 4bytes, use DMA for aligned - * part first, move to PIO for the left 1~3 bytes - */ - if (tran_size < 4 || BYTES_TO_ALIGN(tran_start)) { - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP); - wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)| - SIRFUART_IO_MODE); - if (BYTES_TO_ALIGN(tran_start)) { - pio_tx_size = sirfsoc_uart_pio_tx_chars(sirfport, - BYTES_TO_ALIGN(tran_start)); - tran_size -= pio_tx_size; - } - if (tran_size < 4) - sirfsoc_uart_pio_tx_chars(sirfport, tran_size); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg)| - uint_en->sirfsoc_txfifo_empty_en); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_txfifo_empty_en); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); - } else { - /* tx transfer mode switch into dma mode */ - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP); - wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)& - ~SIRFUART_IO_MODE); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); - tran_size &= ~(0x3); - - sirfport->tx_dma_addr = dma_map_single(port->dev, - xmit->buf + xmit->tail, - tran_size, DMA_TO_DEVICE); - sirfport->tx_dma_desc = dmaengine_prep_slave_single( - sirfport->tx_dma_chan, sirfport->tx_dma_addr, - tran_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); - if (!sirfport->tx_dma_desc) { - dev_err(port->dev, "DMA prep slave single fail\n"); - return; - } - sirfport->tx_dma_desc->callback = - sirfsoc_uart_tx_dma_complete_callback; - sirfport->tx_dma_desc->callback_param = (void *)sirfport; - sirfport->transfer_size = tran_size; - - dmaengine_submit(sirfport->tx_dma_desc); - dma_async_issue_pending(sirfport->tx_dma_chan); - sirfport->tx_dma_state = TX_DMA_RUNNING; - } -} - -static void sirfsoc_uart_start_tx(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - if (sirfport->tx_dma_chan) - sirfsoc_uart_tx_with_dma(sirfport); - else { - if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, - ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP); - sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg)| - uint_en->sirfsoc_txfifo_empty_en); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_txfifo_empty_en); - } -} - -static void sirfsoc_uart_stop_rx(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - - wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - if (sirfport->rx_dma_chan) { - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(SIRFUART_RX_DMA_INT_EN(uint_en, - sirfport->uart_reg->uart_type) | - uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - SIRFUART_RX_DMA_INT_EN(uint_en, - sirfport->uart_reg->uart_type)| - uint_en->sirfsoc_rx_done_en); - dmaengine_terminate_all(sirfport->rx_dma_chan); - } else { - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg)& - ~(SIRFUART_RX_IO_INT_EN(uint_en, - sirfport->uart_reg->uart_type))); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - SIRFUART_RX_IO_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); - } -} - -static void sirfsoc_uart_disable_ms(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - - if (!sirfport->hw_flow_ctrl) - return; - sirfport->ms_enabled = false; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - wr_regl(port, ureg->sirfsoc_afc_ctrl, - rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg)& - ~uint_en->sirfsoc_cts_en); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - uint_en->sirfsoc_cts_en); - } else - disable_irq(gpio_to_irq(sirfport->cts_gpio)); -} - -static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id) -{ - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id; - struct uart_port *port = &sirfport->port; - spin_lock(&port->lock); - if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled) - uart_handle_cts_change(port, - !gpio_get_value(sirfport->cts_gpio)); - spin_unlock(&port->lock); - return IRQ_HANDLED; -} - -static void sirfsoc_uart_enable_ms(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - - if (!sirfport->hw_flow_ctrl) - return; - sirfport->ms_enabled = true; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - wr_regl(port, ureg->sirfsoc_afc_ctrl, - rd_regl(port, ureg->sirfsoc_afc_ctrl) | - SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN | - SIRFUART_AFC_CTRL_RX_THD); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) - | uint_en->sirfsoc_cts_en); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_cts_en); - } else - enable_irq(gpio_to_irq(sirfport->cts_gpio)); -} - -static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl); - if (break_state) - ulcon |= SIRFUART_SET_BREAK; - else - ulcon &= ~SIRFUART_SET_BREAK; - wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon); - } -} - -static unsigned int -sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - unsigned int ch, rx_count = 0; - struct tty_struct *tty; - tty = tty_port_tty_get(&port->state->port); - if (!tty) - return -ENODEV; - while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - ufifo_st->ff_empty(port))) { - ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) | - SIRFUART_DUMMY_READ; - if (unlikely(uart_handle_sysrq_char(port, ch))) - continue; - uart_insert_char(port, 0, 0, ch, TTY_NORMAL); - rx_count++; - if (rx_count >= max_rx_count) - break; - } - - port->icount.rx += rx_count; - - return rx_count; -} - -static unsigned int -sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count) -{ - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - struct circ_buf *xmit = &port->state->xmit; - unsigned int num_tx = 0; - while (!uart_circ_empty(xmit) && - !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_full(port)) && - count--) { - wr_regl(port, ureg->sirfsoc_tx_fifo_data, - xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - num_tx++; - } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - return num_tx; -} - -static void sirfsoc_uart_tx_dma_complete_callback(void *param) -{ - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - struct uart_port *port = &sirfport->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - xmit->tail = (xmit->tail + sirfport->transfer_size) & - (UART_XMIT_SIZE - 1); - port->icount.tx += sirfport->transfer_size; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - if (sirfport->tx_dma_addr) - dma_unmap_single(port->dev, sirfport->tx_dma_addr, - sirfport->transfer_size, DMA_TO_DEVICE); - sirfport->tx_dma_state = TX_DMA_IDLE; - sirfsoc_uart_tx_with_dma(sirfport); - spin_unlock_irqrestore(&port->lock, flags); -} - -static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) -{ - unsigned long intr_status; - unsigned long cts_status; - unsigned long flag = TTY_NORMAL; - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id; - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct uart_state *state = port->state; - struct circ_buf *xmit = &port->state->xmit; - spin_lock(&port->lock); - intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg); - wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status); - intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg); - if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st, - sirfport->uart_reg->uart_type)))) { - if (intr_status & uint_st->sirfsoc_rxd_brk) { - port->icount.brk++; - if (uart_handle_break(port)) - goto recv_char; - } - if (intr_status & uint_st->sirfsoc_rx_oflow) { - port->icount.overrun++; - flag = TTY_OVERRUN; - } - if (intr_status & uint_st->sirfsoc_frm_err) { - port->icount.frame++; - flag = TTY_FRAME; - } - if (intr_status & uint_st->sirfsoc_parity_err) { - port->icount.parity++; - flag = TTY_PARITY; - } - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); - intr_status &= port->read_status_mask; - uart_insert_char(port, intr_status, - uint_en->sirfsoc_rx_oflow_en, 0, flag); - } -recv_char: - if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) && - (intr_status & SIRFUART_CTS_INT_ST(uint_st)) && - !sirfport->tx_dma_state) { - cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) & - SIRFUART_AFC_CTS_STATUS; - if (cts_status != 0) - cts_status = 0; - else - cts_status = 1; - uart_handle_cts_change(port, cts_status); - wake_up_interruptible(&state->port.delta_msr_wait); - } - if (!sirfport->rx_dma_chan && - (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) { - /* - * chip will trigger continuous RX_TIMEOUT interrupt - * in RXFIFO empty and not trigger if RXFIFO recevice - * data in limit time, original method use RX_TIMEOUT - * will trigger lots of useless interrupt in RXFIFO - * empty.RXFIFO received one byte will trigger RX_DONE - * interrupt.use RX_DONE to wait for data received - * into RXFIFO, use RX_THD/RX_FULL for lots data receive - * and use RX_TIMEOUT for the last left data. - */ - if (intr_status & uint_st->sirfsoc_rx_done) { - if (!sirfport->is_atlas7) { - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) - & ~(uint_en->sirfsoc_rx_done_en)); - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) - | (uint_en->sirfsoc_rx_timeout_en)); - } else { - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, - uint_en->sirfsoc_rx_done_en); - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_rx_timeout_en); - } - } else { - if (intr_status & uint_st->sirfsoc_rx_timeout) { - if (!sirfport->is_atlas7) { - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) - & ~(uint_en->sirfsoc_rx_timeout_en)); - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) - | (uint_en->sirfsoc_rx_done_en)); - } else { - wr_regl(port, - ureg->sirfsoc_int_en_clr_reg, - uint_en->sirfsoc_rx_timeout_en); - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_rx_done_en); - } - } - sirfsoc_uart_pio_rx_chars(port, port->fifosize); - } - } - spin_unlock(&port->lock); - tty_flip_buffer_push(&state->port); - spin_lock(&port->lock); - if (intr_status & uint_st->sirfsoc_txfifo_empty) { - if (sirfport->tx_dma_chan) - sirfsoc_uart_tx_with_dma(sirfport); - else { - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - spin_unlock(&port->lock); - return IRQ_HANDLED; - } else { - sirfsoc_uart_pio_tx_chars(sirfport, - port->fifosize); - if ((uart_circ_empty(xmit)) && - (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_empty(port))) - sirfsoc_uart_stop_tx(port); - } - } - } - spin_unlock(&port->lock); - - return IRQ_HANDLED; -} - -static void sirfsoc_uart_rx_dma_complete_callback(void *param) -{ -} - -/* submit rx dma task into dmaengine */ -static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & - ~SIRFUART_IO_MODE); - sirfport->rx_dma_items.xmit.tail = - sirfport->rx_dma_items.xmit.head = 0; - sirfport->rx_dma_items.desc = - dmaengine_prep_dma_cyclic(sirfport->rx_dma_chan, - sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE, - SIRFSOC_RX_DMA_BUF_SIZE / 2, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); - if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) { - dev_err(port->dev, "DMA slave single fail\n"); - return; - } - sirfport->rx_dma_items.desc->callback = - sirfsoc_uart_rx_dma_complete_callback; - sirfport->rx_dma_items.desc->callback_param = sirfport; - sirfport->rx_dma_items.cookie = - dmaengine_submit(sirfport->rx_dma_items.desc); - dma_async_issue_pending(sirfport->rx_dma_chan); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_DMA_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_DMA_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); -} - -static unsigned int -sirfsoc_usp_calc_sample_div(unsigned long set_rate, - unsigned long ioclk_rate, unsigned long *sample_reg) -{ - unsigned long min_delta = ~0UL; - unsigned short sample_div; - unsigned long ioclk_div = 0; - unsigned long temp_delta; - - for (sample_div = SIRF_USP_MIN_SAMPLE_DIV; - sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) { - temp_delta = ioclk_rate - - (ioclk_rate + (set_rate * sample_div) / 2) - / (set_rate * sample_div) * set_rate * sample_div; - - temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta; - if (temp_delta < min_delta) { - ioclk_div = (2 * ioclk_rate / - (set_rate * sample_div) + 1) / 2 - 1; - if (ioclk_div > SIRF_IOCLK_DIV_MAX) - continue; - min_delta = temp_delta; - *sample_reg = sample_div; - if (!temp_delta) - break; - } - } - return ioclk_div; -} - -static unsigned int -sirfsoc_uart_calc_sample_div(unsigned long baud_rate, - unsigned long ioclk_rate, unsigned long *set_baud) -{ - unsigned long min_delta = ~0UL; - unsigned short sample_div; - unsigned int regv = 0; - unsigned long ioclk_div; - unsigned long baud_tmp; - int temp_delta; - - for (sample_div = SIRF_MIN_SAMPLE_DIV; - sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) { - ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1; - if (ioclk_div > SIRF_IOCLK_DIV_MAX) - continue; - baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1)); - temp_delta = baud_tmp - baud_rate; - temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta; - if (temp_delta < min_delta) { - regv = regv & (~SIRF_IOCLK_DIV_MASK); - regv = regv | ioclk_div; - regv = regv & (~SIRF_SAMPLE_DIV_MASK); - regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT); - min_delta = temp_delta; - *set_baud = baud_tmp; - } - } - return regv; -} - -static void sirfsoc_uart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - unsigned long config_reg = 0; - unsigned long baud_rate; - unsigned long set_baud; - unsigned long flags; - unsigned long ic; - unsigned int clk_div_reg = 0; - unsigned long txfifo_op_reg, ioclk_rate; - unsigned long rx_time_out; - int threshold_div; - u32 data_bit_len, stop_bit_len, len_val; - unsigned long sample_div_reg = 0xf; - ioclk_rate = port->uartclk; - - switch (termios->c_cflag & CSIZE) { - default: - case CS8: - data_bit_len = 8; - config_reg |= SIRFUART_DATA_BIT_LEN_8; - break; - case CS7: - data_bit_len = 7; - config_reg |= SIRFUART_DATA_BIT_LEN_7; - break; - case CS6: - data_bit_len = 6; - config_reg |= SIRFUART_DATA_BIT_LEN_6; - break; - case CS5: - data_bit_len = 5; - config_reg |= SIRFUART_DATA_BIT_LEN_5; - break; - } - if (termios->c_cflag & CSTOPB) { - config_reg |= SIRFUART_STOP_BIT_LEN_2; - stop_bit_len = 2; - } else - stop_bit_len = 1; - - spin_lock_irqsave(&port->lock, flags); - port->read_status_mask = uint_en->sirfsoc_rx_oflow_en; - port->ignore_status_mask = 0; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - if (termios->c_iflag & INPCK) - port->read_status_mask |= uint_en->sirfsoc_frm_err_en | - uint_en->sirfsoc_parity_err_en; - } else { - if (termios->c_iflag & INPCK) - port->read_status_mask |= uint_en->sirfsoc_frm_err_en; - } - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= - uint_en->sirfsoc_frm_err_en | - uint_en->sirfsoc_parity_err_en; - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & CMSPAR) { - if (termios->c_cflag & PARODD) - config_reg |= SIRFUART_STICK_BIT_MARK; - else - config_reg |= SIRFUART_STICK_BIT_SPACE; - } else { - if (termios->c_cflag & PARODD) - config_reg |= SIRFUART_STICK_BIT_ODD; - else - config_reg |= SIRFUART_STICK_BIT_EVEN; - } - } - } else { - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= - uint_en->sirfsoc_frm_err_en; - if (termios->c_cflag & PARENB) - dev_warn(port->dev, - "USP-UART not support parity err\n"); - } - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= - uint_en->sirfsoc_rxd_brk_en; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= - uint_en->sirfsoc_rx_oflow_en; - } - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= SIRFUART_DUMMY_READ; - /* Hardware Flow Control Settings */ - if (UART_ENABLE_MS(port, termios->c_cflag)) { - if (!sirfport->ms_enabled) - sirfsoc_uart_enable_ms(port); - } else { - if (sirfport->ms_enabled) - sirfsoc_uart_disable_ms(port); - } - baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000); - if (ioclk_rate == 150000000) { - for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++) - if (baud_rate == baudrate_to_regv[ic].baud_rate) - clk_div_reg = baudrate_to_regv[ic].reg_val; - } - set_baud = baud_rate; - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - if (unlikely(clk_div_reg == 0)) - clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate, - ioclk_rate, &set_baud); - wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg); - } else { - clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate, - ioclk_rate, &sample_div_reg); - sample_div_reg--; - set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) / - (sample_div_reg + 1)); - /* setting usp mode 2 */ - len_val = ((1 << SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET) | - (1 << SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET)); - len_val |= ((clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK) - << SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET); - wr_regl(port, ureg->sirfsoc_mode2, len_val); - } - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, set_baud, set_baud); - /* set receive timeout && data bits len */ - rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000); - rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out); - txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, - (txfifo_op_reg & ~SIRFUART_FIFO_START)); - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out); - wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg); - } else { - /*tx frame ctrl*/ - len_val = (data_bit_len - 1) << SIRFSOC_USP_TX_DATA_LEN_OFFSET; - len_val |= (data_bit_len + 1 + stop_bit_len - 1) << - SIRFSOC_USP_TX_FRAME_LEN_OFFSET; - len_val |= ((data_bit_len - 1) << - SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET); - len_val |= (((clk_div_reg & 0xc00) >> 10) << - SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET); - wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val); - /*rx frame ctrl*/ - len_val = (data_bit_len - 1) << SIRFSOC_USP_RX_DATA_LEN_OFFSET; - len_val |= (data_bit_len + 1 + stop_bit_len - 1) << - SIRFSOC_USP_RX_FRAME_LEN_OFFSET; - len_val |= (data_bit_len - 1) << - SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET; - len_val |= (((clk_div_reg & 0xf000) >> 12) << - SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET); - wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val); - /*async param*/ - wr_regl(port, ureg->sirfsoc_async_param_reg, - (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) | - (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) << - SIRFSOC_USP_ASYNC_DIV2_OFFSET); - } - if (sirfport->tx_dma_chan) - wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE); - else - wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE); - if (sirfport->rx_dma_chan) - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & - ~SIRFUART_IO_MODE); - else - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | - SIRFUART_IO_MODE); - sirfport->rx_period_time = 20000000; - /* Reset Rx/Tx FIFO Threshold level for proper baudrate */ - if (set_baud < 1000000) - threshold_div = 1; - else - threshold_div = 2; - wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, - SIRFUART_FIFO_THD(port) / threshold_div); - wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, - SIRFUART_FIFO_THD(port) / threshold_div); - txfifo_op_reg |= SIRFUART_FIFO_START; - wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg); - uart_update_timeout(port, termios->c_cflag, set_baud); - wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - if (!state) - clk_prepare_enable(sirfport->clk); - else - clk_disable_unprepare(sirfport->clk); -} - -static int sirfsoc_uart_startup(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - unsigned int index = port->line; - int ret; - irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN); - ret = request_irq(port->irq, - sirfsoc_uart_isr, - 0, - SIRFUART_PORT_NAME, - sirfport); - if (ret != 0) { - dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n", - index, port->irq); - goto irq_err; - } - /* initial hardware settings */ - wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) | - SIRFUART_IO_MODE); - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | - SIRFUART_IO_MODE); - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & - ~SIRFUART_RX_DMA_FLUSH); - wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0); - wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0); - wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN); - if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(port, ureg->sirfsoc_mode1, - SIRFSOC_USP_ENDIAN_CTRL_LSBF | - SIRFSOC_USP_EN); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port)); - wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port)); - if (sirfport->rx_dma_chan) - wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk, - SIRFUART_RX_FIFO_CHK_SC(port->line, 0x1) | - SIRFUART_RX_FIFO_CHK_LC(port->line, 0x2) | - SIRFUART_RX_FIFO_CHK_HC(port->line, 0x4)); - if (sirfport->tx_dma_chan) { - sirfport->tx_dma_state = TX_DMA_IDLE; - wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk, - SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) | - SIRFUART_TX_FIFO_CHK_LC(port->line, 0xe) | - SIRFUART_TX_FIFO_CHK_HC(port->line, 0x4)); - } - sirfport->ms_enabled = false; - if (sirfport->uart_reg->uart_type == SIRF_USP_UART && - sirfport->hw_flow_ctrl) { - irq_modify_status(gpio_to_irq(sirfport->cts_gpio), - IRQ_NOREQUEST, IRQ_NOAUTOEN); - ret = request_irq(gpio_to_irq(sirfport->cts_gpio), - sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING | - IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport); - if (ret != 0) { - dev_err(port->dev, "UART-USP:request gpio irq fail\n"); - goto init_rx_err; - } - } - if (sirfport->uart_reg->uart_type == SIRF_REAL_UART && - sirfport->rx_dma_chan) - wr_regl(port, ureg->sirfsoc_swh_dma_io, - SIRFUART_CLEAR_RX_ADDR_EN); - if (sirfport->uart_reg->uart_type == SIRF_USP_UART && - sirfport->rx_dma_chan) - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | - SIRFSOC_USP_FRADDR_CLR_EN); - if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) { - sirfport->is_hrt_enabled = true; - sirfport->rx_period_time = 20000000; - sirfport->rx_last_pos = -1; - sirfport->pio_fetch_cnt = 0; - sirfport->rx_dma_items.xmit.tail = - sirfport->rx_dma_items.xmit.head = 0; - hrtimer_start(&sirfport->hrt, - ns_to_ktime(sirfport->rx_period_time), - HRTIMER_MODE_REL); - } - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); - if (sirfport->rx_dma_chan) - sirfsoc_uart_start_next_rx_dma(port); - else { - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_IO_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_IO_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); - } - enable_irq(port->irq); - - return 0; -init_rx_err: - free_irq(port->irq, sirfport); -irq_err: - return ret; -} - -static void sirfsoc_uart_shutdown(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct circ_buf *xmit; - - xmit = &sirfport->rx_dma_items.xmit; - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, 0); - else - wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL); - - free_irq(port->irq, sirfport); - if (sirfport->ms_enabled) - sirfsoc_uart_disable_ms(port); - if (sirfport->uart_reg->uart_type == SIRF_USP_UART && - sirfport->hw_flow_ctrl) { - gpio_set_value(sirfport->rts_gpio, 1); - free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport); - } - if (sirfport->tx_dma_chan) - sirfport->tx_dma_state = TX_DMA_IDLE; - if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) { - while (((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt) && - !CIRC_CNT(xmit->head, xmit->tail, - SIRFSOC_RX_DMA_BUF_SIZE)) - ; - sirfport->is_hrt_enabled = false; - hrtimer_cancel(&sirfport->hrt); - } -} - -static const char *sirfsoc_uart_type(struct uart_port *port) -{ - return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL; -} - -static int sirfsoc_uart_request_port(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_uart_param *uart_param = &sirfport->uart_reg->uart_param; - void *ret; - ret = request_mem_region(port->mapbase, - SIRFUART_MAP_SIZE, uart_param->port_name); - return ret ? 0 : -EBUSY; -} - -static void sirfsoc_uart_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, SIRFUART_MAP_SIZE); -} - -static void sirfsoc_uart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = SIRFSOC_PORT_TYPE; - sirfsoc_uart_request_port(port); - } -} - -static const struct uart_ops sirfsoc_uart_ops = { - .tx_empty = sirfsoc_uart_tx_empty, - .get_mctrl = sirfsoc_uart_get_mctrl, - .set_mctrl = sirfsoc_uart_set_mctrl, - .stop_tx = sirfsoc_uart_stop_tx, - .start_tx = sirfsoc_uart_start_tx, - .stop_rx = sirfsoc_uart_stop_rx, - .enable_ms = sirfsoc_uart_enable_ms, - .break_ctl = sirfsoc_uart_break_ctl, - .startup = sirfsoc_uart_startup, - .shutdown = sirfsoc_uart_shutdown, - .set_termios = sirfsoc_uart_set_termios, - .pm = sirfsoc_uart_pm, - .type = sirfsoc_uart_type, - .release_port = sirfsoc_uart_release_port, - .request_port = sirfsoc_uart_request_port, - .config_port = sirfsoc_uart_config_port, -}; - -#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE -static int __init -sirfsoc_uart_console_setup(struct console *co, char *options) -{ - unsigned int baud = 115200; - unsigned int bits = 8; - unsigned int parity = 'n'; - unsigned int flow = 'n'; - struct sirfsoc_uart_port *sirfport; - struct sirfsoc_register *ureg; - if (co->index < 0 || co->index >= SIRFSOC_UART_NR) - co->index = 1; - sirfport = sirf_ports[co->index]; - if (!sirfport) - return -ENODEV; - ureg = &sirfport->uart_reg->uart_reg; - if (!sirfport->port.mapbase) - return -ENODEV; - - /* enable usp in mode1 register */ - if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | - SIRFSOC_USP_ENDIAN_CTRL_LSBF); - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - sirfport->port.cons = co; - - /* default console tx/rx transfer using io mode */ - sirfport->rx_dma_chan = NULL; - sirfport->tx_dma_chan = NULL; - return uart_set_options(&sirfport->port, co, baud, parity, bits, flow); -} - -static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_full(port)) - cpu_relax(); - wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch); -} - -static void sirfsoc_uart_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct sirfsoc_uart_port *sirfport = sirf_ports[co->index]; - - uart_console_write(&sirfport->port, s, count, - sirfsoc_uart_console_putchar); -} - -static struct console sirfsoc_uart_console = { - .name = SIRFSOC_UART_NAME, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .index = -1, - .write = sirfsoc_uart_console_write, - .setup = sirfsoc_uart_console_setup, - .data = &sirfsoc_uart_drv, -}; - -static int __init sirfsoc_uart_console_init(void) -{ - register_console(&sirfsoc_uart_console); - return 0; -} -console_initcall(sirfsoc_uart_console_init); -#endif - -static struct uart_driver sirfsoc_uart_drv = { - .owner = THIS_MODULE, - .driver_name = SIRFUART_PORT_NAME, - .nr = SIRFSOC_UART_NR, - .dev_name = SIRFSOC_UART_NAME, - .major = SIRFSOC_UART_MAJOR, - .minor = SIRFSOC_UART_MINOR, -#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE - .cons = &sirfsoc_uart_console, -#else - .cons = NULL, -#endif -}; - -static enum hrtimer_restart - sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt) -{ - struct sirfsoc_uart_port *sirfport; - struct uart_port *port; - int count, inserted; - struct dma_tx_state tx_state; - struct tty_struct *tty; - struct sirfsoc_register *ureg; - struct circ_buf *xmit; - struct sirfsoc_fifo_status *ufifo_st; - int max_pio_cnt; - - sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt); - port = &sirfport->port; - inserted = 0; - tty = port->state->port.tty; - ureg = &sirfport->uart_reg->uart_reg; - xmit = &sirfport->rx_dma_items.xmit; - ufifo_st = &sirfport->uart_reg->fifo_status; - - dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items.cookie, &tx_state); - if (SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue != - sirfport->rx_last_pos) { - xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; - sirfport->rx_last_pos = xmit->head; - sirfport->pio_fetch_cnt = 0; - } - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, - SIRFSOC_RX_DMA_BUF_SIZE); - while (count > 0) { - inserted = tty_insert_flip_string(tty->port, - (const unsigned char *)&xmit->buf[xmit->tail], count); - if (!inserted) - goto next_hrt; - port->icount.rx += inserted; - xmit->tail = (xmit->tail + inserted) & - (SIRFSOC_RX_DMA_BUF_SIZE - 1); - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, - SIRFSOC_RX_DMA_BUF_SIZE); - tty_flip_buffer_push(tty->port); - } - /* - * if RX DMA buffer data have all push into tty buffer, and there is - * only little data(less than a dma transfer unit) left in rxfifo, - * fetch it out in pio mode and switch back to dma immediately - */ - if (!inserted && !count && - ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt)) { - dmaengine_pause(sirfport->rx_dma_chan); - /* switch to pio mode */ - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | - SIRFUART_IO_MODE); - /* - * UART controller SWH_DMA_IO register have CLEAR_RX_ADDR_EN - * When found changing I/O to DMA mode, it clears - * two low bits of read point; - * USP have similar FRADDR_CLR_EN bit in USP_RX_DMA_IO_CTRL. - * Fetch data out from rxfifo into DMA buffer in PIO mode, - * while switch back to DMA mode, the data fetched will override - * by DMA, as hardware have a strange behaviour: - * after switch back to DMA mode, check rxfifo status it will - * be the number PIO fetched, so record the fetched data count - * to avoid the repeated fetch - */ - max_pio_cnt = 3; - while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - ufifo_st->ff_empty(port)) && max_pio_cnt--) { - xmit->buf[xmit->head] = - rd_regl(port, ureg->sirfsoc_rx_fifo_data); - xmit->head = (xmit->head + 1) & - (SIRFSOC_RX_DMA_BUF_SIZE - 1); - sirfport->pio_fetch_cnt++; - } - /* switch back to dma mode */ - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & - ~SIRFUART_IO_MODE); - dmaengine_resume(sirfport->rx_dma_chan); - } -next_hrt: - hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time)); - return HRTIMER_RESTART; -} - -static const struct of_device_id sirfsoc_uart_ids[] = { - { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,}, - { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart}, - { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp}, - { .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp}, - {} -}; -MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids); - -static int sirfsoc_uart_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct sirfsoc_uart_port *sirfport; - struct uart_port *port; - struct resource *res; - int ret; - struct dma_slave_config slv_cfg = { - .src_maxburst = 1, - }; - struct dma_slave_config tx_slv_cfg = { - .dst_maxburst = 2, - }; - const struct of_device_id *match; - - match = of_match_node(sirfsoc_uart_ids, np); - sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL); - if (!sirfport) { - ret = -ENOMEM; - goto err; - } - sirfport->port.line = of_alias_get_id(np, "serial"); - if (sirfport->port.line >= ARRAY_SIZE(sirf_ports)) { - dev_err(&pdev->dev, "serial%d out of range\n", - sirfport->port.line); - return -EINVAL; - } - sirf_ports[sirfport->port.line] = sirfport; - sirfport->port.iotype = UPIO_MEM; - sirfport->port.flags = UPF_BOOT_AUTOCONF; - port = &sirfport->port; - port->dev = &pdev->dev; - port->private_data = sirfport; - sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data; - - sirfport->hw_flow_ctrl = - of_property_read_bool(np, "uart-has-rtscts") || - of_property_read_bool(np, "sirf,uart-has-rtscts") /* deprecated */; - if (of_device_is_compatible(np, "sirf,prima2-uart") || - of_device_is_compatible(np, "sirf,atlas7-uart")) - sirfport->uart_reg->uart_type = SIRF_REAL_UART; - if (of_device_is_compatible(np, "sirf,prima2-usp-uart") || - of_device_is_compatible(np, "sirf,atlas7-usp-uart")) { - sirfport->uart_reg->uart_type = SIRF_USP_UART; - if (!sirfport->hw_flow_ctrl) - goto usp_no_flow_control; - if (of_find_property(np, "cts-gpios", NULL)) - sirfport->cts_gpio = - of_get_named_gpio(np, "cts-gpios", 0); - else - sirfport->cts_gpio = -1; - if (of_find_property(np, "rts-gpios", NULL)) - sirfport->rts_gpio = - of_get_named_gpio(np, "rts-gpios", 0); - else - sirfport->rts_gpio = -1; - - if ((!gpio_is_valid(sirfport->cts_gpio) || - !gpio_is_valid(sirfport->rts_gpio))) { - ret = -EINVAL; - dev_err(&pdev->dev, - "Usp flow control must have cts and rts gpio"); - goto err; - } - ret = devm_gpio_request(&pdev->dev, sirfport->cts_gpio, - "usp-cts-gpio"); - if (ret) { - dev_err(&pdev->dev, "Unable request cts gpio"); - goto err; - } - gpio_direction_input(sirfport->cts_gpio); - ret = devm_gpio_request(&pdev->dev, sirfport->rts_gpio, - "usp-rts-gpio"); - if (ret) { - dev_err(&pdev->dev, "Unable request rts gpio"); - goto err; - } - gpio_direction_output(sirfport->rts_gpio, 1); - } -usp_no_flow_control: - if (of_device_is_compatible(np, "sirf,atlas7-uart") || - of_device_is_compatible(np, "sirf,atlas7-usp-uart")) - sirfport->is_atlas7 = true; - - if (of_property_read_u32(np, "fifosize", &port->fifosize)) { - dev_err(&pdev->dev, - "Unable to find fifosize in uart node.\n"); - ret = -EFAULT; - goto err; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Insufficient resources.\n"); - ret = -EFAULT; - goto err; - } - port->mapbase = res->start; - port->membase = devm_ioremap(&pdev->dev, - res->start, resource_size(res)); - if (!port->membase) { - dev_err(&pdev->dev, "Cannot remap resource.\n"); - ret = -ENOMEM; - goto err; - } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Insufficient resources.\n"); - ret = -EFAULT; - goto err; - } - port->irq = res->start; - - sirfport->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(sirfport->clk)) { - ret = PTR_ERR(sirfport->clk); - goto err; - } - port->uartclk = clk_get_rate(sirfport->clk); - - port->ops = &sirfsoc_uart_ops; - spin_lock_init(&port->lock); - - platform_set_drvdata(pdev, sirfport); - ret = uart_add_one_port(&sirfsoc_uart_drv, port); - if (ret != 0) { - dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id); - goto err; - } - - sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); - sirfport->rx_dma_items.xmit.buf = - dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - &sirfport->rx_dma_items.dma_addr, GFP_KERNEL); - if (!sirfport->rx_dma_items.xmit.buf) { - dev_err(port->dev, "Uart alloc bufa failed\n"); - ret = -ENOMEM; - goto alloc_coherent_err; - } - sirfport->rx_dma_items.xmit.head = - sirfport->rx_dma_items.xmit.tail = 0; - if (sirfport->rx_dma_chan) - dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); - sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx"); - if (sirfport->tx_dma_chan) - dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); - if (sirfport->rx_dma_chan) { - hrtimer_init(&sirfport->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - sirfport->hrt.function = sirfsoc_uart_rx_dma_hrtimer_callback; - sirfport->is_hrt_enabled = false; - } - - return 0; -alloc_coherent_err: - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items.xmit.buf, - sirfport->rx_dma_items.dma_addr); - dma_release_channel(sirfport->rx_dma_chan); -err: - return ret; -} - -static int sirfsoc_uart_remove(struct platform_device *pdev) -{ - struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); - struct uart_port *port = &sirfport->port; - uart_remove_one_port(&sirfsoc_uart_drv, port); - if (sirfport->rx_dma_chan) { - dmaengine_terminate_all(sirfport->rx_dma_chan); - dma_release_channel(sirfport->rx_dma_chan); - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items.xmit.buf, - sirfport->rx_dma_items.dma_addr); - } - if (sirfport->tx_dma_chan) { - dmaengine_terminate_all(sirfport->tx_dma_chan); - dma_release_channel(sirfport->tx_dma_chan); - } - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int -sirfsoc_uart_suspend(struct device *pdev) -{ - struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev); - struct uart_port *port = &sirfport->port; - uart_suspend_port(&sirfsoc_uart_drv, port); - return 0; -} - -static int sirfsoc_uart_resume(struct device *pdev) -{ - struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev); - struct uart_port *port = &sirfport->port; - uart_resume_port(&sirfsoc_uart_drv, port); - return 0; -} -#endif - -static const struct dev_pm_ops sirfsoc_uart_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_uart_suspend, sirfsoc_uart_resume) -}; - -static struct platform_driver sirfsoc_uart_driver = { - .probe = sirfsoc_uart_probe, - .remove = sirfsoc_uart_remove, - .driver = { - .name = SIRFUART_PORT_NAME, - .of_match_table = sirfsoc_uart_ids, - .pm = &sirfsoc_uart_pm_ops, - }, -}; - -static int __init sirfsoc_uart_init(void) -{ - int ret = 0; - - ret = uart_register_driver(&sirfsoc_uart_drv); - if (ret) - goto out; - - ret = platform_driver_register(&sirfsoc_uart_driver); - if (ret) - uart_unregister_driver(&sirfsoc_uart_drv); -out: - return ret; -} -module_init(sirfsoc_uart_init); - -static void __exit sirfsoc_uart_exit(void) -{ - platform_driver_unregister(&sirfsoc_uart_driver); - uart_unregister_driver(&sirfsoc_uart_drv); -} -module_exit(sirfsoc_uart_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>"); -MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver"); diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h deleted file mode 100644 index fb88ac565227..000000000000 --- a/drivers/tty/serial/sirfsoc_uart.h +++ /dev/null @@ -1,447 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Drivers for CSR SiRFprimaII onboard UARTs. - * - * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - */ -#include <linux/bitops.h> -#include <linux/log2.h> -#include <linux/hrtimer.h> -struct sirfsoc_uart_param { - const char *uart_name; - const char *port_name; -}; - -struct sirfsoc_register { - /* hardware uart specific */ - u32 sirfsoc_line_ctrl; - u32 sirfsoc_divisor; - /* uart - usp common */ - u32 sirfsoc_tx_rx_en; - u32 sirfsoc_int_en_reg; - u32 sirfsoc_int_st_reg; - u32 sirfsoc_int_en_clr_reg; - u32 sirfsoc_tx_dma_io_ctrl; - u32 sirfsoc_tx_dma_io_len; - u32 sirfsoc_tx_fifo_ctrl; - u32 sirfsoc_tx_fifo_level_chk; - u32 sirfsoc_tx_fifo_op; - u32 sirfsoc_tx_fifo_status; - u32 sirfsoc_tx_fifo_data; - u32 sirfsoc_rx_dma_io_ctrl; - u32 sirfsoc_rx_dma_io_len; - u32 sirfsoc_rx_fifo_ctrl; - u32 sirfsoc_rx_fifo_level_chk; - u32 sirfsoc_rx_fifo_op; - u32 sirfsoc_rx_fifo_status; - u32 sirfsoc_rx_fifo_data; - u32 sirfsoc_afc_ctrl; - u32 sirfsoc_swh_dma_io; - /* hardware usp specific */ - u32 sirfsoc_mode1; - u32 sirfsoc_mode2; - u32 sirfsoc_tx_frame_ctrl; - u32 sirfsoc_rx_frame_ctrl; - u32 sirfsoc_async_param_reg; -}; - -typedef u32 (*fifo_full_mask)(struct uart_port *port); -typedef u32 (*fifo_empty_mask)(struct uart_port *port); - -struct sirfsoc_fifo_status { - fifo_full_mask ff_full; - fifo_empty_mask ff_empty; -}; - -struct sirfsoc_int_en { - u32 sirfsoc_rx_done_en; - u32 sirfsoc_tx_done_en; - u32 sirfsoc_rx_oflow_en; - u32 sirfsoc_tx_allout_en; - u32 sirfsoc_rx_io_dma_en; - u32 sirfsoc_tx_io_dma_en; - u32 sirfsoc_rxfifo_full_en; - u32 sirfsoc_txfifo_empty_en; - u32 sirfsoc_rxfifo_thd_en; - u32 sirfsoc_txfifo_thd_en; - u32 sirfsoc_frm_err_en; - u32 sirfsoc_rxd_brk_en; - u32 sirfsoc_rx_timeout_en; - u32 sirfsoc_parity_err_en; - u32 sirfsoc_cts_en; - u32 sirfsoc_rts_en; -}; - -struct sirfsoc_int_status { - u32 sirfsoc_rx_done; - u32 sirfsoc_tx_done; - u32 sirfsoc_rx_oflow; - u32 sirfsoc_tx_allout; - u32 sirfsoc_rx_io_dma; - u32 sirfsoc_tx_io_dma; - u32 sirfsoc_rxfifo_full; - u32 sirfsoc_txfifo_empty; - u32 sirfsoc_rxfifo_thd; - u32 sirfsoc_txfifo_thd; - u32 sirfsoc_frm_err; - u32 sirfsoc_rxd_brk; - u32 sirfsoc_rx_timeout; - u32 sirfsoc_parity_err; - u32 sirfsoc_cts; - u32 sirfsoc_rts; -}; - -enum sirfsoc_uart_type { - SIRF_REAL_UART, - SIRF_USP_UART, -}; - -struct sirfsoc_uart_register { - struct sirfsoc_register uart_reg; - struct sirfsoc_int_en uart_int_en; - struct sirfsoc_int_status uart_int_st; - struct sirfsoc_fifo_status fifo_status; - struct sirfsoc_uart_param uart_param; - enum sirfsoc_uart_type uart_type; -}; - -static u32 uart_usp_ff_full_mask(struct uart_port *port) -{ - u32 full_bit; - - full_bit = ilog2(port->fifosize); - return (1 << full_bit); -} - -static u32 uart_usp_ff_empty_mask(struct uart_port *port) -{ - u32 empty_bit; - - empty_bit = ilog2(port->fifosize) + 1; - return (1 << empty_bit); -} - -static struct sirfsoc_uart_register sirfsoc_usp = { - .uart_reg = { - .sirfsoc_mode1 = 0x0000, - .sirfsoc_mode2 = 0x0004, - .sirfsoc_tx_frame_ctrl = 0x0008, - .sirfsoc_rx_frame_ctrl = 0x000c, - .sirfsoc_tx_rx_en = 0x0010, - .sirfsoc_int_en_reg = 0x0014, - .sirfsoc_int_st_reg = 0x0018, - .sirfsoc_async_param_reg = 0x0024, - .sirfsoc_tx_dma_io_ctrl = 0x0100, - .sirfsoc_tx_dma_io_len = 0x0104, - .sirfsoc_tx_fifo_ctrl = 0x0108, - .sirfsoc_tx_fifo_level_chk = 0x010c, - .sirfsoc_tx_fifo_op = 0x0110, - .sirfsoc_tx_fifo_status = 0x0114, - .sirfsoc_tx_fifo_data = 0x0118, - .sirfsoc_rx_dma_io_ctrl = 0x0120, - .sirfsoc_rx_dma_io_len = 0x0124, - .sirfsoc_rx_fifo_ctrl = 0x0128, - .sirfsoc_rx_fifo_level_chk = 0x012c, - .sirfsoc_rx_fifo_op = 0x0130, - .sirfsoc_rx_fifo_status = 0x0134, - .sirfsoc_rx_fifo_data = 0x0138, - .sirfsoc_int_en_clr_reg = 0x140, - }, - .uart_int_en = { - .sirfsoc_rx_done_en = BIT(0), - .sirfsoc_tx_done_en = BIT(1), - .sirfsoc_rx_oflow_en = BIT(2), - .sirfsoc_tx_allout_en = BIT(3), - .sirfsoc_rx_io_dma_en = BIT(4), - .sirfsoc_tx_io_dma_en = BIT(5), - .sirfsoc_rxfifo_full_en = BIT(6), - .sirfsoc_txfifo_empty_en = BIT(7), - .sirfsoc_rxfifo_thd_en = BIT(8), - .sirfsoc_txfifo_thd_en = BIT(9), - .sirfsoc_frm_err_en = BIT(10), - .sirfsoc_rx_timeout_en = BIT(11), - .sirfsoc_rxd_brk_en = BIT(15), - }, - .uart_int_st = { - .sirfsoc_rx_done = BIT(0), - .sirfsoc_tx_done = BIT(1), - .sirfsoc_rx_oflow = BIT(2), - .sirfsoc_tx_allout = BIT(3), - .sirfsoc_rx_io_dma = BIT(4), - .sirfsoc_tx_io_dma = BIT(5), - .sirfsoc_rxfifo_full = BIT(6), - .sirfsoc_txfifo_empty = BIT(7), - .sirfsoc_rxfifo_thd = BIT(8), - .sirfsoc_txfifo_thd = BIT(9), - .sirfsoc_frm_err = BIT(10), - .sirfsoc_rx_timeout = BIT(11), - .sirfsoc_rxd_brk = BIT(15), - }, - .fifo_status = { - .ff_full = uart_usp_ff_full_mask, - .ff_empty = uart_usp_ff_empty_mask, - }, - .uart_param = { - .uart_name = "ttySiRF", - .port_name = "sirfsoc-uart", - }, -}; - -static struct sirfsoc_uart_register sirfsoc_uart = { - .uart_reg = { - .sirfsoc_line_ctrl = 0x0040, - .sirfsoc_tx_rx_en = 0x004c, - .sirfsoc_divisor = 0x0050, - .sirfsoc_int_en_reg = 0x0054, - .sirfsoc_int_st_reg = 0x0058, - .sirfsoc_int_en_clr_reg = 0x0060, - .sirfsoc_tx_dma_io_ctrl = 0x0100, - .sirfsoc_tx_dma_io_len = 0x0104, - .sirfsoc_tx_fifo_ctrl = 0x0108, - .sirfsoc_tx_fifo_level_chk = 0x010c, - .sirfsoc_tx_fifo_op = 0x0110, - .sirfsoc_tx_fifo_status = 0x0114, - .sirfsoc_tx_fifo_data = 0x0118, - .sirfsoc_rx_dma_io_ctrl = 0x0120, - .sirfsoc_rx_dma_io_len = 0x0124, - .sirfsoc_rx_fifo_ctrl = 0x0128, - .sirfsoc_rx_fifo_level_chk = 0x012c, - .sirfsoc_rx_fifo_op = 0x0130, - .sirfsoc_rx_fifo_status = 0x0134, - .sirfsoc_rx_fifo_data = 0x0138, - .sirfsoc_afc_ctrl = 0x0140, - .sirfsoc_swh_dma_io = 0x0148, - }, - .uart_int_en = { - .sirfsoc_rx_done_en = BIT(0), - .sirfsoc_tx_done_en = BIT(1), - .sirfsoc_rx_oflow_en = BIT(2), - .sirfsoc_tx_allout_en = BIT(3), - .sirfsoc_rx_io_dma_en = BIT(4), - .sirfsoc_tx_io_dma_en = BIT(5), - .sirfsoc_rxfifo_full_en = BIT(6), - .sirfsoc_txfifo_empty_en = BIT(7), - .sirfsoc_rxfifo_thd_en = BIT(8), - .sirfsoc_txfifo_thd_en = BIT(9), - .sirfsoc_frm_err_en = BIT(10), - .sirfsoc_rxd_brk_en = BIT(11), - .sirfsoc_rx_timeout_en = BIT(12), - .sirfsoc_parity_err_en = BIT(13), - .sirfsoc_cts_en = BIT(14), - .sirfsoc_rts_en = BIT(15), - }, - .uart_int_st = { - .sirfsoc_rx_done = BIT(0), - .sirfsoc_tx_done = BIT(1), - .sirfsoc_rx_oflow = BIT(2), - .sirfsoc_tx_allout = BIT(3), - .sirfsoc_rx_io_dma = BIT(4), - .sirfsoc_tx_io_dma = BIT(5), - .sirfsoc_rxfifo_full = BIT(6), - .sirfsoc_txfifo_empty = BIT(7), - .sirfsoc_rxfifo_thd = BIT(8), - .sirfsoc_txfifo_thd = BIT(9), - .sirfsoc_frm_err = BIT(10), - .sirfsoc_rxd_brk = BIT(11), - .sirfsoc_rx_timeout = BIT(12), - .sirfsoc_parity_err = BIT(13), - .sirfsoc_cts = BIT(14), - .sirfsoc_rts = BIT(15), - }, - .fifo_status = { - .ff_full = uart_usp_ff_full_mask, - .ff_empty = uart_usp_ff_empty_mask, - }, - .uart_param = { - .uart_name = "ttySiRF", - .port_name = "sirfsoc_uart", - }, -}; -/* uart io ctrl */ -#define SIRFUART_DATA_BIT_LEN_MASK 0x3 -#define SIRFUART_DATA_BIT_LEN_5 BIT(0) -#define SIRFUART_DATA_BIT_LEN_6 1 -#define SIRFUART_DATA_BIT_LEN_7 2 -#define SIRFUART_DATA_BIT_LEN_8 3 -#define SIRFUART_STOP_BIT_LEN_1 0 -#define SIRFUART_STOP_BIT_LEN_2 BIT(2) -#define SIRFUART_PARITY_EN BIT(3) -#define SIRFUART_EVEN_BIT BIT(4) -#define SIRFUART_STICK_BIT_MASK (7 << 3) -#define SIRFUART_STICK_BIT_NONE (0 << 3) -#define SIRFUART_STICK_BIT_EVEN BIT(3) -#define SIRFUART_STICK_BIT_ODD (3 << 3) -#define SIRFUART_STICK_BIT_MARK (5 << 3) -#define SIRFUART_STICK_BIT_SPACE (7 << 3) -#define SIRFUART_SET_BREAK BIT(6) -#define SIRFUART_LOOP_BACK BIT(7) -#define SIRFUART_PARITY_MASK (7 << 3) -#define SIRFUART_DUMMY_READ BIT(16) -#define SIRFUART_AFC_CTRL_RX_THD 0x70 -#define SIRFUART_AFC_RX_EN BIT(8) -#define SIRFUART_AFC_TX_EN BIT(9) -#define SIRFUART_AFC_CTS_CTRL BIT(10) -#define SIRFUART_AFC_RTS_CTRL BIT(11) -#define SIRFUART_AFC_CTS_STATUS BIT(12) -#define SIRFUART_AFC_RTS_STATUS BIT(13) -/* UART FIFO Register */ -#define SIRFUART_FIFO_STOP 0x0 -#define SIRFUART_FIFO_RESET BIT(0) -#define SIRFUART_FIFO_START BIT(1) - -#define SIRFUART_RX_EN BIT(0) -#define SIRFUART_TX_EN BIT(1) - -#define SIRFUART_IO_MODE BIT(0) -#define SIRFUART_DMA_MODE 0x0 -#define SIRFUART_RX_DMA_FLUSH 0x4 - -#define SIRFUART_CLEAR_RX_ADDR_EN 0x2 -/* Baud Rate Calculation */ -#define SIRF_USP_MIN_SAMPLE_DIV 0x1 -#define SIRF_MIN_SAMPLE_DIV 0xf -#define SIRF_MAX_SAMPLE_DIV 0x3f -#define SIRF_IOCLK_DIV_MAX 0xffff -#define SIRF_SAMPLE_DIV_SHIFT 16 -#define SIRF_IOCLK_DIV_MASK 0xffff -#define SIRF_SAMPLE_DIV_MASK 0x3f0000 -#define SIRF_BAUD_RATE_SUPPORT_NR 18 - -/* USP SPEC */ -#define SIRFSOC_USP_ENDIAN_CTRL_LSBF BIT(4) -#define SIRFSOC_USP_EN BIT(5) -#define SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET 0 -#define SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET 8 -#define SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK 0x3ff -#define SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET 21 -#define SIRFSOC_USP_TX_DATA_LEN_OFFSET 0 -#define SIRFSOC_USP_TX_SYNC_LEN_OFFSET 8 -#define SIRFSOC_USP_TX_FRAME_LEN_OFFSET 16 -#define SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET 24 -#define SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET 30 -#define SIRFSOC_USP_RX_DATA_LEN_OFFSET 0 -#define SIRFSOC_USP_RX_FRAME_LEN_OFFSET 8 -#define SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET 16 -#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24 -#define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f -#define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16 -#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2) -#define SIRFSOC_USP_FRADDR_CLR_EN BIT(1) -/* USP-UART Common */ -#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000) -#define SIRFUART_RECV_TIMEOUT_VALUE(x) \ - (((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF)) -#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF) -#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16) - -#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1) -#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \ - (uint_st->sirfsoc_rx_oflow | \ - uint_st->sirfsoc_frm_err | \ - uint_st->sirfsoc_rxd_brk | \ - ((uart_type != SIRF_REAL_UART) ? \ - 0 : uint_st->sirfsoc_parity_err)) -#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \ - (uint_en->sirfsoc_rx_done_en |\ - uint_en->sirfsoc_rxfifo_thd_en |\ - uint_en->sirfsoc_rxfifo_full_en |\ - uint_en->sirfsoc_frm_err_en |\ - uint_en->sirfsoc_rx_oflow_en |\ - uint_en->sirfsoc_rxd_brk_en |\ - ((uart_type != SIRF_REAL_UART) ? \ - 0 : uint_en->sirfsoc_parity_err_en)) -#define SIRFUART_RX_IO_INT_ST(uint_st) \ - (uint_st->sirfsoc_rxfifo_thd |\ - uint_st->sirfsoc_rxfifo_full|\ - uint_st->sirfsoc_rx_done |\ - uint_st->sirfsoc_rx_timeout) -#define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts) -#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \ - (uint_en->sirfsoc_frm_err_en |\ - uint_en->sirfsoc_rx_oflow_en |\ - uint_en->sirfsoc_rxd_brk_en |\ - ((uart_type != SIRF_REAL_UART) ? \ - 0 : uint_en->sirfsoc_parity_err_en)) -/* Generic Definitions */ -#define SIRFSOC_UART_NAME "ttySiRF" -#define SIRFSOC_UART_MAJOR 0 -#define SIRFSOC_UART_MINOR 0 -#define SIRFUART_PORT_NAME "sirfsoc-uart" -#define SIRFUART_MAP_SIZE 0x200 -#define SIRFSOC_UART_NR 11 -#define SIRFSOC_PORT_TYPE 0xa5 - -/* Uart Common Use Macro*/ -#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32) -#define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3) -/* Uart Fifo Level Chk */ -#define SIRFUART_TX_FIFO_SC_OFFSET 0 -#define SIRFUART_TX_FIFO_LC_OFFSET 10 -#define SIRFUART_TX_FIFO_HC_OFFSET 20 -#define SIRFUART_TX_FIFO_CHK_SC(line, value) ((((line) == 1) ? (value & 0x3) :\ - (value & 0x1f)) << SIRFUART_TX_FIFO_SC_OFFSET) -#define SIRFUART_TX_FIFO_CHK_LC(line, value) ((((line) == 1) ? (value & 0x3) :\ - (value & 0x1f)) << SIRFUART_TX_FIFO_LC_OFFSET) -#define SIRFUART_TX_FIFO_CHK_HC(line, value) ((((line) == 1) ? (value & 0x3) :\ - (value & 0x1f)) << SIRFUART_TX_FIFO_HC_OFFSET) - -#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC -#define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC -#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC -#define SIRFUART_RX_FIFO_MASK 0x7f -/* Indicate how many buffers used */ - -/* For Fast Baud Rate Calculation */ -struct sirfsoc_baudrate_to_regv { - unsigned int baud_rate; - unsigned int reg_val; -}; - -enum sirfsoc_tx_state { - TX_DMA_IDLE, - TX_DMA_RUNNING, - TX_DMA_PAUSE, -}; - -struct sirfsoc_rx_buffer { - struct circ_buf xmit; - dma_cookie_t cookie; - struct dma_async_tx_descriptor *desc; - dma_addr_t dma_addr; -}; - -struct sirfsoc_uart_port { - bool hw_flow_ctrl; - bool ms_enabled; - - struct uart_port port; - struct clk *clk; - /* for SiRFatlas7, there are SET/CLR for UART_INT_EN */ - bool is_atlas7; - struct sirfsoc_uart_register *uart_reg; - struct dma_chan *rx_dma_chan; - struct dma_chan *tx_dma_chan; - dma_addr_t tx_dma_addr; - struct dma_async_tx_descriptor *tx_dma_desc; - unsigned long transfer_size; - enum sirfsoc_tx_state tx_dma_state; - unsigned int cts_gpio; - unsigned int rts_gpio; - - struct sirfsoc_rx_buffer rx_dma_items; - struct hrtimer hrt; - bool is_hrt_enabled; - unsigned long rx_period_time; - unsigned long rx_last_pos; - unsigned long pio_fetch_cnt; -}; - -/* Register Access Control */ -#define portaddr(port, reg) ((port)->membase + (reg)) -#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) -#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) - -/* UART Port Mask */ -#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF) -#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF) -#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1) diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 9a7ae6384edf..092755f35683 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -53,10 +53,12 @@ #define SPRD_IEN_TX_EMPTY BIT(1) #define SPRD_IEN_BREAK_DETECT BIT(7) #define SPRD_IEN_TIMEOUT BIT(13) +#define SPRD_IEN_DATA_TIMEOUT BIT(17) /* interrupt clear register */ #define SPRD_ICLR 0x0014 #define SPRD_ICLR_TIMEOUT BIT(13) +#define SPRD_ICLR_DATA_TIMEOUT BIT(17) /* line control register */ #define SPRD_LCR 0x0018 @@ -102,6 +104,7 @@ #define SPRD_IMSR_TX_FIFO_EMPTY BIT(1) #define SPRD_IMSR_BREAK_DETECT BIT(7) #define SPRD_IMSR_TIMEOUT BIT(13) +#define SPRD_IMSR_DATA_TIMEOUT BIT(17) #define SPRD_DEFAULT_SOURCE_CLK 26000000 #define SPRD_RX_DMA_STEP 1 @@ -118,6 +121,12 @@ struct sprd_uart_dma { bool enable; }; +struct sprd_uart_data { + unsigned int timeout_ien; + unsigned int timeout_iclr; + unsigned int timeout_imsr; +}; + struct sprd_uart_port { struct uart_port port; char name[16]; @@ -126,6 +135,7 @@ struct sprd_uart_port { struct sprd_uart_dma rx_dma; dma_addr_t pos; unsigned char *rx_buf_tail; + const struct sprd_uart_data *pdata; }; static struct sprd_uart_port *sprd_port[UART_NR_MAX]; @@ -134,6 +144,18 @@ static int sprd_ports_num; static int sprd_start_dma_rx(struct uart_port *port); static int sprd_tx_dma_config(struct uart_port *port); +static const struct sprd_uart_data sc9836_data = { + .timeout_ien = SPRD_IEN_TIMEOUT, + .timeout_iclr = SPRD_ICLR_TIMEOUT, + .timeout_imsr = SPRD_IMSR_TIMEOUT, +}; + +static const struct sprd_uart_data sc9632_data = { + .timeout_ien = SPRD_IEN_DATA_TIMEOUT, + .timeout_iclr = SPRD_ICLR_DATA_TIMEOUT, + .timeout_imsr = SPRD_IMSR_DATA_TIMEOUT, +}; + static inline unsigned int serial_in(struct uart_port *port, unsigned int offset) { @@ -206,7 +228,6 @@ static void sprd_stop_tx_dma(struct uart_port *port) { struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; struct dma_tx_state state; u32 trans_len; @@ -215,8 +236,7 @@ static void sprd_stop_tx_dma(struct uart_port *port) dmaengine_tx_status(sp->tx_dma.chn, sp->tx_dma.cookie, &state); if (state.residue) { trans_len = state.residue - sp->tx_dma.phys_addr; - xmit->tail = (xmit->tail + trans_len) & (UART_XMIT_SIZE - 1); - port->icount.tx += trans_len; + uart_xmit_advance(port, trans_len); dma_unmap_single(port->dev, sp->tx_dma.phys_addr, sp->tx_dma.trans_len, DMA_TO_DEVICE); } @@ -229,13 +249,13 @@ static int sprd_tx_buf_remap(struct uart_port *port) { struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char *tail; - sp->tx_dma.trans_len = - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + sp->tx_dma.trans_len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); - sp->tx_dma.phys_addr = dma_map_single(port->dev, - (void *)&(xmit->buf[xmit->tail]), + sp->tx_dma.phys_addr = dma_map_single(port->dev, tail, sp->tx_dma.trans_len, DMA_TO_DEVICE); return dma_mapping_error(port->dev, sp->tx_dma.phys_addr); @@ -246,24 +266,23 @@ static void sprd_complete_tx_dma(void *data) struct uart_port *port = (struct uart_port *)data; struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); dma_unmap_single(port->dev, sp->tx_dma.phys_addr, sp->tx_dma.trans_len, DMA_TO_DEVICE); - xmit->tail = (xmit->tail + sp->tx_dma.trans_len) & (UART_XMIT_SIZE - 1); - port->icount.tx += sp->tx_dma.trans_len; + uart_xmit_advance(port, sp->tx_dma.trans_len); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit) || sprd_tx_buf_remap(port) || + if (kfifo_is_empty(&tport->xmit_fifo) || sprd_tx_buf_remap(port) || sprd_tx_dma_config(port)) sp->tx_dma.trans_len = 0; - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int sprd_uart_dma_submit(struct uart_port *port, @@ -322,7 +341,7 @@ static void sprd_start_tx_dma(struct uart_port *port) { struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; if (port->x_char) { serial_out(port, SPRD_TXD, port->x_char); @@ -331,7 +350,7 @@ static void sprd_start_tx_dma(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { sprd_stop_tx_dma(port); return; } @@ -367,7 +386,7 @@ static void sprd_rx_free_buf(struct sprd_uart_port *sp) if (sp->rx_dma.virt) dma_free_coherent(sp->port.dev, SPRD_UART_RX_SIZE, sp->rx_dma.virt, sp->rx_dma.phys_addr); - + sp->rx_dma.virt = NULL; } static int sprd_rx_dma_config(struct uart_port *port, u32 burst) @@ -432,13 +451,13 @@ static void sprd_complete_rx_dma(void *data) enum dma_status status; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); status = dmaengine_tx_status(sp->rx_dma.chn, sp->rx_dma.cookie, &state); if (status != DMA_COMPLETE) { sprd_stop_rx(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return; } @@ -452,7 +471,7 @@ static void sprd_complete_rx_dma(void *data) if (sprd_start_dma_rx(port)) sprd_stop_rx(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int sprd_start_dma_rx(struct uart_port *port) @@ -561,7 +580,7 @@ static void sprd_break_ctl(struct uart_port *port, int break_state) } static int handle_lsr_errors(struct uart_port *port, - unsigned int *flag, + u8 *flag, unsigned int *lsr) { int ret = 0; @@ -597,7 +616,8 @@ static inline void sprd_rx(struct uart_port *port) struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); struct tty_port *tty = &port->state->port; - unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT; + unsigned int lsr, max_count = SPRD_TIMEOUT; + u8 ch, flag; if (sp->rx_dma.enable) { sprd_uart_dma_irq(port); @@ -626,35 +646,12 @@ static inline void sprd_rx(struct uart_port *port) static inline void sprd_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - serial_out(port, SPRD_TXD, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - sprd_stop_tx(port); - return; - } + u8 ch; - count = THLD_TX_EMPTY; - do { - serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - sprd_stop_tx(port); + uart_port_tx_limited(port, ch, THLD_TX_EMPTY, + true, + serial_out(port, SPRD_TXD, ch), + ({})); } /* this handles the interrupt from one port */ @@ -662,30 +659,32 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; unsigned int ims; + struct sprd_uart_port *sp = + container_of(port, struct sprd_uart_port, port); - spin_lock(&port->lock); + uart_port_lock(port); ims = serial_in(port, SPRD_IMSR); if (!ims) { - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_NONE; } - if (ims & SPRD_IMSR_TIMEOUT) - serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT); + if (ims & sp->pdata->timeout_imsr) + serial_out(port, SPRD_ICLR, sp->pdata->timeout_iclr); if (ims & SPRD_IMSR_BREAK_DETECT) serial_out(port, SPRD_ICLR, SPRD_IMSR_BREAK_DETECT); if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT | - SPRD_IMSR_TIMEOUT)) + sp->pdata->timeout_imsr)) sprd_rx(port); if (ims & SPRD_IMSR_TX_FIFO_EMPTY) sprd_tx(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -752,13 +751,13 @@ static int sprd_startup(struct uart_port *port) serial_out(port, SPRD_CTL1, fc); /* enable interrupt */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ien = serial_in(port, SPRD_IEN); - ien |= SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT; + ien |= SPRD_IEN_BREAK_DETECT | sp->pdata->timeout_ien; if (!sp->rx_dma.enable) ien |= SPRD_IEN_RX_FULL; serial_out(port, SPRD_IEN, ien); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -771,9 +770,8 @@ static void sprd_shutdown(struct uart_port *port) devm_free_irq(port->dev, port->irq, port); } -static void sprd_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) +static void sprd_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old) { unsigned int baud, quot; unsigned int lcr = 0, fc; @@ -819,7 +817,7 @@ static void sprd_set_termios(struct uart_port *port, lcr |= SPRD_LCR_EVEN_PAR; } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); @@ -863,7 +861,7 @@ static void sprd_set_termios(struct uart_port *port, fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF; serial_out(port, SPRD_CTL1, fc); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) @@ -984,7 +982,7 @@ static void wait_for_xmitr(struct uart_port *port) } while (status & SPRD_TX_FIFO_CNT_MASK); } -static void sprd_console_putchar(struct uart_port *port, int ch) +static void sprd_console_putchar(struct uart_port *port, unsigned char ch) { wait_for_xmitr(port); serial_out(port, SPRD_TXD, ch); @@ -1000,9 +998,9 @@ static void sprd_console_write(struct console *co, const char *s, if (port->sysrq) locked = 0; else if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); uart_console_write(port, s, count, sprd_console_putchar); @@ -1010,7 +1008,7 @@ static void sprd_console_write(struct console *co, const char *s, wait_for_xmitr(port); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int sprd_console_setup(struct console *co, char *options) @@ -1058,7 +1056,7 @@ console_initcall(sprd_serial_console_init); #define SPRD_CONSOLE (&sprd_console) /* Support for earlycon */ -static void sprd_putc(struct uart_port *port, int c) +static void sprd_putc(struct uart_port *port, unsigned char c) { unsigned int timeout = SPRD_TIMEOUT; @@ -1102,7 +1100,7 @@ static struct uart_driver sprd_uart_driver = { .cons = SPRD_CONSOLE, }; -static int sprd_remove(struct platform_device *dev) +static void sprd_remove(struct platform_device *dev) { struct sprd_uart_port *sup = platform_get_drvdata(dev); @@ -1115,8 +1113,6 @@ static int sprd_remove(struct platform_device *dev) if (!sprd_ports_num) uart_unregister_driver(&sprd_uart_driver); - - return 0; } static bool sprd_uart_is_console(struct uart_port *uport) @@ -1133,10 +1129,13 @@ static bool sprd_uart_is_console(struct uart_port *uport) static int sprd_clk_init(struct uart_port *uport) { struct clk *clk_uart, *clk_parent; - struct sprd_uart_port *u = sprd_port[uport->line]; + struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port); clk_uart = devm_clk_get(uport->dev, "uart"); if (IS_ERR(clk_uart)) { + if (PTR_ERR(clk_uart) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_warn(uport->dev, "uart%d can't get uart clock\n", uport->line); clk_uart = NULL; @@ -1144,6 +1143,9 @@ static int sprd_clk_init(struct uart_port *uport) clk_parent = devm_clk_get(uport->dev, "source"); if (IS_ERR(clk_parent)) { + if (PTR_ERR(clk_parent) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_warn(uport->dev, "uart%d can't get source clock\n", uport->line); clk_parent = NULL; @@ -1176,22 +1178,22 @@ static int sprd_probe(struct platform_device *pdev) { struct resource *res; struct uart_port *up; + struct sprd_uart_port *sport; int irq; int index; int ret; index = of_alias_get_id(pdev->dev.of_node, "serial"); - if (index < 0 || index >= ARRAY_SIZE(sprd_port)) { + if (index < 0 || index >= UART_NR_MAX) { dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index); return -EINVAL; } - sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]), - GFP_KERNEL); - if (!sprd_port[index]) + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); + if (!sport) return -ENOMEM; - up = &sprd_port[index]->port; + up = &sport->port; up->dev = &pdev->dev; up->line = index; up->type = PORT_SPRD; @@ -1206,13 +1208,18 @@ static int sprd_probe(struct platform_device *pdev) if (ret) return ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - up->membase = devm_ioremap_resource(&pdev->dev, res); + up->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(up->membase)) return PTR_ERR(up->membase); up->mapbase = res->start; + sport->pdata = of_device_get_match_data(&pdev->dev); + if (!sport->pdata) { + dev_err(&pdev->dev, "get match data failed!\n"); + return -EINVAL; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -1222,7 +1229,7 @@ static int sprd_probe(struct platform_device *pdev) * Allocate one dma buffer to prepare for receive transfer, in case * memory allocation failure at runtime. */ - ret = sprd_rx_alloc_buf(sprd_port[index]); + ret = sprd_rx_alloc_buf(sport); if (ret) return ret; @@ -1230,17 +1237,27 @@ static int sprd_probe(struct platform_device *pdev) ret = uart_register_driver(&sprd_uart_driver); if (ret < 0) { pr_err("Failed to register SPRD-UART driver\n"); - return ret; + goto free_rx_buf; } } + sprd_ports_num++; + sprd_port[index] = sport; ret = uart_add_one_port(&sprd_uart_driver, up); if (ret) - sprd_remove(pdev); + goto clean_port; platform_set_drvdata(pdev, up); + return 0; + +clean_port: + sprd_port[index] = NULL; + if (--sprd_ports_num == 0) + uart_unregister_driver(&sprd_uart_driver); +free_rx_buf: + sprd_rx_free_buf(sport); return ret; } @@ -1267,7 +1284,8 @@ static int sprd_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume); static const struct of_device_id serial_ids[] = { - {.compatible = "sprd,sc9836-uart",}, + {.compatible = "sprd,sc9836-uart", .data = &sc9836_data}, + {.compatible = "sprd,sc9632-uart", .data = &sc9632_data}, {} }; MODULE_DEVICE_TABLE(of, serial_ids); @@ -1277,7 +1295,7 @@ static struct platform_driver sprd_platform_driver = { .remove = sprd_remove, .driver = { .name = "sprd_serial", - .of_match_table = of_match_ptr(serial_ids), + .of_match_table = serial_ids, .pm = &sprd_pm_ops, }, }; diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index e7048515a79c..6ed9a327702b 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -17,7 +17,6 @@ #include <linux/tty_flip.h> #include <linux/delay.h> #include <linux/spinlock.h> -#include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/serial_core.h> @@ -65,7 +64,7 @@ static struct uart_driver asc_uart_driver; /* ASC_RXBUF */ #define ASC_RXBUF_PE 0x100 #define ASC_RXBUF_FE 0x200 -/** +/* * Some of status comes from higher bits of the character and some come from * the status register. Combining both of them in to single status using dummy * bits. @@ -238,50 +237,12 @@ static inline unsigned asc_hw_txroom(struct uart_port *port) */ static void asc_transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - int txroom; - unsigned char c; - - txroom = asc_hw_txroom(port); - - if ((txroom != 0) && port->x_char) { - c = port->x_char; - port->x_char = 0; - asc_out(port, ASC_TXBUF, c); - port->icount.tx++; - txroom = asc_hw_txroom(port); - } - - if (uart_tx_stopped(port)) { - /* - * We should try and stop the hardware here, but I - * don't think the ASC has any way to do that. - */ - asc_disable_tx_interrupts(port); - return; - } - - if (uart_circ_empty(xmit)) { - asc_disable_tx_interrupts(port); - return; - } - - if (txroom == 0) - return; + u8 ch; - do { - c = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - asc_out(port, ASC_TXBUF, c); - port->icount.tx++; - txroom--; - } while ((txroom > 0) && (!uart_circ_empty(xmit))); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - asc_disable_tx_interrupts(port); + uart_port_tx_limited(port, ch, asc_hw_txroom(port), + true, + asc_out(port, ASC_TXBUF, ch), + ({})); } static void asc_receive_chars(struct uart_port *port) @@ -289,7 +250,7 @@ static void asc_receive_chars(struct uart_port *port) struct tty_port *tport = &port->state->port; unsigned long status, mode; unsigned long c = 0; - char flag; + u8 flag; bool ignore_pe = false; /* @@ -358,7 +319,7 @@ static irqreturn_t asc_interrupt(int irq, void *ptr) struct uart_port *port = ptr; u32 status; - spin_lock(&port->lock); + uart_port_lock(port); status = asc_in(port, ASC_STA); @@ -373,7 +334,7 @@ static irqreturn_t asc_interrupt(int irq, void *ptr) asc_transmit_chars(port); } - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } @@ -426,9 +387,9 @@ static unsigned int asc_get_mctrl(struct uart_port *port) /* There are probably characters waiting to be transmitted. */ static void asc_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) asc_enable_tx_interrupts(port); } @@ -478,7 +439,7 @@ static void asc_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct asc_port *ascport = to_asc_port(port); - unsigned long flags = 0; + unsigned long flags; u32 ctl; switch (state) { @@ -491,19 +452,20 @@ static void asc_pm(struct uart_port *port, unsigned int state, * we can come to turning it off. Note this is not called with * the port spinlock held. */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN; asc_out(port, ASC_CTL, ctl); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); clk_disable_unprepare(ascport->clk); break; } } static void asc_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct asc_port *ascport = to_asc_port(port); + bool manual_rts, toggle_rts = false; struct gpio_desc *gpiod; unsigned int baud; u32 ctrl_val; @@ -519,7 +481,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); cflag = termios->c_cflag; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* read control register */ ctrl_val = asc_in(port, ASC_CTL); @@ -535,10 +497,14 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, /* set character length */ if ((cflag & CSIZE) == CS7) { ctrl_val |= ASC_CTL_MODE_7BIT_PAR; + cflag |= PARENB; } else { ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR : ASC_CTL_MODE_8BIT; + cflag &= ~CSIZE; + cflag |= CS8; } + termios->c_cflag = cflag; /* set stop bit */ ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT; @@ -553,25 +519,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, /* If flow-control selected, stop handling RTS manually */ if (ascport->rts) { - devm_gpiod_put(port->dev, ascport->rts); - ascport->rts = NULL; - - pinctrl_select_state(ascport->pinctrl, - ascport->states[DEFAULT]); + toggle_rts = true; + manual_rts = false; } } else { /* If flow-control disabled, it's safe to handle RTS manually */ - if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) { - pinctrl_select_state(ascport->pinctrl, - ascport->states[NO_HW_FLOWCTRL]); - - gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW); - if (!IS_ERR(gpiod)) { - gpiod_set_consumer_name(gpiod, - port->dev->of_node->name); - ascport->rts = gpiod; - } - } + if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) + manual_rts = toggle_rts = true; } if ((baud < 19200) && !ascport->force_m1) { @@ -629,7 +583,26 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, /* write final value and enable port */ asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN)); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); + + if (toggle_rts) { + if (manual_rts) { + pinctrl_select_state(ascport->pinctrl, + ascport->states[NO_HW_FLOWCTRL]); + + gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW); + if (!IS_ERR(gpiod)) { + gpiod_set_consumer_name(gpiod, + port->dev->of_node->name); + ascport->rts = gpiod; + } + } else { + devm_gpiod_put(port->dev, ascport->rts); + ascport->rts = NULL; + pinctrl_select_state(ascport->pinctrl, + ascport->states[DEFAULT]); + } + } } static const char *asc_type(struct uart_port *port) @@ -726,8 +699,7 @@ static int asc_init_port(struct asc_port *ascport, port->irq = platform_get_irq(pdev, 0); port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_ST_ASC_CONSOLE); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - port->membase = devm_ioremap_resource(&pdev->dev, res); + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); port->mapbase = res->start; @@ -739,7 +711,9 @@ static int asc_init_port(struct asc_port *ascport, if (WARN_ON(IS_ERR(ascport->clk))) return -EINVAL; /* ensure that clk rate is correct by enabling the clk */ - clk_prepare_enable(ascport->clk); + ret = clk_prepare_enable(ascport->clk); + if (ret) + return ret; ascport->port.uartclk = clk_get_rate(ascport->clk); WARN_ON(ascport->port.uartclk == 0); clk_disable_unprepare(ascport->clk); @@ -789,7 +763,7 @@ static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev) asc_ports[id].hw_flow_control = of_property_read_bool(np, "uart-has-rtscts"); - asc_ports[id].force_m1 = of_property_read_bool(np, "st,force_m1"); + asc_ports[id].force_m1 = of_property_read_bool(np, "st,force-m1"); asc_ports[id].port.line = id; asc_ports[id].rts = NULL; @@ -827,14 +801,13 @@ static int asc_serial_probe(struct platform_device *pdev) return 0; } -static int asc_serial_remove(struct platform_device *pdev) +static void asc_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - return uart_remove_one_port(&asc_uart_driver, port); + uart_remove_one_port(&asc_uart_driver, port); } -#ifdef CONFIG_PM_SLEEP static int asc_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); @@ -849,12 +822,10 @@ static int asc_serial_resume(struct device *dev) return uart_resume_port(&asc_uart_driver, port); } -#endif /* CONFIG_PM_SLEEP */ - /*----------------------------------------------------------------------*/ #ifdef CONFIG_SERIAL_ST_ASC_CONSOLE -static void asc_console_putchar(struct uart_port *port, int ch) +static void asc_console_putchar(struct uart_port *port, unsigned char ch) { unsigned int timeout = 1000000; @@ -881,9 +852,9 @@ static void asc_console_write(struct console *co, const char *s, unsigned count) if (port->sysrq) locked = 0; /* asc_interrupt has already claimed the lock */ else if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* * Disable interrupts so we don't get the IRQ line bouncing @@ -901,7 +872,7 @@ static void asc_console_write(struct console *co, const char *s, unsigned count) asc_out(port, ASC_INTEN, intenable); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int asc_console_setup(struct console *co, char *options) @@ -958,16 +929,15 @@ static struct uart_driver asc_uart_driver = { .cons = ASC_SERIAL_CONSOLE, }; -static const struct dev_pm_ops asc_serial_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(asc_serial_pm_ops, asc_serial_suspend, + asc_serial_resume); static struct platform_driver asc_serial_driver = { .probe = asc_serial_probe, .remove = asc_serial_remove, .driver = { .name = DRIVER_NAME, - .pm = &asc_serial_pm_ops, + .pm = pm_sleep_ptr(&asc_serial_pm_ops), .of_match_table = of_match_ptr(asc_match), }, }; diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 8602ff357321..ad06b760cfca 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -3,11 +3,13 @@ * Copyright (C) Maxime Coquelin 2015 * Copyright (C) STMicroelectronics SA 2017 * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com> - * Gerald Baeza <gerald.baeza@st.com> + * Gerald Baeza <gerald.baeza@foss.st.com> + * Erwan Le Ray <erwan.leray@foss.st.com> * * Inspired by st-asc.c from STMicroelectronics (c) */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/console.h> #include <linux/delay.h> @@ -34,15 +36,88 @@ #include "serial_mctrl_gpio.h" #include "stm32-usart.h" -static void stm32_stop_tx(struct uart_port *port); -static void stm32_transmit_chars(struct uart_port *port); + +/* Register offsets */ +static struct stm32_usart_info __maybe_unused stm32f4_info = { + .ofs = { + .isr = 0x00, + .rdr = 0x04, + .tdr = 0x04, + .brr = 0x08, + .cr1 = 0x0c, + .cr2 = 0x10, + .cr3 = 0x14, + .gtpr = 0x18, + .rtor = UNDEF_REG, + .rqr = UNDEF_REG, + .icr = UNDEF_REG, + .presc = UNDEF_REG, + .hwcfgr1 = UNDEF_REG, + }, + .cfg = { + .uart_enable_bit = 13, + .has_7bits_data = false, + } +}; + +static struct stm32_usart_info __maybe_unused stm32f7_info = { + .ofs = { + .cr1 = 0x00, + .cr2 = 0x04, + .cr3 = 0x08, + .brr = 0x0c, + .gtpr = 0x10, + .rtor = 0x14, + .rqr = 0x18, + .isr = 0x1c, + .icr = 0x20, + .rdr = 0x24, + .tdr = 0x28, + .presc = UNDEF_REG, + .hwcfgr1 = UNDEF_REG, + }, + .cfg = { + .uart_enable_bit = 0, + .has_7bits_data = true, + .has_swap = true, + } +}; + +static struct stm32_usart_info __maybe_unused stm32h7_info = { + .ofs = { + .cr1 = 0x00, + .cr2 = 0x04, + .cr3 = 0x08, + .brr = 0x0c, + .gtpr = 0x10, + .rtor = 0x14, + .rqr = 0x18, + .isr = 0x1c, + .icr = 0x20, + .rdr = 0x24, + .tdr = 0x28, + .presc = 0x2c, + .hwcfgr1 = 0x3f0, + }, + .cfg = { + .uart_enable_bit = 0, + .has_7bits_data = true, + .has_swap = true, + .has_wakeup = true, + .has_fifo = true, + } +}; + +static void stm32_usart_stop_tx(struct uart_port *port); +static void stm32_usart_transmit_chars(struct uart_port *port); +static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch); static inline struct stm32_port *to_stm32_port(struct uart_port *port) { return container_of(port, struct stm32_port, port); } -static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) +static void stm32_usart_set_bits(struct uart_port *port, u32 reg, u32 bits) { u32 val; @@ -51,7 +126,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } -static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) +static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits) { u32 val; @@ -60,8 +135,55 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } -static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, - u32 delay_DDE, u32 baud) +static unsigned int stm32_usart_tx_empty(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) + return TIOCSER_TEMT; + + return 0; +} + +static void stm32_usart_rs485_rts_enable(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct serial_rs485 *rs485conf = &port->rs485; + + if (stm32_port->hw_flow_control || + !(rs485conf->flags & SER_RS485_ENABLED)) + return; + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl | TIOCM_RTS); + } else { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl & ~TIOCM_RTS); + } +} + +static void stm32_usart_rs485_rts_disable(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct serial_rs485 *rs485conf = &port->rs485; + + if (stm32_port->hw_flow_control || + !(rs485conf->flags & SER_RS485_ENABLED)) + return; + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl & ~TIOCM_RTS); + } else { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl | TIOCM_RTS); + } +} + +static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, + u32 delay_DDE, u32 baud) { u32 rs485_deat_dedt; u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); @@ -70,6 +192,8 @@ static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, *cr3 |= USART_CR3_DEM; over8 = *cr1 & USART_CR1_OVER8; + *cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + if (over8) rs485_deat_dedt = delay_ADE * baud * 8; else @@ -95,20 +219,16 @@ static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, *cr1 |= rs485_deat_dedt; } -static int stm32_config_rs485(struct uart_port *port, - struct serial_rs485 *rs485conf) +static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485conf) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_config *cfg = &stm32_port->info->cfg; u32 usartdiv, baud, cr1, cr3; bool over8; - stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - - port->rs485 = *rs485conf; - - rs485conf->flags |= SER_RS485_RX_DURING_TX; + stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); if (rs485conf->flags & SER_RS485_ENABLED) { cr1 = readl_relaxed(port->membase + ofs->cr1); @@ -122,33 +242,42 @@ static int stm32_config_rs485(struct uart_port *port, << USART_BRR_04_R_SHIFT; baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); - stm32_config_reg_rs485(&cr1, &cr3, - rs485conf->delay_rts_before_send, - rs485conf->delay_rts_after_send, baud); + stm32_usart_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, + baud); - if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) cr3 &= ~USART_CR3_DEP; - rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; - } else { + else cr3 |= USART_CR3_DEP; - rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; - } writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr1, port->membase + ofs->cr1); + + if (!port->rs485_rx_during_tx_gpio) + rs485conf->flags |= SER_RS485_RX_DURING_TX; + } else { - stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); - stm32_clr_bits(port, ofs->cr1, - USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + stm32_usart_clr_bits(port, ofs->cr3, + USART_CR3_DEM | USART_CR3_DEP); + stm32_usart_clr_bits(port, ofs->cr1, + USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); } - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + + /* Adjust RTS polarity in case it's driven in software */ + if (stm32_usart_tx_empty(port)) + stm32_usart_rs485_rts_disable(port); + else + stm32_usart_rs485_rts_enable(port); return 0; } -static int stm32_init_rs485(struct uart_port *port, - struct platform_device *pdev) +static int stm32_usart_init_rs485(struct uart_port *port, + struct platform_device *pdev) { struct serial_rs485 *rs485conf = &port->rs485; @@ -162,64 +291,102 @@ static int stm32_init_rs485(struct uart_port *port, return uart_get_rs485_mode(port); } -static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, - bool threaded) +static bool stm32_usart_rx_dma_started(struct stm32_port *stm32_port) +{ + return stm32_port->rx_ch ? stm32_port->rx_dma_busy : false; +} + +static void stm32_usart_rx_dma_terminate(struct stm32_port *stm32_port) +{ + dmaengine_terminate_async(stm32_port->rx_ch); + stm32_port->rx_dma_busy = false; +} + +static int stm32_usart_dma_pause_resume(struct stm32_port *stm32_port, + struct dma_chan *chan, + enum dma_status expected_status, + int dmaengine_pause_or_resume(struct dma_chan *), + bool stm32_usart_xx_dma_started(struct stm32_port *), + void stm32_usart_xx_dma_terminate(struct stm32_port *)) +{ + struct uart_port *port = &stm32_port->port; + enum dma_status dma_status; + int ret; + + if (!stm32_usart_xx_dma_started(stm32_port)) + return -EPERM; + + dma_status = dmaengine_tx_status(chan, chan->cookie, NULL); + if (dma_status != expected_status) + return -EAGAIN; + + ret = dmaengine_pause_or_resume(chan); + if (ret) { + dev_err(port->dev, "DMA failed with error code: %d\n", ret); + stm32_usart_xx_dma_terminate(stm32_port); + } + return ret; +} + +static int stm32_usart_rx_dma_pause(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->rx_ch, + DMA_IN_PROGRESS, dmaengine_pause, + stm32_usart_rx_dma_started, + stm32_usart_rx_dma_terminate); +} + +static int stm32_usart_rx_dma_resume(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->rx_ch, + DMA_PAUSED, dmaengine_resume, + stm32_usart_rx_dma_started, + stm32_usart_rx_dma_terminate); +} + +/* Return true when data is pending (in pio mode), and false when no data is pending. */ +static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - enum dma_status status; - struct dma_tx_state state; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; *sr = readl_relaxed(port->membase + ofs->isr); - - if (threaded && stm32_port->rx_ch) { - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); - if ((status == DMA_IN_PROGRESS) && - (*last_res != state.residue)) - return 1; - else - return 0; - } else if (*sr & USART_SR_RXNE) { - return 1; + /* Get pending characters in RDR or FIFO */ + if (*sr & USART_SR_RXNE) { + /* Get all pending characters from the RDR or the FIFO when using interrupts */ + if (!stm32_usart_rx_dma_started(stm32_port)) + return true; + + /* Handle only RX data errors when using DMA */ + if (*sr & USART_SR_ERR_MASK) + return true; } - return 0; + + return false; } -static unsigned long stm32_get_char(struct uart_port *port, u32 *sr, - int *last_res) +static u8 stm32_usart_get_char_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; - if (stm32_port->rx_ch) { - c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; - if ((*last_res) == 0) - *last_res = RX_BUF_L; - } else { - c = readl_relaxed(port->membase + ofs->rdr); - /* apply RDR data mask */ - c &= stm32_port->rdr_mask; - } + c = readl_relaxed(port->membase + ofs->rdr); + /* Apply RDR data mask */ + c &= stm32_port->rdr_mask; return c; } -static void stm32_receive_chars(struct uart_port *port, bool threaded) +static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - unsigned long c; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned int size = 0; u32 sr; - char flag; - - if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) - pm_wakeup_event(tport->tty->dev, 0); + u8 c, flag; - while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { + while (stm32_usart_pending_rx_pio(port, &sr)) { sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; @@ -238,8 +405,9 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) writel_relaxed(sr & USART_SR_ERR_MASK, port->membase + ofs->icr); - c = stm32_get_char(port, &sr, &stm32_port->last_res); + c = stm32_usart_get_char_pio(port); port->icount.rx++; + size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { port->icount.overrun++; @@ -268,252 +436,497 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) } } - if (uart_handle_sysrq_char(port, c)) + if (uart_prepare_sysrq_char(port, c)) continue; uart_insert_char(port, sr, USART_SR_ORE, c, flag); } - spin_unlock(&port->lock); - tty_flip_buffer_push(tport); - spin_lock(&port->lock); + return size; +} + +static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_port *ttyport = &stm32_port->port.state->port; + unsigned char *dma_start; + int dma_count, i; + + dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); + + /* + * Apply rdr_mask on buffer in order to mask parity bit. + * This loop is useless in cs8 mode because DMA copies only + * 8 bits and already ignores parity bit. + */ + if (!(stm32_port->rdr_mask == (BIT(8) - 1))) + for (i = 0; i < dma_size; i++) + *(dma_start + i) &= stm32_port->rdr_mask; + + dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); + port->icount.rx += dma_count; + if (dma_count != dma_size) + port->icount.buf_overrun++; + stm32_port->last_res -= dma_count; + if (stm32_port->last_res == 0) + stm32_port->last_res = RX_BUF_L; +} + +static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int dma_size, size = 0; + + /* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */ + if (stm32_port->rx_dma_state.residue > stm32_port->last_res) { + /* Conditional first part: from last_res to end of DMA buffer */ + dma_size = stm32_port->last_res; + stm32_usart_push_buffer_dma(port, dma_size); + size = dma_size; + } + + dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; + stm32_usart_push_buffer_dma(port, dma_size); + size += dma_size; + + return size; +} + +static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force_dma_flush) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + enum dma_status rx_dma_status; + u32 sr; + unsigned int size = 0; + + if (stm32_usart_rx_dma_started(stm32_port) || force_dma_flush) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &stm32_port->rx_dma_state); + if (rx_dma_status == DMA_IN_PROGRESS || + rx_dma_status == DMA_PAUSED) { + /* Empty DMA buffer */ + size = stm32_usart_receive_chars_dma(port); + sr = readl_relaxed(port->membase + ofs->isr); + if (sr & USART_SR_ERR_MASK) { + /* Disable DMA request line */ + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + + /* Switch to PIO mode to handle the errors */ + size += stm32_usart_receive_chars_pio(port); + + /* Switch back to DMA mode */ + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + } + } else { + /* Disable RX DMA */ + stm32_usart_rx_dma_terminate(stm32_port); + /* Fall back to interrupt mode */ + dev_dbg(port->dev, "DMA error, fallback to irq mode\n"); + size = stm32_usart_receive_chars_pio(port); + } + } else { + size = stm32_usart_receive_chars_pio(port); + } + + return size; +} + +static void stm32_usart_rx_dma_complete(void *arg) +{ + struct uart_port *port = arg; + struct tty_port *tport = &port->state->port; + unsigned int size; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); +} + +static int stm32_usart_rx_dma_start_or_resume(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct dma_async_tx_descriptor *desc; + enum dma_status rx_dma_status; + int ret; + + if (stm32_port->throttled) + return 0; + + if (stm32_port->rx_dma_busy) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + NULL); + if (rx_dma_status == DMA_IN_PROGRESS) + return 0; + + if (rx_dma_status == DMA_PAUSED && !stm32_usart_rx_dma_resume(stm32_port)) + return 0; + + dev_err(port->dev, "DMA failed : status error.\n"); + stm32_usart_rx_dma_terminate(stm32_port); + } + + stm32_port->rx_dma_busy = true; + + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + stm32_port->rx_dma_busy = false; + return -ENODEV; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + stm32_port->rx_dma_busy = false; + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + + return 0; +} + +static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port) +{ + dmaengine_terminate_async(stm32_port->tx_ch); + stm32_port->tx_dma_busy = false; +} + +static bool stm32_usart_tx_dma_started(struct stm32_port *stm32_port) +{ + /* + * We cannot use the function "dmaengine_tx_status" to know the + * status of DMA. This function does not show if the "dma complete" + * callback of the DMA transaction has been called. So we prefer + * to use "tx_dma_busy" flag to prevent dual DMA transaction at the + * same time. + */ + return stm32_port->tx_dma_busy; } -static void stm32_tx_dma_complete(void *arg) +static int stm32_usart_tx_dma_pause(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->tx_ch, + DMA_IN_PROGRESS, dmaengine_pause, + stm32_usart_tx_dma_started, + stm32_usart_tx_dma_terminate); +} + +static int stm32_usart_tx_dma_resume(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->tx_ch, + DMA_PAUSED, dmaengine_resume, + stm32_usart_tx_dma_started, + stm32_usart_tx_dma_terminate); +} + +static void stm32_usart_tx_dma_complete(void *arg) { struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + unsigned long flags; - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32port->tx_dma_busy = false; + stm32_usart_tx_dma_terminate(stm32port); /* Let's see if we have pending data to send */ - stm32_transmit_chars(port); + uart_port_lock_irqsave(port, &flags); + stm32_usart_transmit_chars(port); + uart_port_unlock_irqrestore(port, flags); } -static void stm32_tx_interrupt_enable(struct uart_port *port) +static void stm32_usart_tx_interrupt_enable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; /* * Enables TX FIFO threashold irq when FIFO is enabled, * or TX empty irq when FIFO is disabled */ - if (stm32_port->fifoen) - stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); + if (stm32_port->fifoen && stm32_port->txftcfg >= 0) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); else - stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); } -static void stm32_tx_interrupt_disable(struct uart_port *port) +static void stm32_usart_tc_interrupt_enable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - if (stm32_port->fifoen) - stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TCIE); +} + +static void stm32_usart_tx_interrupt_disable(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (stm32_port->fifoen && stm32_port->txftcfg >= 0) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); else - stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); } -static void stm32_transmit_chars_pio(struct uart_port *port) +static void stm32_usart_tc_interrupt_disable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct circ_buf *xmit = &port->state->xmit; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - if (stm32_port->tx_dma_busy) { - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; - } + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TCIE); +} + +static void stm32_usart_transmit_chars_pio(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + + while (1) { + unsigned char ch; - while (!uart_circ_empty(xmit)) { /* Check that TDR is empty before filling FIFO */ if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) break; - writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + + if (!uart_fifo_get(port, &ch)) + break; + + writel_relaxed(ch, port->membase + ofs->tdr); } /* rely on TXE irq (mask or unmask) for sending remaining data */ - if (uart_circ_empty(xmit)) - stm32_tx_interrupt_disable(port); + if (kfifo_is_empty(&tport->xmit_fifo)) + stm32_usart_tx_interrupt_disable(port); else - stm32_tx_interrupt_enable(port); + stm32_usart_tx_interrupt_enable(port); } -static void stm32_transmit_chars_dma(struct uart_port *port) +static void stm32_usart_transmit_chars_dma(struct uart_port *port) { struct stm32_port *stm32port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_async_tx_descriptor *desc = NULL; - dma_cookie_t cookie; - unsigned int count, i; + unsigned int count; + int ret; - if (stm32port->tx_dma_busy) + if (stm32_usart_tx_dma_started(stm32port)) { + ret = stm32_usart_tx_dma_resume(stm32port); + if (ret < 0 && ret != -EAGAIN) + goto fallback_err; return; - - stm32port->tx_dma_busy = true; - - count = uart_circ_chars_pending(xmit); - - if (count > TX_BUF_L) - count = TX_BUF_L; - - if (xmit->tail < xmit->head) { - memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count); - } else { - size_t one = UART_XMIT_SIZE - xmit->tail; - size_t two; - - if (one > count) - one = count; - two = count - one; - - memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one); - if (two) - memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two); } + count = kfifo_out_peek(&tport->xmit_fifo, &stm32port->tx_buf[0], + TX_BUF_L); + desc = dmaengine_prep_slave_single(stm32port->tx_ch, stm32port->tx_dma_buf, count, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); - if (!desc) { - for (i = count; i > 0; i--) - stm32_transmit_chars_pio(port); - return; - } + if (!desc) + goto fallback_err; + + /* + * Set "tx_dma_busy" flag. This flag will be released when + * dmaengine_terminate_async will be called. This flag helps + * transmit_chars_dma not to start another DMA transaction + * if the callback of the previous is not yet called. + */ + stm32port->tx_dma_busy = true; - desc->callback = stm32_tx_dma_complete; + desc->callback = stm32_usart_tx_dma_complete; desc->callback_param = port; /* Push current DMA TX transaction in the pending queue */ - cookie = dmaengine_submit(desc); + /* DMA no yet started, safe to free resources */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dev_err(port->dev, "DMA failed with error code: %d\n", ret); + stm32_usart_tx_dma_terminate(stm32port); + goto fallback_err; + } /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); - stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); + uart_xmit_advance(port, count); + + return; - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - port->icount.tx += count; +fallback_err: + stm32_usart_transmit_chars_pio(port); } -static void stm32_transmit_chars(struct uart_port *port) +static void stm32_usart_transmit_chars(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct circ_buf *xmit = &port->state->xmit; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + u32 isr; + int ret; + + if (!stm32_port->hw_flow_control && + port->rs485.flags & SER_RS485_ENABLED && + (port->x_char || + !(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)))) { + stm32_usart_tc_interrupt_disable(port); + stm32_usart_rs485_rts_enable(port); + } if (port->x_char) { - if (stm32_port->tx_dma_busy) - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + /* dma terminate may have been called in case of dma pause failure */ + stm32_usart_tx_dma_pause(stm32_port); + + /* Check that TDR is empty before filling FIFO */ + ret = + readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TXE), + 10, 1000); + if (ret) + dev_warn(port->dev, "1 character may be erased\n"); + writel_relaxed(port->x_char, port->membase + ofs->tdr); port->x_char = 0; port->icount.tx++; - if (stm32_port->tx_dma_busy) - stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); + + /* dma terminate may have been called in case of dma resume failure */ + stm32_usart_tx_dma_resume(stm32_port); return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - stm32_tx_interrupt_disable(port); + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { + stm32_usart_tx_interrupt_disable(port); return; } if (ofs->icr == UNDEF_REG) - stm32_clr_bits(port, ofs->isr, USART_SR_TC); + stm32_usart_clr_bits(port, ofs->isr, USART_SR_TC); else writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); if (stm32_port->tx_ch) - stm32_transmit_chars_dma(port); + stm32_usart_transmit_chars_dma(port); else - stm32_transmit_chars_pio(port); + stm32_usart_transmit_chars_pio(port); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - stm32_tx_interrupt_disable(port); + if (kfifo_is_empty(&tport->xmit_fifo)) { + stm32_usart_tx_interrupt_disable(port); + if (!stm32_port->hw_flow_control && + port->rs485.flags & SER_RS485_ENABLED) { + stm32_usart_tc_interrupt_enable(port); + } + } } -static irqreturn_t stm32_interrupt(int irq, void *ptr) +static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; - - spin_lock(&port->lock); + unsigned int size; + irqreturn_t ret = IRQ_NONE; sr = readl_relaxed(port->membase + ofs->isr); - if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG) + if (!stm32_port->hw_flow_control && + port->rs485.flags & SER_RS485_ENABLED && + (sr & USART_SR_TC)) { + stm32_usart_tc_interrupt_disable(port); + stm32_usart_rs485_rts_disable(port); + ret = IRQ_HANDLED; + } + + if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG) { writel_relaxed(USART_ICR_RTOCF, port->membase + ofs->icr); + ret = IRQ_HANDLED; + } - if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG)) + if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) { + /* Clear wake up flag and disable wake up interrupt */ writel_relaxed(USART_ICR_WUCF, port->membase + ofs->icr); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); + if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) + pm_wakeup_event(tport->tty->dev, 0); + ret = IRQ_HANDLED; + } - if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) - stm32_receive_chars(port, false); - - if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) - stm32_transmit_chars(port); - - spin_unlock(&port->lock); - - if (stm32_port->rx_ch) - return IRQ_WAKE_THREAD; - else - return IRQ_HANDLED; -} - -static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) -{ - struct uart_port *port = ptr; - struct stm32_port *stm32_port = to_stm32_port(port); - - spin_lock(&port->lock); - - if (stm32_port->rx_ch) - stm32_receive_chars(port, true); - - spin_unlock(&port->lock); + /* + * rx errors in dma mode has to be handled ASAP to avoid overrun as the DMA request + * line has been masked by HW and rx data are stacking in FIFO. + */ + if (!stm32_port->throttled) { + if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_started(stm32_port)) || + ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_started(stm32_port))) { + uart_port_lock(port); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) + tty_flip_buffer_push(tport); + ret = IRQ_HANDLED; + } + } - return IRQ_HANDLED; -} + if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { + uart_port_lock(port); + stm32_usart_transmit_chars(port); + uart_port_unlock(port); + ret = IRQ_HANDLED; + } -static unsigned int stm32_tx_empty(struct uart_port *port) -{ - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + /* Receiver timeout irq for DMA RX */ + if (stm32_usart_rx_dma_started(stm32_port) && !stm32_port->throttled) { + uart_port_lock(port); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) + tty_flip_buffer_push(tport); + ret = IRQ_HANDLED; + } - return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; + return ret; } -static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) - stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE); + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_RTSE); else - stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_RTSE); mctrl_gpio_set(stm32_port->gpios, mctrl); } -static unsigned int stm32_get_mctrl(struct uart_port *port) +static unsigned int stm32_usart_get_mctrl(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); unsigned int ret; @@ -524,126 +937,184 @@ static unsigned int stm32_get_mctrl(struct uart_port *port) return mctrl_gpio_get(stm32_port->gpios, &ret); } -static void stm32_enable_ms(struct uart_port *port) +static void stm32_usart_enable_ms(struct uart_port *port) { mctrl_gpio_enable_ms(to_stm32_port(port)->gpios); } -static void stm32_disable_ms(struct uart_port *port) +static void stm32_usart_disable_ms(struct uart_port *port) { - mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); + mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios); } /* Transmit stop */ -static void stm32_stop_tx(struct uart_port *port) +static void stm32_usart_stop_tx(struct uart_port *port) { - stm32_tx_interrupt_disable(port); + struct stm32_port *stm32_port = to_stm32_port(port); + + stm32_usart_tx_interrupt_disable(port); + + /* dma terminate may have been called in case of dma pause failure */ + stm32_usart_tx_dma_pause(stm32_port); + + stm32_usart_rs485_rts_disable(port); } /* There are probably characters waiting to be transmitted. */ -static void stm32_start_tx(struct uart_port *port) +static void stm32_usart_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char) return; - stm32_transmit_chars(port); + stm32_usart_rs485_rts_enable(port); + + stm32_usart_transmit_chars(port); +} + +/* Flush the transmit buffer. */ +static void stm32_usart_flush_buffer(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + + if (stm32_port->tx_ch) + stm32_usart_tx_dma_terminate(stm32_port); } /* Throttle the remote when input buffer is about to overflow. */ -static void stm32_throttle(struct uart_port *port) +static void stm32_usart_throttle(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + uart_port_lock_irqsave(port, &flags); + + /* + * Pause DMA transfer, so the RX data gets queued into the FIFO. + * Hardware flow control is triggered when RX FIFO is full. + */ + stm32_usart_rx_dma_pause(stm32_port); + + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) - stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); - spin_unlock_irqrestore(&port->lock, flags); + stm32_port->throttled = true; + uart_port_unlock_irqrestore(port, flags); } /* Unthrottle the remote, the input buffer can now accept data. */ -static void stm32_unthrottle(struct uart_port *port) +static void stm32_usart_unthrottle(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq); + uart_port_lock_irqsave(port, &flags); + stm32_usart_set_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) - stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + + stm32_port->throttled = false; + + /* + * Switch back to DMA mode (resume DMA). + * Hardware flow control is stopped when FIFO is not full any more. + */ + if (stm32_port->rx_ch) + stm32_usart_rx_dma_start_or_resume(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* Receive stop */ -static void stm32_stop_rx(struct uart_port *port) +static void stm32_usart_stop_rx(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); - if (stm32_port->cr3_irq) - stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + /* Disable DMA request line. */ + stm32_usart_rx_dma_pause(stm32_port); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + if (stm32_port->cr3_irq) + stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); } -/* Handle breaks - ignored by us */ -static void stm32_break_ctl(struct uart_port *port, int break_state) +static void stm32_usart_break_ctl(struct uart_port *port, int break_state) { + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + + if (break_state) + stm32_usart_set_bits(port, ofs->rqr, USART_RQR_SBKRQ); + else + stm32_usart_clr_bits(port, ofs->rqr, USART_RQR_SBKRQ); + + uart_port_unlock_irqrestore(port, flags); } -static int stm32_startup(struct uart_port *port) +static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; - ret = request_threaded_irq(port->irq, stm32_interrupt, - stm32_threaded_interrupt, - IRQF_NO_SUSPEND, name, port); + ret = request_irq(port->irq, stm32_usart_interrupt, + IRQF_NO_SUSPEND, name, port); if (ret) return ret; + if (stm32_port->swap) { + val = readl_relaxed(port->membase + ofs->cr2); + val |= USART_CR2_SWAP; + writel_relaxed(val, port->membase + ofs->cr2); + } + stm32_port->throttled = false; + /* RX FIFO Flush */ if (ofs->rqr != UNDEF_REG) - stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); + writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); - /* Tx and RX FIFO configuration */ - if (stm32_port->fifoen) { - val = readl_relaxed(port->membase + ofs->cr3); - val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK); - val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; - val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; - writel_relaxed(val, port->membase + ofs->cr3); + if (stm32_port->rx_ch) { + ret = stm32_usart_rx_dma_start_or_resume(port); + if (ret) { + free_irq(port->irq, port); + return ret; + } } - /* RX FIFO enabling */ - val = stm32_port->cr1_irq | USART_CR1_RE; - if (stm32_port->fifoen) - val |= USART_CR1_FIFOEN; - stm32_set_bits(port, ofs->cr1, val); + /* RX enabling */ + val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); + stm32_usart_set_bits(port, ofs->cr1, val); return 0; } -static void stm32_shutdown(struct uart_port *port) +static void stm32_usart_shutdown(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_config *cfg = &stm32_port->info->cfg; u32 val, isr; int ret; + if (stm32_usart_tx_dma_started(stm32_port)) + stm32_usart_tx_dma_terminate(stm32_port); + + if (stm32_port->tx_ch) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + /* Disable modem control interrupts */ - stm32_disable_ms(port); + stm32_usart_disable_ms(port); val = USART_CR1_TXEIE | USART_CR1_TE; val |= stm32_port->cr1_irq | USART_CR1_RE; @@ -655,84 +1126,88 @@ static void stm32_shutdown(struct uart_port *port) isr, (isr & USART_SR_TC), 10, 100000); + /* Send the TC error message only when ISR_TC is not set */ if (ret) - dev_err(port->dev, "transmission complete not set\n"); - - stm32_clr_bits(port, ofs->cr1, val); - - free_irq(port->irq, port); -} + dev_err(port->dev, "Transmission is not complete\n"); -static unsigned int stm32_get_databits(struct ktermios *termios) -{ - unsigned int bits; + /* Disable RX DMA. */ + if (stm32_port->rx_ch) { + stm32_usart_rx_dma_terminate(stm32_port); + dmaengine_synchronize(stm32_port->rx_ch); + } - tcflag_t cflag = termios->c_cflag; + /* flush RX & TX FIFO */ + if (ofs->rqr != UNDEF_REG) + writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, + port->membase + ofs->rqr); - switch (cflag & CSIZE) { - /* - * CSIZE settings are not necessarily supported in hardware. - * CSIZE unsupported configurations are handled here to set word length - * to 8 bits word as default configuration and to print debug message. - */ - case CS5: - bits = 5; - break; - case CS6: - bits = 6; - break; - case CS7: - bits = 7; - break; - /* default including CS8 */ - default: - bits = 8; - break; - } + stm32_usart_clr_bits(port, ofs->cr1, val); - return bits; + free_irq(port->irq, port); } -static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static const unsigned int stm32_usart_presc_val[] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256}; + +static void stm32_usart_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_config *cfg = &stm32_port->info->cfg; struct serial_rs485 *rs485conf = &port->rs485; - unsigned int baud, bits; + unsigned int baud, bits, uart_clk, uart_clk_pres; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; - u32 cr1, cr2, cr3; + u32 cr1, cr2, cr3, isr, brr, presc; unsigned long flags; + int ret; if (!stm32_port->hw_flow_control) cflag &= ~CRTSCTS; - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); + uart_clk = clk_get_rate(stm32_port->clk); + + baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8); + + uart_port_lock_irqsave(port, &flags); - spin_lock_irqsave(&port->lock, flags); + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TC), + 10, 100000); + + /* Send the TC error message only when ISR_TC is not set. */ + if (ret) + dev_err(port->dev, "Transmission is not complete\n"); /* Stop serial port and reset value */ writel_relaxed(0, port->membase + ofs->cr1); /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) - stm32_set_bits(port, ofs->rqr, - USART_RQR_TXFRQ | USART_RQR_RXFRQ); + writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, + port->membase + ofs->rqr); cr1 = USART_CR1_TE | USART_CR1_RE; if (stm32_port->fifoen) cr1 |= USART_CR1_FIFOEN; - cr2 = 0; + cr2 = stm32_port->swap ? USART_CR2_SWAP : 0; + + /* Tx and RX FIFO configuration */ cr3 = readl_relaxed(port->membase + ofs->cr3); - cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE - | USART_CR3_TXFTCFG_MASK; + cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; + if (stm32_port->fifoen) { + if (stm32_port->txftcfg >= 0) + cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT; + if (stm32_port->rxftcfg >= 0) + cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT; + } if (cflag & CSTOPB) cr2 |= USART_CR2_STOP_2B; - bits = stm32_get_databits(termios); + bits = tty_get_char_size(cflag); stm32_port->rdr_mask = (BIT(bits) - 1); if (cflag & PARENB) { @@ -747,16 +1222,26 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, * CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00 * M0 and M1 already cleared by cr1 initialization. */ - if (bits == 9) + if (bits == 9) { cr1 |= USART_CR1_M0; - else if ((bits == 7) && cfg->has_7bits_data) + } else if ((bits == 7) && cfg->has_7bits_data) { cr1 |= USART_CR1_M1; - else if (bits != 8) + } else if (bits != 8) { dev_dbg(port->dev, "Unsupported data bits config: %u bits\n" , bits); + cflag &= ~CSIZE; + cflag |= CS8; + termios->c_cflag = cflag; + bits = 8; + if (cflag & PARENB) { + bits++; + cr1 |= USART_CR1_M0; + } + } if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || - stm32_port->fifoen)) { + (stm32_port->fifoen && + stm32_port->rxftcfg >= 0))) { if (cflag & CSTOPB) bits = bits + 3; /* 1 start bit + 2 stop bits */ else @@ -766,9 +1251,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, stm32_port->cr1_irq = USART_CR1_RTOIE; writel_relaxed(bits, port->membase + ofs->rtor); cr2 |= USART_CR2_RTOEN; - /* Not using dma, enable fifo threshold irq */ - if (!stm32_port->rx_ch) - stm32_port->cr3_irq = USART_CR3_RXFTIE; + /* + * Enable fifo threshold irq in two cases, either when there is no DMA, or when + * wake up over usart, from low power until the DMA gets re-enabled by resume. + */ + stm32_port->cr3_irq = USART_CR3_RXFTIE; } cr1 |= stm32_port->cr1_irq; @@ -783,33 +1270,48 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } - /* Handle modem control interrupts */ - if (UART_ENABLE_MS(port, termios->c_cflag)) - stm32_enable_ms(port); - else - stm32_disable_ms(port); + for (presc = 0; presc <= USART_PRESC_MAX; presc++) { + uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]); + usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud); - usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + /* + * The USART supports 16 or 8 times oversampling. + * By default we prefer 16 times oversampling, so that the receiver + * has a better tolerance to clock deviations. + * 8 times oversampling is only used to achieve higher speeds. + */ + if (usartdiv < 16) { + oversampling = 8; + cr1 |= USART_CR1_OVER8; + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); + } else { + oversampling = 16; + cr1 &= ~USART_CR1_OVER8; + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + } - /* - * The USART supports 16 or 8 times oversampling. - * By default we prefer 16 times oversampling, so that the receiver - * has a better tolerance to clock deviations. - * 8 times oversampling is only used to achieve higher speeds. - */ - if (usartdiv < 16) { - oversampling = 8; - cr1 |= USART_CR1_OVER8; - stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); - } else { - oversampling = 16; - cr1 &= ~USART_CR1_OVER8; - stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; + fraction = usartdiv % oversampling; + brr = mantissa | fraction; + + if (FIELD_FIT(USART_BRR_MASK, brr)) { + if (ofs->presc != UNDEF_REG) { + port->uartclk = uart_clk_pres; + writel_relaxed(presc, port->membase + ofs->presc); + } else if (presc) { + /* We need a prescaler but we don't have it (STM32F4, STM32F7) */ + dev_err(port->dev, + "unable to set baudrate, input clock is too high"); + } + break; + } else if (presc == USART_PRESC_MAX) { + /* Even with prescaler and brr at max value we can't set baudrate */ + dev_err(port->dev, "unable to set baudrate, input clock is too high"); + break; + } } - mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; - fraction = usartdiv % oversampling; - writel_relaxed(mantissa | fraction, port->membase + ofs->brr); + writel_relaxed(brr, port->membase + ofs->brr); uart_update_timeout(port, cflag, baud); @@ -837,13 +1339,25 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= USART_SR_DUMMY_RX; - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + /* + * Setup DMA to collect only valid data and enable error irqs. + * This also enables break reception when using DMA. + */ + cr1 |= USART_CR1_PEIE; + cr3 |= USART_CR3_EIE; cr3 |= USART_CR3_DMAR; + cr3 |= USART_CR3_DDRE; + } + + if (stm32_port->tx_ch) + cr3 |= USART_CR3_DMAT; if (rs485conf->flags & SER_RS485_ENABLED) { - stm32_config_reg_rs485(&cr1, &cr3, - rs485conf->delay_rts_before_send, - rs485conf->delay_rts_after_send, baud); + stm32_usart_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, + baud); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; @@ -857,120 +1371,226 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); } + /* Configure wake up from low power on start bit detection */ + if (stm32_port->wakeup_src) { + cr3 &= ~USART_CR3_WUS_MASK; + cr3 |= USART_CR3_WUS_START_BIT; + } + writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr2, port->membase + ofs->cr2); writel_relaxed(cr1, port->membase + ofs->cr1); - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - spin_unlock_irqrestore(&port->lock, flags); + stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + uart_port_unlock_irqrestore(port, flags); + + /* Handle modem control interrupts */ + if (UART_ENABLE_MS(port, termios->c_cflag)) + stm32_usart_enable_ms(port); + else + stm32_usart_disable_ms(port); } -static const char *stm32_type(struct uart_port *port) +static const char *stm32_usart_type(struct uart_port *port) { return (port->type == PORT_STM32) ? DRIVER_NAME : NULL; } -static void stm32_release_port(struct uart_port *port) +static void stm32_usart_release_port(struct uart_port *port) { } -static int stm32_request_port(struct uart_port *port) +static int stm32_usart_request_port(struct uart_port *port) { return 0; } -static void stm32_config_port(struct uart_port *port, int flags) +static void stm32_usart_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) port->type = PORT_STM32; } static int -stm32_verify_port(struct uart_port *port, struct serial_struct *ser) +stm32_usart_verify_port(struct uart_port *port, struct serial_struct *ser) { /* No user changeable parameters */ return -EINVAL; } -static void stm32_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) +static void stm32_usart_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { struct stm32_port *stm32port = container_of(port, struct stm32_port, port); - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; - struct stm32_usart_config *cfg = &stm32port->info->cfg; - unsigned long flags = 0; + const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + const struct stm32_usart_config *cfg = &stm32port->info->cfg; + unsigned long flags; switch (state) { case UART_PM_STATE_ON: pm_runtime_get_sync(port->dev); break; case UART_PM_STATE_OFF: - spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); + stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + uart_port_unlock_irqrestore(port, flags); pm_runtime_put_sync(port->dev); break; } } +#if defined(CONFIG_CONSOLE_POLL) + + /* Callbacks for characters polling in debug context (i.e. KGDB). */ +static int stm32_usart_poll_init(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + + return clk_prepare_enable(stm32_port->clk); +} + +static int stm32_usart_poll_get_char(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_RXNE)) + return NO_POLL_CHAR; + + return readl_relaxed(port->membase + ofs->rdr) & stm32_port->rdr_mask; +} + +static void stm32_usart_poll_put_char(struct uart_port *port, unsigned char ch) +{ + stm32_usart_console_putchar(port, ch); +} +#endif /* CONFIG_CONSOLE_POLL */ + static const struct uart_ops stm32_uart_ops = { - .tx_empty = stm32_tx_empty, - .set_mctrl = stm32_set_mctrl, - .get_mctrl = stm32_get_mctrl, - .stop_tx = stm32_stop_tx, - .start_tx = stm32_start_tx, - .throttle = stm32_throttle, - .unthrottle = stm32_unthrottle, - .stop_rx = stm32_stop_rx, - .enable_ms = stm32_enable_ms, - .break_ctl = stm32_break_ctl, - .startup = stm32_startup, - .shutdown = stm32_shutdown, - .set_termios = stm32_set_termios, - .pm = stm32_pm, - .type = stm32_type, - .release_port = stm32_release_port, - .request_port = stm32_request_port, - .config_port = stm32_config_port, - .verify_port = stm32_verify_port, + .tx_empty = stm32_usart_tx_empty, + .set_mctrl = stm32_usart_set_mctrl, + .get_mctrl = stm32_usart_get_mctrl, + .stop_tx = stm32_usart_stop_tx, + .start_tx = stm32_usart_start_tx, + .throttle = stm32_usart_throttle, + .unthrottle = stm32_usart_unthrottle, + .stop_rx = stm32_usart_stop_rx, + .enable_ms = stm32_usart_enable_ms, + .break_ctl = stm32_usart_break_ctl, + .startup = stm32_usart_startup, + .shutdown = stm32_usart_shutdown, + .flush_buffer = stm32_usart_flush_buffer, + .set_termios = stm32_usart_set_termios, + .pm = stm32_usart_pm, + .type = stm32_usart_type, + .release_port = stm32_usart_release_port, + .request_port = stm32_usart_request_port, + .config_port = stm32_usart_config_port, + .verify_port = stm32_usart_verify_port, +#if defined(CONFIG_CONSOLE_POLL) + .poll_init = stm32_usart_poll_init, + .poll_get_char = stm32_usart_poll_get_char, + .poll_put_char = stm32_usart_poll_put_char, +#endif /* CONFIG_CONSOLE_POLL */ +}; + +struct stm32_usart_thresh_ratio { + int mul; + int div; }; -static int stm32_init_port(struct stm32_port *stm32port, - struct platform_device *pdev) +static const struct stm32_usart_thresh_ratio stm32h7_usart_fifo_thresh_cfg[] = { + {1, 8}, {1, 4}, {1, 2}, {3, 4}, {7, 8}, {1, 1} }; + +static int stm32_usart_get_thresh_value(u32 fifo_size, int index) +{ + return fifo_size * stm32h7_usart_fifo_thresh_cfg[index].mul / + stm32h7_usart_fifo_thresh_cfg[index].div; +} + +static int stm32_usart_get_ftcfg(struct platform_device *pdev, struct stm32_port *stm32port, + const char *p, int *ftcfg) +{ + const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + u32 bytes, i, cfg8; + int fifo_size; + + if (WARN_ON(ofs->hwcfgr1 == UNDEF_REG)) + return 1; + + cfg8 = FIELD_GET(USART_HWCFGR1_CFG8, + readl_relaxed(stm32port->port.membase + ofs->hwcfgr1)); + + /* On STM32H7, hwcfgr is not present, so returned value will be 0 */ + fifo_size = cfg8 ? 1 << cfg8 : STM32H7_USART_FIFO_SIZE; + + /* DT option to get RX & TX FIFO threshold (default to half fifo size) */ + if (of_property_read_u32(pdev->dev.of_node, p, &bytes)) + bytes = fifo_size / 2; + + if (bytes < stm32_usart_get_thresh_value(fifo_size, 0)) { + *ftcfg = -EINVAL; + return fifo_size; + } + + for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) { + if (stm32_usart_get_thresh_value(fifo_size, i) >= bytes) + break; + } + if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg)) + i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1; + + dev_dbg(&pdev->dev, "%s set to %d/%d bytes\n", p, + stm32_usart_get_thresh_value(fifo_size, i), fifo_size); + + *ftcfg = i; + return fifo_size; +} + +static void stm32_usart_deinit_port(struct stm32_port *stm32port) +{ + clk_disable_unprepare(stm32port->clk); +} + +static const struct serial_rs485 stm32_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + +static int stm32_usart_init_port(struct stm32_port *stm32port, + struct platform_device *pdev) { struct uart_port *port = &stm32port->port; struct resource *res; - int ret; + int ret, irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; port->ops = &stm32_uart_ops; port->dev = &pdev->dev; - port->fifosize = stm32port->info->cfg.fifosize; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); + port->irq = irq; + port->rs485_config = stm32_usart_config_rs485; + port->rs485_supported = stm32_rs485_supported; - ret = platform_get_irq(pdev, 0); - if (ret <= 0) - return ret ? : -ENODEV; - port->irq = ret; - - port->rs485_config = stm32_config_rs485; - - ret = stm32_init_rs485(port, pdev); + ret = stm32_usart_init_rs485(port, pdev); if (ret) return ret; - if (stm32port->info->cfg.has_wakeup) { - stm32port->wakeirq = platform_get_irq(pdev, 1); - if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) - return stm32port->wakeirq ? : -ENODEV; - } + stm32port->wakeup_src = stm32port->info->cfg.has_wakeup && + of_property_read_bool(pdev->dev.of_node, "wakeup-source"); - stm32port->fifoen = stm32port->info->cfg.has_fifo; + stm32port->swap = stm32port->info->cfg.has_swap && + of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - port->membase = devm_ioremap_resource(&pdev->dev, res); + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); port->mapbase = res->start; @@ -992,13 +1612,25 @@ static int stm32_init_port(struct stm32_port *stm32port, goto err_clk; } + stm32port->fifoen = stm32port->info->cfg.has_fifo; + if (stm32port->fifoen) { + stm32_usart_get_ftcfg(pdev, stm32port, "rx-threshold", &stm32port->rxftcfg); + port->fifosize = stm32_usart_get_ftcfg(pdev, stm32port, "tx-threshold", + &stm32port->txftcfg); + } else { + port->fifosize = 1; + } + stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0); if (IS_ERR(stm32port->gpios)) { ret = PTR_ERR(stm32port->gpios); goto err_clk; } - /* Both CTS/RTS gpios and "st,hw-flow-ctrl" should not be specified */ + /* + * Both CTS/RTS gpios and "st,hw-flow-ctrl" (deprecated) or "uart-has-rtscts" + * properties should not be specified. + */ if (stm32port->hw_flow_control) { if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) || mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) { @@ -1016,7 +1648,7 @@ err_clk: return ret; } -static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) +static struct stm32_port *stm32_usart_of_get_port(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; int id; @@ -1033,8 +1665,9 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) if (WARN_ON(id >= STM32_MAX_PORTS)) return NULL; - stm32_ports[id].hw_flow_control = of_property_read_bool(np, - "st,hw-flow-ctrl"); + stm32_ports[id].hw_flow_control = + of_property_read_bool (np, "st,hw-flow-ctrl") /*deprecated*/ || + of_property_read_bool (np, "uart-has-rtscts"); stm32_ports[id].port.line = id; stm32_ports[id].cr1_irq = USART_CR1_RXNEIE; stm32_ports[id].cr3_irq = 0; @@ -1053,30 +1686,28 @@ static const struct of_device_id stm32_match[] = { MODULE_DEVICE_TABLE(of, stm32_match); #endif -static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, - struct platform_device *pdev) +static void stm32_usart_of_dma_rx_remove(struct stm32_port *stm32port, + struct platform_device *pdev) { - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + if (stm32port->rx_buf) + dma_free_coherent(&pdev->dev, RX_BUF_L, stm32port->rx_buf, + stm32port->rx_dma_buf); +} + +static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; - struct dma_async_tx_descriptor *desc = NULL; - dma_cookie_t cookie; int ret; - /* Request DMA RX channel */ - stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); - if (!stm32port->rx_ch) { - dev_info(dev, "rx dma alloc failed\n"); - return -ENODEV; - } - stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, - &stm32port->rx_dma_buf, - GFP_KERNEL); - if (!stm32port->rx_buf) { - ret = -ENOMEM; - goto alloc_err; - } + stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L, + &stm32port->rx_dma_buf, + GFP_KERNEL); + if (!stm32port->rx_buf) + return -ENOMEM; /* Configure DMA channel */ memset(&config, 0, sizeof(config)); @@ -1086,69 +1717,35 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->rx_ch, &config); if (ret < 0) { dev_err(dev, "rx dma channel config failed\n"); - ret = -ENODEV; - goto config_err; - } - - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, - stm32port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(dev, "rx dma prep cyclic failed\n"); - ret = -ENODEV; - goto config_err; + stm32_usart_of_dma_rx_remove(stm32port, pdev); + return ret; } - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; - - /* Push current DMA transaction in the pending queue */ - cookie = dmaengine_submit(desc); - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32port->rx_ch); - return 0; +} -config_err: - dma_free_coherent(&pdev->dev, - RX_BUF_L, stm32port->rx_buf, - stm32port->rx_dma_buf); - -alloc_err: - dma_release_channel(stm32port->rx_ch); - stm32port->rx_ch = NULL; - - return ret; +static void stm32_usart_of_dma_tx_remove(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + if (stm32port->tx_buf) + dma_free_coherent(&pdev->dev, TX_BUF_L, stm32port->tx_buf, + stm32port->tx_dma_buf); } -static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, - struct platform_device *pdev) +static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, + struct platform_device *pdev) { - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; int ret; - stm32port->tx_dma_busy = false; - - /* Request DMA TX channel */ - stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); - if (!stm32port->tx_ch) { - dev_info(dev, "tx dma alloc failed\n"); - return -ENODEV; - } - stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, - &stm32port->tx_dma_buf, - GFP_KERNEL); - if (!stm32port->tx_buf) { - ret = -ENOMEM; - goto alloc_err; - } + stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L, + &stm32port->tx_dma_buf, + GFP_KERNEL); + if (!stm32port->tx_buf) + return -ENOMEM; /* Configure DMA channel */ memset(&config, 0, sizeof(config)); @@ -1158,166 +1755,189 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->tx_ch, &config); if (ret < 0) { dev_err(dev, "tx dma channel config failed\n"); - ret = -ENODEV; - goto config_err; + stm32_usart_of_dma_tx_remove(stm32port, pdev); + return ret; } return 0; - -config_err: - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32port->tx_buf, - stm32port->tx_dma_buf); - -alloc_err: - dma_release_channel(stm32port->tx_ch); - stm32port->tx_ch = NULL; - - return ret; } -static int stm32_serial_probe(struct platform_device *pdev) +static int stm32_usart_serial_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct stm32_port *stm32port; int ret; - stm32port = stm32_of_get_stm32_port(pdev); + stm32port = stm32_usart_of_get_port(pdev); if (!stm32port) return -ENODEV; - match = of_match_device(stm32_match, &pdev->dev); - if (match && match->data) - stm32port->info = (struct stm32_usart_info *)match->data; - else + stm32port->info = of_device_get_match_data(&pdev->dev); + if (!stm32port->info) return -EINVAL; - ret = stm32_init_port(stm32port, pdev); - if (ret) - return ret; + stm32port->rx_ch = dma_request_chan(&pdev->dev, "rx"); + if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) + return -EPROBE_DEFER; - if (stm32port->wakeirq > 0) { - ret = device_init_wakeup(&pdev->dev, true); - if (ret) - goto err_uninit; - - ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, - stm32port->wakeirq); - if (ret) - goto err_nowup; + /* Fall back in interrupt mode for any non-deferral error */ + if (IS_ERR(stm32port->rx_ch)) + stm32port->rx_ch = NULL; - device_set_wakeup_enable(&pdev->dev, false); + stm32port->tx_ch = dma_request_chan(&pdev->dev, "tx"); + if (PTR_ERR(stm32port->tx_ch) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_dma_rx; } + /* Fall back in interrupt mode for any non-deferral error */ + if (IS_ERR(stm32port->tx_ch)) + stm32port->tx_ch = NULL; - ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); + ret = stm32_usart_init_port(stm32port, pdev); if (ret) - goto err_wirq; + goto err_dma_tx; - ret = stm32_of_dma_rx_probe(stm32port, pdev); - if (ret) - dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n"); + if (stm32port->wakeup_src) { + device_set_wakeup_capable(&pdev->dev, true); + ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq); + if (ret) + goto err_deinit_port; + } - ret = stm32_of_dma_tx_probe(stm32port, pdev); - if (ret) - dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n"); + if (stm32port->rx_ch && stm32_usart_of_dma_rx_probe(stm32port, pdev)) { + /* Fall back in interrupt mode */ + dma_release_channel(stm32port->rx_ch); + stm32port->rx_ch = NULL; + } + + if (stm32port->tx_ch && stm32_usart_of_dma_tx_probe(stm32port, pdev)) { + /* Fall back in interrupt mode */ + dma_release_channel(stm32port->tx_ch); + stm32port->tx_ch = NULL; + } + + if (!stm32port->rx_ch) + dev_info(&pdev->dev, "interrupt mode for rx (no dma)\n"); + if (!stm32port->tx_ch) + dev_info(&pdev->dev, "interrupt mode for tx (no dma)\n"); platform_set_drvdata(pdev, &stm32port->port); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); + if (ret) + goto err_port; + pm_runtime_put_sync(&pdev->dev); return 0; -err_wirq: - if (stm32port->wakeirq > 0) +err_port: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + if (stm32port->tx_ch) + stm32_usart_of_dma_tx_remove(stm32port, pdev); + if (stm32port->rx_ch) + stm32_usart_of_dma_rx_remove(stm32port, pdev); + + if (stm32port->wakeup_src) dev_pm_clear_wake_irq(&pdev->dev); -err_nowup: - if (stm32port->wakeirq > 0) - device_init_wakeup(&pdev->dev, false); +err_deinit_port: + if (stm32port->wakeup_src) + device_set_wakeup_capable(&pdev->dev, false); -err_uninit: - clk_disable_unprepare(stm32port->clk); + stm32_usart_deinit_port(stm32port); + +err_dma_tx: + if (stm32port->tx_ch) + dma_release_channel(stm32port->tx_ch); + +err_dma_rx: + if (stm32port->rx_ch) + dma_release_channel(stm32port->rx_ch); return ret; } -static int stm32_serial_remove(struct platform_device *pdev) +static void stm32_usart_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - int err; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + u32 cr3; pm_runtime_get_sync(&pdev->dev); + uart_remove_one_port(&stm32_usart_driver, port); - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - - if (stm32_port->rx_ch) - dma_release_channel(stm32_port->rx_ch); - - if (stm32_port->rx_dma_buf) - dma_free_coherent(&pdev->dev, - RX_BUF_L, stm32_port->rx_buf, - stm32_port->rx_dma_buf); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE); - if (stm32_port->tx_ch) + if (stm32_port->tx_ch) { + stm32_usart_of_dma_tx_remove(stm32_port, pdev); dma_release_channel(stm32_port->tx_ch); + } - if (stm32_port->tx_dma_buf) - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32_port->tx_buf, - stm32_port->tx_dma_buf); + if (stm32_port->rx_ch) { + stm32_usart_of_dma_rx_remove(stm32_port, pdev); + dma_release_channel(stm32_port->rx_ch); + } + + cr3 = readl_relaxed(port->membase + ofs->cr3); + cr3 &= ~USART_CR3_EIE; + cr3 &= ~USART_CR3_DMAR; + cr3 &= ~USART_CR3_DMAT; + cr3 &= ~USART_CR3_DDRE; + writel_relaxed(cr3, port->membase + ofs->cr3); - if (stm32_port->wakeirq > 0) { + if (stm32_port->wakeup_src) { dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); } - clk_disable_unprepare(stm32_port->clk); - - err = uart_remove_one_port(&stm32_usart_driver, port); - - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - - return err; + stm32_usart_deinit_port(stm32_port); } - -#ifdef CONFIG_SERIAL_STM32_CONSOLE -static void stm32_console_putchar(struct uart_port *port, int ch) +static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - - while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) - cpu_relax(); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + u32 isr; + int ret; + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, isr, + (isr & USART_SR_TXE), 100, + STM32_USART_TIMEOUT_USEC); + if (ret != 0) { + dev_err(port->dev, "Error while sending data in UART TX : %d\n", ret); + return; + } writel_relaxed(ch, port->membase + ofs->tdr); } -static void stm32_console_write(struct console *co, const char *s, unsigned cnt) +#ifdef CONFIG_SERIAL_STM32_CONSOLE +static void stm32_usart_console_write(struct console *co, const char *s, + unsigned int cnt) { struct uart_port *port = &stm32_ports[co->index].port; struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + const struct stm32_usart_config *cfg = &stm32_port->info->cfg; unsigned long flags; u32 old_cr1, new_cr1; int locked = 1; - local_irq_save(flags); - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&port->lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock(&port->lock); + uart_port_lock_irqsave(port, &flags); /* Save and disable interrupts, enable the transmitter */ old_cr1 = readl_relaxed(port->membase + ofs->cr1); @@ -1325,17 +1945,16 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) new_cr1 |= USART_CR1_TE | BIT(cfg->uart_enable_bit); writel_relaxed(new_cr1, port->membase + ofs->cr1); - uart_console_write(port, s, cnt, stm32_console_putchar); + uart_console_write(port, s, cnt, stm32_usart_console_putchar); /* Restore interrupt state */ writel_relaxed(old_cr1, port->membase + ofs->cr1); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(port, flags); } -static int stm32_console_setup(struct console *co, char *options) +static int stm32_usart_console_setup(struct console *co, char *options) { struct stm32_port *stm32port; int baud = 9600; @@ -1354,7 +1973,7 @@ static int stm32_console_setup(struct console *co, char *options) * this to be called during the uart port registration when the * driver gets probed and the port should be mapped at that point. */ - if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL) + if (stm32port->port.mapbase == 0 || !stm32port->port.membase) return -ENXIO; if (options) @@ -1366,8 +1985,8 @@ static int stm32_console_setup(struct console *co, char *options) static struct console stm32_console = { .name = STM32_SERIAL_NAME, .device = uart_console_device, - .write = stm32_console_write, - .setup = stm32_console_setup, + .write = stm32_usart_console_write, + .setup = stm32_usart_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &stm32_usart_driver, @@ -1379,6 +1998,57 @@ static struct console stm32_console = { #define STM32_SERIAL_CONSOLE NULL #endif /* CONFIG_SERIAL_STM32_CONSOLE */ +#ifdef CONFIG_SERIAL_EARLYCON +static void early_stm32_usart_console_putchar(struct uart_port *port, unsigned char ch) +{ + struct stm32_usart_info *info = port->private_data; + + while (!(readl_relaxed(port->membase + info->ofs.isr) & USART_SR_TXE)) + cpu_relax(); + + writel_relaxed(ch, port->membase + info->ofs.tdr); +} + +static void early_stm32_serial_write(struct console *console, const char *s, unsigned int count) +{ + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; + + uart_console_write(port, s, count, early_stm32_usart_console_putchar); +} + +static int __init early_stm32_h7_serial_setup(struct earlycon_device *device, const char *options) +{ + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + device->port.private_data = &stm32h7_info; + device->con->write = early_stm32_serial_write; + return 0; +} + +static int __init early_stm32_f7_serial_setup(struct earlycon_device *device, const char *options) +{ + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + device->port.private_data = &stm32f7_info; + device->con->write = early_stm32_serial_write; + return 0; +} + +static int __init early_stm32_f4_serial_setup(struct earlycon_device *device, const char *options) +{ + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + device->port.private_data = &stm32f4_info; + device->con->write = early_stm32_serial_write; + return 0; +} + +OF_EARLYCON_DECLARE(stm32, "st,stm32h7-uart", early_stm32_h7_serial_setup); +OF_EARLYCON_DECLARE(stm32, "st,stm32f7-uart", early_stm32_f7_serial_setup); +OF_EARLYCON_DECLARE(stm32, "st,stm32-uart", early_stm32_f4_serial_setup); +#endif /* CONFIG_SERIAL_EARLYCON */ + static struct uart_driver stm32_usart_driver = { .driver_name = DRIVER_NAME, .dev_name = STM32_SERIAL_NAME, @@ -1388,41 +2058,72 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port, - bool enable) +static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + int ret; + unsigned int size = 0; + unsigned long flags; - if (stm32_port->wakeirq <= 0) - return; + if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) + return 0; + /* + * Enable low-power wake-up and wake-up irq if argument is set to + * "enable", disable low-power wake-up and wake-up irq otherwise + */ if (enable) { - stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - stm32_set_bits(port, ofs->cr1, USART_CR1_UESM); - val = readl_relaxed(port->membase + ofs->cr3); - val &= ~USART_CR3_WUS_MASK; - /* Enable Wake up interrupt from low power on start bit */ - val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; - writel_relaxed(val, port->membase + ofs->cr3); - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + mctrl_gpio_enable_irq_wake(stm32_port->gpios); + + /* + * When DMA is used for reception, it must be disabled before + * entering low-power mode and re-enabled when exiting from + * low-power mode. + */ + if (stm32_port->rx_ch) { + uart_port_lock_irqsave(port, &flags); + /* Poll data from DMA RX buffer if any */ + if (!stm32_usart_rx_dma_pause(stm32_port)) + size += stm32_usart_receive_chars(port, true); + stm32_usart_rx_dma_terminate(stm32_port); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); + } + + /* Poll data from RX FIFO if any */ + stm32_usart_receive_chars(port, false); } else { - stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM); + if (stm32_port->rx_ch) { + ret = stm32_usart_rx_dma_start_or_resume(port); + if (ret) + return ret; + } + mctrl_gpio_disable_irq_wake(stm32_port->gpios); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } + + return 0; } -static int __maybe_unused stm32_serial_suspend(struct device *dev) +static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev)) - stm32_serial_enable_wakeup(port, true); - else - stm32_serial_enable_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, true); + if (ret) + return ret; + } /* * When "no_console_suspend" is enabled, keep the pinctrl default state @@ -1431,7 +2132,7 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev) * capabilities. */ if (console_suspend_enabled || !uart_console(port)) { - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev) || device_wakeup_path(dev)) pinctrl_pm_select_idle_state(dev); else pinctrl_pm_select_sleep_state(dev); @@ -1440,19 +2141,23 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev) return 0; } -static int __maybe_unused stm32_serial_resume(struct device *dev) +static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev)) - stm32_serial_enable_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, false); + if (ret) + return ret; + } return uart_resume_port(&stm32_usart_driver, port); } -static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) +static int __maybe_unused stm32_usart_runtime_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); struct stm32_port *stm32port = container_of(port, @@ -1463,7 +2168,7 @@ static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) +static int __maybe_unused stm32_usart_runtime_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); struct stm32_port *stm32port = container_of(port, @@ -1473,14 +2178,15 @@ static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) } static const struct dev_pm_ops stm32_serial_pm_ops = { - SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, - stm32_serial_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) + SET_RUNTIME_PM_OPS(stm32_usart_runtime_suspend, + stm32_usart_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(stm32_usart_serial_suspend, + stm32_usart_serial_resume) }; static struct platform_driver stm32_serial_driver = { - .probe = stm32_serial_probe, - .remove = stm32_serial_remove, + .probe = stm32_usart_serial_probe, + .remove = stm32_usart_serial_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_serial_pm_ops, @@ -1488,7 +2194,7 @@ static struct platform_driver stm32_serial_driver = { }, }; -static int __init usart_init(void) +static int __init stm32_usart_init(void) { static char banner[] __initdata = "STM32 USART driver initialized"; int ret; @@ -1506,14 +2212,14 @@ static int __init usart_init(void) return ret; } -static void __exit usart_exit(void) +static void __exit stm32_usart_exit(void) { platform_driver_unregister(&stm32_serial_driver); uart_unregister_driver(&stm32_usart_driver); } -module_init(usart_init); -module_exit(usart_exit); +module_init(stm32_usart_init); +module_exit(stm32_usart_exit); MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver"); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index d4c916e78d40..af20258ccc7a 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -9,25 +9,27 @@ #define DRIVER_NAME "stm32-usart" struct stm32_usart_offsets { - u8 cr1; - u8 cr2; - u8 cr3; - u8 brr; - u8 gtpr; - u8 rtor; - u8 rqr; - u8 isr; - u8 icr; - u8 rdr; - u8 tdr; + u16 cr1; + u16 cr2; + u16 cr3; + u16 brr; + u16 gtpr; + u16 rtor; + u16 rqr; + u16 isr; + u16 icr; + u16 rdr; + u16 tdr; + u16 presc; + u16 hwcfgr1; }; struct stm32_usart_config { u8 uart_enable_bit; /* USART_CR1_UE */ bool has_7bits_data; + bool has_swap; bool has_wakeup; bool has_fifo; - int fifosize; }; struct stm32_usart_info { @@ -35,78 +37,12 @@ struct stm32_usart_info { struct stm32_usart_config cfg; }; -#define UNDEF_REG 0xff - -/* Register offsets */ -struct stm32_usart_info stm32f4_info = { - .ofs = { - .isr = 0x00, - .rdr = 0x04, - .tdr = 0x04, - .brr = 0x08, - .cr1 = 0x0c, - .cr2 = 0x10, - .cr3 = 0x14, - .gtpr = 0x18, - .rtor = UNDEF_REG, - .rqr = UNDEF_REG, - .icr = UNDEF_REG, - }, - .cfg = { - .uart_enable_bit = 13, - .has_7bits_data = false, - .fifosize = 1, - } -}; - -struct stm32_usart_info stm32f7_info = { - .ofs = { - .cr1 = 0x00, - .cr2 = 0x04, - .cr3 = 0x08, - .brr = 0x0c, - .gtpr = 0x10, - .rtor = 0x14, - .rqr = 0x18, - .isr = 0x1c, - .icr = 0x20, - .rdr = 0x24, - .tdr = 0x28, - }, - .cfg = { - .uart_enable_bit = 0, - .has_7bits_data = true, - .fifosize = 1, - } -}; - -struct stm32_usart_info stm32h7_info = { - .ofs = { - .cr1 = 0x00, - .cr2 = 0x04, - .cr3 = 0x08, - .brr = 0x0c, - .gtpr = 0x10, - .rtor = 0x14, - .rqr = 0x18, - .isr = 0x1c, - .icr = 0x20, - .rdr = 0x24, - .tdr = 0x28, - }, - .cfg = { - .uart_enable_bit = 0, - .has_7bits_data = true, - .has_wakeup = true, - .has_fifo = true, - .fifosize = 16, - } -}; +#define UNDEF_REG 0xffff /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) #define USART_SR_FE BIT(1) -#define USART_SR_NF BIT(2) +#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ #define USART_SR_ORE BIT(3) #define USART_SR_IDLE BIT(4) #define USART_SR_RXNE BIT(5) @@ -123,13 +59,11 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) +#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE |\ + USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) -/* USART_ICR (F7) */ -#define USART_CR_TC BIT(6) - /* USART_DR */ #define USART_DR_MASK GENMASK(8, 0) @@ -138,6 +72,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_SHIFT 4 #define USART_BRR_04_R_SHIFT 1 +#define USART_BRR_MASK (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK) /* USART_CR1 */ #define USART_CR1_SBK BIT(0) @@ -216,12 +151,6 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */ #define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */ -/* TX FIFO threashold set to half of its depth */ -#define USART_CR3_TXFTCFG_HALF 0x2 - -/* RX FIFO threashold set to half of its depth */ -#define USART_CR3_RXFTCFG_HALF 0x2 - /* USART_GTPR */ #define USART_GTPR_PSC_MASK GENMASK(7, 0) #define USART_GTPR_GT_MASK GENMASK(15, 8) @@ -249,17 +178,27 @@ struct stm32_usart_info stm32h7_info = { #define USART_ICR_CMCF BIT(17) /* F7 */ #define USART_ICR_WUCF BIT(20) /* H7 */ +/* USART_PRESC */ +#define USART_PRESC GENMASK(3, 0) /* H7 */ +#define USART_PRESC_MAX 0b1011 + +/* USART_HWCFCR1 */ +#define USART_HWCFGR1_CFG8 GENMASK(31, 28) /* MP1 */ + #define STM32_SERIAL_NAME "ttySTM" -#define STM32_MAX_PORTS 8 +#define STM32_MAX_PORTS 9 +#define STM32H7_USART_FIFO_SIZE 16 + +#define RX_BUF_L 4096 /* dma rx buffer length */ +#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ -#define RX_BUF_L 200 /* dma rx buffer length */ -#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -#define TX_BUF_L 200 /* dma tx buffer length */ +#define STM32_USART_TIMEOUT_USEC USEC_PER_SEC /* 1s timeout in µs */ struct stm32_port { struct uart_port port; struct clk *clk; - struct stm32_usart_info *info; + const struct stm32_usart_info *info; struct dma_chan *rx_ch; /* dma rx channel */ dma_addr_t rx_dma_buf; /* dma rx buffer bus address */ unsigned char *rx_buf; /* dma rx buffer cpu address */ @@ -269,12 +208,18 @@ struct stm32_port { u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; - bool tx_dma_busy; /* dma tx busy */ + bool tx_dma_busy; /* dma tx transaction in progress */ + bool rx_dma_busy; /* dma rx transaction in progress */ + bool throttled; /* port throttled */ bool hw_flow_control; + bool swap; /* swap RX & TX pins */ bool fifoen; - int wakeirq; + int rxftcfg; /* RX FIFO threshold CFG */ + int txftcfg; /* TX FIFO threshold CFG */ + bool wakeup_src; int rdr_mask; /* receive data register mask */ struct mctrl_gpios *gpios; /* modem control gpios */ + struct dma_tx_state rx_dma_state; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index e35073e93a5b..2b3ec65d595d 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -17,11 +17,11 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <asm/hypervisor.h> #include <asm/spitfire.h> -#include <asm/prom.h> #include <asm/irq.h> #include <asm/setup.h> @@ -39,32 +39,35 @@ static char *con_read_page; static int hung_up = 0; -static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit) +static void transmit_chars_putchar(struct uart_port *port, + struct tty_port *tport) { - while (!uart_circ_empty(xmit)) { - long status = sun4v_con_putchar(xmit->buf[xmit->tail]); + unsigned char ch; + + while (kfifo_peek(&tport->xmit_fifo, &ch)) { + long status = sun4v_con_putchar(ch); if (status != HV_EOK) break; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + uart_xmit_advance(port, 1); } } -static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit) +static void transmit_chars_write(struct uart_port *port, struct tty_port *tport) { - while (!uart_circ_empty(xmit)) { - unsigned long ra = __pa(xmit->buf + xmit->tail); - unsigned long len, status, sent; + while (!kfifo_is_empty(&tport->xmit_fifo)) { + unsigned long len, ra, status, sent; + unsigned char *tail; + + len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); + ra = __pa(tail); - len = CIRC_CNT_TO_END(xmit->head, xmit->tail, - UART_XMIT_SIZE); status = sun4v_con_write(ra, len, &sent); if (status != HV_EOK) break; - xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1); - port->icount.tx += sent; + uart_xmit_advance(port, sent); } } @@ -89,10 +92,10 @@ static int receive_chars_getchar(struct uart_port *port) if (c == CON_HUP) { hung_up = 1; - uart_handle_dcd_change(port, 0); + uart_handle_dcd_change(port, false); } else if (hung_up) { hung_up = 0; - uart_handle_dcd_change(port, 1); + uart_handle_dcd_change(port, true); } if (port->state == NULL) { @@ -135,7 +138,7 @@ static int receive_chars_read(struct uart_port *port) bytes_read = 1; } else if (stat == CON_HUP) { hung_up = 1; - uart_handle_dcd_change(port, 0); + uart_handle_dcd_change(port, false); continue; } else { /* HV_EWOULDBLOCK, etc. */ @@ -145,7 +148,7 @@ static int receive_chars_read(struct uart_port *port) if (hung_up) { hung_up = 0; - uart_handle_dcd_change(port, 1); + uart_handle_dcd_change(port, true); } if (port->sysrq != 0 && *con_read_page) { @@ -167,7 +170,7 @@ static int receive_chars_read(struct uart_port *port) } struct sunhv_ops { - void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit); + void (*transmit_chars)(struct uart_port *port, struct tty_port *tport); int (*receive_chars)(struct uart_port *port); }; @@ -198,18 +201,18 @@ static struct tty_port *receive_chars(struct uart_port *port) static void transmit_chars(struct uart_port *port) { - struct circ_buf *xmit; + struct tty_port *tport; if (!port->state) return; - xmit = &port->state->xmit; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + tport = &port->state->port; + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; - sunhv_ops->transmit_chars(port, xmit); + sunhv_ops->transmit_chars(port, tport); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -219,10 +222,10 @@ static irqreturn_t sunhv_interrupt(int irq, void *dev_id) struct tty_port *tport; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); tport = receive_chars(port); transmit_chars(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); if (tport) tty_flip_buffer_push(tport); @@ -273,7 +276,7 @@ static void sunhv_send_xchar(struct uart_port *port, char ch) if (ch == __DISABLED_CHAR) return; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); while (limit-- > 0) { long status = sun4v_con_putchar(ch); @@ -282,7 +285,7 @@ static void sunhv_send_xchar(struct uart_port *port, char ch) udelay(1); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* port->lock held by caller. */ @@ -297,7 +300,7 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state) unsigned long flags; int limit = 10000; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); while (limit-- > 0) { long status = sun4v_con_putchar(CON_BREAK); @@ -306,7 +309,7 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state) udelay(1); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } } @@ -323,14 +326,14 @@ static void sunhv_shutdown(struct uart_port *port) /* port->lock is not held. */ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); unsigned int quot = uart_get_divisor(port, baud); unsigned int iflag, cflag; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); iflag = termios->c_iflag; cflag = termios->c_cflag; @@ -345,7 +348,7 @@ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, cflag, (port->uartclk / (16 * quot))); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *sunhv_type(struct uart_port *port) @@ -439,9 +442,9 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign int locked = 1; if (port->sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); while (n > 0) { unsigned long ra = __pa(con_write_page); @@ -472,7 +475,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign } if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static inline void sunhv_console_putchar(struct uart_port *port, char c) @@ -494,9 +497,9 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig int i, locked = 1; if (port->sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); for (i = 0; i < n; i++) { if (*s == '\n') @@ -505,7 +508,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig } if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static struct console sunhv_console = { @@ -567,9 +570,6 @@ static int hv_probe(struct platform_device *op) sunserial_console_match(&sunhv_console, op->dev.of_node, &sunhv_reg, port->line, false); - /* We need to initialize lock even for non-registered console */ - spin_lock_init(&port->lock); - err = uart_add_one_port(&sunhv_reg, port); if (err) goto out_unregister_driver; @@ -600,7 +600,7 @@ out_free_port: return err; } -static int hv_remove(struct platform_device *dev) +static void hv_remove(struct platform_device *dev) { struct uart_port *port = platform_get_drvdata(dev); @@ -613,8 +613,6 @@ static int hv_remove(struct platform_device *dev) kfree(con_write_page); kfree(port); sunhv_port = NULL; - - return 0; } static const struct of_device_id hv_match[] = { diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c new file mode 100644 index 000000000000..38deee571b0d --- /dev/null +++ b/drivers/tty/serial/sunplus-uart.c @@ -0,0 +1,767 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sunplus SoC UART driver + * + * Author: Hammer Hsieh <hammerh0314@gmail.com> + * + * Note1: This driver is 8250-like uart, but are not register compatible. + * + * Note2: On some buses, for preventing data incoherence, must do a read + * for ensure write made it to hardware. In this driver, function startup + * and shutdown did not do a read but only do a write directly. For what? + * In Sunplus bus communication between memory bus and peripheral bus with + * posted write, it will send a specific command after last write command + * to make sure write done. Then memory bus identify the specific command + * and send done signal back to master device. After master device received + * done signal, then proceed next write command. It is no need to do a read + * before write. + */ +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/sysrq.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <asm/irq.h> + +/* Register offsets */ +#define SUP_UART_DATA 0x00 +#define SUP_UART_LSR 0x04 +#define SUP_UART_MSR 0x08 +#define SUP_UART_LCR 0x0C +#define SUP_UART_MCR 0x10 +#define SUP_UART_DIV_L 0x14 +#define SUP_UART_DIV_H 0x18 +#define SUP_UART_ISC 0x1C +#define SUP_UART_TX_RESIDUE 0x20 +#define SUP_UART_RX_RESIDUE 0x24 + +/* Line Status Register bits */ +#define SUP_UART_LSR_BC BIT(5) /* break condition status */ +#define SUP_UART_LSR_FE BIT(4) /* frame error status */ +#define SUP_UART_LSR_OE BIT(3) /* overrun error status */ +#define SUP_UART_LSR_PE BIT(2) /* parity error status */ +#define SUP_UART_LSR_RX BIT(1) /* 1: receive fifo not empty */ +#define SUP_UART_LSR_TX BIT(0) /* 1: transmit fifo is not full */ +#define SUP_UART_LSR_TX_NOT_FULL 1 +#define SUP_UART_LSR_BRK_ERROR_BITS GENMASK(5, 2) + +/* Line Control Register bits */ +#define SUP_UART_LCR_SBC BIT(5) /* select break condition */ + +/* Modem Control Register bits */ +#define SUP_UART_MCR_RI BIT(3) /* ring indicator */ +#define SUP_UART_MCR_DCD BIT(2) /* data carrier detect */ + +/* Interrupt Status/Control Register bits */ +#define SUP_UART_ISC_RXM BIT(5) /* RX interrupt enable */ +#define SUP_UART_ISC_TXM BIT(4) /* TX interrupt enable */ +#define SUP_UART_ISC_RX BIT(1) /* RX interrupt status */ +#define SUP_UART_ISC_TX BIT(0) /* TX interrupt status */ + +#define SUP_DUMMY_READ BIT(16) /* drop bytes received on a !CREAD port */ +#define SUP_UART_NR 5 + +struct sunplus_uart_port { + struct uart_port port; + struct clk *clk; + struct reset_control *rstc; +}; + +static void sp_uart_put_char(struct uart_port *port, unsigned int ch) +{ + writel(ch, port->membase + SUP_UART_DATA); +} + +static u32 sunplus_tx_buf_not_full(struct uart_port *port) +{ + unsigned int lsr = readl(port->membase + SUP_UART_LSR); + + return (lsr & SUP_UART_LSR_TX) ? SUP_UART_LSR_TX_NOT_FULL : 0; +} + +static unsigned int sunplus_tx_empty(struct uart_port *port) +{ + unsigned int lsr = readl(port->membase + SUP_UART_LSR); + + return (lsr & UART_LSR_TEMT) ? TIOCSER_TEMT : 0; +} + +static void sunplus_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int mcr = readl(port->membase + SUP_UART_MCR); + + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + else + mcr &= ~UART_MCR_DTR; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + else + mcr &= ~UART_MCR_RTS; + + if (mctrl & TIOCM_CAR) + mcr |= SUP_UART_MCR_DCD; + else + mcr &= ~SUP_UART_MCR_DCD; + + if (mctrl & TIOCM_RI) + mcr |= SUP_UART_MCR_RI; + else + mcr &= ~SUP_UART_MCR_RI; + + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + else + mcr &= ~UART_MCR_LOOP; + + writel(mcr, port->membase + SUP_UART_MCR); +} + +static unsigned int sunplus_get_mctrl(struct uart_port *port) +{ + unsigned int mcr, ret = 0; + + mcr = readl(port->membase + SUP_UART_MCR); + + if (mcr & UART_MCR_DTR) + ret |= TIOCM_DTR; + + if (mcr & UART_MCR_RTS) + ret |= TIOCM_RTS; + + if (mcr & SUP_UART_MCR_DCD) + ret |= TIOCM_CAR; + + if (mcr & SUP_UART_MCR_RI) + ret |= TIOCM_RI; + + if (mcr & UART_MCR_LOOP) + ret |= TIOCM_LOOP; + + return ret; +} + +static void sunplus_stop_tx(struct uart_port *port) +{ + unsigned int isc; + + isc = readl(port->membase + SUP_UART_ISC); + isc &= ~SUP_UART_ISC_TXM; + writel(isc, port->membase + SUP_UART_ISC); +} + +static void sunplus_start_tx(struct uart_port *port) +{ + unsigned int isc; + + isc = readl(port->membase + SUP_UART_ISC); + isc |= SUP_UART_ISC_TXM; + writel(isc, port->membase + SUP_UART_ISC); +} + +static void sunplus_stop_rx(struct uart_port *port) +{ + unsigned int isc; + + isc = readl(port->membase + SUP_UART_ISC); + isc &= ~SUP_UART_ISC_RXM; + writel(isc, port->membase + SUP_UART_ISC); +} + +static void sunplus_break_ctl(struct uart_port *port, int ctl) +{ + unsigned long flags; + unsigned int lcr; + + uart_port_lock_irqsave(port, &flags); + + lcr = readl(port->membase + SUP_UART_LCR); + + if (ctl) + lcr |= SUP_UART_LCR_SBC; /* start break */ + else + lcr &= ~SUP_UART_LCR_SBC; /* stop break */ + + writel(lcr, port->membase + SUP_UART_LCR); + + uart_port_unlock_irqrestore(port, flags); +} + +static void transmit_chars(struct uart_port *port) +{ + struct tty_port *tport = &port->state->port; + + if (port->x_char) { + sp_uart_put_char(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { + sunplus_stop_tx(port); + return; + } + + do { + unsigned char ch; + + if (!uart_fifo_get(port, &ch)) + break; + + sp_uart_put_char(port, ch); + } while (sunplus_tx_buf_not_full(port)); + + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (kfifo_is_empty(&tport->xmit_fifo)) + sunplus_stop_tx(port); +} + +static void receive_chars(struct uart_port *port) +{ + unsigned int lsr = readl(port->membase + SUP_UART_LSR); + u8 ch, flag; + + do { + ch = readl(port->membase + SUP_UART_DATA); + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) { + if (lsr & SUP_UART_LSR_BC) { + lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE); + port->icount.brk++; + flag = TTY_BREAK; + if (uart_handle_break(port)) + goto ignore_char; + } else if (lsr & SUP_UART_LSR_PE) { + port->icount.parity++; + flag = TTY_PARITY; + } else if (lsr & SUP_UART_LSR_FE) { + port->icount.frame++; + flag = TTY_FRAME; + } + + if (lsr & SUP_UART_LSR_OE) + port->icount.overrun++; + } + + if (port->ignore_status_mask & SUP_DUMMY_READ) + goto ignore_char; + + if (uart_prepare_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag); + +ignore_char: + lsr = readl(port->membase + SUP_UART_LSR); + } while (lsr & SUP_UART_LSR_RX); + + tty_flip_buffer_push(&port->state->port); +} + +static irqreturn_t sunplus_uart_irq(int irq, void *args) +{ + struct uart_port *port = args; + unsigned int isc; + + uart_port_lock(port); + + isc = readl(port->membase + SUP_UART_ISC); + + if (isc & SUP_UART_ISC_RX) + receive_chars(port); + + if (isc & SUP_UART_ISC_TX) + transmit_chars(port); + + uart_unlock_and_check_sysrq(port); + + return IRQ_HANDLED; +} + +static int sunplus_startup(struct uart_port *port) +{ + unsigned long flags; + unsigned int isc = 0; + int ret; + + ret = request_irq(port->irq, sunplus_uart_irq, 0, "sunplus_uart", port); + if (ret) + return ret; + + uart_port_lock_irqsave(port, &flags); + /* isc define Bit[7:4] int setting, Bit[3:0] int status + * isc register will clean Bit[3:0] int status after read + * only do a write to Bit[7:4] int setting + */ + isc |= SUP_UART_ISC_RXM; + writel(isc, port->membase + SUP_UART_ISC); + uart_port_unlock_irqrestore(port, flags); + + return 0; +} + +static void sunplus_shutdown(struct uart_port *port) +{ + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + /* isc define Bit[7:4] int setting, Bit[3:0] int status + * isc register will clean Bit[3:0] int status after read + * only do a write to Bit[7:4] int setting + */ + writel(0, port->membase + SUP_UART_ISC); /* disable all interrupt */ + uart_port_unlock_irqrestore(port, flags); + + free_irq(port->irq, port); +} + +static void sunplus_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *oldtermios) +{ + u32 ext, div, div_l, div_h, baud, lcr; + u32 clk = port->uartclk; + unsigned long flags; + + baud = uart_get_baud_rate(port, termios, oldtermios, 0, port->uartclk / 16); + + /* baud rate = uartclk / ((16 * divisor + 1) + divisor_ext) */ + clk += baud >> 1; + div = clk / baud; + ext = div & 0x0F; + div = (div >> 4) - 1; + div_l = (div & 0xFF) | (ext << 12); + div_h = div >> 8; + + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr = UART_LCR_WLEN5; + break; + case CS6: + lcr = UART_LCR_WLEN6; + break; + case CS7: + lcr = UART_LCR_WLEN7; + break; + default: + lcr = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + lcr |= UART_LCR_STOP; + + if (termios->c_cflag & PARENB) { + lcr |= UART_LCR_PARITY; + + if (!(termios->c_cflag & PARODD)) + lcr |= UART_LCR_EPAR; + } + + uart_port_lock_irqsave(port, &flags); + + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = 0; + if (termios->c_iflag & INPCK) + port->read_status_mask |= SUP_UART_LSR_PE | SUP_UART_LSR_FE; + + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SUP_UART_LSR_BC; + + /* Characters to ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= SUP_UART_LSR_FE | SUP_UART_LSR_PE; + + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= SUP_UART_LSR_BC; + + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= SUP_UART_LSR_OE; + } + + /* Ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) { + port->ignore_status_mask |= SUP_DUMMY_READ; + /* flush rx data FIFO */ + writel(0, port->membase + SUP_UART_RX_RESIDUE); + } + + /* Settings for baud rate divisor and lcr */ + writel(div_h, port->membase + SUP_UART_DIV_H); + writel(div_l, port->membase + SUP_UART_DIV_L); + writel(lcr, port->membase + SUP_UART_LCR); + + uart_port_unlock_irqrestore(port, flags); +} + +static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios) +{ + int new = termios->c_line; + + if (new == N_PPS) + port->flags |= UPF_HARDPPS_CD; + else + port->flags &= ~UPF_HARDPPS_CD; +} + +static const char *sunplus_type(struct uart_port *port) +{ + return port->type == PORT_SUNPLUS ? "sunplus_uart" : NULL; +} + +static void sunplus_config_port(struct uart_port *port, int type) +{ + if (type & UART_CONFIG_TYPE) + port->type = PORT_SUNPLUS; +} + +static int sunplus_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_SUNPLUS) + return -EINVAL; + + return 0; +} + +#if defined(CONFIG_SERIAL_SUNPLUS_CONSOLE) || defined(CONFIG_CONSOLE_POLL) +static void wait_for_xmitr(struct uart_port *port) +{ + unsigned int val; + int ret; + + /* Wait while FIFO is full or timeout */ + ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val, + (val & SUP_UART_LSR_TX), 1, 10000); + + if (ret == -ETIMEDOUT) { + dev_err(port->dev, "Timeout waiting while UART TX FULL\n"); + return; + } +} +#endif + +#ifdef CONFIG_CONSOLE_POLL +static void sunplus_poll_put_char(struct uart_port *port, unsigned char data) +{ + wait_for_xmitr(port); + sp_uart_put_char(port, data); +} + +static int sunplus_poll_get_char(struct uart_port *port) +{ + unsigned int lsr = readl(port->membase + SUP_UART_LSR); + + if (!(lsr & SUP_UART_LSR_RX)) + return NO_POLL_CHAR; + + return readl(port->membase + SUP_UART_DATA); +} +#endif + +static const struct uart_ops sunplus_uart_ops = { + .tx_empty = sunplus_tx_empty, + .set_mctrl = sunplus_set_mctrl, + .get_mctrl = sunplus_get_mctrl, + .stop_tx = sunplus_stop_tx, + .start_tx = sunplus_start_tx, + .stop_rx = sunplus_stop_rx, + .break_ctl = sunplus_break_ctl, + .startup = sunplus_startup, + .shutdown = sunplus_shutdown, + .set_termios = sunplus_set_termios, + .set_ldisc = sunplus_set_ldisc, + .type = sunplus_type, + .config_port = sunplus_config_port, + .verify_port = sunplus_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = sunplus_poll_put_char, + .poll_get_char = sunplus_poll_get_char, +#endif +}; + +#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE +static struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR]; + +static void sunplus_uart_console_putchar(struct uart_port *port, + unsigned char ch) +{ + wait_for_xmitr(port); + sp_uart_put_char(port, ch); +} + +static void sunplus_console_write(struct console *co, + const char *s, + unsigned int count) +{ + unsigned long flags; + int locked = 1; + + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&sunplus_console_ports[co->index]->port, &flags); + else + uart_port_lock_irqsave(&sunplus_console_ports[co->index]->port, &flags); + + uart_console_write(&sunplus_console_ports[co->index]->port, s, count, + sunplus_uart_console_putchar); + + if (locked) + uart_port_unlock_irqrestore(&sunplus_console_ports[co->index]->port, flags); +} + +static int __init sunplus_console_setup(struct console *co, char *options) +{ + struct sunplus_uart_port *sup; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= SUP_UART_NR) + return -EINVAL; + + sup = sunplus_console_ports[co->index]; + if (!sup) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&sup->port, co, baud, parity, bits, flow); +} + +static struct uart_driver sunplus_uart_driver; +static struct console sunplus_uart_console = { + .name = "ttySUP", + .write = sunplus_console_write, + .device = uart_console_device, + .setup = sunplus_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sunplus_uart_driver +}; + +#define SERIAL_SUNPLUS_CONSOLE (&sunplus_uart_console) +#else +#define SERIAL_SUNPLUS_CONSOLE NULL +#endif + +static struct uart_driver sunplus_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "sunplus_uart", + .dev_name = "ttySUP", + .major = TTY_MAJOR, + .minor = 64, + .nr = SUP_UART_NR, + .cons = SERIAL_SUNPLUS_CONSOLE, +}; + +static void sunplus_uart_disable_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + +static void sunplus_uart_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + +static int sunplus_uart_probe(struct platform_device *pdev) +{ + struct sunplus_uart_port *sup; + struct uart_port *port; + struct resource *res; + int ret, irq; + + pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + + if (pdev->id < 0 || pdev->id >= SUP_UART_NR) + return -EINVAL; + + sup = devm_kzalloc(&pdev->dev, sizeof(*sup), GFP_KERNEL); + if (!sup) + return -ENOMEM; + + sup->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(sup->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sup->clk), "clk not found\n"); + + ret = clk_prepare_enable(sup->clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_disable_unprepare, sup->clk); + if (ret) + return ret; + + sup->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(sup->rstc)) + return dev_err_probe(&pdev->dev, PTR_ERR(sup->rstc), "rstc not found\n"); + + port = &sup->port; + + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(port->membase)) + return dev_err_probe(&pdev->dev, PTR_ERR(port->membase), "membase not found\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + port->mapbase = res->start; + port->uartclk = clk_get_rate(sup->clk); + port->line = pdev->id; + port->irq = irq; + port->dev = &pdev->dev; + port->iotype = UPIO_MEM; + port->ops = &sunplus_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->fifosize = 128; + + ret = reset_control_deassert(sup->rstc); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_reset_control_assert, sup->rstc); + if (ret) + return ret; + +#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE + sunplus_console_ports[sup->port.line] = sup; +#endif + + platform_set_drvdata(pdev, &sup->port); + + ret = uart_add_one_port(&sunplus_uart_driver, &sup->port); +#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE + if (ret) + sunplus_console_ports[sup->port.line] = NULL; +#endif + + return ret; +} + +static void sunplus_uart_remove(struct platform_device *pdev) +{ + struct sunplus_uart_port *sup = platform_get_drvdata(pdev); + + uart_remove_one_port(&sunplus_uart_driver, &sup->port); +} + +static int __maybe_unused sunplus_uart_suspend(struct device *dev) +{ + struct sunplus_uart_port *sup = dev_get_drvdata(dev); + + if (!uart_console(&sup->port)) + uart_suspend_port(&sunplus_uart_driver, &sup->port); + + return 0; +} + +static int __maybe_unused sunplus_uart_resume(struct device *dev) +{ + struct sunplus_uart_port *sup = dev_get_drvdata(dev); + + if (!uart_console(&sup->port)) + uart_resume_port(&sunplus_uart_driver, &sup->port); + + return 0; +} + +static const struct dev_pm_ops sunplus_uart_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sunplus_uart_suspend, sunplus_uart_resume) +}; + +static const struct of_device_id sp_uart_of_match[] = { + { .compatible = "sunplus,sp7021-uart" }, + {} +}; +MODULE_DEVICE_TABLE(of, sp_uart_of_match); + +static struct platform_driver sunplus_uart_platform_driver = { + .probe = sunplus_uart_probe, + .remove = sunplus_uart_remove, + .driver = { + .name = "sunplus_uart", + .of_match_table = sp_uart_of_match, + .pm = &sunplus_uart_pm_ops, + } +}; + +static int __init sunplus_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&sunplus_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&sunplus_uart_platform_driver); + if (ret) + uart_unregister_driver(&sunplus_uart_driver); + + return ret; +} +module_init(sunplus_uart_init); + +static void __exit sunplus_uart_exit(void) +{ + platform_driver_unregister(&sunplus_uart_platform_driver); + uart_unregister_driver(&sunplus_uart_driver); +} +module_exit(sunplus_uart_exit); + +#ifdef CONFIG_SERIAL_EARLYCON +static void sunplus_uart_putc(struct uart_port *port, unsigned char c) +{ + unsigned int val; + int ret; + + ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val, + (val & UART_LSR_TEMT), 1, 10000); + if (ret) + return; + + writel(c, port->membase + SUP_UART_DATA); +} + +static void sunplus_uart_early_write(struct console *con, const char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, sunplus_uart_putc); +} + +static int __init +sunplus_uart_early_setup(struct earlycon_device *dev, const char *opt) +{ + if (!(dev->port.membase || dev->port.iobase)) + return -ENODEV; + + dev->con->write = sunplus_uart_early_write; + + return 0; +} +OF_EARLYCON_DECLARE(sunplus_uart, "sunplus,sp7021-uart", sunplus_uart_early_setup); +#endif + +MODULE_DESCRIPTION("Sunplus UART driver"); +MODULE_AUTHOR("Hammer Hsieh <hammerh0314@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 1eb703c980e0..df906ccf2e8a 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -33,9 +33,10 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/setup.h> @@ -231,7 +232,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *); static void transmit_chars(struct uart_sunsab_port *up, union sab82532_irq_status *stat) { - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; int i; if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) { @@ -251,7 +252,7 @@ static void transmit_chars(struct uart_sunsab_port *up, set_bit(SAB82532_XPR, &up->irqflags); sunsab_tx_idle(up); - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&up->port)) { up->interrupt_mask1 |= SAB82532_IMR1_XPR; writeb(up->interrupt_mask1, &up->regs->w.imr1); return; @@ -264,22 +265,22 @@ static void transmit_chars(struct uart_sunsab_port *up, /* Stuff 32 bytes into Transmit FIFO. */ clear_bit(SAB82532_XPR, &up->irqflags); for (i = 0; i < up->port.fifosize; i++) { - writeb(xmit->buf[xmit->tail], - &up->regs->w.xfifo[i]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) + unsigned char ch; + + if (!uart_fifo_get(&up->port, &ch)) break; + + writeb(ch, &up->regs->w.xfifo[i]); } /* Issue a Transmit Frame command. */ sunsab_cec_wait(up); writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) sunsab_stop_tx(&up->port); } @@ -310,7 +311,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) unsigned long flags; unsigned char gis; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); status.stat = 0; gis = readb(&up->regs->r.gis) >> up->gis_shift; @@ -331,7 +332,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) transmit_chars(up, &status); } - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); if (port) tty_flip_buffer_push(port); @@ -435,15 +436,15 @@ static void sunsab_start_tx(struct uart_port *port) { struct uart_sunsab_port *up = container_of(port, struct uart_sunsab_port, port); - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; int i; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); writeb(up->interrupt_mask1, &up->regs->w.imr1); - + if (!test_bit(SAB82532_XPR, &up->irqflags)) return; @@ -451,12 +452,12 @@ static void sunsab_start_tx(struct uart_port *port) clear_bit(SAB82532_XPR, &up->irqflags); for (i = 0; i < up->port.fifosize; i++) { - writeb(xmit->buf[xmit->tail], - &up->regs->w.xfifo[i]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) + unsigned char ch; + + if (!uart_fifo_get(&up->port, &ch)) break; + + writeb(ch, &up->regs->w.xfifo[i]); } /* Issue a Transmit Frame command. */ @@ -474,12 +475,12 @@ static void sunsab_send_xchar(struct uart_port *port, char ch) if (ch == __DISABLED_CHAR) return; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); sunsab_tec_wait(up); writeb(ch, &up->regs->w.tic); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } /* port->lock held by caller. */ @@ -500,7 +501,7 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) unsigned long flags; unsigned char val; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); val = up->cached_dafo; if (break_state) @@ -513,7 +514,7 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) if (test_bit(SAB82532_XPR, &up->irqflags)) sunsab_tx_idle(up); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } /* port->lock is not held. */ @@ -528,7 +529,7 @@ static int sunsab_startup(struct uart_port *port) if (err) return err; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Wait for any commands or immediate characters @@ -550,7 +551,7 @@ static int sunsab_startup(struct uart_port *port) (void) readb(&up->regs->r.isr1); /* - * Now, initialize the UART + * Now, initialize the UART */ writeb(0, &up->regs->w.ccr0); /* power-down */ writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | @@ -564,7 +565,7 @@ static int sunsab_startup(struct uart_port *port) SAB82532_MODE_RAC); writeb(up->cached_mode, &up->regs->w.mode); writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); - + tmp = readb(&up->regs->rw.ccr0); tmp |= SAB82532_CCR0_PU; /* power-up */ writeb(tmp, &up->regs->rw.ccr0); @@ -583,7 +584,7 @@ static int sunsab_startup(struct uart_port *port) set_bit(SAB82532_ALLS, &up->irqflags); set_bit(SAB82532_XPR, &up->irqflags); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return 0; } @@ -595,7 +596,7 @@ static void sunsab_shutdown(struct uart_port *port) container_of(port, struct uart_sunsab_port, port); unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* Disable Interrupts */ up->interrupt_mask0 = 0xff; @@ -608,7 +609,7 @@ static void sunsab_shutdown(struct uart_port *port) up->cached_dafo &= ~SAB82532_DAFO_XBRK; writeb(up->cached_dafo, &up->regs->rw.dafo); - /* Disable Receiver */ + /* Disable Receiver */ up->cached_mode &= ~SAB82532_MODE_RAC; writeb(up->cached_mode, &up->regs->rw.mode); @@ -623,13 +624,13 @@ static void sunsab_shutdown(struct uart_port *port) * speed the chip was configured for when the port was open). */ #if 0 - /* Power Down */ + /* Power Down */ tmp = readb(&up->regs->rw.ccr0); tmp &= ~SAB82532_CCR0_PU; writeb(tmp, &up->regs->rw.ccr0); #endif - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); free_irq(up->port.irq, up); } @@ -650,7 +651,7 @@ static void calc_ebrg(int baud, int *n_ret, int *m_ret) *m_ret = 0; return; } - + /* * We scale numbers by 10 so that we get better accuracy * without having to use floating point. Here we increment m @@ -681,27 +682,23 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla unsigned int quot) { unsigned char dafo; - int bits, n, m; + int n, m; /* Byte size and parity */ switch (cflag & CSIZE) { - case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; - case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; - case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; - case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + case CS5: dafo = SAB82532_DAFO_CHL5; break; + case CS6: dafo = SAB82532_DAFO_CHL6; break; + case CS7: dafo = SAB82532_DAFO_CHL7; break; + case CS8: dafo = SAB82532_DAFO_CHL8; break; /* Never happens, but GCC is too dumb to figure it out */ - default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + default: dafo = SAB82532_DAFO_CHL5; break; } - if (cflag & CSTOPB) { + if (cflag & CSTOPB) dafo |= SAB82532_DAFO_STOP; - bits++; - } - if (cflag & PARENB) { + if (cflag & PARENB) dafo |= SAB82532_DAFO_PARE; - bits++; - } if (cflag & PARODD) { dafo |= SAB82532_DAFO_PAR_ODD; @@ -776,7 +773,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla /* port->lock is not held. */ static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_sunsab_port *up = container_of(port, struct uart_sunsab_port, port); @@ -784,16 +781,16 @@ static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); unsigned int quot = uart_get_divisor(port, baud); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static const char *sunsab_type(struct uart_port *port) { struct uart_sunsab_port *up = (void *)port; static char buf[36]; - + sprintf(buf, "SAB82532 %s", sab82532_version[up->type]); return buf; } @@ -846,7 +843,7 @@ static struct uart_sunsab_port *sunsab_ports; #ifdef CONFIG_SERIAL_SUNSAB_CONSOLE -static void sunsab_console_putchar(struct uart_port *port, int c) +static void sunsab_console_putchar(struct uart_port *port, unsigned char c) { struct uart_sunsab_port *up = container_of(port, struct uart_sunsab_port, port); @@ -862,15 +859,15 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n) int locked = 1; if (up->port.sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&up->port.lock, flags); + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); uart_console_write(&up->port, s, n, sunsab_console_putchar); sunsab_tec_wait(up); if (locked) - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int sunsab_console_setup(struct console *con, char *options) @@ -886,7 +883,7 @@ static int sunsab_console_setup(struct console *con, char *options) * though... */ if (up->port.type != PORT_SUNSAB) - return -1; + return -EINVAL; printk("Console: ttyS%d (SAB82532)\n", (sunsab_reg.minor - 64) + con->index); @@ -919,7 +916,7 @@ static int sunsab_console_setup(struct console *con, char *options) */ sunsab_startup(&up->port); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Finally, enable interrupts @@ -937,8 +934,8 @@ static int sunsab_console_setup(struct console *con, char *options) sunsab_convert_to_sab(up, con->cflag, 0, baud, quot); sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - spin_unlock_irqrestore(&up->port.lock, flags); - + uart_port_unlock_irqrestore(&up->port, flags); + return 0; } @@ -1071,7 +1068,7 @@ out: return err; } -static int sab_remove(struct platform_device *op) +static void sab_remove(struct platform_device *op) { struct uart_sunsab_port *up = platform_get_drvdata(op); @@ -1083,8 +1080,6 @@ static int sab_remove(struct platform_device *op) of_iounmap(&op->resource[0], up[0].port.membase, sizeof(union sab82532_async_regs)); - - return 0; } static const struct of_device_id sab_match[] = { @@ -1137,7 +1132,13 @@ static int __init sunsab_init(void) } } - return platform_driver_register(&sab_driver); + err = platform_driver_register(&sab_driver); + if (err) { + kfree(sunsab_ports); + sunsab_ports = NULL; + } + + return err; } static void __exit sunsab_exit(void) diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 8ce9a7a256e5..383141fe7ba0 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -37,11 +37,11 @@ #include <linux/serial_reg.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> -#include <asm/prom.h> #include <asm/setup.h> #include <linux/serial_core.h> @@ -127,7 +127,8 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value) * gate outputs a logical one. Since we use level triggered interrupts * we have lockup and watchdog reset. We cannot mask IRQ because * keyboard shares IRQ with us (Word has it as Bob Smelik's design). - * This problem is similar to what Alpha people suffer, see serial.c. + * This problem is similar to what Alpha people suffer, see + * 8250_alpha.c. */ if (offset == UART_MCR) value |= UART_MCR_OUT2; @@ -150,16 +151,6 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value) } /* - * We used to support using pause I/O for certain machines. We - * haven't supported this for a while, but just in case it's badly - * needed for certain old 386 machines, I've left these #define's - * in.... - */ -#define serial_inp(up, offset) serial_in(up, offset) -#define serial_outp(up, offset, value) serial_out(up, offset, value) - - -/* * For the 16C950 */ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value) @@ -168,20 +159,6 @@ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value) serial_out(up, UART_ICR, value); } -#if 0 /* Unused currently */ -static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset) -{ - unsigned int value; - - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); - - return value; -} -#endif - #ifdef CONFIG_SERIAL_8250_RSA /* * Attempts to turn on the RSA FIFO. Returns zero on failure. @@ -192,12 +169,12 @@ static int __enable_rsa(struct uart_sunsu_port *up) unsigned char mode; int result; - mode = serial_inp(up, UART_RSA_MSR); + mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; if (!result) { - serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); + serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; } @@ -211,12 +188,12 @@ static void enable_rsa(struct uart_sunsu_port *up) { if (up->port.type == PORT_RSA) { if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); + uart_port_lock_irq(&up->port); __enable_rsa(up); - spin_unlock_irq(&up->port.lock); + uart_port_unlock_irq(&up->port); } if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_outp(up, UART_RSA_FRR, 0); + serial_out(up, UART_RSA_FRR, 0); } } @@ -233,20 +210,20 @@ static void disable_rsa(struct uart_sunsu_port *up) if (up->port.type == PORT_RSA && up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); + uart_port_lock_irq(&up->port); - mode = serial_inp(up, UART_RSA_MSR); + mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); if (!result) { - serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); + serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); } if (result) up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); + uart_port_unlock_irq(&up->port); } } #endif /* CONFIG_SERIAL_8250_RSA */ @@ -310,10 +287,10 @@ static void sunsu_enable_ms(struct uart_port *port) container_of(port, struct uart_sunsu_port, port); unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static void @@ -325,7 +302,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status) int saw_console_brk = 0; do { - ch = serial_inp(up, UART_RX); + ch = serial_in(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; @@ -386,7 +363,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status) */ tty_insert_flip_char(port, 0, TTY_OVERRUN); ignore_char: - *status = serial_inp(up, UART_LSR); + *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); if (saw_console_brk) @@ -395,11 +372,12 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status) static void transmit_chars(struct uart_sunsu_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; + unsigned char ch; int count; if (up->port.x_char) { - serial_outp(up, UART_TX, up->port.x_char); + serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; up->port.x_char = 0; return; @@ -408,24 +386,23 @@ static void transmit_chars(struct uart_sunsu_port *up) sunsu_stop_tx(&up->port); return; } - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { __stop_tx(up); return; } count = up->port.fifosize; do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&up->port, &ch)) break; + + serial_out(up, UART_TX, ch); } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) __stop_tx(up); } @@ -456,25 +433,21 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) unsigned long flags; unsigned char status; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); do { - status = serial_inp(up, UART_LSR); + status = serial_in(up, UART_LSR); if (status & UART_LSR_DR) receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); - spin_unlock_irqrestore(&up->port.lock, flags); - tty_flip_buffer_push(&up->port.state->port); - spin_lock_irqsave(&up->port.lock, flags); - } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return IRQ_HANDLED; } @@ -501,7 +474,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up) static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) { do { - unsigned char ch = serial_inp(up, UART_RX); + unsigned char ch = serial_in(up, UART_RX); /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { @@ -514,7 +487,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) switch (ret) { case 2: sunsu_change_mouse_baud(up); - /* fallthru */ + fallthrough; case 1: break; @@ -533,7 +506,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id) struct uart_sunsu_port *up = dev_id; if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) { - unsigned char status = serial_inp(up, UART_LSR); + unsigned char status = serial_in(up, UART_LSR); if ((status & UART_LSR_DR) || (status & UART_LSR_BI)) receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0); @@ -549,9 +522,9 @@ static unsigned int sunsu_tx_empty(struct uart_port *port) unsigned long flags; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return ret; } @@ -603,13 +576,13 @@ static void sunsu_break_ctl(struct uart_port *port, int break_state) container_of(port, struct uart_sunsu_port, port); unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int sunsu_startup(struct uart_port *port) @@ -622,14 +595,14 @@ static int sunsu_startup(struct uart_port *port) if (up->port.type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0; - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_IER, 0); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, 0xBF); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_IER, 0); + serial_out(up, UART_LCR, 0); serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, 0xBF); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0); } #ifdef CONFIG_SERIAL_8250_RSA @@ -645,19 +618,19 @@ static int sunsu_startup(struct uart_port *port) * (they will be reenabled in set_termios()) */ if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); + serial_out(up, UART_FCR, 0); } /* * Clear the interrupt registers. */ - (void) serial_inp(up, UART_LSR); - (void) serial_inp(up, UART_RX); - (void) serial_inp(up, UART_IIR); - (void) serial_inp(up, UART_MSR); + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); /* * At this point, there's no way the LSR could still be 0xff; @@ -665,7 +638,7 @@ static int sunsu_startup(struct uart_port *port) * here. */ if (!(up->port.flags & UPF_BUGGY_UART) && - (serial_inp(up, UART_LSR) == 0xff)) { + (serial_in(up, UART_LSR) == 0xff)) { printk("ttyS%d: LSR safety check engaged!\n", up->port.line); return -ENODEV; } @@ -685,14 +658,14 @@ static int sunsu_startup(struct uart_port *port) /* * Now, initialize the UART */ - serial_outp(up, UART_LCR, UART_LCR_WLEN8); + serial_out(up, UART_LCR, UART_LCR_WLEN8); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->port.mctrl |= TIOCM_OUT2; sunsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Finally, enable interrupts. Note: Modem status interrupts @@ -700,7 +673,7 @@ static int sunsu_startup(struct uart_port *port) * anyway, so we don't enable them here. */ up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_outp(up, UART_IER, up->ier); + serial_out(up, UART_IER, up->ier); if (up->port.flags & UPF_FOURPORT) { unsigned int icp; @@ -715,10 +688,10 @@ static int sunsu_startup(struct uart_port *port) /* * And clear the interrupt registers again for luck. */ - (void) serial_inp(up, UART_LSR); - (void) serial_inp(up, UART_RX); - (void) serial_inp(up, UART_IIR); - (void) serial_inp(up, UART_MSR); + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); return 0; } @@ -733,9 +706,9 @@ static void sunsu_shutdown(struct uart_port *port) * Disable interrupts from this port */ up->ier = 0; - serial_outp(up, UART_IER, 0); + serial_out(up, UART_IER, 0); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (up->port.flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ inb((up->port.iobase & 0xfe0) | 0x1f); @@ -744,16 +717,16 @@ static void sunsu_shutdown(struct uart_port *port) up->port.mctrl &= ~TIOCM_OUT2; sunsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); + serial_out(up, UART_FCR, 0); #ifdef CONFIG_SERIAL_8250_RSA /* @@ -801,10 +774,8 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; -#ifdef CMSPAR if (cflag & CMSPAR) cval |= UART_LCR_SPAR; -#endif /* * Work around a bug in the Oxford Semiconductor 952 rev B @@ -832,7 +803,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Update the per-port timeout. @@ -877,32 +848,32 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, serial_out(up, UART_IER, up->ier); if (uart_config[up->port.type].flags & UART_STARTECH) { - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0); + serial_out(up, UART_LCR, 0xBF); + serial_out(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0); } - 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 */ + serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ if (up->port.type == PORT_16750) - serial_outp(up, UART_FCR, fcr); /* set fcr */ - serial_outp(up, UART_LCR, cval); /* reset DLAB */ + serial_out(up, UART_FCR, fcr); /* set fcr */ + serial_out(up, UART_LCR, cval); /* reset DLAB */ up->lcr = cval; /* Save LCR */ if (up->port.type != PORT_16750) { if (fcr & UART_FCR_ENABLE_FIFO) { /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); } - serial_outp(up, UART_FCR, fcr); /* set fcr */ + serial_out(up, UART_FCR, fcr); /* set fcr */ } up->cflag = cflag; - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static void sunsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud, quot; @@ -1044,7 +1015,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) up->type_probed = PORT_UNKNOWN; up->port.iotype = UPIO_MEM; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (!(up->port.flags & UPF_BUGGY_UART)) { /* @@ -1056,18 +1027,18 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) * 0x80 is a non-existent port; which should be safe since * include/asm/io.h also makes this assumption. */ - scratch = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, 0); + scratch = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); #ifdef __i386__ outb(0xff, 0x080); #endif - scratch2 = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, 0x0f); + scratch2 = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0x0f); #ifdef __i386__ outb(0, 0x080); #endif - scratch3 = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, scratch); + scratch3 = serial_in(up, UART_IER); + serial_out(up, UART_IER, scratch); if (scratch2 != 0 || scratch3 != 0x0F) goto out; /* We failed; there's nothing here */ } @@ -1085,16 +1056,16 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) * that conflicts with COM 1-4 --- we hope! */ if (!(up->port.flags & UPF_SKIP_TEST)) { - serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(up, UART_MSR) & 0xF0; - serial_outp(up, UART_MCR, save_mcr); + serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_in(up, UART_MSR) & 0xF0; + serial_out(up, UART_MCR, save_mcr); if (status1 != 0x90) goto out; /* We failed loopback test */ } - serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */ - serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, 0xBF); /* set up for StarTech test */ + serial_out(up, UART_EFR, 0); /* EFR is the same as FCR */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); scratch = serial_in(up, UART_IIR) >> 6; switch (scratch) { case 0: @@ -1112,19 +1083,19 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) } if (up->port.type == PORT_16550A) { /* Check for Startech UART's */ - serial_outp(up, UART_LCR, UART_LCR_DLAB); + serial_out(up, UART_LCR, UART_LCR_DLAB); if (serial_in(up, UART_EFR) == 0) { up->port.type = PORT_16650; } else { - serial_outp(up, UART_LCR, 0xBF); + serial_out(up, UART_LCR, 0xBF); if (serial_in(up, UART_EFR) == 0) up->port.type = PORT_16650V2; } } if (up->port.type == PORT_16550A) { /* Check for TI 16750 */ - serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB); - serial_outp(up, UART_FCR, + serial_out(up, UART_LCR, save_lcr | UART_LCR_DLAB); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(up, UART_IIR) >> 5; if (scratch == 7) { @@ -1134,24 +1105,24 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) * mode if the UART_FCR7_64BYTE bit was set * while UART_LCR_DLAB was latched. */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(up, UART_IIR) >> 5; if (scratch == 6) up->port.type = PORT_16750; } - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); } - serial_outp(up, UART_LCR, save_lcr); + serial_out(up, UART_LCR, save_lcr); if (up->port.type == PORT_16450) { scratch = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0xa5); + serial_out(up, UART_SCR, 0xa5); status1 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0x5a); + serial_out(up, UART_SCR, 0x5a); status2 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, scratch); + serial_out(up, UART_SCR, scratch); if ((status1 != 0xa5) || (status2 != 0x5a)) up->port.type = PORT_8250; @@ -1168,18 +1139,18 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) */ #ifdef CONFIG_SERIAL_8250_RSA if (up->port.type == PORT_RSA) - serial_outp(up, UART_RSA_FRR, 0); + serial_out(up, UART_RSA_FRR, 0); #endif - serial_outp(up, UART_MCR, save_mcr); - serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | + serial_out(up, UART_MCR, save_mcr); + serial_out(up, UART_FCR, (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); - serial_outp(up, UART_FCR, 0); + serial_out(up, UART_FCR, 0); (void)serial_in(up, UART_RX); - serial_outp(up, UART_IER, 0); + serial_out(up, UART_IER, 0); out: - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static struct uart_driver sunsu_reg = { @@ -1222,13 +1193,13 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up) serio->id.type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "sukbd", sizeof(serio->name)); + strscpy(serio->name, "sukbd", sizeof(serio->name)); } else { serio->id.proto = SERIO_SUN; serio->id.extra = 1; - strlcpy(serio->name, "sums", sizeof(serio->name)); + strscpy(serio->name, "sums", sizeof(serio->name)); } - strlcpy(serio->phys, + strscpy(serio->phys, (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), sizeof(serio->phys)); @@ -1254,8 +1225,6 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up) #ifdef CONFIG_SERIAL_SUNSU_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Wait for transmitter & holding register to empty */ @@ -1273,7 +1242,7 @@ static void wait_for_xmitr(struct uart_sunsu_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { @@ -1284,7 +1253,7 @@ static void wait_for_xmitr(struct uart_sunsu_port *up) } } -static void sunsu_console_putchar(struct uart_port *port, int ch) +static void sunsu_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); @@ -1306,9 +1275,9 @@ static void sunsu_console_write(struct console *co, const char *s, int locked = 1; if (up->port.sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&up->port.lock, flags); + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the UER then disable the interrupts @@ -1326,7 +1295,7 @@ static void sunsu_console_write(struct console *co, const char *s, serial_out(up, UART_IER, ier); if (locked) - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } /* @@ -1389,44 +1358,29 @@ static inline struct console *SUNSU_CONSOLE(void) static enum su_type su_get_type(struct device_node *dp) { - struct device_node *ap = of_find_node_by_path("/aliases"); - enum su_type rc = SU_PORT_PORT; + struct device_node *ap __free(device_node) = + of_find_node_by_path("/aliases"); if (ap) { const char *keyb = of_get_property(ap, "keyboard", NULL); const char *ms = of_get_property(ap, "mouse", NULL); - struct device_node *match; if (keyb) { - match = of_find_node_by_path(keyb); - - /* - * The pointer is used as an identifier not - * as a pointer, we can drop the refcount on - * the of__node immediately after getting it. - */ - of_node_put(match); + struct device_node *match __free(device_node) = + of_find_node_by_path(keyb); - if (dp == match) { - rc = SU_PORT_KBD; - goto out; - } + if (dp == match) + return SU_PORT_KBD; } if (ms) { - match = of_find_node_by_path(ms); + struct device_node *match __free(device_node) = + of_find_node_by_path(ms); - of_node_put(match); - - if (dp == match) { - rc = SU_PORT_MS; - goto out; - } + if (dp == match) + return SU_PORT_MS; } } - -out: - of_node_put(ap); - return rc; + return SU_PORT_PORT; } static int su_probe(struct platform_device *op) @@ -1523,7 +1477,7 @@ out_unmap: return err; } -static int su_remove(struct platform_device *op) +static void su_remove(struct platform_device *op) { struct uart_sunsu_port *up = platform_get_drvdata(op); bool kbdms = false; @@ -1544,8 +1498,6 @@ static int su_remove(struct platform_device *op) if (kbdms) kfree(up); - - return 0; } static const struct of_device_id su_match[] = { diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 103ab8c556e7..0551c24c06f5 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -33,11 +33,11 @@ #include <linux/serio.h> #endif #include <linux/init.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> -#include <asm/prom.h> #include <asm/setup.h> #include <linux/serial_core.h> @@ -100,7 +100,7 @@ struct uart_sunzilog_port { #endif }; -static void sunzilog_putchar(struct uart_port *port, int ch); +static void sunzilog_putchar(struct uart_port *port, unsigned char ch); #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) @@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, switch (ret) { case 2: sunzilog_change_mouse_baud(up); - /* fallthru */ + fallthrough; case 1: break; @@ -453,7 +453,8 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, struct zilog_channel __iomem *channel) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char ch; if (ZS_IS_CONS(up)) { unsigned char status = readb(&channel->control); @@ -496,22 +497,20 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, if (up->port.state == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; + tport = &up->port.state->port; if (uart_tx_stopped(&up->port)) goto ack_tx_int; + if (!uart_fifo_get(&up->port, &ch)) + goto ack_tx_int; + up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); return; @@ -532,7 +531,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) struct tty_port *port; unsigned char r3; - spin_lock(&up->port.lock); + uart_port_lock(&up->port); r3 = read_zsreg(channel, R3); /* Channel A */ @@ -549,7 +548,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) if (r3 & CHATxIP) sunzilog_transmit_chars(up, channel); } - spin_unlock(&up->port.lock); + uart_port_unlock(&up->port); if (port) tty_flip_buffer_push(port); @@ -558,7 +557,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) up = up->next; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - spin_lock(&up->port.lock); + uart_port_lock(&up->port); port = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { writeb(RES_H_IUS, &channel->control); @@ -572,7 +571,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) if (r3 & CHBTxIP) sunzilog_transmit_chars(up, channel); } - spin_unlock(&up->port.lock); + uart_port_unlock(&up->port); if (port) tty_flip_buffer_push(port); @@ -605,11 +604,11 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port) unsigned char status; unsigned int ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); status = sunzilog_read_channel_status(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); if (status & Tx_BUF_EMP) ret = TIOCSER_TEMT; @@ -701,18 +700,16 @@ static void sunzilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&up->port, &ch)) return; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); } } @@ -766,7 +763,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state) else clear_bits |= SND_BRK; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; if (new_reg != up->curregs[R5]) { @@ -776,7 +773,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state) write_zsreg(channel, R5, up->curregs[R5]); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void __sunzilog_startup(struct uart_sunzilog_port *up) @@ -802,9 +799,9 @@ static int sunzilog_startup(struct uart_port *port) if (ZS_IS_CONS(up)) return 0; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); __sunzilog_startup(up); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -842,7 +839,7 @@ static void sunzilog_shutdown(struct uart_port *port) if (ZS_IS_CONS(up)) return; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); channel = ZILOG_CHANNEL_FROM_PORT(port); @@ -855,7 +852,7 @@ static void sunzilog_shutdown(struct uart_port *port) up->curregs[R5] &= ~SND_BRK; sunzilog_maybe_update_regs(up, channel); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* Shared by TTY driver and serial console setup. The port lock is held @@ -938,7 +935,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_sunzilog_port *up = container_of(port, struct uart_sunzilog_port, port); @@ -947,7 +944,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 1200, 76800); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); @@ -964,7 +961,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static const char *sunzilog_type(struct uart_port *port) @@ -1125,7 +1122,7 @@ static void sunzilog_free_tables(void) #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ -static void sunzilog_putchar(struct uart_port *port, int ch) +static void __maybe_unused sunzilog_putchar(struct uart_port *port, unsigned char ch) { struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); int loops = ZS_PUT_CHAR_MAX_DELAY; @@ -1203,15 +1200,15 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) int locked = 1; if (up->port.sysrq || oops_in_progress) - locked = spin_trylock_irqsave(&up->port.lock, flags); + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); uart_console_write(&up->port, s, count, sunzilog_putchar); udelay(2); if (locked) - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static int __init sunzilog_console_setup(struct console *con, char *options) @@ -1221,7 +1218,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) int baud, brg; if (up->port.type != PORT_SUNZILOG) - return -1; + return -EINVAL; printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n", (sunzilog_reg.minor - 64) + con->index, con->index); @@ -1246,7 +1243,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->curregs[R15] |= BRKIE; sunzilog_convert_to_zs(up, con->cflag, 0, brg); @@ -1254,7 +1251,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); __sunzilog_startup(up); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return 0; } @@ -1307,13 +1304,13 @@ static void sunzilog_register_serio(struct uart_sunzilog_port *up) serio->id.type = SERIO_RS232; if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "zskbd", sizeof(serio->name)); + strscpy(serio->name, "zskbd", sizeof(serio->name)); } else { serio->id.proto = SERIO_SUN; serio->id.extra = 1; - strlcpy(serio->name, "zsms", sizeof(serio->name)); + strscpy(serio->name, "zsms", sizeof(serio->name)); } - strlcpy(serio->phys, + strscpy(serio->phys, ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ? "zs/serio0" : "zs/serio1"), sizeof(serio->phys)); @@ -1335,7 +1332,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up) channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (ZS_IS_CHANNEL_A(up)) { write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); @@ -1385,7 +1382,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up) write_zsreg(channel, R9, up->curregs[R9]); } - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); #ifdef CONFIG_SERIO if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | @@ -1405,7 +1402,7 @@ static int zs_probe(struct platform_device *op) int keyboard_mouse = 0; int err; - if (of_find_property(op->dev.of_node, "keyboard", NULL)) + if (of_property_present(op->dev.of_node, "keyboard")) keyboard_mouse = 1; /* uarts must come before keyboards/mice */ @@ -1515,7 +1512,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up) uart_remove_one_port(&sunzilog_reg, &up->port); } -static int zs_remove(struct platform_device *op) +static void zs_remove(struct platform_device *op) { struct uart_sunzilog_port *up = platform_get_drvdata(op); struct zilog_layout __iomem *regs; @@ -1525,8 +1522,6 @@ static int zs_remove(struct platform_device *op) regs = sunzilog_chip_regs[up[0].port.line / 2]; of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); - - return 0; } static const struct of_device_id zs_match[] = { @@ -1555,7 +1550,7 @@ static int __init sunzilog_init(void) for_each_node_by_name(dp, "zs") { num_sunzilog++; - if (of_find_property(dp, "keyboard", NULL)) + if (of_property_present(dp, "keyboard")) num_keybms++; } diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index aaf8748a6147..7033dbfe8ba1 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -7,7 +7,6 @@ #include <linux/mailbox_client.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/serial.h> #include <linux/serial_core.h> @@ -92,16 +91,18 @@ static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s, static void tegra_tcu_uart_start_tx(struct uart_port *port) { struct tegra_tcu *tcu = port->private_data; - struct circ_buf *xmit = &port->state->xmit; - unsigned long count; + struct tty_port *tport = &port->state->port; + unsigned char *tail; + unsigned int count; for (;;) { - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); if (!count) break; - tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count); - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + tegra_tcu_write(tcu, tail, count); + uart_xmit_advance(port, count); } uart_write_wakeup(port); @@ -126,7 +127,7 @@ static void tegra_tcu_uart_shutdown(struct uart_port *port) static void tegra_tcu_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { } @@ -195,13 +196,6 @@ static int tegra_tcu_probe(struct platform_device *pdev) return err; } - tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); - if (IS_ERR(tcu->rx)) { - err = PTR_ERR(tcu->rx); - dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); - goto free_tx; - } - #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) /* setup the console */ strcpy(tcu->console.name, "ttyTCU"); @@ -226,7 +220,7 @@ static int tegra_tcu_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "failed to register UART driver: %d\n", err); - goto free_rx; + goto free_tx; } /* setup the port */ @@ -246,6 +240,17 @@ static int tegra_tcu_probe(struct platform_device *pdev) goto unregister_uart; } + /* + * Request RX channel after creating port to ensure tcu->port + * is ready for any immediate incoming bytes. + */ + tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); + if (IS_ERR(tcu->rx)) { + err = PTR_ERR(tcu->rx); + dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); + goto remove_uart_port; + } + platform_set_drvdata(pdev, tcu); #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) register_console(&tcu->console); @@ -253,35 +258,34 @@ static int tegra_tcu_probe(struct platform_device *pdev) return 0; +remove_uart_port: + uart_remove_one_port(&tcu->driver, &tcu->port); unregister_uart: uart_unregister_driver(&tcu->driver); -free_rx: - mbox_free_channel(tcu->rx); free_tx: mbox_free_channel(tcu->tx); return err; } -static int tegra_tcu_remove(struct platform_device *pdev) +static void tegra_tcu_remove(struct platform_device *pdev) { struct tegra_tcu *tcu = platform_get_drvdata(pdev); #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) unregister_console(&tcu->console); #endif + mbox_free_channel(tcu->rx); uart_remove_one_port(&tcu->driver, &tcu->port); uart_unregister_driver(&tcu->driver); - mbox_free_channel(tcu->rx); mbox_free_channel(tcu->tx); - - return 0; } static const struct of_device_id tegra_tcu_match[] = { { .compatible = "nvidia,tegra194-tcu" }, { } }; +MODULE_DEVICE_TABLE(of, tegra_tcu_match); static struct platform_driver tegra_tcu_driver = { .driver = { diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c new file mode 100644 index 000000000000..0c70d3e7b9b9 --- /dev/null +++ b/drivers/tty/serial/tegra-utc.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// NVIDIA Tegra UTC (UART Trace Controller) driver. + +#include <linux/bits.h> +#include <linux/console.h> +#include <linux/container_of.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/kfifo.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/types.h> + +#define TEGRA_UTC_ENABLE 0x000 +#define TEGRA_UTC_ENABLE_CLIENT_ENABLE BIT(0) + +#define TEGRA_UTC_FIFO_THRESHOLD 0x008 + +#define TEGRA_UTC_COMMAND 0x00c +#define TEGRA_UTC_COMMAND_RESET BIT(0) +#define TEGRA_UTC_COMMAND_FLUSH BIT(1) + +#define TEGRA_UTC_DATA 0x020 + +#define TEGRA_UTC_FIFO_STATUS 0x100 +#define TEGRA_UTC_FIFO_EMPTY BIT(0) +#define TEGRA_UTC_FIFO_FULL BIT(1) +#define TEGRA_UTC_FIFO_REQ BIT(2) +#define TEGRA_UTC_FIFO_OVERFLOW BIT(3) +#define TEGRA_UTC_FIFO_TIMEOUT BIT(4) + +#define TEGRA_UTC_FIFO_OCCUPANCY 0x104 + +#define TEGRA_UTC_INTR_STATUS 0x108 +#define TEGRA_UTC_INTR_SET 0x10c +#define TEGRA_UTC_INTR_MASK 0x110 +#define TEGRA_UTC_INTR_CLEAR 0x114 +#define TEGRA_UTC_INTR_EMPTY BIT(0) +#define TEGRA_UTC_INTR_FULL BIT(1) +#define TEGRA_UTC_INTR_REQ BIT(2) +#define TEGRA_UTC_INTR_OVERFLOW BIT(3) +#define TEGRA_UTC_INTR_TIMEOUT BIT(4) + +#define TEGRA_UTC_UART_NR 16 + +#define TEGRA_UTC_INTR_COMMON (TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_FULL | TEGRA_UTC_INTR_EMPTY) + +struct tegra_utc_port { +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE) + struct console console; +#endif + struct uart_port port; + + void __iomem *rx_base; + void __iomem *tx_base; + + u32 tx_irqmask; + u32 rx_irqmask; + + unsigned int fifosize; + u32 tx_threshold; + u32 rx_threshold; +}; + +static u32 tegra_utc_rx_readl(struct tegra_utc_port *tup, unsigned int offset) +{ + void __iomem *addr = tup->rx_base + offset; + + return readl_relaxed(addr); +} + +static void tegra_utc_rx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset) +{ + void __iomem *addr = tup->rx_base + offset; + + writel_relaxed(val, addr); +} + +static u32 tegra_utc_tx_readl(struct tegra_utc_port *tup, unsigned int offset) +{ + void __iomem *addr = tup->tx_base + offset; + + return readl_relaxed(addr); +} + +static void tegra_utc_tx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset) +{ + void __iomem *addr = tup->tx_base + offset; + + writel_relaxed(val, addr); +} + +static void tegra_utc_enable_tx_irq(struct tegra_utc_port *tup) +{ + tup->tx_irqmask = TEGRA_UTC_INTR_REQ; + + tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK); + tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET); +} + +static void tegra_utc_disable_tx_irq(struct tegra_utc_port *tup) +{ + tup->tx_irqmask = 0x0; + + tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK); + tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET); +} + +static void tegra_utc_stop_tx(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + tegra_utc_disable_tx_irq(tup); +} + +static void tegra_utc_init_tx(struct tegra_utc_port *tup) +{ + /* Disable TX. */ + tegra_utc_tx_writel(tup, 0x0, TEGRA_UTC_ENABLE); + + /* Update the FIFO Threshold. */ + tegra_utc_tx_writel(tup, tup->tx_threshold, TEGRA_UTC_FIFO_THRESHOLD); + + /* Clear and mask all the interrupts. */ + tegra_utc_tx_writel(tup, TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR); + tegra_utc_disable_tx_irq(tup); + + /* Enable TX. */ + tegra_utc_tx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE); +} + +static void tegra_utc_init_rx(struct tegra_utc_port *tup) +{ + tup->rx_irqmask = TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_TIMEOUT; + + tegra_utc_rx_writel(tup, TEGRA_UTC_COMMAND_RESET, TEGRA_UTC_COMMAND); + tegra_utc_rx_writel(tup, tup->rx_threshold, TEGRA_UTC_FIFO_THRESHOLD); + + /* Clear all the pending interrupts. */ + tegra_utc_rx_writel(tup, TEGRA_UTC_INTR_TIMEOUT | TEGRA_UTC_INTR_OVERFLOW | + TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR); + tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK); + tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET); + + /* Enable RX. */ + tegra_utc_rx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE); +} + +static bool tegra_utc_tx_chars(struct tegra_utc_port *tup) +{ + struct uart_port *port = &tup->port; + unsigned int pending; + u8 c; + + pending = uart_port_tx(port, c, + !(tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_FULL), + tegra_utc_tx_writel(tup, c, TEGRA_UTC_DATA)); + + return pending; +} + +static void tegra_utc_rx_chars(struct tegra_utc_port *tup) +{ + struct tty_port *port = &tup->port.state->port; + unsigned int max_chars = 256; + u32 status; + int sysrq; + u32 ch; + + while (max_chars--) { + status = tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS); + if (status & TEGRA_UTC_FIFO_EMPTY) + break; + + ch = tegra_utc_rx_readl(tup, TEGRA_UTC_DATA); + tup->port.icount.rx++; + + if (status & TEGRA_UTC_FIFO_OVERFLOW) + tup->port.icount.overrun++; + + uart_port_unlock(&tup->port); + sysrq = uart_handle_sysrq_char(&tup->port, ch); + uart_port_lock(&tup->port); + + if (!sysrq) + tty_insert_flip_char(port, ch, TTY_NORMAL); + } + + tty_flip_buffer_push(port); +} + +static irqreturn_t tegra_utc_isr(int irq, void *dev_id) +{ + struct tegra_utc_port *tup = dev_id; + unsigned int handled = 0; + u32 status; + + uart_port_lock(&tup->port); + + /* Process RX_REQ and RX_TIMEOUT interrupts. */ + do { + status = tegra_utc_rx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->rx_irqmask; + if (status) { + tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_CLEAR); + tegra_utc_rx_chars(tup); + handled = 1; + } + } while (status); + + /* Process TX_REQ interrupt. */ + do { + status = tegra_utc_tx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->tx_irqmask; + if (status) { + tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_CLEAR); + tegra_utc_tx_chars(tup); + handled = 1; + } + } while (status); + + uart_port_unlock(&tup->port); + + return IRQ_RETVAL(handled); +} + +static unsigned int tegra_utc_tx_empty(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + return tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY) ? 0 : TIOCSER_TEMT; +} + +static void tegra_utc_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int tegra_utc_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void tegra_utc_start_tx(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + if (tegra_utc_tx_chars(tup)) + tegra_utc_enable_tx_irq(tup); +} + +static void tegra_utc_stop_rx(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + tup->rx_irqmask = 0x0; + tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK); + tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET); +} + +static void tegra_utc_hw_init(struct tegra_utc_port *tup) +{ + tegra_utc_init_tx(tup); + tegra_utc_init_rx(tup); +} + +static int tegra_utc_startup(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + int ret; + + tegra_utc_hw_init(tup); + + /* Interrupt is dedicated to this UTC client. */ + ret = request_irq(port->irq, tegra_utc_isr, 0, dev_name(port->dev), tup); + if (ret < 0) + dev_err(port->dev, "failed to register interrupt handler\n"); + + return ret; +} + +static void tegra_utc_shutdown(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + tegra_utc_rx_writel(tup, 0x0, TEGRA_UTC_ENABLE); + free_irq(port->irq, tup); +} + +static void tegra_utc_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old) +{ + /* The Tegra UTC clients supports only 8-N-1 configuration without HW flow control */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag &= ~(CMSPAR | CRTSCTS); + termios->c_cflag |= CS8 | CLOCAL; +} + +#ifdef CONFIG_CONSOLE_POLL + +static int tegra_utc_poll_init(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + tegra_utc_hw_init(tup); + return 0; +} + +static int tegra_utc_get_poll_char(struct uart_port *port) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + if (tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_EMPTY) + return NO_POLL_CHAR; + + return tegra_utc_rx_readl(tup, TEGRA_UTC_DATA); +} + +static void tegra_utc_put_poll_char(struct uart_port *port, unsigned char ch) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + u32 val; + + read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL), + 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS); + + tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA); +} + +#endif + +static const struct uart_ops tegra_utc_uart_ops = { + .tx_empty = tegra_utc_tx_empty, + .set_mctrl = tegra_utc_set_mctrl, + .get_mctrl = tegra_utc_get_mctrl, + .stop_tx = tegra_utc_stop_tx, + .start_tx = tegra_utc_start_tx, + .stop_rx = tegra_utc_stop_rx, + .startup = tegra_utc_startup, + .shutdown = tegra_utc_shutdown, + .set_termios = tegra_utc_set_termios, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = tegra_utc_poll_init, + .poll_get_char = tegra_utc_get_poll_char, + .poll_put_char = tegra_utc_put_poll_char, +#endif +}; + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE) +#define TEGRA_UTC_DEFAULT_FIFO_THRESHOLD 4 +#define TEGRA_UTC_EARLYCON_MAX_BURST_SIZE 128 + +static void tegra_utc_putc(struct uart_port *port, unsigned char c) +{ + writel(c, port->membase + TEGRA_UTC_DATA); +} + +static void tegra_utc_early_write(struct console *con, const char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + + while (n) { + u32 burst_size = TEGRA_UTC_EARLYCON_MAX_BURST_SIZE; + + burst_size -= readl(dev->port.membase + TEGRA_UTC_FIFO_OCCUPANCY); + if (n < burst_size) + burst_size = n; + + uart_console_write(&dev->port, s, burst_size, tegra_utc_putc); + + n -= burst_size; + s += burst_size; + } +} + +static int __init tegra_utc_early_console_setup(struct earlycon_device *device, const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + /* Configure TX */ + writel(TEGRA_UTC_COMMAND_FLUSH | TEGRA_UTC_COMMAND_RESET, + device->port.membase + TEGRA_UTC_COMMAND); + writel(TEGRA_UTC_DEFAULT_FIFO_THRESHOLD, device->port.membase + TEGRA_UTC_FIFO_THRESHOLD); + + /* Clear and mask all the interrupts. */ + writel(TEGRA_UTC_INTR_COMMON, device->port.membase + TEGRA_UTC_INTR_CLEAR); + + writel(0x0, device->port.membase + TEGRA_UTC_INTR_MASK); + writel(0x0, device->port.membase + TEGRA_UTC_INTR_SET); + + /* Enable TX. */ + writel(TEGRA_UTC_ENABLE_CLIENT_ENABLE, device->port.membase + TEGRA_UTC_ENABLE); + + device->con->write = tegra_utc_early_write; + + return 0; +} +OF_EARLYCON_DECLARE(tegra_utc, "nvidia,tegra264-utc", tegra_utc_early_console_setup); + +static void tegra_utc_console_putchar(struct uart_port *port, unsigned char ch) +{ + struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port); + + tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA); +} + +static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_write_context *wctxt) +{ + struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console); + unsigned int len; + char *outbuf; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + outbuf = wctxt->outbuf; + len = wctxt->len; + + while (len) { + u32 burst_size = tup->fifosize; + + burst_size -= tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY); + if (len < burst_size) + burst_size = len; + + uart_console_write(&tup->port, outbuf, burst_size, tegra_utc_console_putchar); + + outbuf += burst_size; + len -= burst_size; + } + + nbcon_exit_unsafe(wctxt); +} + +static void tegra_utc_console_write_thread(struct console *cons, struct nbcon_write_context *wctxt) +{ + struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console); + unsigned int len = READ_ONCE(wctxt->len); + unsigned int i; + u32 val; + + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + + read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL), + 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS); + uart_console_write(&tup->port, wctxt->outbuf + i, 1, tegra_utc_console_putchar); + + if (!nbcon_exit_unsafe(wctxt)) + break; + } +} + +static void tegra_utc_console_device_lock(struct console *cons, unsigned long *flags) +{ + struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console); + struct uart_port *port = &tup->port; + + __uart_port_lock_irqsave(port, flags); +} + +static void tegra_utc_console_device_unlock(struct console *cons, unsigned long flags) +{ + struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console); + struct uart_port *port = &tup->port; + + __uart_port_unlock_irqrestore(port, flags); +} + +static int tegra_utc_console_setup(struct console *cons, char *options) +{ + struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console); + + tegra_utc_init_tx(tup); + + return 0; +} +#endif + +static struct uart_driver tegra_utc_driver = { + .driver_name = "tegra-utc", + .dev_name = "ttyUTC", + .nr = TEGRA_UTC_UART_NR, +}; + +static int tegra_utc_setup_port(struct device *dev, struct tegra_utc_port *tup) +{ + tup->port.dev = dev; + tup->port.fifosize = tup->fifosize; + tup->port.flags = UPF_BOOT_AUTOCONF; + tup->port.iotype = UPIO_MEM; + tup->port.ops = &tegra_utc_uart_ops; + tup->port.type = PORT_TEGRA_TCU; + tup->port.private_data = tup; + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE) + strscpy(tup->console.name, "ttyUTC", sizeof(tup->console.name)); + tup->console.write_atomic = tegra_utc_console_write_atomic; + tup->console.write_thread = tegra_utc_console_write_thread; + tup->console.device_lock = tegra_utc_console_device_lock; + tup->console.device_unlock = tegra_utc_console_device_unlock; + tup->console.device = uart_console_device; + tup->console.setup = tegra_utc_console_setup; + tup->console.flags = CON_PRINTBUFFER | CON_NBCON; + tup->console.data = &tegra_utc_driver; +#endif + + return uart_read_port_properties(&tup->port); +} + +static int tegra_utc_register_port(struct tegra_utc_port *tup) +{ + int ret; + + ret = uart_add_one_port(&tegra_utc_driver, &tup->port); + if (ret) + return ret; + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE) + register_console(&tup->console); +#endif + + return 0; +} + +static int tegra_utc_probe(struct platform_device *pdev) +{ + const unsigned int *soc_fifosize; + struct device *dev = &pdev->dev; + struct tegra_utc_port *tup; + int ret; + + tup = devm_kzalloc(dev, sizeof(*tup), GFP_KERNEL); + if (!tup) + return -ENOMEM; + + ret = device_property_read_u32(dev, "tx-threshold", &tup->tx_threshold); + if (ret) + return dev_err_probe(dev, ret, "missing %s property\n", "tx-threshold"); + + ret = device_property_read_u32(dev, "rx-threshold", &tup->rx_threshold); + if (ret) + return dev_err_probe(dev, ret, "missing %s property\n", "rx-threshold"); + + soc_fifosize = device_get_match_data(dev); + tup->fifosize = *soc_fifosize; + + tup->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx"); + if (IS_ERR(tup->tx_base)) + return PTR_ERR(tup->tx_base); + + tup->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx"); + if (IS_ERR(tup->rx_base)) + return PTR_ERR(tup->rx_base); + + ret = tegra_utc_setup_port(dev, tup); + if (ret) + dev_err_probe(dev, ret, "failed to setup uart port\n"); + + platform_set_drvdata(pdev, tup); + + return tegra_utc_register_port(tup); +} + +static void tegra_utc_remove(struct platform_device *pdev) +{ + struct tegra_utc_port *tup = platform_get_drvdata(pdev); + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE) + unregister_console(&tup->console); +#endif + uart_remove_one_port(&tegra_utc_driver, &tup->port); +} + +static const unsigned int tegra264_utc_soc = 128; + +static const struct of_device_id tegra_utc_of_match[] = { + { .compatible = "nvidia,tegra264-utc", .data = &tegra264_utc_soc }, + {} +}; +MODULE_DEVICE_TABLE(of, tegra_utc_of_match); + +static struct platform_driver tegra_utc_platform_driver = { + .probe = tegra_utc_probe, + .remove = tegra_utc_remove, + .driver = { + .name = "tegra-utc", + .of_match_table = tegra_utc_of_match, + }, +}; + +static int __init tegra_utc_init(void) +{ + int ret; + + ret = uart_register_driver(&tegra_utc_driver); + if (ret) + return ret; + + ret = platform_driver_register(&tegra_utc_platform_driver); + if (ret) + uart_unregister_driver(&tegra_utc_driver); + + return ret; +} +module_init(tegra_utc_init); + +static void __exit tegra_utc_exit(void) +{ + platform_driver_unregister(&tegra_utc_platform_driver); + uart_unregister_driver(&tegra_utc_driver); +} +module_exit(tegra_utc_exit); + +MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>"); +MODULE_DESCRIPTION("Tegra UART Trace Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 19d38b504e27..6fa93c3872a7 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -87,9 +87,7 @@ static void timbuart_rx_chars(struct uart_port *port) tty_insert_flip_char(tport, ch, TTY_NORMAL); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); dev_dbg(port->dev, "%s - total read %d bytes\n", __func__, port->icount.rx); @@ -97,15 +95,11 @@ static void timbuart_rx_chars(struct uart_port *port) static void timbuart_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + unsigned char ch; while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) && - !uart_circ_empty(xmit)) { - iowrite8(xmit->buf[xmit->tail], - port->membase + TIMBUART_TXFIFO); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } + uart_fifo_get(port, &ch)) + iowrite8(ch, port->membase + TIMBUART_TXFIFO); dev_dbg(port->dev, "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", @@ -120,9 +114,9 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) { struct timbuart_port *uart = container_of(port, struct timbuart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; if (port->x_char) @@ -133,7 +127,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) /* clear all TX interrupts */ iowrite32(TXFLAGS, port->membase + TIMBUART_ISR); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } else /* Re-enable any tx interrupt */ @@ -144,7 +138,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) * we wake up the upper layer later when we got the interrupt * to give it some time to go out... */ - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) *ier |= TXBAE; dev_dbg(port->dev, "%s - leaving\n", __func__); @@ -172,12 +166,12 @@ static void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier) dev_dbg(port->dev, "%s - leaving\n", __func__); } -static void timbuart_tasklet(unsigned long arg) +static void timbuart_tasklet(struct tasklet_struct *t) { - struct timbuart_port *uart = (struct timbuart_port *)arg; + struct timbuart_port *uart = from_tasklet(uart, t, tasklet); u32 isr, ier = 0; - spin_lock(&uart->port.lock); + uart_port_lock(&uart->port); isr = ioread32(uart->port.membase + TIMBUART_ISR); dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); @@ -192,7 +186,7 @@ static void timbuart_tasklet(unsigned long arg) iowrite32(ier, uart->port.membase + TIMBUART_IER); - spin_unlock(&uart->port.lock); + uart_port_unlock(&uart->port); dev_dbg(uart->port.dev, "%s leaving\n", __func__); } @@ -277,8 +271,8 @@ static int get_bindex(int baud) } static void timbuart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { unsigned int baud; short bindex; @@ -298,10 +292,10 @@ static void timbuart_set_termios(struct uart_port *port, tty_termios_copy_hw(termios, old); tty_termios_encode_baud_rate(termios, baud, baud); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *timbuart_type(struct uart_port *port) @@ -451,7 +445,7 @@ static int timbuart_probe(struct platform_device *dev) } uart->port.irq = irq; - tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); + tasklet_setup(&uart->tasklet, timbuart_tasklet); err = uart_register_driver(&timbuart_driver); if (err) @@ -476,7 +470,7 @@ err_mem: return err; } -static int timbuart_remove(struct platform_device *dev) +static void timbuart_remove(struct platform_device *dev) { struct timbuart_port *uart = platform_get_drvdata(dev); @@ -484,8 +478,6 @@ static int timbuart_remove(struct platform_device *dev) uart_remove_one_port(&timbuart_driver, &uart->port); uart_unregister_driver(&timbuart_driver); kfree(uart); - - return 0; } static struct platform_driver timbuart_platform_driver = { diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 7dbd0c471d92..39c1fd1ff9ce 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -8,6 +8,7 @@ #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/bitfield.h> #include <linux/console.h> #include <linux/serial.h> #include <linux/serial_core.h> @@ -17,22 +18,26 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_platform.h> #include <linux/clk.h> +#include <linux/pm_runtime.h> #define ULITE_NAME "ttyUL" +#if CONFIG_SERIAL_UARTLITE_NR_UARTS > 4 +#define ULITE_MAJOR 0 /* use dynamic node allocation */ +#define ULITE_MINOR 0 +#else #define ULITE_MAJOR 204 #define ULITE_MINOR 187 +#endif #define ULITE_NR_UARTS CONFIG_SERIAL_UARTLITE_NR_UARTS /* --------------------------------------------------------------------- * Register definitions * * For register details see datasheet: - * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf + * https://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf */ #define ULITE_RX 0x00 @@ -54,15 +59,25 @@ #define ULITE_CONTROL_RST_TX 0x01 #define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_IE 0x10 +#define UART_AUTOSUSPEND_TIMEOUT 3000 /* ms */ /* Static pointer to console port */ #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE static struct uart_port *console_port; #endif +/** + * struct uartlite_data - Driver private data + * @reg_ops: Functions to read/write registers + * @clk: Our parent clock, if present + * @baud: The baud rate configured when this device was synthesized + * @cflags: The cflags for parity and data bits + */ struct uartlite_data { const struct uartlite_reg_ops *reg_ops; struct clk *clk; + unsigned int baud; + tcflag_t cflags; }; struct uartlite_reg_ops { @@ -116,6 +131,8 @@ static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) static struct uart_port ulite_ports[ULITE_NR_UARTS]; +static struct uart_driver ulite_uart_driver; + /* --------------------------------------------------------------------- * Core UART driver operations */ @@ -172,7 +189,8 @@ static int ulite_receive(struct uart_port *port, int stat) static int ulite_transmit(struct uart_port *port, int stat) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; if (stat & ULITE_STATUS_TXFULL) return 0; @@ -184,15 +202,16 @@ static int ulite_transmit(struct uart_port *port, int stat) return 1; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (uart_tx_stopped(port)) return 0; - uart_out32(xmit->buf[xmit->tail], ULITE_TX, port); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); - port->icount.tx++; + if (!uart_fifo_get(port, &ch)) + return 0; + + uart_out32(ch, ULITE_TX, port); /* wake up */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); return 1; @@ -205,11 +224,11 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) unsigned long flags; do { - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); stat = uart_in32(ULITE_STATUS, port); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); n++; } while (busy); @@ -227,9 +246,9 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned long flags; unsigned int ret; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); ret = uart_in32(ULITE_STATUS, port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; } @@ -299,13 +318,20 @@ static void ulite_shutdown(struct uart_port *port) clk_disable(pdata->clk); } -static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static void ulite_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) { unsigned long flags; - unsigned int baud; + struct uartlite_data *pdata = port->private_data; + + /* Set termios to what the hardware supports */ + termios->c_iflag &= ~BRKINT; + termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE); + termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE); + tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN | ULITE_STATUS_TXFULL; @@ -326,10 +352,9 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; /* update timeout */ - baud = uart_get_baud_rate(port, termios, old, 0, 460800); - uart_update_timeout(port, termios->c_cflag, baud); + uart_update_timeout(port, termios->c_cflag, pdata->baud); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *ulite_type(struct uart_port *port) @@ -390,12 +415,16 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) static void ulite_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uartlite_data *pdata = port->private_data; + int ret; - if (!state) - clk_enable(pdata->clk); - else - clk_disable(pdata->clk); + if (!state) { + ret = pm_runtime_get_sync(port->dev); + if (ret < 0) + dev_err(port->dev, "Failed to enable clocks\n"); + } else { + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + } } #ifdef CONFIG_CONSOLE_POLL @@ -448,27 +477,18 @@ static const struct uart_ops ulite_ops = { static void ulite_console_wait_tx(struct uart_port *port) { u8 val; - unsigned long timeout; /* * Spin waiting for TX fifo to have space available. * When using the Microblaze Debug Module this can take up to 1s */ - timeout = jiffies + msecs_to_jiffies(1000); - while (1) { - val = uart_in32(ULITE_STATUS, port); - if ((val & ULITE_STATUS_TXFULL) == 0) - break; - if (time_after(jiffies, timeout)) { - dev_warn(port->dev, - "timeout waiting for TX buffer empty\n"); - break; - } - cpu_relax(); - } + if (read_poll_timeout_atomic(uart_in32, val, !(val & ULITE_STATUS_TXFULL), + 0, 1000000, false, ULITE_STATUS, port)) + dev_warn(port->dev, + "timeout waiting for TX buffer empty\n"); } -static void ulite_console_putchar(struct uart_port *port, int ch) +static void ulite_console_putchar(struct uart_port *port, unsigned char ch) { ulite_console_wait_tx(port); uart_out32(ch, ULITE_TX, port); @@ -483,9 +503,9 @@ static void ulite_console_write(struct console *co, const char *s, int locked = 1; if (oops_in_progress) { - locked = spin_trylock_irqsave(&port->lock, flags); + locked = uart_port_trylock_irqsave(port, &flags); } else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* save and disable interrupt */ ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE; @@ -500,26 +520,28 @@ static void ulite_console_write(struct console *co, const char *s, uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static int ulite_console_setup(struct console *co, char *options) { - struct uart_port *port; + struct uart_port *port = NULL; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; - - port = console_port; + if (co->index >= 0 && co->index < ULITE_NR_UARTS) + port = ulite_ports + co->index; /* Has the device been initialized yet? */ - if (!port->mapbase) { + if (!port || !port->mapbase) { pr_debug("console on ttyUL%i not present\n", co->index); return -ENODEV; } + console_port = port; + /* not initialized yet? */ if (!port->membase) { if (ulite_request_port(port)) @@ -532,8 +554,6 @@ static int ulite_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct uart_driver ulite_uart_driver; - static struct console ulite_console = { .name = ULITE_NAME, .write = ulite_console_write, @@ -544,7 +564,7 @@ static struct console ulite_console = { .data = &ulite_uart_driver, }; -static void early_uartlite_putc(struct uart_port *port, int c) +static void early_uartlite_putc(struct uart_port *port, unsigned char c) { /* * Limit how many times we'll spin waiting for TX FIFO status. @@ -553,16 +573,15 @@ static void early_uartlite_putc(struct uart_port *port, int c) * This limit is pretty arbitrary, unless we are at about 10 baud * we'll never timeout on a working UART. */ - unsigned retries = 1000000; - /* read status bit - 0x8 offset */ - while (--retries && (readl(port->membase + 8) & (1 << 3))) + + while (--retries && + (readl(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)) ; /* Only attempt the iowrite if we didn't timeout */ - /* write to TX_FIFO - 0x4 offset */ if (retries) - writel(c & 0xff, port->membase + 4); + writel(c & 0xff, port->membase + ULITE_TX); } static void early_uartlite_write(struct console *console, @@ -613,7 +632,7 @@ static struct uart_driver ulite_uart_driver = { * * Returns: 0 on success, <0 otherwise */ -static int ulite_assign(struct device *dev, int id, u32 base, int irq, +static int ulite_assign(struct device *dev, int id, phys_addr_t base, int irq, struct uartlite_data *pdata) { struct uart_port *port; @@ -655,17 +674,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, dev_set_drvdata(dev, port); -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE - /* - * If console hasn't been found yet try to assign this port - * because it is required to be assigned for console setup function. - * If register_console() don't assign value, then console_port pointer - * is cleanup. - */ - if (ulite_uart_driver.cons->index == -1) - console_port = port; -#endif - /* Register the port */ rc = uart_add_one_port(&ulite_uart_driver, port); if (rc) { @@ -675,12 +683,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, return rc; } -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE - /* This is not port which is used for console that's why clean it up */ - if (ulite_uart_driver.cons->index == -1) - console_port = NULL; -#endif - return 0; } @@ -688,18 +690,15 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, * * @dev: pointer to device structure */ -static int ulite_release(struct device *dev) +static void ulite_release(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); - int rc = 0; if (port) { - rc = uart_remove_one_port(&ulite_uart_driver, port); + uart_remove_one_port(&ulite_uart_driver, port); dev_set_drvdata(dev, NULL); port->mapbase = 0; } - - return rc; } /** @@ -734,11 +733,38 @@ static int __maybe_unused ulite_resume(struct device *dev) return 0; } +static int __maybe_unused ulite_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct uartlite_data *pdata = port->private_data; + + clk_disable(pdata->clk); + return 0; +}; + +static int __maybe_unused ulite_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct uartlite_data *pdata = port->private_data; + int ret; + + ret = clk_enable(pdata->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + return 0; +} + /* --------------------------------------------------------------------- * Platform bus binding */ -static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume); +static const struct dev_pm_ops ulite_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume) + SET_RUNTIME_PM_OPS(ulite_runtime_suspend, + ulite_runtime_resume, NULL) +}; #if defined(CONFIG_OF) /* Match table for of_platform binding */ @@ -756,25 +782,80 @@ static int ulite_probe(struct platform_device *pdev) struct uartlite_data *pdata; int irq, ret; int id = pdev->id; -#ifdef CONFIG_OF - const __be32 *prop; - prop = of_get_property(pdev->dev.of_node, "port-number", NULL); - if (prop) - id = be32_to_cpup(prop); -#endif pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data), GFP_KERNEL); if (!pdata) return -ENOMEM; + if (IS_ENABLED(CONFIG_OF)) { + const char *prop; + struct device_node *np = pdev->dev.of_node; + u32 val = 0; + + prop = "port-number"; + ret = of_property_read_u32(np, prop, &id); + if (ret && ret != -EINVAL) +of_err: + return dev_err_probe(&pdev->dev, ret, + "could not read %s\n", prop); + + prop = "current-speed"; + ret = of_property_read_u32(np, prop, &pdata->baud); + if (ret) + goto of_err; + + prop = "xlnx,use-parity"; + ret = of_property_read_u32(np, prop, &val); + if (ret && ret != -EINVAL) + goto of_err; + + if (val) { + prop = "xlnx,odd-parity"; + ret = of_property_read_u32(np, prop, &val); + if (ret) + goto of_err; + + if (val) + pdata->cflags |= PARODD; + pdata->cflags |= PARENB; + } + + val = 8; + prop = "xlnx,data-bits"; + ret = of_property_read_u32(np, prop, &val); + if (ret && ret != -EINVAL) + goto of_err; + + switch (val) { + case 5: + pdata->cflags |= CS5; + break; + case 6: + pdata->cflags |= CS6; + break; + case 7: + pdata->cflags |= CS7; + break; + case 8: + pdata->cflags |= CS8; + break; + default: + return dev_err_probe(&pdev->dev, -EINVAL, + "bad data bits %d\n", val); + } + } else { + pdata->baud = 9600; + pdata->cflags = CS8; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -ENXIO; + if (irq < 0) + return irq; pdata->clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); if (IS_ERR(pdata->clk)) { @@ -794,29 +875,29 @@ static int ulite_probe(struct platform_device *pdev) return ret; } - if (!ulite_uart_driver.state) { - dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n"); - ret = uart_register_driver(&ulite_uart_driver); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register driver\n"); - return ret; - } - } + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata); - clk_disable(pdata->clk); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); return ret; } -static int ulite_remove(struct platform_device *pdev) +static void ulite_remove(struct platform_device *pdev) { struct uart_port *port = dev_get_drvdata(&pdev->dev); struct uartlite_data *pdata = port->private_data; clk_disable_unprepare(pdata->clk); - return ulite_release(&pdev->dev); + ulite_release(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); } /* work with hotplug and coldplug */ @@ -838,16 +919,25 @@ static struct platform_driver ulite_platform_driver = { static int __init ulite_init(void) { + int ret; + + pr_debug("uartlite: calling uart_register_driver()\n"); + ret = uart_register_driver(&ulite_uart_driver); + if (ret) + return ret; pr_debug("uartlite: calling platform_driver_register()\n"); - return platform_driver_register(&ulite_platform_driver); + ret = platform_driver_register(&ulite_platform_driver); + if (ret) + uart_unregister_driver(&ulite_uart_driver); + + return ret; } static void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); - if (ulite_uart_driver.state) - uart_unregister_driver(&ulite_uart_driver); + uart_unregister_driver(&ulite_uart_driver); } module_init(ulite_init); diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 3c8c662c69e2..0613f8c11ab1 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -17,18 +17,18 @@ */ #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/io.h> +#include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/of_platform.h> #include <linux/dma-mapping.h> -#include <linux/fs_uart_pd.h> #include <soc/fsl/qe/ucc_slow.h> #include <linux/firmware.h> @@ -59,7 +59,7 @@ static int firmware_loaded; /* #define LOOPBACK */ /* The major and minor device numbers are defined in - * http://www.lanana.org/docs/device-list/devices-2.6+.txt. For the QE + * Documentation/admin-guide/devices.txt. For the QE * UART, we have major number 204 and minor numbers 46 - 49, which are the * same as for the CPM2. This decision was made because no Freescale part * has both a CPM and a QE. @@ -189,10 +189,10 @@ struct uart_qe_port { u16 tx_fifosize; int wait_closing; u32 flags; - struct qe_bd *rx_bd_base; - struct qe_bd *rx_cur; - struct qe_bd *tx_bd_base; - struct qe_bd *tx_cur; + struct qe_bd __iomem *rx_bd_base; + struct qe_bd __iomem *rx_cur; + struct qe_bd __iomem *tx_bd_base; + struct qe_bd __iomem *tx_cur; unsigned char *tx_buf; unsigned char *rx_buf; void *bd_virt; /* virtual address of the BD buffers */ @@ -258,14 +258,14 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) { struct uart_qe_port *qe_port = container_of(port, struct uart_qe_port, port); - struct qe_bd *bdp = qe_port->tx_bd_base; + struct qe_bd __iomem *bdp = qe_port->tx_bd_base; while (1) { - if (qe_ioread16be(&bdp->status) & BD_SC_READY) + if (ioread16be(&bdp->status) & BD_SC_READY) /* This BD is not done, so return "not done" */ return 0; - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) /* * This BD is done and it's the last one, so return * "done" @@ -283,7 +283,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) * don't need that support. This function must exist, however, otherwise * the kernel will panic. */ -void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { } @@ -330,24 +330,24 @@ static void qe_uart_stop_tx(struct uart_port *port) */ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) { - struct qe_bd *bdp; + struct qe_bd __iomem *bdp; unsigned char *p; unsigned int count; struct uart_port *port = &qe_port->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; /* Handle xon/xoff */ if (port->x_char) { /* Pick next descriptor and fill from buffer */ bdp = qe_port->tx_cur; - p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); + p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); *p++ = port->x_char; - qe_iowrite16be(1, &bdp->length); + iowrite16be(1, &bdp->length); qe_setbits_be16(&bdp->status, BD_SC_READY); /* Get next BD. */ - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) bdp = qe_port->tx_bd_base; else bdp++; @@ -358,7 +358,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) return 1; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { qe_uart_stop_tx(port); return 0; } @@ -366,34 +366,26 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) /* Pick next descriptor and fill from buffer */ bdp = qe_port->tx_cur; - while (!(qe_ioread16be(&bdp->status) & BD_SC_READY) && - (xmit->tail != xmit->head)) { - count = 0; - p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); - while (count < qe_port->tx_fifosize) { - *p++ = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - count++; - if (xmit->head == xmit->tail) - break; - } + while (!(ioread16be(&bdp->status) & BD_SC_READY) && + !kfifo_is_empty(&tport->xmit_fifo)) { + p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); + count = uart_fifo_out(port, p, qe_port->tx_fifosize); - qe_iowrite16be(count, &bdp->length); + iowrite16be(count, &bdp->length); qe_setbits_be16(&bdp->status, BD_SC_READY); /* Get next BD. */ - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) bdp = qe_port->tx_bd_base; else bdp++; } qe_port->tx_cur = bdp; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { /* The kernel buffer is empty, so turn off TX interrupts. We don't need to be told when the QE is finished transmitting the data. */ @@ -416,7 +408,7 @@ static void qe_uart_start_tx(struct uart_port *port) container_of(port, struct uart_qe_port, port); /* If we currently are transmitting, then just return */ - if (qe_ioread16be(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) + if (ioread16be(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) return; /* Otherwise, pump the port and start transmission */ @@ -462,7 +454,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) unsigned char ch, *cp; struct uart_port *port = &qe_port->port; struct tty_port *tport = &port->state->port; - struct qe_bd *bdp; + struct qe_bd __iomem *bdp; u16 status; unsigned int flg; @@ -471,14 +463,14 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) */ bdp = qe_port->rx_cur; while (1) { - status = qe_ioread16be(&bdp->status); + status = ioread16be(&bdp->status); /* If this one is empty, then we assume we've read them all */ if (status & BD_SC_EMPTY) break; /* get number of characters, and check space in RX buffer */ - i = qe_ioread16be(&bdp->length); + i = ioread16be(&bdp->length); /* If we don't have enough room in RX buffer for the entire BD, * then we try later, which will be the next RX interrupt. @@ -489,7 +481,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) } /* get pointer */ - cp = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); + cp = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); /* loop through the buffer */ while (i-- > 0) { @@ -512,7 +504,7 @@ error_return: qe_clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID, BD_SC_EMPTY); - if (qe_ioread16be(&bdp->status) & BD_SC_WRAP) + if (ioread16be(&bdp->status) & BD_SC_WRAP) bdp = qe_port->rx_bd_base; else bdp++; @@ -569,8 +561,8 @@ static irqreturn_t qe_uart_int(int irq, void *data) u16 events; /* Clear the interrupts */ - events = qe_ioread16be(&uccp->ucce); - qe_iowrite16be(events, &uccp->ucce); + events = ioread16be(&uccp->ucce); + iowrite16be(events, &uccp->ucce); if (events & UCC_UART_UCCE_BRKE) uart_handle_break(&qe_port->port); @@ -592,7 +584,7 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) { int i; void *bd_virt; - struct qe_bd *bdp; + struct qe_bd __iomem *bdp; /* Set the physical address of the host memory buffers in the buffer * descriptors, and the virtual address for us to work with. @@ -601,17 +593,17 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) bdp = qe_port->rx_bd_base; qe_port->rx_cur = qe_port->rx_bd_base; for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) { - qe_iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); bd_virt += qe_port->rx_fifosize; bdp++; } /* */ - qe_iowrite16be(BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -622,9 +614,9 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) qe_port->tx_cur = qe_port->tx_bd_base; bdp = qe_port->tx_bd_base; for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) { - qe_iowrite16be(BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); bd_virt += qe_port->tx_fifosize; bdp++; } @@ -634,9 +626,9 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) qe_setbits_be16(&qe_port->tx_cur->status, BD_SC_P); #endif - qe_iowrite16be(BD_SC_WRAP | BD_SC_INTRPT, &bdp->status); - qe_iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); - qe_iowrite16be(0, &bdp->length); + iowrite16be(BD_SC_WRAP | BD_SC_INTRPT, &bdp->status); + iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); + iowrite16be(0, &bdp->length); } /* @@ -650,7 +642,7 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) { u32 cecr_subblock; struct ucc_slow __iomem *uccp = qe_port->uccp; - struct ucc_uart_pram *uccup = qe_port->uccup; + struct ucc_uart_pram __iomem *uccup = qe_port->uccup; unsigned int i; @@ -658,21 +650,21 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); /* Program the UCC UART parameter RAM */ - qe_iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.rbmr); - qe_iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.tbmr); - qe_iowrite16be(qe_port->rx_fifosize, &uccup->common.mrblr); - qe_iowrite16be(0x10, &uccup->maxidl); - qe_iowrite16be(1, &uccup->brkcr); - qe_iowrite16be(0, &uccup->parec); - qe_iowrite16be(0, &uccup->frmec); - qe_iowrite16be(0, &uccup->nosec); - qe_iowrite16be(0, &uccup->brkec); - qe_iowrite16be(0, &uccup->uaddr[0]); - qe_iowrite16be(0, &uccup->uaddr[1]); - qe_iowrite16be(0, &uccup->toseq); + iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.rbmr); + iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.tbmr); + iowrite16be(qe_port->rx_fifosize, &uccup->common.mrblr); + iowrite16be(0x10, &uccup->maxidl); + iowrite16be(1, &uccup->brkcr); + iowrite16be(0, &uccup->parec); + iowrite16be(0, &uccup->frmec); + iowrite16be(0, &uccup->nosec); + iowrite16be(0, &uccup->brkec); + iowrite16be(0, &uccup->uaddr[0]); + iowrite16be(0, &uccup->uaddr[1]); + iowrite16be(0, &uccup->toseq); for (i = 0; i < 8; i++) - qe_iowrite16be(0xC000, &uccup->cchars[i]); - qe_iowrite16be(0xc0ff, &uccup->rccm); + iowrite16be(0xC000, &uccup->cchars[i]); + iowrite16be(0xc0ff, &uccup->rccm); /* Configure the GUMR registers for UART */ if (soft_uart) { @@ -702,30 +694,30 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) #endif /* Disable rx interrupts and clear all pending events. */ - qe_iowrite16be(0, &uccp->uccm); - qe_iowrite16be(0xffff, &uccp->ucce); - qe_iowrite16be(0x7e7e, &uccp->udsr); + iowrite16be(0, &uccp->uccm); + iowrite16be(0xffff, &uccp->ucce); + iowrite16be(0x7e7e, &uccp->udsr); /* Initialize UPSMR */ - qe_iowrite16be(0, &uccp->upsmr); + iowrite16be(0, &uccp->upsmr); if (soft_uart) { - qe_iowrite16be(0x30, &uccup->supsmr); - qe_iowrite16be(0, &uccup->res92); - qe_iowrite32be(0, &uccup->rx_state); - qe_iowrite32be(0, &uccup->rx_cnt); - qe_iowrite8(0, &uccup->rx_bitmark); - qe_iowrite8(10, &uccup->rx_length); - qe_iowrite32be(0x4000, &uccup->dump_ptr); - qe_iowrite8(0, &uccup->rx_temp_dlst_qe); - qe_iowrite32be(0, &uccup->rx_frame_rem); - qe_iowrite8(0, &uccup->rx_frame_rem_size); + iowrite16be(0x30, &uccup->supsmr); + iowrite16be(0, &uccup->res92); + iowrite32be(0, &uccup->rx_state); + iowrite32be(0, &uccup->rx_cnt); + iowrite8(0, &uccup->rx_bitmark); + iowrite8(10, &uccup->rx_length); + iowrite32be(0x4000, &uccup->dump_ptr); + iowrite8(0, &uccup->rx_temp_dlst_qe); + iowrite32be(0, &uccup->rx_frame_rem); + iowrite8(0, &uccup->rx_frame_rem_size); /* Soft-UART requires TX to be 1X */ - qe_iowrite8(UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1, + iowrite8(UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1, &uccup->tx_mode); - qe_iowrite16be(0, &uccup->tx_state); - qe_iowrite8(0, &uccup->resD4); - qe_iowrite16be(0, &uccup->resD5); + iowrite16be(0, &uccup->tx_state); + iowrite8(0, &uccup->resD4); + iowrite16be(0, &uccup->resD5); /* Set UART mode. * Enable receive and transmit. @@ -843,23 +835,17 @@ static void qe_uart_shutdown(struct uart_port *port) * Set the serial port parameters. */ static void qe_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { struct uart_qe_port *qe_port = container_of(port, struct uart_qe_port, port); struct ucc_slow __iomem *uccp = qe_port->uccp; unsigned int baud; unsigned long flags; - u16 upsmr = qe_ioread16be(&uccp->upsmr); + u16 upsmr = ioread16be(&uccp->upsmr); struct ucc_uart_pram __iomem *uccup = qe_port->uccup; - u16 supsmr = qe_ioread16be(&uccup->supsmr); - u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */ - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ + u16 supsmr = ioread16be(&uccup->supsmr); /* byte size */ upsmr &= UCC_UART_UPSMR_CL_MASK; @@ -869,22 +855,18 @@ static void qe_uart_set_termios(struct uart_port *port, case CS5: upsmr |= UCC_UART_UPSMR_CL_5; supsmr |= UCC_UART_SUPSMR_CL_5; - char_length += 5; break; case CS6: upsmr |= UCC_UART_UPSMR_CL_6; supsmr |= UCC_UART_SUPSMR_CL_6; - char_length += 6; break; case CS7: upsmr |= UCC_UART_UPSMR_CL_7; supsmr |= UCC_UART_SUPSMR_CL_7; - char_length += 7; break; default: /* case CS8 */ upsmr |= UCC_UART_UPSMR_CL_8; supsmr |= UCC_UART_SUPSMR_CL_8; - char_length += 8; break; } @@ -892,13 +874,11 @@ static void qe_uart_set_termios(struct uart_port *port, if (termios->c_cflag & CSTOPB) { upsmr |= UCC_UART_UPSMR_SL; supsmr |= UCC_UART_SUPSMR_SL; - char_length++; /* + SL */ } if (termios->c_cflag & PARENB) { upsmr |= UCC_UART_UPSMR_PEN; supsmr |= UCC_UART_SUPSMR_PEN; - char_length++; /* + PEN */ if (!(termios->c_cflag & PARODD)) { upsmr &= ~(UCC_UART_UPSMR_RPM_MASK | @@ -945,15 +925,15 @@ static void qe_uart_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); /* Do we really need a spinlock here? */ - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); - qe_iowrite16be(upsmr, &uccp->upsmr); + iowrite16be(upsmr, &uccp->upsmr); if (soft_uart) { - qe_iowrite16be(supsmr, &uccup->supsmr); - qe_iowrite8(char_length, &uccup->rx_length); + iowrite16be(supsmr, &uccup->supsmr); + iowrite8(tty_get_frame_size(termios->c_cflag), &uccup->rx_length); /* Soft-UART requires a 1X multiplier for TX */ qe_setbrg(qe_port->us_info.rx_clock, baud, 16); @@ -963,7 +943,7 @@ static void qe_uart_set_termios(struct uart_port *port, qe_setbrg(qe_port->us_info.tx_clock, baud, 16); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* @@ -997,7 +977,7 @@ static int qe_uart_request_port(struct uart_port *port) qe_port->us_private = uccs; qe_port->uccp = uccs->us_regs; - qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram; + qe_port->uccup = (struct ucc_uart_pram __iomem *)uccs->us_pram; qe_port->rx_bd_base = uccs->rx_bd; qe_port->tx_bd_base = uccs->tx_bd; @@ -1065,7 +1045,7 @@ static int qe_uart_verify_port(struct uart_port *port, if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) return -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) return -EINVAL; if (ser->baud_base < 9600) @@ -1137,6 +1117,8 @@ static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) /* No compatible property, so try the name. */ soc_string = np->name; + of_node_put(np); + /* Extract the SOC number from the "PowerPC," string */ if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) return 0; @@ -1168,7 +1150,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context) firmware = (struct qe_firmware *) fw->data; - if (firmware->header.length != fw->size) { + if (be32_to_cpu(firmware->header.length) != fw->size) { dev_err(dev, "invalid firmware\n"); goto out; } @@ -1190,7 +1172,7 @@ static int soft_uart_init(struct platform_device *ofdev) struct qe_firmware_info *qe_fw_info; int ret; - if (of_find_property(np, "soft-uart", NULL)) { + if (of_property_read_bool(np, "soft-uart")) { dev_dbg(&ofdev->dev, "using Soft-UART mode\n"); soft_uart = 1; } else { @@ -1227,7 +1209,7 @@ static int soft_uart_init(struct platform_device *ofdev) * kernel, then we use it. */ ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, filename, &ofdev->dev, + FW_ACTION_UEVENT, filename, &ofdev->dev, GFP_KERNEL, &ofdev->dev, uart_firmware_cont); if (ret) { dev_err(&ofdev->dev, @@ -1471,7 +1453,7 @@ out_free: return ret; } -static int ucc_uart_remove(struct platform_device *ofdev) +static void ucc_uart_remove(struct platform_device *ofdev) { struct uart_qe_port *qe_port = platform_get_drvdata(ofdev); @@ -1479,9 +1461,9 @@ static int ucc_uart_remove(struct platform_device *ofdev) uart_remove_one_port(&ucc_uart_driver, &qe_port->port); - kfree(qe_port); + of_node_put(qe_port->np); - return 0; + kfree(qe_port); } static const struct of_device_id ucc_uart_match[] = { diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c deleted file mode 100644 index eeb4b6568776..000000000000 --- a/drivers/tty/serial/vr41xx_siu.c +++ /dev/null @@ -1,947 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for NEC VR4100 series Serial Interface Unit. - * - * Copyright (C) 2004-2008 Yoichi Yuasa <yuasa@linux-mips.org> - * - * Based on drivers/serial/8250.c, by Russell King. - */ - -#include <linux/console.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/serial.h> -#include <linux/serial_core.h> -#include <linux/serial_reg.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> - -#include <asm/io.h> -#include <asm/vr41xx/siu.h> -#include <asm/vr41xx/vr41xx.h> - -#define SIU_BAUD_BASE 1152000 -#define SIU_MAJOR 204 -#define SIU_MINOR_BASE 82 - -#define RX_MAX_COUNT 256 -#define TX_MAX_COUNT 15 - -#define SIUIRSEL 0x08 - #define TMICMODE 0x20 - #define TMICTX 0x10 - #define IRMSEL 0x0c - #define IRMSEL_HP 0x08 - #define IRMSEL_TEMIC 0x04 - #define IRMSEL_SHARP 0x00 - #define IRUSESEL 0x02 - #define SIRSEL 0x01 - -static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { - [0 ... SIU_PORTS_MAX-1] = { - .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), - .irq = 0, - }, -}; - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE -static uint8_t lsr_break_flag[SIU_PORTS_MAX]; -#endif - -#define siu_read(port, offset) readb((port)->membase + (offset)) -#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset)) - -void vr41xx_select_siu_interface(siu_interface_t interface) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - if (interface == SIU_INTERFACE_IRDA) - irsel |= SIRSEL; - else - irsel &= ~SIRSEL; - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface); - -void vr41xx_use_irda(irda_use_t use) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - if (use == FIR_USE_IRDA) - irsel |= IRUSESEL; - else - irsel &= ~IRUSESEL; - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_use_irda); - -void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - irsel &= ~(IRMSEL | TMICTX | TMICMODE); - switch (module) { - case SHARP_IRDA: - irsel |= IRMSEL_SHARP; - break; - case TEMIC_IRDA: - irsel |= IRMSEL_TEMIC | TMICMODE; - if (speed == IRDA_TX_4MBPS) - irsel |= TMICTX; - break; - case HP_IRDA: - irsel |= IRMSEL_HP; - break; - default: - break; - } - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_select_irda_module); - -static inline void siu_clear_fifo(struct uart_port *port) -{ - siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO); - siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - siu_write(port, UART_FCR, 0); -} - -static inline unsigned long siu_port_size(struct uart_port *port) -{ - switch (port->type) { - case PORT_VR41XX_SIU: - return 11UL; - case PORT_VR41XX_DSIU: - return 8UL; - } - - return 0; -} - -static inline unsigned int siu_check_type(struct uart_port *port) -{ - if (port->line == 0) - return PORT_VR41XX_SIU; - if (port->line == 1 && port->irq) - return PORT_VR41XX_DSIU; - - return PORT_UNKNOWN; -} - -static inline const char *siu_type_name(struct uart_port *port) -{ - switch (port->type) { - case PORT_VR41XX_SIU: - return "SIU"; - case PORT_VR41XX_DSIU: - return "DSIU"; - } - - return NULL; -} - -static unsigned int siu_tx_empty(struct uart_port *port) -{ - uint8_t lsr; - - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_TEMT) - return TIOCSER_TEMT; - - return 0; -} - -static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - uint8_t mcr = 0; - - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - siu_write(port, UART_MCR, mcr); -} - -static unsigned int siu_get_mctrl(struct uart_port *port) -{ - uint8_t msr; - unsigned int mctrl = 0; - - msr = siu_read(port, UART_MSR); - if (msr & UART_MSR_DCD) - mctrl |= TIOCM_CAR; - if (msr & UART_MSR_RI) - mctrl |= TIOCM_RNG; - if (msr & UART_MSR_DSR) - mctrl |= TIOCM_DSR; - if (msr & UART_MSR_CTS) - mctrl |= TIOCM_CTS; - - return mctrl; -} - -static void siu_stop_tx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_THRI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_start_tx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier |= UART_IER_THRI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_stop_rx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_RLSI; - siu_write(port, UART_IER, ier); - - port->read_status_mask &= ~UART_LSR_DR; - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_enable_ms(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier |= UART_IER_MSI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_break_ctl(struct uart_port *port, int ctl) -{ - unsigned long flags; - uint8_t lcr; - - spin_lock_irqsave(&port->lock, flags); - - lcr = siu_read(port, UART_LCR); - if (ctl == -1) - lcr |= UART_LCR_SBC; - else - lcr &= ~UART_LCR_SBC; - siu_write(port, UART_LCR, lcr); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static inline void receive_chars(struct uart_port *port, uint8_t *status) -{ - uint8_t lsr, ch; - char flag; - int max_count = RX_MAX_COUNT; - - lsr = *status; - - do { - ch = siu_read(port, UART_RX); - port->icount.rx++; - flag = TTY_NORMAL; - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE - lsr |= lsr_break_flag[port->line]; - lsr_break_flag[port->line] = 0; -#endif - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE | - UART_LSR_PE | UART_LSR_OE))) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - - if (uart_handle_break(port)) - goto ignore_char; - } - - if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_PE) - port->icount.parity++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - lsr &= port->read_status_mask; - if (lsr & UART_LSR_BI) - flag = TTY_BREAK; - if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - - ignore_char: - lsr = siu_read(port, UART_LSR); - } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); - - tty_flip_buffer_push(&port->state->port); - - *status = lsr; -} - -static inline void check_modem_status(struct uart_port *port) -{ - uint8_t msr; - - msr = siu_read(port, UART_MSR); - if ((msr & UART_MSR_ANY_DELTA) == 0) - return; - if (msr & UART_MSR_DDCD) - uart_handle_dcd_change(port, msr & UART_MSR_DCD); - if (msr & UART_MSR_TERI) - port->icount.rng++; - if (msr & UART_MSR_DDSR) - port->icount.dsr++; - if (msr & UART_MSR_DCTS) - uart_handle_cts_change(port, msr & UART_MSR_CTS); - - wake_up_interruptible(&port->state->port.delta_msr_wait); -} - -static inline void transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit; - int max_count = TX_MAX_COUNT; - - xmit = &port->state->xmit; - - if (port->x_char) { - siu_write(port, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - siu_stop_tx(port); - return; - } - - do { - siu_write(port, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (max_count-- > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - siu_stop_tx(port); -} - -static irqreturn_t siu_interrupt(int irq, void *dev_id) -{ - struct uart_port *port; - uint8_t iir, lsr; - - port = (struct uart_port *)dev_id; - - iir = siu_read(port, UART_IIR); - if (iir & UART_IIR_NO_INT) - return IRQ_NONE; - - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(port, &lsr); - - check_modem_status(port); - - if (lsr & UART_LSR_THRE) - transmit_chars(port); - - return IRQ_HANDLED; -} - -static int siu_startup(struct uart_port *port) -{ - int retval; - - if (port->membase == NULL) - return -ENODEV; - - siu_clear_fifo(port); - - (void)siu_read(port, UART_LSR); - (void)siu_read(port, UART_RX); - (void)siu_read(port, UART_IIR); - (void)siu_read(port, UART_MSR); - - if (siu_read(port, UART_LSR) == 0xff) - return -ENODEV; - - retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port); - if (retval) - return retval; - - if (port->type == PORT_VR41XX_DSIU) - vr41xx_enable_dsiuint(DSIUINT_ALL); - - siu_write(port, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irq(&port->lock); - siu_set_mctrl(port, port->mctrl); - spin_unlock_irq(&port->lock); - - siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI); - - (void)siu_read(port, UART_LSR); - (void)siu_read(port, UART_RX); - (void)siu_read(port, UART_IIR); - (void)siu_read(port, UART_MSR); - - return 0; -} - -static void siu_shutdown(struct uart_port *port) -{ - unsigned long flags; - uint8_t lcr; - - siu_write(port, UART_IER, 0); - - spin_lock_irqsave(&port->lock, flags); - - port->mctrl &= ~TIOCM_OUT2; - siu_set_mctrl(port, port->mctrl); - - spin_unlock_irqrestore(&port->lock, flags); - - lcr = siu_read(port, UART_LCR); - lcr &= ~UART_LCR_SBC; - siu_write(port, UART_LCR, lcr); - - siu_clear_fifo(port); - - (void)siu_read(port, UART_RX); - - if (port->type == PORT_VR41XX_DSIU) - vr41xx_disable_dsiuint(DSIUINT_ALL); - - free_irq(port->irq, port); -} - -static void siu_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) -{ - tcflag_t c_cflag, c_iflag; - uint8_t lcr, fcr, ier; - unsigned int baud, quot; - unsigned long flags; - - c_cflag = new->c_cflag; - switch (c_cflag & CSIZE) { - case CS5: - lcr = UART_LCR_WLEN5; - break; - case CS6: - lcr = UART_LCR_WLEN6; - break; - case CS7: - lcr = UART_LCR_WLEN7; - break; - default: - lcr = UART_LCR_WLEN8; - break; - } - - if (c_cflag & CSTOPB) - lcr |= UART_LCR_STOP; - if (c_cflag & PARENB) - lcr |= UART_LCR_PARITY; - if ((c_cflag & PARODD) != PARODD) - lcr |= UART_LCR_EPAR; - if (c_cflag & CMSPAR) - lcr |= UART_LCR_SPAR; - - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; - - spin_lock_irqsave(&port->lock, flags); - - uart_update_timeout(port, c_cflag, baud); - - c_iflag = new->c_iflag; - - port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; - if (c_iflag & INPCK) - port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART_LSR_BI; - - port->ignore_status_mask = 0; - if (c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_LSR_BI; - if (c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_OE; - } - - if ((c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_LSR_DR; - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(port, c_cflag)) - ier |= UART_IER_MSI; - siu_write(port, UART_IER, ier); - - siu_write(port, UART_LCR, lcr | UART_LCR_DLAB); - - siu_write(port, UART_DLL, (uint8_t)quot); - siu_write(port, UART_DLM, (uint8_t)(quot >> 8)); - - siu_write(port, UART_LCR, lcr); - - siu_write(port, UART_FCR, fcr); - - siu_set_mctrl(port, port->mctrl); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) -{ - switch (state) { - case 0: - switch (port->type) { - case PORT_VR41XX_SIU: - vr41xx_supply_clock(SIU_CLOCK); - break; - case PORT_VR41XX_DSIU: - vr41xx_supply_clock(DSIU_CLOCK); - break; - } - break; - case 3: - switch (port->type) { - case PORT_VR41XX_SIU: - vr41xx_mask_clock(SIU_CLOCK); - break; - case PORT_VR41XX_DSIU: - vr41xx_mask_clock(DSIU_CLOCK); - break; - } - break; - } -} - -static const char *siu_type(struct uart_port *port) -{ - return siu_type_name(port); -} - -static void siu_release_port(struct uart_port *port) -{ - unsigned long size; - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - size = siu_port_size(port); - release_mem_region(port->mapbase, size); -} - -static int siu_request_port(struct uart_port *port) -{ - unsigned long size; - struct resource *res; - - size = siu_port_size(port); - res = request_mem_region(port->mapbase, size, siu_type_name(port)); - if (res == NULL) - return -EBUSY; - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_resource(res); - return -ENOMEM; - } - } - - return 0; -} - -static void siu_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = siu_check_type(port); - (void)siu_request_port(port); - } -} - -static int siu_verify_port(struct uart_port *port, struct serial_struct *serial) -{ - if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU) - return -EINVAL; - if (port->irq != serial->irq) - return -EINVAL; - if (port->iotype != serial->io_type) - return -EINVAL; - if (port->mapbase != (unsigned long)serial->iomem_base) - return -EINVAL; - - return 0; -} - -static const struct uart_ops siu_uart_ops = { - .tx_empty = siu_tx_empty, - .set_mctrl = siu_set_mctrl, - .get_mctrl = siu_get_mctrl, - .stop_tx = siu_stop_tx, - .start_tx = siu_start_tx, - .stop_rx = siu_stop_rx, - .enable_ms = siu_enable_ms, - .break_ctl = siu_break_ctl, - .startup = siu_startup, - .shutdown = siu_shutdown, - .set_termios = siu_set_termios, - .pm = siu_pm, - .type = siu_type, - .release_port = siu_release_port, - .request_port = siu_request_port, - .config_port = siu_config_port, - .verify_port = siu_verify_port, -}; - -static int siu_init_ports(struct platform_device *pdev) -{ - struct uart_port *port; - struct resource *res; - int *type = dev_get_platdata(&pdev->dev); - int i; - - if (!type) - return 0; - - port = siu_uart_ports; - for (i = 0; i < SIU_PORTS_MAX; i++) { - port->type = type[i]; - if (port->type == PORT_UNKNOWN) - continue; - port->irq = platform_get_irq(pdev, i); - port->uartclk = SIU_BAUD_BASE * 16; - port->fifosize = 16; - port->regshift = 0; - port->iotype = UPIO_MEM; - port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - port->line = i; - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - port->mapbase = res->start; - port++; - } - - return i; -} - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static void wait_for_xmitr(struct uart_port *port) -{ - int timeout = 10000; - uint8_t lsr, msr; - - do { - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_BI) - lsr_break_flag[port->line] = UART_LSR_BI; - - if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) - break; - } while (timeout-- > 0); - - if (port->flags & UPF_CONS_FLOW) { - timeout = 1000000; - - do { - msr = siu_read(port, UART_MSR); - if ((msr & UART_MSR_CTS) != 0) - break; - } while (timeout-- > 0); - } -} - -static void siu_console_putchar(struct uart_port *port, int ch) -{ - wait_for_xmitr(port); - siu_write(port, UART_TX, ch); -} - -static void siu_console_write(struct console *con, const char *s, unsigned count) -{ - struct uart_port *port; - uint8_t ier; - - port = &siu_uart_ports[con->index]; - - ier = siu_read(port, UART_IER); - siu_write(port, UART_IER, 0); - - uart_console_write(port, s, count, siu_console_putchar); - - wait_for_xmitr(port); - siu_write(port, UART_IER, ier); -} - -static int __init siu_console_setup(struct console *con, char *options) -{ - struct uart_port *port; - int baud = 9600; - int parity = 'n'; - int bits = 8; - int flow = 'n'; - - if (con->index >= SIU_PORTS_MAX) - con->index = 0; - - port = &siu_uart_ports[con->index]; - if (port->membase == NULL) { - if (port->mapbase == 0) - return -ENODEV; - port->membase = ioremap(port->mapbase, siu_port_size(port)); - } - - if (port->type == PORT_VR41XX_SIU) - vr41xx_select_siu_interface(SIU_INTERFACE_RS232C); - - if (options != NULL) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, con, baud, parity, bits, flow); -} - -static struct uart_driver siu_uart_driver; - -static struct console siu_console = { - .name = "ttyVR", - .write = siu_console_write, - .device = uart_console_device, - .setup = siu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &siu_uart_driver, -}; - -static int siu_console_init(void) -{ - struct uart_port *port; - int i; - - for (i = 0; i < SIU_PORTS_MAX; i++) { - port = &siu_uart_ports[i]; - port->ops = &siu_uart_ops; - } - - register_console(&siu_console); - - return 0; -} - -console_initcall(siu_console_init); - -void __init vr41xx_siu_early_setup(struct uart_port *port) -{ - if (port->type == PORT_UNKNOWN) - return; - - siu_uart_ports[port->line].line = port->line; - siu_uart_ports[port->line].type = port->type; - siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; - siu_uart_ports[port->line].mapbase = port->mapbase; - siu_uart_ports[port->line].ops = &siu_uart_ops; -} - -#define SERIAL_VR41XX_CONSOLE &siu_console -#else -#define SERIAL_VR41XX_CONSOLE NULL -#endif - -static struct uart_driver siu_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "SIU", - .dev_name = "ttyVR", - .major = SIU_MAJOR, - .minor = SIU_MINOR_BASE, - .cons = SERIAL_VR41XX_CONSOLE, -}; - -static int siu_probe(struct platform_device *dev) -{ - struct uart_port *port; - int num, i, retval; - - num = siu_init_ports(dev); - if (num <= 0) - return -ENODEV; - - siu_uart_driver.nr = num; - retval = uart_register_driver(&siu_uart_driver); - if (retval) - return retval; - - for (i = 0; i < num; i++) { - port = &siu_uart_ports[i]; - port->ops = &siu_uart_ops; - port->dev = &dev->dev; - port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_VR41XX_CONSOLE); - - retval = uart_add_one_port(&siu_uart_driver, port); - if (retval < 0) { - port->dev = NULL; - break; - } - } - - if (i == 0 && retval < 0) { - uart_unregister_driver(&siu_uart_driver); - return retval; - } - - return 0; -} - -static int siu_remove(struct platform_device *dev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if (port->dev == &dev->dev) { - uart_remove_one_port(&siu_uart_driver, port); - port->dev = NULL; - } - } - - uart_unregister_driver(&siu_uart_driver); - - return 0; -} - -static int siu_suspend(struct platform_device *dev, pm_message_t state) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if ((port->type == PORT_VR41XX_SIU || - port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) - uart_suspend_port(&siu_uart_driver, port); - - } - - return 0; -} - -static int siu_resume(struct platform_device *dev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if ((port->type == PORT_VR41XX_SIU || - port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) - uart_resume_port(&siu_uart_driver, port); - } - - return 0; -} - -static struct platform_driver siu_device_driver = { - .probe = siu_probe, - .remove = siu_remove, - .suspend = siu_suspend, - .resume = siu_resume, - .driver = { - .name = "SIU", - }, -}; - -module_platform_driver(siu_device_driver); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:SIU"); diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 764e992438b2..78a1c1eea11b 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -14,6 +14,7 @@ #include <linux/irq.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/platform_device.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial_core.h> @@ -21,7 +22,6 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/err.h> /* @@ -168,7 +168,7 @@ static void handle_rx(struct uart_port *port) c = readw(port->membase + VT8500_RXFIFO) & 0x3ff; - /* Mask conditions we're ignorning. */ + /* Mask conditions we're ignoring. */ c &= ~port->read_status_mask; if (c & FER) { @@ -184,40 +184,23 @@ static void handle_rx(struct uart_port *port) tty_insert_flip_char(tport, c, flag); } - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); } -static void handle_tx(struct uart_port *port) +static unsigned int vt8500_tx_empty(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - writeb(port->x_char, port->membase + VT8500_TXFIFO); - port->icount.tx++; - port->x_char = 0; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - vt8500_stop_tx(port); - return; - } + unsigned int idx = vt8500_read(port, VT8500_URFIDX) & 0x1f; - while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) { - if (uart_circ_empty(xmit)) - break; - - writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } + return idx < 16 ? TIOCSER_TEMT : 0; +} - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); +static void handle_tx(struct uart_port *port) +{ + u8 ch; - if (uart_circ_empty(xmit)) - vt8500_stop_tx(port); + uart_port_tx(port, ch, + vt8500_tx_empty(port), + writeb(ch, port->membase + VT8500_TXFIFO)); } static void vt8500_start_tx(struct uart_port *port) @@ -244,7 +227,7 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id) struct uart_port *port = dev_id; unsigned long isr; - spin_lock(&port->lock); + uart_port_lock(port); isr = vt8500_read(port, VT8500_URISR); /* Acknowledge active status bits */ @@ -257,17 +240,11 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id) if (isr & TCTS) handle_delta_cts(port); - spin_unlock(&port->lock); + uart_port_unlock(port); return IRQ_HANDLED; } -static unsigned int vt8500_tx_empty(struct uart_port *port) -{ - return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ? - TIOCSER_TEMT : 0; -} - static unsigned int vt8500_get_mctrl(struct uart_port *port) { unsigned int usr; @@ -357,7 +334,7 @@ static void vt8500_shutdown(struct uart_port *port) static void vt8500_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct vt8500_port *vt8500_port = container_of(port, struct vt8500_port, uart); @@ -365,7 +342,7 @@ static void vt8500_set_termios(struct uart_port *port, unsigned int baud, lcr; unsigned int loops = 1000; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* calculate and set baud rate */ baud = uart_get_baud_rate(port, termios, old, 900, 921600); @@ -433,7 +410,7 @@ static void vt8500_set_termios(struct uart_port *port, vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR); vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *vt8500_type(struct uart_port *port) @@ -486,7 +463,7 @@ static void wait_for_xmitr(struct uart_port *port) } while (status & 0x10); } -static void vt8500_console_putchar(struct uart_port *port, int c) +static void vt8500_console_putchar(struct uart_port *port, unsigned char c) { wait_for_xmitr(port); writeb(c, port->membase + VT8500_TXFIFO); @@ -623,23 +600,20 @@ static const struct of_device_id wmt_dt_ids[] = { static int vt8500_serial_probe(struct platform_device *pdev) { struct vt8500_port *vt8500_port; - struct resource *mmres, *irqres; + struct resource *mmres; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; const unsigned int *flags; int ret; int port; + int irq; - match = of_match_device(wmt_dt_ids, &pdev->dev); - if (!match) + flags = of_device_get_match_data(&pdev->dev); + if (!flags) return -EINVAL; - flags = match->data; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; if (np) { port = of_alias_get_id(np, "serial"); @@ -669,7 +643,7 @@ static int vt8500_serial_probe(struct platform_device *pdev) if (!vt8500_port) return -ENOMEM; - vt8500_port->uart.membase = devm_ioremap_resource(&pdev->dev, mmres); + vt8500_port->uart.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &mmres); if (IS_ERR(vt8500_port->uart.membase)) return PTR_ERR(vt8500_port->uart.membase); @@ -693,7 +667,7 @@ static int vt8500_serial_probe(struct platform_device *pdev) vt8500_port->uart.type = PORT_VT8500; vt8500_port->uart.iotype = UPIO_MEM; vt8500_port->uart.mapbase = mmres->start; - vt8500_port->uart.irq = irqres->start; + vt8500_port->uart.irq = irq; vt8500_port->uart.fifosize = 16; vt8500_port->uart.ops = &vt8500_uart_pops; vt8500_port->uart.line = port; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index b9d672af8b65..c793fc74c26b 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -2,7 +2,7 @@ /* * Cadence UART driver (found in Xilinx Zynq) * - * 2011 - 2014 (C) Xilinx Inc. + * Copyright (c) 2011 - 2014 Xilinx, Inc. * * This driver has originally been pushed by Xilinx using a Zynq-branding. This * still shows in the naming of this file, the kconfig symbols and some symbols @@ -22,7 +22,10 @@ #include <linux/of.h> #include <linux/module.h> #include <linux/pm_runtime.h> -#include <linux/iopoll.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/delay.h> +#include <linux/reset.h> #define CDNS_UART_TTY_NAME "ttyPS" #define CDNS_UART_NAME "xuartps" @@ -30,7 +33,6 @@ #define CDNS_UART_MINOR 0 /* works best with devtmpfs */ #define CDNS_UART_NR_PORTS 16 #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ -#define CDNS_UART_REGISTER_SPACE 0x1000 #define TX_TIMEOUT 500000 /* Rx Trigger level */ @@ -188,24 +190,39 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); * @port: Pointer to the UART port * @uartclk: Reference clock * @pclk: APB clock - * @cdns_uart_driver: Pointer to UART driver * @baud: Current baud rate * @clk_rate_change_nb: Notifier block for clock changes * @quirks: Flags for RXBS support. + * @cts_override: Modem control state override + * @gpiod_rts: Pointer to the gpio descriptor + * @rs485_tx_started: RS485 tx state + * @tx_timer: Timer for tx + * @rstc: Pointer to the reset control */ struct cdns_uart { struct uart_port *port; struct clk *uartclk; struct clk *pclk; - struct uart_driver *cdns_uart_driver; unsigned int baud; struct notifier_block clk_rate_change_nb; u32 quirks; bool cts_override; + struct gpio_desc *gpiod_rts; + bool rs485_tx_started; + struct hrtimer tx_timer; + struct reset_control *rstc; }; struct cdns_platform_data { u32 quirks; }; + +static struct serial_rs485 cdns_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ clk_rate_change_nb) @@ -267,7 +284,7 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) continue; } - if (uart_handle_sysrq_char(port, data)) + if (uart_prepare_sysrq_char(port, data)) continue; if (is_rxbs_support) { @@ -300,53 +317,143 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) tty_insert_flip_char(&port->state->port, data, status); isrstatus = 0; } - spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } /** - * cdns_uart_handle_tx - Handle the bytes to be Txed. + * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low + * @cdns_uart: Handle to the cdns_uart + * @enable: Value to be set to RTS/GPIO + */ +static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable) +{ + u32 val; + + if (cdns_uart->gpiod_rts) { + gpiod_set_value(cdns_uart->gpiod_rts, enable); + } else { + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR); + if (enable) + val |= CDNS_UART_MODEMCR_RTS; + else + val &= ~CDNS_UART_MODEMCR_RTS; + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR); + } +} + +/** + * cdns_rs485_tx_setup - Tx setup specific to rs485 + * @cdns_uart: Handle to the cdns_uart + */ +static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart) +{ + bool enable; + + enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_ON_SEND; + cdns_rts_gpio_enable(cdns_uart, enable); + + cdns_uart->rs485_tx_started = true; +} + +/** + * cdns_rs485_rx_setup - Rx setup specific to rs485 + * @cdns_uart: Handle to the cdns_uart + */ +static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart) +{ + bool enable; + + enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_AFTER_SEND; + cdns_rts_gpio_enable(cdns_uart, enable); + + cdns_uart->rs485_tx_started = false; +} + +/** + * cdns_uart_tx_empty - Check whether TX is empty + * @port: Handle to the uart port structure + * + * Return: TIOCSER_TEMT on success, 0 otherwise + */ +static unsigned int cdns_uart_tx_empty(struct uart_port *port) +{ + unsigned int status; + + status = readl(port->membase + CDNS_UART_SR); + status &= (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); + return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; +} + +/** + * cdns_rs485_rx_callback - Timer rx callback handler for rs485. + * @t: Handle to the hrtimer structure + */ +static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t) +{ + struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer); + + /* + * Default Rx should be setup, because Rx signaling path + * need to enable to receive data. + */ + cdns_rs485_rx_setup(cdns_uart); + + return HRTIMER_NORESTART; +} + +/** + * cdns_calc_after_tx_delay - calculate delay required for after tx. + * @cdns_uart: Handle to the cdns_uart + */ +static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart) +{ + /* + * Frame time + stop bit time + rs485.delay_rts_after_send + */ + return cdns_uart->port->frame_time + + DIV_ROUND_UP(cdns_uart->port->frame_time, 7) + + (u64)cdns_uart->port->rs485.delay_rts_after_send * NSEC_PER_MSEC; +} + +/** + * cdns_uart_handle_tx - Handle the bytes to be transmitted. * @dev_id: Id of the UART port * Return: None */ static void cdns_uart_handle_tx(void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; + struct cdns_uart *cdns_uart = port->private_data; + struct tty_port *tport = &port->state->port; unsigned int numbytes; + unsigned char ch; - if (uart_circ_empty(&port->state->xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { + /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); - } else { - numbytes = port->fifosize; - while (numbytes && !uart_circ_empty(&port->state->xmit) && - !(readl(port->membase + CDNS_UART_SR) & - CDNS_UART_SR_TXFULL)) { - /* - * Get the data from the UART circular buffer - * and write it to the cdns_uart's TX_FIFO - * register. - */ - writel( - port->state->xmit.buf[port->state->xmit.tail], - port->membase + CDNS_UART_FIFO); - - port->icount.tx++; - - /* - * Adjust the tail of the UART buffer and wrap - * the buffer if it reaches limit. - */ - port->state->xmit.tail = - (port->state->xmit.tail + 1) & - (UART_XMIT_SIZE - 1); - - numbytes--; - } + return; + } + + numbytes = port->fifosize; + while (numbytes && + !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) && + uart_fifo_get(port, &ch)) { + writel(ch, port->membase + CDNS_UART_FIFO); + numbytes--; + } - if (uart_circ_chars_pending( - &port->state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* Enable the TX Empty interrupt */ + writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED && + (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) { + hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback); + hrtimer_start(&cdns_uart->tx_timer, + ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL); } } @@ -362,7 +469,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) struct uart_port *port = (struct uart_port *)dev_id; unsigned int isrstatus; - spin_lock(&port->lock); + uart_port_lock(port); /* Read the interrupt status register to determine which * interrupt(s) is/are active and clear them. @@ -375,6 +482,8 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } + isrstatus &= port->read_status_mask; + isrstatus &= ~port->ignore_status_mask; /* * Skip RX processing if RX is disabled as RXEMPTY will never be set * as read bytes will not be removed from the FIFO. @@ -383,7 +492,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS)) cdns_uart_handle_rx(dev_id, isrstatus); - spin_unlock(&port->lock); + uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } @@ -484,7 +593,7 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, #ifdef CONFIG_COMMON_CLK /** - * cdns_uart_clk_notitifer_cb - Clock notifier callback + * cdns_uart_clk_notifier_cb - Clock notifier callback * @nb: Notifier block * @event: Notify event * @data: Notifier data @@ -497,8 +606,8 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, struct uart_port *port; int locked = 0; struct clk_notifier_data *ndata = data; - unsigned long flags = 0; struct cdns_uart *cdns_uart = to_cdns_uart(nb); + unsigned long flags; port = cdns_uart->port; if (port->suspended) @@ -520,14 +629,14 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, return NOTIFY_BAD; } - spin_lock_irqsave(&cdns_uart->port->lock, flags); + uart_port_lock_irqsave(cdns_uart->port, &flags); /* Disable the TX and RX to set baud rate */ ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; writel(ctrl_reg, port->membase + CDNS_UART_CR); - spin_unlock_irqrestore(&cdns_uart->port->lock, flags); + uart_port_unlock_irqrestore(cdns_uart->port, flags); return NOTIFY_OK; } @@ -537,17 +646,17 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, * frequency. */ - spin_lock_irqsave(&cdns_uart->port->lock, flags); + uart_port_lock_irqsave(cdns_uart->port, &flags); locked = 1; port->uartclk = ndata->new_rate; cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port, cdns_uart->baud); - /* fall through */ + fallthrough; case ABORT_RATE_CHANGE: if (!locked) - spin_lock_irqsave(&cdns_uart->port->lock, flags); + uart_port_lock_irqsave(cdns_uart->port, &flags); /* Set TX/RX Reset */ ctrl_reg = readl(port->membase + CDNS_UART_CR); @@ -569,7 +678,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; writel(ctrl_reg, port->membase + CDNS_UART_CR); - spin_unlock_irqrestore(&cdns_uart->port->lock, flags); + uart_port_unlock_irqrestore(cdns_uart->port, flags); return NOTIFY_OK; default: @@ -579,12 +688,28 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, #endif /** + * cdns_rs485_tx_callback - Timer tx callback handler for rs485. + * @t: Handle to the hrtimer structure + */ +static enum hrtimer_restart cdns_rs485_tx_callback(struct hrtimer *t) +{ + struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer); + + uart_port_lock(cdns_uart->port); + cdns_uart_handle_tx(cdns_uart->port); + uart_port_unlock(cdns_uart->port); + + return HRTIMER_NORESTART; +} + +/** * cdns_uart_start_tx - Start transmitting bytes * @port: Handle to the uart port structure */ static void cdns_uart_start_tx(struct uart_port *port) { unsigned int status; + struct cdns_uart *cdns_uart = port->private_data; if (uart_tx_stopped(port)) return; @@ -598,14 +723,22 @@ static void cdns_uart_start_tx(struct uart_port *port) status |= CDNS_UART_CR_TX_EN; writel(status, port->membase + CDNS_UART_CR); - if (uart_circ_empty(&port->state->xmit)) + if (kfifo_is_empty(&port->state->port.xmit_fifo)) return; - cdns_uart_handle_tx(port); - + /* Clear the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); - /* Enable the TX Empty interrupt */ - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { + if (!cdns_uart->rs485_tx_started) { + hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_tx_callback); + cdns_rs485_tx_setup(cdns_uart); + return hrtimer_start(&cdns_uart->tx_timer, + ms_to_ktime(port->rs485.delay_rts_before_send), + HRTIMER_MODE_REL); + } + } + cdns_uart_handle_tx(port); } /** @@ -615,6 +748,10 @@ static void cdns_uart_start_tx(struct uart_port *port) static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; + struct cdns_uart *cdns_uart = port->private_data; + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) + cdns_rs485_rx_setup(cdns_uart); regval = readl(port->membase + CDNS_UART_CR); regval |= CDNS_UART_CR_TX_DIS; @@ -640,21 +777,6 @@ static void cdns_uart_stop_rx(struct uart_port *port) } /** - * cdns_uart_tx_empty - Check whether TX is empty - * @port: Handle to the uart port structure - * - * Return: TIOCSER_TEMT on success, 0 otherwise - */ -static unsigned int cdns_uart_tx_empty(struct uart_port *port) -{ - unsigned int status; - - status = readl(port->membase + CDNS_UART_SR) & - (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); - return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; -} - -/** * cdns_uart_break_ctl - Based on the input ctl we have to start or stop * transmitting char breaks * @port: Handle to the uart port structure @@ -665,19 +787,19 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) unsigned int status; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); status = readl(port->membase + CDNS_UART_CR); if (ctl == -1) - writel(CDNS_UART_CR_STARTBRK | status, + writel(CDNS_UART_CR_STARTBRK | (~CDNS_UART_CR_STOPBRK & status), port->membase + CDNS_UART_CR); else { if ((status & CDNS_UART_CR_STOPBRK) == 0) writel(CDNS_UART_CR_STOPBRK | status, port->membase + CDNS_UART_CR); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /** @@ -688,14 +810,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) * @old: Values of the previously saved termios structure */ static void cdns_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { u32 cval = 0; unsigned int baud, minbaud, maxbaud; unsigned long flags; unsigned int ctrl_reg, mode_reg; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable the TX and RX to set baud rate */ ctrl_reg = readl(port->membase + CDNS_UART_CR); @@ -806,7 +929,7 @@ static void cdns_uart_set_termios(struct uart_port *port, cval &= ~CDNS_UART_MODEMCR_FCM; writel(cval, port->membase + CDNS_UART_MODEMCR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /** @@ -825,7 +948,11 @@ static int cdns_uart_startup(struct uart_port *port) is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; - spin_lock_irqsave(&port->lock, flags); + ret = reset_control_deassert(cdns_uart->rstc); + if (ret) + return ret; + + uart_port_lock_irqsave(port, &flags); /* Disable the TX and RX */ writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, @@ -841,6 +968,9 @@ static int cdns_uart_startup(struct uart_port *port) (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) + cdns_rs485_rx_setup(cdns_uart); + /* * Clear the RX disable bit and then set the RX enable bit to enable * the receiver. @@ -873,7 +1003,7 @@ static int cdns_uart_startup(struct uart_port *port) writel(readl(port->membase + CDNS_UART_ISR), port->membase + CDNS_UART_ISR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port); if (ret) { @@ -900,8 +1030,12 @@ static void cdns_uart_shutdown(struct uart_port *port) { int status; unsigned long flags; + struct cdns_uart *cdns_uart = port->private_data; + + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) + hrtimer_cancel(&cdns_uart->tx_timer); - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Disable interrupts */ status = readl(port->membase + CDNS_UART_IMR); @@ -912,7 +1046,7 @@ static void cdns_uart_shutdown(struct uart_port *port) writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, port->membase + CDNS_UART_CR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); free_irq(port->irq, port); } @@ -961,15 +1095,15 @@ static int cdns_uart_verify_port(struct uart_port *port, */ static int cdns_uart_request_port(struct uart_port *port) { - if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE, + if (!request_mem_region(port->mapbase, port->mapsize, CDNS_UART_NAME)) { return -ENOMEM; } - port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE); + port->membase = ioremap(port->mapbase, port->mapsize); if (!port->membase) { dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); + release_mem_region(port->mapbase, port->mapsize); return -ENOMEM; } return 0; @@ -984,7 +1118,7 @@ static int cdns_uart_request_port(struct uart_port *port) */ static void cdns_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); + release_mem_region(port->mapbase, port->mapsize); iounmap(port->membase); port->membase = NULL; } @@ -1045,6 +1179,8 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_RTS) val |= CDNS_UART_MODEMCR_RTS; + if (cdns_uart_data->gpiod_rts) + gpiod_set_value(cdns_uart_data->gpiod_rts, !(mctrl & TIOCM_RTS)); if (mctrl & TIOCM_DTR) val |= CDNS_UART_MODEMCR_DTR; if (mctrl & TIOCM_LOOP) @@ -1062,7 +1198,7 @@ static int cdns_uart_poll_get_char(struct uart_port *port) int c; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Check if FIFO is empty */ if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY) @@ -1070,7 +1206,7 @@ static int cdns_uart_poll_get_char(struct uart_port *port) else /* Read a character */ c = (unsigned char) readl(port->membase + CDNS_UART_FIFO); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); return c; } @@ -1079,7 +1215,7 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Wait until FIFO is empty */ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) @@ -1092,7 +1228,7 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) cpu_relax(); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } #endif @@ -1141,15 +1277,42 @@ static struct uart_driver cdns_uart_uart_driver; * @port: Handle to the uart port structure * @ch: Character to be written */ -static void cdns_uart_console_putchar(struct uart_port *port, int ch) +static void cdns_uart_console_putchar(struct uart_port *port, unsigned char ch) { - while (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) + unsigned int ctrl_reg; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + ctrl_reg = readl(port->membase + CDNS_UART_CR); + if (!(ctrl_reg & CDNS_UART_CR_TX_DIS)) + break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for Enable\n"); + return; + } cpu_relax(); + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + ctrl_reg = readl(port->membase + CDNS_UART_SR); + + if (!(ctrl_reg & CDNS_UART_SR_TXFULL)) + break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for TX fifo\n"); + return; + } + cpu_relax(); + } writel(ch, port->membase + CDNS_UART_FIFO); } static void cdns_early_write(struct console *con, const char *s, - unsigned n) + unsigned int n) { struct earlycon_device *dev = con->data; @@ -1210,16 +1373,14 @@ static void cdns_uart_console_write(struct console *co, const char *s, unsigned int count) { struct uart_port *port = console_port; - unsigned long flags = 0; + unsigned long flags; unsigned int imr, ctrl; int locked = 1; - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(port, &flags); else - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* save and disable interrupt */ imr = readl(port->membase + CDNS_UART_IMR); @@ -1242,7 +1403,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, writel(imr, port->membase + CDNS_UART_IER); if (locked) - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /** @@ -1302,15 +1463,14 @@ static struct console cdns_uart_console = { static int cdns_uart_suspend(struct device *device) { struct uart_port *port = dev_get_drvdata(device); - struct cdns_uart *cdns_uart = port->private_data; int may_wake; may_wake = device_may_wakeup(device); if (console_suspend_enabled && uart_console(port) && may_wake) { - unsigned long flags = 0; + unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Empty the receive FIFO 1st before making changes */ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) @@ -1319,14 +1479,14 @@ static int cdns_uart_suspend(struct device *device) writel(1, port->membase + CDNS_UART_RXWM); /* disable RX timeout interrups */ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } /* * Call the API provided in serial_core.c file which handles * the suspend. */ - return uart_suspend_port(cdns_uart->cdns_uart_driver, port); + return uart_suspend_port(&cdns_uart_uart_driver, port); } /** @@ -1339,17 +1499,25 @@ static int cdns_uart_resume(struct device *device) { struct uart_port *port = dev_get_drvdata(device); struct cdns_uart *cdns_uart = port->private_data; - unsigned long flags = 0; + unsigned long flags; u32 ctrl_reg; int may_wake; + int ret; may_wake = device_may_wakeup(device); if (console_suspend_enabled && uart_console(port) && !may_wake) { - clk_enable(cdns_uart->pclk); - clk_enable(cdns_uart->uartclk); + ret = clk_enable(cdns_uart->pclk); + if (ret) + return ret; + + ret = clk_enable(cdns_uart->uartclk); + if (ret) { + clk_disable(cdns_uart->pclk); + return ret; + } - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* Set TX/RX Reset */ ctrl_reg = readl(port->membase + CDNS_UART_CR); @@ -1369,17 +1537,17 @@ static int cdns_uart_resume(struct device *device) clk_disable(cdns_uart->uartclk); clk_disable(cdns_uart->pclk); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } else { - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); /* restore original rx trigger level */ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM); /* enable RX timeout interrupt */ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } - return uart_resume_port(cdns_uart->cdns_uart_driver, port); + return uart_resume_port(&cdns_uart_uart_driver, port); } #endif /* ! CONFIG_PM_SLEEP */ static int __maybe_unused cdns_runtime_suspend(struct device *dev) @@ -1396,9 +1564,17 @@ static int __maybe_unused cdns_runtime_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); struct cdns_uart *cdns_uart = port->private_data; + int ret; + + ret = clk_enable(cdns_uart->pclk); + if (ret) + return ret; - clk_enable(cdns_uart->pclk); - clk_enable(cdns_uart->uartclk); + ret = clk_enable(cdns_uart->uartclk); + if (ret) { + clk_disable(cdns_uart->pclk); + return ret; + } return 0; }; @@ -1425,6 +1601,39 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match); static int instances; /** + * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl. + * @port: Pointer to the uart_port structure + * @termios: Pointer to the ktermios structure + * @rs485: Pointer to the serial_rs485 structure + * + * Return: 0 + */ +static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + u32 val; + struct cdns_uart *cdns_uart = port->private_data; + + if (rs485->flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + /* Make sure auto RTS is disabled */ + val = readl(port->membase + CDNS_UART_MODEMCR); + val &= ~CDNS_UART_MODEMCR_FCM; + writel(val, port->membase + CDNS_UART_MODEMCR); + + /* Timer setup */ + hrtimer_setup(&cdns_uart->tx_timer, &cdns_rs485_tx_callback, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + + /* Disable transmitter and make Rx setup*/ + cdns_uart_stop_tx(port); + } else { + hrtimer_cancel(&cdns_uart->tx_timer); + } + return 0; +} + +/** * cdns_uart_probe - Platform driver probe * @pdev: Pointer to the platform device structure * @@ -1465,7 +1674,6 @@ static int cdns_uart_probe(struct platform_device *pdev) cdns_uart_uart_driver.nr = CDNS_UART_NR_PORTS; #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE cdns_uart_uart_driver.cons = &cdns_uart_console; - cdns_uart_console.index = id; #endif rc = uart_register_driver(&cdns_uart_uart_driver); @@ -1475,8 +1683,6 @@ static int cdns_uart_probe(struct platform_device *pdev) } } - cdns_uart_data->cdns_uart_driver = &cdns_uart_uart_driver; - match = of_match_node(cdns_uart_of_match, pdev->dev.of_node); if (match && match->data) { const struct cdns_platform_data *data = match->data; @@ -1514,6 +1720,13 @@ static int cdns_uart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); } + cdns_uart_data->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + if (IS_ERR(cdns_uart_data->rstc)) { + rc = PTR_ERR(cdns_uart_data->rstc); + dev_err_probe(&pdev->dev, rc, "Cannot get UART reset\n"); + goto err_out_unregister_driver; + } + rc = clk_prepare_enable(cdns_uart_data->pclk); if (rc) { dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); @@ -1532,8 +1745,8 @@ static int cdns_uart_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - rc = -ENXIO; + if (irq < 0) { + rc = irq; goto err_out_clk_disable; } @@ -1561,13 +1774,30 @@ static int cdns_uart_probe(struct platform_device *pdev) * and triggers invocation of the config_port() entry point. */ port->mapbase = res->start; + port->mapsize = resource_size(res); port->irq = irq; port->dev = &pdev->dev; port->uartclk = clk_get_rate(cdns_uart_data->uartclk); port->private_data = cdns_uart_data; + port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; + port->rs485_config = cdns_rs485_config; + port->rs485_supported = cdns_rs485_supported; cdns_uart_data->port = port; platform_set_drvdata(pdev, port); + rc = uart_get_rs485_mode(port); + if (rc) + goto err_out_clk_notifier; + + cdns_uart_data->gpiod_rts = devm_gpiod_get_optional(&pdev->dev, "rts", + GPIOD_OUT_LOW); + if (IS_ERR(cdns_uart_data->gpiod_rts)) { + rc = PTR_ERR(cdns_uart_data->gpiod_rts); + dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n"); + goto err_out_clk_notifier; + } + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); pm_runtime_set_active(&pdev->dev); @@ -1581,9 +1811,13 @@ static int cdns_uart_probe(struct platform_device *pdev) * If register_console() don't assign value, then console_port pointer * is cleanup. */ - if (!console_port) + if (!console_port) { + cdns_uart_console.index = id; console_port = port; + } #endif + if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED) + cdns_rs485_rx_setup(cdns_uart_data); rc = uart_add_one_port(&cdns_uart_uart_driver, port); if (rc) { @@ -1595,8 +1829,10 @@ static int cdns_uart_probe(struct platform_device *pdev) #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE /* This is not port which is used for console that's why clean it up */ if (console_port == port && - !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) + !console_is_registered(cdns_uart_uart_driver.cons)) { console_port = NULL; + cdns_uart_console.index = -1; + } #endif cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node, @@ -1610,6 +1846,7 @@ err_out_pm_disable: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); +err_out_clk_notifier: #ifdef CONFIG_COMMON_CLK clk_notifier_unregister(cdns_uart_data->uartclk, &cdns_uart_data->clk_rate_change_nb); @@ -1620,28 +1857,25 @@ err_out_clk_dis_pclk: clk_disable_unprepare(cdns_uart_data->pclk); err_out_unregister_driver: if (!instances) - uart_unregister_driver(cdns_uart_data->cdns_uart_driver); + uart_unregister_driver(&cdns_uart_uart_driver); return rc; } /** * cdns_uart_remove - called when the platform driver is unregistered * @pdev: Pointer to the platform device structure - * - * Return: 0 on success, negative errno otherwise */ -static int cdns_uart_remove(struct platform_device *pdev) +static void cdns_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct cdns_uart *cdns_uart_data = port->private_data; - int rc; /* Remove the cdns_uart port from the serial core */ #ifdef CONFIG_COMMON_CLK clk_notifier_unregister(cdns_uart_data->uartclk, &cdns_uart_data->clk_rate_change_nb); #endif - rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port); + uart_remove_one_port(&cdns_uart_uart_driver, port); port->mapbase = 0; clk_disable_unprepare(cdns_uart_data->uartclk); clk_disable_unprepare(cdns_uart_data->pclk); @@ -1654,10 +1888,10 @@ static int cdns_uart_remove(struct platform_device *pdev) if (console_port == port) console_port = NULL; #endif + reset_control_assert(cdns_uart_data->rstc); if (!--instances) - uart_unregister_driver(cdns_uart_data->cdns_uart_driver); - return rc; + uart_unregister_driver(&cdns_uart_uart_driver); } static struct platform_driver cdns_uart_platform_driver = { diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 4b4f604646a7..79ea7108a0f3 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -539,8 +539,9 @@ static void zs_receive_chars(struct zs_port *zport) struct uart_port *uport = &zport->port; struct zs_scc *scc = zport->scc; struct uart_icount *icount; - unsigned int avail, status, ch, flag; + unsigned int avail, status; int count; + u8 ch, flag; for (count = 16; count; count--) { spin_lock(&scc->zlock); @@ -605,7 +606,8 @@ static void zs_receive_chars(struct zs_port *zport) static void zs_raw_transmit_chars(struct zs_port *zport) { - struct circ_buf *xmit = &zport->port.state->xmit; + struct tty_port *tport = &zport->port.state->port; + unsigned char ch; /* XON/XOFF chars. */ if (zport->port.x_char) { @@ -616,21 +618,20 @@ static void zs_raw_transmit_chars(struct zs_port *zport) } /* If nothing to do or stopped or hardware stopped. */ - if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) { + if (uart_tx_stopped(&zport->port) || + !uart_fifo_get(&zport->port, &ch)) { zs_raw_stop_tx(zport); return; } /* Send char. */ - write_zsdata(zport, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - zport->port.icount.tx++; + write_zsdata(zport, ch); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&zport->port); /* Are we are done? */ - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) zs_raw_stop_tx(zport); } @@ -846,7 +847,7 @@ static void zs_reset(struct zs_port *zport) } static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct zs_port *zport = to_zport(uport); struct zs_scc *scc = zport->scc; @@ -981,7 +982,7 @@ static const char *zs_type(struct uart_port *uport) static void zs_release_port(struct uart_port *uport) { iounmap(uport->membase); - uport->membase = 0; + uport->membase = NULL; release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); } @@ -1124,7 +1125,7 @@ static int __init zs_probe_sccs(void) #ifdef CONFIG_SERIAL_ZS_CONSOLE -static void zs_console_putchar(struct uart_port *uport, int ch) +static void zs_console_putchar(struct uart_port *uport, unsigned char ch) { struct zs_port *zport = to_zport(uport); struct zs_scc *scc = zport->scc; |
