Back to home page

LXR

 
 

    


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

0001 /*
0002  * RTEMS TQM8xx BSP
0003  *
0004  * This file contains the console driver.
0005  *
0006  *  SMC1/2 SCC1..4 raw console serial I/O.
0007  *  adapted to work with up to 4 SCC and 2 SMC
0008  *
0009  *  This driver is an example of `TASK DRIVEN' `POLLING' or `INTERRUPT' I/O.
0010  *
0011  *  To run with interrupt-driven I/O, ensure m8xx_smc1_interrupt
0012  *  is set before calling the initialization routine.
0013  */
0014 
0015 /*
0016  * Copyright (c) 2005 Eric Norum <eric@norum.ca>
0017  *
0018  * COPYRIGHT (c) 1989-1998.
0019  * On-Line Applications Research Corporation (OAR).
0020  * Copyright assigned to U.S. Government, 1994.
0021  *
0022  * Copyright (c) 2008 Thomas Doerfler, embedded brains GmbH & Co. KG
0023  * All rights reserved.
0024  *
0025  * The license and distribution terms for this file may be
0026  * found in the file LICENSE in this distribution or at
0027  * http://www.OARcorp.com/rtems/license.html.
0028  */
0029 
0030 #include <unistd.h>
0031 
0032 #include <rtems.h>
0033 #include <rtems/console.h>
0034 #include <rtems/termiostypes.h>
0035 #include <rtems/bspIo.h>
0036 #include <rtems/error.h>
0037 
0038 #include <bsp.h>
0039 #include <mpc8xx.h>
0040 #include <bsp/irq.h>
0041 
0042 /*
0043  * Interrupt-driven input buffer
0044  */
0045 #define RXBUFSIZE   16
0046 
0047 #define M8xx_SICR_BRG1 (0)
0048 #define M8xx_SICR_BRG2 (1)
0049 #define M8xx_SICR_BRG3 (2)
0050 #define M8xx_SICR_BRG4 (3)
0051 
0052 #define M8xx_SICR_SCCRX_MSK(scc) ((  7) << (((scc))*8+3))
0053 #define M8xx_SICR_SCCRX(scc,clk) ((clk) << (((scc))*8+3))
0054 
0055 #define M8xx_SICR_SCCTX_MSK(scc) ((  7) << (((scc))*8+0))
0056 #define M8xx_SICR_SCCTX(scc,clk) ((clk) << (((scc))*8+0))
0057 
0058 #define M8xx_SIMODE_SMCCS(smc,clk) ((clk) << ((smc)*16+12))
0059 #define M8xx_SIMODE_SMCCS_MSK(smc) M8xx_SIMODE_SMCCS(smc,7)
0060 
0061 #define CONS_CHN_CNT 6
0062 #define CONS_CHN_SCC1 0
0063 #define CONS_CHN_SCC2 1
0064 #define CONS_CHN_SCC3 2
0065 #define CONS_CHN_SCC4 3
0066 #define CONS_CHN_SMC1 4
0067 #define CONS_CHN_SMC2 5
0068 #define CONS_CHN_NONE -1
0069 
0070 /*
0071  * possible identifiers for bspopts.h: CONS_SxCy_MODE
0072  */
0073 #define CONS_MODE_UNUSED -1
0074 #define CONS_MODE_POLLED TERMIOS_POLLED
0075 #define CONS_MODE_IRQ    TERMIOS_IRQ_DRIVEN
0076 
0077 #define CHN_IS_SCC(chan) ((chan) < CONS_CHN_SMC1)
0078 
0079 #define BRG_CNT 4
0080 
0081 #define MAX_IDL_DEFAULT 10
0082 #define DEVICEPREFIX "tty"
0083 
0084 /*
0085  * I/O buffers and pointers to buffer descriptors
0086  */
0087 #define SCC_RXBD_CNT 4
0088 #define SCC_TXBD_CNT 4
0089 typedef char sccRxBuf_t[SCC_RXBD_CNT][RXBUFSIZE];
0090 
0091 /*
0092  * Interrupt-driven callback
0093  */
0094 typedef struct m8xx_console_chan_desc_s {
0095   rtems_termios_device_context base;
0096   volatile m8xxBufferDescriptor_t *sccFrstRxBd;
0097   volatile m8xxBufferDescriptor_t *sccCurrRxBd;
0098   volatile m8xxBufferDescriptor_t *sccFrstTxBd;
0099   volatile m8xxBufferDescriptor_t *sccPrepTxBd;
0100   volatile m8xxBufferDescriptor_t *sccDequTxBd;
0101   bool is_scc;                  /* true for SCC */
0102   struct {
0103     volatile m8xxSCCparms_t *sccp;
0104     volatile m8xxSMCparms_t *smcp;
0105   } parms;
0106   struct {
0107     volatile m8xxSCCRegisters_t *sccr;
0108     volatile m8xxSMCRegisters_t *smcr;
0109   } regs;
0110   int chan;
0111   rtems_termios_device_mode mode;
0112   rtems_vector_number ivec_src;
0113   int cr_chan_code;
0114   int brg_used;
0115   sccRxBuf_t *rxBuf;
0116 } m8xx_console_chan_desc_t;
0117 
0118 m8xx_console_chan_desc_t m8xx_console_chan_desc[CONS_CHN_CNT] = {
0119   /* SCC1 */
0120   { .is_scc = true,
0121    .parms = {(m8xxSCCparms_t *)&(m8xx.scc1p),NULL},
0122    .regs = {&(m8xx.scc1),NULL},
0123    .chan = CONS_CHN_SCC1,
0124    .ivec_src = BSP_CPM_IRQ_SCC1,
0125    .cr_chan_code = M8xx_CR_CHAN_SCC1,
0126    .brg_used = -1},
0127   /* SCC2 */
0128   { .is_scc = true,
0129    .parms = {&(m8xx.scc2p),NULL},
0130    .regs = {&(m8xx.scc2),NULL},
0131    .chan = CONS_CHN_SCC2,
0132    .ivec_src = BSP_CPM_IRQ_SCC2,
0133    .cr_chan_code = M8xx_CR_CHAN_SCC2,
0134    .brg_used = -1},
0135   /* SCC3 */
0136   { .is_scc = true,
0137    .parms = {&(m8xx.scc3p),NULL},
0138    .regs = {&(m8xx.scc3),NULL},
0139    .chan = CONS_CHN_SCC3,
0140    .ivec_src = BSP_CPM_IRQ_SCC3,
0141    .cr_chan_code = M8xx_CR_CHAN_SCC3,
0142    .brg_used = -1},
0143   /* SCC4 */
0144   { .is_scc = true,
0145    .parms = {&(m8xx.scc4p),NULL},
0146    .regs = {&(m8xx.scc4),NULL},
0147    .chan = CONS_CHN_SCC4,
0148    .ivec_src = BSP_CPM_IRQ_SCC4,
0149    .cr_chan_code = M8xx_CR_CHAN_SCC4,
0150    .brg_used = -1},
0151   /* SMC1 */
0152   { .is_scc = false,
0153    .parms = {NULL,&(m8xx.smc1p)},
0154    .regs = {NULL,&(m8xx.smc1)},
0155    .chan = CONS_CHN_SMC1,
0156    .ivec_src = BSP_CPM_IRQ_SMC1,
0157    .cr_chan_code = M8xx_CR_CHAN_SMC1,
0158    .brg_used = -1},
0159   /* SMC2 */
0160   { .is_scc = false,
0161    .parms = {NULL,&(m8xx.smc2p)},
0162    .regs = {NULL,&(m8xx.smc2)},
0163    .chan = CONS_CHN_SMC2,
0164    .ivec_src = BSP_CPM_IRQ_SMC2_OR_PIP,
0165    .cr_chan_code = M8xx_CR_CHAN_SMC2,
0166    .brg_used = -1}};
0167 
0168 #define CHN_PARAM_GET(cd,param) \
0169   (cd->is_scc           \
0170    ? cd->parms.sccp->param  \
0171    : cd->parms.smcp->param)
0172 
0173 #define CHN_PARAM_SET(cd,param,value)   \
0174   do {if (cd->is_scc)           \
0175       cd->parms.sccp->param = value;    \
0176     else                \
0177       cd->parms.smcp->param = value;    \
0178   } while (0)
0179 
0180 #define CHN_EVENT_GET(cd)   \
0181   (cd->is_scc           \
0182    ? cd->regs.sccr->scce    \
0183    : cd->regs.smcr->smce)
0184 
0185 #define CHN_EVENT_CLR(cd,mask)      \
0186   do {                  \
0187     if (cd->is_scc)             \
0188       cd->regs.sccr->scce = (mask); \
0189     else                \
0190       cd->regs.smcr->smce = (mask); \
0191   }while (0)
0192 
0193 #define CHN_MASK_GET(cd)    \
0194   (cd->is_scc           \
0195    ? cd->regs.sccr->sccm    \
0196    : cd->regs.smcr->smcm)
0197 
0198 #define CHN_MASK_SET(cd,mask)       \
0199   do {                  \
0200     if (cd->is_scc)             \
0201       cd->regs.sccr->sccm = (mask); \
0202     else                \
0203       cd->regs.smcr->smcm = (mask); \
0204   }while (0)
0205 
0206 /*
0207  * Compute baud-rate-generator configuration register value
0208  */
0209 static uint32_t
0210 sccBRGval (int baud)
0211 {
0212   int divisor;
0213   int div16 = 0;
0214 
0215   divisor = ((BSP_bus_frequency / 16) + (baud / 2)) / baud;
0216   if (divisor > 4096) {
0217     div16 = 1;
0218     divisor = (divisor + 8) / 16;
0219   }
0220   return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
0221 }
0222 
0223 typedef struct {
0224   uint32_t reg_content;
0225   int link_cnt;
0226 }brg_state_t;
0227 brg_state_t scc_brg_state[BRG_CNT];
0228 
0229 /*
0230  * initialize brg_state
0231  */
0232 static void sccBRGinit(void)
0233 {
0234   int brg_idx;
0235 
0236   for (brg_idx = 0;brg_idx < BRG_CNT;brg_idx++) {
0237     scc_brg_state[brg_idx].reg_content = 0;
0238     scc_brg_state[brg_idx].link_cnt    = 0;
0239   }
0240 #ifndef MDE360
0241   /*
0242    * on ZEM40, init CLK4/5 inputs
0243    */
0244   m8xx.papar |=  ((1 << 11) | (1 << 12));
0245   m8xx.padir &= ~((1 << 11) | (1 << 12));
0246 #endif
0247 }
0248 
0249 #if CONS_USE_EXT_CLK
0250 /*
0251  * input clock frq for CPM clock inputs
0252  */
0253 static uint32_t clkin_frq[2][4] = {
0254 #ifdef MDE360
0255   {0,0,0,0},
0256   {0,0,0,0}
0257 #else
0258   {0,0,0,1843000},
0259   {1843000,0,0,0}
0260 #endif
0261 };
0262 #endif
0263 
0264 /*
0265  * allocate, set and connect baud rate generators
0266  * FIXME: or clock input
0267  * FIXME: set pin to be clock input
0268  */
0269 
0270 static bool sccBRGalloc(m8xx_console_chan_desc_t *cd,int baud)
0271 {
0272   rtems_interrupt_level level;
0273   uint32_t reg_val;
0274   int old_brg;
0275   int new_brg = -1;
0276   int brg_idx;
0277 #if CONS_USE_EXT_CLK
0278   int clk_group;
0279   int clk_sel;
0280 #endif
0281 
0282   old_brg = cd->brg_used;
0283   /* compute brg register contents needed */
0284   reg_val = sccBRGval(baud);
0285 
0286 #if CONS_EXT_CLK
0287   /* search for clock input with this frq */
0288   clk_group = ((chan == CONS_CHN_SCC3) ||
0289            (chan == CONS_CHN_SCC4) ||
0290            (chan == CONS_CHN_SMC2)) ? 1 : 0;
0291 
0292   for (clk_sel = 0, new_brg = -1;
0293        (clk_sel < 4) && (new_brg < 0);
0294        clk_sel++) {
0295     if (baud == (clkin_frq[clk_group][clk_sel] / 16)) {
0296       new_brg = clk_sel + 4;
0297     }
0298   }
0299 #endif
0300 
0301   rtems_interrupt_disable(level);
0302 
0303   if (new_brg < 0) {
0304     /* search for brg with this settings */
0305     for (brg_idx = 0;
0306      (new_brg < 0) && (brg_idx < BRG_CNT);
0307      brg_idx++) {
0308       if (scc_brg_state[brg_idx].reg_content == reg_val) {
0309     new_brg = brg_idx;
0310       }
0311     }
0312     /*
0313      * if not found: check, whether brg currently in use
0314      * is linked only from our channel
0315      */
0316     if ((new_brg < 0) &&
0317     (old_brg >= 0) &&
0318     (scc_brg_state[old_brg].link_cnt == 1)) {
0319       new_brg = old_brg;
0320     }
0321     /* if not found: search for unused brg, set it  */
0322     for (brg_idx = 0;
0323      (new_brg < 0) && (brg_idx < BRG_CNT);
0324      brg_idx++) {
0325       if (scc_brg_state[brg_idx].link_cnt == 0) {
0326     new_brg = brg_idx;
0327       }
0328     }
0329   }
0330 
0331   /* decrease old link count */
0332   if ((old_brg >= 0) &&
0333       (old_brg < 4)) {
0334     scc_brg_state[old_brg].link_cnt--;
0335   }
0336   /* increase new brg link count, set brg */
0337   if ((new_brg >= 0) &&
0338       (new_brg < 4)) {
0339     scc_brg_state[new_brg].link_cnt++;
0340     scc_brg_state[new_brg].reg_content = reg_val;
0341     (&m8xx.brgc1)[new_brg] = reg_val;
0342   }
0343   rtems_interrupt_enable(level);
0344 
0345   /* connect to scc/smc */
0346   if (new_brg >= 0) {
0347     cd->brg_used = new_brg;
0348     /*
0349      * Put SCC in NMSI mode, connect SCC to BRG or CLKx
0350      */
0351     if (cd->is_scc) {
0352       m8xx.sicr = ((m8xx.sicr & ~(M8xx_SICR_SCCRX_MSK(cd->chan) |
0353                   M8xx_SICR_SCCTX_MSK(cd->chan))) |
0354            M8xx_SICR_SCCRX(cd->chan,new_brg)|
0355            M8xx_SICR_SCCTX(cd->chan,new_brg));
0356     }
0357     else {
0358       /* connect SMC to BRGx or CLKx... */
0359       m8xx.simode = ((m8xx.simode & ~(M8xx_SIMODE_SMCCS_MSK(cd->chan - CONS_CHN_SMC1)))|
0360              M8xx_SIMODE_SMCCS(cd->chan - CONS_CHN_SMC1,new_brg));
0361     }
0362 
0363     return true;
0364   } else {
0365     return false;
0366   }
0367 }
0368 
0369 
0370 /*
0371  * Hardware-dependent portion of tcsetattr().
0372  */
0373 static bool
0374 sccSetAttributes (rtems_termios_device_context *base, const struct termios *t)
0375 {
0376   m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
0377   speed_t speed;
0378   rtems_termios_baud_t baud;
0379 
0380   speed = cfgetispeed(t);
0381   if (speed == B0) {
0382         speed = cfgetospeed(t);
0383   }
0384 
0385   baud = rtems_termios_baud_to_number(speed);
0386   if (baud == 0) {
0387     return false;
0388   }
0389 
0390   return sccBRGalloc(cd,baud);
0391 }
0392 
0393 /*
0394  * Interrupt handler
0395  */
0396 static rtems_isr
0397 sccInterruptHandler (void *arg)
0398 {
0399   rtems_termios_tty *tty = arg;
0400   m8xx_console_chan_desc_t *cd = rtems_termios_get_device_context(tty);
0401   uint16_t status;
0402   uint16_t length;
0403   void *buffer;
0404 
0405   /*
0406    * Buffer received?
0407    */
0408   if (CHN_EVENT_GET(cd) & 0x1) {
0409     /*
0410      * clear SCC event flag
0411      */
0412     CHN_EVENT_CLR(cd,0x01);
0413     /*
0414      * process event
0415      */
0416     while (true) {
0417       status = cd->sccCurrRxBd->status;
0418 
0419       if ((cd->sccCurrRxBd->status & M8xx_BD_EMPTY) != 0) {
0420         break;
0421       }
0422 
0423       buffer = cd->sccCurrRxBd->buffer;
0424       length = cd->sccCurrRxBd->length;
0425       rtems_cache_invalidate_multiple_data_lines(buffer, length);
0426       rtems_termios_enqueue_raw_characters (tty, buffer, length);
0427 
0428       /*
0429        * clear status
0430        */
0431       cd->sccCurrRxBd->status = (status & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
0432         | M8xx_BD_EMPTY;
0433       /*
0434        * advance to next BD
0435        */
0436       if ((status & M8xx_BD_WRAP) != 0) {
0437         cd->sccCurrRxBd = cd->sccFrstRxBd;
0438       } else {
0439         cd->sccCurrRxBd++;
0440       }
0441     }
0442   }
0443   /*
0444    * Buffer transmitted?
0445    */
0446   if (CHN_EVENT_GET(cd) & 0x2) {
0447     /*
0448      * then clear interrupt event bit
0449      */
0450     CHN_EVENT_CLR(cd,0x2);
0451     /*
0452      * and signal successful transmit to termios
0453      */
0454     /*
0455      * FIXME: multiple dequeue calls for multiple buffers
0456      */
0457     while (cd->sccDequTxBd != cd->sccPrepTxBd) {
0458       status = cd->sccDequTxBd->status;
0459 
0460       if ((status & M8xx_BD_READY) != 0) {
0461         break;
0462       }
0463 
0464       if ((status & M8xx_BD_INTERRUPT) != 0) {
0465         rtems_termios_dequeue_characters (tty, cd->sccDequTxBd->length);
0466       }
0467 
0468       /*
0469        * advance to next BD
0470        */
0471       if ((status & M8xx_BD_WRAP) != 0) {
0472         cd->sccDequTxBd = cd->sccFrstTxBd;
0473       } else {
0474         cd->sccDequTxBd++;
0475       }
0476     }
0477   }
0478 }
0479 
0480 static void
0481 mpc8xx_console_irq_on(m8xx_console_chan_desc_t *cd)
0482 {
0483     CHN_MASK_SET(cd, 3);    /* Enable TX and RX interrupts */
0484 }
0485 
0486 static void
0487 sccInitialize (m8xx_console_chan_desc_t *cd)
0488 {
0489   int i;
0490   /*
0491    * allocate buffers
0492    * FIXME: use a cache-line size boundary alloc here
0493    */
0494   cd->rxBuf = rtems_cache_aligned_malloc(sizeof(*cd->rxBuf));
0495   if (cd->rxBuf == NULL) {
0496     rtems_panic("Cannot allocate console rx buffer\n");
0497   }
0498 
0499   /*
0500    * Allocate buffer descriptors
0501    */
0502   cd->sccCurrRxBd =
0503     cd->sccFrstRxBd = m8xx_bd_allocate(SCC_RXBD_CNT);
0504   cd->sccPrepTxBd =
0505     cd->sccDequTxBd =
0506     cd->sccFrstTxBd = m8xx_bd_allocate(SCC_TXBD_CNT);
0507   switch(cd->chan) {
0508   case CONS_CHN_SCC1:
0509     /*
0510      * Configure port A pins to enable TXD1 and RXD1 pins
0511      * FIXME: add setup for modem control lines....
0512      */
0513     m8xx.papar |=  0x03;
0514     m8xx.padir &= ~0x03;
0515 
0516     /*
0517      * Configure port C pins to enable RTS1 pins (static active low)
0518      */
0519     m8xx.pcpar &= ~0x01;
0520     m8xx.pcso  &= ~0x01;
0521     m8xx.pcdir |=  0x01;
0522     m8xx.pcdat &= ~0x01;
0523     break;
0524   case CONS_CHN_SCC2:
0525     /*
0526      * Configure port A pins to enable TXD2 and RXD2 pins
0527      * FIXME: add setup for modem control lines....
0528      */
0529     m8xx.papar |=  0x0C;
0530     m8xx.padir &= ~0x0C;
0531 
0532     /*
0533      * Configure port C pins to enable RTS2 pins (static active low)
0534      */
0535     m8xx.pcpar &= ~0x02;
0536     m8xx.pcso  &= ~0x02;
0537     m8xx.pcdir |=  0x02;
0538     m8xx.pcdat &= ~0x02;
0539     break;
0540   case CONS_CHN_SCC3:
0541     /*
0542      * Configure port A pins to enable TXD3 and RXD3 pins
0543      * FIXME: add setup for modem control lines....
0544      */
0545     m8xx.papar |=  0x30;
0546     m8xx.padir &= ~0x30;
0547 
0548     /*
0549      * Configure port C pins to enable RTS3 (static active low)
0550      */
0551     m8xx.pcpar &= ~0x04;
0552     m8xx.pcso  &= ~0x04;
0553     m8xx.pcdir |=  0x04;
0554     m8xx.pcdat &= ~0x04;
0555     break;
0556   case CONS_CHN_SCC4:
0557     /*
0558      * Configure port A pins to enable TXD4 and RXD4 pins
0559      * FIXME: add setup for modem control lines....
0560      */
0561     m8xx.papar |=  0xC0;
0562     m8xx.padir &= ~0xC0;
0563 
0564     /*
0565      * Configure port C pins to enable RTS4 pins (static active low)
0566      */
0567     m8xx.pcpar &= ~0x08;
0568     m8xx.pcso  &= ~0x08;
0569     m8xx.pcdir |=  0x08;
0570     m8xx.pcdat &= ~0x08;
0571     break;
0572   case CONS_CHN_SMC1:
0573     /*
0574      * Configure port B pins to enable SMTXD1 and SMRXD1 pins
0575      */
0576     m8xx.pbpar |=  0xC0;
0577     m8xx.pbdir &= ~0xC0;
0578     break;
0579   case CONS_CHN_SMC2:
0580     /*
0581      * Configure port B pins to enable SMTXD2 and SMRXD2 pins
0582      */
0583     m8xx.pbpar |=  0xC00;
0584     m8xx.pbdir &= ~0xC00;
0585     break;
0586   }
0587   /*
0588    * allocate and connect BRG
0589    */
0590   sccBRGalloc(cd,9600);
0591 
0592 
0593   /*
0594    * Set up SCCx parameter RAM common to all protocols
0595    */
0596   CHN_PARAM_SET(cd,rbase,(char *)cd->sccFrstRxBd - (char *)&m8xx);
0597   CHN_PARAM_SET(cd,tbase,(char *)cd->sccFrstTxBd - (char *)&m8xx);
0598   CHN_PARAM_SET(cd,rfcr ,M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0));
0599   CHN_PARAM_SET(cd,tfcr ,M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0));
0600   if (cd->mode != TERMIOS_POLLED)
0601     CHN_PARAM_SET(cd,mrblr,RXBUFSIZE);
0602   else
0603     CHN_PARAM_SET(cd,mrblr,1);
0604 
0605   /*
0606    * Set up SCCx parameter RAM UART-specific parameters
0607    */
0608   CHN_PARAM_SET(cd,un.uart.max_idl ,MAX_IDL_DEFAULT);
0609   CHN_PARAM_SET(cd,un.uart.brkln   ,0);
0610   CHN_PARAM_SET(cd,un.uart.brkec   ,0);
0611   CHN_PARAM_SET(cd,un.uart.brkcr   ,0);
0612   if (cd->is_scc) {
0613     cd->parms.sccp->un.uart.character[0]=0x8000; /* no char filter */
0614     cd->parms.sccp->un.uart.rccm=0x80FF; /* control character mask */
0615   }
0616 
0617   /*
0618    * Set up the Receive Buffer Descriptors
0619    */
0620   for (i = 0;i < SCC_RXBD_CNT;i++) {
0621     cd->sccFrstRxBd[i].status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT;
0622     if (i == SCC_RXBD_CNT-1) {
0623       cd->sccFrstRxBd[i].status |= M8xx_BD_WRAP;
0624     }
0625     cd->sccFrstRxBd[i].length = 0;
0626     cd->sccFrstRxBd[i].buffer = (*cd->rxBuf)[i];
0627   }
0628   /*
0629    * Setup the Transmit Buffer Descriptor
0630    */
0631   for (i = 0;i < SCC_TXBD_CNT;i++) {
0632     cd->sccFrstTxBd[i].status = M8xx_BD_INTERRUPT;
0633     if (i == SCC_TXBD_CNT-1) {
0634       cd->sccFrstTxBd[i].status |= M8xx_BD_WRAP;
0635     }
0636     cd->sccFrstTxBd[i].length = 0;
0637     cd->sccFrstTxBd[i].buffer = NULL;
0638   }
0639 
0640   /*
0641    * Set up SCC general and protocol-specific mode registers
0642    */
0643   CHN_EVENT_CLR(cd,~0); /* Clear any pending events */
0644   CHN_MASK_SET(cd,0);           /* Mask all interrupt/event sources */
0645 
0646   if (cd->is_scc) {
0647     cd->regs.sccr->psmr = 0xb000; /* 8N1, CTS flow control */
0648     cd->regs.sccr->gsmr_h = 0x00000000;
0649     cd->regs.sccr->gsmr_l = 0x00028004; /* UART mode */
0650   }
0651   else {
0652     cd->regs.smcr->smcmr = 0x4820;
0653   }
0654   /*
0655    * Send "Init parameters" command
0656    */
0657   m8xx_cp_execute_cmd(M8xx_CR_OP_INIT_RX_TX | cd->cr_chan_code);
0658 
0659   /*
0660    * Enable receiver and transmitter
0661    */
0662   if (cd->is_scc) {
0663     cd->regs.sccr->gsmr_l |= 0x00000030;
0664   }
0665   else {
0666     cd->regs.smcr->smcmr |= 0x0003;
0667   }
0668 }
0669 
0670 /*
0671  * polled scc read function
0672  */
0673 static int
0674 sccPollRead (rtems_termios_device_context *base)
0675 {
0676   m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
0677   int c = -1;
0678 
0679   while(1) {
0680     if ((cd->sccCurrRxBd->status & M8xx_BD_EMPTY) != 0) {
0681       return -1;
0682     }
0683 
0684     if (0 == (cd->sccCurrRxBd->status & (M8xx_BD_OVERRUN
0685                        | M8xx_BD_PARITY_ERROR
0686                        | M8xx_BD_FRAMING_ERROR
0687                        | M8xx_BD_BREAK
0688                        | M8xx_BD_IDLE))) {
0689       /* character received and no error detected */
0690       rtems_cache_invalidate_multiple_data_lines((void *)cd->sccCurrRxBd->buffer,
0691                          cd->sccCurrRxBd->length);
0692       c = (unsigned)*((char *)cd->sccCurrRxBd->buffer);
0693       /*
0694        * clear status
0695        */
0696     }
0697     cd->sccCurrRxBd->status =
0698       (cd->sccCurrRxBd->status
0699        & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
0700       | M8xx_BD_EMPTY;
0701     /*
0702      * advance to next BD
0703      */
0704     if ((cd->sccCurrRxBd->status & M8xx_BD_WRAP) != 0) {
0705       cd->sccCurrRxBd = cd->sccFrstRxBd;
0706     }
0707     else {
0708       cd->sccCurrRxBd++;
0709     }
0710     if (c >= 0) {
0711       return c;
0712     }
0713   }
0714 }
0715 
0716 
0717 /*
0718  * Device-dependent write routine
0719  * Interrupt-driven devices:
0720  *  Begin transmission of as many characters as possible (minimum is 1).
0721  * Polling devices:
0722  *  Transmit all characters.
0723  */
0724 static void
0725 sccInterruptWrite (rtems_termios_device_context *base, const char *buf, size_t len)
0726 {
0727   m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
0728 
0729   if (len > 0) {
0730     uint16_t status = cd->sccPrepTxBd->status;
0731 
0732     if ((status & M8xx_BD_READY) == 0) {
0733       cd->sccPrepTxBd->buffer = RTEMS_DECONST(char*, buf);
0734       cd->sccPrepTxBd->length = len;
0735       rtems_cache_flush_multiple_data_lines(buf, len);
0736 
0737       /*
0738        * clear status, set ready bit
0739        */
0740       cd->sccPrepTxBd->status = (status & M8xx_BD_WRAP)
0741         | M8xx_BD_READY | M8xx_BD_INTERRUPT;
0742 
0743       if ((status & M8xx_BD_WRAP) != 0) {
0744         cd->sccPrepTxBd = cd->sccFrstTxBd;
0745       } else {
0746         cd->sccPrepTxBd++;
0747       }
0748     }
0749   }
0750 }
0751 
0752 static void
0753 sccPollWrite (rtems_termios_device_context *base, const char *buf, size_t len)
0754 {
0755   m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
0756   volatile m8xxBufferDescriptor_t *bd = NULL;
0757 
0758   rtems_cache_flush_multiple_data_lines (buf, len);
0759 
0760   while (bd == NULL) {
0761     rtems_interrupt_level level;
0762     uint16_t status;
0763 
0764     rtems_interrupt_disable(level);
0765 
0766     bd = cd->sccPrepTxBd;
0767     status = bd->status;
0768 
0769     if ((status & M8xx_BD_READY) == 0) {
0770       bd->buffer = RTEMS_DECONST (char *, buf);
0771       bd->length = len;
0772       bd->status = (status & M8xx_BD_WRAP) | M8xx_BD_READY;
0773 
0774       if ((status & M8xx_BD_WRAP) != 0) {
0775         cd->sccPrepTxBd = cd->sccFrstTxBd;
0776       } else {
0777         cd->sccPrepTxBd++;
0778       }
0779     } else {
0780       bd = NULL;
0781     }
0782 
0783     rtems_interrupt_enable(level);
0784   }
0785 
0786   while ((bd->status & M8xx_BD_READY) != 0) {
0787     /* Wait */
0788   }
0789 }
0790 
0791 /*
0792  * printk basic support
0793  */
0794 int BSP_output_chan = CONS_CHN_NONE; /* channel used for printk operation */
0795 
0796 static void console_debug_putc_onlcr(const char c)
0797 {
0798   rtems_interrupt_level irq_level;
0799 
0800   if (BSP_output_chan != CONS_CHN_NONE) {
0801     rtems_interrupt_disable(irq_level);
0802 
0803     sccPollWrite (&m8xx_console_chan_desc[BSP_output_chan].base,&c,1);
0804     rtems_interrupt_enable(irq_level);
0805   }
0806 }
0807 
0808 BSP_output_char_function_type     BSP_output_char = console_debug_putc_onlcr;
0809 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0810 
0811 
0812 /*
0813 ***************
0814 * BOILERPLATE *
0815 ***************
0816 */
0817 
0818 struct {
0819   rtems_device_minor_number minor;
0820   int driver_mode;
0821 } channel_list[] = {
0822   {CONS_CHN_SMC1,CONS_SMC1_MODE},
0823   {CONS_CHN_SMC2,CONS_SMC2_MODE},
0824   {CONS_CHN_SCC1,CONS_SCC1_MODE},
0825   {CONS_CHN_SCC2,CONS_SCC2_MODE},
0826   {CONS_CHN_SCC3,CONS_SCC3_MODE},
0827   {CONS_CHN_SCC4,CONS_SCC4_MODE}
0828 };
0829 
0830 static bool m8xx_console_first_open(
0831   rtems_termios_tty *tty,
0832   rtems_termios_device_context *base,
0833   struct termios *term,
0834   rtems_libio_open_close_args_t *args
0835 )
0836 {
0837   m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
0838 
0839   if (cd->mode == TERMIOS_IRQ_DRIVEN) {
0840     rtems_status_code sc;
0841 
0842     sc = rtems_interrupt_handler_install(
0843       cd->ivec_src,
0844       "SCC",
0845       RTEMS_INTERRUPT_UNIQUE,
0846       sccInterruptHandler,
0847       tty
0848     );
0849     if (sc != RTEMS_SUCCESSFUL) {
0850       return false;
0851     }
0852 
0853     mpc8xx_console_irq_on(cd);
0854   }
0855 
0856   return true;
0857 }
0858 
0859 static const rtems_termios_device_handler m8xx_console_handler_polled = {
0860   .first_open = m8xx_console_first_open,
0861   .set_attributes = sccSetAttributes,
0862   .write = sccPollWrite,
0863   .poll_read = sccPollRead,
0864   .mode = TERMIOS_POLLED
0865 };
0866 
0867 static const rtems_termios_device_handler m8xx_console_handler_irq_driven = {
0868   .first_open = m8xx_console_first_open,
0869   .set_attributes = sccSetAttributes,
0870   .write = sccInterruptWrite,
0871   .mode = TERMIOS_IRQ_DRIVEN
0872 };
0873 
0874 /*
0875  * Initialize and register the device
0876  */
0877 rtems_device_driver console_initialize(rtems_device_major_number  major,
0878                        rtems_device_minor_number  minor,/* ignored */
0879                        void                      *arg
0880                        )
0881 {
0882   rtems_status_code status = RTEMS_SUCCESSFUL;
0883   int entry,ttynum;
0884   char tty_name[] = "/dev/tty00";
0885 
0886   /*
0887    * Set up TERMIOS
0888    */
0889   rtems_termios_initialize ();
0890   /*
0891    * init BRG allocataion
0892    */
0893   sccBRGinit();
0894   ttynum = 0;
0895   for (entry = 0;
0896        (entry < sizeof(channel_list)/sizeof(channel_list[0]))
0897      && (status == RTEMS_SUCCESSFUL);
0898        entry++) {
0899     if (channel_list[entry].driver_mode != CONS_MODE_UNUSED) {
0900       m8xx_console_chan_desc_t *cd =
0901     &m8xx_console_chan_desc[channel_list[entry].minor];
0902       /*
0903        * Do device-specific initialization
0904        */
0905       cd->mode = channel_list[entry].driver_mode;
0906       sccInitialize (cd);
0907 
0908       /*
0909        * build device name
0910        */
0911       tty_name[sizeof(tty_name)-2] = '0'+ttynum;
0912       ttynum++;
0913       /*
0914        * Register the device
0915        */
0916       status = rtems_termios_device_install(
0917     tty_name,
0918     cd->mode == TERMIOS_IRQ_DRIVEN ?
0919       &m8xx_console_handler_irq_driven : &m8xx_console_handler_polled,
0920     NULL,
0921     &cd->base
0922       );
0923       if (status != RTEMS_SUCCESSFUL) {
0924     rtems_fatal_error_occurred (status);
0925       }
0926 
0927       if (cd->chan == CONSOLE_CHN) {
0928     int rv;
0929 
0930     rv = link(tty_name, CONSOLE_DEVICE_NAME);
0931     if (rv != 0) {
0932       rtems_fatal_error_occurred (RTEMS_IO_ERROR);
0933     }
0934       }
0935     }
0936   }
0937 
0938   /*
0939    * enable printk support
0940    */
0941   BSP_output_chan = PRINTK_CHN;
0942 
0943   return RTEMS_SUCCESSFUL;
0944 }