drv_uart.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-07-15 JasonHu first version
  9. */
  10. #include <rtconfig.h>
  11. #ifdef BSP_DRV_UART
  12. #include <rthw.h>
  13. #include <rtdevice.h>
  14. #include "drv_uart.h"
  15. #include "board.h"
  16. struct hw_uart_device
  17. {
  18. rt_uint32_t hw_base;
  19. rt_uint32_t irqno;
  20. rt_uint16_t data_reg;
  21. rt_uint16_t divisor_low_reg;
  22. rt_uint16_t intr_enable_reg;
  23. rt_uint16_t divisor_high_reg;
  24. rt_uint16_t intr_indenty_reg;
  25. rt_uint16_t fifo_reg;
  26. rt_uint16_t line_ctrl_reg;
  27. rt_uint16_t modem_ctrl_reg;
  28. rt_uint16_t line_status_reg;
  29. rt_uint16_t modem_status_reg;
  30. rt_uint16_t scratch_reg;
  31. };
  32. /* I/O port base addr */
  33. #define SERIAL0_BASE 0X3F8
  34. #define SERIAL1_BASE 0X2F8
  35. #define SERIAL0_IRQ 4
  36. #define SERIAL1_IRQ 3
  37. #define MAX_BAUD_VALUE 115200
  38. #define DEFAULT_BAUD_VALUE 115200
  39. #define DEFAULT_DIVISOR_VALUE (MAX_BAUD_VALUE / DEFAULT_BAUD_VALUE)
  40. enum uart_fifo_control_register_bits
  41. {
  42. FIFO_ENABLE = 1, /* Enable FIFOs */
  43. FIFO_CLEAR_RECEIVE = (1 << 1), /* Clear Receive FIFO */
  44. FIFO_CLEAR_TRANSMIT = (1 << 2), /* Clear Transmit FIFO */
  45. FIFO_DMA_MODE_SELECT = (1 << 3), /* DMA Mode Select */
  46. FIFO_RESERVED = (1 << 4), /* Reserved */
  47. FIFO_ENABLE_64 = (1 << 5), /* Enable 64 Byte FIFO(16750) */
  48. /* Interrupt Trigger Level/Trigger Level */
  49. FIFO_TRIGGER_1 = (0 << 6), /* 1 Byte */
  50. FIFO_TRIGGER_4 = (1 << 6), /* 4 Byte */
  51. FIFO_TRIGGER_8 = (1 << 7), /* 8 Byte */
  52. FIFO_TRIGGER_14 = (1 << 6) | (1 << 7), /* 14 Byte */
  53. };
  54. enum uart_line_control_register_bits
  55. {
  56. /* Word Length */
  57. LINE_WORD_LENGTH_5 = 0, /* 5 Bits */
  58. LINE_WORD_LENGTH_6 = 1, /* 6 Bits */
  59. LINE_WORD_LENGTH_7 = (1 << 1), /* 7 Bits */
  60. LINE_WORD_LENGTH_8 = ((1 << 1) | 1), /* 8 Bits */
  61. LINE_STOP_BIT_1 = (0 << 2), /* One Stop Bit */
  62. LINE_STOP_BIT_2 = (1 << 2), /* 1.5 Stop Bits or 2 Stop Bits */
  63. /* Parity Select */
  64. LINE_PARITY_NO = (0 << 3), /* No Parity */
  65. LINE_PARITY_ODD = (1 << 3), /* Odd Parity */
  66. LINE_PARITY_EVEN = (1 << 3) | (1 << 4), /* Even Parity */
  67. LINE_PARITY_MARK = (1 << 3) | (1 << 5), /* Mark */
  68. LINE_PARITY_SPACE = (1 << 3) | (1 << 4) | (1 << 5), /* Space */
  69. LINE_BREAK_ENABLE = (1 << 6), /* Set Break Enable */
  70. LINE_DLAB = (1 << 7), /* Divisor Latch Access Bit */
  71. };
  72. enum uart_interrupt_enable_register_bits
  73. {
  74. INTR_RECV_DATA_AVALIABLE = 1, /* Enable Received Data Available Interrupt */
  75. INTR_TRANSMIT_HOLDING = (1 << 1), /* Enable Transmitter Holding Register Empty Interrupt */
  76. INTR_STATUS_CHANGED = (1 << 2), /* Enable Receiver Line Status Interrupt */
  77. INTR_MODEM_STATUS = (1 << 3), /* Enable Modem Status Interrupt */
  78. INTR_SLEEP_MODE = (1 << 4), /* Enable Sleep Mode(16750) */
  79. INTR_LOW_POWER_MODE = (1 << 5), /* Enable Low Power Mode(16750) */
  80. INTR_RESERVED1 = (1 << 6), /* Reserved */
  81. INTR_RESERVED2 = (1 << 7), /* Reserved */
  82. };
  83. enum uart_line_status_register_bits
  84. {
  85. LINE_STATUS_DATA_READY = 1, /* Data Ready */
  86. LINE_STATUS_OVERRUN_ERROR = (1 << 1), /* Overrun Error */
  87. LINE_STATUS_PARITY_ERROR = (1 << 2), /* Parity Error */
  88. LINE_STATUS_FRAMING_ERROR = (1 << 3), /* Framing Error */
  89. LINE_STATUS_BREAK_INTERRUPT = (1 << 4), /* Break Interrupt */
  90. LINE_STATUS_EMPTY_TRANSMITTER_HOLDING = (1 << 5), /* Empty Transmitter Holding Register */
  91. LINE_STATUS_EMPTY_DATA_HOLDING = (1 << 6), /* Empty Data Holding Registers */
  92. LINE_STATUS_ERROR_RECEIVE_FIFO = (1 << 7), /* Error in Received FIFO */
  93. };
  94. enum uart_intr_indenty_reg_bits
  95. {
  96. INTR_STATUS_PENDING_FLAG = 1, /* Interrupt Pending Flag */
  97. /* 产生的什么中断 */
  98. INTR_STATUS_MODEM = (0 << 1), /* Transmitter Holding Register Empty Interrupt */
  99. INTR_STATUS_TRANSMITTER_HOLDING = (1 << 1), /* Received Data Available Interrupt */
  100. INTR_STATUS_RECEIVE_DATA = (1 << 2), /* Received Data Available Interrupt */
  101. INTR_STATUS_RECEIVE_LINE = (1 << 1) | (1 << 2), /* Receiver Line Status Interrupt */
  102. INTR_STATUS_TIME_OUT_PENDING = (1 << 2) | (1 << 3), /* Time-out Interrupt Pending (16550 & later) */
  103. INTR_STATUS_64BYTE_FIFO = (1 << 5), /* 64 Byte FIFO Enabled (16750 only) */
  104. INTR_STATUS_NO_FIFO = (0 << 6), /* No FIFO on chip */
  105. INTR_STATUS_RESERVED_CONDITION = (1 << 6), /* Reserved condition */
  106. INTR_STATUS_FIFO_NOT_FUNC = (1 << 7), /* FIFO enabled, but not functioning */
  107. INTR_STATUS_FIFO = (1 << 6) | (1 << 7), /* FIFO enabled */
  108. };
  109. enum uart_modem_control_register_bits
  110. {
  111. MCR_DTR = 1, /* Programs -DTR. If set, -DTR is low and the DTR pin of the port goes 'high'. */
  112. MCR_RTS = (1 << 1), /* Programs -RTS. dito. */
  113. MCR_OUT1 = (1 << 2), /* Programs -OUT1. Normally not used in a PC, but used with some
  114. multi-port serial adapters to enable or disable a port. Best
  115. thing is to write a '1' to this bit. */
  116. MCR_OUT2 = (1 << 3), /* Programs -OUT2. If set to 1, interrupts generated by the UART
  117. are transferred to the ICU (Interrupt Control Unit) while 0
  118. sets the interrupt output of the card to high impedance.
  119. (This is PC-only). */
  120. MCR_LOOPBACK = (1 << 4), /* '1': local loopback. All outputs disabled. This is a means of
  121. testing the chip: you 'receive' all the data you send. */
  122. };
  123. static void rt_hw_uart_isr(int irqno, void *param)
  124. {
  125. struct rt_serial_device *serial = (struct rt_serial_device *)param;
  126. rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
  127. }
  128. static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  129. {
  130. RT_ASSERT(serial != RT_NULL);
  131. serial->config = *cfg;
  132. return RT_EOK;
  133. }
  134. static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
  135. {
  136. struct hw_uart_device *uart;
  137. RT_ASSERT(serial != RT_NULL);
  138. uart = (struct hw_uart_device *)serial->parent.user_data;
  139. rt_uint8_t val;
  140. switch (cmd)
  141. {
  142. case RT_DEVICE_CTRL_CLR_INT:
  143. /* disable rx irq */
  144. val = inb(uart->intr_enable_reg);
  145. outb(uart->intr_enable_reg, val & ~INTR_RECV_DATA_AVALIABLE);
  146. break;
  147. case RT_DEVICE_CTRL_SET_INT:
  148. /* enable rx irq */
  149. val = inb(uart->intr_enable_reg);
  150. outb(uart->intr_enable_reg, val | INTR_RECV_DATA_AVALIABLE);
  151. break;
  152. }
  153. return RT_EOK;
  154. }
  155. static int uart_putc(struct rt_serial_device *serial, char c)
  156. {
  157. struct hw_uart_device *uart;
  158. RT_ASSERT(serial != RT_NULL);
  159. uart = (struct hw_uart_device *)serial->parent.user_data;
  160. int timeout = 100000;
  161. while (!(inb(uart->line_status_reg) & LINE_STATUS_EMPTY_TRANSMITTER_HOLDING) && timeout--)
  162. {
  163. }
  164. outb(uart->data_reg, c);
  165. return 1;
  166. }
  167. static int uart_getc(struct rt_serial_device *serial)
  168. {
  169. struct hw_uart_device *uart;
  170. RT_ASSERT(serial != RT_NULL);
  171. uart = (struct hw_uart_device *)serial->parent.user_data;
  172. int timeout = 100000;
  173. while (!(inb(uart->line_status_reg) & LINE_STATUS_DATA_READY) && timeout--)
  174. {
  175. }
  176. int data = -1;
  177. if (timeout > 0)
  178. {
  179. data = inb(uart->data_reg);
  180. }
  181. return data;
  182. }
  183. static const struct rt_uart_ops _uart_ops =
  184. {
  185. uart_configure,
  186. uart_control,
  187. uart_putc,
  188. uart_getc,
  189. };
  190. #ifdef RT_USING_UART0
  191. /* UART device driver structure */
  192. static struct hw_uart_device _uart0_device =
  193. {
  194. SERIAL0_BASE,
  195. SERIAL0_IRQ,
  196. };
  197. static struct rt_serial_device _serial0;
  198. #endif /* RT_USING_UART0 */
  199. #ifdef RT_USING_UART1
  200. /* UART1 device driver structure */
  201. static struct hw_uart_device _uart1_device =
  202. {
  203. SERIAL1_BASE,
  204. SERIAL1_IRQ,
  205. };
  206. static struct rt_serial_device _serial1;
  207. #endif /* RT_USING_UART1 */
  208. #if defined(RT_USING_UART0) || defined(RT_USING_UART1)
  209. static void do_uart_init(char *name, struct hw_uart_device *uart, struct rt_serial_device *serial)
  210. {
  211. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  212. rt_uint32_t iobase = uart->hw_base;
  213. uart->data_reg = iobase + 0;
  214. uart->divisor_low_reg = iobase + 0;
  215. uart->intr_enable_reg = iobase + 1;
  216. uart->divisor_high_reg = iobase + 1;
  217. uart->intr_indenty_reg = iobase + 2;
  218. uart->line_ctrl_reg = iobase + 3;
  219. uart->modem_ctrl_reg = iobase + 4;
  220. uart->line_status_reg = iobase + 5;
  221. uart->modem_status_reg = iobase + 6;
  222. uart->scratch_reg = iobase + 7;
  223. /* Setting can change the baud rate Baud */
  224. outb(uart->line_ctrl_reg, LINE_DLAB);
  225. /* Set Baud rate */
  226. outb(uart->divisor_low_reg, (MAX_BAUD_VALUE / config.baud_rate) & 0xff);
  227. outb(uart->divisor_high_reg, ((MAX_BAUD_VALUE / config.baud_rate) >> 8) & 0xff);
  228. /* Set DLAB to 0, set the character width to 8, stop bit to 1, no parity, break signal Disabled */
  229. outb(uart->line_ctrl_reg, LINE_WORD_LENGTH_8 |
  230. LINE_STOP_BIT_1 | LINE_PARITY_NO);
  231. /* enable recv intr */
  232. outb(uart->intr_enable_reg, INTR_RECV_DATA_AVALIABLE |
  233. INTR_STATUS_CHANGED | INTR_LOW_POWER_MODE);
  234. /*
  235. * Set FIFO, open FIFO, clear receive FIFO, clear transmit FIFO Open 64Byte FIFO,
  236. * interrupt trigger level is 14Byte
  237. */
  238. outb(uart->fifo_reg, FIFO_ENABLE | FIFO_CLEAR_TRANSMIT |
  239. FIFO_CLEAR_RECEIVE | FIFO_ENABLE_64 |
  240. FIFO_TRIGGER_14);
  241. /* IRQs enabled, RTS/DSR set */
  242. outb(uart->modem_ctrl_reg, MCR_DTR | MCR_RTS | MCR_OUT2);
  243. outb(uart->scratch_reg, 0x00);
  244. serial->ops = &_uart_ops;
  245. serial->config = config;
  246. /* register device */
  247. rt_hw_serial_register(serial, name,
  248. RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
  249. uart);
  250. rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, name);
  251. rt_hw_interrupt_umask(uart->irqno);
  252. }
  253. #endif
  254. int rt_hw_uart_init(void)
  255. {
  256. #ifdef RT_USING_UART0
  257. do_uart_init("uart0", &_uart0_device, &_serial0);
  258. #endif /* RT_USING_UART0 */
  259. #ifdef RT_USING_UART1
  260. do_uart_init("uart1", &_uart1_device, &_serial1);
  261. #endif /* RT_USING_UART1 */
  262. return 0;
  263. }
  264. #endif /* BSP_DRV_UART */