serial.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * Copyright (c) 2006-2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-08-10 Siwei Xu Add i.MX91 SDK
  9. * 2025-09-15 Siwei Xu Fix LPUART driver
  10. */
  11. #include <rthw.h>
  12. #include <rtdevice.h>
  13. #include <ioremap.h>
  14. #include <drivers/misc.h>
  15. #include "serial.h"
  16. #include "MIMX9131.h"
  17. #include "fsl_clock.h"
  18. #include "fsl_lpuart.h"
  19. struct hw_uart_device
  20. {
  21. struct rt_serial_device serial; /* Select serial device */
  22. const char *device_name; /* serial device name */
  23. LPUART_Type *uart_ptr;
  24. rt_base_t uart_base;
  25. int instance;
  26. int irqn;
  27. clock_root_t clock_root; /* clock root */
  28. clock_root_mux_source_t clock_mux; /* clock mux */
  29. clock_ip_name_t clock_ip_name; /* clock control gate */
  30. };
  31. #ifdef BSP_USING_UART1
  32. /* UART1 device driver structure */
  33. static struct hw_uart_device _uart1_device = {
  34. .device_name = "uart1",
  35. .uart_ptr = RT_NULL,
  36. .uart_base = LPUART1_BASE,
  37. .instance = 1,
  38. .irqn = LPUART1_IRQn,
  39. .clock_root = kCLOCK_Root_Lpuart1,
  40. .clock_mux = kCLOCK_LPUART1_ClockRoot_MuxOsc24M,
  41. .clock_ip_name = kCLOCK_Lpuart1,
  42. };
  43. #endif
  44. static struct hw_uart_device *hw_uart_devices[] = {
  45. #ifdef BSP_USING_UART1
  46. &_uart1_device,
  47. #endif
  48. };
  49. static void rt_hw_uart_isr(int irqn, void *param)
  50. {
  51. struct rt_serial_device *serial = (struct rt_serial_device *)param;
  52. rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
  53. }
  54. static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  55. {
  56. struct hw_uart_device *uart = RT_NULL;
  57. static lpuart_config_t config;
  58. RT_ASSERT(serial != RT_NULL);
  59. uart = (struct hw_uart_device *)serial->parent.user_data;
  60. LPUART_GetDefaultConfig(&config);
  61. // baud rate
  62. config.baudRate_Bps = cfg->baud_rate;
  63. // data bits
  64. switch (cfg->data_bits)
  65. {
  66. case DATA_BITS_8:
  67. config.dataBitsCount = kLPUART_EightDataBits;
  68. break;
  69. case DATA_BITS_7:
  70. #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
  71. config.dataBitsCount = kLPUART_SevenDataBits;
  72. break;
  73. #endif
  74. default:
  75. config.dataBitsCount = kLPUART_EightDataBits;
  76. break;
  77. }
  78. // parity bit
  79. switch (cfg->parity)
  80. {
  81. case PARITY_NONE:
  82. config.parityMode = kLPUART_ParityDisabled;
  83. break;
  84. case PARITY_ODD:
  85. config.parityMode = kLPUART_ParityOdd;
  86. break;
  87. case PARITY_EVEN:
  88. config.parityMode = kLPUART_ParityEven;
  89. break;
  90. default:
  91. config.parityMode = kLPUART_ParityDisabled;
  92. break;
  93. }
  94. // stop bits
  95. #if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
  96. switch (cfg->stop_bits)
  97. {
  98. case STOP_BITS_1:
  99. config.stopBitCount = kLPUART_OneStopBit;
  100. break;
  101. case STOP_BITS_2:
  102. config.stopBitCount = kLPUART_TwoStopBit;
  103. break;
  104. default:
  105. config.stopBitCount = kLPUART_OneStopBit;
  106. break;
  107. }
  108. #endif
  109. // LSB/MSB
  110. if (cfg->bit_order == BIT_ORDER_LSB)
  111. {
  112. config.isMsb = false;
  113. }
  114. else
  115. {
  116. config.isMsb = true;
  117. }
  118. // hardware flow control
  119. #if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
  120. if (cfg->flowcontrol == RT_SERIAL_FLOWCONTROL_NONE)
  121. {
  122. // disable hardware flow control
  123. config.enableRxRTS = false;
  124. config.enableTxCTS = false;
  125. }
  126. else
  127. {
  128. // enable hardware flow control
  129. config.enableRxRTS = true;
  130. config.enableTxCTS = true;
  131. }
  132. #endif
  133. // enable TX and RX
  134. config.enableTx = serial->parent.flag & RT_DEVICE_FLAG_WRONLY;
  135. config.enableRx = serial->parent.flag & RT_DEVICE_FLAG_RDONLY;
  136. // Set UART clock source and clock divider
  137. CLOCK_SetRootClockMux(uart->clock_root, uart->clock_mux);
  138. CLOCK_SetRootClockDiv(uart->clock_root, 1U);
  139. // Initialize the LPUART module with the configuration structure and clock source
  140. LPUART_Init(uart->uart_ptr, &config, CLOCK_GetIpFreq(uart->clock_root));
  141. // Install interrupt handler
  142. rt_hw_interrupt_install(uart->irqn, rt_hw_uart_isr, serial, "uart");
  143. rt_hw_interrupt_mask(uart->irqn);
  144. // Enable RX interrupt
  145. LPUART_EnableInterrupts(uart->uart_ptr, kLPUART_RxDataRegFullInterruptEnable);
  146. return RT_EOK;
  147. }
  148. static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
  149. {
  150. struct hw_uart_device *uart = RT_NULL;
  151. RT_ASSERT(serial != RT_NULL);
  152. uart = (struct hw_uart_device *)serial->parent.user_data;
  153. switch (cmd)
  154. {
  155. case RT_DEVICE_CTRL_CLR_INT:
  156. /* disable rx irq */
  157. rt_hw_interrupt_mask(uart->irqn);
  158. break;
  159. case RT_DEVICE_CTRL_SET_INT:
  160. /* enable rx irq */
  161. rt_hw_interrupt_umask(uart->irqn);
  162. break;
  163. }
  164. return RT_EOK;
  165. }
  166. static int uart_putc(struct rt_serial_device *serial, char c)
  167. {
  168. struct hw_uart_device *uart;
  169. RT_ASSERT(serial != RT_NULL);
  170. uart = (struct hw_uart_device *)serial->parent.user_data;
  171. while (!(LPUART_GetStatusFlags(uart->uart_ptr) & kLPUART_TxDataRegEmptyFlag))
  172. {
  173. __NOP();
  174. }
  175. LPUART_WriteByte(uart->uart_ptr, c);
  176. return 1;
  177. }
  178. #ifdef BSP_USING_EARLY_CONSOLE
  179. LPUART_Type *earlycon_base = RT_NULL;
  180. void rt_hw_earlycon_set(void *base)
  181. {
  182. earlycon_base = (LPUART_Type *)base;
  183. }
  184. void rt_hw_earlycon_ioremap(void)
  185. {
  186. earlycon_base = rt_ioremap_early((void *)LPUART1, LPUART1_SIZE);
  187. }
  188. void rt_hw_earlycon_putc(char c)
  189. {
  190. LPUART_WriteByte(earlycon_base, c);
  191. while (!(LPUART_GetStatusFlags(earlycon_base) & kLPUART_TxDataRegEmptyFlag))
  192. ;
  193. }
  194. static void rt_hw_earlycon_print(const char *str, int print_newline)
  195. {
  196. int has_cr = 0;
  197. int has_lf = 0;
  198. while (*str)
  199. {
  200. if (*str == '\r')
  201. {
  202. has_cr = 1;
  203. }
  204. else if (*str == '\n')
  205. {
  206. has_lf = 1;
  207. }
  208. rt_hw_earlycon_putc(*str++);
  209. }
  210. if (!has_cr && print_newline)
  211. {
  212. rt_hw_earlycon_putc('\r');
  213. }
  214. if (!has_lf && print_newline)
  215. {
  216. rt_hw_earlycon_putc('\n');
  217. }
  218. }
  219. void rt_hw_earlycon_puts(const char *str)
  220. {
  221. rt_hw_earlycon_print(str, 1);
  222. }
  223. void rt_hw_earlycon_print_hex(const char *str, rt_base_t hex)
  224. {
  225. rt_hw_earlycon_print(str, 0);
  226. rt_hw_earlycon_putc('0');
  227. rt_hw_earlycon_putc('x');
  228. for (int i = 60; i >= 0; i -= 4)
  229. {
  230. rt_base_t h = (hex >> i) & 0xF;
  231. rt_hw_earlycon_putc(h < 10 ? '0' + h : 'A' + h - 10);
  232. }
  233. rt_hw_earlycon_putc('\r');
  234. rt_hw_earlycon_putc('\n');
  235. }
  236. #endif
  237. void rt_hw_console_putc(char c)
  238. {
  239. #if defined(BSP_USING_UART1)
  240. uart_putc(&_uart1_device.serial, c);
  241. #endif
  242. }
  243. void rt_hw_console_output(const char *str)
  244. {
  245. #if defined(BSP_USING_UART1)
  246. int has_cr = 0;
  247. int has_lf = 0;
  248. while (*str)
  249. {
  250. if (*str == '\r')
  251. {
  252. has_cr = 1;
  253. }
  254. else if (*str == '\n')
  255. {
  256. has_lf = 1;
  257. }
  258. rt_hw_console_putc(*str++);
  259. }
  260. if (!has_cr)
  261. {
  262. rt_hw_console_putc('\r');
  263. }
  264. if (!has_lf)
  265. {
  266. rt_hw_console_putc('\n');
  267. }
  268. #endif
  269. }
  270. static int uart_getc(struct rt_serial_device *serial)
  271. {
  272. int ch;
  273. struct hw_uart_device *uart;
  274. RT_ASSERT(serial != RT_NULL);
  275. uart = (struct hw_uart_device *)serial->parent.user_data;
  276. uint32_t flags = LPUART_GetStatusFlags(uart->uart_ptr);
  277. if (flags & kLPUART_RxDataRegFullFlag)
  278. {
  279. ch = LPUART_ReadByte(uart->uart_ptr);
  280. }
  281. else
  282. {
  283. ch = -1;
  284. }
  285. return ch;
  286. }
  287. static const struct rt_uart_ops _uart_ops = {
  288. uart_configure,
  289. uart_control,
  290. uart_putc,
  291. uart_getc,
  292. };
  293. int rt_hw_uart_init(void)
  294. {
  295. struct serial_configure config;
  296. /* setup default serial configure */
  297. config.baud_rate = BAUD_RATE_115200;
  298. config.bit_order = BIT_ORDER_LSB;
  299. config.data_bits = DATA_BITS_8;
  300. config.parity = PARITY_NONE;
  301. config.stop_bits = STOP_BITS_1;
  302. config.invert = NRZ_NORMAL;
  303. config.bufsz = RT_SERIAL_RB_BUFSZ;
  304. /* Remap CCM controller to virtual address */
  305. CCM_CTRL = rt_ioremap((void *)CCM_CTRL_BASE, CCM_CTRL_SIZE);
  306. for (int i = 0; i < RT_ARRAY_SIZE(hw_uart_devices); i++)
  307. {
  308. if (hw_uart_devices[i] != RT_NULL)
  309. {
  310. hw_uart_devices[i]->serial.ops = &_uart_ops;
  311. hw_uart_devices[i]->serial.config = config;
  312. /* Remap LPUART instance to virtual address */
  313. hw_uart_devices[i]->uart_ptr = rt_ioremap((void *)hw_uart_devices[i]->uart_base, LPUART1_SIZE);
  314. /* Update LPUART instance */
  315. LPUART_SetInstance(hw_uart_devices[i]->instance, hw_uart_devices[i]->uart_ptr);
  316. rt_hw_serial_register(&hw_uart_devices[i]->serial, hw_uart_devices[i]->device_name,
  317. RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, hw_uart_devices[i]);
  318. }
  319. }
  320. return 0;
  321. }