drv_uart.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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. * 2018-05-05 Bernard The first version
  9. * 2022-08-24 GuEe-GUI add OFW support
  10. */
  11. #include <rthw.h>
  12. #include <rtthread.h>
  13. #include <rtdevice.h>
  14. #include <cpuport.h>
  15. #include <ioremap.h>
  16. #include <drivers/serial_dm.h>
  17. #define PL011_OEIM RT_BIT(10) /* overrun error interrupt mask */
  18. #define PL011_BEIM RT_BIT(9) /* break error interrupt mask */
  19. #define PL011_PEIM RT_BIT(8) /* parity error interrupt mask */
  20. #define PL011_FEIM RT_BIT(7) /* framing error interrupt mask */
  21. #define PL011_RTIM RT_BIT(6) /* receive timeout interrupt mask */
  22. #define PL011_TXIM RT_BIT(5) /* transmit interrupt mask */
  23. #define PL011_RXIM RT_BIT(4) /* receive interrupt mask */
  24. #define PL011_DSRMIM RT_BIT(3) /* DSR interrupt mask */
  25. #define PL011_DCDMIM RT_BIT(2) /* DCD interrupt mask */
  26. #define PL011_CTSMIM RT_BIT(1) /* CTS interrupt mask */
  27. #define PL011_RIMIM RT_BIT(0) /* RI interrupt mask */
  28. #define PL011_DR 0x000
  29. #define PL011_FR 0x018
  30. #define PL011_IBRD 0x024
  31. #define PL011_FBRD 0x028
  32. #define PL011_LCR 0x02c
  33. #define PL011_CR 0x030
  34. #define PL011_IMSC 0x038
  35. #define PL011_RIS 0x03c
  36. #define PL011_DMACR 0x048
  37. #define PL011_LCRH_SPS (1 << 7)
  38. #define PL011_LCRH_WLEN_8 (3 << 5)
  39. #define PL011_LCRH_WLEN_7 (2 << 5)
  40. #define PL011_LCRH_WLEN_6 (1 << 5)
  41. #define PL011_LCRH_WLEN_5 (0 << 5)
  42. #define PL011_LCRH_FEN (1 << 4)
  43. #define PL011_LCRH_STP2 (1 << 3)
  44. #define PL011_LCRH_EPS (1 << 2)
  45. #define PL011_LCRH_PEN (1 << 1)
  46. #define PL011_LCRH_BRK (1 << 0)
  47. #define PL011_LCRH_WLEN(n) ((n - 5) << 5)
  48. #define PL011_CR_CTSEN RT_BIT(15)
  49. #define PL011_CR_RTSEN RT_BIT(14)
  50. #define PL011_CR_RTS RT_BIT(11)
  51. #define PL011_CR_DTR RT_BIT(10)
  52. #define PL011_CR_RXE RT_BIT(9)
  53. #define PL011_CR_TXE RT_BIT(8)
  54. #define PL011_CR_LBE RT_BIT(7)
  55. #define PL011_CR_SIRLP RT_BIT(2)
  56. #define PL011_CR_SIREN RT_BIT(1)
  57. #define PL011_CR_UARTEN RT_BIT(0)
  58. struct pl011
  59. {
  60. struct rt_serial_device parent;
  61. int irq;
  62. void *base;
  63. rt_ubase_t freq;
  64. struct rt_clk *clk;
  65. struct rt_clk *pclk;
  66. struct rt_spinlock spinlock;
  67. };
  68. #define raw_to_pl011(raw) rt_container_of(raw, struct pl011, parent)
  69. rt_inline rt_uint32_t pl011_read(struct pl011 *pl011, int offset)
  70. {
  71. return HWREG32(pl011->base + offset);
  72. }
  73. rt_inline void pl011_write(struct pl011 *pl011, int offset, rt_uint32_t value)
  74. {
  75. HWREG32(pl011->base + offset) = value;
  76. }
  77. static void pl011_isr(int irqno, void *param)
  78. {
  79. struct pl011 *pl011 = param;
  80. /* Check irq */
  81. if (pl011_read(pl011, PL011_RIS) & PL011_RXIM)
  82. {
  83. rt_base_t level = rt_spin_lock_irqsave(&pl011->spinlock);
  84. rt_hw_serial_isr(&pl011->parent, RT_SERIAL_EVENT_RX_IND);
  85. rt_spin_unlock_irqrestore(&pl011->spinlock, level);
  86. }
  87. }
  88. static rt_err_t pl011_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  89. {
  90. rt_ubase_t quot;
  91. struct pl011 *pl011 = raw_to_pl011(serial);
  92. /* Clear UART setting */
  93. pl011_write(pl011, PL011_CR, 0);
  94. /* Disable FIFO */
  95. pl011_write(pl011, PL011_LCR, 0);
  96. if (cfg->baud_rate > pl011->freq / 16)
  97. {
  98. quot = RT_DIV_ROUND_CLOSEST(pl011->freq * 8, cfg->baud_rate);
  99. }
  100. else
  101. {
  102. quot = RT_DIV_ROUND_CLOSEST(pl011->freq * 4, cfg->baud_rate);
  103. }
  104. pl011_write(pl011, PL011_IBRD, quot >> 6);
  105. pl011_write(pl011, PL011_FBRD, quot & 0x3f);
  106. /* FIFO */
  107. pl011_write(pl011, PL011_LCR, PL011_LCRH_WLEN(cfg->data_bits));
  108. /* Art enable, TX/RX enable */
  109. pl011_write(pl011, PL011_CR, PL011_CR_UARTEN | PL011_CR_TXE | PL011_CR_RXE);
  110. return RT_EOK;
  111. }
  112. static rt_err_t pl011_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
  113. {
  114. struct pl011 *pl011 = raw_to_pl011(serial);
  115. switch (cmd)
  116. {
  117. case RT_DEVICE_CTRL_CLR_INT:
  118. /* Disable rx irq */
  119. pl011_write(pl011, PL011_IMSC, pl011_read(pl011, PL011_IMSC) & ~PL011_RXIM);
  120. rt_hw_interrupt_mask(pl011->irq);
  121. break;
  122. case RT_DEVICE_CTRL_SET_INT:
  123. /* Enable rx irq */
  124. pl011_write(pl011, PL011_IMSC, pl011_read(pl011, PL011_IMSC) | PL011_RXIM);
  125. rt_hw_interrupt_umask(pl011->irq);
  126. break;
  127. }
  128. return RT_EOK;
  129. }
  130. static int pl011_uart_putc(struct rt_serial_device *serial, char c)
  131. {
  132. struct pl011 *pl011 = raw_to_pl011(serial);
  133. while (pl011_read(pl011, PL011_FR) & PL011_TXIM)
  134. {
  135. rt_hw_cpu_relax();
  136. }
  137. pl011_write(pl011, PL011_DR, c);
  138. return 1;
  139. }
  140. static int pl011_uart_getc(struct rt_serial_device *serial)
  141. {
  142. int ch = -1;
  143. struct pl011 *pl011 = raw_to_pl011(serial);
  144. if (!(pl011_read(pl011, PL011_FR) & PL011_RXIM))
  145. {
  146. ch = pl011_read(pl011, PL011_DR);
  147. }
  148. return ch;
  149. }
  150. static const struct rt_uart_ops pl011_uart_ops =
  151. {
  152. .configure = pl011_uart_configure,
  153. .control = pl011_uart_control,
  154. .putc = pl011_uart_putc,
  155. .getc = pl011_uart_getc,
  156. };
  157. static void pl011_early_kick(struct rt_fdt_earlycon *con, int why)
  158. {
  159. struct pl011 *pl011 = raw_to_pl011(con->data);
  160. switch (why)
  161. {
  162. case FDT_EARLYCON_KICK_UPDATE:
  163. pl011->base = rt_ioremap((void *)con->mmio, con->size);
  164. break;
  165. case FDT_EARLYCON_KICK_COMPLETED:
  166. rt_iounmap(pl011->base);
  167. break;
  168. default:
  169. break;
  170. }
  171. }
  172. static rt_err_t pl011_early_setup(struct rt_fdt_earlycon *con, const char *options)
  173. {
  174. rt_err_t err = RT_EOK;
  175. static struct pl011 pl011 = { };
  176. if (options && !con->mmio)
  177. {
  178. char *arg;
  179. con->mmio = RT_NULL;
  180. /*
  181. * The pl011 serial port must already be setup and configured in early.
  182. * Options are not yet supported.
  183. * pl011,<addr>
  184. * pl011,mmio32,<addr>
  185. */
  186. serial_for_each_args(arg, options)
  187. {
  188. if (!rt_strcmp(arg, "pl011") || !rt_strcmp(arg, "mmio32"))
  189. {
  190. continue;
  191. }
  192. if (!con->mmio)
  193. {
  194. con->mmio = (rt_ubase_t)serial_base_from_args(arg);
  195. break;
  196. }
  197. }
  198. }
  199. if (!con->size)
  200. {
  201. con->size = 0x1000;
  202. }
  203. if (con->mmio)
  204. {
  205. pl011.base = rt_ioremap_early((void *)con->mmio, con->size);
  206. }
  207. if (pl011.base)
  208. {
  209. con->console_putc = (typeof(con->console_putc))&pl011_uart_putc;
  210. con->console_kick = pl011_early_kick;
  211. con->data = &pl011.parent;
  212. pl011.parent.config = (typeof(pl011.parent.config))RT_SERIAL_CONFIG_DEFAULT;
  213. }
  214. else
  215. {
  216. err = -RT_ERROR;
  217. }
  218. return err;
  219. }
  220. RT_FDT_EARLYCON_EXPORT(pl011, "pl011", "arm,pl011", pl011_early_setup);
  221. static void pl011_free(struct pl011 *pl011)
  222. {
  223. if (pl011->base)
  224. {
  225. rt_iounmap(pl011->base);
  226. }
  227. /* if (!rt_is_err_or_null(pl011->clk))*/
  228. /* {*/
  229. /* rt_clk_disable(pl011->clk);*/
  230. /* rt_clk_put(pl011->clk);*/
  231. /* }*/
  232. /* if (!rt_is_err_or_null(pl011->pclk))*/
  233. /* {*/
  234. /* rt_clk_disable_unprepare(pl011->pclk);*/
  235. /* rt_clk_put(pl011->pclk);*/
  236. /* }*/
  237. rt_free(pl011);
  238. }
  239. static rt_err_t pl011_probe(struct rt_platform_device *pdev)
  240. {
  241. rt_err_t err;
  242. const char *name;
  243. char isr_name[RT_NAME_MAX];
  244. struct rt_device *dev = &pdev->parent;
  245. struct pl011 *pl011 = rt_calloc(1, sizeof(*pl011));
  246. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  247. if (!pl011)
  248. {
  249. return -RT_ENOMEM;
  250. }
  251. pl011->base = rt_dm_dev_iomap(dev, 0);
  252. if (!pl011->base)
  253. {
  254. err = -RT_EIO;
  255. goto _fail;
  256. }
  257. pl011->irq = rt_dm_dev_get_irq(dev, 0);
  258. if (pl011->irq < 0)
  259. {
  260. err = pl011->irq;
  261. goto _fail;
  262. }
  263. /* pl011->clk = rt_clk_get_by_index(dev, 0);*/
  264. /* if (rt_is_err(pl011->clk))*/
  265. /* {*/
  266. /* err = rt_ptr_err(pl011->clk);*/
  267. /* goto _fail;*/
  268. /* }*/
  269. /* pl011->pclk = rt_clk_get_by_name(dev, "apb_pclk");*/
  270. /* if (rt_is_err(pl011->pclk))*/
  271. /* {*/
  272. /* err = rt_ptr_err(pl011->pclk);*/
  273. /* goto _fail;*/
  274. /* }*/
  275. /* if ((err = rt_clk_prepare_enable(pl011->pclk)))*/
  276. /* {*/
  277. /* goto _fail;*/
  278. /* }*/
  279. rt_dm_dev_bind_fwdata(&pl011->parent.parent, dev->ofw_node, &pl011->parent);
  280. /* rt_clk_enable(pl011->clk);*/
  281. /* pl011->freq = rt_clk_get_rate(pl011->clk);*/
  282. dev->user_data = pl011;
  283. pl011->parent.ops = &pl011_uart_ops;
  284. pl011->parent.config = config;
  285. rt_spin_lock_init(&pl011->spinlock);
  286. serial_dev_set_name(&pl011->parent);
  287. name = rt_dm_dev_get_name(&pl011->parent.parent);
  288. rt_hw_serial_register(&pl011->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, pl011);
  289. rt_snprintf(isr_name, RT_NAME_MAX, "%s-pl011", name);
  290. rt_hw_interrupt_install(pl011->irq, pl011_isr, pl011, isr_name);
  291. return RT_EOK;
  292. _fail:
  293. pl011_free(pl011);
  294. return err;
  295. }
  296. static rt_err_t pl011_remove(struct rt_platform_device *pdev)
  297. {
  298. struct rt_device *dev = &pdev->parent;
  299. struct pl011 *pl011 = dev->user_data;
  300. rt_dm_dev_unbind_fwdata(dev, RT_NULL);
  301. rt_hw_interrupt_mask(pl011->irq);
  302. rt_pic_detach_irq(pl011->irq, pl011);
  303. rt_device_unregister(&pl011->parent.parent);
  304. pl011_free(pl011);
  305. return RT_EOK;
  306. }
  307. static const struct rt_ofw_node_id pl011_ofw_ids[] =
  308. {
  309. { .type = "ttyAMA", .compatible = "arm,pl011" },
  310. { .type = "ttyAMA", .compatible = "arm,pl011-axi" },
  311. { /* sentinel */ }
  312. };
  313. static struct rt_platform_driver pl011_driver =
  314. {
  315. .name = "serial-pl011",
  316. .ids = pl011_ofw_ids,
  317. .probe = pl011_probe,
  318. .remove = pl011_remove,
  319. };
  320. static int pl011_drv_register(void)
  321. {
  322. rt_platform_driver_register(&pl011_driver);
  323. return 0;
  324. }
  325. INIT_DRIVER_EARLY_EXPORT(pl011_drv_register);