Index: bsps/powerpc/mpc8260ads/dev/console-generic.c
===================================================================
--- bsps/powerpc/mpc8260ads/dev/console-generic.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
+++ bsps/powerpc/mpc8260ads/dev/console-generic.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
@@ -0,0 +1,1096 @@
+/*
+ *  General Serial I/O functions.
+ *
+ *  This file contains the functions for performing serial I/O.
+ *  The actual system calls (console_*) should be in the BSP part
+ *  of the source tree. That way different BSPs can use whichever
+ *  SMCs and SCCs they want. Originally, all the stuff was in
+ *  this file, and it caused problems with one BSP using SCC2
+ *  as /dev/console, others using SMC1 for /dev/console, etc.
+ *
+ *  On-chip resources used:
+ *   resource   minor                note
+ *    SMC1       0
+ *    SMC2       1
+ *    SCC1       2
+ *    SCC2       3
+ *    SCC3       4
+ *    SCC4       5
+ *    BRG1
+ *    BRG2
+ *    BRG3
+ *    BRG4
+ */
+
+/*
+ *  Author: Jay Monkman (jmonkman@frasca.com)
+ *  Copyright (C) 1998 by Frasca International, Inc.
+ *
+ *  Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by:
+ *    W. Eric Norum
+ *    Saskatchewan Accelerator Laboratory
+ *    University of Saskatchewan
+ *    Saskatoon, Saskatchewan, CANADA
+ *    eric@skatter.usask.ca
+ *
+ *  COPYRIGHT (c) 1989-1998.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
+ *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
+ *  Copyright (c) 1999, National Research Council of Canada
+ *
+ *  Copyright (c) 2001, Surrey Satellite Technology Ltd
+ *    SCC1 and SSC2 are used on MPC8260ADS board
+ *    SMCs are unused
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <mpc8260.h>
+#include <mpc8260/console.h>
+#include <mpc8260/cpm.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <bsp/irq.h>
+#include <rtems/bspIo.h>   /* for printk */
+
+/*
+ * Interrupt-driven input buffer
+ */
+#define RXBUFSIZE       16
+
+/*
+ *  I/O buffers and pointers to buffer descriptors.
+ *  Currently, single buffered input is done. This will work only
+ *  if the Rx interrupts are serviced quickly.
+ *
+ *  TODO: Add a least double buffering for safety.
+ */
+static volatile char rxBuf[NUM_PORTS][RXBUFSIZE];
+static volatile char txBuf[NUM_PORTS];
+
+/* SCC/SMC buffer descriptors */
+static volatile m8260BufferDescriptor_t *RxBd[NUM_PORTS], *TxBd[NUM_PORTS];
+
+/* Used to track termios private data for callbacks */
+struct rtems_termios_tty *ttyp[NUM_PORTS];
+
+#if 0
+/* Used to record previous ISR */
+static rtems_isr_entry old_handler[NUM_PORTS];
+#endif
+
+/*
+ * Device-specific routines
+ */
+static int m8xx_smc_set_attributes(int, const struct termios*);
+static int m8xx_scc_set_attributes(int, const struct termios*);
+static rtems_isr m8xx_smc1_interrupt_handler(rtems_irq_hdl_param unused);
+static rtems_isr m8xx_smc2_interrupt_handler(rtems_irq_hdl_param unused);
+static rtems_isr m8xx_scc1_interrupt_handler(rtems_irq_hdl_param unused);
+static rtems_isr m8xx_scc2_interrupt_handler(rtems_irq_hdl_param unused);
+static rtems_isr m8xx_scc3_interrupt_handler(rtems_irq_hdl_param unused);
+static rtems_isr m8xx_scc4_interrupt_handler(rtems_irq_hdl_param unused);
+
+/*
+ * Hardware-dependent portion of tcsetattr().
+ */
+static int
+m8xx_smc_set_attributes (int minor, const struct termios *t)
+{
+  int baud, brg=0, csize=0, ssize, psize;
+  uint16_t   clen=0, cstopb, parenb, parodd, cread;
+
+  /* Baud rate */
+  switch (t->c_ospeed) {
+  default:      baud = -1;      break;
+  case B50:     baud = 50;      break;
+  case B75:     baud = 75;      break;
+  case B110:    baud = 110;     break;
+  case B134:    baud = 134;     break;
+  case B150:    baud = 150;     break;
+  case B200:    baud = 200;     break;
+  case B300:    baud = 300;     break;
+  case B600:    baud = 600;     break;
+  case B1200:   baud = 1200;    break;
+  case B1800:   baud = 1800;    break;
+  case B2400:   baud = 2400;    break;
+  case B4800:   baud = 4800;    break;
+  case B9600:   baud = 9600;    break;
+  case B19200:  baud = 19200;   break;
+  case B38400:  baud = 38400;   break;
+  case B57600:  baud = 57600;   break;
+  case B115200: baud = 115200;  break;
+  case B230400: baud = 230400;  break;
+  case B460800: baud = 460800;  break;
+  }
+  if (baud > 0) {
+   switch( minor ) {
+      case SMC1_MINOR:
+        /* SMC1 can only choose between BRG1 and 7 */
+        brg = m8xx_get_brg( M8260_SMC1_BRGS, baud*16 ) + 1;
+ 	m8260.cmxsmr &= ~0x30;
+	m8260.cmxsmr |= (brg==1? 0x00: 0x10 );
+        break;
+      case SMC2_MINOR:
+        /* SMC2 can only choose between BRG2 and 8 */
+	brg = m8xx_get_brg(  M8260_SMC2_BRGS, baud*16 ) + 1;
+ 	m8260.cmxsmr &= ~0x30;
+	m8260.cmxsmr |= (brg==2? 0x00: 0x01 );
+        break;
+    }
+  }
+
+  /* Number of data bits */
+  switch ( t->c_cflag & CSIZE ) {
+    case CS5:     csize = 5;       break;
+    case CS6:     csize = 6;       break;
+    case CS7:     csize = 7;       break;
+    case CS8:     csize = 8;       break;
+  }
+
+  /* Stop bits */
+  if ( t->c_cflag & CSTOPB ) {
+    cstopb = 0x0400;              /* Two stop bits */
+    ssize  = 2;
+  } else {
+    cstopb = 0x0000;              /* One stop bit */
+    ssize  = 1;
+  }
+
+  /* Parity */
+  if ( t->c_cflag & PARENB ) {
+    parenb = 0x0200;              /* Parity enabled on Tx and Rx */
+    psize  = 1;
+  } else {
+    parenb = 0x0000;              /* No parity on Tx and Rx */
+    psize  = 0;
+  }
+
+  if ( t->c_cflag & PARODD )
+    parodd = 0x0000;              /* Odd parity */
+  else
+    parodd = 0x0100;
+
+  /*
+   * Character Length = start + data + parity + stop - 1
+   */
+  switch ( 1 + csize + psize + ssize - 1 ) {
+    case 6:     clen = 0x3000;       break;
+    case 7:     clen = 0x3800;       break;
+    case 8:     clen = 0x4000;       break;
+    case 9:     clen = 0x4800;       break;
+    case 10:    clen = 0x5000;       break;
+    case 11:    clen = 0x5800;       break;
+  }
+
+  if ( t->c_cflag & CREAD )
+    cread = 0x0023;		/* UART normal operation, enable Rx and Tx */
+  else
+    cread = 0x0021;		/* UART normal operation, enable Tx */
+
+  /* Write the SIMODE/SMCMR registers */
+  switch (minor) {
+    case SMC1_MINOR:
+/*
+      m8xx.simode = ( (m8xx.simode & 0xffff8fff) | (brg << 12) );
+*/
+      m8260.smc1.smcmr = clen | cstopb | parenb | parodd | cread;
+      break;
+    case SMC2_MINOR:
+      /* CHECK THIS */
+/*
+      m8xx.simode = ( (m8xx.simode & 0x8fffffff) | (brg << 28) );
+*/
+      m8260.smc2.smcmr = clen | cstopb | parenb | parodd | cread;
+      break;
+  }
+  return 0;
+}
+
+static int
+m8xx_scc_set_attributes (int minor, const struct termios *t)
+{
+  int baud, brg=0;
+  uint16_t   csize=0, cstopb, parenb, parodd;
+
+  /* Baud rate */
+  switch (t->c_ospeed) {
+  default:      baud = -1;      break;
+  case B50:     baud = 50;      break;
+  case B75:     baud = 75;      break;
+  case B110:    baud = 110;     break;
+  case B134:    baud = 134;     break;
+  case B150:    baud = 150;     break;
+  case B200:    baud = 200;     break;
+  case B300:    baud = 300;     break;
+  case B600:    baud = 600;     break;
+  case B1200:   baud = 1200;    break;
+  case B1800:   baud = 1800;    break;
+  case B2400:   baud = 2400;    break;
+  case B4800:   baud = 4800;    break;
+  case B9600:   baud = 9600;    break;
+  case B19200:  baud = 19200;   break;
+  case B38400:  baud = 38400;   break;
+  case B57600:  baud = 57600;   break;
+  case B115200: baud = 115200;  break;
+  case B230400: baud = 230400;  break;
+  case B460800: baud = 460800;  break;
+  }
+  if (baud > 0) {
+    brg = m8xx_get_brg( M8260_SCC_BRGS, baud*16 );
+    m8260.cmxscr &= ~(0xFF000000 >> (8*(minor-SCC1_MINOR)) );
+    m8260.cmxscr |= ((brg<<(3+8*(3-(minor-SCC1_MINOR)))) &
+		     (brg<<(8*(3-(minor-SCC1_MINOR)))));
+  }
+  /* Number of data bits */
+  switch ( t->c_cflag & CSIZE ) {
+    case CS5:     csize = 0x0000;       break;
+    case CS6:     csize = 0x1000;       break;
+    case CS7:     csize = 0x2000;       break;
+    case CS8:     csize = 0x3000;       break;
+  }
+
+  /* Stop bits */
+  if ( t->c_cflag & CSTOPB )
+    cstopb = 0x4000;              /* Two stop bits */
+  else
+    cstopb = 0x0000;              /* One stop bit */
+
+  /* Parity */
+  if ( t->c_cflag & PARENB )
+    parenb = 0x0010;              /* Parity enabled on Tx and Rx */
+  else
+    parenb = 0x0000;              /* No parity on Tx and Rx */
+
+  if ( t->c_cflag & PARODD )
+    parodd = 0x0000;              /* Odd parity */
+  else
+    parodd = 0x000a;
+
+  /* Write the SICR/PSMR Registers */
+  switch (minor) {
+    case SCC1_MINOR:
+/*
+      m8xx.sicr = ( (m8xx.sicr & 0xffffc0ff) | (brg << 11) | (brg << 8) );
+*/
+      m8260.scc1.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc1.psmr & 0x8fe0) );
+      break;
+    case SCC2_MINOR:
+/*
+      m8xx.sicr = ( (m8xx.sicr & 0xffffc0ff) | (brg << 11) | (brg << 8) );
+*/
+      m8260.scc2.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc2.psmr & 0x8fe0) );
+      break;
+    case SCC3_MINOR:
+/*
+      m8xx.sicr = ( (m8xx.sicr & 0xffc0ffff) | (brg << 19) | (brg << 16) );
+*/
+      m8260.scc3.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc3.psmr & 0x8fe0) );
+      break;
+    case SCC4_MINOR:
+/*
+      m8xx.sicr = ( (m8xx.sicr & 0xc0ffffff) | (brg << 27) | (brg << 24) );
+*/
+      m8260.scc4.psmr = ( (cstopb | csize | parenb | parodd) | (m8260.scc4.psmr & 0x8fe0) );
+      break;
+  }
+
+  return 0;
+}
+
+int
+m8xx_uart_setAttributes(
+  int minor,
+  const struct termios *t
+)
+{
+  /*
+   * Check that port number is valid
+   */
+  if ( (minor < SMC1_MINOR) || (minor > NUM_PORTS-1) )
+    return 0;
+
+  switch (minor) {
+    case SMC1_MINOR:
+    case SMC2_MINOR:
+      return m8xx_smc_set_attributes( minor, t );
+
+    case SCC1_MINOR:
+    case SCC2_MINOR:
+    case SCC3_MINOR:
+    case SCC4_MINOR:
+      return m8xx_scc_set_attributes( minor, t );
+  }
+  return 0;
+}
+
+/*
+ * Interrupt handlers
+ */
+static void
+m8xx_scc1_interrupt_handler (rtems_irq_hdl_param unused)
+{
+  /*
+   * Buffer received?
+   */
+  if ((m8260.scc1.sccm & M8260_SCCE_RX) && (m8260.scc1.scce & M8260_SCCE_RX)) {
+    m8260.scc1.scce = M8260_SCCE_RX;    /* Clear the event */
+
+
+    /* Check that the buffer is ours */
+    if ((RxBd[SCC1_MINOR]->status & M8260_BD_EMPTY) == 0) {
+      rtems_cache_invalidate_multiple_data_lines(
+        (const void *) RxBd[SCC1_MINOR]->buffer,
+        RxBd[SCC1_MINOR]->length );
+      rtems_termios_enqueue_raw_characters(
+        (void *)ttyp[SCC1_MINOR],
+        (char *)RxBd[SCC1_MINOR]->buffer,
+        (int)RxBd[SCC1_MINOR]->length );
+      RxBd[SCC1_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
+                                 M8260_BD_INTERRUPT;
+    }
+  }
+
+  /*
+   * Buffer transmitted?
+   */
+  if (m8260.scc1.scce & M8260_SCCE_TX) {
+    m8260.scc1.scce = M8260_SCCE_TX;  /* Clear the event */
+
+    /* Check that the buffer is ours */
+    if ((TxBd[SCC1_MINOR]->status & M8260_BD_READY) == 0)
+      rtems_termios_dequeue_characters (
+        (void *)ttyp[SCC1_MINOR],
+        (int)TxBd[SCC1_MINOR]->length);
+  }
+
+#if 0
+  m8260.sipnr_l |= M8260_SIMASK_SCC1;      /* Clear pending register */
+#endif
+}
+
+static void
+m8xx_scc2_interrupt_handler (rtems_irq_hdl_param unused)
+{
+  /*
+   * Buffer received?
+   */
+  if ((m8260.scc2.sccm & M8260_SCCE_RX) && (m8260.scc2.scce & M8260_SCCE_RX)) {
+    m8260.scc2.scce = M8260_SCCE_RX;    /* Clear the event */
+
+
+    /* Check that the buffer is ours */
+    if ((RxBd[SCC2_MINOR]->status & M8260_BD_EMPTY) == 0) {
+      rtems_cache_invalidate_multiple_data_lines(
+        (const void *) RxBd[SCC2_MINOR]->buffer,
+        RxBd[SCC2_MINOR]->length );
+      rtems_termios_enqueue_raw_characters(
+        (void *)ttyp[SCC2_MINOR],
+        (char *)RxBd[SCC2_MINOR]->buffer,
+        (int)RxBd[SCC2_MINOR]->length );
+      RxBd[SCC2_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
+                                 M8260_BD_INTERRUPT;
+    }
+  }
+
+  /*
+   * Buffer transmitted?
+   */
+  if (m8260.scc2.scce & M8260_SCCE_TX) {
+    m8260.scc2.scce = M8260_SCCE_TX;  /* Clear the event */
+
+    /* Check that the buffer is ours */
+    if ((TxBd[SCC2_MINOR]->status & M8260_BD_READY) == 0)
+      rtems_termios_dequeue_characters (
+        (void *)ttyp[SCC2_MINOR],
+        (int)TxBd[SCC2_MINOR]->length);
+  }
+
+#if 0
+  m8260.sipnr_l |= M8260_SIMASK_SCC2;      /* Clear pending register */
+#endif
+}
+
+static void
+m8xx_scc3_interrupt_handler (rtems_irq_hdl_param unused)
+{
+  /*
+   * Buffer received?
+   */
+  if ((m8260.scc3.sccm & M8260_SCCE_RX) && (m8260.scc3.scce & M8260_SCCE_RX)) {
+    m8260.scc3.scce = M8260_SCCE_RX;  /* Clear the event */
+
+
+    /* Check that the buffer is ours */
+    if ((RxBd[SCC3_MINOR]->status & M8260_BD_EMPTY) == 0) {
+      rtems_cache_invalidate_multiple_data_lines(
+        (const void *) RxBd[SCC3_MINOR]->buffer,
+        RxBd[SCC3_MINOR]->length );
+      rtems_termios_enqueue_raw_characters(
+        (void *)ttyp[SCC3_MINOR],
+        (char *)RxBd[SCC3_MINOR]->buffer,
+        (int)RxBd[SCC3_MINOR]->length );
+      RxBd[SCC3_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
+                                 M8260_BD_INTERRUPT;
+    }
+  }
+
+  /*
+   * Buffer transmitted?
+   */
+  if (m8260.scc3.scce & M8260_SCCE_TX) {
+    m8260.scc3.scce = M8260_SCCE_TX;    /* Clear the event */
+
+    /* Check that the buffer is ours */
+    if ((TxBd[SCC3_MINOR]->status & M8260_BD_READY) == 0)
+      rtems_termios_dequeue_characters (
+        (void *)ttyp[SCC3_MINOR],
+        (int)TxBd[SCC3_MINOR]->length);
+  }
+
+
+#if 0
+  m8260.sipnr_l |= M8260_SIMASK_SCC3;      /* Clear pending register */
+#endif
+}
+
+static void
+m8xx_scc4_interrupt_handler (rtems_irq_hdl_param unused)
+{
+  /*
+   * Buffer received?
+   */
+  if ((m8260.scc4.sccm & M8260_SCCE_RX) && (m8260.scc4.scce & M8260_SCCE_RX)) {
+    m8260.scc4.scce = M8260_SCCE_RX;  /* Clear the event */
+
+
+    /* Check that the buffer is ours */
+    if ((RxBd[SCC4_MINOR]->status & M8260_BD_EMPTY) == 0) {
+      rtems_cache_invalidate_multiple_data_lines(
+        (const void *) RxBd[SCC4_MINOR]->buffer,
+        RxBd[SCC4_MINOR]->length );
+      rtems_termios_enqueue_raw_characters(
+        (void *)ttyp[SCC4_MINOR],
+        (char *)RxBd[SCC4_MINOR]->buffer,
+        (int)RxBd[SCC4_MINOR]->length );
+      RxBd[SCC4_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
+                                 M8260_BD_INTERRUPT;
+    }
+  }
+
+  /*
+   * Buffer transmitted?
+   */
+  if (m8260.scc4.scce & M8260_SCCE_TX) {
+    m8260.scc4.scce = M8260_SCCE_TX;    /* Clear the event */
+
+    /* Check that the buffer is ours */
+    if ((TxBd[SCC4_MINOR]->status & M8260_BD_READY) == 0)
+      rtems_termios_dequeue_characters (
+        (void *)ttyp[SCC4_MINOR],
+        (int)TxBd[SCC4_MINOR]->length);
+  }
+
+#if 0
+  m8260.sipnr_l |= M8260_SIMASK_SCC4;      /* Clear pending register */
+#endif
+}
+
+static void
+m8xx_smc1_interrupt_handler (rtems_irq_hdl_param unused)
+{
+  /*
+   * Buffer received?
+   */
+  if (m8260.smc1.smce & M8260_SMCE_RX) {
+    m8260.smc1.smce = M8260_SMCE_RX;  /* Clear the event */
+
+
+    /* Check that the buffer is ours */
+    if ((RxBd[SMC1_MINOR]->status & M8260_BD_EMPTY) == 0) {
+      rtems_cache_invalidate_multiple_data_lines(
+        (const void *) RxBd[SMC1_MINOR]->buffer,
+        RxBd[SMC1_MINOR]->length );
+      rtems_termios_enqueue_raw_characters(
+        (void *)ttyp[SMC1_MINOR],
+        (char *)RxBd[SMC1_MINOR]->buffer,
+        (int)RxBd[SMC1_MINOR]->length );
+      RxBd[SMC1_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
+                                 M8260_BD_INTERRUPT;
+    }
+  }
+
+  /*
+   * Buffer transmitted?
+   */
+  if (m8260.smc1.smce & M8260_SMCE_TX) {
+    m8260.smc1.smce = M8260_SMCE_TX;    /* Clear the event */
+
+    /* Check that the buffer is ours */
+    if ((TxBd[SMC1_MINOR]->status & M8260_BD_READY) == 0)
+      rtems_termios_dequeue_characters (
+        (void *)ttyp[SMC1_MINOR],
+        (int)TxBd[SMC1_MINOR]->length);
+  }
+
+#if 0
+  m8260.sipnr_l = 0x00001000; /* Clear SMC1 interrupt-in-service bit */
+#endif
+}
+
+static void
+m8xx_smc2_interrupt_handler (rtems_irq_hdl_param unused)
+{
+  /*
+   * Buffer received?
+   */
+  if (m8260.smc2.smce & M8260_SMCE_RX) {
+    m8260.smc2.smce = M8260_SMCE_RX;  /* Clear the event */
+
+
+    /* Check that the buffer is ours */
+    if ((RxBd[SMC2_MINOR]->status & M8260_BD_EMPTY) == 0) {
+      rtems_cache_invalidate_multiple_data_lines(
+        (const void *) RxBd[SMC2_MINOR]->buffer,
+        RxBd[SMC2_MINOR]->length );
+      rtems_termios_enqueue_raw_characters(
+        (void *)ttyp[SMC2_MINOR],
+        (char *)RxBd[SMC2_MINOR]->buffer,
+        (int)RxBd[SMC2_MINOR]->length );
+      RxBd[SMC2_MINOR]->status = M8260_BD_EMPTY | M8260_BD_WRAP |
+                                 M8260_BD_INTERRUPT;
+    }
+  }
+
+  /*
+   * Buffer transmitted?
+   */
+  if (m8260.smc2.smce & M8260_SMCE_TX) {
+    m8260.smc2.smce = M8260_SMCE_TX;    /* Clear the event */
+
+    /* Check that the buffer is ours */
+    if ((TxBd[SMC2_MINOR]->status & M8260_BD_READY) == 0)
+      rtems_termios_dequeue_characters (
+        (void *)ttyp[SMC2_MINOR],
+        (int)TxBd[SMC2_MINOR]->length);
+  }
+
+#if 0
+  m8260.sipnr_l = 0x00000800; /* Clear SMC2 interrupt-in-service bit */
+#endif
+}
+
+static void m8xx_scc_enable(const rtems_irq_connect_data* ptr)
+{
+  volatile m8260SCCRegisters_t *sccregs = 0;
+  switch (ptr->name) {
+  case BSP_CPM_IRQ_SCC4 :
+    m8260.sipnr_l |= M8260_SIMASK_SCC4;
+    sccregs = &m8260.scc4;
+    break;
+  case BSP_CPM_IRQ_SCC3 :
+    m8260.sipnr_l |= M8260_SIMASK_SCC3;
+    sccregs = &m8260.scc3;
+    break;
+  case BSP_CPM_IRQ_SCC2 :
+    m8260.sipnr_l |= M8260_SIMASK_SCC2;
+    sccregs = &m8260.scc2;
+    break;
+  case BSP_CPM_IRQ_SCC1 :
+    m8260.sipnr_l |= M8260_SIMASK_SCC1;
+    sccregs = &m8260.scc1;
+    break;
+  default:
+    break;
+  }
+  sccregs->sccm = 3;
+}
+
+static void m8xx_scc_disable(const rtems_irq_connect_data* ptr)
+{
+  volatile m8260SCCRegisters_t *sccregs = 0;
+  switch (ptr->name) {
+  case BSP_CPM_IRQ_SCC4 :
+    sccregs = &m8260.scc4;
+    break;
+  case BSP_CPM_IRQ_SCC3 :
+    sccregs = &m8260.scc3;
+    break;
+  case BSP_CPM_IRQ_SCC2 :
+    sccregs = &m8260.scc2;
+    break;
+  case BSP_CPM_IRQ_SCC1 :
+    sccregs = &m8260.scc1;
+    break;
+  default:
+    break;
+  }
+  sccregs->sccm &= (~3);
+}
+
+static int m8xx_scc_isOn(const rtems_irq_connect_data* ptr)
+{
+ return BSP_irq_enabled_at_cpm (ptr->name);
+}
+
+static rtems_irq_connect_data consoleIrqData =
+{
+  BSP_CPM_IRQ_SCC1,
+  (rtems_irq_hdl)m8xx_scc1_interrupt_handler,
+  NULL,
+  (rtems_irq_enable) m8xx_scc_enable,
+  (rtems_irq_disable) m8xx_scc_disable,
+  (rtems_irq_is_enabled) m8xx_scc_isOn
+};
+
+void
+m8xx_uart_scc_initialize (int minor)
+{
+  unsigned char brg;
+  volatile m8260SCCparms_t *sccparms = 0;
+  volatile m8260SCCRegisters_t *sccregs = 0;
+
+  /*
+   * Check that minor number is valid
+   */
+  if ( (minor < SCC1_MINOR) || (minor > NUM_PORTS-1) )
+    return;
+
+  /* Get the sicr clock source bit values for 9600 bps */
+  brg = m8xx_get_brg(M8260_SCC_BRGS, 9600*16);
+
+  m8260.cmxscr &= ~(0xFF000000 >> (8*(minor-SCC1_MINOR)) );
+  m8260.cmxscr |= (brg<<(3+8*(3-(minor-SCC1_MINOR))));
+  m8260.cmxscr |= (brg<<(8*(3-(minor-SCC1_MINOR))));
+
+  /*
+   * Allocate buffer descriptors
+   */
+  RxBd[minor] = m8xx_bd_allocate(1);
+  TxBd[minor] = m8xx_bd_allocate(1);
+
+  /*
+   * Configure ports to enable TXDx and RXDx pins
+   */
+
+  m8260.ppard |=  (0x07 << ((minor-SCC1_MINOR)*3));
+  m8260.psord &= ~(0x07 << ((minor-SCC1_MINOR)*3));
+  if( minor == SCC1_MINOR )
+    m8260.psord |= 0x02;
+  m8260.pdird |=  (0x06 << ((minor-SCC1_MINOR)*3));
+  m8260.pdird &= ~(0x01 << ((minor-SCC1_MINOR)*3));
+
+
+  /*
+   * Set up SMC1 parameter RAM common to all protocols
+   */
+  if( minor == SCC1_MINOR ) {
+    sccparms = (m8260SCCparms_t*)&m8260.scc1p;
+    sccregs  = (m8260SCCRegisters_t*)&m8260.scc1;
+  }
+  else if( minor == SCC2_MINOR ) {
+    sccparms = (m8260SCCparms_t*)&m8260.scc2p;
+    sccregs  = (m8260SCCRegisters_t*)&m8260.scc2;
+  }
+  else if( minor == SCC3_MINOR ) {
+    sccparms = (m8260SCCparms_t*)&m8260.scc3p;
+    sccregs  = (m8260SCCRegisters_t*)&m8260.scc3;
+  }
+  else {
+    sccparms = (m8260SCCparms_t*)&m8260.scc4p;
+    sccregs  = (m8260SCCRegisters_t*)&m8260.scc4;
+  }
+
+  sccparms->rbase = (char *)RxBd[minor] - (char *)&m8260;
+  sccparms->tbase = (char *)TxBd[minor] - (char *)&m8260;
+
+  sccparms->rfcr = M8260_RFCR_MOT | M8260_RFCR_60X_BUS;
+  sccparms->tfcr = M8260_TFCR_MOT | M8260_TFCR_60X_BUS;
+  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
+    sccparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
+  else
+    sccparms->mrblr = 1;            /* Maximum Rx buffer size */
+  sccparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
+  sccparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
+
+  sccparms->un.uart.parec = 0;      /* Clear parity error counter */
+  sccparms->un.uart.frmec = 0;      /* Clear framing error counter */
+  sccparms->un.uart.nosec = 0;      /* Clear noise counter */
+  sccparms->un.uart.brkec = 0;      /* Clear break counter */
+
+  sccparms->un.uart.uaddr[0] = 0;   /* Not in multidrop mode, so clear */
+  sccparms->un.uart.uaddr[1] = 0;   /* Not in multidrop mode, so clear */
+  sccparms->un.uart.toseq  = 0;     /* Tx Out-Of-SEQuence--no XON/XOFF now */
+
+  sccparms->un.uart.character[0] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[1] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[2] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[3] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[4] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[5] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[6] = 0x8000; /* Entry is invalid */
+  sccparms->un.uart.character[7] = 0x8000; /* Entry is invalid */
+
+  sccparms->un.uart.rccm = 0xc0ff;  /* No masking */
+
+  /*
+   * Set up the Receive Buffer Descriptor
+   */
+  RxBd[minor]->status = M8260_BD_EMPTY | M8260_BD_WRAP | M8260_BD_INTERRUPT;
+  RxBd[minor]->length = 0;
+  RxBd[minor]->buffer = rxBuf[minor];
+
+  /*
+   * Setup the Transmit Buffer Descriptor
+   */
+  TxBd[minor]->status = M8260_BD_WRAP;
+
+ /*
+   * Set up SCCx general and protocol-specific mode registers
+   */
+  sccregs->gsmr_h = 0x00000020;     /* RFW=low latency operation */
+  sccregs->gsmr_l = 0x00028004;     /* TDCR=RDCR=16x clock mode, MODE=uart*/
+  sccregs->scce = ~0;               /* Clear any pending event */
+  sccregs->sccm = 0;                /* Mask all interrupt/event sources */
+  sccregs->psmr = 0x3000;           /* Normal operation & mode, 1 stop bit,
+                                       8 data bits, no parity */
+  sccregs->dsr = 0x7E7E;            /* No fractional stop bits */
+  sccregs->gsmr_l = 0x00028034;     /* ENT=enable Tx, ENR=enable Rx */
+
+  /*
+   *  Initialize the Rx and Tx with the new parameters.
+   */
+  switch (minor) {
+    case SCC1_MINOR:
+      m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC1);
+      break;
+    case SCC2_MINOR:
+      m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC2);
+      break;
+    case SCC3_MINOR:
+      m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC3);
+      break;
+    case SCC4_MINOR:
+      m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC4);
+      break;
+  }
+
+  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
+    switch (minor) {
+      case SCC1_MINOR:
+	consoleIrqData.name = BSP_CPM_IRQ_SCC1;
+        consoleIrqData.hdl = m8xx_scc1_interrupt_handler;
+	break;
+      case SCC2_MINOR:
+	consoleIrqData.name = BSP_CPM_IRQ_SCC2;
+        consoleIrqData.hdl = m8xx_scc2_interrupt_handler;
+	break;
+      case SCC3_MINOR:
+	consoleIrqData.name = BSP_CPM_IRQ_SCC3;
+        consoleIrqData.hdl = m8xx_scc3_interrupt_handler;
+	break;
+      case SCC4_MINOR:
+	consoleIrqData.name = BSP_CPM_IRQ_SCC4;
+        consoleIrqData.hdl = m8xx_scc4_interrupt_handler;
+	break;
+
+    }
+    if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
+      printk("Unable to connect SCC Irq handler\n");
+      rtems_fatal_error_occurred(1);
+    }
+  }
+}
+
+static void m8xx_smc_enable(const rtems_irq_connect_data* ptr)
+{
+  volatile m8260SMCRegisters_t *smcregs = 0;
+  switch (ptr->name) {
+  case BSP_CPM_IRQ_SMC1 :
+    smcregs = &m8260.smc1;
+    break;
+  case BSP_CPM_IRQ_SMC2 :
+    smcregs = &m8260.smc2;
+    break;
+  default:
+    break;
+  }
+  smcregs->smcm = 3;
+}
+
+static void m8xx_smc_disable(const rtems_irq_connect_data* ptr)
+{
+  volatile m8260SMCRegisters_t *smcregs = 0;
+  switch (ptr->name) {
+  case BSP_CPM_IRQ_SMC1 :
+    smcregs = &m8260.smc1;
+    break;
+  case BSP_CPM_IRQ_SMC2 :
+    smcregs = &m8260.smc2;
+    break;
+  default:
+    break;
+  }
+  smcregs->smcm &= (~3);
+}
+
+static int m8xx_smc_isOn(const rtems_irq_connect_data* ptr)
+{
+ return BSP_irq_enabled_at_cpm (ptr->name);
+}
+
+void
+m8xx_uart_smc_initialize (int minor)
+{
+  unsigned char brg;
+  volatile m8260SMCparms_t *smcparms = 0;
+  volatile m8260SMCRegisters_t *smcregs = 0;
+
+  /*
+   * Check that minor number is valid
+   */
+  if ( (minor < SMC1_MINOR) || (minor > SMC2_MINOR) )
+    return;
+
+  /* Get the simode clock source bit values for 9600 bps */
+  if( minor == SMC1_MINOR )
+    brg = m8xx_get_brg(M8260_SMC1_BRGS, 9600*16);
+  else
+    brg = m8xx_get_brg(M8260_SMC2_BRGS, 9600*16);
+  (void) brg; /* avoid set but not used warning */
+
+  /*
+   * Allocate buffer descriptors
+   */
+  RxBd[minor] = m8xx_bd_allocate (1);
+  TxBd[minor] = m8xx_bd_allocate (1);
+
+  /*
+   *  Get the address of the parameter RAM for the specified port,
+   *  configure I/O port B and put SMC in NMSI mode, connect the
+   *  SMC to the appropriate BRG.
+   *
+   *  SMC2 RxD is shared with port B bit 20
+   *  SMC2 TxD is shared with port B bit 21
+   *  SMC1 RxD is shared with port B bit 24
+   *  SMC1 TxD is shared with port B bit 25
+   */
+  switch (minor) {
+    case SMC1_MINOR:
+      smcparms = &m8260.smc1p;
+      smcregs  = &m8260.smc1;
+
+#if 0
+      m8260.pbpar |=  0x000000C0;    /* PB24 & PB25 are dedicated peripheral pins */
+      m8260.pbdir &= ~0x000000C0;    /* PB24 & PB25 must not drive UART lines */
+      m8260.pbodr &= ~0x000000C0;    /* PB24 & PB25 are not open drain */
+
+      m8260.simode &= 0xFFFF0FFF;    /* Clear SMC1CS & SMC1 for NMSI mode */
+      m8260.simode |= brg << 12;     /* SMC1CS = brg */
+#endif
+      break;
+
+    case SMC2_MINOR:
+      smcparms = &m8260.smc2p;
+      smcregs = &m8260.smc2;
+#if 0
+      m8260.pbpar |=  0x00000C00;    /* PB20 & PB21 are dedicated peripheral pins */
+      m8260.pbdir &= ~0x00000C00;    /* PB20 & PB21 must not drive the UART lines */
+      m8260.pbodr &= ~0x00000C00;    /* PB20 & PB21 are not open drain */
+
+      m8260.simode &= 0x0FFFFFFF;    /* Clear SMC2CS & SMC2 for NMSI mode */
+      m8260.simode |= brg << 28;     /* SMC2CS = brg */
+#endif
+      break;
+  }
+
+  /*
+   * Set up SMC parameter RAM common to all protocols
+   */
+  smcparms->rbase = (char *)RxBd[minor] - (char *)&m8260;
+  smcparms->tbase = (char *)TxBd[minor] - (char *)&m8260;
+  smcparms->rfcr = M8260_RFCR_MOT | M8260_RFCR_60X_BUS;
+  smcparms->tfcr = M8260_TFCR_MOT | M8260_TFCR_60X_BUS;
+  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
+    smcparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
+  else
+    smcparms->mrblr = 1;            /* Maximum Rx buffer size */
+
+  /*
+   * Set up SMC1 parameter RAM UART-specific parameters
+   */
+  smcparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
+  smcparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
+  smcparms->un.uart.brkec = 0;      /* Clear break counter */
+
+  /*
+   * Set up the Receive Buffer Descriptor
+   */
+  RxBd[minor]->status = M8260_BD_EMPTY | M8260_BD_WRAP | M8260_BD_INTERRUPT;
+  RxBd[minor]->length = 0;
+  RxBd[minor]->buffer = rxBuf[minor];
+
+  /*
+   * Setup the Transmit Buffer Descriptor
+   */
+  TxBd[minor]->status = M8260_BD_WRAP;
+
+  /*
+   * Set up SMCx general and protocol-specific mode registers
+   */
+  smcregs->smce = ~0;               /* Clear any pending events */
+  smcregs->smcm = 0;                /* Enable SMC Rx & Tx interrupts */
+  smcregs->smcmr = M8260_SMCMR_CLEN(9) | M8260_SMCMR_SM_UART;
+
+  /*
+   * Send "Init parameters" command
+   */
+  switch (minor) {
+    case SMC1_MINOR:
+      m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SMC1);
+      break;
+
+    case SMC2_MINOR:
+      m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SMC2);
+      break;
+  }
+
+  /*
+   * Enable receiver and transmitter
+   */
+  smcregs->smcmr |= M8260_SMCMR_TEN | M8260_SMCMR_REN;
+  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
+    consoleIrqData.on = m8xx_smc_enable;
+    consoleIrqData.off = m8xx_smc_disable;
+    consoleIrqData.isOn = m8xx_smc_isOn;
+    switch (minor) {
+      case SMC1_MINOR:
+	consoleIrqData.name = BSP_CPM_IRQ_SMC1;
+	consoleIrqData.hdl  = m8xx_smc1_interrupt_handler;
+	break;
+
+      case SMC2_MINOR:
+	consoleIrqData.name = BSP_CPM_IRQ_SMC2;
+	consoleIrqData.hdl  = m8xx_smc2_interrupt_handler;
+	break;
+#if 0
+      case SMC1_MINOR:
+        rtems_interrupt_catch (m8xx_smc1_interrupt_handler,
+                                    PPC_IRQ_CPM_SMC1,
+                                    &old_handler[minor]);
+
+        smcregs->smcm = 3;            /* Enable SMC1 Rx & Tx interrupts */
+        m8260.sipnr_l |= M8260_SIMASK_SMC1;      /* Clear pending register */
+        m8260.simr_l  |= M8260_SIMASK_SMC1;      /* Enable SMC1 interrupts */
+        break;
+
+      case SMC2_MINOR:
+        rtems_interrupt_catch (m8xx_smc2_interrupt_handler,
+                                    PPC_IRQ_CPM_SMC2,
+                                    &old_handler[minor]);
+
+        smcregs->smcm = 3;            /* Enable SMC2 Rx & Tx interrupts */
+        m8260.sipnr_l |= M8260_SIMASK_SMC2;      /* Clear pending register */
+        m8260.simr_l  |= M8260_SIMASK_SMC2;      /* Enable SMC2 interrupts */
+        break;
+#endif
+    }
+    if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
+      printk("Unable to connect SMC Irq handler\n");
+      rtems_fatal_error_occurred(1);
+    }
+  }
+}
+
+void
+m8xx_uart_initialize(void)
+{
+}
+
+void
+m8xx_uart_interrupts_initialize(void)
+{
+#ifdef mpc8260
+  /* CHECK THIS */
+
+#else
+
+#if defined(mpc860)
+  m8xx.cicr = 0x00E43F80;           /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
+                                       SCdP=SCC4, IRL=1, HP=PC15, IEN=1 */
+#else
+  m8xx.cicr = 0x00043F80;           /* SCaP=SCC1, SCbP=SCC2, IRL=1, HP=PC15, IEN=1 */
+#endif
+  m8xx.simask |= M8xx_SIMASK_LVM1;  /* Enable level interrupts */
+#endif
+}
+
+int
+m8xx_uart_pollRead(
+  int minor
+)
+{
+  unsigned char c;
+
+  if (RxBd[minor]->status & M8260_BD_EMPTY) {
+    return -1;
+  }
+  rtems_cache_invalidate_multiple_data_lines(
+    (const void *) RxBd[minor]->buffer,
+    RxBd[minor]->length
+  );
+  c = ((char *)RxBd[minor]->buffer)[0];
+  RxBd[minor]->status = M8260_BD_EMPTY | M8260_BD_WRAP;
+  return c;
+}
+
+/*
+ *  TODO: Get a free buffer and set it up.
+ */
+ssize_t
+m8xx_uart_write(
+  int minor,
+  const char *buf,
+  size_t len
+)
+{
+  if (len > 0) {
+    while( (TxBd[minor]->status) & M8260_BD_READY );
+
+    rtems_cache_flush_multiple_data_lines( buf, len );
+    TxBd[minor]->buffer = (char *) buf;
+    TxBd[minor]->length = len;
+    TxBd[minor]->status = M8260_BD_READY | M8260_BD_WRAP | M8260_BD_INTERRUPT;
+  }
+
+  return 0;
+}
+
+ssize_t
+m8xx_uart_pollWrite(
+  int minor,
+  const char *buf,
+  size_t len
+)
+{
+  size_t retval = len;
+
+  while (len--) {
+    while (TxBd[minor]->status & M8260_BD_READY)
+      continue;
+    txBuf[minor] = *buf++;
+    rtems_cache_flush_multiple_data_lines( (void *)&txBuf[minor], 1 );
+    TxBd[minor]->buffer = &txBuf[minor];
+    TxBd[minor]->length = 1;
+    TxBd[minor]->status = M8260_BD_READY | M8260_BD_WRAP;
+  }
+
+  return retval;
+}
Index: bsps/powerpc/mpc8260ads/start/brg.c
===================================================================
--- bsps/powerpc/mpc8260ads/start/brg.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
+++ bsps/powerpc/mpc8260ads/start/brg.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
@@ -0,0 +1,198 @@
+/*
+ *  Baud rate generator management functions.
+ *
+ *  This file contains routines for allocating baud rate generators
+ *  and clock sources to the SCCs and FCCs on the MPC8260.  The
+ *  allocation is a little more complex on this processor because
+ *  there are restrictions on which brgs and clks can be assigned to
+ *  a particular port.  Rather than coming up with a fixed assignment
+ *  these routines try to allocate resources sensibly.
+ *
+ *  *** All attempts to allocate a BRG or CLK line should be made via
+ *      calls to these routines or they simply won't work.
+ */
+
+/*
+ *  Author: Andy Dachs <a.dachs@sstl.co.uk>
+ *  Copyright Surrey Satellite Technology Limited (SSTL), 2001
+ *
+ *  Derived in part from work by:
+ *
+ *    Author: Jay Monkman (jmonkman@frasca.com)
+ *    Copyright (C) 1998 by Frasca International, Inc.
+ *  and
+ *    W. Eric Norum
+ *    Saskatchewan Accelerator Laboratory
+ *    University of Saskatchewan
+ *    Saskatoon, Saskatchewan, CANADA
+ *    eric@skatter.usask.ca
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <mpc8260.h>
+#include <mpc8260/cpm.h>
+#include <rtems/bspIo.h>
+
+#define NUM_BRGS 8
+#define NUM_CLKS 20
+
+/* Used to track the usage of the baud rate generators */
+/* (initialised to zeros) */
+static unsigned long brg_spd[NUM_BRGS];
+static unsigned int brg_use_count[NUM_BRGS];
+
+/* Used to track the usage of the clock inputs */
+/* (initialised to zeros) */
+static unsigned int clk_use_count[NUM_BRGS];
+
+/*
+ * Compute baud-rate-generator configuration register value
+ */
+int
+m8xx_get_brg_cd (int baud)
+{
+  int divisor;
+  int div16 = 0;
+
+  divisor = ((bsp_serial_per_sec) + (baud / 2)) / baud;
+  if (divisor > 4096) {
+    div16 = 1;
+    divisor = (divisor + 8) / 16;
+  }
+  return M8260_BRG_EN | M8260_BRG_EXTC_BRGCLK |
+    ((divisor - 1) << 1) | div16;
+}
+
+/*
+ *  Allocates an existing brg if one is already programmed for the same
+ *  baud rate.  Otherwise a new brg is assigned
+ *  AFD: on the mpc8260 only some combinations of SCC/SMC and BRG are allowed
+ *  so add a mask which specifies which of the BRGs we can choose from
+ */
+int
+m8xx_get_brg(unsigned brgmask, int baud)
+{
+  int i;
+
+  /* first try to find a BRG that is already at the right speed */
+  for ( i = 0; i < NUM_BRGS; i++ ) {
+    if ( (1 << i) & brgmask )    /* is this brg allowed? */
+      if ( brg_spd[i] == baud ) {
+        break;
+    }
+  }
+
+  if ( i == NUM_BRGS ) { /* I guess we didn't find one */
+    for ( i = 0; i < NUM_BRGS; i++ ) {
+      if (((1<<i) & brgmask) && (brg_use_count[i] == 0)) {
+         break;
+      }
+    }
+  }
+  if (i != NUM_BRGS) {
+    brg_use_count[i]++;
+    brg_spd[i]=baud;
+    switch (i) {
+      case 0:
+        m8260.brgc1 = M8260_BRG_RST;
+        m8260.brgc1 = m8xx_get_brg_cd(baud);
+        break;
+      case 1:
+        m8260.brgc2 = M8260_BRG_RST;
+        m8260.brgc2 = m8xx_get_brg_cd(baud);
+        break;
+      case 2:
+        m8260.brgc3 = M8260_BRG_RST;
+        m8260.brgc3 = m8xx_get_brg_cd(baud);
+        break;
+      case 3:
+        m8260.brgc4 = M8260_BRG_RST;
+        m8260.brgc4 = m8xx_get_brg_cd(baud);
+        break;
+      case 4:
+        m8260.brgc5 = M8260_BRG_RST;
+        m8260.brgc5 = m8xx_get_brg_cd(baud);
+        break;
+      case 5:
+        m8260.brgc6 = M8260_BRG_RST;
+        m8260.brgc6 = m8xx_get_brg_cd(baud);
+        break;
+      case 6:
+        m8260.brgc7 = M8260_BRG_RST;
+        m8260.brgc7 = m8xx_get_brg_cd(baud);
+        break;
+      case 7:
+        m8260.brgc8 = M8260_BRG_RST;
+        m8260.brgc8 = m8xx_get_brg_cd(baud);
+        break;
+    }
+    return i;
+  }
+
+  else {
+    printk( "Could not assign a brg for %d\n", baud );
+    return -1;
+  }
+}
+
+
+/*
+ * When the brg is no longer needed call this routine to free the
+ * resource for re--use.
+ */
+void
+m8xx_free_brg( int brg_num )
+{
+  if ( (brg_num>=0) && (brg_num<NUM_BRGS) )
+    if (brg_use_count[brg_num] > 0 )
+      brg_use_count[brg_num]--;
+}
+
+#ifdef DEBUG_BRG
+static void m8xx_dump_brgs( void )
+{
+  int i;
+  for (i=0; i<NUM_BRGS; i++ )
+    printk( "Brg[%d]: %d %d\n", i, brg_use_count[i], brg_spd[i] );
+}
+#endif
+
+/*
+ * Reserve one of a range of clock inputs
+ */
+int
+m8xx_get_clk( unsigned clkmask )
+{
+  int i;
+
+  for ( i = 0; i < NUM_CLKS; i++ ) {
+    if (((1<<i) & clkmask) && (clk_use_count[i] == 0)) {
+       break;
+    }
+  }
+
+  if (i != NUM_CLKS) {
+    clk_use_count[i]++;
+    return i;
+  } else {
+    printk( "Could not assign clock in the range %X\n", clkmask );
+    return -1;
+  }
+}
+
+
+/*
+ * When the clock is no longer needed call this routine to free the
+ * resource for re--use.
+ */
+void
+m8xx_free_clk( int clk_num )
+{
+  if ( (clk_num>=0) && (clk_num<NUM_BRGS) )
+     if (clk_use_count[clk_num] > 0 )
+       clk_use_count[clk_num]--;
+}
Index: bsps/powerpc/mpc8260ads/start/cp.c
===================================================================
--- bsps/powerpc/mpc8260ads/start/cp.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
+++ bsps/powerpc/mpc8260ads/start/cp.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
@@ -0,0 +1,34 @@
+/*
+ * cp.c
+ *
+ * MPC8xx CPM RISC Communication Processor routines.
+ *
+ * Based on code (alloc860.c in eth_comm port) by
+ * Jay Monkman (jmonkman@frasca.com),
+ * which, in turn, is based on code by
+ * W. Eric Norum (eric@skatter.usask.ca).
+ *
+ * Modifications by Darlene Stewart (Darlene.Stewart@iit.nrc.ca):
+ * Copyright (c) 1999, National Research Council of Canada
+ */
+
+#include <rtems.h>
+#include <mpc8260.h>
+#include <mpc8260/cpm.h>
+
+/*
+ * Send a command to the CPM RISC processer
+ */
+
+void m8xx_cp_execute_cmd( uint32_t   command )
+{
+  uint16_t   lvl;
+
+  rtems_interrupt_disable(lvl);
+  while (m8260.cpcr & M8260_CR_FLG) {
+    continue;
+  }
+
+  m8260.cpcr = command | M8260_CR_FLG;
+  rtems_interrupt_enable (lvl);
+}
Index: bsps/powerpc/mpc8260ads/start/dpram.c
===================================================================
--- bsps/powerpc/mpc8260ads/start/dpram.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
+++ bsps/powerpc/mpc8260ads/start/dpram.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
@@ -0,0 +1,93 @@
+/*
+ * dpram.c
+ *
+ * MPC8260 dual-port RAM allocation routines
+ *
+ * Based on code in mpc8xx which is
+ * Based on code (alloc860.c in eth_comm port) by
+ * Jay Monkman (jmonkman@frasca.com),
+ * which, in turn, is based on code by
+ * W. Eric Norum (eric@skatter.usask.ca).
+ *
+ *
+ * Modifications :
+ * Copyright (c) 1999, National Research Council of Canada
+ *
+ * MPC8260 modifications Andy Dachs, <a.dachs@sstl.co.uk>
+ * Surrey Satellite Technology Limited, 2001
+ */
+
+#include <rtems.h>
+#include <rtems/error.h>
+
+#include <mpc8260.h>
+#include <mpc8260/cpm.h>
+
+/*
+ * Allocation order:
+ *      - Dual-Port RAM section 0
+ *      - Dual-Port RAM section 1
+ *      - Dual-Port RAM section 2
+ *      - Dual-Port RAM section 3
+ */
+static struct {
+  uint8_t	*base;
+  size_t         size;
+  unsigned int   used;
+} dpram_regions[] = {
+/*  { (uint8_t *)&m8260.dpram0[0],    sizeof m8260.dpram0,     0 },*/
+  { (uint8_t *)&m8260.dpram1[0],    sizeof m8260.dpram1,     0 },
+/*  { (uint8_t *)&m8260.dpram2[0],    sizeof m8260.dpram2,     0 },*/
+  { (uint8_t *)&m8260.dpram3[0],    sizeof m8260.dpram3,     0 }
+};
+
+#define	NUM_DPRAM_REGIONS	(sizeof(dpram_regions) / sizeof(dpram_regions[0]))
+
+void *
+m8xx_dpram_allocate( unsigned int byte_count )
+{
+  unsigned int i;
+  ISR_Level level;
+  void *blockp = NULL;
+
+  byte_count = (byte_count + 3) & ~0x3;
+
+  /*
+   * Running with interrupts disabled is usually considered bad
+   * form, but this routine is probably being run as part of an
+   * initialization sequence so the effect shouldn't be too severe.
+   */
+  _ISR_Local_disable (level);
+
+  for ( i = 0; i < NUM_DPRAM_REGIONS; i++ ) {
+    /*
+     * Verify that the region is available for use.
+     * This test is necessary because if extra microcode modules
+     * are installed, some regions are locked and unavailable.
+     * See MPC860 User's Manual Pages 19-9 to 19-11.
+     */
+    if (dpram_regions[i].used == 0) {
+      volatile unsigned char *cp = dpram_regions[i].base;
+      *cp = 0xAA;
+      if (*cp != 0xAA)
+        dpram_regions[i].used = dpram_regions[i].size;
+      else {
+        *cp = 0x55;
+        if (*cp != 0x55)
+          dpram_regions[i].used = dpram_regions[i].size;
+      }
+      *cp = 0x0;
+    }
+    if (dpram_regions[i].size - dpram_regions[i].used >= byte_count) {
+      blockp = dpram_regions[i].base + dpram_regions[i].used;
+      dpram_regions[i].used += byte_count;
+      break;
+    }
+  }
+
+  _ISR_Local_enable(level);
+
+  if (blockp == NULL)
+    rtems_panic("Can't allocate %d bytes of dual-port RAM.\n", byte_count);
+  return blockp;
+}
Index: bsps/powerpc/mpc8260ads/start/mmu.c
===================================================================
--- bsps/powerpc/mpc8260ads/start/mmu.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
+++ bsps/powerpc/mpc8260ads/start/mmu.c	(revision a12dcff877bfe4ee8346b35947efab0aae7806e2)
@@ -0,0 +1,130 @@
+/*
+ * mmu.c
+ *
+ * This file contains routines for initializing
+ * and manipulating the MMU on the MPC8xx.
+ *
+ * Copyright (c) 1999, National Research Council of Canada
+ *
+ * Trivially modified for mpc8260 21.3.2001
+ * Andy Dachs <a.dachs@sstl.co.uk>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <mpc8260.h>
+#include <mpc8260/mmu.h>
+
+/*
+ * mmu_init
+ *
+ * This routine sets up the virtual memory maps on an MPC8xx.
+ * The MPC8xx does not support block address translation (BATs)
+ * and does not have segment registers. Thus, we must set up page
+ * translation. However, its MMU supports variable size pages
+ * (1-, 4-, 16-, 512-Kbyte or 8-Mbyte), which simplifies the task.
+ *
+ * The MPC8xx has separate data and instruction 32-entry translation
+ * lookaside buffers (TLB). By mapping all of DRAM as one huge page,
+ * we can preload the TLBs and not have to be concerned with taking
+ * TLB miss exceptions.
+ *
+ * We set up the virtual memory map so that virtual address of a
+ * location is equal to its real address.
+ */
+void mmu_init( void )
+{
+#if 0
+/* so far we leave mmu uninitialised */
+
+  register uint32_t   reg1, i;
+
+  /*
+   * Initialize the TLBs
+   *
+   * Instruction address translation and data address translation
+   * must be disabled during initialization (IR=0, DR=0 in MSR).
+   * We can assume the MSR has already been set this way.
+   */
+
+  /*
+   * Initialize IMMU & DMMU Control Registers (MI_CTR & MD_CTR)
+   * 	GPM [0]			0b0 = PowerPC mode
+   *	PPM [1]			0b0 = Page resolution of protection
+   *	CIDEF [2]		0b0/0b1 = Default cache-inhibit attribute =
+   *							NO for IMMU, YES for DMMU!
+   *	reserved/WTDEF [3]	0b0 = Default write-through attribute = not
+   *	RSV4x [4]		0b0 = 4 entries not reserved
+   *	reserved/TWAM [5]	0b0/0b1 = 4-Kbyte page hardware assist
+   *	PPCS [6]		0b0 = Ignore user/supervisor state
+   *	reserved [7-18]		0x00
+   *	xTLB_INDX [19-23]	31 = 0x1F
+   *	reserved [24-31]	0x00
+   *
+   * Note: It is important that cache-inhibit be set as the default for the
+   * data cache when the DMMU is disabled in order to prevent internal memory
+   * mapped registers from being cached accidentally when address translation
+   * is turned off at the start of exception processing.
+   */
+  reg1 = M8xx_MI_CTR_ITLB_INDX(31);
+  _mtspr( M8xx_MI_CTR, reg1 );
+  reg1 = M8xx_MD_CTR_CIDEF | M8xx_MD_CTR_TWAM | M8xx_MD_CTR_DTLB_INDX(31);
+  _mtspr( M8xx_MD_CTR, reg1 );
+  _isync;
+
+  /*
+   * Invalidate all TLB entries in both TLBs.
+   * Note: We rely on the RSV4 bit in MI_CTR and MD_CTR being 0b0, so
+   *       all 32 entries are invalidated.
+   */
+  __asm__ volatile ("tlbia\n"::);
+  _isync;
+
+  /*
+   * Set Current Address Space ID Register (M_CASID).
+   * Supervisor: CASID = 0
+   */
+  reg1 = 0;
+  _mtspr( M8xx_M_CASID, reg1 );
+
+  /*
+   * Initialize the MMU Access Protection Registers (MI_AP, MD_AP)
+   * We ignore the Access Protection Group (APG) mechanism globally
+   * by setting all of the Mx_AP fields to 0b01 : client access
+   * permission is defined by page protection bits.
+   */
+  reg1 = 0x55555555;
+  _mtspr( M8xx_MI_AP, reg1 );
+  _mtspr( M8xx_MD_AP, reg1 );
+
+  /*
+   * Load both 32-entry TLBs with values from the MMU_TLB_table
+   * which is defined in the BSP.
+   * Note the _TLB_Table must have at most 32 entries. This code
+   * makes no effort to enforce this restriction.
+   */
+  for( i = 0; i < MMU_N_TLB_Table_Entries; ++i ) {
+    reg1 = MMU_TLB_table[i].mmu_epn;
+    _mtspr( M8xx_MI_EPN, reg1 );
+    _mtspr( M8xx_MD_EPN, reg1 );
+    reg1 = MMU_TLB_table[i].mmu_twc;
+    _mtspr( M8xx_MI_TWC, reg1 );
+    _mtspr( M8xx_MD_TWC, reg1 );
+    reg1 = MMU_TLB_table[i].mmu_rpn;	/* RPN must be written last! */
+    _mtspr( M8xx_MI_RPN, reg1 );
+    _mtspr( M8xx_MD_RPN, reg1 );
+  }
+
+  /*
+   * Turn on address translation by setting MSR[IR] and MSR[DR].
+   */
+  _CPU_MSR_GET( reg1 );
+  reg1 |= PPC_MSR_IR | PPC_MSR_DR;
+  _CPU_MSR_SET( reg1 );
+
+#endif
+
+}
