Skip to content

Commit

Permalink
tty: serial: fsl_lpuart: don't break the on-going transfer when globa…
Browse files Browse the repository at this point in the history
…l reset

[ Upstream commit 76bad3f ]

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 60f3617 ("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: bd5305d ("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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Sherry Sun authored and gregkh committed Nov 26, 2022
1 parent 958da6d commit 378f1cd
Showing 1 changed file with 49 additions and 27 deletions.
76 changes: 49 additions & 27 deletions drivers/tty/serial/fsl_lpuart.c
Expand Up @@ -12,6 +12,7 @@
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
Expand Down Expand Up @@ -404,33 +405,6 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
#define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)

static int lpuart_global_reset(struct lpuart_port *sport)
{
struct uart_port *port = &sport->port;
void __iomem *global_addr;
int ret;

if (uart_console(port))
return 0;

ret = clk_prepare_enable(sport->ipg_clk);
if (ret) {
dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
return ret;
}

if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
writel(UART_GLOBAL_RST, global_addr);
usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
writel(0, global_addr);
usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
}

clk_disable_unprepare(sport->ipg_clk);
return 0;
}

static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
Expand Down Expand Up @@ -2641,6 +2615,54 @@ static const struct serial_rs485 lpuart_rs485_supported = {
/* delay_rts_* and RX_DURING_TX are not supported */
};

static int lpuart_global_reset(struct lpuart_port *sport)
{
struct uart_port *port = &sport->port;
void __iomem *global_addr;
unsigned long ctrl, bd;
unsigned int val = 0;
int ret;

ret = clk_prepare_enable(sport->ipg_clk);
if (ret) {
dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
return ret;
}

if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
/*
* If the transmitter is used by earlycon, wait for transmit engine to
* complete and then reset.
*/
ctrl = lpuart32_read(port, UARTCTRL);
if (ctrl & UARTCTRL_TE) {
bd = lpuart32_read(&sport->port, UARTBAUD);
if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false,
port)) {
dev_warn(sport->port.dev,
"timeout waiting for transmit engine to complete\n");
clk_disable_unprepare(sport->ipg_clk);
return 0;
}
}

global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
writel(UART_GLOBAL_RST, global_addr);
usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
writel(0, global_addr);
usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);

/* Recover the transmitter for earlycon. */
if (ctrl & UARTCTRL_TE) {
lpuart32_write(port, bd, UARTBAUD);
lpuart32_write(port, ctrl, UARTCTRL);
}
}

clk_disable_unprepare(sport->ipg_clk);
return 0;
}

static int lpuart_probe(struct platform_device *pdev)
{
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
Expand Down

0 comments on commit 378f1cd

Please sign in to comment.