819-uart-0008-MLK-21445-serial-fsl_lpuart-do-HW-reset-for-communic.patch 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. From d9d113c22c634219cc248a7c6dcf157e2927edad Mon Sep 17 00:00:00 2001
  2. From: Fugang Duan <[email protected]>
  3. Date: Tue, 23 Jul 2019 11:36:22 +0800
  4. Subject: [PATCH] MLK-21445 serial: fsl_lpuart: do HW reset for communication
  5. port
  6. Do HW reset for communication port after the port is registered
  7. if the UART controller support the feature.
  8. Do partition reset with LPUART's power on, LPUART registers will
  9. keep the previous status, like on i.MX8QM platform, which is not
  10. expected action, so reset the HW is required.
  11. Currently, only i.MX7ULP and i.MX8QM LPUART controllers include
  12. global register that support HW reset.
  13. Tested-by: Robin Gong <[email protected]>
  14. Tested-by: Peng Fan <[email protected]>
  15. Reviewed-by: Robby Cai <[email protected]>
  16. Signed-off-by: Fugang Duan <[email protected]>
  17. (cherry picked from commit c2bc1f62ec28981462c9cb5ceac17134931ca19f)
  18. Signed-off-by: Arulpandiyan Vadivel <[email protected]>
  19. Signed-off-by: Shrikant Bobade <[email protected]>
  20. (cherry picked from commit 9f396f540093402317c3c1b9a8fe955b91c89164)
  21. ---
  22. drivers/tty/serial/fsl_lpuart.c | 48 +++++++++++++++++++++++++++++++++++++++++
  23. 1 file changed, 48 insertions(+)
  24. --- a/drivers/tty/serial/fsl_lpuart.c
  25. +++ b/drivers/tty/serial/fsl_lpuart.c
  26. @@ -11,6 +11,7 @@
  27. #include <linux/clk.h>
  28. #include <linux/console.h>
  29. +#include <linux/delay.h>
  30. #include <linux/dma-mapping.h>
  31. #include <linux/dmaengine.h>
  32. #include <linux/dmapool.h>
  33. @@ -116,6 +117,11 @@
  34. #define UARTSFIFO_TXOF 0x02
  35. #define UARTSFIFO_RXUF 0x01
  36. +/* 32-bit global registers only for i.MX7ulp/MX8x
  37. + * The driver only use the reset feature to reset HW.
  38. + */
  39. +#define UART_GLOBAL 0x8
  40. +
  41. /* 32-bit register definition */
  42. #define UARTBAUD 0x00
  43. #define UARTSTAT 0x04
  44. @@ -230,6 +236,10 @@
  45. #define UARTWATER_TXWATER_OFF 0
  46. #define UARTWATER_RXWATER_OFF 16
  47. +#define UART_GLOBAL_RST 0x2
  48. +#define RST_HW_MIN_US 20
  49. +#define RST_HW_MAX_US 40
  50. +
  51. #define UARTFIFO_RXIDEN_RDRF 0x3
  52. #define UARTCTRL_IDLECFG 0x7
  53. @@ -350,6 +360,11 @@ static inline bool is_layerscape_lpuart(
  54. sport->devtype == LS1028A_LPUART);
  55. }
  56. +static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport)
  57. +{
  58. + return sport->devtype == IMX7ULP_LPUART;
  59. +}
  60. +
  61. static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
  62. {
  63. return sport->devtype == IMX8QXP_LPUART;
  64. @@ -413,6 +428,33 @@ static unsigned int lpuart_get_baud_clk_
  65. #define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
  66. #define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
  67. +static int lpuart_hw_reset(struct lpuart_port *sport)
  68. +{
  69. + struct uart_port *port = &sport->port;
  70. + void __iomem *global_addr;
  71. + int ret;
  72. +
  73. + if (uart_console(port))
  74. + return 0;
  75. +
  76. + ret = clk_prepare_enable(sport->ipg_clk);
  77. + if (ret) {
  78. + dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
  79. + return ret;
  80. + }
  81. +
  82. + if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
  83. + global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
  84. + writel(UART_GLOBAL_RST, global_addr);
  85. + usleep_range(RST_HW_MIN_US, RST_HW_MAX_US);
  86. + writel(0, global_addr);
  87. + usleep_range(RST_HW_MIN_US, RST_HW_MAX_US);
  88. + }
  89. +
  90. + clk_disable_unprepare(sport->ipg_clk);
  91. + return 0;
  92. +}
  93. +
  94. static void lpuart_stop_tx(struct uart_port *port)
  95. {
  96. unsigned char temp;
  97. @@ -2728,6 +2770,10 @@ static int lpuart_probe(struct platform_
  98. if (ret)
  99. goto failed_attach_port;
  100. + ret = lpuart_hw_reset(sport);
  101. + if (ret)
  102. + goto failed_reset;
  103. +
  104. uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
  105. if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX)
  106. @@ -2751,6 +2797,8 @@ static int lpuart_probe(struct platform_
  107. return 0;
  108. +failed_reset:
  109. + uart_remove_one_port(&lpuart_reg, &sport->port);
  110. failed_attach_port:
  111. failed_irq_request:
  112. lpuart_disable_clks(sport);