From 021d517296f30f5ca077eef9b976dff04841bc9b Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Fri, 14 Jan 2022 08:51:56 +0000 Subject: tty: serial: max3100: Remove redundant 'flush_workqueue()' calls 'destroy_workqueue()' already drains the queue before destroying it, so there is no need to flush it explicitly. Remove the redundant 'flush_workqueue()' calls. Signed-off-by: Xu Wang Link: https://lore.kernel.org/r/20220114085156.43041-1-vulab@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 3c92d4e01488..9494690dcfe2 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -554,7 +554,6 @@ static void max3100_shutdown(struct uart_port *port) del_timer_sync(&s->timer); if (s->workqueue) { - flush_workqueue(s->workqueue); destroy_workqueue(s->workqueue); s->workqueue = NULL; } -- cgit v1.2.3 From 7a637784d517863e20d0556037aa4758a706a79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Mon, 17 Jan 2022 07:04:17 +0100 Subject: serial: imx: reduce RX interrupt frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Triggering RX interrupt for every byte defeats the purpose of aging timer and leads to interrupt storm at high baud rates. The interrupt storm can starve line discipline worker and prevent tty throttling, rendering hardware/software flow control useless. Increase receiver trigger level to 8 to increase the minimum period between RX interrupts to 8 characters time. The tradeoff is increased latency. Aging timer resets with every received character. Worst case scenario happens when RX data intercharacter delay is slightly less than the aging timer timeout (8 characters time). The upper bound of the time a character can wait in RxFIFO before interrupt is raised is: (RXTL - 1) * (8 character time timeout + received 1 character time) Usually the data is received in frames, with low intercharacter delay. In such case the latency increase is 8 characters time at the end of the frame with probability (RXTL - 1) / RXTL. Acked-by: Uwe Kleine-König Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220117060417.624613-1-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index df8a0c8b8b29..d8034f166686 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1258,7 +1258,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport) } #define TXTL_DEFAULT 2 /* reset default */ -#define RXTL_DEFAULT 1 /* reset default */ +#define RXTL_DEFAULT 8 /* 8 characters or aging timer */ #define TXTL_DMA 8 /* DMA burst setting */ #define RXTL_DMA 9 /* DMA burst setting */ -- cgit v1.2.3 From 93cf538e23d024ef19cb6de531c5490576c23ccb Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Tue, 11 Jan 2022 16:51:30 +0800 Subject: tty: serial: fsl_lpuart: count tty buffer overruns Added support for counting the tty buffer overruns in fsl_lpuart driver like other uart drivers. Reviewed-by: Jiri Slaby Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20220111085130.5817-1-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index ce3e26144689..7d90c5a530ee 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -931,7 +931,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: @@ -1024,7 +1025,8 @@ static void lpuart32_rxint(struct lpuart_port *sport) flg = TTY_OVERRUN; } - tty_insert_flip_char(port, rx, flg); + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -1116,7 +1118,7 @@ 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 = 0, copied; if (lpuart_is_32(sport)) { unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); @@ -1218,20 +1220,24 @@ 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 = tty_insert_flip_string(port, ring->buf + ring->tail, count); + 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 = tty_insert_flip_string(port, ring->buf + ring->tail, count); + 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; } exit: -- cgit v1.2.3 From 15dc475bcc1739caf4e42a93a73ba1970a9e1dde Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:20 +0100 Subject: serial: core: clean up EXPORT_SYMBOLs Some EXPORT_SYMBOLs are grouped at one location. Some follow functions they export, but a newline is present before them. Fix all these and move them where they belong. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index dc40c4155356..1f6df577c75b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -105,6 +105,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) { @@ -351,7 +352,6 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag, */ port->timeout = (HZ * size) / baud + HZ/50; } - EXPORT_SYMBOL(uart_update_timeout); /** @@ -453,7 +453,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, WARN_ON(1); return 0; } - EXPORT_SYMBOL(uart_get_baud_rate); /** @@ -478,7 +477,6 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) return quot; } - EXPORT_SYMBOL(uart_get_divisor); /* Caller holds port mutex */ @@ -2220,6 +2218,7 @@ unlock: return 0; } +EXPORT_SYMBOL(uart_suspend_port); int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) { @@ -2305,6 +2304,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) return 0; } +EXPORT_SYMBOL(uart_resume_port); static inline void uart_report_port(struct uart_driver *drv, struct uart_port *port) @@ -2599,6 +2599,7 @@ out_kfree: out: return retval; } +EXPORT_SYMBOL(uart_register_driver); /** * uart_unregister_driver - remove a driver from the uart core layer @@ -2622,6 +2623,7 @@ void uart_unregister_driver(struct uart_driver *drv) drv->state = NULL; drv->tty_driver = NULL; } +EXPORT_SYMBOL(uart_unregister_driver); struct tty_driver *uart_console_device(struct console *co, int *index) { @@ -2956,6 +2958,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) return ret; } +EXPORT_SYMBOL(uart_add_one_port); /** * uart_remove_one_port - detach a driver defined port structure @@ -3036,6 +3039,7 @@ out: return ret; } +EXPORT_SYMBOL(uart_remove_one_port); /* * Are the two ports equivalent? @@ -3212,14 +3216,6 @@ bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq); #endif -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 * @port: uart device's target port -- cgit v1.2.3 From 702d10a0897744cff4e2f53d61c4fc49ac29551d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:21 +0100 Subject: serial: atmel_serial: include circ_buf.h atmel_uart_port::rx_ring is defined as struct circ_buf, but circ_buf.h is not included explicitly in atmel_serial.c. It is included only implicitly via serial_core.h. Fix this as serial_core.h might not include that header in the future. Signed-off-by:Jiri Slaby Cc: Richard Genoud Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Ludovic Desroches Acked-by: Richard Genoud Signed-off-by: Richard Genoud Link: https://lore.kernel.org/r/20220124071430.14907-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index c370eddc651b..2d09a89974a2 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -8,6 +8,7 @@ * * DMA support added by Chip Coldwell. */ +#include #include #include #include -- cgit v1.2.3 From 4e2a44c1408b6a6a46122704511234f68cf012b8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:22 +0100 Subject: tty: add kfifo to tty_port Define a kfifo inside struct tty_port. We use DECLARE_KFIFO_PTR and let the preexisting tty_port::xmit_buf be also the buffer for the kfifo. And handle the initialization/decomissioning along with xmit_buf, i.e. in tty_port_alloc_xmit_buf() and tty_port_free_xmit_buf(), respectively. This allows for kfifo use in drivers which opt-in, while others still may use the old xmit_buf. mxser will be the first user in the next few patches. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 7709ce655f44..7644834640f1 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -225,8 +225,11 @@ int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ mutex_lock(&port->buf_mutex); - if (port->xmit_buf == NULL) + if (port->xmit_buf == NULL) { port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + if (port->xmit_buf) + kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE); + } mutex_unlock(&port->buf_mutex); if (port->xmit_buf == NULL) return -ENOMEM; @@ -240,6 +243,7 @@ void tty_port_free_xmit_buf(struct tty_port *port) if (port->xmit_buf != NULL) { free_page((unsigned long)port->xmit_buf); port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); } mutex_unlock(&port->buf_mutex); } -- cgit v1.2.3 From d56738a38a65ab785557a1ccf8257a486d1b93b6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:23 +0100 Subject: tty: tty_port_open, document shutdown vs failed activate Add a note that ->shutdown is not called when ->activate fails. Just so we are clear. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 7644834640f1..4282895ede9e 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -736,6 +736,9 @@ EXPORT_SYMBOL_GPL(tty_port_install); * the device to be ready using tty_port_block_til_ready() (e.g. raises * DTR/CTS and waits for carrier). * + * Note that @port->ops->shutdown is not called when @port->ops->activate + * returns an error (on the contrary, @tty->ops->close is). + * * Locking: Caller holds tty lock. * * Note: may drop and reacquire tty lock (in tty_port_block_til_ready()) so -- cgit v1.2.3 From cd3a4907ee334b40d7aa880c7ab310b154fd5cd4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:24 +0100 Subject: mxser: fix xmit_buf leak in activate when LSR == 0xff When LSR is 0xff in ->activate() (rather unlike), we return an error. Provided ->shutdown() is not called when ->activate() fails, nothing actually frees the buffer in this case. Fix this by properly freeing the buffer in a designated label. We jump there also from the "!info->type" if now too. Fixes: 6769140d3047 ("tty: mxser: use the tty_port_open method") Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index c858aff721c4..fbb796f83753 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -744,6 +744,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) struct mxser_port *info = container_of(port, struct mxser_port, port); unsigned long page; unsigned long flags; + int ret; page = __get_free_page(GFP_KERNEL); if (!page) @@ -753,9 +754,9 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (!info->type) { set_bit(TTY_IO_ERROR, &tty->flags); - free_page(page); spin_unlock_irqrestore(&info->slock, flags); - return 0; + ret = 0; + goto err_free_xmit; } info->port.xmit_buf = (unsigned char *) page; @@ -775,8 +776,10 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); return 0; - } else - return -ENODEV; + } + + ret = -ENODEV; + goto err_free_xmit; } /* @@ -821,6 +824,10 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); return 0; +err_free_xmit: + free_page(page); + info->port.xmit_buf = NULL; + return ret; } /* -- cgit v1.2.3 From 92cc9d1d14e3ba8e82c99a4b4c90cce1db3c3fa9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:25 +0100 Subject: mxser: use tty_port xmit_buf helpers For the mxser driver to use kfifo, use tty_port_alloc_xmit_buf() and tty_port_free_xmit_buf() helpers in activate/shutdown, respectively. As these calls have to be done in a non-atomic context, we have to move them outside spinlock and make sure irq is really stopped after we write to the ISR register. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index fbb796f83753..4ddc12a63666 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -742,13 +742,12 @@ static void mxser_disable_and_clear_FIFO(struct mxser_port *info) static int mxser_activate(struct tty_port *port, struct tty_struct *tty) { struct mxser_port *info = container_of(port, struct mxser_port, port); - unsigned long page; unsigned long flags; int ret; - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + ret = tty_port_alloc_xmit_buf(port); + if (ret < 0) + return ret; spin_lock_irqsave(&info->slock, flags); @@ -758,7 +757,6 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) ret = 0; goto err_free_xmit; } - info->port.xmit_buf = (unsigned char *) page; /* * Clear the FIFO buffers and disable them @@ -825,8 +823,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) return 0; err_free_xmit: - free_page(page); - info->port.xmit_buf = NULL; + tty_port_free_xmit_buf(port); return ret; } @@ -862,14 +859,6 @@ static void mxser_shutdown_port(struct tty_port *port) */ wake_up_interruptible(&info->port.delta_msr_wait); - /* - * Free the xmit buffer, if necessary - */ - if (info->port.xmit_buf) { - free_page((unsigned long) info->port.xmit_buf); - info->port.xmit_buf = NULL; - } - info->IER = 0; outb(0x00, info->ioaddr + UART_IER); @@ -884,6 +873,11 @@ static void mxser_shutdown_port(struct tty_port *port) mxser_must_no_sw_flow_control(info->ioaddr); spin_unlock_irqrestore(&info->slock, flags); + + /* make sure ISR is not running while we free the buffer */ + synchronize_irq(info->board->irq); + + tty_port_free_xmit_buf(port); } /* -- cgit v1.2.3 From 32330c833442d4041dbd20508f6cd2419deb16eb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:26 +0100 Subject: mxser: switch from xmit_buf to kfifo Use kfifo for xmit buffer handling. The change is mostly straightforward. It saves complexity both on the stuffing side (mxser_write() and mxser_put_char()) and pulling side (mxser_transmit_chars()). In fact, the loop in mxser_write() can be completely deleted as the wrap of the buffer is taken care of in the kfifo code now. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 74 +++++++++++++++++++---------------------------------- 1 file changed, 27 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 4ddc12a63666..836c9eca2946 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -275,9 +275,6 @@ struct mxser_port { u8 read_status_mask; u8 ignore_status_mask; u8 xmit_fifo_size; - unsigned int xmit_head; - unsigned int xmit_tail; - unsigned int xmit_cnt; spinlock_t slock; }; @@ -813,7 +810,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) (void) inb(info->ioaddr + UART_MSR); clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + kfifo_reset(&port->xmit_fifo); /* * and set the speed of the serial port @@ -901,9 +898,8 @@ static void mxser_flush_buffer(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; unsigned long flags; - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + kfifo_reset(&info->port.xmit_fifo); outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, info->ioaddr + UART_FCR); @@ -920,50 +916,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) { - int c, total = 0; struct mxser_port *info = tty->driver_data; unsigned long flags; + int written; + bool is_empty; - while (1) { - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - memcpy(info->port.xmit_buf + info->xmit_head, buf, c); - spin_lock_irqsave(&info->slock, flags); - info->xmit_head = (info->xmit_head + c) & - (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->slock, flags); - - buf += c; - count -= c; - total += c; - } + spin_lock_irqsave(&info->slock, flags); + written = kfifo_in(&info->port.xmit_fifo, buf, count); + is_empty = kfifo_is_empty(&info->port.xmit_fifo); + spin_unlock_irqrestore(&info->slock, flags); - if (info->xmit_cnt && !tty->flow.stopped) + if (!is_empty && !tty->flow.stopped) if (!tty->hw_stopped || mxser_16550A_or_MUST(info)) mxser_start_tx(info); - return total; + return written; } static int mxser_put_char(struct tty_struct *tty, unsigned char ch) { struct mxser_port *info = tty->driver_data; unsigned long flags; - - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) - return 0; + int ret; spin_lock_irqsave(&info->slock, flags); - info->port.xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE - 1; - info->xmit_cnt++; + ret = kfifo_put(&info->port.xmit_fifo, ch); spin_unlock_irqrestore(&info->slock, flags); - return 1; + return ret; } @@ -971,7 +951,7 @@ static void mxser_flush_chars(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - if (!info->xmit_cnt || tty->flow.stopped || + if (kfifo_is_empty(&info->port.xmit_fifo) || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(info))) return; @@ -981,16 +961,15 @@ static void mxser_flush_chars(struct tty_struct *tty) static unsigned int mxser_write_room(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - int ret; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - return ret < 0 ? 0 : ret; + return kfifo_avail(&info->port.xmit_fifo); } static unsigned int mxser_chars_in_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - return info->xmit_cnt; + + return kfifo_len(&info->port.xmit_fifo); } /* @@ -1379,7 +1358,7 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt) + if (!kfifo_is_empty(&info->port.xmit_fifo)) __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1610,7 +1589,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port return; } - if (!port->xmit_cnt || tty->flow.stopped || + if (kfifo_is_empty(&port->port.xmit_fifo) || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(port))) { __mxser_stop_tx(port); return; @@ -1618,18 +1597,19 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port count = port->xmit_fifo_size; do { - outb(port->port.xmit_buf[port->xmit_tail++], - port->ioaddr + UART_TX); - port->xmit_tail &= SERIAL_XMIT_SIZE - 1; - port->icount.tx++; - if (!--port->xmit_cnt) + unsigned char c; + + if (!kfifo_get(&port->port.xmit_fifo, &c)) break; + + outb(c, port->ioaddr + UART_TX); + port->icount.tx++; } while (--count > 0); - if (port->xmit_cnt < WAKEUP_CHARS) + if (kfifo_len(&port->port.xmit_fifo) < WAKEUP_CHARS) tty_wakeup(tty); - if (!port->xmit_cnt) + if (kfifo_is_empty(&port->port.xmit_fifo)) __mxser_stop_tx(port); } -- cgit v1.2.3 From 7b9528c2919091d77a892096d24480af39c70d25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:27 +0100 Subject: serial: fsl_linflexuart: deduplicate character sending Introduce a new linflex_put_char() helper to send a character. And use it on both places this code was duplicated. Cc: Stefan-gabriel Mirea Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_linflexuart.c | 42 +++++++++++++++--------------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 283757264608..81a04039b6c1 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -157,27 +157,29 @@ 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) + ; + + writel(status | LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR); +} +static inline void linflex_transmit_buffer(struct uart_port *sport) +{ + struct circ_buf *xmit = &sport->state->xmit; + + while (!uart_circ_empty(xmit)) { + linflex_put_char(sport, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->icount.tx++; - - writel(status | LINFLEXD_UARTSR_DTFTFF, - sport->membase + UARTSR); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -201,21 +203,11 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) struct uart_port *sport = dev_id; struct circ_buf *xmit = &sport->state->xmit; unsigned long flags; - unsigned long status; spin_lock_irqsave(&sport->lock, 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; } -- cgit v1.2.3 From d88812a8d66617efdb41d787efca0907ccd98716 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:28 +0100 Subject: serial: fsl_linflexuart: don't call uart_write_wakeup() twice linflex_txint() calls linflex_transmit_buffer() which calls uart_write_wakeup(). So there is no point to repeat it in linflex_txint() again -- remove it. Cc: Stefan-gabriel Mirea Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-10-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_linflexuart.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 81a04039b6c1..e72cba085743 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -217,10 +217,6 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) } linflex_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(sport); - out: spin_unlock_irqrestore(&sport->lock, flags); return IRQ_HANDLED; -- cgit v1.2.3 From e41752c0e79b033fe0ea186bba0f6bb558c49729 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Jan 2022 08:14:30 +0100 Subject: serial: mcf: use helpers in mcf_tx_chars() Use uart_circ_empty() instead of open-coding it via xmit->head & tail. Use preexisting mcf_stop_tx() to avoid stop-tx code duplication. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220124071430.14907-12-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mcf.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index c7cec7d03620..2aec62b5d6c4 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -338,7 +338,7 @@ static void mcf_tx_chars(struct mcf_uart *pp) } while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { - if (xmit->head == xmit->tail) + if (uart_circ_empty(xmit)) break; writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); @@ -348,9 +348,8 @@ static void mcf_tx_chars(struct mcf_uart *pp) 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); + if (uart_circ_empty(xmit)) { + mcf_stop_tx(port); /* Disable TX to negate RTS automatically */ if (port->rs485.flags & SER_RS485_ENABLED) writeb(MCFUART_UCR_TXDISABLE, -- cgit v1.2.3 From f31afa6151ae6b2cc6bc55e6383db85dbfc5ad2d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 26 Jan 2022 20:55:39 +0100 Subject: tty: Replace acpi_bus_get_device() Replace acpi_bus_get_device() that is going to be dropped with acpi_fetch_acpi_dev(). No intentional functional impact. Reviewed-by: Jiri Slaby Signed-off-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/7355105.EvYhyI6sBW@kreacher Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 92e3433276f8..0180e1e4e75d 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -704,13 +704,10 @@ static const struct acpi_device_id serdev_acpi_devices_blacklist[] = { static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, void *data, void **return_value) { + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); struct serdev_controller *ctrl = data; - struct acpi_device *adev; - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - - if (acpi_device_enumerated(adev)) + if (!adev || acpi_device_enumerated(adev)) return AE_OK; /* Skip if black listed */ -- cgit v1.2.3 From 8e4413aaf6a2e3a46e99a0718ca54c0cf8609cb2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 27 Jan 2022 20:06:08 +0200 Subject: serial: 8250_exar: derive nr_ports from PCI ID for Acces I/O cards In the similar way how it's done in 8250_pericom, derive the number of the UART ports from PCI ID for Acces I/O cards. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220127180608.71509-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index d502240bbcf2..7292917ac878 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -623,7 +623,12 @@ 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; + if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) + nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1); + else if (board->num_ports) + nr_ports = board->num_ports; + else + nr_ports = pcidev->device & 0x0f; priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) @@ -722,22 +727,6 @@ static int __maybe_unused exar_resume(struct device *dev) 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 const struct exar8250_board pbn_fastcom335_2 = { .num_ports = 2, .setup = pci_fastcom335_setup, @@ -822,13 +811,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { } 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), + 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_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), -- cgit v1.2.3 From a5e3faf161a3f225cd307f4a78e8b6673b2344bf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 2 Feb 2022 18:56:55 +0200 Subject: amiserial: Drop duplicate NULL check in shutdown() The free_page(addr), which becomes free_pages(addr, 0) checks addr against 0. No need to repeat this check in the caller. Acked-by: Jiri Slaby Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220202165655.5647-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/amiserial.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 1e60dbef676c..533d02b38e02 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -538,10 +538,8 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) */ free_irq(IRQ_AMIGA_VERTB, info); - if (info->xmit.buf) { - free_page((unsigned long) info->xmit.buf); - info->xmit.buf = NULL; - } + free_page((unsigned long)info->xmit.buf); + info->xmit.buf = NULL; info->IER = 0; amiga_custom.intena = IF_RBF | IF_TBE; -- cgit v1.2.3 From 3c5b2f5b9a829992f3760395a64d6102f11fe62d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Feb 2022 17:32:53 +0200 Subject: tty: Drop duplicate NULL check in TTY port functions The free_page(addr), which becomes free_pages(addr, 0) checks addr against 0. No need to repeat this check in the callers, i.e. tty_port_free_xmit_buf() and tty_port_destructor(). Note, INIT_KFIFO() is safe without that check, because it operates on a separate member and doesn't rely on the FIFO itself to be allocated. Acked-by: Jiri Slaby Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220204153253.11006-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 4282895ede9e..880608a65773 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -240,11 +240,9 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf); void tty_port_free_xmit_buf(struct tty_port *port) { mutex_lock(&port->buf_mutex); - if (port->xmit_buf != NULL) { - free_page((unsigned long)port->xmit_buf); - port->xmit_buf = NULL; - INIT_KFIFO(port->xmit_fifo); - } + free_page((unsigned long)port->xmit_buf); + port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); mutex_unlock(&port->buf_mutex); } EXPORT_SYMBOL(tty_port_free_xmit_buf); @@ -271,8 +269,7 @@ static void tty_port_destructor(struct kref *kref) /* check if last port ref was dropped before tty release */ if (WARN_ON(port->itty)) return; - if (port->xmit_buf) - free_page((unsigned long)port->xmit_buf); + free_page((unsigned long)port->xmit_buf); tty_port_destroy(port); if (port->ops && port->ops->destruct) port->ops->destruct(port); -- cgit v1.2.3 From 186ab09930aac24fad59a56d22ea507c8505b84f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Feb 2022 17:28:08 +0200 Subject: serial: core: Drop duplicate NULL check in uart_*shutdown() The free_page(addr), which becomes free_pages(addr, 0) checks addr against 0. No need to repeat this check in the callers. Acked-by: Jiri Slaby Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220204152808.10808-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ba4baa756d51..846192a7b4bf 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -317,8 +317,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) state->xmit.buf = NULL; uart_port_unlock(uport, flags); - if (xmit_buf) - free_page((unsigned long)xmit_buf); + free_page((unsigned long)xmit_buf); } /** @@ -1569,8 +1568,7 @@ static void uart_tty_port_shutdown(struct tty_port *port) state->xmit.buf = NULL; spin_unlock_irq(&uport->lock); - if (buf) - free_page((unsigned long)buf); + free_page((unsigned long)buf); uart_change_pm(state, UART_PM_STATE_OFF); } -- cgit v1.2.3 From 9978c2f14f20a1aaea3840c16220ef64e4ad1872 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Thu, 3 Feb 2022 18:16:43 +0100 Subject: serial: mctrl_gpio: add a new API to enable / disable wake_irq Add a new API to enable / disable wake_irq in order to enable gpio irqs as wakeup irqs for the uart port. Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20220203171644.12231-2-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_mctrl_gpio.c | 38 ++++++++++++++++++++++++++++++++++ drivers/tty/serial/serial_mctrl_gpio.h | 18 ++++++++++++++++ 2 files changed, 56 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index c41d8911ce95..1663b3afc3a0 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -299,4 +299,42 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) } EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); +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_irq_wake); + MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index b134a0ffc894..fc76910fb105 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -91,6 +91,16 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); */ void mctrl_gpio_disable_ms(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 wakeup interrupts to enable wake up source. + */ +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios); + #else /* GPIOLIB */ static inline @@ -142,6 +152,14 @@ static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) { } +static inline void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) +{ +} + +static inline void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) +{ +} + #endif /* GPIOLIB */ #endif -- cgit v1.2.3 From 7547d9ab03720e9ef3e300b12c57f380310a6e30 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Thu, 3 Feb 2022 18:16:44 +0100 Subject: serial: stm32: enable / disable wake irqs for mcrtl_gpio wakeup sources Enable mctrl_gpio wake_irq if device_may_wakeup when usart is suspended, and disable mctrl_gpios wake_irq if device_may_wakeup when usart is resumed. Signed-off-by: Erwan Le Ray Link: https://lore.kernel.org/r/20220203171644.12231-3-erwan.leray@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 9570002d07e7..1b3a611ac39e 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1756,6 +1756,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { 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 @@ -1782,7 +1783,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *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); } -- cgit v1.2.3 From fcc446c8aa6303b247b0d88f460167b731265282 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Mon, 7 Feb 2022 18:21:29 -0500 Subject: serial: 8250_bcm2835aux: Add ACPI support Add ACPI support to 8250_bcm2835aux driver. This makes it possible to use the miniuart on the Raspberry Pi with the tianocore/edk2 UEFI firmware. Tested-by: Jeremy Linton Reviewed-by: Florian Fainelli Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220207232129.402882-1-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 52 +++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index fd95860cd661..2a1226a78a0c 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "8250.h" @@ -44,6 +45,10 @@ struct bcm2835aux_data { u32 cntl; }; +struct bcm2835_aux_serial_driver_data { + resource_size_t offset; +}; + static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) { if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { @@ -80,9 +85,12 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) static int bcm2835aux_serial_probe(struct platform_device *pdev) { + const struct bcm2835_aux_serial_driver_data *bcm_data; struct uart_8250_port up = { }; struct bcm2835aux_data *data; + resource_size_t offset = 0; struct resource *res; + unsigned int uartclk; int ret; /* allocate the custom structure */ @@ -109,9 +117,7 @@ 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); - if (IS_ERR(data->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); + data->clk = devm_clk_get_optional(&pdev->dev, NULL); /* get the interrupt */ ret = platform_get_irq(pdev, 0); @@ -125,8 +131,24 @@ 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); + + bcm_data = device_get_match_data(&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. + */ + if (bcm_data) + offset = bcm_data->offset; + + up.port.mapbase = res->start + offset; + up.port.mapsize = resource_size(res) - offset; /* Check for a fixed line number */ ret = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -141,12 +163,19 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) return ret; } + uartclk = clk_get_rate(data->clk); + if (!uartclk) { + ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk); + if (ret) + return dev_err_probe(&pdev->dev, ret, "could not get clk rate\n"); + } + /* 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 = uartclk * 2; /* register the port */ ret = serial8250_register_8250_port(&up); @@ -173,16 +202,27 @@ static int bcm2835aux_serial_remove(struct platform_device *pdev) return 0; } +static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = { + .offset = 0x40, +}; + 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_data }, + { } +}; +MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match); + 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, }, .probe = bcm2835aux_serial_probe, .remove = bcm2835aux_serial_remove, -- cgit v1.2.3 From 582e9a24fc139adabb1dc951620870806bfc1583 Mon Sep 17 00:00:00 2001 From: Harald Seiler Date: Wed, 19 Jan 2022 15:52:03 +0100 Subject: tty: serial: imx: Add fast path when rs485 delays are 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now, even when `delay_rts_before_send` and `delay_rts_after_send` are 0, the hrtimer is triggered (with timeout 0) which can introduce a few 100us of additional overhead on slower i.MX platforms. Implement a fast path when the delays are 0, where the RTS signal is toggled immediately instead of going through an hrtimer. This fast path behaves identical to the code before delay support was implemented. Reviewed-by: Uwe Kleine-König Signed-off-by: Harald Seiler Link: https://lore.kernel.org/r/20220119145204.238767-1-hws@denx.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d8034f166686..0b467ce8d737 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -455,9 +455,14 @@ static void imx_uart_stop_tx(struct uart_port *port) if (port->rs485.flags & SER_RS485_ENABLED) { if (sport->tx_state == SEND) { sport->tx_state = WAIT_AFTER_SEND; - start_hrtimer_ms(&sport->trigger_stop_tx, + + if (port->rs485.delay_rts_after_send > 0) { + start_hrtimer_ms(&sport->trigger_stop_tx, port->rs485.delay_rts_after_send); - return; + return; + } + + /* continue without any delay */ } if (sport->tx_state == WAIT_AFTER_RTS || @@ -698,9 +703,14 @@ static void imx_uart_start_tx(struct uart_port *port) imx_uart_stop_rx(port); sport->tx_state = WAIT_AFTER_RTS; - start_hrtimer_ms(&sport->trigger_start_tx, + + if (port->rs485.delay_rts_before_send > 0) { + start_hrtimer_ms(&sport->trigger_start_tx, port->rs485.delay_rts_before_send); - return; + return; + } + + /* continue without any delay */ } if (sport->tx_state == WAIT_AFTER_SEND -- cgit v1.2.3 From aab68e959b37eddfe6b1640636457e960f66db2c Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 17 Feb 2022 10:46:20 +0100 Subject: tty: serial: atmel: add earlycon support Add early console support which relies on the bootloader for the initialization of the UART. Please note, that the compatibles are taken from at91-usart MFD driver. Tested-by: Claudiu Beznea Reviewed-by: Claudiu Beznea Acked-by: Richard Genoud Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20220217094620.1148571-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/atmel_serial.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0e5ccb25bdb1..407a98ec0791 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -139,6 +139,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 diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2d09a89974a2..73d43919898d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2673,6 +2673,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 -- cgit v1.2.3 From 81ddb200f63604a3df21ad82584c62dab8fb0300 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Feb 2022 17:29:25 +0100 Subject: serial: sh-sci: Simplify multiplication/shift logic "a * (1 << b)" == "a << b". No change in generated code. Reviewed-by: Ulrich Hecht Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/118d62e167f6cf5e98bdf9a738634b4590ea8d09.1645460901.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 968967d722d4..77d76973858f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2293,7 +2293,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: -- cgit v1.2.3 From 2394f3596049c9b287cc3268bf2f77844cbc8a72 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 15 Feb 2022 12:41:26 +0200 Subject: serial: 8250_mid: Get rid of custom MID_DEVICE() macro Since PCI core provides a generic PCI_DEVICE_DATA() macro, replace MID_DEVICE() with former one. No functional change intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220215104126.7220-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index efa0515139f8..771453c1bb13 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -368,16 +368,14 @@ static const struct mid8250_board dnv_board = { .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); -- cgit v1.2.3 From 324facd1ccb353a213ea2c2785604f2507f79297 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 15 Feb 2022 12:11:11 +0200 Subject: serial: 8250_mid: Remove unneeded test for ->setup() presence All supported platforms by this driver require ->setup() and ->exit(). Remove unneeded test for ->setup() presence. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220215101111.47250-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 771453c1bb13..83592b51a996 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -312,11 +312,9 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) 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) -- cgit v1.2.3 From a603ca60cebff8589882427a67f870ed946b3fc8 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Thu, 10 Feb 2022 16:42:03 -0800 Subject: serial: 8250_aspeed_vuart: add PORT_ASPEED_VUART port type Commit 54da3e381c2b ("serial: 8250_aspeed_vuart: use UPF_IOREMAP to set up register mapping") fixed a bug that had, as a side-effect, prevented the 8250_aspeed_vuart driver from enabling the VUART's FIFOs. However, fixing that (and hence enabling the FIFOs) has in turn revealed what appears to be a hardware bug in the ASPEED VUART in which the host-side THRE bit doesn't get if the BMC-side receive FIFO trigger level is set to anything but one byte. This causes problems for polled-mode writes from the host -- for example, Linux kernel console writes proceed at a glacial pace (less than 100 bytes per second) because the write path waits for a 10ms timeout to expire after every character instead of being able to continue on to the next character upon seeing THRE asserted. (GRUB behaves similarly.) As a workaround, introduce a new port type for the ASPEED VUART that's identical to PORT_16550A as it had previously been using, but with UART_FCR_R_TRIG_00 instead to set the receive FIFO trigger level to one byte, which (experimentally) seems to avoid the problematic THRE behavior. Fixes: 54da3e381c2b ("serial: 8250_aspeed_vuart: use UPF_IOREMAP to set up register mapping") Tested-by: Konstantin Aladyshev Reviewed-by: Andy Shevchenko Signed-off-by: Zev Weiss Link: https://lore.kernel.org/r/20220211004203.14915-1-zev@bewilderbeest.net Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_aspeed_vuart.c | 2 +- drivers/tty/serial/8250/8250_port.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 2350fb3bb5e4..c2cecc6f47db 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -487,7 +487,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) 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.type = PORT_ASPEED_VUART; port.port.uartclk = clk; port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3b12bfc1ed67..973870ebff69 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -307,6 +307,14 @@ 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, + }, }; /* Uart divisor latch read */ -- cgit v1.2.3 From 932d596378b0253354246f4aa3662add4883a167 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Thu, 17 Feb 2022 22:18:39 +0100 Subject: serial: 8250: Return early in .start_tx() if there are no chars to send MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't start the whole chain for TX if there is no data to send. This is mostly relevant for rs485 mode as there might be rts-before-send and rts-after-send delays involved. Signed-off-by: Steffen Trumtrar Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220217211839.443039-1-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 973870ebff69..728d60be8975 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1665,6 +1665,9 @@ static void serial8250_start_tx(struct uart_port *port) serial8250_rpm_get_tx(up); + if (!port->x_char && uart_circ_empty(&port->state->xmit)) + return; + if (em485 && em485->active_timer == &em485->start_tx_timer) return; -- cgit v1.2.3 From c112653b89e0cea4aa2ea26fcfbbb30a2193339e Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Mon, 21 Feb 2022 11:56:13 +0100 Subject: sc16is7xx: Preserve EFR bits on update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preserve unaffected bits state when accessing EFR register. This prevents hardware flow control bits from being cleared on enhanced functions access. Signed-off-by: Lech Perczak Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220221105618.3503470-2-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 64e7e6c8145f..3a808b2cae4f 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -289,6 +289,14 @@ * 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) @@ -523,8 +531,10 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) /* Enable enhanced features */ regcache_cache_bypass(s->regmap, true); - sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, - SC16IS7XX_EFR_ENABLE_BIT); + sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT, + SC16IS7XX_EFR_ENABLE_BIT); + regcache_cache_bypass(s->regmap, false); /* Put LCR back to the normal mode */ @@ -932,7 +942,10 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (termios->c_iflag & IXOFF) flow |= SC16IS7XX_EFR_SWFLOW1_BIT; - sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); + sc16is7xx_port_update(port, + SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_FLOWCTRL_BITS, + flow); regcache_cache_bypass(s->regmap, false); /* Update LCR register */ @@ -1007,8 +1020,9 @@ static int sc16is7xx_startup(struct uart_port *port) 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); + sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT, + SC16IS7XX_EFR_ENABLE_BIT); /* Enable TCR/TLR */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, -- cgit v1.2.3 From 6cca8f154a296ead948d1ff0f6c63febf84a8856 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Mon, 21 Feb 2022 11:56:14 +0100 Subject: sc16is7xx: Update status lines in single call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RTS, DTR and LOOP bits can be updated in a single MCR register update. This reduces the number of (slow) SPI/I2C bus transactions. Signed-off-by: Lech Perczak Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220221105618.3503470-3-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 3a808b2cae4f..a2873acbabd2 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -784,19 +784,24 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws) spin_unlock_irqrestore(&one->port.lock, 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); -- cgit v1.2.3 From 679875d1d8802669590ef4d69b0e7d13207ebd61 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Mon, 21 Feb 2022 11:56:15 +0100 Subject: sc16is7xx: Separate GPIOs from modem control lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export only the GPIOs that are not shared with hardware modem control lines. Introduce new device parameter indicating whether modem control lines are available. Signed-off-by: Lech Perczak Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220221105618.3503470-4-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index a2873acbabd2..b7a2db9c03e2 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -306,6 +306,7 @@ struct sc16is7xx_devtype { char name[10]; int nr_gpio; int nr_uart; + int has_mctrl; }; #define SC16IS7XX_RECONF_MD (1 << 0) @@ -440,30 +441,35 @@ static const struct sc16is7xx_devtype sc16is74x_devtype = { .name = "SC16IS74X", .nr_gpio = 0, .nr_uart = 1, + .has_mctrl = 0, }; static const struct sc16is7xx_devtype sc16is750_devtype = { .name = "SC16IS750", - .nr_gpio = 8, + .nr_gpio = 4, .nr_uart = 1, + .has_mctrl = 1, }; static const struct sc16is7xx_devtype sc16is752_devtype = { .name = "SC16IS752", - .nr_gpio = 8, + .nr_gpio = 0, .nr_uart = 2, + .has_mctrl = 1, }; static const struct sc16is7xx_devtype sc16is760_devtype = { .name = "SC16IS760", - .nr_gpio = 8, + .nr_gpio = 4, .nr_uart = 1, + .has_mctrl = 1, }; static const struct sc16is7xx_devtype sc16is762_devtype = { .name = "SC16IS762", - .nr_gpio = 8, + .nr_gpio = 0, .nr_uart = 2, + .has_mctrl = 1, }; static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) -- cgit v1.2.3 From b7e2b5360f9bd44733d80ffd2d070ba1f3ca7e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 19 Feb 2022 16:28:15 +0100 Subject: serial: mvebu-uart: implement UART clock driver for configuring UART base clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement a new device driver for controlling UART clocks on Marvell Armada 3700 SoC. This device driver is loaded for devices which match the compatible string "marvell,armada-3700-uart-clock". There are more pitfalls related to UART clocks: - both UARTs use same parent clock source (which can be xtal or one of the TBG clocks), - if a TBG clock is used as the parent clock, there are two additional divisors that can both be configured to divide the rate by 1, 2, ... 6, but these divisors are again shared between the two UART controllers on the SOC, - the configuration of the parent clock source and divisors is done in the address space of the first UART controller, UART1. Clocks can be gated separately for UART1 and UART2, but this setting also lives in the address space of UART1, - Marvell's Functional Specification for Armada 3720 document has the clock gating bits swapped, so the one described to gate UART1 clock actually gates UART2 and vice versa, - each UART has it's own "special divisor", and this uses the parent clock described above. These divisors are configure in each UART's address space separately. Thus the driver for UART2 controller needs to have access to UART1 address space, since UART1 address space contains some bits exclusive for UART2 and also some bits which are shared between UART1 and UART2. Also, during boot, when early console is active on one of the UARTs, and we want to switch parent clock from xtal (default) to TBG (to be more flexible with baudrates), the driver changing UART clocks also needs to be able to change the "special divisor", so that the baudrate of earlycon is not changed when swtiching to normal console. Thus the clock driver also needs to be able to access UART2 register space, for UART2's "special divisor". For these reasons, this new UART clock driver does not use ioremap_resource(), but only ioremap() to prevent resource conflicts between UART clock driver and UART driver. We need to share only two 32-bit registers between the UART driver and the UART clock driver: - UART Clock Control - UART 2 Baud Rate Divisor Access to these two registers are protected by one spinlock to prevent any conflicts. Access is required only during probing, when changing baudrate or during suspend/resume. Hardware can be configured to use one of following clocks as UART parent clock: TBG-A-P, TBG-B-P, TBG-A-S, TBG-B-S, xtal. Not every clock is usable for higher buadrates. Any subset can be specified in the device-tree and the driver will choose the best one which also still supports the mandatory baudrate of 9600 Bd. For smooth boot log output it is needed to specify clock used by early console, otherwise garbage would be printed on UART during probe of UART clock driver and transitioning from early console to normal console. We are implementing this to be able to configure TBG clock as UART parent clock, which is required to be able to achieve higher baudrates than 230400 Bd. We achieve this by referencing this new UART clock device node in UART's device node. UART clock device driver automatically chooses the best clock source for UART driver. Until now, UART's device-tree node needed to reference one of the static clocks (xtal or one of the TBGs) as parent clock in the `clocks` phandle - the parent clock which was configured before booting the kernel. If bootloader changed UART's parent clock, it needed to change the `clocks` phandle in DTB correspondingly before booting. From now on both the old mechanism (xtal or TBG referenced as parent clock in `clocks` phandle) and the new one (UART clock referenced in the `clocks` phandle) are supported, to provide full backward compatibility with existing DTS files, full backward compatibility with existing boot loaders, and to provide new features (runtime clock configuration to allow higher baudrates than 230400 Bd). New features are available only with new DTS files. There was also a discussion about how the UART node and the clock-controller node could be wrapped together in a new binding [1, 2]. As explained there, this is not possible if we want to keep backwards compatibility with existing bootloaders, and thus we are doing this by putting the UART clock-controller node inside the UART1 node. [1] https://lore.kernel.org/linux-serial/20220120000651.in7s6nazif5qjkme@pali/ [2] https://lore.kernel.org/linux-serial/20220125204006.A6D09C340E0@smtp.kernel.org/ Reviewed-by: Marek Behún Reviewed-by: Stephen Boyd Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Link: https://lore.kernel.org/r/20220219152818.4319-4-kabel@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/mvebu-uart.c | 521 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 520 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 407a98ec0791..66916397a19c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1446,6 +1446,7 @@ config SERIAL_STM32_CONSOLE 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 diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index ab226da75f7b..56278b29f5f5 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -8,12 +8,14 @@ */ #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -68,8 +70,31 @@ #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 @@ -153,6 +178,8 @@ 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) { @@ -445,6 +472,7 @@ static void mvebu_uart_shutdown(struct uart_port *port) static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) { unsigned int d_divisor, m_divisor; + unsigned long flags; u32 brdv, osamp; if (!port->uartclk) @@ -463,10 +491,12 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) m_divisor = OSAMP_DEFAULT_DIVISOR; d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor); + 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; @@ -762,6 +792,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); @@ -770,7 +801,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); @@ -782,13 +815,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); @@ -972,6 +1008,478 @@ 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 long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate, + 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_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, + .round_rate = mvebu_uart_clock_round_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 (IS_ERR(uart_clock_base->reg1)) + return PTR_ERR(uart_clock_base->reg1); + + 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 (IS_ERR(uart_clock_base->reg2)) + return PTR_ERR(uart_clock_base->reg2); + + 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_DEFAULT_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_DEFAULT_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_DEFAULT_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; @@ -980,10 +1488,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); -- cgit v1.2.3 From 694b7112473a33a3685e75f6cc45cbe939950753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 19 Feb 2022 16:28:17 +0100 Subject: serial: mvebu-uart: implement support for baudrates higher than 230400 Bd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement simple usage of fractional divisor. When main divisor D is too large to represent requested baudrate then use divisor M from the fractional divisor feature. All the M prescalers are set to the same and maximal value 63, so the fractional part of the fractional divisor is not used at all. We also determine upper limit for possible baudrates. Experiments show that UART at baudrate 1500000 Bd with this configuration is stable. So there is no need to implement complicated calculation of fractional coefficients yet. To use this feature with higher baudrates, it is required to use UART clock provided by UART clock driver. Default boot xtal clock is not capable of higher baudrates. Reviewed-by: Marek Behún Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Link: https://lore.kernel.org/r/20220219152818.4319-6-kabel@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 83 ++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 56278b29f5f5..2e9263888ddc 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -99,6 +99,7 @@ #define UART_OSAMP 0x14 #define OSAMP_DEFAULT_DIVISOR 16 #define OSAMP_DIVISORS_MASK 0x3F3F3F3F +#define OSAMP_MAX_DIVISOR 63 #define MVEBU_NR_UARTS 2 @@ -479,18 +480,60 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) return -EOPNOTSUPP; /* - * 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) * - * 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. + * 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); + * + * 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_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; @@ -500,6 +543,9 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) 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; @@ -529,14 +575,16 @@ static void mvebu_uart_set_termios(struct uart_port *port, port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR; /* - * Maximal divisor is 1023 * 16 when using default (x16) scheme. - * 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. */ - min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16); - max_baud = 230400; + 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); if (mvebu_uart_baud_rate_set(port, baud)) { @@ -1395,14 +1443,14 @@ static int mvebu_uart_clock_probe(struct platform_device *pdev) * Calculate the smallest TBG d1 and d2 divisors that * still can provide 9600 baudrate. */ - d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_DEFAULT_DIVISOR * + 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_DEFAULT_DIVISOR * + d2 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX * d1); if (d2 < 1) d2 = 1; @@ -1417,8 +1465,7 @@ static int mvebu_uart_clock_probe(struct platform_device *pdev) } /* Skip clock source which cannot provide 9600 baudrate */ - if (rate > 9600 * OSAMP_DEFAULT_DIVISOR * BRDV_BAUD_MAX * d1 * - d2) + if (rate > 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX * d1 * d2) continue; /* -- cgit v1.2.3 From 6ba6351b023eb8a6e8919f4aa5b85241b2025ca2 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 12 Feb 2022 17:30:53 +0000 Subject: serial: 8250: Correct Kconfig help text for blacklisted PCI devices Correct the Kconfig help text for SERIAL_8250_LPSS, SERIAL_8250_MID and SERIAL_8250_PERICOM configuration options for dedicated PCI UART drivers that have been blacklisted in the generic PCI 8250 UART driver and as from commit a13e19cf3dc10 ("serial: 8250_lpss: split LPSS driver to separate module"), commit d9eda9bab2372 ("serial: 8250_pci: Intel MID UART support to its own driver"), and commit fcfd3c09f4078 ("serial: 8250_pci: Split out Pericom driver") respectively are not handled by said driver anymore (rather than for extra features only, as the current text indicates), and therefore require the respective dedicated drivers to work at all. Signed-off-by: Maciej W. Rozycki Link: https://lore.kernel.org/r/alpine.DEB.2.21.2202121704560.34636@angie.orcam.me.uk Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 9d415a38cc71..cd93ea6eed65 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -479,11 +479,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" @@ -494,17 +495,18 @@ 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 extra features - present on the Pericom and Acces I/O UARTs. + 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" -- cgit v1.2.3 From c5e453f9c9a97c03d6c050a2bfbe6859fe1d9d5a Mon Sep 17 00:00:00 2001 From: Yang Guang Date: Sat, 12 Feb 2022 10:19:48 +0800 Subject: serial: 8250_aspeed_vuart: replace snprintf with sysfs_emit coccinelle report: ./drivers/tty/serial/8250/8250_aspeed_vuart.c:85:8-16: WARNING: use scnprintf or sprintf ./drivers/tty/serial/8250/8250_aspeed_vuart.c:174:8-16: WARNING: use scnprintf or sprintf ./drivers/tty/serial/8250/8250_aspeed_vuart.c:127:8-16: WARNING: use scnprintf or sprintf Use sysfs_emit instead of scnprintf or sprintf makes more sense. Reported-by: Zeal Robot Signed-off-by: Yang Guang Signed-off-by: David Yang Link: https://lore.kernel.org/r/fed40753603dac4d14b17970c88e6f5f936348c1.1644541843.git.yang.guang5@zte.com.cn Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_aspeed_vuart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index c2cecc6f47db..93fe10c680fb 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -82,7 +82,7 @@ static ssize_t lpc_address_show(struct device *dev, addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) | (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL)); - return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr); + return sysfs_emit(buf, "0x%x\n", addr); } static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr) @@ -124,7 +124,7 @@ static ssize_t sirq_show(struct device *dev, 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) @@ -171,7 +171,7 @@ static ssize_t sirq_polarity_show(struct device *dev, 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, -- cgit v1.2.3 From 67ec6dd0b257bd81b4e9fcac89b29da72f6265e5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 15 Feb 2022 12:09:20 +0200 Subject: serial: 8250_mid: Balance reference count for PCI DMA device The pci_get_slot() increases its reference count, the caller must decrement the reference count by calling pci_dev_put(). Fixes: 90b9aacf912a ("serial: 8250_pci: add Intel Tangier support") Fixes: f549e94effa1 ("serial: 8250_pci: add Intel Penwell ports") Reported-by: Qing Wang Signed-off-by: Andy Shevchenko Depends-on: d9eda9bab237 ("serial: 8250_pci: Intel MID UART support to its own driver") Link: https://lore.kernel.org/r/20220215100920.41984-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 83592b51a996..a2a03acb04ad 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -73,6 +73,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 +129,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; @@ -328,9 +338,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; } @@ -340,8 +350,7 @@ 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 = { @@ -349,6 +358,7 @@ static const struct mid8250_board pnw_board = { .freq = 50000000, .base_baud = 115200, .setup = pnw_setup, + .exit = pnw_exit, }; static const struct mid8250_board tng_board = { @@ -356,6 +366,7 @@ static const struct mid8250_board tng_board = { .freq = 38400000, .base_baud = 1843200, .setup = tng_setup, + .exit = tng_exit, }; static const struct mid8250_board dnv_board = { -- cgit v1.2.3 From 5318f70da7e82649d794fc27d8a127c22aa3566e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Feb 2022 17:12:40 +0200 Subject: serial: 8250_lpss: Balance reference count for PCI DMA device The pci_get_slot() increases its reference count, the caller must decrement the reference count by calling pci_dev_put(). Fixes: 9a1870ce812e ("serial: 8250: don't use slave_id of dma_slave_config") Depends-on: a13e19cf3dc1 ("serial: 8250_lpss: split LPSS driver to separate module") Reported-by: Qing Wang Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220223151240.70248-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_lpss.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index d3bafec7619d..0f5af061e0b4 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -117,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: @@ -137,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; @@ -152,6 +153,14 @@ 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; @@ -170,6 +179,13 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) 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, @@ -344,8 +360,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; } @@ -356,8 +371,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); } @@ -365,12 +379,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 = { -- cgit v1.2.3 From 18662a1d8f35ef6b1758578ad884e37746c753c8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 12:10:24 +0100 Subject: tty: serial: mpc52xx_uart: make rx/tx hooks return unsigned All these return bitmasks, so it makes more sense to return unsigned -- this is what a reader and also all the callers expect. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224111028.20917-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mpc52xx_uart.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 2704dc988e4a..8a6958377764 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -83,11 +83,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); @@ -203,34 +203,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); @@ -1365,7 +1365,7 @@ static const struct uart_ops mpc52xx_uart_ops = { /* Interrupt handling */ /* ======================================================================== */ -static inline int +static inline unsigned int mpc52xx_uart_int_rx_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; -- cgit v1.2.3 From d185a852e17c2ca6a3c796dbde4ee98d0ecbded1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 12:10:25 +0100 Subject: tty: serial: serial_txx9: remove info print from init Remove the hello print among with version and name definitions. Drivers should print nothing if they are successful. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224111028.20917-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_txx9.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index aaca4fe38486..cd38cf1f03cb 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -26,9 +26,6 @@ #include -static char *serial_version = "1.11"; -static char *serial_name = "TX39/49 Serial driver"; - #define PASS_LIMIT 256 #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) @@ -1255,8 +1252,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; -- cgit v1.2.3 From f52361790aaf58d489952a7641777549979428f4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 12:10:28 +0100 Subject: tty: serial: lpc32xx_hs: use serial_lpc32xx_stop_tx() helper Instead of open-coding what serial_lpc32xx_stop_tx() already does, call it in __serial_lpc32xx_tx() directly. Cc: Vladimir Zapolskiy Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224111028.20917-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lpc32xx_hs.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 07c4161eb4cc..54437a087aa0 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -276,10 +276,11 @@ static void __serial_lpc32xx_rx(struct uart_port *port) tty_flip_buffer_push(tport); } +static void serial_lpc32xx_stop_tx(struct uart_port *port); + static void __serial_lpc32xx_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; - unsigned int tmp; if (port->x_char) { writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase)); @@ -306,11 +307,8 @@ static void __serial_lpc32xx_tx(struct uart_port *port) uart_write_wakeup(port); 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)); - } + if (uart_circ_empty(xmit)) + serial_lpc32xx_stop_tx(port); } static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) -- cgit v1.2.3 From f166d19f9e82431e121213371ce2eec5f8cf39be Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 12:10:27 +0100 Subject: tty: serial: amba-pl010: use more uart_port pointers The code uses uart_amba_port::port on many places. Sometimes it even needs not uart_amba_port itself. So simplify the code on many places and remove the need of uart_amba_port on some places completely. No functional changes intended. The objdump -d output shows only a code move in pl010_rx_chars(). Signed-off-by: Jiri Slaby Cc: Russell King Link: https://lore.kernel.org/r/20220224111028.20917-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl010.c | 174 +++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 47654073123d..b73375214ac3 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -110,38 +110,38 @@ 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; - 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,56 +151,57 @@ 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); } - tty_flip_buffer_push(&uap->port.state->port); + 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; + struct circ_buf *xmit = &port->state->xmit; int count; - if (uap->port.x_char) { - writel(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; + if (port->x_char) { + writel(port->x_char, port->membase + UART01x_DR); + port->icount.tx++; + port->x_char = 0; return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { - pl010_stop_tx(&uap->port); + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + pl010_stop_tx(port); return; } - count = uap->port.fifosize >> 1; + count = port->fifosize >> 1; do { - writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); + writel(xmit->buf[xmit->tail], port->membase + UART01x_DR); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; + 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); + uart_write_wakeup(port); if (uart_circ_empty(xmit)) - pl010_stop_tx(&uap->port); + pl010_stop_tx(port); } 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; @@ -209,65 +210,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); + spin_lock(&port->lock); - 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); + spin_unlock(&port->lock); 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) @@ -284,24 +283,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); + spin_lock_irqsave(&port->lock, 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); + spin_unlock_irqrestore(&port->lock, flags); } static int pl010_startup(struct uart_port *port) @@ -317,25 +314,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; @@ -353,17 +350,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,8 +372,6 @@ static void pl010_set_termios(struct uart_port *port, struct ktermios *termios, 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; @@ -384,7 +379,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) { @@ -408,63 +403,63 @@ 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); + spin_lock_irqsave(&port->lock, 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; - 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; /* 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); + spin_unlock_irqrestore(&port->lock, flags); } static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios) @@ -558,21 +553,20 @@ static struct uart_amba_port *amba_ports[UART_NR]; static void pl010_console_putchar(struct uart_port *port, int 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); @@ -580,20 +574,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); } -- cgit v1.2.3 From 841f913e770f3cfb69023f00557e37cb23230861 Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Fri, 25 Feb 2022 15:39:17 +0800 Subject: tty: serial: meson: Move request the register region to probe This simplifies resetting the UART controller during probe and will make it easier to integrate the common clock code which will require the registers at probe time as well. Reviewed-by: Jiri Slaby Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220225073922.3947-2-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 45e00d928253..6b80e41b4cc1 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -395,24 +395,11 @@ static int meson_uart_verify_port(struct uart_port *port, static void meson_uart_release_port(struct uart_port *port) { - devm_iounmap(port->dev, port->membase); - port->membase = NULL; - devm_release_mem_region(port->dev, port->mapbase, port->mapsize); + /* nothing to do */ } static int meson_uart_request_port(struct uart_port *port) { - if (!devm_request_mem_region(port->dev, port->mapbase, port->mapsize, - dev_name(port->dev))) { - dev_err(port->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = devm_ioremap(port->dev, port->mapbase, - port->mapsize); - if (!port->membase) - return -ENOMEM; - return 0; } @@ -733,6 +720,18 @@ static int meson_uart_probe(struct platform_device *pdev) if (!port) return -ENOMEM; + if (!devm_request_mem_region(&pdev->dev, res_mem->start, + resource_size(res_mem), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Memory region busy\n"); + return -EBUSY; + } + + port->membase = devm_ioremap(&pdev->dev, res_mem->start, + resource_size(res_mem)); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + ret = meson_uart_probe_clocks(pdev, port); if (ret) return ret; @@ -754,10 +753,7 @@ static int meson_uart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, port); /* reset port before registering (and possibly registering console) */ - if (meson_uart_request_port(port) >= 0) { - meson_uart_reset(port); - meson_uart_release_port(port); - } + meson_uart_reset(port); ret = uart_add_one_port(&meson_uart_driver, port); if (ret) -- cgit v1.2.3 From 6436dd8f9b25ea756b27ca0ec10d017ea51b42e2 Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Fri, 25 Feb 2022 15:39:18 +0800 Subject: tty: serial: meson: Use devm_ioremap_resource to get register mapped memory Replace devm_request_mem_region and devm_ioremap with devm_ioremap_resource to make the code cleaner. Reviewed-by: Jiri Slaby Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220225073922.3947-3-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 6b80e41b4cc1..7570958d010c 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -720,15 +720,7 @@ static int meson_uart_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res_mem->start, - resource_size(res_mem), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = devm_ioremap(&pdev->dev, res_mem->start, - resource_size(res_mem)); + port->membase = devm_ioremap_resource(&pdev->dev, res_mem); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); -- cgit v1.2.3 From 44023b8e1f14bc72bb773dd84dc3563fc912d210 Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Fri, 25 Feb 2022 15:39:19 +0800 Subject: tty: serial: meson: Describes the calculation of the UART baud rate clock using a clock frame Using the common Clock code to describe the UART baud rate clock makes it easier for the UART driver to be compatible with the baud rate requirements of the UART IP on different meson chips. Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220225073922.3947-4-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 194 +++++++++++++++++++++++++++++----------- 1 file changed, 142 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 7570958d010c..4768d51fac70 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -65,9 +66,7 @@ #define AML_UART_RECV_IRQ(c) ((c) & 0xff) /* AML_UART_REG5 bits */ -#define AML_UART_BAUD_MASK 0x7fffff #define AML_UART_BAUD_USE BIT(23) -#define AML_UART_BAUD_XTAL BIT(24) #define AML_UART_PORT_NUM 12 #define AML_UART_PORT_OFFSET 6 @@ -76,6 +75,11 @@ #define AML_UART_POLL_USEC 5 #define AML_UART_TIMEOUT_USEC 10000 +struct meson_uart_data { + struct clk *baud_clk; + bool use_xtal_clk; +}; + static struct uart_driver meson_uart_driver; static struct uart_port *meson_ports[AML_UART_PORT_NUM]; @@ -293,19 +297,17 @@ static int meson_uart_startup(struct uart_port *port) static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) { + struct meson_uart_data *private_data = port->private_data; u32 val; while (!meson_uart_tx_empty(port)) cpu_relax(); - if (port->uartclk == 24000000) { - val = ((port->uartclk / 3) / baud) - 1; - val |= AML_UART_BAUD_XTAL; - } else { - val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1; - } + val = readl(port->membase + AML_UART_REG5); val |= AML_UART_BAUD_USE; writel(val, port->membase + AML_UART_REG5); + + clk_set_rate(private_data->baud_clk, baud); } static void meson_uart_set_termios(struct uart_port *port, @@ -395,11 +397,20 @@ static int meson_uart_verify_port(struct uart_port *port, static void meson_uart_release_port(struct uart_port *port) { - /* nothing to do */ + struct meson_uart_data *private_data = port->private_data; + + clk_disable_unprepare(private_data->baud_clk); } static int meson_uart_request_port(struct uart_port *port) { + struct meson_uart_data *private_data = port->private_data; + int ret; + + ret = clk_prepare_enable(private_data->baud_clk); + if (ret) + return ret; + return 0; } @@ -629,57 +640,106 @@ static struct uart_driver meson_uart_driver = { .cons = MESON_SERIAL_CONSOLE, }; -static inline struct clk *meson_uart_probe_clock(struct device *dev, - const char *id) -{ - struct clk *clk = NULL; - int ret; - - clk = devm_clk_get(dev, id); - if (IS_ERR(clk)) - return clk; - - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(dev, "couldn't enable clk\n"); - return ERR_PTR(ret); - } +static const struct clk_div_table xtal_div_table[] = { + { 0, 3 }, + { 1, 1 }, + { 2, 2 }, + { 3, 2 }, +}; - devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - clk); +static u32 use_xtal_mux_table; - return clk; -} - -static int meson_uart_probe_clocks(struct platform_device *pdev, - struct uart_port *port) +static int meson_uart_probe_clocks(struct uart_port *port) { - struct clk *clk_xtal = NULL; - struct clk *clk_pclk = NULL; - struct clk *clk_baud = NULL; + struct meson_uart_data *private_data = port->private_data; + struct clk *clk_baud, *clk_xtal; + struct clk_hw *hw, *clk81_div4_hw; + char clk_name[32]; + struct clk_parent_data use_xtal_mux_parents; - clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk"); - if (IS_ERR(clk_pclk)) - return PTR_ERR(clk_pclk); + clk_baud = devm_clk_get(port->dev, "baud"); + if (IS_ERR(clk_baud)) { + dev_err(port->dev, "Failed to get the 'baud' clock\n"); + return PTR_ERR(clk_baud); + } - clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal"); + clk_xtal = devm_clk_get(port->dev, "xtal"); if (IS_ERR(clk_xtal)) - return PTR_ERR(clk_xtal); - - clk_baud = meson_uart_probe_clock(&pdev->dev, "baud"); - if (IS_ERR(clk_baud)) - return PTR_ERR(clk_baud); + return dev_err_probe(port->dev, PTR_ERR(clk_xtal), + "Failed to get the 'xtal' clock\n"); + + snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), + "clk81_div4"); + clk81_div4_hw = devm_clk_hw_register_fixed_factor(port->dev, + clk_name, + __clk_get_name(clk_baud), + CLK_SET_RATE_NO_REPARENT, + 1, 4); + if (IS_ERR(clk81_div4_hw)) + return PTR_ERR(clk81_div4_hw); + + snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), + "xtal_div"); + hw = devm_clk_hw_register_divider_table(port->dev, + clk_name, + __clk_get_name(clk_baud), + CLK_SET_RATE_NO_REPARENT, + port->membase + AML_UART_REG5, + 26, 2, + CLK_DIVIDER_READ_ONLY, + xtal_div_table, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + if (private_data->use_xtal_clk) { + use_xtal_mux_table = 1; + use_xtal_mux_parents.hw = hw; + } else { + use_xtal_mux_parents.hw = clk81_div4_hw; + } - port->uartclk = clk_get_rate(clk_baud); + snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), + "use_xtal"); + hw = __devm_clk_hw_register_mux(port->dev, NULL, + clk_name, + 1, + NULL, NULL, + &use_xtal_mux_parents, + CLK_SET_RATE_PARENT, + port->membase + AML_UART_REG5, + 24, 0x1, + CLK_MUX_READ_ONLY, + &use_xtal_mux_table, NULL); + + if (IS_ERR(hw)) + return PTR_ERR(hw); + + port->uartclk = clk_hw_get_rate(hw); + + snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), + "baud_div"); + hw = devm_clk_hw_register_divider(port->dev, + clk_name, + clk_hw_get_name(hw), + CLK_SET_RATE_PARENT, + port->membase + AML_UART_REG5, + 0, 23, + CLK_DIVIDER_ROUND_CLOSEST, + NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + private_data->baud_clk = hw->clk; return 0; } static int meson_uart_probe(struct platform_device *pdev) { + struct meson_uart_data *private_data; struct resource *res_mem; struct uart_port *port; + struct clk *pclk; u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */ int ret = 0; int irq; @@ -705,6 +765,15 @@ static int meson_uart_probe(struct platform_device *pdev) if (!res_mem) return -ENODEV; + pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pclk), + "Failed to get the 'pclk' clock\n"); + + ret = clk_prepare_enable(pclk); + if (ret) + return ret; + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -724,9 +793,13 @@ static int meson_uart_probe(struct platform_device *pdev) if (IS_ERR(port->membase)) return PTR_ERR(port->membase); - ret = meson_uart_probe_clocks(pdev, port); - if (ret) - return ret; + private_data = devm_kzalloc(&pdev->dev, sizeof(*private_data), + GFP_KERNEL); + if (!private_data) + return -ENOMEM; + + if (device_get_match_data(&pdev->dev)) + private_data->use_xtal_clk = true; port->iotype = UPIO_MEM; port->mapbase = res_mem->start; @@ -740,6 +813,11 @@ static int meson_uart_probe(struct platform_device *pdev) port->x_char = 0; port->ops = &meson_uart_ops; port->fifosize = fifosize; + port->private_data = private_data; + + ret = meson_uart_probe_clocks(port); + if (ret) + return ret; meson_ports[pdev->id] = port; platform_set_drvdata(pdev, port); @@ -766,10 +844,22 @@ static int meson_uart_remove(struct platform_device *pdev) } static const struct of_device_id meson_uart_dt_match[] = { - { .compatible = "amlogic,meson6-uart" }, - { .compatible = "amlogic,meson8-uart" }, - { .compatible = "amlogic,meson8b-uart" }, - { .compatible = "amlogic,meson-gx-uart" }, + { + .compatible = "amlogic,meson6-uart", + .data = (void *)false, + }, + { + .compatible = "amlogic,meson8-uart", + .data = (void *)false, + }, + { + .compatible = "amlogic,meson8b-uart", + .data = (void *)false, + }, + { + .compatible = "amlogic,meson-gx-uart", + .data = (void *)true, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, meson_uart_dt_match); -- cgit v1.2.3 From e5fc2b99840dab2bf870bc3224a8c22445aedf3f Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Fri, 25 Feb 2022 15:39:20 +0800 Subject: tty: serial: meson: Make some bit of the REG5 register writable Make the internal clock source mux and divider writeable, allowing the uart to deviate from the settings intially applied by the ROMCode and using the most appropriate clocks. Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220225073922.3947-5-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 4768d51fac70..ba8dc203b9cb 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -686,7 +686,7 @@ static int meson_uart_probe_clocks(struct uart_port *port) CLK_SET_RATE_NO_REPARENT, port->membase + AML_UART_REG5, 26, 2, - CLK_DIVIDER_READ_ONLY, + CLK_DIVIDER_ROUND_CLOSEST, xtal_div_table, NULL); if (IS_ERR(hw)) return PTR_ERR(hw); @@ -708,7 +708,7 @@ static int meson_uart_probe_clocks(struct uart_port *port) CLK_SET_RATE_PARENT, port->membase + AML_UART_REG5, 24, 0x1, - CLK_MUX_READ_ONLY, + CLK_MUX_ROUND_CLOSEST, &use_xtal_mux_table, NULL); if (IS_ERR(hw)) -- cgit v1.2.3 From 19b2ba0baffcd707eecd718da4941e74af341e4f Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Fri, 25 Feb 2022 15:39:21 +0800 Subject: tty: serial: meson: The system stuck when you run the stty command on the console to change the baud rate Start the console and run the following commands in turn: stty -F /dev/ttyAML0 115200 and stty -F /dev/ttyAML0 921600. The system will stuck. Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220225073922.3947-6-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index ba8dc203b9cb..d19349ead738 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -365,8 +365,13 @@ static void meson_uart_set_termios(struct uart_port *port, writel(val, port->membase + AML_UART_CONTROL); baud = uart_get_baud_rate(port, termios, old, 50, 4000000); + + spin_unlock_irqrestore(&port->lock, flags); + meson_uart_change_speed(port, baud); + spin_lock_irqsave(&port->lock, flags); + port->read_status_mask = AML_UART_TX_FIFO_WERR; if (iflags & INPCK) port->read_status_mask |= AML_UART_PARITY_ERR | -- cgit v1.2.3 From 5427c352a993748846263262e70652216e75b2a5 Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Fri, 25 Feb 2022 15:39:22 +0800 Subject: tty: serial: meson: Added S4 SOC compatibility Make UART driver compatible with S4 SOC UART. Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220225073922.3947-7-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index d19349ead738..bf6be5468aaf 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -865,6 +865,10 @@ static const struct of_device_id meson_uart_dt_match[] = { .compatible = "amlogic,meson-gx-uart", .data = (void *)true, }, + { + .compatible = "amlogic,meson-s4-uart", + .data = (void *)true, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, meson_uart_dt_match); -- cgit v1.2.3 From dedab69fd650ea74710b2e626e63fd35584ef773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 15 Feb 2022 17:02:36 +0100 Subject: serial: 8250: Fix race condition in RTS-after-send handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set em485->active_timer = NULL isn't always enough to take out the stop timer. While there is a check that it acts in the right state (i.e. waiting for RTS-after-send to pass after sending some chars) but the following might happen: - CPU1: some chars send, shifter becomes empty, stop tx timer armed - CPU0: more chars send before RTS-after-send expired - CPU0: shifter empty irq, port lock taken - CPU1: tx timer triggers, waits for port lock - CPU0: em485->active_timer = &em485->stop_tx_timer, hrtimer_start(), releases lock() - CPU1: get lock, see em485->active_timer == &em485->stop_tx_timer, tear down RTS too early This fix bases on research done by Steffen Trumtrar. Fixes: b86f86e8e7c5 ("serial: 8250: fix potential deadlock in rs485-mode") Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220215160236.344236-1-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 728d60be8975..d30a6c1c4c20 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1623,6 +1623,18 @@ static inline void 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) { -- cgit v1.2.3 From 9e8d5470325f25bed7d33f9faaae6d5e4f313650 Mon Sep 17 00:00:00 2001 From: Hammer Hsieh Date: Tue, 22 Feb 2022 17:36:03 +0800 Subject: serial: sunplus-uart: Add Sunplus SoC UART Driver Add Sunplus SoC UART Driver. SP7021 UART block contains 5 UARTs. There are UART0~4 that supported in SP7021, the features list as below. Support Full-duplex communication. Support data packet length configurable. Support stop bit number configurable. Support force break condition. Support baud rate configurable. Support error detection and report. Support RXD Noise Rejection Vote configurable. UART0 pinout only support TX/RX two pins. UART1 to UART4 pinout support TX/RX/CTS/RTS four pins. Normally UART0 used for kernel console, also can be used for normal uart. Command line set "console=ttySUP0,115200", SUP means Sunplus Uart Port. UART driver probe will create path named "/dev/ttySUPx". https://sunplus.atlassian.net/wiki/spaces/doc/pages/1873412290/13.+Universal+Asynchronous+Receiver+Transmitter+UART Signed-off-by: Hammer Hsieh Link: https://lore.kernel.org/r/1645522563-17183-3-git-send-email-hammerh0314@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 25 ++ drivers/tty/serial/Makefile | 1 + drivers/tty/serial/sunplus-uart.c | 770 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 796 insertions(+) create mode 100644 drivers/tty/serial/sunplus-uart.c (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 66916397a19c..e952ec5c7a7c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1564,6 +1564,31 @@ config SERIAL_LITEUART_CONSOLE and warnings and which allows logins in single user mode). Otherwise, say 'N'. +config SERIAL_SUNPLUS + tristate "Sunplus UART support" + depends on OF || 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". + endmenu config SERIAL_MCTRL_GPIO diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 7da0856cd198..61cc8de95571 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -87,6 +87,7 @@ obj-$(CONFIG_SERIAL_RDA) += rda-uart.o obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o +obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c new file mode 100644 index 000000000000..450c8e75abb4 --- /dev/null +++ b/drivers/tty/serial/sunplus-uart.c @@ -0,0 +1,770 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sunplus SoC UART driver + * + * Author: Hammer Hsieh + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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; + + spin_lock_irqsave(&port->lock, 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); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + sp_uart_put_char(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + sunplus_stop_tx(port); + return; + } + + do { + sp_uart_put_char(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; + port->icount.tx++; + + if (uart_circ_empty(xmit)) + break; + } while (sunplus_tx_buf_not_full(port)); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + sunplus_stop_tx(port); +} + +static void receive_chars(struct uart_port *port) +{ + unsigned int lsr = readl(port->membase + SUP_UART_LSR); + unsigned int 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_handle_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; + + spin_lock(&port->lock); + + 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); + + spin_unlock(&port->lock); + + 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; + + spin_lock_irqsave(&port->lock, 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); + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void sunplus_shutdown(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, 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 */ + spin_unlock_irqrestore(&port->lock, flags); + + free_irq(port->irq, port); +} + +static void sunplus_set_termios(struct uart_port *port, + struct ktermios *termios, + 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; + } + + spin_lock_irqsave(&port->lock, 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); + + spin_unlock_irqrestore(&port->lock, 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; +} + +#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE +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 +struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR]; + +static void sunplus_uart_console_putchar(struct uart_port *port, int 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; + + local_irq_save(flags); + + if (sunplus_console_ports[co->index]->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock); + else + spin_lock(&sunplus_console_ports[co->index]->port.lock); + + uart_console_write(&sunplus_console_ports[co->index]->port, s, count, + sunplus_uart_console_putchar); + + if (locked) + spin_unlock(&sunplus_console_ports[co->index]->port.lock); + + local_irq_restore(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 +}; +#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 = &sunplus_uart_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 int 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); + + return 0; +} + +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, int 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 "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 988c5bbea59ffacb7762983760ae40d721ea304b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 10:55:55 +0100 Subject: tty: serial: make use of UART_LCR_WLEN() + tty_get_char_size() Having a generic UART_LCR_WLEN() macro and the tty_get_char_size() helper, we can remove all those repeated switch-cases in drivers. Cc: Laxman Dewangan Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org Reviewed-by: Thierry Reding Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224095558.30929-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 16 +--------------- drivers/tty/serial/8250/8250_port.c | 16 +--------------- drivers/tty/serial/jsm/jsm_cls.c | 16 +--------------- drivers/tty/serial/jsm/jsm_neo.c | 16 +--------------- drivers/tty/serial/omap-serial.c | 16 +--------------- drivers/tty/serial/pxa.c | 16 +--------------- drivers/tty/serial/serial-tegra.c | 22 ++++------------------ drivers/tty/serial/vr41xx_siu.c | 15 +-------------- 8 files changed, 11 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 73e5f1dbd075..ac8bfa042391 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -357,21 +357,7 @@ static void omap_8250_set_termios(struct uart_port *port, unsigned char cval = 0; unsigned int baud; - 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; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d30a6c1c4c20..25b84d30e771 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2605,21 +2605,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, { 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; - } + cval = UART_LCR_WLEN(tty_get_char_size(c_cflag)); if (c_cflag & CSTOPB) cval |= UART_LCR_STOP; diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index b507a2cec926..b280da50290c 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -737,21 +737,7 @@ static void cls_param(struct jsm_channel *ch) 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); diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index c6f927a76c3b..c4fd31de04b4 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -1008,21 +1008,7 @@ static void neo_param(struct jsm_channel *ch) 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); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0862941862c8..b4e060205e61 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -808,21 +808,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, 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; diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 30b099746a75..b4987b417f19 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -430,21 +430,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; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index b6223fab0687..d942ab152f5a 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1277,6 +1277,7 @@ static void tegra_uart_set_termios(struct uart_port *u, unsigned int baud; unsigned long flags; unsigned int lcr; + unsigned char char_bits; int symb_bit = 1; struct clk *parent_clk = clk_get_parent(tup->uart_clk); unsigned long parent_clk_rate = clk_get_rate(parent_clk); @@ -1316,25 +1317,10 @@ static void tegra_uart_set_termios(struct uart_port *u, } } + char_bits = tty_get_char_size(termios->c_cflag); + symb_bit += char_bits; 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) { diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index 647198b1e2b9..8586a56d4deb 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -504,20 +504,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new, 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; - } + lcr = UART_LCR_WLEN(tty_get_char_size(c_cflag)); if (c_cflag & CSTOPB) lcr |= UART_LCR_STOP; -- cgit v1.2.3 From 5e1440bc23324846a003052787af6aa492e90773 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 10:55:56 +0100 Subject: USB: serial: make use of UART_LCR_WLEN() + tty_get_char_size() Having a generic UART_LCR_WLEN() macro and the tty_get_char_size() helper, we can remove all those repeated switch-cases in drivers. Cc: Johan Hovold Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224095558.30929-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ark3116.c | 17 ++--------------- drivers/usb/serial/f81232.c | 16 +--------------- drivers/usb/serial/f81534.c | 16 +--------------- drivers/usb/serial/mos7720.c | 20 +------------------- drivers/usb/serial/quatech2.c | 16 +--------------- drivers/usb/serial/ssu100.c | 16 +--------------- 6 files changed, 7 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5dd710e9fe7d..c0e4df87ff22 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -200,21 +200,8 @@ static void ark3116_set_termios(struct tty_struct *tty, __u8 lcr, hcr, eval; /* set data bit count */ - switch (cflag & CSIZE) { - case CS5: - lcr = UART_LCR_WLEN5; - break; - case CS6: - lcr = UART_LCR_WLEN6; - break; - case CS7: - lcr = UART_LCR_WLEN7; - break; - default: - case CS8: - lcr = UART_LCR_WLEN8; - break; - } + lcr = UART_LCR_WLEN(tty_get_char_size(cflag)); + if (cflag & CSTOPB) lcr |= UART_LCR_STOP; if (cflag & PARENB) diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 3ad1f515fb68..d9f20256a6a8 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -643,21 +643,7 @@ static void f81232_set_termios(struct tty_struct *tty, if (C_CSTOPB(tty)) new_lcr |= UART_LCR_STOP; - switch (C_CSIZE(tty)) { - case CS5: - new_lcr |= UART_LCR_WLEN5; - break; - case CS6: - new_lcr |= UART_LCR_WLEN6; - break; - case CS7: - new_lcr |= UART_LCR_WLEN7; - break; - default: - case CS8: - new_lcr |= UART_LCR_WLEN8; - break; - } + new_lcr |= UART_LCR_WLEN(tty_get_char_size(tty->termios.c_cflag)); mutex_lock(&priv->lock); diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index c0bca52ef92a..d789c1ec87b3 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -970,21 +970,7 @@ static void f81534_set_termios(struct tty_struct *tty, if (C_CSTOPB(tty)) new_lcr |= UART_LCR_STOP; - switch (C_CSIZE(tty)) { - case CS5: - new_lcr |= UART_LCR_WLEN5; - break; - case CS6: - new_lcr |= UART_LCR_WLEN6; - break; - case CS7: - new_lcr |= UART_LCR_WLEN7; - break; - default: - case CS8: - new_lcr |= UART_LCR_WLEN8; - break; - } + new_lcr |= UART_LCR_WLEN(tty_get_char_size(tty->termios.c_cflag)); baud = tty_get_baud_rate(tty); if (!baud) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 227f43d2bd56..1e12b5f30dcc 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1380,30 +1380,12 @@ static void change_port_settings(struct tty_struct *tty, return; } - lData = UART_LCR_WLEN8; lStop = 0x00; /* 1 stop bit */ lParity = 0x00; /* No parity */ cflag = tty->termios.c_cflag; - /* Change the number of bits */ - switch (cflag & CSIZE) { - case CS5: - lData = UART_LCR_WLEN5; - break; - - case CS6: - lData = UART_LCR_WLEN6; - break; - - case CS7: - lData = UART_LCR_WLEN7; - break; - default: - case CS8: - lData = UART_LCR_WLEN8; - break; - } + lData = UART_LCR_WLEN(tty_get_char_size(cflag)); /* Change the Parity bit */ if (cflag & PARENB) { diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 971907f083a3..36b1e064e51f 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -281,21 +281,7 @@ static void qt2_set_termios(struct tty_struct *tty, new_lcr |= SERIAL_EVEN_PARITY; } - switch (cflag & CSIZE) { - case CS5: - new_lcr |= UART_LCR_WLEN5; - break; - case CS6: - new_lcr |= UART_LCR_WLEN6; - break; - case CS7: - new_lcr |= UART_LCR_WLEN7; - break; - default: - case CS8: - new_lcr |= UART_LCR_WLEN8; - break; - } + new_lcr |= UART_LCR_WLEN(tty_get_char_size(cflag)); baud = tty_get_baud_rate(tty); if (!baud) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3baf7c0f5a98..181e302136a5 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -231,21 +231,7 @@ static void ssu100_set_termios(struct tty_struct *tty, urb_value |= SERIAL_EVEN_PARITY; } - switch (cflag & CSIZE) { - case CS5: - urb_value |= UART_LCR_WLEN5; - break; - case CS6: - urb_value |= UART_LCR_WLEN6; - break; - case CS7: - urb_value |= UART_LCR_WLEN7; - break; - default: - case CS8: - urb_value |= UART_LCR_WLEN8; - break; - } + urb_value |= UART_LCR_WLEN(tty_get_char_size(cflag)); baud = tty_get_baud_rate(tty); if (!baud) -- cgit v1.2.3 From 834119f5763148e2a9c56785cd09dd397fd24020 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 10:55:57 +0100 Subject: sdio_uart: make use of UART_LCR_WLEN() + tty_get_char_size() Having a generic UART_LCR_WLEN() macro and the tty_get_char_size() helper, we can remove all those repeated switch-cases in drivers. Cc: Ulf Hansson Cc: linux-mmc@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224095558.30929-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/sdio_uart.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index 04c0823e0359..414aa82abc39 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -250,21 +251,7 @@ static void sdio_uart_change_speed(struct sdio_uart_port *port, unsigned char cval, fcr = 0; 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; -- cgit v1.2.3 From e7d6f84c9b5aaddf119b11799fd13411d33f13dd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Feb 2022 10:55:58 +0100 Subject: mxser: make use of UART_LCR_WLEN() + tty_get_char_size() Having a generic UART_LCR_WLEN() macro and the tty_get_char_size() helper, we can remove all those repeated switch-cases in drivers. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220224095558.30929-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 836c9eca2946..6ebd3e4ed859 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -588,21 +588,7 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term } /* byte size and parity */ - switch (cflag & CSIZE) { - default: - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - case CS8: - cval = UART_LCR_WLEN8; - break; - } + cval = UART_LCR_WLEN(tty_get_char_size(tty->termios.c_cflag)); if (cflag & CSTOPB) cval |= UART_LCR_STOP; -- cgit v1.2.3 From 31979060cc07600b250d5837a33dae1beacfeb74 Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Mon, 28 Feb 2022 14:49:10 +0800 Subject: tty: serial: meson: Fix the compile link error reported by kernel test robot Describes the calculation of the UART baud rate clock using a clock frame. Forgot to add in Kconfig kernel test Robot compilation error due to COMMON_CLK dependency. Fixes: 44023b8e1f14 ("tty: serial: meson: Describes the calculation of the UART baud rate clock using a clock frame") Reported-by: kernel test robot Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20220228064910.11636-1-yu.tu@amlogic.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index e952ec5c7a7c..a0f2b82fc18b 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -200,6 +200,7 @@ config SERIAL_KGDB_NMI config SERIAL_MESON tristate "Meson serial port support" depends on ARCH_MESON || COMPILE_TEST + depends on COMMON_CLK select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Amlogic -- cgit v1.2.3 From a106848c42b6a0ed4817008373562a4ab67f9e7e Mon Sep 17 00:00:00 2001 From: Hammer Hsieh Date: Tue, 1 Mar 2022 12:19:46 +0800 Subject: serial: sunplus-uart: Fix compile error while CONFIG_SERIAL_SUNPLUS_CONSOLE=n 1. Fix implicit declaration of function 'wait_for_xmitr' issue. 2. Fix 'sunplus_uart_console' undeclared here issue. 3. Fix use of undeclared identifier 'sunplus_uart_console' issue. Fixes: 9e8d5470325f ("serial: sunplus-uart: Add Sunplus SoC UART Driver") Reported-by: Randy Dunlap Reported-by: kernel test robot Tested-by: Randy Dunlap Acked-by: Randy Dunlap Signed-off-by: Hammer Hsieh Link: https://lore.kernel.org/r/1646108386-29905-1-git-send-email-hammerh0314@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sunplus-uart.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index 450c8e75abb4..1c7a30bf5f04 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -441,7 +441,7 @@ static int sunplus_verify_port(struct uart_port *port, struct serial_struct *ser return 0; } -#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE +#if defined(CONFIG_SERIAL_SUNPLUS_CONSOLE) || defined(CONFIG_CONSOLE_POLL) static void wait_for_xmitr(struct uart_port *port) { unsigned int val; @@ -562,6 +562,10 @@ static struct console sunplus_uart_console = { .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 = { @@ -571,7 +575,7 @@ static struct uart_driver sunplus_uart_driver = { .major = TTY_MAJOR, .minor = 64, .nr = SUP_UART_NR, - .cons = &sunplus_uart_console, + .cons = SERIAL_SUNPLUS_CONSOLE, }; static void sunplus_uart_disable_unprepare(void *data) -- cgit v1.2.3 From 16b3ac9041a33fd34990717096476145d08d42fc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 Mar 2022 22:06:50 +0100 Subject: Revert "tty: serial: meson: *" This reverts the following commits: 31979060cc07 tty: serial: meson: Fix the compile link error reported by kernel test robot 5427c352a993 tty: serial: meson: Added S4 SOC compatibility 19b2ba0baffc tty: serial: meson: The system stuck when you run the stty command on the console to change the baud rate e5fc2b99840d tty: serial: meson: Make some bit of the REG5 register writable 44023b8e1f14 tty: serial: meson: Describes the calculation of the UART baud rate clock using a clock frame 6436dd8f9b25 tty: serial: meson: Use devm_ioremap_resource to get register mapped memory 841f913e770f tty: serial: meson: Move request the register region to probe They seem to cause lots of problems with existing hardware platforms, and caused build issues, so revert the whole series all at once. Link: https://lore.kernel.org/r/849a95fd-ae81-9a3b-0c06-dd7826af9eb2@baylibre.com Link: https://lore.kernel.org/all/20220225073922.3947-1-yu.tu@amlogic.com/ Reported-by: Marek Szyprowski Reported-by: Jerome Brunet Cc: Neil Armstrong Cc: Yu Tu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 - drivers/tty/serial/meson_uart.c | 221 ++++++++++++---------------------------- 2 files changed, 67 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a0f2b82fc18b..e952ec5c7a7c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -200,7 +200,6 @@ config SERIAL_KGDB_NMI config SERIAL_MESON tristate "Meson serial port support" depends on ARCH_MESON || COMPILE_TEST - depends on COMMON_CLK select SERIAL_CORE help This enables the driver for the on-chip UARTs of the Amlogic diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index bf6be5468aaf..45e00d928253 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include @@ -66,7 +65,9 @@ #define AML_UART_RECV_IRQ(c) ((c) & 0xff) /* AML_UART_REG5 bits */ +#define AML_UART_BAUD_MASK 0x7fffff #define AML_UART_BAUD_USE BIT(23) +#define AML_UART_BAUD_XTAL BIT(24) #define AML_UART_PORT_NUM 12 #define AML_UART_PORT_OFFSET 6 @@ -75,11 +76,6 @@ #define AML_UART_POLL_USEC 5 #define AML_UART_TIMEOUT_USEC 10000 -struct meson_uart_data { - struct clk *baud_clk; - bool use_xtal_clk; -}; - static struct uart_driver meson_uart_driver; static struct uart_port *meson_ports[AML_UART_PORT_NUM]; @@ -297,17 +293,19 @@ static int meson_uart_startup(struct uart_port *port) static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) { - struct meson_uart_data *private_data = port->private_data; u32 val; while (!meson_uart_tx_empty(port)) cpu_relax(); - val = readl(port->membase + AML_UART_REG5); + if (port->uartclk == 24000000) { + val = ((port->uartclk / 3) / baud) - 1; + val |= AML_UART_BAUD_XTAL; + } else { + val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1; + } val |= AML_UART_BAUD_USE; writel(val, port->membase + AML_UART_REG5); - - clk_set_rate(private_data->baud_clk, baud); } static void meson_uart_set_termios(struct uart_port *port, @@ -365,13 +363,8 @@ static void meson_uart_set_termios(struct uart_port *port, writel(val, port->membase + AML_UART_CONTROL); baud = uart_get_baud_rate(port, termios, old, 50, 4000000); - - spin_unlock_irqrestore(&port->lock, flags); - meson_uart_change_speed(port, baud); - spin_lock_irqsave(&port->lock, flags); - port->read_status_mask = AML_UART_TX_FIFO_WERR; if (iflags & INPCK) port->read_status_mask |= AML_UART_PARITY_ERR | @@ -402,19 +395,23 @@ static int meson_uart_verify_port(struct uart_port *port, static void meson_uart_release_port(struct uart_port *port) { - struct meson_uart_data *private_data = port->private_data; - - clk_disable_unprepare(private_data->baud_clk); + devm_iounmap(port->dev, port->membase); + port->membase = NULL; + devm_release_mem_region(port->dev, port->mapbase, port->mapsize); } static int meson_uart_request_port(struct uart_port *port) { - struct meson_uart_data *private_data = port->private_data; - int ret; + if (!devm_request_mem_region(port->dev, port->mapbase, port->mapsize, + dev_name(port->dev))) { + dev_err(port->dev, "Memory region busy\n"); + return -EBUSY; + } - ret = clk_prepare_enable(private_data->baud_clk); - if (ret) - return ret; + port->membase = devm_ioremap(port->dev, port->mapbase, + port->mapsize); + if (!port->membase) + return -ENOMEM; return 0; } @@ -645,106 +642,57 @@ static struct uart_driver meson_uart_driver = { .cons = MESON_SERIAL_CONSOLE, }; -static const struct clk_div_table xtal_div_table[] = { - { 0, 3 }, - { 1, 1 }, - { 2, 2 }, - { 3, 2 }, -}; +static inline struct clk *meson_uart_probe_clock(struct device *dev, + const char *id) +{ + struct clk *clk = NULL; + int ret; + + clk = devm_clk_get(dev, id); + if (IS_ERR(clk)) + return clk; + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "couldn't enable clk\n"); + return ERR_PTR(ret); + } + + devm_add_action_or_reset(dev, + (void(*)(void *))clk_disable_unprepare, + clk); -static u32 use_xtal_mux_table; + return clk; +} -static int meson_uart_probe_clocks(struct uart_port *port) +static int meson_uart_probe_clocks(struct platform_device *pdev, + struct uart_port *port) { - struct meson_uart_data *private_data = port->private_data; - struct clk *clk_baud, *clk_xtal; - struct clk_hw *hw, *clk81_div4_hw; - char clk_name[32]; - struct clk_parent_data use_xtal_mux_parents; + struct clk *clk_xtal = NULL; + struct clk *clk_pclk = NULL; + struct clk *clk_baud = NULL; - clk_baud = devm_clk_get(port->dev, "baud"); - if (IS_ERR(clk_baud)) { - dev_err(port->dev, "Failed to get the 'baud' clock\n"); - return PTR_ERR(clk_baud); - } + clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk"); + if (IS_ERR(clk_pclk)) + return PTR_ERR(clk_pclk); - clk_xtal = devm_clk_get(port->dev, "xtal"); + clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal"); if (IS_ERR(clk_xtal)) - return dev_err_probe(port->dev, PTR_ERR(clk_xtal), - "Failed to get the 'xtal' clock\n"); - - snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), - "clk81_div4"); - clk81_div4_hw = devm_clk_hw_register_fixed_factor(port->dev, - clk_name, - __clk_get_name(clk_baud), - CLK_SET_RATE_NO_REPARENT, - 1, 4); - if (IS_ERR(clk81_div4_hw)) - return PTR_ERR(clk81_div4_hw); - - snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), - "xtal_div"); - hw = devm_clk_hw_register_divider_table(port->dev, - clk_name, - __clk_get_name(clk_baud), - CLK_SET_RATE_NO_REPARENT, - port->membase + AML_UART_REG5, - 26, 2, - CLK_DIVIDER_ROUND_CLOSEST, - xtal_div_table, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - if (private_data->use_xtal_clk) { - use_xtal_mux_table = 1; - use_xtal_mux_parents.hw = hw; - } else { - use_xtal_mux_parents.hw = clk81_div4_hw; - } + return PTR_ERR(clk_xtal); + + clk_baud = meson_uart_probe_clock(&pdev->dev, "baud"); + if (IS_ERR(clk_baud)) + return PTR_ERR(clk_baud); - snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), - "use_xtal"); - hw = __devm_clk_hw_register_mux(port->dev, NULL, - clk_name, - 1, - NULL, NULL, - &use_xtal_mux_parents, - CLK_SET_RATE_PARENT, - port->membase + AML_UART_REG5, - 24, 0x1, - CLK_MUX_ROUND_CLOSEST, - &use_xtal_mux_table, NULL); - - if (IS_ERR(hw)) - return PTR_ERR(hw); - - port->uartclk = clk_hw_get_rate(hw); - - snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(port->dev), - "baud_div"); - hw = devm_clk_hw_register_divider(port->dev, - clk_name, - clk_hw_get_name(hw), - CLK_SET_RATE_PARENT, - port->membase + AML_UART_REG5, - 0, 23, - CLK_DIVIDER_ROUND_CLOSEST, - NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - private_data->baud_clk = hw->clk; + port->uartclk = clk_get_rate(clk_baud); return 0; } static int meson_uart_probe(struct platform_device *pdev) { - struct meson_uart_data *private_data; struct resource *res_mem; struct uart_port *port; - struct clk *pclk; u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */ int ret = 0; int irq; @@ -770,15 +718,6 @@ static int meson_uart_probe(struct platform_device *pdev) if (!res_mem) return -ENODEV; - pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(pclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(pclk), - "Failed to get the 'pclk' clock\n"); - - ret = clk_prepare_enable(pclk); - if (ret) - return ret; - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -794,17 +733,9 @@ static int meson_uart_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - port->membase = devm_ioremap_resource(&pdev->dev, res_mem); - if (IS_ERR(port->membase)) - return PTR_ERR(port->membase); - - private_data = devm_kzalloc(&pdev->dev, sizeof(*private_data), - GFP_KERNEL); - if (!private_data) - return -ENOMEM; - - if (device_get_match_data(&pdev->dev)) - private_data->use_xtal_clk = true; + ret = meson_uart_probe_clocks(pdev, port); + if (ret) + return ret; port->iotype = UPIO_MEM; port->mapbase = res_mem->start; @@ -818,17 +749,15 @@ static int meson_uart_probe(struct platform_device *pdev) port->x_char = 0; port->ops = &meson_uart_ops; port->fifosize = fifosize; - port->private_data = private_data; - - ret = meson_uart_probe_clocks(port); - if (ret) - return ret; meson_ports[pdev->id] = port; platform_set_drvdata(pdev, port); /* reset port before registering (and possibly registering console) */ - meson_uart_reset(port); + if (meson_uart_request_port(port) >= 0) { + meson_uart_reset(port); + meson_uart_release_port(port); + } ret = uart_add_one_port(&meson_uart_driver, port); if (ret) @@ -849,26 +778,10 @@ static int meson_uart_remove(struct platform_device *pdev) } static const struct of_device_id meson_uart_dt_match[] = { - { - .compatible = "amlogic,meson6-uart", - .data = (void *)false, - }, - { - .compatible = "amlogic,meson8-uart", - .data = (void *)false, - }, - { - .compatible = "amlogic,meson8b-uart", - .data = (void *)false, - }, - { - .compatible = "amlogic,meson-gx-uart", - .data = (void *)true, - }, - { - .compatible = "amlogic,meson-s4-uart", - .data = (void *)true, - }, + { .compatible = "amlogic,meson6-uart" }, + { .compatible = "amlogic,meson8-uart" }, + { .compatible = "amlogic,meson8b-uart" }, + { .compatible = "amlogic,meson-gx-uart" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, meson_uart_dt_match); -- cgit v1.2.3 From cc4c1d05eb10c3ad4c6315f1897bc56b1e7429aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 1 Mar 2022 07:03:30 +0100 Subject: sc16is7xx: Properly resume TX after stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sc16is7xx_stop_tx() clears THRI bit and thus disables THRI interrupt. This makes it possible for transmission to cease indefinitely when more than 64 characters are being sent. The sc16is7xx_handle_tx() call executed by sc16is7xx_tx_proc() can send up to FIFO length (64) characters. If more characters are written to the output buffer, then the THRI interrupt is needed. Solve the issue by enabling THRI interrupt in sc16is7xx_tx_proc(). Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220301060332.2561851-2-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 47 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 21ae2c0b7bbe..17e79af36604 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -315,7 +315,8 @@ struct sc16is7xx_devtype { struct sc16is7xx_one_config { unsigned int flags; - u8 ier_clear; + u8 ier_mask; + u8 ier_val; }; struct sc16is7xx_one { @@ -349,6 +350,9 @@ static struct uart_driver sc16is7xx_uart = { .nr = SC16IS7XX_MAX_DEVS, }; +static void sc16is7xx_ier_set(struct uart_port *port, u8 bit); +static void sc16is7xx_stop_tx(struct uart_port *port); + #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))) @@ -651,6 +655,7 @@ 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; + unsigned long flags; if (unlikely(port->x_char)) { sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); @@ -659,8 +664,12 @@ static void sc16is7xx_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + spin_lock_irqsave(&port->lock, flags); + sc16is7xx_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); return; + } /* Get length of data pending in circular buffer */ to_send = uart_circ_chars_pending(xmit); @@ -687,8 +696,13 @@ static void sc16is7xx_handle_tx(struct uart_port *port) sc16is7xx_fifo_write(port, to_send); } + spin_lock_irqsave(&port->lock, flags); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + sc16is7xx_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); } static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) @@ -751,6 +765,7 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws) { struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned long flags; if ((port->rs485.flags & SER_RS485_ENABLED) && (port->rs485.delay_rts_before_send > 0)) @@ -759,6 +774,10 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws) mutex_lock(&s->efr_lock); sc16is7xx_handle_tx(port); mutex_unlock(&s->efr_lock); + + spin_lock_irqsave(&port->lock, flags); + sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); + spin_unlock_irqrestore(&port->lock, flags); } static void sc16is7xx_reconf_rs485(struct uart_port *port) @@ -813,7 +832,7 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws) 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); @@ -824,8 +843,24 @@ static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + 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 void sc16is7xx_ier_set(struct uart_port *port, u8 bit) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + lockdep_assert_held_once(&port->lock); + one->config.flags |= SC16IS7XX_RECONF_IER; - one->config.ier_clear |= bit; + one->config.ier_mask |= bit; + one->config.ier_val |= bit; kthread_queue_work(&s->kworker, &one->reg_work); } @@ -1067,8 +1102,8 @@ 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 interrupt */ + val = SC16IS7XX_IER_RDI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); return 0; -- cgit v1.2.3 From 21144bab4f1191e01e1cf785720e6af99d86a347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 1 Mar 2022 07:03:31 +0100 Subject: sc16is7xx: Handle modem status lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uart_handle_cts_change() and uart_handle_dcd_change() must be called with port lock being held. Acquire the lock after reading MSR register. Do not acquire spin lock when reading MSR register because I2C/SPI port functions cannot be called with spinlocks held. Update rng and dsr counters. Wake up delta_msr_wait to allow tty notice modem status change. Co-developed-by: Lech Perczak Co-developed-by: Tomasz Moń Signed-off-by: Lech Perczak Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220301060332.2561851-3-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 120 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 17e79af36604..5c247b4a01a9 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -324,8 +324,10 @@ struct sc16is7xx_one { u8 line; struct kthread_work tx_work; struct kthread_work reg_work; + struct kthread_delayed_work ms_work; struct sc16is7xx_one_config config; bool irda_mode; + unsigned int old_mctrl; }; struct sc16is7xx_port { @@ -705,12 +707,56 @@ static void sc16is7xx_handle_tx(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); } +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; + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned long flags; + unsigned int status, changed; + + lockdep_assert_held_once(&s->efr_lock); + + status = sc16is7xx_get_hwmctrl(port); + changed = status ^ one->old_mctrl; + + if (changed == 0) + return; + + one->old_mctrl = status; + + spin_lock_irqsave(&port->lock, 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); + spin_unlock_irqrestore(&port->lock, flags); +} + static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) { struct uart_port *port = &s->p[portno].port; do { unsigned int iir, rxlen; + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); if (iir & SC16IS7XX_IIR_NO_INT_BIT) @@ -727,6 +773,11 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) 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; @@ -874,6 +925,30 @@ static void sc16is7xx_stop_rx(struct uart_port *port) sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); } +static void sc16is7xx_ms_proc(struct kthread_work *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work); + struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + + if (one->port.state) { + mutex_lock(&s->efr_lock); + sc16is7xx_update_mlines(one); + mutex_unlock(&s->efr_lock); + + 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, port); + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + lockdep_assert_held_once(&port->lock); + + kthread_queue_delayed_work(&s->kworker, &one->ms_work, 0); +} + static void sc16is7xx_start_tx(struct uart_port *port) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); @@ -893,10 +968,10 @@ 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, 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) @@ -920,8 +995,12 @@ static void sc16is7xx_set_termios(struct uart_port *port, struct ktermios *old) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, 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; @@ -1010,8 +1089,15 @@ static void sc16is7xx_set_termios(struct uart_port *port, /* Setup baudrate generator */ baud = sc16is7xx_set_baud(port, baud); + spin_lock_irqsave(&port->lock, 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); + + spin_unlock_irqrestore(&port->lock, flags); } static int sc16is7xx_config_rs485(struct uart_port *port, @@ -1052,6 +1138,7 @@ static int sc16is7xx_startup(struct uart_port *port) struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val; + unsigned long flags; sc16is7xx_power(port, 1); @@ -1102,16 +1189,25 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_EFCR_TXDISABLE_BIT, 0); - /* Enable RX interrupt */ - val = SC16IS7XX_IER_RDI_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 */ + spin_lock_irqsave(&port->lock, flags); + sc16is7xx_enable_ms(port); + spin_unlock_irqrestore(&port->lock, flags); + 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, port); + + kthread_cancel_delayed_work_sync(&one->ms_work); /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); @@ -1175,6 +1271,7 @@ static const struct uart_ops sc16is7xx_ops = { .stop_tx = sc16is7xx_stop_tx, .start_tx = sc16is7xx_start_tx, .stop_rx = sc16is7xx_stop_rx, + .enable_ms = sc16is7xx_enable_ms, .break_ctl = sc16is7xx_break_ctl, .startup = sc16is7xx_startup, .shutdown = sc16is7xx_shutdown, @@ -1341,7 +1438,9 @@ static int sc16is7xx_probe(struct device *dev, 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].old_mctrl = 0; s->p[i].port.line = sc16is7xx_alloc_line(); + if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { ret = -ENOMEM; goto out_ports; @@ -1353,9 +1452,17 @@ static int sc16is7xx_probe(struct device *dev, sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); + + /* Use GPIO lines as modem status registers */ + if (devtype->has_mctrl) + sc16is7xx_port_write(&s->p[i].port, + SC16IS7XX_IOCONTROL_REG, + SC16IS7XX_IOCONTROL_MODEM_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); + kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc); /* Register port */ uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); @@ -1439,6 +1546,7 @@ static void sc16is7xx_remove(struct device *dev) #endif for (i = 0; i < s->devtype->nr_uart; i++) { + kthread_cancel_delayed_work_sync(&s->p[i].ms_work); 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); -- cgit v1.2.3 From 6e124e58ae2e0e3f6400dce21e942a94a67a7949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 1 Mar 2022 07:03:32 +0100 Subject: sc16is7xx: Set AUTOCTS and AUTORTS bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let serial core know that the chip automatically handles RTS/CTS signal. This elimines completely unnecessary I2C/SPI bus traffic. Cease reading from RX FIFO (by disabling RDI interrupt) when throttled. Eventually the FIFO will fill up and the device will drive RTS output inactive. Unthrottle by enabling back RDI interrupt. Indirectly controlling RTS via RX FIFO state seems to be the only option because RTS bit is ignored when hardware flow control is enabled. Signed-off-by: Tomasz Moń Link: https://lore.kernel.org/r/20220301060332.2561851-4-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 5c247b4a01a9..683dd3be010d 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -957,6 +957,29 @@ static void sc16is7xx_start_tx(struct uart_port *port) kthread_queue_work(&s->kworker, &one->tx_work); } +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. + */ + spin_lock_irqsave(&port->lock, flags); + sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void sc16is7xx_unthrottle(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + sc16is7xx_ier_set(port, SC16IS7XX_IER_RDI_BIT); + spin_unlock_irqrestore(&port->lock, flags); +} + static unsigned int sc16is7xx_tx_empty(struct uart_port *port) { unsigned int lsr; @@ -1062,9 +1085,13 @@ static void sc16is7xx_set_termios(struct uart_port *port, 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) @@ -1270,6 +1297,8 @@ 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, -- cgit v1.2.3 From 47b95e8ab731511b7ed7924ec3ec922e14737e4e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 1 Mar 2022 07:58:06 +0000 Subject: serial: mvebu-uart: fix return value check in mvebu_uart_clock_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of error, the function devm_ioremap() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: b7e2b5360f9b ("serial: mvebu-uart: implement UART clock driver for configuring UART base clock") Reported-by: Hulk Robot Reviewed-by: Pali Rohár Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20220301075806.3950108-1-weiyongjun1@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 2e9263888ddc..45976e2140d4 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -1382,8 +1382,8 @@ static int mvebu_uart_clock_probe(struct platform_device *pdev) */ uart_clock_base->reg1 = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(uart_clock_base->reg1)) - return PTR_ERR(uart_clock_base->reg1); + if (!uart_clock_base->reg1) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) { @@ -1401,8 +1401,8 @@ static int mvebu_uart_clock_probe(struct platform_device *pdev) */ uart_clock_base->reg2 = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(uart_clock_base->reg2)) - return PTR_ERR(uart_clock_base->reg2); + if (!uart_clock_base->reg2) + return -ENOMEM; hw_clk_data = devm_kzalloc(dev, struct_size(hw_clk_data, hws, -- cgit v1.2.3 From 3f8bab174cb26aa5a8053c4457cc733881e3ad88 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Mar 2022 09:08:31 +0100 Subject: serial: make uart_console_write->putchar()'s character an unsigned char MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, uart_console_write->putchar's second parameter (the character) is of type int. It makes little sense, provided uart_console_write() accepts the input string as "const char *s" and passes its content -- the characters -- to putchar(). So switch the character's type to unsigned char. We don't use char as that is signed on some platforms. That would cause troubles for drivers which (implicitly) cast the char to u16 when writing to the device. Sign extension would happen in that case and the value written would be completely different to the provided char. DZ is an example of such a driver -- on MIPS, it uses u16 for dz_out in dz_console_putchar(). Note we do the char -> uchar conversion implicitly in uart_console_write(). Provided we do not change size of the data type, sign extension does not happen there, so the problem is void. This makes the types consistent and unified with the rest of the uart layer, which uses unsigned char in most places already. One exception is xmit_buf, but that is going to be converted later. Cc: Paul Cercueil Cc: Tobias Klauser Cc: Russell King Cc: Vineet Gupta Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Ludovic Desroches Cc: Florian Fainelli Cc: bcm-kernel-feedback-list@broadcom.com Cc: Alexander Shiyan Cc: Baruch Siach Cc: "Maciej W. Rozycki" Cc: Paul Walmsley Cc: Palmer Dabbelt Cc: Albert Ou Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Karol Gugala Cc: Mateusz Holenko Cc: Vladimir Zapolskiy Cc: Neil Armstrong Cc: Kevin Hilman Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Taichi Sugaya Cc: Takao Orito Cc: Liviu Dudau Cc: Sudeep Holla Cc: Lorenzo Pieralisi Cc: "Andreas Färber" Cc: Manivannan Sadhasivam Cc: Michael Ellerman Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Andy Gross Cc: Bjorn Andersson Cc: Krzysztof Kozlowski Cc: Orson Zhai Cc: Baolin Wang Cc: Chunyan Zhang Cc: Patrice Chotard Cc: Maxime Coquelin Cc: Alexandre Torgue Cc: "David S. Miller" Cc: Peter Korsgaard Cc: Michal Simek Acked-by: Richard Genoud [atmel_serial] Acked-by: Uwe Kleine-König Acked-by: Paul Cercueil Acked-by: Neil Armstrong # meson_serial Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220303080831.21783-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 2 +- drivers/tty/hvc/hvc_dcc.c | 2 +- drivers/tty/serial/21285.c | 2 +- drivers/tty/serial/8250/8250_early.c | 2 +- drivers/tty/serial/8250/8250_ingenic.c | 2 +- drivers/tty/serial/8250/8250_port.c | 2 +- drivers/tty/serial/altera_jtaguart.c | 4 ++-- drivers/tty/serial/altera_uart.c | 2 +- drivers/tty/serial/amba-pl010.c | 2 +- drivers/tty/serial/amba-pl011.c | 6 +++--- drivers/tty/serial/apbuart.c | 2 +- drivers/tty/serial/ar933x_uart.c | 2 +- drivers/tty/serial/arc_uart.c | 2 +- drivers/tty/serial/atmel_serial.c | 2 +- drivers/tty/serial/bcm63xx_uart.c | 2 +- drivers/tty/serial/clps711x.c | 2 +- drivers/tty/serial/digicolor-usart.c | 2 +- drivers/tty/serial/dz.c | 2 +- drivers/tty/serial/earlycon-arm-semihost.c | 2 +- drivers/tty/serial/earlycon-riscv-sbi.c | 2 +- drivers/tty/serial/fsl_linflexuart.c | 4 ++-- drivers/tty/serial/fsl_lpuart.c | 4 ++-- drivers/tty/serial/imx.c | 2 +- drivers/tty/serial/imx_earlycon.c | 2 +- drivers/tty/serial/ip22zilog.c | 2 +- drivers/tty/serial/lantiq.c | 2 +- drivers/tty/serial/liteuart.c | 2 +- drivers/tty/serial/lpc32xx_hs.c | 2 +- drivers/tty/serial/meson_uart.c | 2 +- drivers/tty/serial/milbeaut_usio.c | 2 +- drivers/tty/serial/mps2-uart.c | 4 ++-- drivers/tty/serial/mvebu-uart.c | 4 ++-- drivers/tty/serial/mxs-auart.c | 2 +- drivers/tty/serial/omap-serial.c | 4 ++-- drivers/tty/serial/owl-uart.c | 2 +- drivers/tty/serial/pch_uart.c | 2 +- drivers/tty/serial/pic32_uart.c | 2 +- drivers/tty/serial/pmac_zilog.c | 2 +- drivers/tty/serial/pxa.c | 2 +- drivers/tty/serial/qcom_geni_serial.c | 2 +- drivers/tty/serial/rda-uart.c | 2 +- drivers/tty/serial/sa1100.c | 2 +- drivers/tty/serial/samsung_tty.c | 4 ++-- drivers/tty/serial/sb1250-duart.c | 2 +- drivers/tty/serial/sccnxp.c | 2 +- drivers/tty/serial/serial_core.c | 2 +- drivers/tty/serial/serial_txx9.c | 2 +- drivers/tty/serial/sh-sci.c | 2 +- drivers/tty/serial/sifive.c | 4 ++-- drivers/tty/serial/sprd_serial.c | 4 ++-- drivers/tty/serial/st-asc.c | 2 +- drivers/tty/serial/stm32-usart.c | 2 +- drivers/tty/serial/sunplus-uart.c | 5 +++-- drivers/tty/serial/sunsab.c | 2 +- drivers/tty/serial/sunsu.c | 2 +- drivers/tty/serial/sunzilog.c | 4 ++-- drivers/tty/serial/uartlite.c | 4 ++-- drivers/tty/serial/vr41xx_siu.c | 2 +- drivers/tty/serial/vt8500_serial.c | 2 +- drivers/tty/serial/xilinx_uartps.c | 2 +- drivers/tty/serial/zs.c | 2 +- 61 files changed, 76 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 5ed19a9857ad..ad13532e92fe 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -434,7 +434,7 @@ static int goldfish_tty_remove(struct platform_device *pdev) } #ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE -static void gf_early_console_putchar(struct uart_port *port, int ch) +static void gf_early_console_putchar(struct uart_port *port, unsigned char ch) { __raw_writel(ch, port->membase); } diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c index 8e0edb7d93fd..bd61f9372d83 100644 --- a/drivers/tty/hvc/hvc_dcc.c +++ b/drivers/tty/hvc/hvc_dcc.c @@ -15,7 +15,7 @@ #define DCC_STATUS_RX (1 << 30) #define DCC_STATUS_TX (1 << 29) -static void dcc_uart_console_putchar(struct uart_port *port, int ch) +static void dcc_uart_console_putchar(struct uart_port *port, unsigned char ch) { while (__dcc_getstatus() & DCC_STATUS_TX) cpu_relax(); diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 09baef4ccc39..7520cc02fd4d 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -403,7 +403,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(); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c171ce6db691..e52585064565 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -86,7 +86,7 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value) #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; diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 65402d05eff9..cff91aa03f29 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -52,7 +52,7 @@ 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; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 25b84d30e771..267026892264 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3305,7 +3305,7 @@ 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) { struct uart_8250_port *up = up_to_u8250p(port); diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 37bffe406b18..1c16345d0a1f 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -298,7 +298,7 @@ static struct altera_jtaguart 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; @@ -318,7 +318,7 @@ static void altera_jtaguart_console_putc(struct uart_port *port, int c) spin_unlock_irqrestore(&port->lock, 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; diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 64a352b40197..8b749ed557c6 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -438,7 +438,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)) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index b73375214ac3..fae0b581ff42 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -551,7 +551,7 @@ 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) { unsigned int status; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ba053a68529f..51ecb050ae40 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2255,7 +2255,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); @@ -2471,7 +2471,7 @@ static struct console amba_console = { #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(); @@ -2487,7 +2487,7 @@ static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned 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(); diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index d8c937bdf3f9..9ef82d870ff2 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -413,7 +413,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 8cabe50c4a33..6269dbf93546 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -613,7 +613,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); diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 596217d10d5c..2a09e92ef9ed 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -508,7 +508,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(); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 73d43919898d..3a45e4fc7993 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2541,7 +2541,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(); diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 6471a54b616b..53b43174aa40 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -681,7 +681,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); diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 95abc6faa3d5..b9b66ad31a08 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -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; diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index 13ac36e2da4f..6d70fea76bb3 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -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(); diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index e9edabc5a211..2e21acf39720 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -802,7 +802,7 @@ 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; diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-arm-semihost.c index fa096c10b591..fcdec5f42376 100644 --- a/drivers/tty/serial/earlycon-arm-semihost.c +++ b/drivers/tty/serial/earlycon-arm-semihost.c @@ -21,7 +21,7 @@ /* * Semihosting-based debug console */ -static void smh_putc(struct uart_port *port, int c) +static void smh_putc(struct uart_port *port, unsigned char c) { #ifdef CONFIG_ARM64 asm volatile("mov x1, %0\n" diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c index ce81523c3113..27afb0b74ea7 100644 --- a/drivers/tty/serial/earlycon-riscv-sbi.c +++ b/drivers/tty/serial/earlycon-riscv-sbi.c @@ -10,7 +10,7 @@ #include #include -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); } diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index e72cba085743..98bb0c315e13 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -553,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; @@ -578,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; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 7d90c5a530ee..87789872f400 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2333,13 +2333,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); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0b467ce8d737..fd38e6ed4fda 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1968,7 +1968,7 @@ static const struct uart_ops imx_uart_pops = { static struct imx_port *imx_uart_ports[UART_NR]; #if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) -static void imx_uart_console_putchar(struct uart_port *port, int ch) +static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch) { struct imx_port *sport = (struct imx_port *)port; diff --git a/drivers/tty/serial/imx_earlycon.c b/drivers/tty/serial/imx_earlycon.c index 795606e1a22f..7aab38b2bd8c 100644 --- a/drivers/tty/serial/imx_earlycon.c +++ b/drivers/tty/serial/imx_earlycon.c @@ -16,7 +16,7 @@ #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, int ch) +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(); diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index f4dc5fe4ba92..655e64b26852 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -990,7 +990,7 @@ static struct zilog_layout * __init get_zs(int chip) #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; diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 3e324d3f0a6d..a3120c3347dd 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -598,7 +598,7 @@ 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; diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 7f74bf7bdcff..328b50521f14 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -93,7 +93,7 @@ static void liteuart_timer(struct timer_list *t) mod_timer(&uart->timer, jiffies + uart_poll_timeout(port)); } -static void liteuart_putchar(struct uart_port *port, int ch) +static void liteuart_putchar(struct uart_port *port, unsigned char ch) { while (litex_read8(port->membase + OFF_TXFULL)) cpu_relax(); diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 54437a087aa0..93140cac1ca1 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)); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 45e00d928253..2bf1c57e0981 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -513,7 +513,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; diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index 8f2cab7f66ad..347088bb380e 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -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(); diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index 587b42f754cb..5e9429dcc51f 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -432,7 +432,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 +484,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(); diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 45976e2140d4..0429c2a54290 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -676,7 +676,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; @@ -737,7 +737,7 @@ static void wait_for_xmite(struct uart_port *port) (val & STAT_TX_EMP), 1, 10000); } -static void mvebu_uart_console_putchar(struct uart_port *port, int ch) +static void mvebu_uart_console_putchar(struct uart_port *port, unsigned char ch) { wait_for_xmitr(port); writel(ch, port->membase + UART_TSH(port)); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index ac45f3386e97..1944daf8593a 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1305,7 +1305,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; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index b4e060205e61..8d5ffa196097 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1180,7 +1180,7 @@ 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; @@ -1224,7 +1224,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); diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 91f1eb0058d7..5250bd7d390a 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -516,7 +516,7 @@ static const struct uart_ops owl_uart_ops = { #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; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index f0351e6f0ef6..affe71f8b50c 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1600,7 +1600,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); diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 0a12fb11e698..b7a3a1b959b1 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -691,7 +691,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); diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 5359236b32d6..5d97c201ad88 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1944,7 +1944,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); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index b4987b417f19..e80ba8e10407 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -605,7 +605,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; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index aedc38893e6c..1543a6028856 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -397,7 +397,7 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport, #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_wr_char(struct uart_port *uport, unsigned char ch) { struct qcom_geni_private_data *private_data = uport->private_data; diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index d550d8fa2fab..e5f1fded423a 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -573,7 +573,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; diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 697b6a002a16..5fe6cccfc1ae 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -695,7 +695,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); diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index d002a4e48ed9..2bde7bde7116 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2478,7 +2478,7 @@ 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); @@ -2965,7 +2965,7 @@ static void samsung_early_busyuart_fifo(struct uart_port *port) ; } -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); diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index 738df6d9c0d9..2cf8533ef760 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -820,7 +820,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); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 10cc16a71f26..c56de2e104d4 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -828,7 +828,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; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 846192a7b4bf..a1688a341411 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1911,7 +1911,7 @@ static void uart_port_spin_lock_init(struct uart_port *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; diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index cd38cf1f03cb..a695e9c1a06a 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -876,7 +876,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv, #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 *port, unsigned char ch) { struct uart_txx9_port *up = to_uart_txx9_port(port); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 77d76973858f..0f9b8bd23500 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2960,7 +2960,7 @@ static void sci_cleanup_single(struct sci_port *port) #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); } diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index b79900d0e91a..f5ac14c384c4 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -756,7 +756,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) @@ -800,7 +800,7 @@ 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); diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 9a7ae6384edf..4329b9c9cbf0 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -984,7 +984,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); @@ -1058,7 +1058,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; diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 87e480cc8206..d7fd692286cf 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -854,7 +854,7 @@ static int asc_serial_resume(struct device *dev) /*----------------------------------------------------------------------*/ #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; diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 1b3a611ac39e..87b5cd4c9743 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1641,7 +1641,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) } #ifdef CONFIG_SERIAL_STM32_CONSOLE -static void stm32_usart_console_putchar(struct uart_port *port, int ch) +static void stm32_usart_console_putchar(struct uart_port *port, unsigned char ch) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index 1c7a30bf5f04..9f15922e681b 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -500,7 +500,8 @@ static const struct uart_ops sunplus_uart_ops = { #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR]; -static void sunplus_uart_console_putchar(struct uart_port *port, int ch) +static void sunplus_uart_console_putchar(struct uart_port *port, + unsigned char ch) { wait_for_xmitr(port); sp_uart_put_char(port, ch); @@ -736,7 +737,7 @@ static void __exit sunplus_uart_exit(void) module_exit(sunplus_uart_exit); #ifdef CONFIG_SERIAL_EARLYCON -static void sunplus_uart_putc(struct uart_port *port, int c) +static void sunplus_uart_putc(struct uart_port *port, unsigned char c) { unsigned int val; int ret; diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 92e572634009..6ea52293d9f3 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -846,7 +846,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); diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 98b2f4fb9a99..c31389114b86 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1281,7 +1281,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); diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index b714b00d2dad..c14275d83b0b 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -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)) @@ -1125,7 +1125,7 @@ static void sunzilog_free_tables(void) #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ -static void __maybe_unused 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; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index e1fa52d31474..007db67292a2 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -482,7 +482,7 @@ static void ulite_console_wait_tx(struct uart_port *port) "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); @@ -558,7 +558,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. diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index 8586a56d4deb..e0bf003ca3a1 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -730,7 +730,7 @@ static void wait_for_xmitr(struct uart_port *port) } } -static void siu_console_putchar(struct uart_port *port, int ch) +static void siu_console_putchar(struct uart_port *port, unsigned char ch) { wait_for_xmitr(port); siu_write(port, UART_TX, ch); diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 9adfe3dc970f..6f08136ce78a 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -484,7 +484,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); diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index d5e243908d9f..250a1d888eeb 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1142,7 +1142,7 @@ 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) cpu_relax(); diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 4b4f604646a7..70969bf9d82c 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -1124,7 +1124,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; -- cgit v1.2.3 From 3631e48df0dbfcce3b08f0ccafcaa587657379cd Mon Sep 17 00:00:00 2001 From: Woody Lin Date: Wed, 2 Mar 2022 19:49:23 +0800 Subject: serial: samsung: Add samsung_early_read to support early kgdboc The 'kgdboc_earlycon_init' looks for boot console that has both .read and .write callbacks. Adds 'samsung_early_read' to samsung_tty.c's early console to support kgdboc. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Woody Lin Link: https://lore.kernel.org/r/20220302114923.144523-1-woodylin@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 2bde7bde7116..95018a847023 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2949,6 +2949,7 @@ static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val) struct samsung_early_console_data { u32 txfull_mask; + u32 rxfifo_mask; }; static void samsung_early_busyuart(struct uart_port *port) @@ -2983,6 +2984,26 @@ 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 ch, ufstat, num_read = 0; + + 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) { @@ -2990,12 +3011,14 @@ 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, @@ -3011,6 +3034,7 @@ OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart", /* S3C2412, S3C2440, 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, @@ -3030,6 +3054,7 @@ OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart", /* 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, -- cgit v1.2.3 From 53819a0d97aace1425bb042829e3446952a9e8a9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 7 Mar 2022 18:42:28 -0800 Subject: tty: hvc: fix return value of __setup handler __setup() handlers should return 1 to indicate that the boot option has been handled or 0 to indicate that it was not handled. Add a pr_warn() message if the option value is invalid and then always return 1. Link: lore.kernel.org/r/64644a2f-4a20-bab3-1e15-3b2cdd0defe3@omprussia.ru Fixes: 86b40567b917 ("tty: replace strict_strtoul() with kstrtoul()") Cc: Jingoo Han Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Michael Ellerman Cc: Julian Wiedmann Cc: Vasily Gorbik Cc: linuxppc-dev@lists.ozlabs.org Reported-by: Igor Zhbanov Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20220308024228.20477-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_iucv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 82a76cac94de..32366caca662 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1417,7 +1417,9 @@ out_error: */ static int __init hvc_iucv_config(char *val) { - return kstrtoul(val, 10, &hvc_iucv_devices); + if (kstrtoul(val, 10, &hvc_iucv_devices)) + pr_warn("hvc_iucv= invalid parameter value '%s'\n", val); + return 1; } -- cgit v1.2.3 From ab818c7aa7544bf8d2dd4bdf68878b17a02eb332 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 8 Mar 2022 19:30:18 -0800 Subject: kgdboc: fix return value of __setup handler __setup() handlers should return 1 to obsolete_checksetup() in init/main.c to indicate that the boot option has been handled. A return of 0 causes the boot option/value to be listed as an Unknown kernel parameter and added to init's (limited) environment strings. So return 1 from kgdboc_option_setup(). Unknown kernel command line parameters "BOOT_IMAGE=/boot/bzImage-517rc7 kgdboc=kbd kgdbts=", will be passed to user space. Run /sbin/init as init process with arguments: /sbin/init with environment: HOME=/ TERM=linux BOOT_IMAGE=/boot/bzImage-517rc7 kgdboc=kbd kgdbts= Link: lore.kernel.org/r/64644a2f-4a20-bab3-1e15-3b2cdd0defe3@omprussia.ru Fixes: 1bd54d851f50 ("kgdboc: Passing ekgdboc to command line causes panic") Fixes: f2d937f3bf00 ("consoles: polling support, kgdboc") Cc: He Zhe Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: kgdb-bugreport@lists.sourceforge.net Cc: Jason Wessel Cc: Daniel Thompson Cc: Douglas Anderson Cc: linux-serial@vger.kernel.org Reported-by: Igor Zhbanov Reviewed-by: Douglas Anderson Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20220309033018.17936-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/kgdboc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 49d0c7f2b29b..79b7db8580e0 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -403,16 +403,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); -- cgit v1.2.3 From 4f6f194f2be43c1df9ad031de86cdaffa5c8084d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 7 Mar 2022 06:43:47 +0100 Subject: tty: serial: serial_txx9: remove struct uart_txx9_port It's only a wrapper to struct uart_port, so unwrap the whole code. No change in functionality is intended. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220307054348.31748-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_txx9.c | 364 ++++++++++++++++++--------------------- 1 file changed, 167 insertions(+), 197 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index a695e9c1a06a..2213e6b841d3 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -54,11 +54,6 @@ */ #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 */ @@ -160,42 +155,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) @@ -210,32 +205,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); @@ -250,15 +236,15 @@ 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; @@ -269,11 +255,11 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) 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))) { /* @@ -281,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. @@ -309,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; @@ -318,34 +304,34 @@ 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)); - tty_flip_buffer_push(&up->port.state->port); + 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; + struct circ_buf *xmit = &up->state->xmit; int count; - if (up->port.x_char) { - sio_out(up, TXX9_SITFIFO, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; + if (up->x_char) { + sio_out(up, TXX9_SITFIFO, up->x_char); + up->icount.tx++; + up->x_char = 0; return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_txx9_stop_tx(&up->port); + if (uart_circ_empty(xmit) || uart_tx_stopped(up)) { + serial_txx9_stop_tx(up); return; } @@ -353,32 +339,32 @@ static inline void transmit_chars(struct uart_txx9_port *up) do { sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; + up->icount.tx++; if (uart_circ_empty(xmit)) break; } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); + uart_write_wakeup(up); if (uart_circ_empty(xmit)) - serial_txx9_stop_tx(&up->port); + serial_txx9_stop_tx(up); } 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); + spin_lock(&up->lock); 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); + spin_unlock(&up->lock); break; } @@ -390,7 +376,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); + spin_unlock(&up->lock); if (pass_counter++ > PASS_LIMIT) break; @@ -399,22 +385,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); + spin_lock_irqsave(&up->lock, flags); ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&up->lock, 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 */ @@ -425,9 +409,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); @@ -435,24 +418,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); + spin_lock_irqsave(&up->lock, 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); + spin_unlock_irqrestore(&up->lock, 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; @@ -462,7 +444,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)) @@ -477,11 +459,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 @@ -504,10 +485,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 @@ -531,9 +511,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; @@ -553,7 +532,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; @@ -561,9 +540,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); + spin_lock_irqsave(&up->lock, flags); + serial_txx9_set_mctrl(up, up->mctrl); + spin_unlock_irqrestore(&up->lock, flags); /* Enable RX/TX */ sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); @@ -576,9 +555,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; /* @@ -586,9 +564,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); + spin_lock_irqsave(&up->lock, flags); + serial_txx9_set_mctrl(up, up->mctrl); + spin_unlock_irqrestore(&up->lock, flags); /* * Disable break condition @@ -596,8 +574,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 @@ -611,14 +589,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, +serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios, 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; @@ -658,8 +635,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. */ @@ -669,45 +646,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); + spin_lock_irqsave(&up->lock, 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 { @@ -719,8 +696,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); + spin_unlock_irqrestore(&up->lock, flags); } static void @@ -739,76 +716,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; /* @@ -818,14 +792,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 * @@ -856,7 +830,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) @@ -864,22 +838,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, unsigned char 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); } @@ -893,7 +865,7 @@ static void serial_txx9_console_putchar(struct uart_port *port, unsigned char 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; /* @@ -905,10 +877,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 @@ -921,8 +893,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'; @@ -936,16 +907,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; @@ -986,9 +956,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; } @@ -1009,14 +979,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; } } @@ -1024,24 +994,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; @@ -1056,16 +1026,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); } @@ -1108,9 +1078,9 @@ static int 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; @@ -1122,10 +1092,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; @@ -1136,10 +1106,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; @@ -1195,10 +1165,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); } } @@ -1206,10 +1176,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; @@ -1217,12 +1187,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 @@ -1302,9 +1272,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); -- cgit v1.2.3 From 988c7c00691008ea1daaa1235680a0da49dab4e8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 8 Mar 2022 12:51:53 +0100 Subject: serial: samsung_tty: do not unlock port->lock for uart_write_wakeup() The commit c15c3747ee32 (serial: samsung: fix potential soft lockup during uart write) added an unlock of port->lock before uart_write_wakeup() and a lock after it. It was always problematic to write data from tty_ldisc_ops::write_wakeup and it was even documented that way. We fixed the line disciplines to conform to this recently. So if there is still a missed one, we should fix them instead of this workaround. On the top of that, s3c24xx_serial_tx_dma_complete() in this driver still holds the port->lock while calling uart_write_wakeup(). So revert the wrap added by the commit above. Cc: Thomas Abraham Cc: Kyungmin Park Cc: Hyeonkook Kim Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220308115153.4225-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 95018a847023..ab26520c9c21 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -921,11 +921,8 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) return; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { - spin_unlock(&port->lock); + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - spin_lock(&port->lock); - } if (uart_circ_empty(xmit)) s3c24xx_serial_stop_tx(port); -- cgit v1.2.3 From a6cee01b4f9205ce664e3442ee7bd5aee0d650de Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Mar 2022 23:00:55 +0000 Subject: serial: 8250_mtk: make two read-only arrays static const Don't populate the read-only arrays fraction_L_mapping and fraction_M_mapping on the stack but instead make them static const. Also makes the object code a little smaller. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220307230055.168241-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mtk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index fb65dc601b23..f4a0caa56f84 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -289,10 +289,10 @@ static void mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, 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); -- cgit v1.2.3 From 168b504bc1d2c4df352bd5bf5e6853aff0d229c9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Mar 2022 15:30:47 +0000 Subject: tty: serial: jsm: remove redundant assignments to variable linestatus Variable linestatus is being assigned values that are never read, the assignments are redundant and can be removed. Cleans up clang scan warnings: drivers/tty/serial/jsm/jsm_cls.c:369:2: warning: Value stored to 'linestatus' is never read [deadcode.DeadStores] drivers/tty/serial/jsm/jsm_cls.c:400:4: warning: Value stored to 'linestatus' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220307153047.139639-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_cls.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index b280da50290c..444f233ebd1f 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 */ -- cgit v1.2.3 From b0db9263b0d599dbc4cf2b5679f873d937c60591 Mon Sep 17 00:00:00 2001 From: Alexander Vorwerk Date: Tue, 15 Mar 2022 03:07:45 +0100 Subject: tty: serial: jsm: fix two assignments in if conditions Fixes two warnings reported of the form "ERROR: do not use assignment in if condition" reported by checkpatch.pl. Signed-off-by: Alexander Vorwerk Link: https://lore.kernel.org/r/20220315020745.15752-1-alexander.vorwerk@stud.uni-goettingen.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_neo.c | 3 ++- drivers/tty/serial/jsm/jsm_tty.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index c4fd31de04b4..110696cdaa1d 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; /* diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index d74cbbbf33c6..cb58bdec2f43 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -749,7 +749,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; /* -- cgit v1.2.3 From 1a282ef0a18fff8a37a60566da3a87b5d8daf1de Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 15 Mar 2022 14:52:32 +0100 Subject: serial: SERIAL_SUNPLUS should depend on ARCH_SUNPLUS Sunplus serial ports are only present on Sunplus SoCs. Hence add a dependency on ARCH_SUNPLUS, to prevent asking the user about this driver when configuring a kernel without Sunplus SoC support. Fixes: 9e8d5470325f25be ("serial: sunplus-uart: Add Sunplus SoC UART Driver") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/59f46272ab5b16853acac4d585c3333cfd394223.1647352195.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index e952ec5c7a7c..5551192560bb 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1566,7 +1566,7 @@ config SERIAL_LITEUART_CONSOLE config SERIAL_SUNPLUS tristate "Sunplus UART support" - depends on OF || COMPILE_TEST + depends on ARCH_SUNPLUS || COMPILE_TEST select SERIAL_CORE help Select this option if you would like to use Sunplus serial port on -- cgit v1.2.3 From 0dc0da881b4574d1e04a079ab2ea75da61f5ad2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 11 Mar 2022 10:32:33 +0100 Subject: tty: serial: bcm63xx: use more precise Kconfig symbol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patches lowering SERIAL_BCM63XX dependencies led to a discussion and documentation change regarding "depends" usage. Adjust Kconfig entry to match current guidelines. Make this symbol available for relevant architectures only. Cc: Geert Uytterhoeven Reviewed-by: Geert Uytterhoeven Acked-by: Florian Fainelli Signed-off-by: Rafał Miłecki Ref: f35a07f92616 ("tty: serial: bcm63xx: lower driver dependencies") Ref: 18084e435ff6 ("Documentation/kbuild: Document platform dependency practises") Link: https://lore.kernel.org/r/20220311093233.10012-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 5551192560bb..162a1657ec60 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1100,7 +1100,8 @@ config SERIAL_TIMBERDALE config SERIAL_BCM63XX tristate "Broadcom BCM63xx/BCM33xx UART support" select SERIAL_CORE - depends on COMMON_CLK + depends on ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST + default ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC help This enables the driver for the onchip UART core found on the following chipsets: -- cgit v1.2.3 From dffa58b64cca6ca266bc0310d8e6b27abd1f8048 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 08:41:57 +0100 Subject: serial: 8250_tegra: mark acpi_device_id as unused with !ACPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver's acpi_device_id table is referenced via ACPI_PTR() so it will be unused for !CONFIG_ACPI builds: drivers/tty/serial/8250/8250_tegra.c:178:36: warning: ‘tegra_uart_acpi_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308074157.113568-1-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c index e13ae18b0713..e7cddeec9d8e 100644 --- a/drivers/tty/serial/8250/8250_tegra.c +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -175,7 +175,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 }, { }, }; -- cgit v1.2.3 From d3a46d0d83f94b5780bcaaea4b4ddbe7c110b35c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:12 +0100 Subject: tty: serial: samsung: embed s3c24xx_uart_info in parent structure Embed "struct s3c24xx_uart_info" directly as a member of "struct s3c24xx_serial_drv_data" instead of keeping it as a pointer. This makes the code clearer (obvious ownership of "struct s3c24xx_serial_drv_data") and saves one pointer. Tested-by: Alim Akhtar Reviewed-by: Jiri Slaby Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-2-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index ab26520c9c21..966398df4b6a 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -85,7 +85,7 @@ struct s3c24xx_uart_info { }; struct s3c24xx_serial_drv_data { - struct s3c24xx_uart_info *info; + struct s3c24xx_uart_info info; struct s3c2410_uartcfg *def_cfg; unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS]; }; @@ -2194,7 +2194,7 @@ 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; @@ -2613,7 +2613,7 @@ static struct console s3c24xx_serial_console = { #ifdef CONFIG_CPU_S3C2410 static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { + .info = { .name = "Samsung S3C2410 UART", .type = TYPE_S3C24XX, .port_type = PORT_S3C2410, @@ -2641,7 +2641,7 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { #ifdef CONFIG_CPU_S3C2412 static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { + .info = { .name = "Samsung S3C2412 UART", .type = TYPE_S3C24XX, .port_type = PORT_S3C2412, @@ -2671,7 +2671,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { #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) { + .info = { .name = "Samsung S3C2440 UART", .type = TYPE_S3C24XX, .port_type = PORT_S3C2440, @@ -2701,7 +2701,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { + .info = { .name = "Samsung S3C6400 UART", .type = TYPE_S3C6400, .port_type = PORT_S3C6400, @@ -2730,7 +2730,7 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { #ifdef CONFIG_CPU_S5PV210 static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { + .info = { .name = "Samsung S5PV210 UART", .type = TYPE_S3C6400, .port_type = PORT_S3C6400, @@ -2759,7 +2759,7 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #if defined(CONFIG_ARCH_EXYNOS) #define EXYNOS_COMMON_SERIAL_DRV_DATA() \ - .info = &(struct s3c24xx_uart_info) { \ + .info = { \ .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ .port_type = PORT_S3C6400, \ @@ -2808,7 +2808,7 @@ static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { #ifdef CONFIG_ARCH_APPLE static struct s3c24xx_serial_drv_data s5l_serial_drv_data = { - .info = &(struct s3c24xx_uart_info) { + .info = { .name = "Apple S5L UART", .type = TYPE_APPLE_S5L, .port_type = PORT_8250, -- cgit v1.2.3 From 7483189d6b3c1dec7e91fa082a4d52cfc9dd1ef0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:13 +0100 Subject: tty: serial: samsung: embed s3c2410_uartcfg in parent structure Embed "struct s3c2410_uartcfg" directly as a member of "struct s3c24xx_serial_drv_data" instead of keeping it as a pointer. This makes the code clearer (obvious ownership of "s3c2410_uartcfg s3c24xx_serial_drv_data") and saves one pointer. Tested-by: Alim Akhtar Reviewed-by: Jiri Slaby Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-3-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 966398df4b6a..40209461c574 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -86,7 +86,7 @@ struct s3c24xx_uart_info { struct s3c24xx_serial_drv_data { struct s3c24xx_uart_info info; - struct s3c2410_uartcfg *def_cfg; + struct s3c2410_uartcfg def_cfg; unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS]; }; @@ -2197,7 +2197,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) 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_S3C24XX: @@ -2629,7 +2629,7 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { .clksel_mask = S3C2410_UCON_CLKMASK, .clksel_shift = S3C2410_UCON_CLKSHIFT, }, - .def_cfg = &(struct s3c2410_uartcfg) { + .def_cfg = { .ucon = S3C2410_UCON_DEFAULT, .ufcon = S3C2410_UFCON_DEFAULT, }, @@ -2658,7 +2658,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { .clksel_mask = S3C2412_UCON_CLKMASK, .clksel_shift = S3C2412_UCON_CLKSHIFT, }, - .def_cfg = &(struct s3c2410_uartcfg) { + .def_cfg = { .ucon = S3C2410_UCON_DEFAULT, .ufcon = S3C2410_UFCON_DEFAULT, }, @@ -2689,7 +2689,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .clksel_shift = S3C2412_UCON_CLKSHIFT, .ucon_mask = S3C2440_UCON0_DIVMASK, }, - .def_cfg = &(struct s3c2410_uartcfg) { + .def_cfg = { .ucon = S3C2410_UCON_DEFAULT, .ufcon = S3C2410_UFCON_DEFAULT, }, @@ -2718,7 +2718,7 @@ 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, }, @@ -2746,7 +2746,7 @@ 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, }, @@ -2775,7 +2775,7 @@ 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, \ @@ -2824,7 +2824,7 @@ static struct s3c24xx_serial_drv_data s5l_serial_drv_data = { .clksel_mask = 0, .clksel_shift = 0, }, - .def_cfg = &(struct s3c2410_uartcfg) { + .def_cfg = { .ucon = APPLE_S5L_UCON_DEFAULT, .ufcon = S3C2410_UFCON_DEFAULT, }, -- cgit v1.2.3 From 3aec400965500697179aed4497d9ad8dc9502e37 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:14 +0100 Subject: tty: serial: samsung: reduce number of casts The pointers to instances of "struct s3c24xx_serial_drv_data" are first cast to kernel_ulong_t and then either used directly (in "platform_device_id.driver_data") or cast again to void * (in "of_device_id.data"). One cast can be dropped, so at least for "of_device_id.data" case there will be no casts at all. This makes the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-4-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 72 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 40209461c574..5078881ee284 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2634,9 +2634,9 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { .ufcon = S3C2410_UFCON_DEFAULT, }, }; -#define S3C2410_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2410_serial_drv_data) +#define S3C2410_SERIAL_DRV_DATA (&s3c2410_serial_drv_data) #else -#define S3C2410_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define S3C2410_SERIAL_DRV_DATA NULL #endif #ifdef CONFIG_CPU_S3C2412 @@ -2663,9 +2663,9 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { .ufcon = S3C2410_UFCON_DEFAULT, }, }; -#define S3C2412_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2412_serial_drv_data) +#define S3C2412_SERIAL_DRV_DATA (&s3c2412_serial_drv_data) #else -#define S3C2412_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define S3C2412_SERIAL_DRV_DATA NULL #endif #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \ @@ -2694,9 +2694,9 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .ufcon = S3C2410_UFCON_DEFAULT, }, }; -#define S3C2440_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2440_serial_drv_data) +#define S3C2440_SERIAL_DRV_DATA (&s3c2440_serial_drv_data) #else -#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define S3C2440_SERIAL_DRV_DATA NULL #endif #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) @@ -2723,9 +2723,9 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .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 @@ -2752,9 +2752,9 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { }, .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) @@ -2796,14 +2796,14 @@ static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { .fifosize = { 256, 64, 64, 64 }, }; -#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data) -#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data) -#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos850_serial_drv_data) +#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) #else -#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) -#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) -#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) +#define EXYNOS4210_SERIAL_DRV_DATA NULL +#define EXYNOS5433_SERIAL_DRV_DATA NULL +#define EXYNOS850_SERIAL_DRV_DATA NULL #endif #ifdef CONFIG_ARCH_APPLE @@ -2829,39 +2829,39 @@ static struct s3c24xx_serial_drv_data s5l_serial_drv_data = { .ufcon = S3C2410_UFCON_DEFAULT, }, }; -#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)&s5l_serial_drv_data) +#define S5L_SERIAL_DRV_DATA (&s5l_serial_drv_data) #else -#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) +#define S5L_SERIAL_DRV_DATA NULL #endif static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { .name = "s3c2410-uart", - .driver_data = S3C2410_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)S3C2410_SERIAL_DRV_DATA, }, { .name = "s3c2412-uart", - .driver_data = S3C2412_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)S3C2412_SERIAL_DRV_DATA, }, { .name = "s3c2440-uart", - .driver_data = S3C2440_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)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 = S5L_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)S5L_SERIAL_DRV_DATA, }, { .name = "exynos850-uart", - .driver_data = EXYNOS850_SERIAL_DRV_DATA, + .driver_data = (kernel_ulong_t)EXYNOS850_SERIAL_DRV_DATA, }, { }, }; @@ -2870,23 +2870,23 @@ 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 }, + .data = S3C2410_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c2412-uart", - .data = (void *)S3C2412_SERIAL_DRV_DATA }, + .data = S3C2412_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c2440-uart", - .data = (void *)S3C2440_SERIAL_DRV_DATA }, + .data = 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 = (void *)S5L_SERIAL_DRV_DATA }, + .data = S5L_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos850-uart", - .data = (void *)EXYNOS850_SERIAL_DRV_DATA }, + .data = EXYNOS850_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); -- cgit v1.2.3 From 97a6cfe8115b04296da6ee6589367234307f0c7d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:15 +0100 Subject: tty: serial: samsung: constify s3c24xx_serial_drv_data The driver data (struct s3c24xx_serial_drv_data) is only used to initialize the driver properly and is not modified. Make it const. Tested-by: Alim Akhtar Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-5-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 58 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 5078881ee284..c7824b80a4bf 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -136,14 +136,14 @@ 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; @@ -221,7 +221,7 @@ static inline void s3c24xx_clear_bit(struct uart_port *port, int idx, local_irq_restore(flags); } -static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port) +static inline struct s3c24xx_uart_port *to_ourport(const struct uart_port *port) { return container_of(port, struct s3c24xx_uart_port, port); } @@ -573,13 +573,13 @@ 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 +static inline const struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port) { struct s3c24xx_uart_port *ourport; @@ -594,7 +594,7 @@ static inline struct s3c2410_uartcfg static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, unsigned long 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; @@ -983,7 +983,7 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id) static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + const 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); @@ -1402,7 +1402,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, static inline int s3c24xx_serial_getsource(struct uart_port *port) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned int ucon; if (info->num_clks == 1) @@ -1416,7 +1416,7 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port) static void s3c24xx_serial_setsource(struct uart_port *port, unsigned int clk_sel) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned int ucon; if (info->num_clks == 1) @@ -1435,7 +1435,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, unsigned int req_baud, struct clk **best_clk, unsigned int *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; @@ -1519,7 +1519,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, 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; @@ -1688,7 +1688,7 @@ static const char *s3c24xx_serial_type(struct uart_port *port) 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) port->type = info->port_type; @@ -1700,7 +1700,7 @@ 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->port_type) return -EINVAL; @@ -1870,9 +1870,9 @@ 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); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned long ucon = rd_regl(port, S3C2410_UCON); ucon &= (info->clksel_mask | info->ucon_mask); @@ -1976,7 +1976,7 @@ s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) 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; @@ -2018,7 +2018,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; @@ -2153,7 +2153,7 @@ static const struct of_device_id s3c24xx_uart_dt_match[]; static int probe_index; -static inline struct s3c24xx_serial_drv_data * +static inline const struct s3c24xx_serial_drv_data * s3c24xx_get_driver_data(struct platform_device *pdev) { #ifdef CONFIG_OF @@ -2416,7 +2416,7 @@ static struct uart_port *cons_uart; static int s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) { - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned long ufstat, utrstat; if (ufcon & S3C2410_UFCON_FIFOMODE) { @@ -2612,7 +2612,7 @@ 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 = { +static const struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { .info = { .name = "Samsung S3C2410 UART", .type = TYPE_S3C24XX, @@ -2640,7 +2640,7 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { #endif #ifdef CONFIG_CPU_S3C2412 -static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { +static const struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { .info = { .name = "Samsung S3C2412 UART", .type = TYPE_S3C24XX, @@ -2670,7 +2670,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { #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 = { +static const struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .info = { .name = "Samsung S3C2440 UART", .type = TYPE_S3C24XX, @@ -2700,7 +2700,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { #endif #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) -static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { +static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .info = { .name = "Samsung S3C6400 UART", .type = TYPE_S3C6400, @@ -2729,7 +2729,7 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { #endif #ifdef CONFIG_CPU_S5PV210 -static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { +static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .info = { .name = "Samsung S5PV210 UART", .type = TYPE_S3C6400, @@ -2781,17 +2781,17 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .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 }, }; -static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { +static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { EXYNOS_COMMON_SERIAL_DRV_DATA(), .fifosize = { 256, 64, 64, 64 }, }; @@ -2807,7 +2807,7 @@ static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { #endif #ifdef CONFIG_ARCH_APPLE -static struct s3c24xx_serial_drv_data s5l_serial_drv_data = { +static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = { .info = { .name = "Apple S5L UART", .type = TYPE_APPLE_S5L, -- cgit v1.2.3 From 5d18bec0cf73370b2328dc311f28271f2b40d163 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:16 +0100 Subject: tty: serial: samsung: constify UART name The UART name from driver data holds only string literals. Tested-by: Alim Akhtar Reviewed-by: Jiri Slaby Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-6-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index c7824b80a4bf..872222e212f1 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -63,7 +63,7 @@ enum s3c24xx_port_type { }; struct s3c24xx_uart_info { - char *name; + const char *name; enum s3c24xx_port_type type; unsigned int port_type; unsigned int fifosize; -- cgit v1.2.3 From 8eea61c00f7cea81e8a7f461716be64ebef264a7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:17 +0100 Subject: tty: serial: samsung: constify s3c24xx_serial_drv_data members The driver data (struct s3c24xx_serial_drv_data) is never modified, so also its members can be made const. Except code style this has no impact because the structure itself is always a const. Tested-by: Alim Akhtar Reviewed-by: Jiri Slaby Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-7-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 872222e212f1..69503550b401 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -85,9 +85,9 @@ struct s3c24xx_uart_info { }; 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[CONFIG_SERIAL_SAMSUNG_UARTS]; }; struct s3c24xx_uart_dma { -- cgit v1.2.3 From bb1d98187b09d44b43115f5086a6de5adce61c17 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:18 +0100 Subject: tty: serial: samsung: constify variables and pointers Constify variables, data pointed by several pointers and "udivslot_table" static array. This makes code a bit safer. Tested-by: Alim Akhtar Reviewed-by: Jiri Slaby Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-8-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 46 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 69503550b401..f466c8f8adcc 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -164,7 +164,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport); #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: @@ -179,7 +179,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: @@ -195,7 +195,7 @@ 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, +static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, unsigned int reg) { unsigned long flags; @@ -208,7 +208,7 @@ 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, +static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx, unsigned int reg) { unsigned long flags; @@ -221,19 +221,19 @@ static inline void s3c24xx_clear_bit(struct uart_port *port, int idx, local_irq_restore(flags); } -static inline struct s3c24xx_uart_port *to_ourport(const struct uart_port *port) +static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port) { return container_of(port, struct s3c24xx_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 int s3c24xx_serial_txempty_nofifo(const struct uart_port *port) { return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } @@ -358,7 +358,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args) 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 */ @@ -387,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 */ @@ -580,9 +580,9 @@ static inline const struct s3c24xx_uart_info } static inline const struct s3c2410_uartcfg - *s3c24xx_port_to_cfg(struct uart_port *port) + *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; @@ -591,7 +591,7 @@ static inline const struct s3c2410_uartcfg return ourport->cfg; } -static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, +static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, unsigned long ufstat) { const struct s3c24xx_uart_info *info = ourport->info; @@ -944,8 +944,8 @@ static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id) /* interrupt handler for s3c64xx and later SoC's.*/ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) { - struct s3c24xx_uart_port *ourport = id; - struct uart_port *port = &ourport->port; + const struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; unsigned int pend = rd_regl(port, S3C64XX_UINTP); irqreturn_t ret = IRQ_HANDLED; @@ -963,8 +963,8 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) /* interrupt handler for Apple SoC's.*/ static irqreturn_t apple_serial_handle_irq(int irq, void *id) { - struct s3c24xx_uart_port *ourport = id; - struct uart_port *port = &ourport->port; + const struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); irqreturn_t ret = IRQ_NONE; @@ -1496,7 +1496,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, @@ -1672,7 +1672,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, static const char *s3c24xx_serial_type(struct uart_port *port) { - struct s3c24xx_uart_port *ourport = to_ourport(port); + const struct s3c24xx_uart_port *ourport = to_ourport(port); switch (ourport->info->type) { case TYPE_S3C24XX: @@ -2447,7 +2447,7 @@ 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); + const struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned int ufstat; ufstat = rd_regl(port, S3C2410_UFSTAT); @@ -2932,7 +2932,7 @@ module_exit(samsung_serial_exit); * 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: @@ -2949,15 +2949,15 @@ struct samsung_early_console_data { 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) ; -- cgit v1.2.3 From f25fbd5b1ef3773bd975135f8a017dc2251626cc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Mar 2022 09:09:19 +0100 Subject: tty: serial: samsung: simplify getting OF match data Simplify the code with of_device_get_match_data() and use dev_of_node() to remove ifdef-erry. Tested-by: Alim Akhtar Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220308080919.152715-9-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index f466c8f8adcc..5affd7e707bd 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2147,23 +2147,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 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; } -- cgit v1.2.3 From 927728a34f11b5a27f4610bdb7068317d6fdc72a Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 8 Mar 2022 19:00:42 +0800 Subject: serial: sc16is7xx: Clear RS485 bits in the shutdown We tested RS485 function on an EVB which has SC16IS752, after finishing the test, we started the RS232 function test, but found the RTS is still working in the RS485 mode. That is because both startup and shutdown call port_update() to set the EFCR_REG, this will not clear the RS485 bits once the bits are set in the reconf_rs485(). To fix it, clear the RS485 bits in shutdown. Cc: Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20220308110042.108451-1-hui.wang@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 683dd3be010d..91434876fcde 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1238,10 +1238,12 @@ static void sc16is7xx_shutdown(struct uart_port *port) /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); - /* Disable TX/RX */ + /* Disable TX/RX, clear auto RS485 and RTS invert */ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | - SC16IS7XX_EFCR_TXDISABLE_BIT, + SC16IS7XX_EFCR_TXDISABLE_BIT | + SC16IS7XX_EFCR_AUTO_RS485_BIT | + SC16IS7XX_EFCR_RTS_INVERT_BIT, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); -- cgit v1.2.3 From 1db536f95d0264a2b83fb032d5b057ba0113e622 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Fri, 11 Mar 2022 10:45:15 +0100 Subject: tty: serial: samsung: Add ARTPEC-8 support Add support for the UART block on the ARTPEC-8 SoC. This is closely related to the variants used on the Exynos chips. The register layout is identical to Exynos850 et al but the fifo size is different (64 bytes in each direction for all instances). Reviewed-by: Krzysztof Kozlowski Signed-off-by: Vincent Whitchurch Link: https://lore.kernel.org/r/20220311094515.3223023-3-vincent.whitchurch@axis.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- drivers/tty/serial/samsung_tty.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 162a1657ec60..6949e883ffab 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -237,7 +237,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || 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 diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 5affd7e707bd..e1585fbae909 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2825,6 +2825,36 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = { #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, + .fifosize = 64, + .has_divslot = 1, + .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", @@ -2853,6 +2883,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = { }, { .name = "exynos850-uart", .driver_data = (kernel_ulong_t)EXYNOS850_SERIAL_DRV_DATA, + }, { + .name = "artpec8-uart", + .driver_data = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA, }, { }, }; @@ -2878,6 +2911,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = { .data = S5L_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos850-uart", .data = EXYNOS850_SERIAL_DRV_DATA }, + { .compatible = "axis,artpec8-uart", + .data = ARTPEC8_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); @@ -3056,6 +3091,8 @@ 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); /* Apple S5L */ static int __init apple_s5l_early_console_setup(struct earlycon_device *device, -- cgit v1.2.3 From f58c252e30cf74f68b0054293adc03b5923b9f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 14 Mar 2022 11:14:32 +0200 Subject: serial: 8250: fix XOFF/XON sending when DMA is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When 8250 UART is using DMA, x_char (XON/XOFF) is never sent to the wire. After this change, x_char is injected correctly. Create uart_xchar_out() helper for sending the x_char out and accounting related to it. It seems that almost every driver does these same steps with x_char. Except for 8250, however, almost all currently lack .serial_out so they cannot immediately take advantage of this new helper. The downside of this patch is that it might reintroduce the problems some devices faced with mixed DMA/non-DMA transfer which caused revert f967fc8f165f (Revert "serial: 8250_dma: don't bother DMA with small transfers"). However, the impact should be limited to cases with XON/XOFF (that didn't work with DMA capable devices to begin with so this problem is not very likely to cause a major issue, if any at all). Fixes: 9ee4b83e51f74 ("serial: 8250: Add support for dmaengine") Reported-by: Gilles Buloz Tested-by: Gilles Buloz Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220314091432.4288-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dma.c | 11 ++++++++++- drivers/tty/serial/8250/8250_port.c | 4 +--- drivers/tty/serial/serial_core.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 890fa7ddaa7f..b3c3f7e5851a 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -64,10 +64,19 @@ 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 dma_async_tx_descriptor *desc; + struct uart_port *up = &p->port; 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)) { /* We have been called from __dma_tx_complete() */ diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 267026892264..318af6f13605 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1822,9 +1822,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) 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)) { diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a1688a341411..6a8963caf954 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -641,6 +641,20 @@ static void uart_flush_buffer(struct tty_struct *tty) 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 -- cgit v1.2.3 From b31c41339f4f8a833cb9dc509f87aab6a159ffe4 Mon Sep 17 00:00:00 2001 From: Xiaomeng Tong Date: Mon, 14 Mar 2022 20:29:21 +0800 Subject: vt_ioctl: fix potential spectre v1 in VT_DISALLOCATE In VT_ACTIVATE an almost identical code path has been patched with array_index_nospec. In the VT_DISALLOCATE path, the arg is the user input from a system call argument and lately used as a index for vc_cons[index].d access, which can be reached through path like vt_disallocate->vc_busy or vt_disallocate->vc_deallocate. For consistency both code paths should have the same mitigations applied. Also, the code style is adjusted as suggested by Jiri. Reviewed-by: Jiri Slaby Signed-off-by: Xiaomeng Tong Link: https://lore.kernel.org/r/20220314122921.31223-1-xiam0nd.tong@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 58013698635f..8c685b501404 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -898,11 +898,13 @@ int vt_ioctl(struct tty_struct *tty, if (arg > MAX_NR_CONSOLES) return -ENXIO; - if (arg == 0) + if (arg == 0) { vt_disallocate_all(); - else - return vt_disallocate(--arg); - break; + break; + } + + arg = array_index_nospec(arg - 1, MAX_NR_CONSOLES); + return vt_disallocate(arg); case VT_RESIZE: { -- cgit v1.2.3