core.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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. 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. break;
  71. }
  72. if (!serial->size)
  73. {
  74. serial->size = 0x1000;
  75. }
  76. }
  77. return ret;
  78. }
  79. static void serial8250_isr(int irqno, void *param)
  80. {
  81. struct serial8250 *serial = (struct serial8250 *)param;
  82. if (serial->handle_irq)
  83. {
  84. serial->handle_irq(serial, irqno);
  85. }
  86. else
  87. {
  88. rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND);
  89. }
  90. }
  91. static rt_err_t serial8250_dma_enable_dummy(struct serial8250 *serial, rt_bool_t enabled)
  92. {
  93. return RT_EOK;
  94. }
  95. static rt_ssize_t serial8250_dma_tx_dummy(struct serial8250 *serial,
  96. const rt_uint8_t *buf, rt_size_t size)
  97. {
  98. return 0;
  99. }
  100. static rt_ssize_t serial8250_dma_rx_dummy(struct serial8250 *serial,
  101. rt_uint8_t *buf, rt_size_t size)
  102. {
  103. return 0;
  104. }
  105. rt_err_t serial8250_setup(struct serial8250 *serial)
  106. {
  107. rt_uint32_t flags;
  108. rt_err_t err = RT_EOK;
  109. const char *uart_name;
  110. char dev_name[RT_NAME_MAX];
  111. if (serial)
  112. {
  113. struct rt_device *dev = &serial->parent.parent;
  114. rt_spin_lock_init(&serial->spinlock);
  115. flags = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
  116. if (!serial->regshift)
  117. {
  118. rt_dm_dev_prop_read_u32(dev, "reg-shift", &serial->regshift);
  119. }
  120. if (serial->iotype == PORT_UNKNOWN)
  121. {
  122. rt_uint32_t width = sizeof(rt_uint32_t);
  123. rt_dm_dev_prop_read_u32(dev, "reg-io-width", &width);
  124. switch (width)
  125. {
  126. case sizeof(rt_uint8_t):
  127. serial->iotype = PORT_MMIO;
  128. break;
  129. case sizeof(rt_uint16_t):
  130. serial->iotype = PORT_MMIO16;
  131. break;
  132. case sizeof(rt_uint32_t):
  133. default:
  134. serial->iotype = rt_dm_dev_is_big_endian(dev) ? PORT_MMIO32BE : PORT_MMIO32;
  135. break;
  136. }
  137. }
  138. serial->serial_in = serial->serial_in ? : &serial8250_in;
  139. serial->serial_out = serial->serial_out ? : &serial8250_out;
  140. serial->serial_dma_enable = serial->serial_dma_enable ? : &serial8250_dma_enable_dummy;
  141. if (serial->serial_dma_tx)
  142. {
  143. flags |= RT_DEVICE_FLAG_DMA_TX;
  144. }
  145. else
  146. {
  147. serial->serial_dma_tx = &serial8250_dma_tx_dummy;
  148. }
  149. if (serial->serial_dma_rx)
  150. {
  151. flags |= RT_DEVICE_FLAG_DMA_RX;
  152. }
  153. else
  154. {
  155. serial->serial_dma_rx = &serial8250_dma_rx_dummy;
  156. }
  157. serial_dev_set_name(&serial->parent);
  158. uart_name = rt_dm_dev_get_name(&serial->parent.parent);
  159. rt_hw_serial_register(&serial->parent, uart_name, flags, serial->data);
  160. rt_snprintf(dev_name, sizeof(dev_name), "%s-8250", uart_name);
  161. rt_hw_interrupt_install(serial->irq, serial8250_isr, serial, dev_name);
  162. }
  163. else
  164. {
  165. err = -RT_EINVAL;
  166. }
  167. return err;
  168. }
  169. rt_err_t serial8250_remove(struct serial8250 *serial)
  170. {
  171. rt_err_t err;
  172. rt_iounmap((void *)serial->base);
  173. serial->base = RT_NULL;
  174. rt_hw_interrupt_mask(serial->irq);
  175. rt_pic_detach_irq(serial->irq, serial);
  176. err = rt_device_unregister(&serial->parent.parent);
  177. if (!err && serial->remove)
  178. {
  179. serial->remove(serial);
  180. }
  181. return err;
  182. }
  183. rt_uint32_t serial8250_in(struct serial8250 *serial, int offset)
  184. {
  185. rt_uint32_t ret = 0;
  186. offset <<= serial->regshift;
  187. switch (serial->iotype)
  188. {
  189. case PORT_MMIO:
  190. ret = HWREG8(serial->base + offset);
  191. break;
  192. case PORT_MMIO16:
  193. ret = HWREG16(serial->base + offset);
  194. break;
  195. case PORT_MMIO32:
  196. ret = HWREG32(serial->base + offset);
  197. break;
  198. case PORT_MMIO32BE:
  199. ret = rt_cpu_to_be32(HWREG32(serial->base + offset));
  200. break;
  201. #ifdef ARCH_SUPPORT_PIO
  202. case PORT_IO:
  203. ret = inb(serial->base + offset);
  204. break;
  205. #endif
  206. default:
  207. break;
  208. }
  209. return ret;
  210. }
  211. void serial8250_out(struct serial8250 *serial, int offset, int value)
  212. {
  213. offset <<= serial->regshift;
  214. switch (serial->iotype)
  215. {
  216. case PORT_MMIO:
  217. HWREG8(serial->base + offset) = value;
  218. break;
  219. case PORT_MMIO16:
  220. HWREG16(serial->base + offset) = value;
  221. break;
  222. case PORT_MMIO32:
  223. HWREG32(serial->base + offset) = value;
  224. break;
  225. case PORT_MMIO32BE:
  226. HWREG32(serial->base + offset) = rt_cpu_to_be32(value);
  227. break;
  228. #ifdef ARCH_SUPPORT_PIO
  229. case PORT_IO:
  230. outb(serial->base + offset, value);
  231. break;
  232. #endif
  233. default:
  234. break;
  235. }
  236. }
  237. void serial8250_dma_tx_done(struct serial8250 *serial)
  238. {
  239. rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_TX_DMADONE);
  240. }
  241. void serial8250_dma_rx_done(struct serial8250 *serial, int recv_len)
  242. {
  243. rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
  244. }
  245. rt_inline rt_ubase_t baudrate_to_divisor(rt_ubase_t freq, rt_ubase_t baudrate)
  246. {
  247. return (freq + baudrate * 8) / (16 * baudrate);
  248. }
  249. static void serial8250_hw_ios(struct serial8250 *serial, struct serial_configure *cfg)
  250. {
  251. rt_uint32_t ier;
  252. /* Disable RX interrupt */
  253. ier = serial->serial_in(serial, UART_IER);
  254. ier &= ~UART_IER_RDI;
  255. ier |= UART_IER_UUE;
  256. serial->serial_out(serial, UART_IER, ier);
  257. /* Enable FIFO, Clear FIFO */
  258. serial->serial_out(serial, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
  259. /* DTR + RTS */
  260. serial->serial_out(serial, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
  261. if (serial->freq)
  262. {
  263. rt_uint32_t wlen = cfg->data_bits - DATA_BITS_5 + UART_LCR_WLEN5;
  264. rt_uint32_t divisor = baudrate_to_divisor(serial->freq, cfg->baud_rate);
  265. /* Enable access DLL & DLH */
  266. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) | UART_LCR_DLAB);
  267. serial->serial_out(serial, UART_DLL, (divisor & 0xff));
  268. serial->serial_out(serial, UART_DLM, (divisor >> 8) & 0xff);
  269. /* Clear DLAB bit */
  270. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_DLAB));
  271. serial->serial_out(serial, UART_LCR, (serial->serial_in(serial, UART_LCR) & (~wlen)) | wlen);
  272. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_STOP));
  273. serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_PARITY));
  274. }
  275. /* Enable RX interrupt */
  276. ier |= UART_IER_RDI;
  277. serial->serial_out(serial, UART_IER, ier);
  278. }
  279. rt_err_t serial8250_ios(struct serial8250 *serial, struct serial_configure *cfg)
  280. {
  281. rt_err_t err = RT_EOK;
  282. rt_uint32_t count = 10000;
  283. rt_uint32_t divisor = baudrate_to_divisor(serial->freq, cfg->baud_rate);
  284. /* Flush FIFO */
  285. while (!(serial->serial_in(serial, UART_LSR) & UART_LSR_TEMT) && count--)
  286. {
  287. rt_hw_cpu_relax();
  288. }
  289. /* Need to increase CLK frequency */
  290. if (divisor == 0 && serial->freq)
  291. {
  292. if (serial->clk)
  293. {
  294. for (rt_ubase_t round = serial->freq, freq = 0; ; round += round)
  295. {
  296. if (baudrate_to_divisor(round, cfg->baud_rate))
  297. {
  298. freq = rt_clk_round_rate(serial->clk, freq);
  299. if (freq < 0)
  300. {
  301. continue;
  302. }
  303. rt_clk_disable_unprepare(serial->clk);
  304. err = rt_clk_set_rate(serial->clk, freq);
  305. if (!err)
  306. {
  307. serial->freq = rt_clk_get_rate(serial->clk);
  308. }
  309. rt_clk_prepare_enable(serial->clk);
  310. break;
  311. }
  312. }
  313. }
  314. else
  315. {
  316. err = -RT_ENOSYS;
  317. }
  318. }
  319. if (!err)
  320. {
  321. serial8250_hw_ios(serial, cfg);
  322. }
  323. return err;
  324. }
  325. rt_err_t serial8250_uart_configure(struct rt_serial_device *raw_serial, struct serial_configure *cfg)
  326. {
  327. rt_err_t err;
  328. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  329. if (serial->serial_ios)
  330. {
  331. err = serial->serial_ios(serial, cfg);
  332. }
  333. else
  334. {
  335. err = serial8250_ios(serial, cfg);
  336. }
  337. return err;
  338. }
  339. rt_err_t serial8250_uart_control(struct rt_serial_device *raw_serial, int cmd, void *arg)
  340. {
  341. rt_uint32_t value;
  342. rt_err_t err = RT_EOK;
  343. rt_ubase_t ctrl = (rt_ubase_t)arg;
  344. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  345. switch (cmd)
  346. {
  347. case RT_DEVICE_CTRL_CLR_INT:
  348. if (ctrl == RT_DEVICE_FLAG_INT_RX)
  349. {
  350. /* Disable RX irq */
  351. value = serial->serial_in(serial, UART_IER);
  352. value &= ~UART_IER_RDI;
  353. value |= UART_IER_UUE;
  354. serial->serial_out(serial, UART_IER, value);
  355. rt_hw_interrupt_mask(serial->irq);
  356. }
  357. else if (ctrl == RT_DEVICE_FLAG_DMA_RX)
  358. {
  359. err = serial->serial_dma_enable(serial, RT_FALSE);
  360. }
  361. break;
  362. case RT_DEVICE_CTRL_SET_INT:
  363. if (ctrl == RT_DEVICE_FLAG_INT_RX)
  364. {
  365. /* Enable RX irq */
  366. value = serial->serial_in(serial, UART_IER);
  367. serial->serial_out(serial, UART_IER, value | UART_IER_RDI);
  368. rt_hw_interrupt_umask(serial->irq);
  369. }
  370. else if (ctrl == RT_DEVICE_FLAG_DMA_RX)
  371. {
  372. err = serial->serial_dma_enable(serial, RT_TRUE);
  373. }
  374. break;
  375. case RT_DEVICE_CTRL_CLOSE:
  376. err = serial->serial_dma_enable(serial, RT_FALSE);
  377. break;
  378. default:
  379. err = -RT_EINVAL;
  380. break;
  381. }
  382. return err;
  383. }
  384. int serial8250_uart_putc(struct rt_serial_device *raw_serial, char c)
  385. {
  386. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  387. while (!(serial->serial_in(serial, UART_LSR) & UART_LSR_THRE))
  388. {
  389. rt_hw_cpu_relax();
  390. }
  391. serial->serial_out(serial, UART_TX, c);
  392. return 1;
  393. }
  394. int serial8250_uart_getc(struct rt_serial_device *raw_serial)
  395. {
  396. int ch = -1;
  397. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  398. if ((serial->serial_in(serial, UART_LSR) & UART_LSR_DR))
  399. {
  400. ch = serial->serial_in(serial, UART_RX) & 0xff;
  401. }
  402. return ch;
  403. }
  404. rt_ssize_t serial8250_uart_dma_transmit(struct rt_serial_device *raw_serial,
  405. rt_uint8_t *buf, rt_size_t size, int direction)
  406. {
  407. rt_ssize_t res = 0;
  408. struct serial8250 *serial = raw_to_serial8250(raw_serial);
  409. if (direction == RT_SERIAL_DMA_TX)
  410. {
  411. res = serial->serial_dma_tx(serial, (const rt_uint8_t *)buf, size);
  412. }
  413. else if (direction == RT_SERIAL_DMA_RX)
  414. {
  415. res = serial->serial_dma_rx(serial, buf, size);
  416. }
  417. return res;
  418. }
  419. const struct rt_uart_ops serial8250_uart_ops =
  420. {
  421. .configure = serial8250_uart_configure,
  422. .control = serial8250_uart_control,
  423. .putc = serial8250_uart_putc,
  424. .getc = serial8250_uart_getc,
  425. .dma_transmit = serial8250_uart_dma_transmit,
  426. };