File indexing completed on 2025-05-11 08:22:49
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 <sys/param.h>
0029
0030 #include <rtems/bspIo.h>
0031 #include <rtems/console.h>
0032 #include <rtems/sysinit.h>
0033 #include <rtems/termiostypes.h>
0034
0035 #include <bsp.h>
0036 #include <bsp/fdt.h>
0037 #include <bsp/irq.h>
0038
0039 #include <arm/freescale/imx/imx_ccmvar.h>
0040 #include <arm/freescale/imx/imx_uartreg.h>
0041
0042 #include <libfdt.h>
0043
0044 #define IMX_UART_TX_FIFO_LEVEL 16
0045
0046 typedef struct {
0047 rtems_termios_device_context base;
0048 volatile imx_uart *regs;
0049 #ifdef CONSOLE_USE_INTERRUPTS
0050 rtems_vector_number irq;
0051 int tx_in_progress;
0052 #endif
0053 } imx_uart_context;
0054
0055 static imx_uart_context imx_uart_instances[7];
0056
0057 static imx_uart_context *imx_uart_console = &imx_uart_instances[0];
0058
0059 static volatile imx_uart *imx_uart_get_regs(rtems_termios_device_context *base)
0060 {
0061 imx_uart_context *ctx;
0062
0063 ctx = (imx_uart_context *) base;
0064 return ctx->regs;
0065 }
0066
0067 static void imx_uart_write_polled(rtems_termios_device_context *base, char c)
0068 {
0069 volatile imx_uart *regs;
0070
0071 regs = imx_uart_get_regs(base);
0072
0073 while ((regs->usr1 & IMX_UART_USR1_TRDY) == 0) {
0074
0075 }
0076
0077 regs->utxd = IMX_UART_UTXD_TX_DATA(c);
0078 }
0079
0080 static int imx_uart_read_polled(rtems_termios_device_context *base)
0081 {
0082 volatile imx_uart *regs;
0083
0084 regs = imx_uart_get_regs(base);
0085
0086 if ((regs->usr2 & IMX_UART_USR2_RDR) != 0) {
0087 return IMX_UART_URXD_RX_DATA_GET(regs->urxd);
0088 } else {
0089 return -1;
0090 }
0091 }
0092
0093 void imx_uart_console_drain(void)
0094 {
0095 volatile imx_uart *regs;
0096
0097 regs = imx_uart_get_regs(&imx_uart_console->base);
0098
0099 if (regs != NULL) {
0100 while ((regs->usr2 & IMX_UART_USR2_TXFE) == 0) {
0101
0102 }
0103 }
0104 }
0105
0106 static void imx_output_char(char c)
0107 {
0108 imx_uart_write_polled(&imx_uart_console->base, c);
0109 }
0110
0111 static int imx_poll_char(void)
0112 {
0113 return imx_uart_read_polled(&imx_uart_console->base);
0114 }
0115
0116 static void imx_uart_init_context(
0117 imx_uart_context *ctx,
0118 const char *fdt,
0119 const char *serial
0120 )
0121 {
0122 int node;
0123
0124 rtems_termios_device_context_initialize(&ctx->base, "UART");
0125 node = fdt_path_offset(fdt, serial);
0126 ctx->regs = imx_get_reg_of_node(fdt, node);
0127 #ifdef CONSOLE_USE_INTERRUPTS
0128 ctx->irq = imx_get_irq_of_node(fdt, node, 0);
0129 #endif
0130 }
0131
0132 static void imx_uart_probe(void)
0133 {
0134 const void *fdt;
0135 int node;
0136 int offset;
0137 const char *console;
0138 size_t i;
0139
0140 fdt = bsp_fdt_get();
0141 node = fdt_path_offset(fdt, "/chosen");
0142
0143 console = fdt_getprop(fdt, node, "stdout-path", NULL);
0144 if (console == NULL) {
0145 console = "";
0146 }
0147
0148 node = fdt_path_offset(fdt, "/aliases");
0149 offset = fdt_first_property_offset(fdt, node);
0150 i = 0;
0151
0152 while (offset >= 0 && i < RTEMS_ARRAY_SIZE(imx_uart_instances)) {
0153 const struct fdt_property *prop;
0154
0155 prop = fdt_get_property_by_offset(fdt, offset, NULL);
0156
0157 if (prop != NULL) {
0158 const char *name;
0159
0160 name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
0161 if (strstr(name, "serial") != NULL) {
0162 imx_uart_context *ctx;
0163 const char *serial;
0164
0165 ctx = &imx_uart_instances[i];
0166 serial = prop->data;
0167
0168 if (strcmp(serial, console) == 0) {
0169 imx_uart_console = ctx;
0170 }
0171
0172 imx_uart_init_context(ctx, fdt, serial);
0173 ++i;
0174 }
0175 }
0176
0177 offset = fdt_next_property_offset(fdt, offset);
0178 }
0179
0180 BSP_output_char = imx_output_char;
0181 BSP_poll_char = imx_poll_char;
0182 }
0183
0184 static void imx_output_char_init(char c)
0185 {
0186 imx_uart_probe();
0187 imx_output_char(c);
0188 }
0189
0190 BSP_output_char_function_type BSP_output_char = imx_output_char_init;
0191
0192 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0193
0194 #ifdef CONSOLE_USE_INTERRUPTS
0195 static void imx_uart_interrupt(void *arg)
0196 {
0197 rtems_termios_tty *tty;
0198 imx_uart_context *ctx;
0199 volatile imx_uart *regs;
0200 uint32_t usr2;
0201
0202 tty = arg;
0203 ctx = rtems_termios_get_device_context(tty);
0204 regs = ctx->regs;
0205 usr2 = regs->usr2;
0206
0207 regs->usr1 = IMX_UART_USR1_AGTIM;
0208
0209 while ((usr2 & IMX_UART_USR2_RDR) != 0) {
0210 char c;
0211
0212 c = IMX_UART_URXD_RX_DATA_GET(regs->urxd);
0213 rtems_termios_enqueue_raw_characters(tty, &c, 1);
0214 usr2 = regs->usr2;
0215 }
0216
0217 if (ctx->tx_in_progress > 0 && (regs->usr1 & IMX_UART_USR1_TRDY) != 0) {
0218 rtems_termios_dequeue_characters(tty, ctx->tx_in_progress);
0219 }
0220 }
0221 #endif
0222
0223 static bool imx_uart_set_attributes(
0224 rtems_termios_device_context *base,
0225 const struct termios *term
0226 )
0227 {
0228 imx_uart_context *ctx;
0229 volatile imx_uart *regs;
0230 uint32_t ufcr;
0231 uint32_t baud;
0232
0233 ctx = (imx_uart_context *) base;
0234 regs = imx_uart_get_regs(&ctx->base);
0235
0236 baud = rtems_termios_baud_to_number(term->c_ospeed);
0237
0238 if (baud != 0) {
0239 ufcr = regs->ufcr;
0240 ufcr = IMX_UART_UFCR_RFDIV_SET(ufcr, 0x5);
0241 regs->ufcr = ufcr;
0242 regs->ubir = 15;
0243 regs->ubmr = imx_ccm_uart_hz() / baud - 1;
0244 }
0245
0246 return true;
0247 }
0248
0249 static bool imx_uart_first_open(
0250 rtems_termios_tty *tty,
0251 rtems_termios_device_context *base,
0252 struct termios *term,
0253 rtems_libio_open_close_args_t *args
0254 )
0255 {
0256 imx_uart_context *ctx;
0257 volatile imx_uart *regs;
0258 #ifdef CONSOLE_USE_INTERRUPTS
0259 rtems_status_code sc;
0260 uint32_t ufcr;
0261 #endif
0262
0263 ctx = (imx_uart_context *) base;
0264 regs = imx_uart_get_regs(&ctx->base);
0265
0266 regs->ucr1 = IMX_UART_UCR1_UARTEN;
0267 regs->ucr2 = IMX_UART_UCR2_IRTS | IMX_UART_UCR2_WS | IMX_UART_UCR2_RXEN
0268 | IMX_UART_UCR2_TXEN | IMX_UART_UCR2_SRST;
0269 regs->ucr3 |= IMX_UART_UCR3_ADNIMP | IMX_UART_UCR3_RXDMUXSEL;
0270
0271 rtems_termios_set_initial_baud(tty, 115200);
0272 imx_uart_set_attributes(base, term);
0273
0274 #ifdef CONSOLE_USE_INTERRUPTS
0275 ufcr = regs->ufcr;
0276 ufcr = IMX_UART_UFCR_RXTL_SET(ufcr, 16);
0277 ufcr = IMX_UART_UFCR_TXTL_SET(ufcr, IMX_UART_TX_FIFO_LEVEL);
0278 regs->ufcr = ufcr;
0279 regs->ucr1 |= IMX_UART_UCR1_RRDYEN;
0280 regs->ucr2 |= IMX_UART_UCR2_ATEN;
0281 sc = rtems_interrupt_handler_install(
0282 ctx->irq,
0283 "UART",
0284 RTEMS_INTERRUPT_SHARED,
0285 imx_uart_interrupt,
0286 tty
0287 );
0288 if (sc != RTEMS_SUCCESSFUL) {
0289 return false;
0290 }
0291 #endif
0292
0293 return true;
0294 }
0295
0296 static void imx_uart_last_close(
0297 rtems_termios_tty *tty,
0298 rtems_termios_device_context *base,
0299 rtems_libio_open_close_args_t *args
0300 )
0301 {
0302 #ifdef CONSOLE_USE_INTERRUPTS
0303 imx_uart_context *ctx;
0304
0305 ctx = (imx_uart_context *) base;
0306 rtems_interrupt_handler_remove(ctx->irq, imx_uart_interrupt, tty);
0307 #endif
0308 }
0309
0310 static void imx_uart_write(
0311 rtems_termios_device_context *base,
0312 const char *buf,
0313 size_t len
0314 )
0315 {
0316 #ifdef CONSOLE_USE_INTERRUPTS
0317 imx_uart_context *ctx;
0318 volatile imx_uart *regs;
0319 int n;
0320 uint32_t ucr1;
0321
0322 ctx = (imx_uart_context *) base;
0323 regs = imx_uart_get_regs(&ctx->base);
0324 ucr1 = regs->ucr1;
0325
0326 if (len > 0) {
0327 int i;
0328
0329 n = (int) MIN(len, IMX_UART_TX_FIFO_LEVEL);
0330 ucr1 |= IMX_UART_UCR1_TRDYEN;
0331
0332 for (i = 0; i < n; ++i) {
0333 regs->utxd = IMX_UART_UTXD_TX_DATA(buf[i]);
0334 }
0335 } else {
0336 n = 0;
0337 ucr1 &= ~IMX_UART_UCR1_TRDYEN;
0338 }
0339
0340 regs->ucr1 = ucr1;
0341 ctx->tx_in_progress = n;
0342 #else
0343 size_t i;
0344
0345 for (i = 0; i < len; ++i) {
0346 imx_uart_write_polled(base, buf[i]);
0347 }
0348 #endif
0349 }
0350
0351 static const rtems_termios_device_handler imx_uart_handler = {
0352 .first_open = imx_uart_first_open,
0353 .last_close = imx_uart_last_close,
0354 .write = imx_uart_write,
0355 .set_attributes = imx_uart_set_attributes,
0356 #ifdef CONSOLE_USE_INTERRUPTS
0357 .mode = TERMIOS_IRQ_DRIVEN
0358 #else
0359 .poll_read = imx_uart_read_polled,
0360 .mode = TERMIOS_POLLED
0361 #endif
0362 };
0363
0364 rtems_status_code console_initialize(
0365 rtems_device_major_number major,
0366 rtems_device_minor_number minor,
0367 void *arg
0368 )
0369 {
0370 char path[] = "/dev/ttyS?";
0371 size_t i;
0372
0373 rtems_termios_initialize();
0374
0375 for (i = 0; i < RTEMS_ARRAY_SIZE(imx_uart_instances); ++i) {
0376 imx_uart_context *ctx;
0377
0378 ctx = &imx_uart_instances[i];
0379 path[sizeof(path) - 2] = (char) ('0' + i);
0380
0381 rtems_termios_device_install(
0382 path,
0383 &imx_uart_handler,
0384 NULL,
0385 &ctx->base
0386 );
0387
0388 if (ctx == imx_uart_console) {
0389 link(path, CONSOLE_DEVICE_NAME);
0390 }
0391 }
0392
0393 return RTEMS_SUCCESSFUL;
0394 }
0395
0396 RTEMS_SYSINIT_ITEM(
0397 imx_uart_probe,
0398 RTEMS_SYSINIT_BSP_START,
0399 RTEMS_SYSINIT_ORDER_LAST_BUT_5
0400 );