serial.c 3.7 KB

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