Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tty: serial: fsl_lpuart: don't break the on-going transfer when global reset

lpuart_global_reset() shouldn't break the on-going transmit engine, need
to recover the on-going data transfer after reset.

This can help earlycon here, since commit 60f361722ad2 ("serial:
fsl_lpuart: Reset prior to registration") moved lpuart_global_reset()
before uart_add_one_port(), earlycon is writing during global reset,
as global reset will disable the TX and clear the baud rate register,
which caused the earlycon cannot work any more after reset, needs to
restore the baud rate and re-enable the transmitter to recover the
earlycon write.

Also move the lpuart_global_reset() down, then we can reuse the
lpuart32_tx_empty() without declaration.

Fixes: bd5305dcabbc ("tty: serial: fsl_lpuart: do software reset for imx7ulp and imx8qxp")
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
Link: https://lore.kernel.org/r/20221024085844.22786-1-sherry.sun@nxp.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Sherry Sun and committed by
Greg Kroah-Hartman
76bad3f8 d0b68629

+49 -27
+49 -27
drivers/tty/serial/fsl_lpuart.c
··· 12 12 #include <linux/dmaengine.h> 13 13 #include <linux/dmapool.h> 14 14 #include <linux/io.h> 15 + #include <linux/iopoll.h> 15 16 #include <linux/irq.h> 16 17 #include <linux/module.h> 17 18 #include <linux/of.h> ··· 404 403 405 404 #define lpuart_enable_clks(x) __lpuart_enable_clks(x, true) 406 405 #define lpuart_disable_clks(x) __lpuart_enable_clks(x, false) 407 - 408 - static int lpuart_global_reset(struct lpuart_port *sport) 409 - { 410 - struct uart_port *port = &sport->port; 411 - void __iomem *global_addr; 412 - int ret; 413 - 414 - if (uart_console(port)) 415 - return 0; 416 - 417 - ret = clk_prepare_enable(sport->ipg_clk); 418 - if (ret) { 419 - dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret); 420 - return ret; 421 - } 422 - 423 - if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) { 424 - global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF; 425 - writel(UART_GLOBAL_RST, global_addr); 426 - usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); 427 - writel(0, global_addr); 428 - usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); 429 - } 430 - 431 - clk_disable_unprepare(sport->ipg_clk); 432 - return 0; 433 - } 434 406 435 407 static void lpuart_stop_tx(struct uart_port *port) 436 408 { ··· 2609 2635 .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, 2610 2636 /* delay_rts_* and RX_DURING_TX are not supported */ 2611 2637 }; 2638 + 2639 + static int lpuart_global_reset(struct lpuart_port *sport) 2640 + { 2641 + struct uart_port *port = &sport->port; 2642 + void __iomem *global_addr; 2643 + unsigned long ctrl, bd; 2644 + unsigned int val = 0; 2645 + int ret; 2646 + 2647 + ret = clk_prepare_enable(sport->ipg_clk); 2648 + if (ret) { 2649 + dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret); 2650 + return ret; 2651 + } 2652 + 2653 + if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) { 2654 + /* 2655 + * If the transmitter is used by earlycon, wait for transmit engine to 2656 + * complete and then reset. 2657 + */ 2658 + ctrl = lpuart32_read(port, UARTCTRL); 2659 + if (ctrl & UARTCTRL_TE) { 2660 + bd = lpuart32_read(&sport->port, UARTBAUD); 2661 + if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false, 2662 + port)) { 2663 + dev_warn(sport->port.dev, 2664 + "timeout waiting for transmit engine to complete\n"); 2665 + clk_disable_unprepare(sport->ipg_clk); 2666 + return 0; 2667 + } 2668 + } 2669 + 2670 + global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF; 2671 + writel(UART_GLOBAL_RST, global_addr); 2672 + usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); 2673 + writel(0, global_addr); 2674 + usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); 2675 + 2676 + /* Recover the transmitter for earlycon. */ 2677 + if (ctrl & UARTCTRL_TE) { 2678 + lpuart32_write(port, bd, UARTBAUD); 2679 + lpuart32_write(port, ctrl, UARTCTRL); 2680 + } 2681 + } 2682 + 2683 + clk_disable_unprepare(sport->ipg_clk); 2684 + return 0; 2685 + } 2612 2686 2613 2687 static int lpuart_probe(struct platform_device *pdev) 2614 2688 {