core.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Copyright (c) 2006-2024 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. rt_err_t serial8250_config(struct serial8250 *serial, const char *options)
  12. {
  13. rt_err_t ret = -RT_EINVAL;
  14. if (serial)
  15. {
  16. char *arg;
  17. rt_bool_t has_iotype = RT_FALSE;
  18. /*
  19. * uart8250,io,<addr>[,options]
  20. * uart8250,mmio,<addr>[,options]
  21. * uart8250,mmio16,<addr>[,options]
  22. * uart8250,mmio32,<addr>[,options]
  23. * uart8250,mmio32be,<addr>[,options]
  24. * uart8250,0x<addr>[,options]
  25. */
  26. serial_for_each_args(arg, options)
  27. {
  28. if (!rt_strcmp(arg, "uart8250"))
  29. {
  30. ret = RT_EOK;
  31. continue;
  32. }
  33. /* user call error */
  34. if (ret)
  35. {
  36. break;
  37. }
  38. if (!rt_strncmp(arg, "0x", 2))
  39. {
  40. serial->base = serial_base_from_args(arg);
  41. continue;
  42. }
  43. if (!has_iotype)
  44. {
  45. const struct
  46. {
  47. char *param;
  48. int type;
  49. } iotype_table[] =
  50. {
  51. { "io", PORT_IO },
  52. { "mmio", PORT_MMIO },
  53. { "mmio16", PORT_MMIO16 },
  54. { "mmio32", PORT_MMIO32 },
  55. { "mmio32be", PORT_MMIO32BE },
  56. };
  57. serial->iotype = PORT_MMIO32;
  58. for (int i = 0; i < RT_ARRAY_SIZE(iotype_table); ++i)
  59. {
  60. if (!rt_strcmp(arg, iotype_table[i].param))
  61. {
  62. serial->iotype = iotype_table[i].type;
  63. break;
  64. }
  65. }
  66. has_iotype = RT_TRUE;
  67. continue;
  68. }
  69. serial->parent.config = serial_cfg_from_args(arg);
  70. }
  71. if (!serial->size)
  72. {
  73. serial->size = 0x1000;
  74. }
  75. }
  76. return ret;
  77. }
  78. static void serial8250_isr(int irqno, void *param)
  79. {
  80. struct serial8250 *serial = (struct serial8250 *)param;
  81. if (serial->handle_irq)
  82. {
  83. serial->handle_irq(serial, irqno);
  84. }
  85. else
  86. {
  87. rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND);
  88. }
  89. }
  90. rt_err_t serial8250_setup(struct serial8250 *serial)
  91. {
  92. rt_err_t ret = RT_EOK;
  93. const char *uart_name;
  94. char dev_name[RT_NAME_MAX];
  95. if (serial)
  96. {
  97. rt_spin_lock_init(&serial->spinlock);
  98. serial->serial_in = serial->serial_in ? : &serial8250_in;
  99. serial->serial_out = serial->serial_out ? : &serial8250_out;
  100. serial_dev_set_name(&serial->parent);
  101. uart_name = rt_dm_dev_get_name(&serial->parent.parent);
  102. rt_hw_serial_register(&serial->parent, uart_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, serial->data);
  103. rt_snprintf(dev_name, sizeof(dev_name), "%s-8250", uart_name);
  104. rt_pic_attach_irq(serial->irq, serial8250_isr, serial, dev_name, RT_IRQ_F_NONE);
  105. }
  106. else
  107. {
  108. ret = -RT_EINVAL;
  109. }
  110. return ret;
  111. }
  112. rt_err_t serial8250_remove(struct serial8250 *serial)
  113. {
  114. rt_err_t err;
  115. rt_iounmap((void *)serial->base);
  116. serial->base = RT_NULL;
  117. rt_pic_irq_mask(serial->irq);
  118. rt_pic_detach_irq(serial->irq, serial);
  119. err = rt_device_unregister(&serial->parent.parent);
  120. if (!err && serial->remove)
  121. {
  122. serial->remove(serial);
  123. }
  124. return err;
  125. }
  126. rt_uint32_t serial8250_in(struct serial8250 *serial, int offset)
  127. {
  128. rt_uint32_t ret = 0;
  129. offset <<= serial->regshift;
  130. switch (serial->iotype)
  131. {
  132. case PORT_MMIO:
  133. ret = HWREG8(serial->base + offset);
  134. break;
  135. case PORT_MMIO16:
  136. ret = HWREG16(serial->base + offset);
  137. break;
  138. case PORT_MMIO32:
  139. ret = HWREG32(serial->base + offset);
  140. break;
  141. case PORT_MMIO32BE:
  142. ret = rt_cpu_to_be32(HWREG32(serial->base + offset));
  143. break;
  144. #ifdef ARCH_SUPPORT_PIO
  145. case PORT_IO:
  146. ret = inb(serial->base + offset, value);
  147. break;
  148. #endif
  149. default:
  150. break;
  151. }
  152. return ret;
  153. }
  154. void serial8250_out(struct serial8250 *serial, int offset, int value)
  155. {
  156. offset <<= serial->regshift;
  157. switch (serial->iotype)
  158. {
  159. case PORT_MMIO:
  160. HWREG8(serial->base + offset) = value;
  161. break;
  162. case PORT_MMIO16:
  163. HWREG16(serial->base + offset) = value;
  164. break;
  165. case PORT_MMIO32:
  166. HWREG32(serial->base + offset) = value;
  167. break;
  168. case PORT_MMIO32BE:
  169. HWREG32(serial->base + offset) = rt_cpu_to_be32(value);
  170. break;
  171. #ifdef ARCH_SUPPORT_PIO
  172. case PORT_IO:
  173. outb(serial->base + offset, value);
  174. break;
  175. #endif
  176. default:
  177. break;
  178. }
  179. }
  180. rt_err_t serial8250_uart_configure(struct rt_serial_device *raw_serial, struct serial_configure *cfg)
  181. {
  182. rt_err_t err = RT_EOK;
  183. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  184. /* Disable interrupt */
  185. serial->serial_out(serial, UART_IER, !UART_IER_RDI);
  186. /* Enable FIFO, Clear FIFO*/
  187. serial->serial_out(serial, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
  188. /* DTR + RTS */
  189. serial->serial_out(serial, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
  190. if (serial->freq)
  191. {
  192. rt_uint32_t wlen = cfg->data_bits - DATA_BITS_5 + UART_LCR_WLEN5;
  193. rt_uint32_t divisor = serial->freq / 16 / cfg->baud_rate;
  194. /* Enable access DLL & DLH */
  195. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) | UART_LCR_DLAB);
  196. serial->serial_out(serial, UART_DLL, (divisor & 0xff));
  197. serial->serial_out(serial, UART_DLM, (divisor >> 8) & 0xff);
  198. /* Clear DLAB bit */
  199. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_DLAB));
  200. serial->serial_out(serial, UART_LCR, (serial->serial_in(serial, UART_LCR) & (~wlen)) | wlen);
  201. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_STOP));
  202. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_PARITY));
  203. }
  204. serial->serial_out(serial, UART_IER, UART_IER_RDI);
  205. return err;
  206. }
  207. rt_err_t serial8250_uart_control(struct rt_serial_device *raw_serial, int cmd, void *arg)
  208. {
  209. rt_err_t err = RT_EOK;
  210. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  211. switch (cmd)
  212. {
  213. case RT_DEVICE_CTRL_CLR_INT:
  214. /* disable rx irq */
  215. serial->serial_out(serial, UART_IER, !UART_IER_RDI);
  216. rt_pic_irq_mask(serial->irq);
  217. break;
  218. case RT_DEVICE_CTRL_SET_INT:
  219. /* enable rx irq */
  220. serial->serial_out(serial, UART_IER, UART_IER_RDI);
  221. rt_pic_irq_unmask(serial->irq);
  222. break;
  223. }
  224. return err;
  225. }
  226. int serial8250_uart_putc(struct rt_serial_device *raw_serial, char c)
  227. {
  228. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  229. while (!(serial->serial_in(serial, UART_LSR) & 0x20))
  230. {
  231. rt_hw_cpu_relax();
  232. }
  233. serial->serial_out(serial, UART_TX, c);
  234. return 1;
  235. }
  236. int serial8250_uart_getc(struct rt_serial_device *raw_serial)
  237. {
  238. int ch = -1;
  239. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  240. if ((serial->serial_in(serial, UART_LSR) & 0x1))
  241. {
  242. ch = serial->serial_in(serial, UART_RX) & 0xff;
  243. }
  244. return ch;
  245. }
  246. const struct rt_uart_ops serial8250_uart_ops =
  247. {
  248. .configure = serial8250_uart_configure,
  249. .control = serial8250_uart_control,
  250. .putc = serial8250_uart_putc,
  251. .getc = serial8250_uart_getc,
  252. };