File indexing completed on 2025-05-11 08:23:52
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
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 #include <assert.h>
0041 #include <string.h>
0042
0043 #include <rtems.h>
0044 #include <bsp/mpc5200.h>
0045 #include <bsp.h>
0046 #include <bsp/irq.h>
0047
0048 #include <rtems/console.h>
0049 #include <rtems/bspIo.h>
0050 #include <rtems/libio.h>
0051 #include <rtems/termiostypes.h>
0052
0053
0054 #define NUM_PORTS MPC5200_PSC_NO
0055
0056 #define PSC1_MINOR 0
0057 #define PSC2_MINOR 1
0058 #define PSC3_MINOR 2
0059 #define PSC4_MINOR 3
0060 #define PSC5_MINOR 4
0061 #define PSC6_MINOR 5
0062
0063 uint32_t mpc5200_uart_avail_mask = BSP_UART_AVAIL_MASK;
0064
0065 #if defined(UARTS_USE_TERMIOS_INT)
0066 uint8_t psc_minor_to_irqname[NUM_PORTS] = {
0067 BSP_SIU_IRQ_PSC1,
0068 BSP_SIU_IRQ_PSC2,
0069 BSP_SIU_IRQ_PSC3,
0070 BSP_SIU_IRQ_PSC4,
0071 BSP_SIU_IRQ_PSC5,
0072 BSP_SIU_IRQ_PSC6
0073 };
0074
0075 static int mpc5200_psc_irqname_to_minor(int name) {
0076 int minor;
0077 uint8_t *chrptr;
0078
0079 chrptr = memchr(psc_minor_to_irqname, name, sizeof(psc_minor_to_irqname));
0080 if (chrptr != NULL) {
0081 minor = chrptr - psc_minor_to_irqname;
0082 } else {
0083 minor = -1;
0084 }
0085 return minor;
0086 }
0087 #endif
0088
0089 static void A_BSP_output_char(char c);
0090 static int A_BSP_get_char(void);
0091 BSP_output_char_function_type BSP_output_char = A_BSP_output_char;
0092
0093 BSP_polling_getchar_function_type BSP_poll_char = A_BSP_get_char;
0094
0095
0096 bool console_initialized = false;
0097
0098
0099 struct per_channel_info {
0100 uint16_t shadow_imr;
0101 uint8_t shadow_mode1;
0102 uint8_t shadow_mode2;
0103 int cur_tx_len;
0104 int rx_interrupts;
0105 int tx_interrupts;
0106 int rx_characters;
0107 int tx_characters;
0108 int breaks_detected;
0109 int framing_errors;
0110 int parity_errors;
0111 int overrun_errors;
0112 };
0113
0114
0115 struct per_channel_info channel_info[NUM_PORTS];
0116
0117
0118
0119
0120
0121 uint8_t psc_minor_to_regset[MPC5200_PSC_NO] = {0,1,2,3,4,6};
0122
0123
0124 struct rtems_termios_tty *ttyp[NUM_PORTS];
0125
0126 static int mpc5200_psc_setAttributes(
0127 int minor,
0128 const struct termios *t
0129 )
0130 {
0131 int baud;
0132 uint8_t csize=0, cstopb, parenb, parodd;
0133 struct mpc5200_psc *psc =
0134 (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0135
0136
0137 baud = rtems_termios_baud_to_number(t->c_ospeed);
0138 if (baud > 0) {
0139
0140
0141
0142
0143 baud = (IPB_CLOCK + baud *16) / (baud * 32);
0144 }
0145
0146
0147 switch ( t->c_cflag & CSIZE ) {
0148 case CS5: csize = 0x00; break;
0149 case CS6: csize = 0x01; break;
0150 case CS7: csize = 0x02; break;
0151 case CS8: csize = 0x03; break;
0152 }
0153
0154
0155 if(csize == 0) {
0156 if(t->c_cflag & CSTOPB)
0157 cstopb = 0x0F;
0158 else
0159 cstopb = 0x00;
0160 } else {
0161 if(t->c_cflag & CSTOPB)
0162 cstopb = 0x0F;
0163 else
0164 cstopb = 0x07;
0165 }
0166
0167
0168 if (t->c_cflag & PARENB)
0169 parenb = 0x00;
0170 else
0171 parenb = 0x10;
0172
0173 if (t->c_cflag & PARODD)
0174 parodd = 0x04;
0175 else
0176 parodd = 0x00;
0177
0178
0179
0180
0181 psc->ctur = (uint8_t) (baud >> 8);
0182
0183
0184
0185
0186 psc->ctlr = (uint8_t) baud;
0187
0188
0189
0190
0191 psc->cr = ((1 << 4) << 8);
0192
0193
0194
0195
0196 channel_info[minor].shadow_mode1 &= ~(0x1F);
0197 psc->mr = channel_info[minor].shadow_mode1 | (csize | parenb | parodd);
0198
0199
0200
0201
0202 channel_info[minor].shadow_mode2 &= ~(0x0F);
0203 psc->mr = channel_info[minor].shadow_mode2 | cstopb;
0204
0205 return 0;
0206
0207 }
0208
0209
0210 static int mpc5200_uart_setAttributes(int minor, const struct termios *t)
0211 {
0212
0213
0214
0215 if( (minor < PSC1_MINOR) || (minor > NUM_PORTS-1) )
0216 return 0;
0217
0218 return mpc5200_psc_setAttributes(minor, t);
0219
0220 }
0221
0222 #ifdef UARTS_USE_TERMIOS_INT
0223
0224
0225
0226 static void mpc5200_psc_interrupt_handler(rtems_irq_hdl_param handle)
0227 {
0228 unsigned char c;
0229 uint16_t isr;
0230 int minor = (int)handle;
0231 struct mpc5200_psc *psc =
0232 (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0233
0234
0235
0236
0237 isr = psc->isr_imr;
0238
0239
0240
0241
0242 if (isr & ISR_RX_RDY_FULL) {
0243
0244 channel_info[minor].rx_interrupts++;
0245
0246
0247 #ifndef SINGLE_CHAR_MODE
0248 while(psc->rfnum) {
0249 #endif
0250
0251
0252
0253 c = (psc->rb_tb >> 24);
0254
0255 if (ttyp[minor] != NULL) {
0256 rtems_termios_enqueue_raw_characters(
0257 (void *)ttyp[minor], (char *)&c, (int)1);
0258 channel_info[minor].rx_characters++;
0259 }
0260
0261 #ifndef SINGLE_CHAR_MODE
0262 }
0263 #endif
0264
0265 }
0266
0267
0268
0269
0270 if (isr & ISR_TX_RDY & channel_info[minor].shadow_imr) {
0271 channel_info[minor].tx_interrupts++;
0272
0273 if (ttyp[minor] != NULL) {
0274 #ifndef SINGLE_CHAR_MODE
0275 rtems_termios_dequeue_characters(
0276 (void *)ttyp[minor], channel_info[minor].cur_tx_len);
0277 channel_info[minor].tx_characters += channel_info[minor].cur_tx_len;
0278 #else
0279 rtems_termios_dequeue_characters((void *)ttyp[minor], (int)1);
0280 channel_info[minor].tx_characters++;
0281 #endif
0282 }
0283 }
0284
0285 if(isr & ISR_ERROR) {
0286 if(isr & ISR_RB)
0287 channel_info[minor].breaks_detected++;
0288 if(isr & ISR_FE)
0289 channel_info[minor].framing_errors++;
0290 if(isr & ISR_PE)
0291 channel_info[minor].parity_errors++;
0292 if(isr & ISR_OE)
0293 channel_info[minor].overrun_errors++;
0294
0295
0296
0297
0298 psc->cr = ((4 << 4) << 8);
0299 }
0300 }
0301
0302 static void mpc5200_psc_enable(
0303 const rtems_irq_connect_data* ptr
0304 )
0305 {
0306 struct mpc5200_psc *psc;
0307 int minor = mpc5200_psc_irqname_to_minor(ptr->name);
0308
0309 if (minor >= 0) {
0310 psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0311 psc->isr_imr = channel_info[minor].shadow_imr |=
0312 (IMR_RX_RDY_FULL | IMR_TX_RDY);
0313 }
0314 }
0315
0316
0317 static void mpc5200_psc_disable(
0318 const rtems_irq_connect_data* ptr
0319 )
0320 {
0321 struct mpc5200_psc *psc;
0322 int minor = mpc5200_psc_irqname_to_minor(ptr->name);
0323
0324 if (minor >= 0) {
0325 psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0326 psc->isr_imr = channel_info[minor].shadow_imr &=
0327 ~(IMR_RX_RDY_FULL | IMR_TX_RDY);
0328 }
0329 }
0330
0331 static int mpc5200_psc_isOn(
0332 const rtems_irq_connect_data* ptr
0333 )
0334 {
0335 struct mpc5200_psc *psc;
0336 int minor = mpc5200_psc_irqname_to_minor(ptr->name);
0337
0338 if (minor >= 0) {
0339 psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0340 return ((psc->isr_imr & IMR_RX_RDY_FULL) & (psc->isr_imr & IMR_TX_RDY));
0341 }
0342 return false;
0343 }
0344
0345
0346 static rtems_irq_connect_data consoleIrqData;
0347 #endif
0348
0349 static void mpc5200_uart_psc_initialize(
0350 int minor
0351 )
0352 {
0353 uint32_t baud_divider;
0354 struct mpc5200_psc *psc =
0355 (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0356
0357
0358
0359
0360 if ((minor < PSC1_MINOR) || (minor >= (PSC1_MINOR + NUM_PORTS)))
0361 return;
0362
0363
0364
0365
0366 memset((void *)&channel_info[minor], 0, sizeof(struct per_channel_info));
0367
0368
0369
0370
0371 psc->cr = ((2 << 4) << 8);
0372 psc->cr = ((3 << 4) << 8);
0373
0374
0375
0376
0377 psc->cr = ((1 << 4) << 8);
0378
0379
0380
0381
0382 psc->sr_csr = 0;
0383
0384
0385
0386
0387 psc->mr = channel_info[minor].shadow_mode1 = 0x33;
0388
0389
0390
0391
0392 psc->mr = channel_info[minor].shadow_mode2 = 7;
0393
0394
0395
0396
0397 psc->rfalarm = RX_FIFO_SIZE - 1;
0398
0399
0400
0401
0402 psc->tfalarm = 1;
0403
0404 baud_divider =
0405 (IPB_CLOCK + GEN5200_CONSOLE_BAUD *16) / (GEN5200_CONSOLE_BAUD * 32);
0406
0407
0408
0409
0410 psc->ctur = baud_divider >> 16;
0411
0412
0413
0414
0415
0416 psc->ctlr = baud_divider & 0x0000ffff;
0417
0418
0419
0420
0421 psc->tfcntl = 0;
0422
0423 #ifdef UARTS_USE_TERMIOS_INT
0424
0425
0426
0427 consoleIrqData.on = mpc5200_psc_enable;
0428 consoleIrqData.off = mpc5200_psc_disable;
0429 consoleIrqData.isOn = mpc5200_psc_isOn;
0430 consoleIrqData.handle = (rtems_irq_hdl_param)minor;
0431 consoleIrqData.hdl = (rtems_irq_hdl)mpc5200_psc_interrupt_handler;
0432
0433
0434
0435
0436 consoleIrqData.name = psc_minor_to_irqname[minor];
0437
0438
0439
0440
0441 assert(BSP_install_rtems_irq_handler(&consoleIrqData) == 1);
0442 #endif
0443
0444
0445
0446
0447 psc->rfstat |= 0x70;
0448
0449
0450
0451
0452 psc->tfstat |= 0x70;
0453
0454 #ifdef UARTS_USE_TERMIOS_INT
0455
0456
0457
0458 psc->isr_imr = channel_info[minor].shadow_imr = IMR_RX_RDY_FULL;
0459 #endif
0460
0461
0462
0463
0464 psc->cr = ((1 << 0) << 8);
0465
0466
0467
0468
0469 psc->cr = ((1 << 2) << 8);
0470 }
0471
0472
0473 static int mpc5200_uart_pollRead(
0474 int minor
0475 )
0476 {
0477 unsigned char c;
0478 struct mpc5200_psc *psc =
0479 (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0480
0481 if (psc->sr_csr & (1 << 8))
0482 c = (psc->rb_tb >> 24);
0483 else
0484 return -1;
0485
0486 return c;
0487 }
0488
0489
0490 static ssize_t mpc5200_uart_pollWrite(
0491 int minor,
0492 const char *buf,
0493 size_t len
0494 )
0495 {
0496 size_t retval = len;
0497 const char *tmp_buf = buf;
0498 struct mpc5200_psc *psc =
0499 (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0500
0501 while(len--) {
0502 while(!(psc->sr_csr & (1 << 11)))
0503 continue;
0504
0505
0506
0507 psc->rb_tb = (*tmp_buf << 24);
0508
0509 tmp_buf++;
0510
0511 }
0512 return retval;
0513
0514 }
0515
0516 static ssize_t mpc5200_uart_write(
0517 int minor,
0518 const char *buf,
0519 size_t len
0520 )
0521 {
0522 struct mpc5200_psc *psc =
0523 (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0524
0525 if (len > 0) {
0526 int frame_len = len;
0527 const char *frame_buf = buf;
0528
0529
0530
0531
0532 if(len > (TX_FIFO_SIZE - psc->tfnum))
0533 frame_len = TX_FIFO_SIZE - psc->tfnum;
0534
0535 #ifndef SINGLE_CHAR_MODE
0536 channel_info[minor].cur_tx_len = frame_len;
0537 #else
0538 frame_len = 1;
0539 #endif
0540
0541
0542
0543 while (frame_len--)
0544
0545 (* (volatile char *)&(psc->rb_tb)) = *frame_buf++;
0546
0547
0548
0549
0550 psc->isr_imr = channel_info[minor].shadow_imr |= IMR_TX_RDY;
0551 } else {
0552
0553
0554
0555 psc->isr_imr = channel_info[minor].shadow_imr &= ~(IMR_TX_RDY);
0556 }
0557
0558 return 0;
0559 }
0560
0561
0562
0563
0564 static void A_BSP_output_char(
0565 char c
0566 )
0567 {
0568
0569
0570
0571
0572 #if !defined(HAS_UBOOT)
0573 if (console_initialized == false)
0574 return;
0575 #endif
0576
0577 #define PRINTK_WRITE mpc5200_uart_pollWrite
0578
0579 PRINTK_WRITE(PRINTK_MINOR, &c, 1 );
0580 }
0581
0582 static int A_BSP_get_char(void)
0583 {
0584
0585
0586
0587
0588 #if !defined(HAS_UBOOT)
0589 if (console_initialized == false)
0590 return -1;
0591 #endif
0592
0593 return mpc5200_uart_pollRead(0);
0594 }
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607 rtems_device_driver console_initialize(
0608 rtems_device_major_number major,
0609 rtems_device_minor_number minor,
0610 void *arg
0611 )
0612 {
0613 rtems_status_code status;
0614 rtems_device_minor_number console_minor;
0615 char dev_name[] = "/dev/ttyx";
0616 uint32_t tty_num = 0;
0617 bool first = true;
0618
0619
0620
0621
0622 console_minor = PSC1_MINOR;
0623 rtems_termios_initialize();
0624
0625 for (console_minor = PSC1_MINOR;
0626 console_minor < PSC1_MINOR + NUM_PORTS;
0627 console_minor++) {
0628
0629
0630
0631 if (0 != ((1 << console_minor) & (mpc5200_uart_avail_mask))) {
0632
0633
0634
0635 mpc5200_uart_psc_initialize(console_minor);
0636 dev_name[8] = '0' + tty_num;
0637 status = rtems_io_register_name (dev_name, major, console_minor);
0638 assert(status == RTEMS_SUCCESSFUL);
0639
0640 #ifdef MPC5200_PSC_INDEX_FOR_GPS_MODULE
0641 if (console_minor == MPC5200_PSC_INDEX_FOR_GPS_MODULE) {
0642 status = rtems_io_register_name("/dev/gps", major, console_minor);
0643 assert(status == RTEMS_SUCCESSFUL);
0644 }
0645 #endif
0646
0647 if (first) {
0648 first = false;
0649
0650
0651 status = rtems_io_register_name ("/dev/console", major, console_minor);
0652 assert(status == RTEMS_SUCCESSFUL);
0653 }
0654
0655 tty_num++;
0656 }
0657 }
0658
0659 console_initialized = true;
0660 return RTEMS_SUCCESSFUL;
0661 }
0662
0663
0664
0665
0666 rtems_device_driver console_open(
0667 rtems_device_major_number major,
0668 rtems_device_minor_number minor,
0669 void *arg
0670 )
0671 {
0672 rtems_libio_open_close_args_t *args = arg;
0673 rtems_status_code sc;
0674
0675 #ifdef UARTS_USE_TERMIOS_INT
0676 static const rtems_termios_callbacks intrCallbacks = {
0677 NULL,
0678 NULL,
0679 NULL,
0680 mpc5200_uart_write,
0681 mpc5200_uart_setAttributes,
0682 NULL,
0683 NULL,
0684 TERMIOS_IRQ_DRIVEN
0685 };
0686 #else
0687 static const rtems_termios_callbacks pollCallbacks = {
0688 NULL,
0689 NULL,
0690 mpc5200_uart_pollRead,
0691 mpc5200_uart_pollWrite,
0692 mpc5200_uart_setAttributes,
0693 NULL,
0694 NULL,
0695 TERMIOS_POLLED
0696 };
0697 #endif
0698
0699 if(minor > NUM_PORTS - 1)
0700 return RTEMS_INVALID_NUMBER;
0701
0702 #ifdef UARTS_USE_TERMIOS_INT
0703 sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
0704 #else
0705 sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
0706 #endif
0707
0708 ttyp[minor] = args->iop->data1;
0709
0710 if ( !sc )
0711 rtems_termios_set_initial_baud( ttyp[minor], GEN5200_CONSOLE_BAUD );
0712
0713 return sc;
0714 }
0715
0716
0717
0718
0719
0720 rtems_device_driver console_close(
0721 rtems_device_major_number major,
0722 rtems_device_minor_number minor,
0723 void *arg
0724 )
0725 {
0726 if ( minor > NUM_PORTS-1 )
0727 return RTEMS_INVALID_NUMBER;
0728
0729 ttyp[minor] = NULL;
0730
0731 return rtems_termios_close( arg );
0732 }
0733
0734
0735
0736
0737
0738 rtems_device_driver console_read(
0739 rtems_device_major_number major,
0740 rtems_device_minor_number minor,
0741 void *arg
0742 )
0743 {
0744 if(minor > NUM_PORTS-1)
0745 return RTEMS_INVALID_NUMBER;
0746
0747 return rtems_termios_read(arg);
0748 }
0749
0750
0751
0752
0753 rtems_device_driver console_write(
0754 rtems_device_major_number major,
0755 rtems_device_minor_number minor,
0756 void *arg
0757 )
0758 {
0759 if ( minor > NUM_PORTS-1 )
0760 return RTEMS_INVALID_NUMBER;
0761 return rtems_termios_write(arg);
0762 }
0763
0764
0765
0766
0767 rtems_device_driver console_control(
0768 rtems_device_major_number major,
0769 rtems_device_minor_number minor,
0770 void *arg
0771 )
0772 {
0773 if ( minor > NUM_PORTS-1 )
0774 return RTEMS_INVALID_NUMBER;
0775
0776 return rtems_termios_ioctl(arg);
0777 }