File indexing completed on 2025-05-11 08:22:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <bsp.h>
0029 #include <bsp/fdt.h>
0030 #include <bsp/fatal.h>
0031 #include <bsp/irq.h>
0032 #include <rtems/bspIo.h>
0033 #include <rtems/console.h>
0034 #include <rtems/termiostypes.h>
0035
0036 #include <inttypes.h>
0037 #include <libfdt.h>
0038 #include <stdio.h>
0039
0040 #include <chip.h>
0041 #include <fsl_lpuart.h>
0042
0043 #define LPUART_MAX_INSTANCES 8
0044
0045 #define LPUART_DATA_RT (LPUART_DATA_R0T0_MASK | LPUART_DATA_R1T1_MASK | \
0046 LPUART_DATA_R2T2_MASK | LPUART_DATA_R3T3_MASK | \
0047 LPUART_DATA_R4T4_MASK | LPUART_DATA_R5T5_MASK | \
0048 LPUART_DATA_R6T6_MASK | LPUART_DATA_R7T7_MASK | \
0049 LPUART_DATA_R8T8_MASK | LPUART_DATA_R9T9_MASK)
0050
0051 typedef struct {
0052 rtems_termios_device_context base;
0053 volatile LPUART_Type *regs;
0054 rtems_vector_number irq;
0055 const char *path;
0056 clock_ip_name_t clock_ip;
0057 uint32_t src_clock_hz;
0058 lpuart_config_t config;
0059 } imxrt_lpuart_context;
0060
0061
0062 static imxrt_lpuart_context imxrt_lpuart_console_instance;
0063 static imxrt_lpuart_context *imxrt_lpuart_console;
0064
0065 static void imxrt_output_char(char c);
0066 static int imxrt_poll_char(void);
0067
0068 static imxrt_lpuart_context *imxrt_lpuart_get_context(
0069 rtems_termios_device_context *base
0070 )
0071 {
0072 return RTEMS_CONTAINER_OF(base, imxrt_lpuart_context, base);
0073 }
0074
0075 static void imxrt_lpuart_write_polled(
0076 rtems_termios_device_context *base,
0077 char c
0078 )
0079 {
0080 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0081 volatile LPUART_Type *regs = ctx->regs;
0082 rtems_interrupt_level isr_cookie;
0083 uint32_t ctrl;
0084
0085 rtems_interrupt_disable(isr_cookie);
0086 ctrl = ctx->regs->CTRL;
0087 ctx->regs->CTRL = ctrl & ~LPUART_CTRL_TIE_MASK;
0088 rtems_interrupt_enable(isr_cookie);
0089
0090 while ((regs->STAT & LPUART_STAT_TDRE_MASK) == 0) {
0091
0092 }
0093
0094 regs->DATA = c;
0095
0096 if ((ctrl & LPUART_CTRL_TIE_MASK) != 0) {
0097 ctx->regs->CTRL |= LPUART_CTRL_TIE_MASK;
0098 }
0099 }
0100
0101 static int imxrt_lpuart_read_polled(rtems_termios_device_context *base)
0102 {
0103 uint32_t data;
0104 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0105 volatile LPUART_Type *regs = ctx->regs;
0106
0107 data = regs->DATA;
0108
0109 if ( data & (LPUART_DATA_PARITYE_MASK | LPUART_DATA_FRETSC_MASK |
0110 LPUART_DATA_RXEMPT_MASK) ) {
0111 return -1;
0112 } else {
0113 return data & LPUART_DATA_RT;
0114 }
0115 }
0116
0117 static bool imxrt_lpuart_set_attributes(
0118 rtems_termios_device_context *base,
0119 const struct termios *term
0120 )
0121 {
0122 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0123
0124 switch (term->c_cflag & CSIZE) {
0125 case CS7:
0126 ctx->config.dataBitsCount = kLPUART_SevenDataBits;
0127 break;
0128 case CS8:
0129 ctx->config.dataBitsCount = kLPUART_EightDataBits;
0130 break;
0131 default:
0132 return false;
0133 break;
0134 }
0135
0136 ctx->config.baudRate_Bps = rtems_termios_baud_to_number(term->c_ospeed);
0137
0138 if ((term->c_cflag & CSTOPB) != 0) {
0139 ctx->config.stopBitCount = kLPUART_TwoStopBit;
0140 } else {
0141 ctx->config.stopBitCount = kLPUART_OneStopBit;
0142 }
0143
0144 if ((term->c_cflag & PARENB) != 0) {
0145 if ((term->c_cflag & PARODD) != 0) {
0146 ctx->config.parityMode = kLPUART_ParityOdd;
0147 } else {
0148 ctx->config.parityMode = kLPUART_ParityEven;
0149 }
0150 } else {
0151 ctx->config.parityMode = kLPUART_ParityDisabled;
0152 }
0153
0154 if ((term->c_cflag & CREAD) != 0) {
0155 ctx->config.enableRx = true;
0156 } else {
0157 ctx->config.enableRx = false;
0158 }
0159
0160 if ((term->c_cflag & CCTS_OFLOW) != 0) {
0161 ctx->config.enableTxCTS = true;
0162 } else {
0163 ctx->config.enableTxCTS = false;
0164 }
0165
0166 if ((term->c_cflag & CRTS_IFLOW) != 0) {
0167 ctx->config.enableRxRTS = true;
0168 } else {
0169 ctx->config.enableRxRTS = false;
0170 }
0171
0172 (void) LPUART_Init((LPUART_Type *)ctx->regs, &ctx->config,
0173 ctx->src_clock_hz, false);
0174
0175 return true;
0176 }
0177
0178 static uint32_t imxrt_lpuart_get_src_freq(clock_ip_name_t clock_ip)
0179 {
0180 uint32_t freq;
0181 #if IMXRT_IS_MIMXRT10xx
0182 uint32_t mux;
0183 uint32_t divider;
0184
0185 (void) clock_ip;
0186
0187 mux = CLOCK_GetMux(kCLOCK_UartMux);
0188 divider = 1;
0189
0190 switch (mux) {
0191 case 0:
0192 freq = CLOCK_GetFreq(kCLOCK_Usb1PllClk);
0193 divider = 6;
0194 break;
0195 case 1:
0196 freq = CLOCK_GetFreq(kCLOCK_OscClk);
0197 break;
0198 default:
0199 freq = 0;
0200 }
0201
0202 divider *= CLOCK_GetDiv(kCLOCK_UartDiv) + 1U;
0203 freq /= divider;
0204 #elif IMXRT_IS_MIMXRT11xx
0205
0206
0207
0208
0209 clock_root_t clock_root = clock_ip + kCLOCK_Root_Lpuart1 - kCLOCK_Lpuart1;
0210
0211 freq = CLOCK_GetRootClockFreq(clock_root);
0212 #else
0213 #error Getting UART clock frequency is not implemented for this chip
0214 #endif
0215
0216 return freq;
0217 }
0218
0219 static clock_ip_name_t imxrt_lpuart_clock_ip(volatile LPUART_Type *regs)
0220 {
0221 LPUART_Type *const base_addresses[] = LPUART_BASE_PTRS;
0222 static const clock_ip_name_t lpuart_clocks[] = LPUART_CLOCKS;
0223 size_t i;
0224
0225 for (i = 0; i < RTEMS_ARRAY_SIZE(base_addresses); ++i) {
0226 if (base_addresses[i] == regs) {
0227 return lpuart_clocks[i];
0228 }
0229 }
0230
0231 return kCLOCK_IpInvalid;
0232 }
0233
0234 static void imxrt_lpuart_init_hardware(imxrt_lpuart_context *ctx)
0235 {
0236 (void) LPUART_Init((LPUART_Type *)ctx->regs, &ctx->config,
0237 ctx->src_clock_hz, true);
0238 }
0239
0240 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0241 static void imxrt_lpuart_interrupt(void *arg)
0242 {
0243 rtems_termios_tty *tty = arg;
0244 rtems_termios_device_context *base = rtems_termios_get_device_context(tty);
0245 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0246 uint32_t stat;
0247 uint32_t data;
0248
0249 stat = ctx->regs->STAT;
0250
0251 if ((stat & LPUART_STAT_RDRF_MASK) != 0) {
0252 do {
0253 char c;
0254 data = ctx->regs->DATA;
0255
0256 if ((data & (LPUART_DATA_PARITYE_MASK | LPUART_DATA_FRETSC_MASK |
0257 LPUART_DATA_RXEMPT_MASK)) == 0) {
0258 c = data & LPUART_DATA_RT;
0259 rtems_termios_enqueue_raw_characters(tty, &c, 1);
0260 }
0261 } while ((data & LPUART_DATA_RXEMPT_MASK) == 0);
0262 }
0263
0264 if ((ctx->regs->CTRL & LPUART_CTRL_TIE_MASK) != 0
0265 && (stat & LPUART_STAT_TDRE_MASK) != 0) {
0266
0267 rtems_termios_dequeue_characters(tty, 1);
0268 }
0269 }
0270 #endif
0271
0272 static bool imxrt_lpuart_first_open(
0273 rtems_termios_tty *tty,
0274 rtems_termios_device_context *base,
0275 struct termios *term,
0276 rtems_libio_open_close_args_t *args
0277 )
0278 {
0279 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0280 rtems_status_code sc;
0281 #endif
0282 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0283 rtems_termios_set_initial_baud(tty, BSP_CONSOLE_BAUD);
0284
0285 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0286 sc = rtems_interrupt_handler_install(
0287 ctx->irq,
0288 "LPUART",
0289 RTEMS_INTERRUPT_SHARED,
0290 imxrt_lpuart_interrupt,
0291 tty
0292 );
0293 if (sc != RTEMS_SUCCESSFUL) {
0294 return false;
0295 }
0296 #endif
0297
0298 imxrt_lpuart_init_hardware(ctx);
0299
0300 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0301 ctx->regs->CTRL |= LPUART_CTRL_RIE_MASK;
0302 #endif
0303
0304 imxrt_lpuart_set_attributes(base, term);
0305
0306 return true;
0307 }
0308
0309 static void imxrt_lpuart_last_close(
0310 rtems_termios_tty *tty,
0311 rtems_termios_device_context *base,
0312 rtems_libio_open_close_args_t *args
0313 )
0314 {
0315 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0316
0317 LPUART_Deinit((LPUART_Type *)ctx->regs);
0318
0319 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0320 (void) rtems_interrupt_handler_remove(
0321 ctx->irq,
0322 imxrt_lpuart_interrupt,
0323 tty
0324 );
0325 #endif
0326 }
0327
0328 static void imxrt_lpuart_write(
0329 rtems_termios_device_context *base,
0330 const char *buf,
0331 size_t len
0332 )
0333 {
0334 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0335 imxrt_lpuart_context *ctx = imxrt_lpuart_get_context(base);
0336
0337 if (len > 0) {
0338 ctx->regs->DATA = (uint8_t) buf[0];
0339 ctx->regs->CTRL |= LPUART_CTRL_TIE_MASK;
0340 } else {
0341 ctx->regs->CTRL &= ~LPUART_CTRL_TIE_MASK;
0342 }
0343 #else
0344 size_t i;
0345
0346 for (i = 0; i < len; ++i) {
0347 imxrt_lpuart_write_polled(base, buf[i]);
0348 }
0349 #endif
0350 }
0351
0352 static const rtems_termios_device_handler imxrt_lpuart_handler = {
0353 .first_open = imxrt_lpuart_first_open,
0354 .last_close = imxrt_lpuart_last_close,
0355 .write = imxrt_lpuart_write,
0356 .set_attributes = imxrt_lpuart_set_attributes,
0357 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0358 .mode = TERMIOS_IRQ_DRIVEN,
0359 #else
0360 .poll_read = imxrt_lpuart_read_polled,
0361 .mode = TERMIOS_POLLED,
0362 #endif
0363 };
0364
0365 static int imxrt_lpuart_get_stdout_node(const void *fdt)
0366 {
0367 int node;
0368 const char *console;
0369
0370 node = fdt_path_offset(fdt, "/chosen");
0371 if (node < 0) {
0372 bsp_fatal(IMXRT_FATAL_NO_CONSOLE);
0373 }
0374
0375 console = fdt_getprop(fdt, node, "stdout-path", NULL);
0376 if (console == NULL) {
0377 bsp_fatal(IMXRT_FATAL_NO_CONSOLE);
0378 }
0379
0380 node = fdt_path_offset(fdt, console);
0381 if (node < 0) {
0382 bsp_fatal(IMXRT_FATAL_NO_CONSOLE);
0383 }
0384
0385 return node;
0386 }
0387
0388 static void imxrt_lpuart_init_context_from_fdt(
0389 imxrt_lpuart_context *ctx,
0390 const void *fdt,
0391 int node
0392 )
0393 {
0394 memset(&ctx->base, 0, sizeof(ctx->base));
0395
0396 ctx->regs = imx_get_reg_of_node(fdt, node);
0397 if (ctx->regs == NULL) {
0398 bsp_fatal(IMXRT_FATAL_LPUART_INVALID_FDT);
0399 }
0400
0401 ctx->irq = imx_get_irq_of_node(fdt, node, 0);
0402 if (ctx->irq == BSP_INTERRUPT_VECTOR_INVALID) {
0403 bsp_fatal(IMXRT_FATAL_LPUART_INVALID_FDT);
0404 }
0405
0406 ctx->path = fdt_getprop(fdt, node, "rtems,path", NULL);
0407 if (ctx->path == NULL) {
0408 bsp_fatal(IMXRT_FATAL_LPI2C_INVALID_FDT);
0409 }
0410
0411 ctx->clock_ip = imxrt_lpuart_clock_ip(ctx->regs);
0412 ctx->src_clock_hz = imxrt_lpuart_get_src_freq(ctx->clock_ip);
0413
0414 LPUART_GetDefaultConfig(&ctx->config);
0415 ctx->config.enableTx = true;
0416 ctx->config.enableRx = true;
0417
0418 rtems_termios_device_context_initialize(&ctx->base, "LPUART");
0419 }
0420
0421 static void imxrt_lpuart_console_probe_early(void)
0422 {
0423 int node;
0424 const void *fdt;
0425
0426 imxrt_lpuart_console = NULL;
0427
0428 fdt = bsp_fdt_get();
0429 node = imxrt_lpuart_get_stdout_node(fdt);
0430 imxrt_lpuart_init_context_from_fdt(&imxrt_lpuart_console_instance, fdt, node);
0431 (void) LPUART_Init(
0432 (LPUART_Type *)imxrt_lpuart_console_instance.regs,
0433 &imxrt_lpuart_console_instance.config,
0434 imxrt_lpuart_console_instance.src_clock_hz,
0435 true
0436 );
0437 imxrt_lpuart_console = &imxrt_lpuart_console_instance;
0438
0439 BSP_output_char = imxrt_output_char;
0440 BSP_poll_char = imxrt_poll_char;
0441 }
0442
0443 rtems_status_code console_initialize(
0444 rtems_device_major_number major,
0445 rtems_device_minor_number minor,
0446 void *arg
0447 )
0448 {
0449 const void *fdt;
0450 int stdout_node;
0451 int node;
0452 rtems_status_code sc;
0453
0454 fdt = bsp_fdt_get();
0455 stdout_node = imxrt_lpuart_get_stdout_node(fdt);
0456 node = -1;
0457
0458 rtems_termios_initialize();
0459
0460 do {
0461 node = fdt_node_offset_by_compatible(fdt, node, "nxp,imxrt-lpuart");
0462
0463 if (node >= 0 && imxrt_fdt_node_is_enabled(fdt, node)) {
0464 imxrt_lpuart_context *ctx;
0465
0466 if (node != stdout_node) {
0467 ctx = calloc(1, sizeof(imxrt_lpuart_context));
0468 if (ctx == NULL) {
0469 bsp_fatal(IMXRT_FATAL_LPUART_ALLOC_FAILED);
0470 }
0471
0472 imxrt_lpuart_init_context_from_fdt(ctx, fdt, node);
0473
0474 } else {
0475 ctx = imxrt_lpuart_console;
0476 if (ctx == NULL) {
0477 imxrt_lpuart_console_probe_early();
0478 ctx = imxrt_lpuart_console;
0479 }
0480 }
0481
0482 sc = rtems_termios_device_install(
0483 ctx->path,
0484 &imxrt_lpuart_handler,
0485 NULL,
0486 &ctx->base
0487 );
0488 if (sc != RTEMS_SUCCESSFUL) {
0489 bsp_fatal(IMXRT_FATAL_LPUART_INSTALL_FAILED);
0490 }
0491
0492 if (node == stdout_node) {
0493 link(ctx->path, CONSOLE_DEVICE_NAME);
0494 }
0495 }
0496 } while (node >= 0);
0497
0498 return RTEMS_SUCCESSFUL;
0499 }
0500
0501 static void imxrt_output_char(char c)
0502 {
0503 if (imxrt_lpuart_console != NULL) {
0504 imxrt_lpuart_write_polled(&imxrt_lpuart_console->base, c);
0505 }
0506 }
0507
0508 static int imxrt_poll_char(void)
0509 {
0510 return imxrt_lpuart_read_polled(&imxrt_lpuart_console->base);
0511 }
0512
0513 static void imxrt_output_char_init(char c)
0514 {
0515 imxrt_lpuart_console_probe_early();
0516 imxrt_output_char(c);
0517 }
0518
0519 BSP_output_char_function_type BSP_output_char = imxrt_output_char_init;
0520
0521 BSP_polling_getchar_function_type BSP_poll_char = NULL;