serial.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * arch/arm/mach-lpc32xx/serial.c
  4. *
  5. * Author: Kevin Wells <kevin.wells@nxp.com>
  6. *
  7. * Copyright (C) 2010 NXP Semiconductors
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/types.h>
  11. #include <linux/serial.h>
  12. #include <linux/serial_core.h>
  13. #include <linux/serial_reg.h>
  14. #include <linux/serial_8250.h>
  15. #include <linux/clk.h>
  16. #include <linux/io.h>
  17. #include <linux/soc/nxp/lpc32xx-misc.h>
  18. #include "lpc32xx.h"
  19. #include "common.h"
  20. #define LPC32XX_SUART_FIFO_SIZE 64
  21. struct uartinit {
  22. char *uart_ck_name;
  23. u32 ck_mode_mask;
  24. void __iomem *pdiv_clk_reg;
  25. resource_size_t mapbase;
  26. };
  27. static struct uartinit uartinit_data[] __initdata = {
  28. {
  29. .uart_ck_name = "uart5_ck",
  30. .ck_mode_mask =
  31. LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
  32. .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
  33. .mapbase = LPC32XX_UART5_BASE,
  34. },
  35. {
  36. .uart_ck_name = "uart3_ck",
  37. .ck_mode_mask =
  38. LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
  39. .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
  40. .mapbase = LPC32XX_UART3_BASE,
  41. },
  42. {
  43. .uart_ck_name = "uart4_ck",
  44. .ck_mode_mask =
  45. LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
  46. .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
  47. .mapbase = LPC32XX_UART4_BASE,
  48. },
  49. {
  50. .uart_ck_name = "uart6_ck",
  51. .ck_mode_mask =
  52. LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
  53. .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
  54. .mapbase = LPC32XX_UART6_BASE,
  55. },
  56. };
  57. /* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
  58. void lpc32xx_loopback_set(resource_size_t mapbase, int state)
  59. {
  60. int bit;
  61. u32 tmp;
  62. switch (mapbase) {
  63. case LPC32XX_HS_UART1_BASE:
  64. bit = 0;
  65. break;
  66. case LPC32XX_HS_UART2_BASE:
  67. bit = 1;
  68. break;
  69. case LPC32XX_HS_UART7_BASE:
  70. bit = 6;
  71. break;
  72. default:
  73. WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
  74. return;
  75. }
  76. tmp = readl(LPC32XX_UARTCTL_CLOOP);
  77. if (state)
  78. tmp |= (1 << bit);
  79. else
  80. tmp &= ~(1 << bit);
  81. writel(tmp, LPC32XX_UARTCTL_CLOOP);
  82. }
  83. EXPORT_SYMBOL_GPL(lpc32xx_loopback_set);
  84. void __init lpc32xx_serial_init(void)
  85. {
  86. u32 tmp, clkmodes = 0;
  87. struct clk *clk;
  88. unsigned int puart;
  89. int i, j;
  90. for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
  91. clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
  92. if (!IS_ERR(clk)) {
  93. clk_enable(clk);
  94. }
  95. /* Setup UART clock modes for all UARTs, disable autoclock */
  96. clkmodes |= uartinit_data[i].ck_mode_mask;
  97. /* pre-UART clock divider set to 1 */
  98. __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
  99. /*
  100. * Force a flush of the RX FIFOs to work around a
  101. * HW bug
  102. */
  103. puart = uartinit_data[i].mapbase;
  104. __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
  105. __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
  106. j = LPC32XX_SUART_FIFO_SIZE;
  107. while (j--)
  108. tmp = __raw_readl(
  109. LPC32XX_UART_DLL_FIFO(puart));
  110. __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
  111. }
  112. /* This needs to be done after all UART clocks are setup */
  113. __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
  114. for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
  115. /* Force a flush of the RX FIFOs to work around a HW bug */
  116. puart = uartinit_data[i].mapbase;
  117. __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
  118. __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
  119. j = LPC32XX_SUART_FIFO_SIZE;
  120. while (j--)
  121. tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart));
  122. __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
  123. }
  124. /* Disable IrDA pulsing support on UART6 */
  125. tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
  126. tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
  127. __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
  128. /* Disable UART5->USB transparent mode or USB won't work */
  129. tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
  130. tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
  131. __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
  132. }