Commit 6c6c6d774aa9d982f8599492baaf12b2544c3e16

Authored by Fugang Duan
1 parent c90b6544df

MLK-21445 serial: fsl_lpuart: do HW reset for communication port

Do HW reset for communication port after the port is registered
if the UART controller support the feature.

Do partition reset with LPUART's power on, LPUART registers will
keep the previous status, like on i.MX8QM platform,  which is not
expected action, so reset the HW is required.

Currently, only i.MX7ULP and i.MX8QM LPUART controllers include
global register that support HW reset.

Tested-by: Robin Gong <yibin.gong@nxp.com>
Tested-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Robby Cai <robby.cai@nxp.com>
Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
(cherry picked from commit c2bc1f62ec28981462c9cb5ceac17134931ca19f)

Showing 1 changed file with 43 additions and 0 deletions Side-by-side Diff

drivers/tty/serial/fsl_lpuart.c
... ... @@ -131,6 +131,11 @@
131 131 #define UARTFIFO 0x18
132 132 #define UARTWATER 0x1c
133 133  
  134 +/* 32-bit global registers only for i.MX7ulp/MX8x
  135 + * The driver only use the reset feature to reset HW.
  136 + */
  137 +#define UART_GLOBAL 0x8
  138 +
134 139 #define UARTBAUD_MAEN1 0x80000000
135 140 #define UARTBAUD_MAEN2 0x40000000
136 141 #define UARTBAUD_M10 0x20000000
... ... @@ -236,6 +241,10 @@
236 241 #define UARTWATER_TXWATER_OFF 0
237 242 #define UARTWATER_RXWATER_OFF 16
238 243  
  244 +#define UART_GLOBAL_RST 0x2
  245 +#define RST_HW_MIN_US 20
  246 +#define RST_HW_MAX_US 40
  247 +
239 248 #define UARTFIFO_RXIDEN_RDRF 0x3
240 249 #define UARTCTRL_IDLECFG 0x7
241 250 #define FSL_UART_RX_DMA_BUFFER_SIZE 128
... ... @@ -250,6 +259,8 @@
250 259  
251 260 struct lpuart_port {
252 261 struct uart_port port;
  262 + void __iomem *regbase;
  263 +
253 264 struct clk *ipg_clk;
254 265 struct clk *per_clk;
255 266 unsigned int txfifo_size;
... ... @@ -346,6 +357,33 @@
346 357 }
347 358 }
348 359  
  360 +static int lpuart_hw_reset(struct lpuart_port *sport)
  361 +{
  362 + struct uart_port *port = &sport->port;
  363 + struct device_node *np = sport->port.dev->of_node;
  364 + int ret;
  365 +
  366 + if (uart_console(port))
  367 + return 0;
  368 +
  369 + ret = clk_prepare_enable(sport->ipg_clk);
  370 + if (ret) {
  371 + dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
  372 + return ret;
  373 + }
  374 +
  375 + if (np && (of_device_is_compatible(np, "fsl,imx7ulp-lpuart") ||
  376 + of_device_is_compatible(np, "fsl,imx8qm-lpuart"))) {
  377 + writel(UART_GLOBAL_RST, sport->regbase + UART_GLOBAL);
  378 + usleep_range(RST_HW_MIN_US, RST_HW_MAX_US);
  379 + writel(0, sport->regbase + UART_GLOBAL);
  380 + usleep_range(RST_HW_MIN_US, RST_HW_MAX_US);
  381 + }
  382 +
  383 + clk_disable_unprepare(sport->ipg_clk);
  384 + return 0;
  385 +}
  386 +
349 387 static void lpuart_stop_tx(struct uart_port *port)
350 388 {
351 389 unsigned char temp;
... ... @@ -2420,6 +2458,7 @@
2420 2458 if (IS_ERR(sport->port.membase))
2421 2459 return PTR_ERR(sport->port.membase);
2422 2460  
  2461 + sport->regbase = sport->port.membase;
2423 2462 sport->port.membase += sdata->reg_off;
2424 2463 sport->port.mapbase = res->start + sdata->reg_off;
2425 2464 sport->port.dev = &pdev->dev;
... ... @@ -2500,6 +2539,10 @@
2500 2539 pm_runtime_enable(&pdev->dev);
2501 2540  
2502 2541 ret = uart_add_one_port(&lpuart_reg, &sport->port);
  2542 + if (ret)
  2543 + goto failed_attach_port;
  2544 +
  2545 + ret = lpuart_hw_reset(sport);
2503 2546 if (ret)
2504 2547 goto failed_attach_port;
2505 2548