File indexing completed on 2025-05-11 08:22:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <bsp.h>
0012 #include <rtems/libio.h>
0013 #include <libchip/sersupp.h>
0014 #include <rtems/error.h>
0015 #include <rtems/bspIo.h>
0016 #include <assert.h>
0017 #include <termios.h>
0018 #include <rtems/irq.h>
0019 #include <bsp/irq.h>
0020 #include <mc9328mxl.h>
0021 #include <rtems/console.h>
0022 #include <inttypes.h>
0023
0024
0025 #define USE_INTERRUPTS 1
0026
0027
0028 #define NUM_DEVS 2
0029 #define poll_write(c) imx_uart_poll_write_char(0, c)
0030 #define poll_read() imx_uart_poll_read_char(0)
0031
0032 static int imx_uart_first_open(int, int, void *);
0033 static int imx_uart_last_close(int, int, void *);
0034 static int imx_uart_poll_read(int);
0035 static int imx_uart_set_attrs(int, const struct termios *);
0036 static void imx_uart_init(int minor);
0037 static void imx_uart_set_baud(int, int);
0038 static ssize_t imx_uart_poll_write(int, const char *, size_t);
0039 static int imx_uart_poll_read_char(int minor);
0040 static void imx_uart_poll_write_char(int minor, char c);
0041 static void _BSP_output_char(char c);
0042 static int _BSP_poll_char(void);
0043
0044 #if USE_INTERRUPTS
0045 static void imx_uart_tx_isr(void *);
0046 static void imx_uart_rx_isr(void *);
0047 static void imx_uart_isr_on(rtems_vector_number);
0048 static void imx_uart_isr_off(rtems_vector_number);
0049 static ssize_t imx_uart_intr_write(int, const char *, size_t);
0050 static rtems_vector_number imx_uart_name_transmit(int minor);
0051 static rtems_vector_number imx_uart_name_receive(int minor);
0052 #endif
0053
0054
0055 #if USE_INTERRUPTS
0056 rtems_termios_callbacks imx_uart_cbacks = {
0057 .firstOpen = imx_uart_first_open,
0058 .lastClose = imx_uart_last_close,
0059 .pollRead = NULL,
0060 .write = imx_uart_intr_write,
0061 .setAttributes = imx_uart_set_attrs,
0062 .stopRemoteTx = NULL,
0063 .startRemoteTx = NULL,
0064 .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN,
0065 };
0066 #else
0067 rtems_termios_callbacks imx_uart_cbacks = {
0068 .firstOpen = imx_uart_first_open,
0069 .lastClose = imx_uart_last_close,
0070 .pollRead = imx_uart_poll_read,
0071 .write = imx_uart_poll_write,
0072 .setAttributes = imx_uart_set_attrs,
0073 .stopRemoteTx = NULL,
0074 .startRemoteTx = NULL,
0075 .outputUsesInterrupts = TERMIOS_POLLED,
0076 };
0077 #endif
0078
0079 typedef struct {
0080 int minor;
0081 mc9328mxl_uart_regs_t * regs;
0082 volatile const char *buf;
0083 volatile int len;
0084 volatile int idx;
0085 void *tty;
0086 } imx_uart_data_t;
0087
0088 static imx_uart_data_t imx_uart_data[NUM_DEVS];
0089
0090 rtems_device_driver console_initialize(
0091 rtems_device_major_number major,
0092 rtems_device_minor_number minor,
0093 void *arg
0094 )
0095 {
0096 rtems_status_code status;
0097 int i;
0098
0099 for (i = 0; i < NUM_DEVS; i++) {
0100 imx_uart_init(i);
0101 }
0102
0103 rtems_termios_initialize();
0104
0105
0106 status = rtems_io_register_name("/dev/console", major, 0);
0107 if (status != RTEMS_SUCCESSFUL) {
0108 rtems_panic("%s:%d Error registering /dev/console :: %d\n",
0109 __FUNCTION__, __LINE__, status);
0110 }
0111
0112 status = rtems_io_register_name("/dev/tty0", major, 0);
0113 if (status != RTEMS_SUCCESSFUL) {
0114 rtems_panic("%s:%d Error registering /dev/tty0 :: %d\n",
0115 __FUNCTION__, __LINE__, status);
0116 }
0117
0118 status = rtems_io_register_name("/dev/tty1", major, 1);
0119 if (status != RTEMS_SUCCESSFUL) {
0120 rtems_panic("%s:%d Error registering /dev/tty1 :: %d\n",
0121 __FUNCTION__, __LINE__, status);
0122 }
0123 return RTEMS_SUCCESSFUL;
0124 }
0125
0126 rtems_device_driver console_open(
0127 rtems_device_major_number major,
0128 rtems_device_minor_number minor,
0129 void * arg
0130 )
0131 {
0132 rtems_status_code rc;
0133
0134 if (minor > (NUM_DEVS - 1)) {
0135 return RTEMS_INVALID_NUMBER;
0136 }
0137
0138 rc = rtems_termios_open(major, minor, arg, &imx_uart_cbacks);
0139
0140 return rc;
0141 }
0142
0143 rtems_device_driver console_close(
0144 rtems_device_major_number major,
0145 rtems_device_minor_number minor,
0146 void * arg
0147 )
0148 {
0149 return rtems_termios_close(arg);
0150 }
0151
0152 rtems_device_driver console_read(
0153 rtems_device_major_number major,
0154 rtems_device_minor_number minor,
0155 void * arg
0156 )
0157 {
0158 return rtems_termios_read(arg);
0159 }
0160
0161 rtems_device_driver console_write(
0162 rtems_device_major_number major,
0163 rtems_device_minor_number minor,
0164 void * arg
0165 )
0166 {
0167 return rtems_termios_write(arg);
0168 }
0169
0170 rtems_device_driver console_control(
0171 rtems_device_major_number major,
0172 rtems_device_minor_number minor,
0173 void * arg
0174 )
0175 {
0176 return rtems_termios_ioctl(arg);
0177 }
0178
0179 static void imx_uart_init(int minor)
0180 {
0181 imx_uart_data[minor].minor = minor;
0182 imx_uart_data[minor].buf = NULL;
0183 imx_uart_data[minor].len = 0;
0184 imx_uart_data[minor].idx = 0;
0185
0186 if (minor == 0) {
0187 imx_uart_data[minor].regs =
0188 (mc9328mxl_uart_regs_t *) MC9328MXL_UART1_BASE;
0189 } else if (minor == 1) {
0190 imx_uart_data[minor].regs =
0191 (mc9328mxl_uart_regs_t *) MC9328MXL_UART2_BASE;
0192 } else {
0193 rtems_panic("%s:%d Unknown UART minor number %d\n",
0194 __FUNCTION__, __LINE__, minor);
0195 }
0196
0197 imx_uart_data[minor].regs->cr1 = (
0198 MC9328MXL_UART_CR1_UARTCLKEN |
0199 MC9328MXL_UART_CR1_UARTEN);
0200
0201 imx_uart_data[minor].regs->cr2 = (
0202 MC9328MXL_UART_CR2_IRTS |
0203 MC9328MXL_UART_CR2_WS |
0204 MC9328MXL_UART_CR2_TXEN |
0205 MC9328MXL_UART_CR2_RXEN |
0206 MC9328MXL_UART_CR2_SRST);
0207
0208 imx_uart_data[minor].regs->cr3 = 0;
0209
0210 imx_uart_data[minor].regs->cr4 = 0;
0211
0212 imx_uart_data[minor].regs->fcr = (
0213 MC9328MXL_UART_FCR_TXTL(32) |
0214 MC9328MXL_UART_FCR_RFDIV_1 |
0215 MC9328MXL_UART_FCR_RXTL(1));
0216
0217 imx_uart_set_baud(minor, 38400);
0218
0219 }
0220
0221 static int imx_uart_first_open(int major, int minor, void *arg)
0222 {
0223 rtems_libio_open_close_args_t *args = arg;
0224 rtems_status_code status = RTEMS_SUCCESSFUL;
0225
0226 imx_uart_data[minor].tty = args->iop->data1;
0227
0228 #if USE_INTERRUPTS
0229 status = rtems_interrupt_handler_install(
0230 imx_uart_name_transmit(minor),
0231 "UART",
0232 RTEMS_INTERRUPT_UNIQUE,
0233 imx_uart_tx_isr,
0234 &imx_uart_data[minor]
0235 );
0236 assert(status == RTEMS_SUCCESSFUL);
0237 imx_uart_isr_on(imx_uart_name_transmit(minor));
0238
0239 status = rtems_interrupt_handler_install(
0240 imx_uart_name_receive(minor),
0241 "UART",
0242 RTEMS_INTERRUPT_UNIQUE,
0243 imx_uart_rx_isr,
0244 &imx_uart_data[minor]
0245 );
0246 assert(status == RTEMS_SUCCESSFUL);
0247 imx_uart_isr_on(imx_uart_name_receive(minor));
0248
0249 imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_RRDYEN;
0250 #endif
0251
0252 return 0;
0253 }
0254
0255 static int imx_uart_last_close(int major, int minor, void *arg)
0256 {
0257 #if USE_INTERRUPTS
0258 rtems_status_code status = RTEMS_SUCCESSFUL;
0259
0260 imx_uart_isr_off(imx_uart_name_transmit(minor));
0261 status = rtems_interrupt_handler_remove(
0262 imx_uart_name_transmit(minor),
0263 imx_uart_tx_isr,
0264 &imx_uart_data[minor]
0265 );
0266 assert(status == RTEMS_SUCCESSFUL);
0267
0268 imx_uart_isr_off(imx_uart_name_receive(minor));
0269 status = rtems_interrupt_handler_remove(
0270 imx_uart_name_receive(minor),
0271 imx_uart_rx_isr,
0272 &imx_uart_data[minor]
0273 );
0274 assert(status == RTEMS_SUCCESSFUL);
0275 #endif
0276
0277 return 0;
0278 }
0279
0280 static int imx_uart_poll_read(int minor)
0281 {
0282 if (imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_RDR) {
0283 return imx_uart_data[minor].regs->rxd & 0xff;
0284 } else {
0285 return -1;
0286 }
0287 }
0288
0289
0290 static ssize_t imx_uart_poll_write(int minor, const char *buf, size_t len)
0291 {
0292 int i;
0293 for (i = 0; i < len; i++) {
0294
0295 while (!(imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_TXDC)) {
0296 continue;
0297 }
0298
0299 imx_uart_data[minor].regs->txd = buf[i];
0300 }
0301 return 1;
0302
0303 }
0304
0305 #if USE_INTERRUPTS
0306 static ssize_t imx_uart_intr_write(int minor, const char *buf, size_t len)
0307 {
0308 if (len > 0) {
0309 imx_uart_data[minor].buf = buf;
0310 imx_uart_data[minor].len = len;
0311 imx_uart_data[minor].idx = 0;
0312
0313 imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_TXMPTYEN;
0314 }
0315
0316 return 1;
0317 }
0318 #endif
0319
0320
0321
0322 static int imx_uart_set_attrs(int minor, const struct termios *t)
0323 {
0324 int baud;
0325
0326 baud = rtems_termios_baud_to_number(t->c_ospeed);
0327 imx_uart_set_baud(minor, baud);
0328
0329 return 0;
0330 }
0331
0332 #if USE_INTERRUPTS
0333 static void imx_uart_isr_on(rtems_vector_number name)
0334 {
0335 MC9328MXL_AITC_INTENNUM = name;
0336 }
0337 static void imx_uart_isr_off(rtems_vector_number name)
0338 {
0339 MC9328MXL_AITC_INTDISNUM = name;
0340 }
0341
0342 static void imx_uart_rx_isr(void * param)
0343 {
0344 imx_uart_data_t *uart_data = param;
0345 char buf[32];
0346 int i=0;
0347
0348 while (uart_data->regs->sr2 & MC9328MXL_UART_SR2_RDR) {
0349 buf[i] = uart_data->regs->rxd & 0xff;
0350 i++;
0351 }
0352
0353 rtems_termios_enqueue_raw_characters(uart_data->tty, buf, i);
0354 }
0355
0356 static void imx_uart_tx_isr(void * param)
0357 {
0358 imx_uart_data_t *uart_data = param;
0359 int len;
0360 int minor = uart_data->minor;
0361
0362
0363 if (uart_data->idx < uart_data->len) {
0364 while ( (uart_data->regs->sr1 & MC9328MXL_UART_SR1_TRDY) &&
0365 (uart_data->idx < uart_data->len)) {
0366 uart_data->regs->txd = uart_data->buf[uart_data->idx];
0367 uart_data->idx++;
0368 }
0369 } else {
0370 len = uart_data->len;
0371 uart_data->len = 0;
0372 imx_uart_data[minor].regs->cr1 &= ~MC9328MXL_UART_CR1_TXMPTYEN;
0373 rtems_termios_dequeue_characters(uart_data->tty, len);
0374 }
0375 }
0376
0377 static rtems_vector_number imx_uart_name_transmit(int minor)
0378 {
0379 if (minor == 0) {
0380 return BSP_INT_UART1_TX;
0381 } else if (minor == 1) {
0382 return BSP_INT_UART2_TX;
0383 }
0384
0385 assert(0);
0386 }
0387
0388 static rtems_vector_number imx_uart_name_receive(int minor)
0389 {
0390 if (minor == 0) {
0391 return BSP_INT_UART1_RX;
0392 } else if (minor == 1) {
0393 return BSP_INT_UART2_RX;
0394 }
0395
0396 assert(0);
0397 }
0398 #endif
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411 static void imx_uart_set_baud(int minor, int baud)
0412 {
0413 unsigned int perclk1;
0414 unsigned int denom;
0415 unsigned int ref_freq = 0;
0416 uint32_t fcr;
0417
0418 perclk1 = get_perclk1_freq();
0419 fcr = imx_uart_data[minor].regs->fcr;
0420
0421 switch(fcr & MC9328MXL_UART_FCR_RFDIV_MASK) {
0422 case MC9328MXL_UART_FCR_RFDIV_1: ref_freq = perclk1/1; break;
0423 case MC9328MXL_UART_FCR_RFDIV_2: ref_freq = perclk1/2; break;
0424 case MC9328MXL_UART_FCR_RFDIV_3: ref_freq = perclk1/3; break;
0425 case MC9328MXL_UART_FCR_RFDIV_4: ref_freq = perclk1/4; break;
0426 case MC9328MXL_UART_FCR_RFDIV_5: ref_freq = perclk1/5; break;
0427 case MC9328MXL_UART_FCR_RFDIV_6: ref_freq = perclk1/6; break;
0428 case MC9328MXL_UART_FCR_RFDIV_7: ref_freq = perclk1/7; break;
0429 default:
0430 rtems_panic("%s:%d Unknown RFDIV: 0x%" PRIx32,
0431 __FUNCTION__, __LINE__,
0432 fcr & MC9328MXL_UART_FCR_RFDIV_MASK);
0433 break;
0434 }
0435
0436 denom = ref_freq / baud;
0437
0438 imx_uart_data[minor].regs->bir = 0xf;
0439 imx_uart_data[minor].regs->bmr = denom;
0440 }
0441
0442
0443
0444
0445
0446 static int imx_uart_poll_read_char(int minor)
0447 {
0448 return imx_uart_poll_read(minor);
0449 }
0450
0451
0452
0453
0454 static void imx_uart_poll_write_char(int minor, char c)
0455 {
0456 imx_uart_poll_write(minor, &c, 1);
0457 }
0458
0459
0460
0461
0462 static void _BSP_output_char(char c)
0463 {
0464 poll_write(c);
0465 }
0466
0467 BSP_output_char_function_type BSP_output_char = _BSP_output_char;
0468
0469 static int _BSP_poll_char(void)
0470 {
0471 return poll_read();
0472 }
0473
0474 BSP_polling_getchar_function_type BSP_poll_char = _BSP_poll_char;
0475
0476