early.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-11-16 GuEe-GUI first version
  9. */
  10. #include "8250.h"
  11. struct serial8250 early_serial8250 = { 0 };
  12. static rt_uint32_t serial8250_early_in(struct serial8250 *serial, int offset)
  13. {
  14. return serial8250_in(serial, offset);
  15. }
  16. static void serial8250_early_out(struct serial8250 *serial, int offset, int value)
  17. {
  18. serial8250_out(serial, offset, value);
  19. }
  20. int serial8250_early_putc(struct rt_serial_device *raw_serial, char c)
  21. {
  22. if (raw_serial)
  23. {
  24. /* FIFO and shifting register empty */
  25. const int uart_lsr_both_empty = (UART_LSR_TEMT | UART_LSR_THRE);
  26. struct serial8250 *serial = rt_container_of(raw_serial, struct serial8250, parent);
  27. serial8250_early_out(serial, UART_TX, c);
  28. while ((serial8250_early_in(serial, UART_LSR) & uart_lsr_both_empty) != uart_lsr_both_empty)
  29. {
  30. rt_hw_cpu_relax();
  31. }
  32. }
  33. return 1;
  34. }
  35. static void init_serial(struct serial8250 *serial)
  36. {
  37. unsigned char c;
  38. rt_uint32_t ier, divisor;
  39. serial8250_early_out(serial, UART_LCR, 0x3); /* 8n1 */
  40. ier = serial8250_early_in(serial, UART_IER);
  41. serial8250_early_out(serial, UART_IER, ier & UART_IER_UUE); /* No interrupt */
  42. serial8250_early_out(serial, UART_FCR, 0); /* No fifo */
  43. serial8250_early_out(serial, UART_MCR, 0x3); /* DTR + RTS */
  44. if (serial->freq)
  45. {
  46. divisor = RT_DIV_ROUND_CLOSEST(serial->freq, 16 * serial->parent.config.baud_rate);
  47. c = serial8250_early_in(serial, UART_LCR);
  48. serial8250_early_out(serial, UART_LCR, c | UART_LCR_DLAB);
  49. serial8250_early_out(serial, UART_DLL, divisor & 0xff);
  50. serial8250_early_out(serial, UART_DLM, (divisor >> 8) & 0xff);
  51. serial8250_early_out(serial, UART_LCR, c & ~UART_LCR_DLAB);
  52. }
  53. }
  54. static void serial8250_early_kick(struct rt_fdt_earlycon *con, int why)
  55. {
  56. struct serial8250 *serial = raw_to_serial8250(con->data);
  57. switch (why)
  58. {
  59. case FDT_EARLYCON_KICK_UPDATE:
  60. serial->base = rt_ioremap((void *)con->mmio, con->size);
  61. break;
  62. case FDT_EARLYCON_KICK_COMPLETED:
  63. rt_iounmap(serial->base);
  64. break;
  65. default:
  66. break;
  67. }
  68. }
  69. rt_err_t serial8250_early_fdt_setup(struct serial8250 *serial, struct rt_fdt_earlycon *con, const char *options)
  70. {
  71. rt_err_t ret = RT_EOK;
  72. if (!serial->base && con)
  73. {
  74. serial8250_config(serial, options);
  75. con->mmio = (rt_ubase_t)serial->base;
  76. con->size = serial->size;
  77. }
  78. if (serial->base && con)
  79. {
  80. serial->base = rt_ioremap_early((void *)serial->base, serial->size);
  81. }
  82. if (serial->base && con)
  83. {
  84. con->console_putc = (typeof(con->console_putc))&serial8250_early_putc;
  85. con->console_kick = serial8250_early_kick;
  86. con->data = &serial->parent;
  87. if (!serial->parent.config.baud_rate)
  88. {
  89. /* Assume the device was initialized, only mask interrupts */
  90. rt_uint32_t ier = serial8250_early_in(serial, UART_IER);
  91. serial8250_early_out(serial, UART_IER, ier & UART_IER_UUE);
  92. }
  93. else
  94. {
  95. init_serial(serial);
  96. }
  97. }
  98. else
  99. {
  100. ret = -RT_ERROR;
  101. }
  102. return ret;
  103. }
  104. static void common_init(struct serial8250 *serial, struct rt_fdt_earlycon *con)
  105. {
  106. serial->base = (void *)con->mmio;
  107. serial->size = con->size;
  108. serial->iotype = PORT_MMIO32;
  109. }
  110. static rt_err_t common_early_setup(struct rt_fdt_earlycon *con, const char *options)
  111. {
  112. struct serial8250 *serial = &early_serial8250;
  113. common_init(serial, con);
  114. serial->regshift = 2;
  115. fdt_getprop_u32(con->fdt, con->nodeoffset, "reg-shift", &serial->regshift, RT_NULL);
  116. return serial8250_early_fdt_setup(serial, con, options);
  117. }
  118. RT_FDT_EARLYCON_EXPORT(bcm2835aux, "uart8250", "brcm,bcm2835-aux-uart", common_early_setup);
  119. RT_FDT_EARLYCON_EXPORT(tegra20, "uart8250", "nvidia,tegra20-uart", common_early_setup);
  120. RT_FDT_EARLYCON_EXPORT(dw8250, "uart8250", "snps,dw-apb-uart", common_early_setup);
  121. RT_FDT_EARLYCON_EXPORT(ns16550a, "uart8250", "ns16550a", common_early_setup);
  122. RT_FDT_EARLYCON_EXPORT(ns16550, "uart8250", "ns16550", common_early_setup);
  123. #ifdef RT_USING_8250_OMAP
  124. static rt_err_t omap8250_early_setup(struct rt_fdt_earlycon *con, const char *options)
  125. {
  126. struct serial8250 *serial = &early_serial8250;
  127. common_init(serial, con);
  128. serial->regshift = 2;
  129. return serial8250_early_fdt_setup(serial, con, options);
  130. }
  131. RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap2-uart", omap8250_early_setup);
  132. RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap3-uart", omap8250_early_setup);
  133. RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap4-uart", omap8250_early_setup);
  134. #endif /* RT_USING_8250_OMAP */