serial_npcm.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2021 Nuvoton Technology Corp.
  4. */
  5. #include <common.h>
  6. #include <clk.h>
  7. #include <dm.h>
  8. #include <serial.h>
  9. struct npcm_uart {
  10. union {
  11. u32 rbr; /* Receive Buffer Register */
  12. u32 thr; /* Transmit Holding Register */
  13. u32 dll; /* Divisor Latch (Low Byte) Register */
  14. };
  15. union {
  16. u32 ier; /* Interrupt Enable Register */
  17. u32 dlm; /* Divisor Latch (Low Byte) Register */
  18. };
  19. union {
  20. u32 iir; /* Interrupt Identification Register */
  21. u32 fcr; /* FIFO Control Register */
  22. };
  23. u32 lcr; /* Line Control Register */
  24. u32 mcr; /* Modem Control Register */
  25. u32 lsr; /* Line Status Control Register */
  26. u32 msr; /* Modem Status Register */
  27. u32 tor; /* Timeout Register */
  28. };
  29. #define LCR_WLS_8BITS 3 /* 8-bit word length select */
  30. #define FCR_TFR BIT(2) /* TxFIFO reset */
  31. #define FCR_RFR BIT(1) /* RxFIFO reset */
  32. #define FCR_FME BIT(0) /* FIFO mode enable */
  33. #define LSR_THRE BIT(5) /* Status of TxFIFO empty */
  34. #define LSR_RFDR BIT(0) /* Status of RxFIFO data ready */
  35. #define LCR_DLAB BIT(7) /* Divisor latch access bit */
  36. struct npcm_serial_plat {
  37. struct npcm_uart *reg;
  38. u32 uart_clk; /* frequency of uart clock source */
  39. };
  40. static int npcm_serial_pending(struct udevice *dev, bool input)
  41. {
  42. struct npcm_serial_plat *plat = dev_get_plat(dev);
  43. struct npcm_uart *uart = plat->reg;
  44. if (input)
  45. return readb(&uart->lsr) & LSR_RFDR ? 1 : 0;
  46. else
  47. return readb(&uart->lsr) & LSR_THRE ? 0 : 1;
  48. }
  49. static int npcm_serial_putc(struct udevice *dev, const char ch)
  50. {
  51. struct npcm_serial_plat *plat = dev_get_plat(dev);
  52. struct npcm_uart *uart = plat->reg;
  53. if (!(readb(&uart->lsr) & LSR_THRE))
  54. return -EAGAIN;
  55. writeb(ch, &uart->thr);
  56. return 0;
  57. }
  58. static int npcm_serial_getc(struct udevice *dev)
  59. {
  60. struct npcm_serial_plat *plat = dev_get_plat(dev);
  61. struct npcm_uart *uart = plat->reg;
  62. if (!(readb(&uart->lsr) & LSR_RFDR))
  63. return -EAGAIN;
  64. return readb(&uart->rbr);
  65. }
  66. static int npcm_serial_setbrg(struct udevice *dev, int baudrate)
  67. {
  68. struct npcm_serial_plat *plat = dev_get_plat(dev);
  69. struct npcm_uart *uart = plat->reg;
  70. u16 divisor;
  71. /* BaudOut = UART Clock / (16 * [Divisor + 2]) */
  72. divisor = DIV_ROUND_CLOSEST(plat->uart_clk, 16 * baudrate + 2) - 2;
  73. setbits_8(&uart->lcr, LCR_DLAB);
  74. writeb(divisor & 0xff, &uart->dll);
  75. writeb(divisor >> 8, &uart->dlm);
  76. clrbits_8(&uart->lcr, LCR_DLAB);
  77. return 0;
  78. }
  79. static int npcm_serial_probe(struct udevice *dev)
  80. {
  81. struct npcm_serial_plat *plat = dev_get_plat(dev);
  82. struct npcm_uart *uart = plat->reg;
  83. struct clk clk, parent;
  84. u32 freq;
  85. int ret;
  86. plat->reg = dev_read_addr_ptr(dev);
  87. freq = dev_read_u32_default(dev, "clock-frequency", 0);
  88. ret = clk_get_by_index(dev, 0, &clk);
  89. if (ret < 0)
  90. return ret;
  91. ret = clk_get_by_index(dev, 1, &parent);
  92. if (!ret) {
  93. ret = clk_set_parent(&clk, &parent);
  94. if (ret)
  95. return ret;
  96. }
  97. ret = clk_set_rate(&clk, freq);
  98. if (ret < 0)
  99. return ret;
  100. plat->uart_clk = ret;
  101. /* Disable all interrupt */
  102. writeb(0, &uart->ier);
  103. /* Set 8 bit, 1 stop, no parity */
  104. writeb(LCR_WLS_8BITS, &uart->lcr);
  105. /* Reset RX/TX FIFO */
  106. writeb(FCR_FME | FCR_RFR | FCR_TFR, &uart->fcr);
  107. return 0;
  108. }
  109. static const struct dm_serial_ops npcm_serial_ops = {
  110. .getc = npcm_serial_getc,
  111. .setbrg = npcm_serial_setbrg,
  112. .putc = npcm_serial_putc,
  113. .pending = npcm_serial_pending,
  114. };
  115. static const struct udevice_id npcm_serial_ids[] = {
  116. { .compatible = "nuvoton,npcm750-uart" },
  117. { .compatible = "nuvoton,npcm845-uart" },
  118. { }
  119. };
  120. U_BOOT_DRIVER(serial_npcm) = {
  121. .name = "serial_npcm",
  122. .id = UCLASS_SERIAL,
  123. .of_match = npcm_serial_ids,
  124. .plat_auto = sizeof(struct npcm_serial_plat),
  125. .probe = npcm_serial_probe,
  126. .ops = &npcm_serial_ops,
  127. .flags = DM_FLAG_PRE_RELOC,
  128. };