Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:56

0001 /*
0002  *  General Serial I/O functions.
0003  *
0004  *  This file contains the functions for performing serial I/O.
0005  *  The actual system calls (console_*) should be in the BSP part
0006  *  of the source tree. That way different BSPs can use whichever
0007  *  SMCs and SCCs they want. Originally, all the stuff was in
0008  *  this file, and it caused problems with one BSP using SCC2
0009  *  as /dev/console, others using SMC1 for /dev/console, etc.
0010  *
0011  *  On-chip resources used:
0012  *   resource   minor                note
0013  *    SMC1       0
0014  *    SMC2       1
0015  *    SCC1       2
0016  *    SCC2       3
0017  *    SCC3       4
0018  *    SCC4       5
0019  *    BRG1
0020  *    BRG2
0021  *    BRG3
0022  *    BRG4
0023  */
0024 
0025 /*
0026  *  Author: Jay Monkman (jmonkman@frasca.com)
0027  *  Copyright (C) 1998 by Frasca International, Inc.
0028  *
0029  *  Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by:
0030  *    Eric Norum <eric.norum.ca>
0031  *
0032  *  COPYRIGHT (c) 1989-1998.
0033  *  On-Line Applications Research Corporation (OAR).
0034  *
0035  *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
0036  *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
0037  *  Copyright (c) 1999, National Research Council of Canada
0038  *
0039  *  Copyright (c) 2001, Surrey Satellite Technology Ltd
0040  *    SCC1 and SSC2 are used on MPC8260ADS board
0041  *    SMCs are unused
0042  *
0043  *  The license and distribution terms for this file may be
0044  *  found in the file LICENSE in this distribution or at
0045  *  http://www.rtems.org/license/LICENSE.
0046  */
0047 
0048 #include <bsp.h>
0049 #include <rtems/libio.h>
0050 #include <mpc8260.h>
0051 #include <mpc8260/console.h>
0052 #include <mpc8260/cpm.h>
0053 #include <stdlib.h>
0054 #include <unistd.h>
0055 #include <termios.h>
0056 #include <bsp/irq.h>
0057 #include <rtems/bspIo.h>   /* for printk */
0058 
0059 /*
0060  * Interrupt-driven input buffer
0061  */
0062 #define RXBUFSIZE       16
0063 
0064 /*
0065  *  I/O buffers and pointers to buffer descriptors.
0066  *  Currently, single buffered input is done. This will work only
0067  *  if the Rx interrupts are serviced quickly.
0068  *
0069  *  TODO: Add a least double buffering for safety.
0070  */
0071 static volatile char rxBuf[NUM_PORTS][RXBUFSIZE];
0072 static volatile char txBuf[NUM_PORTS];
0073 
0074 /* SCC/SMC buffer descriptors */
0075 static volatile m8260BufferDescriptor_t *RxBd[NUM_PORTS], *TxBd[NUM_PORTS];
0076 
0077 /* Used to track termios private data for callbacks */
0078 struct rtems_termios_tty *ttyp[NUM_PORTS];
0079 
0080 #if 0
0081 /* Used to record previous ISR */
0082 static rtems_isr_entry old_handler[NUM_PORTS];
0083 #endif
0084 
0085 /*
0086  * Device-specific routines
0087  */
0088 static int m8xx_smc_set_attributes(int, const struct termios*);
0089 static int m8xx_scc_set_attributes(int, const struct termios*);
0090 static rtems_isr m8xx_smc1_interrupt_handler(rtems_irq_hdl_param unused);
0091 static rtems_isr m8xx_smc2_interrupt_handler(rtems_irq_hdl_param unused);
0092 static rtems_isr m8xx_scc1_interrupt_handler(rtems_irq_hdl_param unused);
0093 static rtems_isr m8xx_scc2_interrupt_handler(rtems_irq_hdl_param unused);
0094 static rtems_isr m8xx_scc3_interrupt_handler(rtems_irq_hdl_param unused);
0095 static rtems_isr m8xx_scc4_interrupt_handler(rtems_irq_hdl_param unused);
0096 
0097 /*
0098  * Hardware-dependent portion of tcsetattr().
0099  */
0100 static int
0101 m8xx_smc_set_attributes (int minor, const struct termios *t)
0102 {
0103   int baud, brg=0, csize=0, ssize, psize;
0104   uint16_t   clen=0, cstopb, parenb, parodd, cread;
0105 
0106   /* Baud rate */
0107   switch (t->c_ospeed) {
0108   default:      baud = -1;      break;
0109   case B50:     baud = 50;      break;
0110   case B75:     baud = 75;      break;
0111   case B110:    baud = 110;     break;
0112   case B134:    baud = 134;     break;
0113   case B150:    baud = 150;     break;
0114   case B200:    baud = 200;     break;
0115   case B300:    baud = 300;     break;
0116   case B600:    baud = 600;     break;
0117   case B1200:   baud = 1200;    break;
0118   case B1800:   baud = 1800;    break;
0119   case B2400:   baud = 2400;    break;
0120   case B4800:   baud = 4800;    break;
0121   case B9600:   baud = 9600;    break;
0122   case B19200:  baud = 19200;   break;
0123   case B38400:  baud = 38400;   break;
0124   case B57600:  baud = 57600;   break;
0125   case B115200: baud = 115200;  break;
0126   case B230400: baud = 230400;  break;
0127   case B460800: baud = 460800;  break;
0128   }
0129   if (baud > 0) {
0130    switch( minor ) {
0131       case SMC1_MINOR:
0132         /* SMC1 can only choose between BRG1 and 7 */
0133         brg = m8xx_get_brg( M8260_SMC1_BRGS, baud*16 ) + 1;
0134     m8260.cmxsmr &= ~0x30;
0135     m8260.cmxsmr |= (brg==1? 0x00: 0x10 );
0136         break;
0137       case SMC2_MINOR:
0138         /* SMC2 can only choose between BRG2 and 8 */
0139     brg = m8xx_get_brg(  M8260_SMC2_BRGS, baud*16 ) + 1;
0140     m8260.cmxsmr &= ~0x30;
0141     m8260.cmxsmr |= (brg==2? 0x00: 0x01 );
0142         break;
0143     }
0144   }
0145 
0146   /* Number of data bits */
0147   switch ( t->c_cflag & CSIZE ) {
0148     case CS5:     csize = 5;       break;
0149     case CS6:     csize = 6;       break;
0150     case CS7:     csize = 7;       break;
0151     case CS8:     csize = 8;       break;
0152   }
0153 
0154   /* Stop bits */
0155   if ( t->c_cflag & CSTOPB ) {
0156     cstopb = 0x0400;              /* Two stop bits */
0157     ssize  = 2;
0158   } else {
0159     cstopb = 0x0000;              /* One stop bit */
0160     ssize  = 1;
0161   }
0162 
0163   /* Parity */
0164   if ( t->c_cflag & PARENB ) {
0165     parenb = 0x0200;              /* Parity enabled on Tx and Rx */
0166     psize  = 1;
0167   } else {
0168     parenb = 0x0000;              /* No parity on Tx and Rx */
0169     psize  = 0;
0170   }
0171 
0172   if ( t->c_cflag & PARODD )
0173     parodd = 0x0000;              /* Odd parity */
0174   else
0175     parodd = 0x0100;
0176 
0177   /*
0178    * Character Length = start + data + parity + stop - 1
0179    */
0180   switch ( 1 + csize + psize + ssize - 1 ) {
0181     case 6:     clen = 0x3000;       break;
0182     case 7:     clen = 0x3800;       break;
0183     case 8:     clen = 0x4000;       break;
0184     case 9:     clen = 0x4800;       break;
0185     case 10:    clen = 0x5000;       break;
0186     case 11:    clen = 0x5800;       break;
0187   }
0188 
0189   if ( t->c_cflag & CREAD )
0190     cread = 0x0023;     /* UART normal operation, enable Rx and Tx */
0191   else
0192     cread = 0x0021;     /* UART normal operation, enable Tx */
0193 
0194   /* Write the SIMODE/SMCMR registers */
0195   switch (minor) {
0196     case SMC1_MINOR:
0197 /*
0198       m8xx.simode = ( (m8xx.simode & 0xffff8fff) | (brg << 12) );
0199 */
0200       m8260.smc1.smcmr = clen | cstopb | parenb | parodd | cread;
0201       break;
0202     case SMC2_MINOR:
0203       /* CHECK THIS */
0204 /*
0205       m8xx.simode = ( (m8xx.simode & 0x8fffffff) | (brg << 28) );
0206 */
0207       m8260.smc2.smcmr = clen | cstopb | parenb | parodd | cread;
0208       break;
0209   }
0210   return 0;
0211 }
0212 
0213 static int
0214 m8xx_scc_set_attributes (int minor, const struct termios *t)
0215 {
0216   int baud, brg=0;
0217   uint16_t   csize=0, cstopb, parenb, parodd;
0218 
0219   /* Baud rate */
0220   switch (t->c_ospeed) {
0221   default:      baud = -1;      break;
0222   case B50:     baud = 50;      break;
0223   case B75:     baud = 75;      break;
0224   case B110:    baud = 110;     break;
0225   case B134:    baud = 134;     break;
0226   case B150:    baud = 150;     break;
0227   case B200:    baud = 200;     break;
0228   case B300:    baud = 300;     break;
0229   case B600:    baud = 600;     break;
0230   case B1200:   baud = 1200;    break;
0231   case B1800:   baud = 1800;    break;
0232   case B2400:   baud = 2400;    break;
0233   case B4800:   baud = 4800;    break;
0234   case B9600:   baud = 9600;    break;
0235   case B19200:  baud = 19200;   break;
0236   case B38400:  baud = 38400;   break;
0237   case B57600:  baud = 57600;   break;
0238   case B115200: baud = 115200;  break;
0239   case B230400: baud = 230400;  break;
0240   case B460800: baud = 460800;  break;
0241   }
0242   if (baud > 0) {
0243     brg = m8xx_get_brg( M8260_SCC_BRGS, baud*16 );
0244     m8260.cmxscr &= ~(0xFF000000 >> (8*(minor-SCC1_MINOR)) );
0245     m8260.cmxscr |= ((brg<<(3+8*(3-(minor-SCC1_MINOR)))) &
0246              (brg<<(8*(3-(minor-SCC1_MINOR)))));
0247   }
0248   /* Number of data bits */
0249   switch ( t->c_cflag & CSIZE ) {
0250     case CS5:     csize = 0x0000;       break;
0251     case CS6:     csize = 0x1000;       break;
0252     case CS7:     csize = 0x2000;       break;
0253     case CS8:     csize = 0x3000;       break;
0254   }
0255 
0256   /* Stop bits */
0257   if ( t->c_cflag & CSTOPB )
0258     cstopb = 0x4000;              /* Two stop bits */
0259   else
0260     cstopb = 0x0000;              /* One stop bit */
0261 
0262   /* Parity */
0263   if ( t->c_cflag & PARENB )
0264     parenb = 0x0010;              /* Parity enabled on Tx and Rx */
0265   else
0266     parenb = 0x0000;              /* No parity on Tx and Rx */
0267 
0268   if ( t->c_cflag & PARODD )
0269     parodd = 0x0000;              /* Odd parity */
0270   else
0271     parodd = 0x000a;
0272 
0273   /* Write the SICR/PSMR Registers */
0274   switch (minor) {
0275     case SCC1_MINOR:
0276 /*
0277       m8xx.sicr = ( (m8xx.sicr & 0xffffc0ff) | (brg << 11) | (brg << 8) );
0278 */
0279       m8260.scc1.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc1.psmr & 0x8fe0) );
0280       break;
0281     case SCC2_MINOR:
0282 /*
0283       m8xx.sicr = ( (m8xx.sicr & 0xffffc0ff) | (brg << 11) | (brg << 8) );
0284 */
0285       m8260.scc2.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc2.psmr & 0x8fe0) );
0286       break;
0287     case SCC3_MINOR:
0288 /*
0289       m8xx.sicr = ( (m8xx.sicr & 0xffc0ffff) | (brg << 19) | (brg << 16) );
0290 */
0291       m8260.scc3.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc3.psmr & 0x8fe0) );
0292       break;
0293     case SCC4_MINOR:
0294 /*
0295       m8xx.sicr = ( (m8xx.sicr & 0xc0ffffff) | (brg << 27) | (brg << 24) );
0296 */
0297       m8260.scc4.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc4.psmr & 0x8fe0) );
0298       break;
0299   }
0300 
0301   return 0;
0302 }
0303 
0304 int
0305 m8xx_uart_setAttributes(
0306   int minor,
0307   const struct termios *t
0308 )
0309 {
0310   /*
0311    * Check that port number is valid
0312    */
0313   if ( (minor < SMC1_MINOR) || (minor > NUM_PORTS-1) )
0314     return 0;
0315 
0316   switch (minor) {
0317     case SMC1_MINOR:
0318     case SMC2_MINOR:
0319       return m8xx_smc_set_attributes( minor, t );
0320 
0321     case SCC1_MINOR:
0322     case SCC2_MINOR:
0323     case SCC3_MINOR:
0324     case SCC4_MINOR:
0325       return m8xx_scc_set_attributes( minor, t );
0326   }
0327   return 0;
0328 }
0329 
0330 /*
0331  * Interrupt handlers
0332  */
0333 static void
0334 m8xx_scc1_interrupt_handler (rtems_irq_hdl_param unused)
0335 {
0336   /*
0337    * Buffer received?
0338    */
0339   if ((m8260.scc1.sccm & M8260_SCCE_RX) && (m8260.scc1.scce & M8260_SCCE_RX)) {
0340     m8260.scc1.scce = M8260_SCCE_RX;    /* Clear the event */
0341 
0342 
0343     /* Check that the buffer is ours */
0344     if ((RxBd[SCC1_MINOR]->status & M8260_BD_EMPTY) == 0) {
0345       rtems_cache_invalidate_multiple_data_lines(
0346         (const void *) RxBd[SCC1_MINOR]->buffer,
0347         RxBd[SCC1_MINOR]->length );
0348       rtems_termios_enqueue_raw_characters(
0349         (void *)ttyp[SCC1_MINOR],
0350         (char *)RxBd[SCC1_MINOR]->buffer,
0351         (int)RxBd[SCC1_MINOR]->length );
0352       RxBd[SCC1_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
0353                                  M8260_BD_INTERRUPT;
0354     }
0355   }
0356 
0357   /*
0358    * Buffer transmitted?
0359    */
0360   if (m8260.scc1.scce & M8260_SCCE_TX) {
0361     m8260.scc1.scce = M8260_SCCE_TX;  /* Clear the event */
0362 
0363     /* Check that the buffer is ours */
0364     if ((TxBd[SCC1_MINOR]->status & M8260_BD_READY) == 0)
0365       rtems_termios_dequeue_characters (
0366         (void *)ttyp[SCC1_MINOR],
0367         (int)TxBd[SCC1_MINOR]->length);
0368   }
0369 
0370 #if 0
0371   m8260.sipnr_l |= M8260_SIMASK_SCC1;      /* Clear pending register */
0372 #endif
0373 }
0374 
0375 static void
0376 m8xx_scc2_interrupt_handler (rtems_irq_hdl_param unused)
0377 {
0378   /*
0379    * Buffer received?
0380    */
0381   if ((m8260.scc2.sccm & M8260_SCCE_RX) && (m8260.scc2.scce & M8260_SCCE_RX)) {
0382     m8260.scc2.scce = M8260_SCCE_RX;    /* Clear the event */
0383 
0384 
0385     /* Check that the buffer is ours */
0386     if ((RxBd[SCC2_MINOR]->status & M8260_BD_EMPTY) == 0) {
0387       rtems_cache_invalidate_multiple_data_lines(
0388         (const void *) RxBd[SCC2_MINOR]->buffer,
0389         RxBd[SCC2_MINOR]->length );
0390       rtems_termios_enqueue_raw_characters(
0391         (void *)ttyp[SCC2_MINOR],
0392         (char *)RxBd[SCC2_MINOR]->buffer,
0393         (int)RxBd[SCC2_MINOR]->length );
0394       RxBd[SCC2_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
0395                                  M8260_BD_INTERRUPT;
0396     }
0397   }
0398 
0399   /*
0400    * Buffer transmitted?
0401    */
0402   if (m8260.scc2.scce & M8260_SCCE_TX) {
0403     m8260.scc2.scce = M8260_SCCE_TX;  /* Clear the event */
0404 
0405     /* Check that the buffer is ours */
0406     if ((TxBd[SCC2_MINOR]->status & M8260_BD_READY) == 0)
0407       rtems_termios_dequeue_characters (
0408         (void *)ttyp[SCC2_MINOR],
0409         (int)TxBd[SCC2_MINOR]->length);
0410   }
0411 
0412 #if 0
0413   m8260.sipnr_l |= M8260_SIMASK_SCC2;      /* Clear pending register */
0414 #endif
0415 }
0416 
0417 static void
0418 m8xx_scc3_interrupt_handler (rtems_irq_hdl_param unused)
0419 {
0420   /*
0421    * Buffer received?
0422    */
0423   if ((m8260.scc3.sccm & M8260_SCCE_RX) && (m8260.scc3.scce & M8260_SCCE_RX)) {
0424     m8260.scc3.scce = M8260_SCCE_RX;  /* Clear the event */
0425 
0426 
0427     /* Check that the buffer is ours */
0428     if ((RxBd[SCC3_MINOR]->status & M8260_BD_EMPTY) == 0) {
0429       rtems_cache_invalidate_multiple_data_lines(
0430         (const void *) RxBd[SCC3_MINOR]->buffer,
0431         RxBd[SCC3_MINOR]->length );
0432       rtems_termios_enqueue_raw_characters(
0433         (void *)ttyp[SCC3_MINOR],
0434         (char *)RxBd[SCC3_MINOR]->buffer,
0435         (int)RxBd[SCC3_MINOR]->length );
0436       RxBd[SCC3_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
0437                                  M8260_BD_INTERRUPT;
0438     }
0439   }
0440 
0441   /*
0442    * Buffer transmitted?
0443    */
0444   if (m8260.scc3.scce & M8260_SCCE_TX) {
0445     m8260.scc3.scce = M8260_SCCE_TX;    /* Clear the event */
0446 
0447     /* Check that the buffer is ours */
0448     if ((TxBd[SCC3_MINOR]->status & M8260_BD_READY) == 0)
0449       rtems_termios_dequeue_characters (
0450         (void *)ttyp[SCC3_MINOR],
0451         (int)TxBd[SCC3_MINOR]->length);
0452   }
0453 
0454 
0455 #if 0
0456   m8260.sipnr_l |= M8260_SIMASK_SCC3;      /* Clear pending register */
0457 #endif
0458 }
0459 
0460 static void
0461 m8xx_scc4_interrupt_handler (rtems_irq_hdl_param unused)
0462 {
0463   /*
0464    * Buffer received?
0465    */
0466   if ((m8260.scc4.sccm & M8260_SCCE_RX) && (m8260.scc4.scce & M8260_SCCE_RX)) {
0467     m8260.scc4.scce = M8260_SCCE_RX;  /* Clear the event */
0468 
0469 
0470     /* Check that the buffer is ours */
0471     if ((RxBd[SCC4_MINOR]->status & M8260_BD_EMPTY) == 0) {
0472       rtems_cache_invalidate_multiple_data_lines(
0473         (const void *) RxBd[SCC4_MINOR]->buffer,
0474         RxBd[SCC4_MINOR]->length );
0475       rtems_termios_enqueue_raw_characters(
0476         (void *)ttyp[SCC4_MINOR],
0477         (char *)RxBd[SCC4_MINOR]->buffer,
0478         (int)RxBd[SCC4_MINOR]->length );
0479       RxBd[SCC4_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
0480                                  M8260_BD_INTERRUPT;
0481     }
0482   }
0483 
0484   /*
0485    * Buffer transmitted?
0486    */
0487   if (m8260.scc4.scce & M8260_SCCE_TX) {
0488     m8260.scc4.scce = M8260_SCCE_TX;    /* Clear the event */
0489 
0490     /* Check that the buffer is ours */
0491     if ((TxBd[SCC4_MINOR]->status & M8260_BD_READY) == 0)
0492       rtems_termios_dequeue_characters (
0493         (void *)ttyp[SCC4_MINOR],
0494         (int)TxBd[SCC4_MINOR]->length);
0495   }
0496 
0497 #if 0
0498   m8260.sipnr_l |= M8260_SIMASK_SCC4;      /* Clear pending register */
0499 #endif
0500 }
0501 
0502 static void
0503 m8xx_smc1_interrupt_handler (rtems_irq_hdl_param unused)
0504 {
0505   /*
0506    * Buffer received?
0507    */
0508   if (m8260.smc1.smce & M8260_SMCE_RX) {
0509     m8260.smc1.smce = M8260_SMCE_RX;  /* Clear the event */
0510 
0511 
0512     /* Check that the buffer is ours */
0513     if ((RxBd[SMC1_MINOR]->status & M8260_BD_EMPTY) == 0) {
0514       rtems_cache_invalidate_multiple_data_lines(
0515         (const void *) RxBd[SMC1_MINOR]->buffer,
0516         RxBd[SMC1_MINOR]->length );
0517       rtems_termios_enqueue_raw_characters(
0518         (void *)ttyp[SMC1_MINOR],
0519         (char *)RxBd[SMC1_MINOR]->buffer,
0520         (int)RxBd[SMC1_MINOR]->length );
0521       RxBd[SMC1_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
0522                                  M8260_BD_INTERRUPT;
0523     }
0524   }
0525 
0526   /*
0527    * Buffer transmitted?
0528    */
0529   if (m8260.smc1.smce & M8260_SMCE_TX) {
0530     m8260.smc1.smce = M8260_SMCE_TX;    /* Clear the event */
0531 
0532     /* Check that the buffer is ours */
0533     if ((TxBd[SMC1_MINOR]->status & M8260_BD_READY) == 0)
0534       rtems_termios_dequeue_characters (
0535         (void *)ttyp[SMC1_MINOR],
0536         (int)TxBd[SMC1_MINOR]->length);
0537   }
0538 
0539 #if 0
0540   m8260.sipnr_l = 0x00001000; /* Clear SMC1 interrupt-in-service bit */
0541 #endif
0542 }
0543 
0544 static void
0545 m8xx_smc2_interrupt_handler (rtems_irq_hdl_param unused)
0546 {
0547   /*
0548    * Buffer received?
0549    */
0550   if (m8260.smc2.smce & M8260_SMCE_RX) {
0551     m8260.smc2.smce = M8260_SMCE_RX;  /* Clear the event */
0552 
0553 
0554     /* Check that the buffer is ours */
0555     if ((RxBd[SMC2_MINOR]->status & M8260_BD_EMPTY) == 0) {
0556       rtems_cache_invalidate_multiple_data_lines(
0557         (const void *) RxBd[SMC2_MINOR]->buffer,
0558         RxBd[SMC2_MINOR]->length );
0559       rtems_termios_enqueue_raw_characters(
0560         (void *)ttyp[SMC2_MINOR],
0561         (char *)RxBd[SMC2_MINOR]->buffer,
0562         (int)RxBd[SMC2_MINOR]->length );
0563       RxBd[SMC2_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
0564                                  M8260_BD_INTERRUPT;
0565     }
0566   }
0567 
0568   /*
0569    * Buffer transmitted?
0570    */
0571   if (m8260.smc2.smce & M8260_SMCE_TX) {
0572     m8260.smc2.smce = M8260_SMCE_TX;    /* Clear the event */
0573 
0574     /* Check that the buffer is ours */
0575     if ((TxBd[SMC2_MINOR]->status & M8260_BD_READY) == 0)
0576       rtems_termios_dequeue_characters (
0577         (void *)ttyp[SMC2_MINOR],
0578         (int)TxBd[SMC2_MINOR]->length);
0579   }
0580 
0581 #if 0
0582   m8260.sipnr_l = 0x00000800; /* Clear SMC2 interrupt-in-service bit */
0583 #endif
0584 }
0585 
0586 static void m8xx_scc_enable(const rtems_irq_connect_data* ptr)
0587 {
0588   volatile m8260SCCRegisters_t *sccregs = 0;
0589   switch (ptr->name) {
0590   case BSP_CPM_IRQ_SCC4 :
0591     m8260.sipnr_l |= M8260_SIMASK_SCC4;
0592     sccregs = &m8260.scc4;
0593     break;
0594   case BSP_CPM_IRQ_SCC3 :
0595     m8260.sipnr_l |= M8260_SIMASK_SCC3;
0596     sccregs = &m8260.scc3;
0597     break;
0598   case BSP_CPM_IRQ_SCC2 :
0599     m8260.sipnr_l |= M8260_SIMASK_SCC2;
0600     sccregs = &m8260.scc2;
0601     break;
0602   case BSP_CPM_IRQ_SCC1 :
0603     m8260.sipnr_l |= M8260_SIMASK_SCC1;
0604     sccregs = &m8260.scc1;
0605     break;
0606   default:
0607     break;
0608   }
0609   sccregs->sccm = 3;
0610 }
0611 
0612 static void m8xx_scc_disable(const rtems_irq_connect_data* ptr)
0613 {
0614   volatile m8260SCCRegisters_t *sccregs = 0;
0615   switch (ptr->name) {
0616   case BSP_CPM_IRQ_SCC4 :
0617     sccregs = &m8260.scc4;
0618     break;
0619   case BSP_CPM_IRQ_SCC3 :
0620     sccregs = &m8260.scc3;
0621     break;
0622   case BSP_CPM_IRQ_SCC2 :
0623     sccregs = &m8260.scc2;
0624     break;
0625   case BSP_CPM_IRQ_SCC1 :
0626     sccregs = &m8260.scc1;
0627     break;
0628   default:
0629     break;
0630   }
0631   sccregs->sccm &= (~3);
0632 }
0633 
0634 static int m8xx_scc_isOn(const rtems_irq_connect_data* ptr)
0635 {
0636  return BSP_irq_enabled_at_cpm (ptr->name);
0637 }
0638 
0639 static rtems_irq_connect_data consoleIrqData =
0640 {
0641   BSP_CPM_IRQ_SCC1,
0642   (rtems_irq_hdl)m8xx_scc1_interrupt_handler,
0643   NULL,
0644   (rtems_irq_enable) m8xx_scc_enable,
0645   (rtems_irq_disable) m8xx_scc_disable,
0646   (rtems_irq_is_enabled) m8xx_scc_isOn
0647 };
0648 
0649 void
0650 m8xx_uart_scc_initialize (int minor)
0651 {
0652   unsigned char brg;
0653   volatile m8260SCCparms_t *sccparms = 0;
0654   volatile m8260SCCRegisters_t *sccregs = 0;
0655 
0656   /*
0657    * Check that minor number is valid
0658    */
0659   if ( (minor < SCC1_MINOR) || (minor > NUM_PORTS-1) )
0660     return;
0661 
0662   /* Get the sicr clock source bit values for 9600 bps */
0663   brg = m8xx_get_brg(M8260_SCC_BRGS, 9600*16);
0664 
0665   m8260.cmxscr &= ~(0xFF000000 >> (8*(minor-SCC1_MINOR)) );
0666   m8260.cmxscr |= (brg<<(3+8*(3-(minor-SCC1_MINOR))));
0667   m8260.cmxscr |= (brg<<(8*(3-(minor-SCC1_MINOR))));
0668 
0669   /*
0670    * Allocate buffer descriptors
0671    */
0672   RxBd[minor] = m8xx_bd_allocate(1);
0673   TxBd[minor] = m8xx_bd_allocate(1);
0674 
0675   /*
0676    * Configure ports to enable TXDx and RXDx pins
0677    */
0678 
0679   m8260.ppard |=  (0x07 << ((minor-SCC1_MINOR)*3));
0680   m8260.psord &= ~(0x07 << ((minor-SCC1_MINOR)*3));
0681   if( minor == SCC1_MINOR )
0682     m8260.psord |= 0x02;
0683   m8260.pdird |=  (0x06 << ((minor-SCC1_MINOR)*3));
0684   m8260.pdird &= ~(0x01 << ((minor-SCC1_MINOR)*3));
0685 
0686 
0687   /*
0688    * Set up SMC1 parameter RAM common to all protocols
0689    */
0690   if( minor == SCC1_MINOR ) {
0691     sccparms = (m8260SCCparms_t*)&m8260.scc1p;
0692     sccregs  = (m8260SCCRegisters_t*)&m8260.scc1;
0693   }
0694   else if( minor == SCC2_MINOR ) {
0695     sccparms = (m8260SCCparms_t*)&m8260.scc2p;
0696     sccregs  = (m8260SCCRegisters_t*)&m8260.scc2;
0697   }
0698   else if( minor == SCC3_MINOR ) {
0699     sccparms = (m8260SCCparms_t*)&m8260.scc3p;
0700     sccregs  = (m8260SCCRegisters_t*)&m8260.scc3;
0701   }
0702   else {
0703     sccparms = (m8260SCCparms_t*)&m8260.scc4p;
0704     sccregs  = (m8260SCCRegisters_t*)&m8260.scc4;
0705   }
0706 
0707   sccparms->rbase = (char *)RxBd[minor] - (char *)&m8260;
0708   sccparms->tbase = (char *)TxBd[minor] - (char *)&m8260;
0709 
0710   sccparms->rfcr = M8260_RFCR_MOT | M8260_RFCR_60X_BUS;
0711   sccparms->tfcr = M8260_TFCR_MOT | M8260_TFCR_60X_BUS;
0712   if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
0713     sccparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
0714   else
0715     sccparms->mrblr = 1;            /* Maximum Rx buffer size */
0716   sccparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
0717   sccparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
0718 
0719   sccparms->un.uart.parec = 0;      /* Clear parity error counter */
0720   sccparms->un.uart.frmec = 0;      /* Clear framing error counter */
0721   sccparms->un.uart.nosec = 0;      /* Clear noise counter */
0722   sccparms->un.uart.brkec = 0;      /* Clear break counter */
0723 
0724   sccparms->un.uart.uaddr[0] = 0;   /* Not in multidrop mode, so clear */
0725   sccparms->un.uart.uaddr[1] = 0;   /* Not in multidrop mode, so clear */
0726   sccparms->un.uart.toseq  = 0;     /* Tx Out-Of-SEQuence--no XON/XOFF now */
0727 
0728   sccparms->un.uart.character[0] = 0x8000; /* Entry is invalid */
0729   sccparms->un.uart.character[1] = 0x8000; /* Entry is invalid */
0730   sccparms->un.uart.character[2] = 0x8000; /* Entry is invalid */
0731   sccparms->un.uart.character[3] = 0x8000; /* Entry is invalid */
0732   sccparms->un.uart.character[4] = 0x8000; /* Entry is invalid */
0733   sccparms->un.uart.character[5] = 0x8000; /* Entry is invalid */
0734   sccparms->un.uart.character[6] = 0x8000; /* Entry is invalid */
0735   sccparms->un.uart.character[7] = 0x8000; /* Entry is invalid */
0736 
0737   sccparms->un.uart.rccm = 0xc0ff;  /* No masking */
0738 
0739   /*
0740    * Set up the Receive Buffer Descriptor
0741    */
0742   RxBd[minor]->status = M8260_BD_EMPTY | M8260_BD_WRAP | M8260_BD_INTERRUPT;
0743   RxBd[minor]->length = 0;
0744   RxBd[minor]->buffer = rxBuf[minor];
0745 
0746   /*
0747    * Setup the Transmit Buffer Descriptor
0748    */
0749   TxBd[minor]->status = M8260_BD_WRAP;
0750 
0751  /*
0752    * Set up SCCx general and protocol-specific mode registers
0753    */
0754   sccregs->gsmr_h = 0x00000020;     /* RFW=low latency operation */
0755   sccregs->gsmr_l = 0x00028004;     /* TDCR=RDCR=16x clock mode, MODE=uart*/
0756   sccregs->scce = ~0;               /* Clear any pending event */
0757   sccregs->sccm = 0;                /* Mask all interrupt/event sources */
0758   sccregs->psmr = 0x3000;           /* Normal operation & mode, 1 stop bit,
0759                                        8 data bits, no parity */
0760   sccregs->dsr = 0x7E7E;            /* No fractional stop bits */
0761   sccregs->gsmr_l = 0x00028034;     /* ENT=enable Tx, ENR=enable Rx */
0762 
0763   /*
0764    *  Initialize the Rx and Tx with the new parameters.
0765    */
0766   switch (minor) {
0767     case SCC1_MINOR:
0768       m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC1);
0769       break;
0770     case SCC2_MINOR:
0771       m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC2);
0772       break;
0773     case SCC3_MINOR:
0774       m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC3);
0775       break;
0776     case SCC4_MINOR:
0777       m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC4);
0778       break;
0779   }
0780 
0781   if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
0782     switch (minor) {
0783       case SCC1_MINOR:
0784     consoleIrqData.name = BSP_CPM_IRQ_SCC1;
0785         consoleIrqData.hdl = m8xx_scc1_interrupt_handler;
0786     break;
0787       case SCC2_MINOR:
0788     consoleIrqData.name = BSP_CPM_IRQ_SCC2;
0789         consoleIrqData.hdl = m8xx_scc2_interrupt_handler;
0790     break;
0791       case SCC3_MINOR:
0792     consoleIrqData.name = BSP_CPM_IRQ_SCC3;
0793         consoleIrqData.hdl = m8xx_scc3_interrupt_handler;
0794     break;
0795       case SCC4_MINOR:
0796     consoleIrqData.name = BSP_CPM_IRQ_SCC4;
0797         consoleIrqData.hdl = m8xx_scc4_interrupt_handler;
0798     break;
0799 
0800     }
0801     if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
0802       printk("Unable to connect SCC Irq handler\n");
0803       rtems_fatal_error_occurred(1);
0804     }
0805   }
0806 }
0807 
0808 static void m8xx_smc_enable(const rtems_irq_connect_data* ptr)
0809 {
0810   volatile m8260SMCRegisters_t *smcregs = 0;
0811   switch (ptr->name) {
0812   case BSP_CPM_IRQ_SMC1 :
0813     smcregs = &m8260.smc1;
0814     break;
0815   case BSP_CPM_IRQ_SMC2 :
0816     smcregs = &m8260.smc2;
0817     break;
0818   default:
0819     break;
0820   }
0821   smcregs->smcm = 3;
0822 }
0823 
0824 static void m8xx_smc_disable(const rtems_irq_connect_data* ptr)
0825 {
0826   volatile m8260SMCRegisters_t *smcregs = 0;
0827   switch (ptr->name) {
0828   case BSP_CPM_IRQ_SMC1 :
0829     smcregs = &m8260.smc1;
0830     break;
0831   case BSP_CPM_IRQ_SMC2 :
0832     smcregs = &m8260.smc2;
0833     break;
0834   default:
0835     break;
0836   }
0837   smcregs->smcm &= (~3);
0838 }
0839 
0840 static int m8xx_smc_isOn(const rtems_irq_connect_data* ptr)
0841 {
0842  return BSP_irq_enabled_at_cpm (ptr->name);
0843 }
0844 
0845 void
0846 m8xx_uart_smc_initialize (int minor)
0847 {
0848   unsigned char brg;
0849   volatile m8260SMCparms_t *smcparms = 0;
0850   volatile m8260SMCRegisters_t *smcregs = 0;
0851 
0852   /*
0853    * Check that minor number is valid
0854    */
0855   if ( (minor < SMC1_MINOR) || (minor > SMC2_MINOR) )
0856     return;
0857 
0858   /* Get the simode clock source bit values for 9600 bps */
0859   if( minor == SMC1_MINOR )
0860     brg = m8xx_get_brg(M8260_SMC1_BRGS, 9600*16);
0861   else
0862     brg = m8xx_get_brg(M8260_SMC2_BRGS, 9600*16);
0863   (void) brg; /* avoid set but not used warning */
0864 
0865   /*
0866    * Allocate buffer descriptors
0867    */
0868   RxBd[minor] = m8xx_bd_allocate (1);
0869   TxBd[minor] = m8xx_bd_allocate (1);
0870 
0871   /*
0872    *  Get the address of the parameter RAM for the specified port,
0873    *  configure I/O port B and put SMC in NMSI mode, connect the
0874    *  SMC to the appropriate BRG.
0875    *
0876    *  SMC2 RxD is shared with port B bit 20
0877    *  SMC2 TxD is shared with port B bit 21
0878    *  SMC1 RxD is shared with port B bit 24
0879    *  SMC1 TxD is shared with port B bit 25
0880    */
0881   switch (minor) {
0882     case SMC1_MINOR:
0883       smcparms = &m8260.smc1p;
0884       smcregs  = &m8260.smc1;
0885 
0886 #if 0
0887       m8260.pbpar |=  0x000000C0;    /* PB24 & PB25 are dedicated peripheral pins */
0888       m8260.pbdir &= ~0x000000C0;    /* PB24 & PB25 must not drive UART lines */
0889       m8260.pbodr &= ~0x000000C0;    /* PB24 & PB25 are not open drain */
0890 
0891       m8260.simode &= 0xFFFF0FFF;    /* Clear SMC1CS & SMC1 for NMSI mode */
0892       m8260.simode |= brg << 12;     /* SMC1CS = brg */
0893 #endif
0894       break;
0895 
0896     case SMC2_MINOR:
0897       smcparms = &m8260.smc2p;
0898       smcregs = &m8260.smc2;
0899 #if 0
0900       m8260.pbpar |=  0x00000C00;    /* PB20 & PB21 are dedicated peripheral pins */
0901       m8260.pbdir &= ~0x00000C00;    /* PB20 & PB21 must not drive the UART lines */
0902       m8260.pbodr &= ~0x00000C00;    /* PB20 & PB21 are not open drain */
0903 
0904       m8260.simode &= 0x0FFFFFFF;    /* Clear SMC2CS & SMC2 for NMSI mode */
0905       m8260.simode |= brg << 28;     /* SMC2CS = brg */
0906 #endif
0907       break;
0908   }
0909 
0910   /*
0911    * Set up SMC parameter RAM common to all protocols
0912    */
0913   smcparms->rbase = (char *)RxBd[minor] - (char *)&m8260;
0914   smcparms->tbase = (char *)TxBd[minor] - (char *)&m8260;
0915   smcparms->rfcr = M8260_RFCR_MOT | M8260_RFCR_60X_BUS;
0916   smcparms->tfcr = M8260_TFCR_MOT | M8260_TFCR_60X_BUS;
0917   if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
0918     smcparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
0919   else
0920     smcparms->mrblr = 1;            /* Maximum Rx buffer size */
0921 
0922   /*
0923    * Set up SMC1 parameter RAM UART-specific parameters
0924    */
0925   smcparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
0926   smcparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
0927   smcparms->un.uart.brkec = 0;      /* Clear break counter */
0928 
0929   /*
0930    * Set up the Receive Buffer Descriptor
0931    */
0932   RxBd[minor]->status = M8260_BD_EMPTY | M8260_BD_WRAP | M8260_BD_INTERRUPT;
0933   RxBd[minor]->length = 0;
0934   RxBd[minor]->buffer = rxBuf[minor];
0935 
0936   /*
0937    * Setup the Transmit Buffer Descriptor
0938    */
0939   TxBd[minor]->status = M8260_BD_WRAP;
0940 
0941   /*
0942    * Set up SMCx general and protocol-specific mode registers
0943    */
0944   smcregs->smce = ~0;               /* Clear any pending events */
0945   smcregs->smcm = 0;                /* Enable SMC Rx & Tx interrupts */
0946   smcregs->smcmr = M8260_SMCMR_CLEN(9) | M8260_SMCMR_SM_UART;
0947 
0948   /*
0949    * Send "Init parameters" command
0950    */
0951   switch (minor) {
0952     case SMC1_MINOR:
0953       m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SMC1);
0954       break;
0955 
0956     case SMC2_MINOR:
0957       m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SMC2);
0958       break;
0959   }
0960 
0961   /*
0962    * Enable receiver and transmitter
0963    */
0964   smcregs->smcmr |= M8260_SMCMR_TEN | M8260_SMCMR_REN;
0965   if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
0966     consoleIrqData.on = m8xx_smc_enable;
0967     consoleIrqData.off = m8xx_smc_disable;
0968     consoleIrqData.isOn = m8xx_smc_isOn;
0969     switch (minor) {
0970       case SMC1_MINOR:
0971     consoleIrqData.name = BSP_CPM_IRQ_SMC1;
0972     consoleIrqData.hdl  = m8xx_smc1_interrupt_handler;
0973     break;
0974 
0975       case SMC2_MINOR:
0976     consoleIrqData.name = BSP_CPM_IRQ_SMC2;
0977     consoleIrqData.hdl  = m8xx_smc2_interrupt_handler;
0978     break;
0979 #if 0
0980       case SMC1_MINOR:
0981         rtems_interrupt_catch (m8xx_smc1_interrupt_handler,
0982                                     PPC_IRQ_CPM_SMC1,
0983                                     &old_handler[minor]);
0984 
0985         smcregs->smcm = 3;            /* Enable SMC1 Rx & Tx interrupts */
0986         m8260.sipnr_l |= M8260_SIMASK_SMC1;      /* Clear pending register */
0987         m8260.simr_l  |= M8260_SIMASK_SMC1;      /* Enable SMC1 interrupts */
0988         break;
0989 
0990       case SMC2_MINOR:
0991         rtems_interrupt_catch (m8xx_smc2_interrupt_handler,
0992                                     PPC_IRQ_CPM_SMC2,
0993                                     &old_handler[minor]);
0994 
0995         smcregs->smcm = 3;            /* Enable SMC2 Rx & Tx interrupts */
0996         m8260.sipnr_l |= M8260_SIMASK_SMC2;      /* Clear pending register */
0997         m8260.simr_l  |= M8260_SIMASK_SMC2;      /* Enable SMC2 interrupts */
0998         break;
0999 #endif
1000     }
1001     if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
1002       printk("Unable to connect SMC Irq handler\n");
1003       rtems_fatal_error_occurred(1);
1004     }
1005   }
1006 }
1007 
1008 void
1009 m8xx_uart_initialize(void)
1010 {
1011 }
1012 
1013 void
1014 m8xx_uart_interrupts_initialize(void)
1015 {
1016 #ifdef mpc8260
1017   /* CHECK THIS */
1018 
1019 #else
1020 
1021 #if defined(mpc860)
1022   m8xx.cicr = 0x00E43F80;           /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
1023                                        SCdP=SCC4, IRL=1, HP=PC15, IEN=1 */
1024 #else
1025   m8xx.cicr = 0x00043F80;           /* SCaP=SCC1, SCbP=SCC2, IRL=1, HP=PC15, IEN=1 */
1026 #endif
1027   m8xx.simask |= M8xx_SIMASK_LVM1;  /* Enable level interrupts */
1028 #endif
1029 }
1030 
1031 int
1032 m8xx_uart_pollRead(
1033   int minor
1034 )
1035 {
1036   unsigned char c;
1037 
1038   if (RxBd[minor]->status & M8260_BD_EMPTY) {
1039     return -1;
1040   }
1041   rtems_cache_invalidate_multiple_data_lines(
1042     (const void *) RxBd[minor]->buffer,
1043     RxBd[minor]->length
1044   );
1045   c = ((char *)RxBd[minor]->buffer)[0];
1046   RxBd[minor]->status = M8260_BD_EMPTY | M8260_BD_WRAP;
1047   return c;
1048 }
1049 
1050 /*
1051  *  TODO: Get a free buffer and set it up.
1052  */
1053 ssize_t
1054 m8xx_uart_write(
1055   int minor,
1056   const char *buf,
1057   size_t len
1058 )
1059 {
1060   if (len > 0) {
1061     while( (TxBd[minor]->status) & M8260_BD_READY );
1062 
1063     rtems_cache_flush_multiple_data_lines( buf, len );
1064     TxBd[minor]->buffer = (char *) buf;
1065     TxBd[minor]->length = len;
1066     TxBd[minor]->status = M8260_BD_READY | M8260_BD_WRAP | M8260_BD_INTERRUPT;
1067   }
1068 
1069   return 0;
1070 }
1071 
1072 ssize_t
1073 m8xx_uart_pollWrite(
1074   int minor,
1075   const char *buf,
1076   size_t len
1077 )
1078 {
1079   size_t retval = len;
1080 
1081   while (len--) {
1082     while (TxBd[minor]->status & M8260_BD_READY)
1083       continue;
1084     txBuf[minor] = *buf++;
1085     rtems_cache_flush_multiple_data_lines( (void *)&txBuf[minor], 1 );
1086     TxBd[minor]->buffer = &txBuf[minor];
1087     TxBd[minor]->length = 1;
1088     TxBd[minor]->status = M8260_BD_READY | M8260_BD_WRAP;
1089   }
1090 
1091   return retval;
1092 }