This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Serial - expand QUICC driver for SCCx


Index: devs/serial/powerpc/quicc/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/serial/powerpc/quicc/current/ChangeLog,v
retrieving revision 1.14
diff -u -5 -p -r1.14 ChangeLog
--- devs/serial/powerpc/quicc/current/ChangeLog	5 Mar 2003 17:15:53 -0000	1.14
+++ devs/serial/powerpc/quicc/current/ChangeLog	17 Mar 2003 22:08:33 -0000
@@ -1,5 +1,12 @@
+2003-03-17  Gary Thomas  <gary at mlbassoc dot com>
+
+	* src/quicc_smc_serial.h: 
+	* src/quicc_smc_serial.c: 
+	* cdl/ser_quicc_smc.cdl: Add support for SCC1/SCC2/SCC3.  Inspired
+	by Paul Randall <prandall at delta-info dot com>
+
 2003-03-05  Gary Thomas  <gary at mlbassoc dot com>
 
 	* src/quicc_smc_serial.c: Use common routines to manage CPM/DPRAM
 	pointers - much nicer in a multi-driver environment.
 
Index: devs/serial/powerpc/quicc/current/cdl/ser_quicc_smc.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/serial/powerpc/quicc/current/cdl/ser_quicc_smc.cdl,v
retrieving revision 1.7
diff -u -5 -p -r1.7 ser_quicc_smc.cdl
--- devs/serial/powerpc/quicc/current/cdl/ser_quicc_smc.cdl	24 Feb 2003 14:18:55 -0000	1.7
+++ devs/serial/powerpc/quicc/current/cdl/ser_quicc_smc.cdl	17 Mar 2003 20:53:10 -0000
@@ -1,17 +1,17 @@
 # ====================================================================
 #
 #      ser_quicc_smc.cdl
 #
-#      eCos serial PowerPC/QUICC SMC configuration data
+#      eCos serial PowerPC/QUICC SMC/SCC configuration data
 #
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
 ## -------------------------------------------
 ## This file is part of eCos, the Embedded Configurable Operating System.
 ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
-## Copyright (C) 2002 Gary Thomas
+## Copyright (C) 2002, 2003 Gary Thomas
 ##
 ## eCos is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free
 ## Software Foundation; either version 2 or (at your option) any later version.
 ##
@@ -61,11 +61,11 @@ cdl_package CYGPKG_IO_SERIAL_POWERPC_QUI
     requires      CYGPKG_ERROR
     include_dir   cyg/io
     include_files ; # none _exported_ whatsoever
     description   "
            This option enables the serial device drivers for the
-           PowerPC QUICC/SMC."
+           PowerPC QUICC/SMC/SCC."
 
     compile       -library=libextras.a   quicc_smc_serial.c
 
     define_proc {
         puts $::cdl_system_header "/***** serial driver proc output start *****/"
@@ -74,11 +74,11 @@ cdl_package CYGPKG_IO_SERIAL_POWERPC_QUI
     }
 
 cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1 {
     display       "PowerPC QUICC/SMC serial port 1 driver"
     flavor        bool
-    requires      CYGNUM_HAL_QUICC_SMC1
+    active_if     CYGNUM_HAL_QUICC_SMC1
     default_value 1
     description   "
         This option includes the serial device driver for the PowerPC 
         QUICC/SMC port 1."
 
@@ -165,11 +165,11 @@ cdl_component CYGPKG_IO_SERIAL_POWERPC_Q
 }
 
 cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2 {
     display       "PowerPC QUICC/SMC serial port 2 driver"
     flavor        bool
-    requires      CYGNUM_HAL_QUICC_SMC2
+    active_if     CYGNUM_HAL_QUICC_SMC2
     default_value 1
     description   "
         This option includes the serial device driver for the PowerPC 
         QUICC/SMC port 2."
 
@@ -283,9 +283,282 @@ cdl_component CYGPKG_IO_SERIAL_POWERPC_Q
             description   "
                 This option modifies the set of compiler flags for
                 building these serial device drivers. These flags are removed from
                 the set of global flags if present."
         }
+    }
+}
+
+cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1 {
+    display       "PowerPC QUICC/SCC serial port 1 driver"
+    flavor        bool
+    active_if     CYGNUM_HAL_QUICC_SCC1
+    default_value 1
+    description   "
+        This option includes the serial device driver for the PowerPC 
+        QUICC/SCC port 1."
+
+    cdl_option CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_NAME {
+        display       "Device name for PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        default_value {"\"/dev/scc1\""}
+        description   "
+            This option specifies the device name for the PowerPC 
+            QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BAUD {
+        display       "Baud rate for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  { 50 75 110 "134_5" 150 200 300 600 1200 1800 2400 3600
+                      4800 7200 9600 14400 19200 38400 57600 115200 230400
+        }
+        default_value 38400
+        description   "
+            This option specifies the default baud rate (speed) for the 
+            PowerPC QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE {
+        display       "Buffer size for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  0 to 8192
+        default_value 256
+        description   "
+            This option specifies the size of the internal buffers used
+            for the PowerPC QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BRG {
+        display       "Which baud rate generator to use for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  1 to 4
+        default_value 2
+        description   "
+            This option specifies which of the four baud rate generators
+            to use for the PowerPC QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxSIZE {
+        display       "Output buffer size for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  16 to 128
+        default_value 16
+        description   "
+            This option specifies the maximum number of characters per 
+            transmit request to be used for the PowerPC QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM {
+        display       "Number of output buffers for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  2 to 16
+        default_value 4
+        description   "
+            This option specifies the number of output buffer packets
+            to be used for the PowerPC QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxSIZE {
+        display       "Input buffer size for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  16 to 128
+        default_value 16
+        description   "
+            This option specifies the maximum number of characters per receive
+            request to be used for the PowerPC QUICC/SCC port 1."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM {
+        display       "Number of input buffers for the PowerPC QUICC/SCC serial port 1"
+        flavor        data
+        legal_values  2 to 16
+        default_value 4
+        description   "
+            This option specifies the number of input buffer packets
+            to be used for the PowerPC QUICC/SCC port 1."
+    }
+}
+
+cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2 {
+    display       "PowerPC QUICC/SCC serial port 2 driver"
+    flavor        bool
+    active_if     CYGNUM_HAL_QUICC_SCC2
+    default_value 1
+    description   "
+        This option includes the serial device driver for the PowerPC 
+        QUICC/SCC port 2."
+
+    cdl_option CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_NAME {
+        display       "Device name for PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        default_value {"\"/dev/scc2\""}
+        description   "
+            This option specifies the device name for the PowerPC 
+            QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BAUD {
+        display       "Baud rate for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  { 50 75 110 "134_5" 150 200 300 600 1200 1800 2400 3600
+                      4800 7200 9600 14400 19200 38400 57600 115200 230400
+        }
+        default_value 38400
+        description   "
+            This option specifies the default baud rate (speed) for the 
+            PowerPC QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE {
+        display       "Buffer size for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  0 to 8192
+        default_value 256
+        description   "
+            This option specifies the size of the internal buffers used
+            for the PowerPC QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BRG {
+        display       "Which baud rate generator to use for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  1 to 4
+        default_value 3
+        description   "
+            This option specifies which of the four baud rate generators
+            to use for the PowerPC QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxSIZE {
+        display       "Output buffer size for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  16 to 128
+        default_value 16
+        description   "
+            This option specifies the maximum number of characters per 
+            transmit request to be used for the PowerPC QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM {
+        display       "Number of output buffers for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  2 to 16
+        default_value 4
+        description   "
+            This option specifies the number of output buffer packets
+            to be used for the PowerPC QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxSIZE {
+        display       "Input buffer size for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  16 to 128
+        default_value 16
+        description   "
+            This option specifies the maximum number of characters per receive
+            request to be used for the PowerPC QUICC/SCC port 2."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM {
+        display       "Number of input buffers for the PowerPC QUICC/SCC serial port 2"
+        flavor        data
+        legal_values  2 to 16
+        default_value 4
+        description   "
+            This option specifies the number of input buffer packets
+            to be used for the PowerPC QUICC/SCC port 2."
+    }
+}
+
+cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3 {
+    display       "PowerPC QUICC/SCC serial port 3 driver"
+    flavor        bool
+    active_if     CYGNUM_HAL_QUICC_SCC3
+    default_value 1
+    description   "
+        This option includes the serial device driver for the PowerPC 
+        QUICC/SCC port 3."
+
+    cdl_option CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_NAME {
+        display       "Device name for PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        default_value {"\"/dev/scc3\""}
+        description   "
+            This option specifies the device name for the PowerPC 
+            QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BAUD {
+        display       "Baud rate for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  { 50 75 110 "134_5" 150 200 300 600 1200 1800 2400 3600
+                      4800 7200 9600 14400 19200 38400 57600 115200 230400
+        }
+        default_value 38400
+        description   "
+            This option specifies the default baud rate (speed) for the 
+            PowerPC QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE {
+        display       "Buffer size for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  0 to 8192
+        default_value 256
+        description   "
+            This option specifies the size of the internal buffers used
+            for the PowerPC QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BRG {
+        display       "Which baud rate generator to use for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  1 to 4
+        default_value 4
+        description   "
+            This option specifies which of the four baud rate generators
+            to use for the PowerPC QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxSIZE {
+        display       "Output buffer size for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  16 to 128
+        default_value 16
+        description   "
+            This option specifies the maximum number of characters per 
+            transmit request to be used for the PowerPC QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM {
+        display       "Number of output buffers for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  2 to 16
+        default_value 4
+        description   "
+            This option specifies the number of output buffer packets
+            to be used for the PowerPC QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxSIZE {
+        display       "Input buffer size for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  16 to 128
+        default_value 16
+        description   "
+            This option specifies the maximum number of characters per receive
+            request to be used for the PowerPC QUICC/SCC port 3."
+    }
+
+    cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM {
+        display       "Number of input buffers for the PowerPC QUICC/SCC serial port 3"
+        flavor        data
+        legal_values  2 to 16
+        default_value 4
+        description   "
+            This option specifies the number of input buffer packets
+            to be used for the PowerPC QUICC/SCC port 3."
     }
 }
 
 # EOF ser_quicc_smc.cdl
Index: devs/serial/powerpc/quicc/current/src/quicc_smc_serial.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/serial/powerpc/quicc/current/src/quicc_smc_serial.c,v
retrieving revision 1.10
diff -u -5 -p -r1.10 quicc_smc_serial.c
--- devs/serial/powerpc/quicc/current/src/quicc_smc_serial.c	5 Mar 2003 17:15:53 -0000	1.10
+++ devs/serial/powerpc/quicc/current/src/quicc_smc_serial.c	17 Mar 2003 22:16:09 -0000
@@ -1,10 +1,10 @@
 //==========================================================================
 //
 //      io/serial/powerpc/quicc_smc_serial.c
 //
-//      PowerPC QUICC (SMC) Serial I/O Interface Module (interrupt driven)
+//      PowerPC QUICC (SMC/SCC) Serial I/O Interface Module (interrupt driven)
 //
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
@@ -66,102 +66,74 @@
 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC
 
 // macro for aligning buffers to cache lines
 #define ALIGN_TO_CACHELINES(b) ((cyg_uint8 *)(((CYG_ADDRESS)(b) + (HAL_DCACHE_LINE_SIZE-1)) & ~(HAL_DCACHE_LINE_SIZE-1)))
 
-// Buffer descriptor control bits
-#define QUICC_BD_CTL_Ready 0x8000  // Buffer contains data (tx) or is empty (rx)
-#define QUICC_BD_CTL_Wrap  0x2000  // Last buffer in list
-#define QUICC_BD_CTL_Int   0x1000  // Generate interrupt when empty (tx) or full (rx)
-#define QUICC_BD_CTL_MASK  0xB000  // User settable bits
-
-// SMC Mode Register
-#define QUICC_SMCMR_CLEN(n)   ((n+1)<<11)   // Character length
-#define QUICC_SMCMR_SB(n)     ((n-1)<<10)   // Stop bits (1 or 2)
-#define QUICC_SMCMR_PE(n)     (n<<9)        // Parity enable (0=disable, 1=enable)
-#define QUICC_SMCMR_PM(n)     (n<<8)        // Parity mode (0=odd, 1=even)
-#define QUICC_SMCMR_UART      (2<<4)        // UART mode
-#define QUICC_SMCMR_TEN       (1<<1)        // Enable transmitter
-#define QUICC_SMCMR_REN       (1<<0)        // Enable receiver
-
-// SMC Events (interrupts)
-#define QUICC_SMCE_BRK 0x10  // Break received
-#define QUICC_SMCE_BSY 0x04  // Busy - receive buffer overrun
-#define QUICC_SMCE_TX  0x02  // Tx interrupt
-#define QUICC_SMCE_RX  0x01  // Rx interrupt
-
-// SMC Commands
-#define QUICC_SMC_CMD_InitTxRx  (0<<8)
-#define QUICC_SMC_CMD_InitTx    (1<<8)
-#define QUICC_SMC_CMD_InitRx    (2<<8)
-#define QUICC_SMC_CMD_StopTx    (4<<8)
-#define QUICC_SMC_CMD_RestartTx (6<<8)
-#define QUICC_SMC_CMD_Reset     0x8000
-#define QUICC_SMC_CMD_Go        0x0001
-
 #include "quicc_smc_serial.h"
 
-typedef struct quicc_smc_serial_info {
-    CYG_ADDRWORD          channel;                   // Which channel SMC1/SMC2
-    CYG_WORD              int_num;                   // Interrupt number
+typedef struct quicc_sxx_serial_info {
+    CYG_ADDRWORD          channel;                   // Which channel SMCx/SCCx
+    short                 int_num;                   // Interrupt number
+    short                 type;                      // Channel type - SCC or SMC
     cyg_uint32            *brg;                      // Which baud rate generator
-    volatile struct smc_uart_pram  *pram;            // Parameter RAM pointer
-    volatile struct smc_regs       *ctl;             // SMC control registers
+    void                  *pram;                     // Parameter RAM pointer
+    void                  *ctl;                      // SMC/SCC control registers
     volatile struct cp_bufdesc     *txbd, *rxbd;     // Next Tx,Rx descriptor to use
     struct cp_bufdesc     *tbase, *rbase;            // First Tx,Rx descriptor
     int                   txsize, rxsize;            // Length of individual buffers
     cyg_interrupt         serial_interrupt;
     cyg_handle_t          serial_interrupt_handle;
-} quicc_smc_serial_info;
+} quicc_sxx_serial_info;
 
-static bool quicc_smc_serial_init(struct cyg_devtab_entry *tab);
-static bool quicc_smc_serial_putc(serial_channel *chan, unsigned char c);
-static Cyg_ErrNo quicc_smc_serial_lookup(struct cyg_devtab_entry **tab, 
+static bool quicc_sxx_serial_init(struct cyg_devtab_entry *tab);
+static bool quicc_sxx_serial_putc(serial_channel *chan, unsigned char c);
+static Cyg_ErrNo quicc_sxx_serial_lookup(struct cyg_devtab_entry **tab, 
                                    struct cyg_devtab_entry *sub_tab,
                                    const char *name);
-static unsigned char quicc_smc_serial_getc(serial_channel *chan);
-static Cyg_ErrNo quicc_smc_serial_set_config(serial_channel *chan,
+static unsigned char quicc_sxx_serial_getc(serial_channel *chan);
+static Cyg_ErrNo quicc_sxx_serial_set_config(serial_channel *chan,
                                              cyg_uint32 key, const void *xbuf,
                                              cyg_uint32 *len);
-static void quicc_smc_serial_start_xmit(serial_channel *chan);
-static void quicc_smc_serial_stop_xmit(serial_channel *chan);
+static void quicc_sxx_serial_start_xmit(serial_channel *chan);
+static void quicc_sxx_serial_stop_xmit(serial_channel *chan);
 
-static cyg_uint32 quicc_smc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
-static void       quicc_smc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
+static cyg_uint32 quicc_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
+static void       quicc_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
 
-static SERIAL_FUNS(quicc_smc_serial_funs, 
-                   quicc_smc_serial_putc, 
-                   quicc_smc_serial_getc,
-                   quicc_smc_serial_set_config,
-                   quicc_smc_serial_start_xmit,
-                   quicc_smc_serial_stop_xmit
+static SERIAL_FUNS(quicc_sxx_serial_funs, 
+                   quicc_sxx_serial_putc, 
+                   quicc_sxx_serial_getc,
+                   quicc_sxx_serial_set_config,
+                   quicc_sxx_serial_start_xmit,
+                   quicc_sxx_serial_stop_xmit
     );
 
 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
-static quicc_smc_serial_info quicc_smc_serial_info1 = {
-    0x90,                         // Channel indicator
-    CYGNUM_HAL_INTERRUPT_CPM_SMC1 // interrupt
+static quicc_sxx_serial_info quicc_sxx_serial_info_smc1 = {
+    QUICC_CPM_SMC1,                 // Channel indicator
+    CYGNUM_HAL_INTERRUPT_CPM_SMC1,  // interrupt
+    _SMC_CHAN
 };
 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE > 0
-static unsigned char quicc_smc_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
-static unsigned char quicc_smc_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
+static unsigned char quicc_smc_serial_out_buf_smc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
+static unsigned char quicc_smc_serial_in_buf_smc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
 
-static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_smc_serial_channel1,
-                                       quicc_smc_serial_funs, 
-                                       quicc_smc_serial_info1,
+static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_smc1,
+                                       quicc_sxx_serial_funs, 
+                                       quicc_sxx_serial_info_smc1,
                                        CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BAUD),
                                        CYG_SERIAL_STOP_DEFAULT,
                                        CYG_SERIAL_PARITY_DEFAULT,
                                        CYG_SERIAL_WORD_LENGTH_DEFAULT,
                                        CYG_SERIAL_FLAGS_DEFAULT,
-                                       &quicc_smc_serial_out_buf1[0], sizeof(quicc_smc_serial_out_buf1),
-                                       &quicc_smc_serial_in_buf1[0], sizeof(quicc_smc_serial_in_buf1)
+                                       &quicc_smc_serial_out_buf_smc1[0], sizeof(quicc_smc_serial_out_buf_smc1),
+                                       &quicc_smc_serial_in_buf_smc1[0], sizeof(quicc_smc_serial_in_buf_smc1)
     );
 #else
-static SERIAL_CHANNEL(quicc_smc_serial_channel1,
-                      quicc_smc_serial_funs, 
-                      quicc_smc_serial_info1,
+static SERIAL_CHANNEL(quicc_sxx_serial_channel_smc1,
+                      quicc_sxx_serial_funs, 
+                      quicc_sxx_serial_info_smc1,
                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BAUD),
                       CYG_SERIAL_STOP_DEFAULT,
                       CYG_SERIAL_PARITY_DEFAULT,
                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
                       CYG_SERIAL_FLAGS_DEFAULT
@@ -169,105 +141,234 @@ static SERIAL_CHANNEL(quicc_smc_serial_c
 #endif
 
 static unsigned char quicc_smc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
 static unsigned char quicc_smc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
 
-DEVTAB_ENTRY(quicc_smc_serial_io1, 
+DEVTAB_ENTRY(quicc_smc_serial_io_smc1, 
              CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_NAME,
              0,                     // Does not depend on a lower level interface
              &cyg_io_serial_devio, 
-             quicc_smc_serial_init, 
-             quicc_smc_serial_lookup,     // Serial driver may need initializing
-             &quicc_smc_serial_channel1
+             quicc_sxx_serial_init, 
+             quicc_sxx_serial_lookup,     // Serial driver may need initializing
+             &quicc_sxx_serial_channel_smc1
     );
 #endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
 
 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
-static quicc_smc_serial_info quicc_smc_serial_info2 = {
-    0xD0,                             // Channel indicator
-    CYGNUM_HAL_INTERRUPT_CPM_SMC2_PIP // interrupt
+static quicc_sxx_serial_info quicc_sxx_serial_info_smc2 = {
+    QUICC_CPM_SMC2,                     // Channel indicator
+    CYGNUM_HAL_INTERRUPT_CPM_SMC2_PIP,  // interrupt
+    _SMC_CHAN
 };
 #if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE > 0
-static unsigned char quicc_smc_serial_out_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
-static unsigned char quicc_smc_serial_in_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
+static unsigned char quicc_smc_serial_out_buf_smc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
+static unsigned char quicc_smc_serial_in_buf_smc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
 
-static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_smc_serial_channel2,
-                                       quicc_smc_serial_funs, 
-                                       quicc_smc_serial_info2,
+static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_smc2,
+                                       quicc_sxx_serial_funs, 
+                                       quicc_sxx_serial_info_smc2,
                                        CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BAUD),
                                        CYG_SERIAL_STOP_DEFAULT,
                                        CYG_SERIAL_PARITY_DEFAULT,
                                        CYG_SERIAL_WORD_LENGTH_DEFAULT,
                                        CYG_SERIAL_FLAGS_DEFAULT,
-                                       &quicc_smc_serial_out_buf2[0], sizeof(quicc_smc_serial_out_buf2),
-                                       &quicc_smc_serial_in_buf2[0], sizeof(quicc_smc_serial_in_buf2)
+                                       &quicc_smc_serial_out_buf_smc2[0], sizeof(quicc_smc_serial_out_buf_smc2),
+                                       &quicc_smc_serial_in_buf_smc2[0], sizeof(quicc_smc_serial_in_buf_smc2)
     );
 #else
-static SERIAL_CHANNEL(quicc_smc_serial_channel2,
-                      quicc_smc_serial_funs, 
-                      quicc_smc_serial_info2,
+static SERIAL_CHANNEL(quicc_sxx_serial_channel_smc2,
+                      quicc_sxx_serial_funs, 
+                      quicc_sxx_serial_info_smc2,
                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BAUD),
                       CYG_SERIAL_STOP_DEFAULT,
                       CYG_SERIAL_PARITY_DEFAULT,
                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
                       CYG_SERIAL_FLAGS_DEFAULT
     );
 #endif
 static unsigned char quicc_smc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
 static unsigned char quicc_smc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
 
-DEVTAB_ENTRY(quicc_smc_serial_io2, 
+DEVTAB_ENTRY(quicc_smc_serial_io_smc2, 
              CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_NAME,
              0,                     // Does not depend on a lower level interface
              &cyg_io_serial_devio, 
-             quicc_smc_serial_init, 
-             quicc_smc_serial_lookup,     // Serial driver may need initializing
-             &quicc_smc_serial_channel2
+             quicc_sxx_serial_init, 
+             quicc_sxx_serial_lookup,     // Serial driver may need initializing
+             &quicc_sxx_serial_channel_smc2
     );
 #endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
 
-#ifdef CYGDBG_DIAG_BUF
-extern int enable_diag_uart;
-#endif // CYGDBG_DIAG_BUF
+#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
+static quicc_sxx_serial_info quicc_sxx_serial_info_scc1 = {
+    QUICC_CPM_SCC1,                     // Channel indicator
+    CYGNUM_HAL_INTERRUPT_CPM_SCC1,      // interrupt
+    _SCC_CHAN
+};
+#if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE > 0
+static unsigned char quicc_smc_serial_out_buf_scc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE];
+static unsigned char quicc_smc_serial_in_buf_scc1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BUFSIZE];
+
+static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_scc1,
+                                       quicc_sxx_serial_funs, 
+                                       quicc_sxx_serial_info_scc1,
+                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BAUD),
+                                       CYG_SERIAL_STOP_DEFAULT,
+                                       CYG_SERIAL_PARITY_DEFAULT,
+                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
+                                       CYG_SERIAL_FLAGS_DEFAULT,
+                                       &quicc_smc_serial_out_buf_scc1[0], sizeof(quicc_smc_serial_out_buf_scc1),
+                                       &quicc_smc_serial_in_buf_scc1[0], sizeof(quicc_smc_serial_in_buf_scc1)
+    );
+#else
+static SERIAL_CHANNEL(quicc_sxx_serial_channel_scc1,
+                      quicc_sxx_serial_funs, 
+                      quicc_sxx_serial_info_scc1,
+                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BAUD),
+                      CYG_SERIAL_STOP_DEFAULT,
+                      CYG_SERIAL_PARITY_DEFAULT,
+                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
+                      CYG_SERIAL_FLAGS_DEFAULT
+    );
+#endif
+static unsigned char quicc_scc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
+static unsigned char quicc_scc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
+
+DEVTAB_ENTRY(quicc_smc_serial_io_scc1, 
+             CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_NAME,
+             0,                     // Does not depend on a lower level interface
+             &cyg_io_serial_devio, 
+             quicc_sxx_serial_init, 
+             quicc_sxx_serial_lookup,     // Serial driver may need initializing
+             &quicc_sxx_serial_channel_scc1
+    );
+#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
+
+#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
+static quicc_sxx_serial_info quicc_sxx_serial_info_scc2 = {
+    QUICC_CPM_SCC2,                     // Channel indicator
+    CYGNUM_HAL_INTERRUPT_CPM_SCC2,      // interrupt
+    _SCC_CHAN
+};
+#if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE > 0
+static unsigned char quicc_smc_serial_out_buf_scc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE];
+static unsigned char quicc_smc_serial_in_buf_scc2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BUFSIZE];
+
+static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_scc2,
+                                       quicc_sxx_serial_funs, 
+                                       quicc_sxx_serial_info_scc2,
+                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BAUD),
+                                       CYG_SERIAL_STOP_DEFAULT,
+                                       CYG_SERIAL_PARITY_DEFAULT,
+                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
+                                       CYG_SERIAL_FLAGS_DEFAULT,
+                                       &quicc_smc_serial_out_buf_scc2[0], sizeof(quicc_smc_serial_out_buf_scc2),
+                                       &quicc_smc_serial_in_buf_scc2[0], sizeof(quicc_smc_serial_in_buf_scc2)
+    );
+#else
+static SERIAL_CHANNEL(quicc_sxx_serial_channel_scc2,
+                      quicc_sxx_serial_funs, 
+                      quicc_sxx_serial_info_scc2,
+                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BAUD),
+                      CYG_SERIAL_STOP_DEFAULT,
+                      CYG_SERIAL_PARITY_DEFAULT,
+                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
+                      CYG_SERIAL_FLAGS_DEFAULT
+    );
+#endif
+static unsigned char quicc_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
+static unsigned char quicc_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
+
+DEVTAB_ENTRY(quicc_smc_serial_io_scc2, 
+             CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_NAME,
+             0,                     // Does not depend on a lower level interface
+             &cyg_io_serial_devio, 
+             quicc_sxx_serial_init, 
+             quicc_sxx_serial_lookup,     // Serial driver may need initializing
+             &quicc_sxx_serial_channel_scc2
+    );
+#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
+
+#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
+static quicc_sxx_serial_info quicc_sxx_serial_info_scc3 = {
+    QUICC_CPM_SCC3,                     // Channel indicator
+    CYGNUM_HAL_INTERRUPT_CPM_SCC3,      // interrupt
+    _SCC_CHAN
+};
+#if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE > 0
+static unsigned char quicc_smc_serial_out_buf_scc3[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE];
+static unsigned char quicc_smc_serial_in_buf_scc3[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BUFSIZE];
+
+static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_sxx_serial_channel_scc3,
+                                       quicc_sxx_serial_funs, 
+                                       quicc_sxx_serial_info_scc3,
+                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BAUD),
+                                       CYG_SERIAL_STOP_DEFAULT,
+                                       CYG_SERIAL_PARITY_DEFAULT,
+                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
+                                       CYG_SERIAL_FLAGS_DEFAULT,
+                                       &quicc_smc_serial_out_buf_scc3[0], sizeof(quicc_smc_serial_out_buf_scc3),
+                                       &quicc_smc_serial_in_buf_scc3[0], sizeof(quicc_smc_serial_in_buf_scc3)
+    );
+#else
+static SERIAL_CHANNEL(quicc_sxx_serial_channel_scc3,
+                      quicc_sxx_serial_funs, 
+                      quicc_sxx_serial_info_scc3,
+                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BAUD),
+                      CYG_SERIAL_STOP_DEFAULT,
+                      CYG_SERIAL_PARITY_DEFAULT,
+                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
+                      CYG_SERIAL_FLAGS_DEFAULT
+    );
+#endif
+static unsigned char quicc_scc3_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
+static unsigned char quicc_scc3_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
+
+DEVTAB_ENTRY(quicc_smc_serial_io_scc3, 
+             CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_NAME,
+             0,                     // Does not depend on a lower level interface
+             &cyg_io_serial_devio, 
+             quicc_sxx_serial_init, 
+             quicc_sxx_serial_lookup,     // Serial driver may need initializing
+             &quicc_sxx_serial_channel_scc3
+    );
+#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
 
 // Internal function to actually configure the hardware to desired baud rate, etc.
 static bool
 quicc_smc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
 {
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     unsigned int baud_divisor = select_baud[new_config->baud];
     cyg_uint32 _lcr;
     EPPC *eppc = eppc_base();
+    volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;
+
     if (baud_divisor == 0) return false;
     // Disable channel during setup
-    smc_chan->ctl->smc_smcmr = QUICC_SMCMR_UART;  // Disabled, UART mode
+    ctl->smc_smcmr = QUICC_SMCMR_UART;  // Disabled, UART mode
     // Disable port interrupts while changing hardware
-    _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | 
-        select_stop_bits[new_config->stop] |
-        select_parity[new_config->parity];
+    _lcr = smc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | 
+        smc_select_stop_bits[new_config->stop] |
+        smc_select_parity[new_config->parity];
     // Stop transmitter while changing baud rate
     eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_StopTx;
     // Set baud rate generator
     *smc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
-#ifdef XX_CYGDBG_DIAG_BUF
-        enable_diag_uart = 0;
-        diag_printf("Set BAUD RATE[%x], %d = %x, tstate = %x\n", smc_chan->brg, baud_divisor, *smc_chan->brg, smc_chan->pram->tstate);
-        enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
 
     // Enable channel with new configuration
-    smc_chan->ctl->smc_smcmr = QUICC_SMCMR_UART|QUICC_SMCMR_TEN|QUICC_SMCMR_REN|_lcr;
+    ctl->smc_smcmr = QUICC_SMCMR_UART|QUICC_SMCMR_TEN|QUICC_SMCMR_REN|_lcr;
     eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_RestartTx;
     if (new_config != &chan->config) {
         chan->config = *new_config;
     }
     return true;
 }
 
 // Function to set up internal tables for device.
 static void
-quicc_smc_serial_init_info(quicc_smc_serial_info *smc_chan,
+quicc_smc_serial_init_info(quicc_sxx_serial_info *smc_chan,
                            volatile struct smc_uart_pram *uart_pram,
                            volatile struct smc_regs *ctl,
                            int TxBD, int TxNUM, int TxSIZE,
                            cyg_uint8 *TxBUF,
                            int RxBD, int RxNUM, int RxSIZE,
@@ -280,12 +381,12 @@ quicc_smc_serial_init_info(quicc_smc_ser
     cyg_uint32 simode = 0;
     int i;
 
     // Disable channel during setup
     ctl->smc_smcmr = QUICC_SMCMR_UART;  // Disabled, UART mode
-    smc_chan->pram = uart_pram;
-    smc_chan->ctl = ctl;
+    smc_chan->pram = (void *)uart_pram;
+    smc_chan->ctl = (void *)ctl;
     /*
      *  SDMA & LCD bus request level 5
      *  (Section 16.10.2.1)
      */
     eppc->dma_sdcr = 1;
@@ -380,36 +481,198 @@ quicc_smc_serial_init_info(quicc_smc_ser
      */
     ctl->smc_smce = 0xFF;
     ctl->smc_smcm = QUICC_SMCE_BSY|QUICC_SMCE_TX|QUICC_SMCE_RX;
 }
 
+// Internal function to actually configure the hardware to desired baud rate, etc.
+static bool
+quicc_scc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
+{
+    quicc_sxx_serial_info *scc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
+    unsigned int baud_divisor = select_baud[new_config->baud];
+    EPPC *eppc = eppc_base();
+    volatile struct scc_regs *regs = (volatile struct scc_regs *)scc_chan->ctl;
+
+    if (baud_divisor == 0) return false;
+    // Set baud rate generator
+    *scc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
+    // Disable channel during setup
+    regs->scc_gsmr_l = 0;
+    regs->scc_psmr = QUICC_SCC_PSMR_ASYNC | 
+        scc_select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | 
+        scc_select_stop_bits[new_config->stop] |
+        scc_select_parity[new_config->parity];
+
+    // Enable channel with new configuration
+    regs->scc_gsmr_h = 0x20;          // 8bit FIFO
+    regs->scc_gsmr_l = 0x00028004;    // 16x TxCLK, 16x RxCLK, UART
+
+    /*
+     *  Init Rx & Tx params for SCCX
+     */
+    eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | scc_chan->channel | QUICC_CPM_CR_BUSY;
+
+    regs->scc_gsmr_l |= (QUICC_SCC_GSMR_L_Tx | QUICC_SCC_GSMR_L_Rx);  // Enable Rx, Tx
+    if (new_config != &chan->config) {
+        chan->config = *new_config;
+    }
+    return true;
+}
+
+// Function to set up internal tables for device.
+static void
+quicc_scc_serial_init_info(quicc_sxx_serial_info *scc_chan,
+                           volatile struct uart_pram *uart_pram,
+                           volatile struct scc_regs *ctl,
+                           int TxBD, int TxNUM, int TxSIZE,
+                           cyg_uint8 *TxBUF,
+                           int RxBD, int RxNUM, int RxSIZE,
+                           cyg_uint8 *RxBUF,
+                           int portAmask, int portBmask, int portCmask,
+                           int BRG, int SIpos)
+{
+    EPPC *eppc = eppc_base();
+    struct cp_bufdesc *txbd, *rxbd;
+    cyg_uint32 simode = 0;
+    int i;
+
+    // Disable channel during setup
+    ctl->scc_gsmr_l = 0;
+    scc_chan->pram = (void *)uart_pram;
+    scc_chan->ctl = (void *)ctl;
+    /*
+     *  SDMA & LCD bus request level 5
+     *  (Section 16.10.2.1)
+     */
+    eppc->dma_sdcr = 1;
+    switch (BRG) {
+    case 1:
+        scc_chan->brg = (cyg_uint32 *)&eppc->brgc1;
+        simode = 0;
+        break;
+    case 2:
+        scc_chan->brg = (cyg_uint32 *)&eppc->brgc2;
+        simode = 1;
+        break;
+    case 3:
+        scc_chan->brg = (cyg_uint32 *)&eppc->brgc3;
+        simode = 2;
+        break;
+    case 4:
+        scc_chan->brg = (cyg_uint32 *)&eppc->brgc4;
+        simode = 3;
+        break;
+    }
+    // Route baud rate generators
+    eppc->si_sicr = (eppc->si_sicr & ~(0xFF<<SIpos)) | (((simode<<3)|(simode<<0))<<SIpos);
+    /*
+     *  Set up the PortA/B/C pins for UART operation.
+     */
+    eppc->pio_papar |= portAmask;
+    eppc->pio_padir &= ~portAmask;
+    eppc->pio_paodr &= ~portAmask;
+
+    eppc->pio_pcdir &= portCmask;
+    eppc->pio_pcpar &= portCmask;
+    eppc->pio_pcso  |= portCmask;
+
+    eppc->pip_pbpar |= portBmask;
+    eppc->pip_pbdir |= portBmask;
+
+    /*
+     *  SDMA & LCD bus request level 5
+     *  (Section 16.10.2.1)
+     */
+    eppc->dma_sdcr = 1;
+    /*
+     *  Set Rx and Tx function code
+     *  (Section 16.15.4.2)
+     */
+    uart_pram->rfcr = 0x18;
+    uart_pram->tfcr = 0x18;
+    /*
+     *  Set pointers to buffer descriptors.
+     *  (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
+     */
+    uart_pram->rbase = RxBD;
+    uart_pram->tbase = TxBD;
+    /* tx and rx buffer descriptors */
+    txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
+    rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
+    scc_chan->txbd = txbd;
+    scc_chan->tbase = txbd;
+    scc_chan->txsize = TxSIZE;
+    scc_chan->rxbd = rxbd;
+    scc_chan->rbase = rxbd;
+    scc_chan->rxsize = RxSIZE;
+    /* max receive buffer length */
+    uart_pram->mrblr = RxSIZE;
+    /* set max_idle feature - generate interrupt after 4 chars idle period */
+    uart_pram->max_idl = 4;
+    /* no last brk char received */
+    uart_pram->brkln = 0;
+    /* no break condition occurred */
+    uart_pram->brkec = 0;
+    /* 1 break char sent on top XMIT */
+    uart_pram->brkcr = 1;
+    /* character mask */
+    uart_pram->rccm  = 0xC0FF;
+    /* control characters */
+    for (i = 0;  i < 8;  i++) {
+        uart_pram->cc[i] = 0x8000;  // Mark unused
+    }
+    /* setup RX buffer descriptors */
+    for (i = 0;  i < RxNUM;  i++) {
+        rxbd->length = 0;
+        rxbd->buffer = RxBUF;
+        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
+        if (i == (RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
+        RxBUF += RxSIZE;
+        rxbd++;
+    }
+    /* setup TX buffer descriptors */
+    for (i = 0;  i < TxNUM;  i++) {
+        txbd->length = 0;
+        txbd->buffer = TxBUF;
+        txbd->ctrl   = 0;
+        if (i == (TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
+        TxBUF += TxSIZE;
+        txbd++;
+    }
+    /*
+     *  Reset Rx & Tx params
+     */
+    eppc->cp_cr = scc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_InitTxRx;
+    /*
+     *  Clear any previous events. Enable interrupts.
+     *  (Section 16.15.7.14 and 16.15.7.15)
+     */
+    ctl->scc_scce = 0xFFFF;
+    ctl->scc_sccm = (QUICC_SCCE_BSY | QUICC_SCCE_TX | QUICC_SCCE_RX);
+}
+
 // Function to initialize the device.  Called at bootstrap time.
 static bool 
-quicc_smc_serial_init(struct cyg_devtab_entry *tab)
+quicc_sxx_serial_init(struct cyg_devtab_entry *tab)
 {
     serial_channel *chan = (serial_channel *)tab->priv;
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     volatile EPPC *eppc = (volatile EPPC *)eppc_base();
     int TxBD, RxBD;
-    static int first_init = 1;
     int cache_state;
 
     HAL_DCACHE_IS_ENABLED(cache_state);
     HAL_DCACHE_SYNC();
     HAL_DCACHE_DISABLE();
 #ifdef CYGDBG_IO_INIT
-    diag_printf("QUICC_SMC SERIAL init - dev: %x.%d\n", smc_chan->channel, smc_chan->int_num);
+    diag_printf("QUICC_SMC SERIAL init - dev: %x.%d = %s\n", smc_chan->channel, smc_chan->int_num, tab->name);
 #endif
-    if (first_init) {
-        // Set up tables since many fields are dynamic [computed at runtime]
-        first_init = 0;
 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
-        eppc->cp_cr = QUICC_SMC_CMD_Reset | QUICC_SMC_CMD_Go;  // Totally reset CP
-        while (eppc->cp_cr & QUICC_SMC_CMD_Reset) ;
+    if (chan == &quicc_sxx_serial_channel_smc1) {
         TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM);
         RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM);
-        quicc_smc_serial_init_info(&quicc_smc_serial_info1,
+        quicc_smc_serial_init_info(&quicc_sxx_serial_info_smc1,
                                    &eppc->pram[2].scc.pothers.smc_modem.psmc.u, // PRAM
                                    &eppc->smc_regs[0], // Control registers
                                    TxBD, 
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM,
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE,
@@ -420,28 +683,17 @@ quicc_smc_serial_init(struct cyg_devtab_
                                    ALIGN_TO_CACHELINES(&quicc_smc1_rxbuf[0][0]),
                                    0xC0, // PortB mask
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BRG,
                                    12  // SI mask position
             );
-#else
-#ifdef CYGPKG_HAL_POWERPC_MBX
-        // Ensure the SMC1 side is initialized first and use shared mem
-        // above where it plays:
-        diag_init();    // (pull in constructor that inits diag channel)
-        TxBD = 0x2830;  // Note: this should be inferred from the chip state
-#else
-        // there is no diag device wanting to use the QUICC, so prepare it
-        // for SMC2 use only.
-        eppc->cp_cr = QUICC_SMC_CMD_Reset | QUICC_SMC_CMD_Go;  // Totally reset CP
-        while (eppc->cp_cr & QUICC_SMC_CMD_Reset) ;
-        TxBD = 0x2800;  // Note: this should be configurable
-#endif        
+    }
 #endif
 #ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
+    if (chan == &quicc_sxx_serial_channel_smc2) {
         TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM);
         RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM);
-        quicc_smc_serial_init_info(&quicc_smc_serial_info2,
+        quicc_smc_serial_init_info(&quicc_sxx_serial_info_smc2,
                                    &eppc->pram[3].scc.pothers.smc_modem.psmc.u, // PRAM
                                    &eppc->smc_regs[1], // Control registers
                                    TxBD, 
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM,
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE,
@@ -452,53 +704,125 @@ quicc_smc_serial_init(struct cyg_devtab_
                                    ALIGN_TO_CACHELINES(&quicc_smc2_rxbuf[0][0]),
                                    0xC00, // PortB mask
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BRG,
                                    28  // SI mask position
             );
+    }
 #endif
+#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC1
+    if (chan == &quicc_sxx_serial_channel_scc1) {
+        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM);
+        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM);
+        quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc1,
+                                   &eppc->pram[0].scc.pscc.u, // PRAM
+                                   &eppc->scc_regs[0],        // Control registersn
+                                   TxBD, 
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxNUM,
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_TxSIZE,
+                                   ALIGN_TO_CACHELINES(&quicc_scc1_txbuf[0][0]),
+                                   RxBD, 
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxNUM,
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_RxSIZE,
+                                   ALIGN_TO_CACHELINES(&quicc_scc1_rxbuf[0][0]),
+                                   0x0003, // PortA mask
+                                   0x1000, // PortB mask
+                                   0x0800, // PortC mask
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC1_BRG,
+                                   0  // SI mask position
+            );
     }
+#endif
+#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC2
+    if (chan == &quicc_sxx_serial_channel_scc2) {
+        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM);
+        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM);
+        quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc2,
+                                   &eppc->pram[1].scc.pscc.u, // PRAM
+                                   &eppc->scc_regs[1],        // Control registersn
+                                   TxBD, 
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxNUM,
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_TxSIZE,
+                                   ALIGN_TO_CACHELINES(&quicc_scc2_txbuf[0][0]),
+                                   RxBD, 
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxNUM,
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_RxSIZE,
+                                   ALIGN_TO_CACHELINES(&quicc_scc2_rxbuf[0][0]),
+                                   0x000C, // PortA mask
+                                   0x2000, // PortB mask
+                                   0x0C00, // PortC mask
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC2_BRG,
+                                   8  // SI mask position
+            );
+    }
+#endif
+#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SCC3
+    if (chan == &quicc_sxx_serial_channel_scc3) {
+        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM);
+        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM);
+        quicc_scc_serial_init_info(&quicc_sxx_serial_info_scc3,
+                                   &eppc->pram[2].scc.pscc.u, // PRAM
+                                   &eppc->scc_regs[2],        // Control registersn
+                                   TxBD, 
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxNUM,
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_TxSIZE,
+                                   ALIGN_TO_CACHELINES(&quicc_scc3_txbuf[0][0]),
+                                   RxBD, 
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxNUM,
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_RxSIZE,
+                                   ALIGN_TO_CACHELINES(&quicc_scc3_rxbuf[0][0]),
+                                   0x0000, // PortA mask
+                                   0x00C0, // PortB mask
+                                   0x0000, // PortC mask
+                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SCC3_BRG,
+                                   16  // SI mask position
+            );
+    }
+#endif
     (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
     if (chan->out_cbuf.len != 0) {
         cyg_drv_interrupt_create(smc_chan->int_num,
                                  CYGARC_SIU_PRIORITY_HIGH, // Priority - unused (but asserted)
                                  (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
-                                 quicc_smc_serial_ISR,
-                                 quicc_smc_serial_DSR,
+                                 quicc_sxx_serial_ISR,
+                                 quicc_sxx_serial_DSR,
                                  &smc_chan->serial_interrupt_handle,
                                  &smc_chan->serial_interrupt);
         cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle);
         cyg_drv_interrupt_unmask(smc_chan->int_num);
     }
-    quicc_smc_serial_config_port(chan, &chan->config, true);
+    if (smc_chan->type == _SMC_CHAN) {
+        quicc_smc_serial_config_port(chan, &chan->config, true);
+    } else {
+        quicc_scc_serial_config_port(chan, &chan->config, true);
+    }
     if (cache_state)
         HAL_DCACHE_ENABLE();
     return true;
 }
 
 // This routine is called when the device is "looked" up (i.e. attached)
 static Cyg_ErrNo 
-quicc_smc_serial_lookup(struct cyg_devtab_entry **tab, 
+quicc_sxx_serial_lookup(struct cyg_devtab_entry **tab, 
                   struct cyg_devtab_entry *sub_tab,
                   const char *name)
 {
     serial_channel *chan = (serial_channel *)(*tab)->priv;
     (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
     return ENOERR;
 }
 
 // Force the current transmit buffer to be sent
 static void
-quicc_smc_serial_flush(quicc_smc_serial_info *smc_chan)
+quicc_sxx_serial_flush(quicc_sxx_serial_info *smc_chan)
 {
     volatile struct cp_bufdesc *txbd = smc_chan->txbd;
     int cache_state;
                                        
     HAL_DCACHE_IS_ENABLED(cache_state);
     if (cache_state) {
       HAL_DCACHE_FLUSH(txbd->buffer, smc_chan->txsize);
     }
-
     if ((txbd->length > 0) && 
         ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0)) {
         txbd->ctrl |= QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int;  // Signal buffer ready
         if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
             txbd = smc_chan->tbase;
@@ -510,18 +834,20 @@ quicc_smc_serial_flush(quicc_smc_serial_
 }
 
 // Send a character to the device output buffer.
 // Return 'true' if character is sent to device
 static bool
-quicc_smc_serial_putc(serial_channel *chan, unsigned char c)
+quicc_sxx_serial_putc(serial_channel *chan, unsigned char c)
 {
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     volatile struct cp_bufdesc *txbd, *txfirst;
+    volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
     EPPC *eppc = eppc_base();
     bool res;
+
     cyg_drv_dsr_lock();  // Avoid race condition testing pointers
-    txbd = (struct cp_bufdesc *)((char *)eppc + smc_chan->pram->tbptr);
+    txbd = (struct cp_bufdesc *)((char *)eppc + pram->tbptr);
     txfirst = txbd;
     // Scan for a non-busy buffer
     while (txbd->ctrl & QUICC_BD_CTL_Ready) {
         // This buffer is busy, move to next one
         if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
@@ -535,11 +861,11 @@ quicc_smc_serial_putc(serial_channel *ch
     if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0) {
         // Transmit buffer is not full/busy
         txbd->buffer[txbd->length++] = c;
         if (txbd->length == smc_chan->txsize) {
             // This buffer is now full, tell SMC to start processing it
-            quicc_smc_serial_flush(smc_chan);
+            quicc_sxx_serial_flush(smc_chan);
         }
         res = true;
     } else {
         // No space
         res = false;
@@ -548,15 +874,16 @@ quicc_smc_serial_putc(serial_channel *ch
     return res;
 }
 
 // Fetch a character from the device input buffer, waiting if necessary
 static unsigned char 
-quicc_smc_serial_getc(serial_channel *chan)
+quicc_sxx_serial_getc(serial_channel *chan)
 {
     unsigned char c;
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
+
     while ((rxbd->ctrl & QUICC_BD_CTL_Ready) != 0) ;
     c = rxbd->buffer[0];
     rxbd->length = smc_chan->rxsize;
     rxbd->ctrl |= QUICC_BD_CTL_Ready;
     if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
@@ -568,113 +895,97 @@ quicc_smc_serial_getc(serial_channel *ch
     return c;
 }
 
 // Set up the device characteristics; baud rate, etc.
 static Cyg_ErrNo
-quicc_smc_serial_set_config(serial_channel *chan, cyg_uint32 key,
+quicc_sxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
                             const void *xbuf, cyg_uint32 *len)
 {
+    int res;
+
     switch (key) {
     case CYG_IO_SET_CONFIG_SERIAL_INFO:
-      {
-          // FIXME - The documentation says that you can't change the baud rate
-          // again until at least two BRG input clocks have occurred.
+    {
+        // FIXME - The documentation says that you can't change the baud rate
+        // again until at least two BRG input clocks have occurred.
         cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
+        quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
         if ( *len < sizeof(cyg_serial_info_t) ) {
             return -EINVAL;
         }
         *len = sizeof(cyg_serial_info_t);
-        if ( true != quicc_smc_serial_config_port(chan, config, false) )
+        if (smc_chan->type == _SMC_CHAN) {
+            res = quicc_smc_serial_config_port(chan, config, true);
+        } else {
+            res = quicc_scc_serial_config_port(chan, config, true);
+        }
+        if ( true != res )
             return -EINVAL;
-      }
-      break;
+    }
+    break;
     default:
         return -EINVAL;
     }
     return ENOERR;
 }
 
 // Enable the transmitter (interrupt) on the device
 static void
-quicc_smc_serial_start_xmit(serial_channel *chan)
+quicc_sxx_serial_start_xmit(serial_channel *chan)
 {
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     cyg_drv_dsr_lock();
     if (smc_chan->txbd->length == 0) {
         // See if there is anything to put in this buffer, just to get it going
         (chan->callbacks->xmt_char)(chan);
     }
     if (smc_chan->txbd->length != 0) {
         // Make sure it gets started
-        quicc_smc_serial_flush(smc_chan);
+        quicc_sxx_serial_flush(smc_chan);
     }
     cyg_drv_dsr_unlock();
 }
 
 // Disable the transmitter on the device
 static void 
-quicc_smc_serial_stop_xmit(serial_channel *chan)
+quicc_sxx_serial_stop_xmit(serial_channel *chan)
 {
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     // If anything is in the last buffer, need to get it started
     if (smc_chan->txbd->length != 0) {
-        quicc_smc_serial_flush(smc_chan);
+        quicc_sxx_serial_flush(smc_chan);
     }
 }
 
 // Serial I/O - low level interrupt handler (ISR)
 static cyg_uint32 
-quicc_smc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
+quicc_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
 {
     serial_channel *chan = (serial_channel *)data;
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
     cyg_drv_interrupt_mask(smc_chan->int_num);
     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Cause DSR to be run
 }
 
 // Serial I/O - high level interrupt handler (DSR)
-static void       
-quicc_smc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+static void
+quicc_smc_serial_DSR(serial_channel *chan)
 {
-    serial_channel *chan = (serial_channel *)data;
-    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
-    volatile struct smc_regs *ctl = smc_chan->ctl;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
+    volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;
     volatile struct cp_bufdesc *txbd;
     volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
+    volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
     struct cp_bufdesc *rxlast;
     int i, cache_state;
-#ifdef CYGDBG_DIAG_BUF
-    int _time, _stime;
-    externC cyg_tick_count_t cyg_current_time(void);
-    cyg_drv_isr_lock();
-    enable_diag_uart = 0;
-    HAL_CLOCK_READ(&_time);
-    _stime = (int)cyg_current_time();
-    diag_printf("DSR start - CE: %x, time: %x.%x\n", ctl->smc_smce, _stime, _time);
-    enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
+
     if (ctl->smc_smce & QUICC_SMCE_TX) {
-#ifdef XX_CYGDBG_DIAG_BUF
-        enable_diag_uart = 0;
-        txbd = smc_chan->tbase;
-        for (i = 0;  i < CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM;  i++, txbd++) {
-            diag_printf("Tx BD: %x, length: %d, ctl: %x\n", txbd, txbd->length, txbd->ctrl);
-        }
-        enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
         // Transmit interrupt
         ctl->smc_smce = QUICC_SMCE_TX;  // Reset interrupt state;
         txbd = smc_chan->tbase;  // First buffer
         while (true) {
             if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
-#ifdef XX_CYGDBG_DIAG_BUF
-                enable_diag_uart = 0;
-                HAL_CLOCK_READ(&_time);
-                _stime = (int)cyg_current_time();
-                diag_printf("TX Done - Tx: %x, length: %d, time: %x.%x\n", txbd, txbd->length, _stime, _time);
-                enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
                 txbd->length = 0;
                 txbd->ctrl &= ~QUICC_BD_CTL_Int;  // Reset interrupt bit
             }
             if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
                 txbd = smc_chan->tbase;
@@ -687,23 +998,13 @@ quicc_smc_serial_DSR(cyg_vector_t vector
     }
     while (ctl->smc_smce & QUICC_SMCE_RX) {
         // Receive interrupt
         ctl->smc_smce = QUICC_SMCE_RX;  // Reset interrupt state;
         rxlast = (struct cp_bufdesc *) (
-            (char *)eppc_base() + smc_chan->pram->rbptr );
-#ifdef CYGDBG_DIAG_BUF
-        enable_diag_uart = 0;
-        HAL_CLOCK_READ(&_time);
-        _stime = (int)cyg_current_time();
-        diag_printf("Scan RX - rxbd: %x, rbptr: %x, time: %x.%x\n", rxbd, rxlast, _stime, _time);
-#endif // CYGDBG_DIAG_BUF
+            (char *)eppc_base() + pram->rbptr );
         while (rxbd != rxlast) {
             if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
-#ifdef CYGDBG_DIAG_BUF
-                diag_printf("rxbuf: %x, flags: %x, length: %d\n", rxbd, rxbd->ctrl, rxbd->length);
-                diag_dump_buf(rxbd->buffer, rxbd->length);
-#endif // CYGDBG_DIAG_BUF
                 for (i = 0;  i < rxbd->length;  i++) {
                     (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
                 }
                 // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
                 HAL_DCACHE_IS_ENABLED(cache_state);
@@ -717,35 +1018,91 @@ quicc_smc_serial_DSR(cyg_vector_t vector
                 rxbd = smc_chan->rbase;
             } else {
                 rxbd++;
             }
         }
-#ifdef CYGDBG_DIAG_BUF
-        enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
         smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
     }
     if (ctl->smc_smce & QUICC_SMCE_BSY) {
-#ifdef CYGDBG_DIAG_BUF
-        enable_diag_uart = 0;
-        diag_printf("RX BUSY interrupt\n");
-        enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
         ctl->smc_smce = QUICC_SMCE_BSY;  // Reset interrupt state;
     }
-#ifdef CYGDBG_DIAG_BUF
-    enable_diag_uart = 0;
-    HAL_CLOCK_READ(&_time);
-    _stime = (int)cyg_current_time();
-    diag_printf("DSR done - CE: %x, time: %x.%x\n", ctl->smc_smce, _stime, _time);
-    enable_diag_uart = 1;
-#endif // CYGDBG_DIAG_BUF
     cyg_drv_interrupt_acknowledge(smc_chan->int_num);
     cyg_drv_interrupt_unmask(smc_chan->int_num);
-#ifdef CYGDBG_DIAG_BUF
-    cyg_drv_isr_unlock();
-#endif // CYGDBG_DIAG_BUF
+}
+
+static void
+quicc_scc_serial_DSR(serial_channel *chan)
+{
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
+    volatile struct scc_regs *ctl = (volatile struct scc_regs *)smc_chan->ctl;
+    volatile struct cp_bufdesc *txbd;
+    volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
+    volatile struct uart_pram *pram = (volatile struct uart_pram *)smc_chan->pram;
+    struct cp_bufdesc *rxlast;
+    int i, cache_state;
+
+    if (ctl->scc_scce & QUICC_SCCE_TX) {
+        // Transmit interrupt
+        ctl->scc_scce = QUICC_SCCE_TX;  // Reset interrupt state;
+        txbd = smc_chan->tbase;  // First buffer
+        while (true) {
+            if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
+                txbd->length = 0;
+                txbd->ctrl &= ~QUICC_BD_CTL_Int;  // Reset interrupt bit
+            }
+            if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
+                txbd = smc_chan->tbase;
+                break;
+            } else {
+                txbd++;
+            }
+        }
+        (chan->callbacks->xmt_char)(chan);
+    }
+    while (ctl->scc_scce & QUICC_SCCE_RX) {
+        // Receive interrupt
+        ctl->scc_scce = QUICC_SCCE_RX;  // Reset interrupt state;
+        rxlast = (struct cp_bufdesc *) ((char *)eppc_base() + pram->rbptr);
+        while (rxbd != rxlast) {
+            if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
+                for (i = 0;  i < rxbd->length;  i++) {
+                    (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
+                }
+                // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
+                HAL_DCACHE_IS_ENABLED(cache_state);
+                if (cache_state) {
+                    HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize);  // Make sure no stale data
+                }
+                rxbd->length = 0;
+                rxbd->ctrl |= QUICC_BD_CTL_Ready;
+            }
+            if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
+                rxbd = smc_chan->rbase;
+            } else {
+                rxbd++;
+            }
+        }
+        smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
+    }
+    if (ctl->scc_scce & QUICC_SCCE_BSY) {
+        ctl->scc_scce = QUICC_SCCE_BSY;  // Reset interrupt state;
+    }
+    cyg_drv_interrupt_acknowledge(smc_chan->int_num);
+    cyg_drv_interrupt_unmask(smc_chan->int_num);
+}
+
+static void       
+quicc_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    serial_channel *chan = (serial_channel *)data;
+    quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
+
+    if (smc_chan->type == _SMC_CHAN) {
+        quicc_smc_serial_DSR(chan);
+    } else {
+        quicc_scc_serial_DSR(chan);
+    }
 }
 
 void
 show_rxbd(int dump_all)
 {
Index: devs/serial/powerpc/quicc/current/src/quicc_smc_serial.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/serial/powerpc/quicc/current/src/quicc_smc_serial.h,v
retrieving revision 1.3
diff -u -5 -p -r1.3 quicc_smc_serial.h
--- devs/serial/powerpc/quicc/current/src/quicc_smc_serial.h	23 May 2002 23:01:23 -0000	1.3
+++ devs/serial/powerpc/quicc/current/src/quicc_smc_serial.h	17 Mar 2003 22:15:44 -0000
@@ -10,10 +10,11 @@
 // ====================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -55,32 +56,104 @@
 
 // Description of serial ports using QUICC/SMC
 
 #include <cyg/hal/quicc/ppc8xx.h>                  // QUICC structure definitions
 
-static unsigned int select_word_length[] = {
+// SMC Mode Register
+#define QUICC_SMCMR_CLEN(n)   ((n+1)<<11)   // Character length
+#define QUICC_SMCMR_SB(n)     ((n-1)<<10)   // Stop bits (1 or 2)
+#define QUICC_SMCMR_PE(n)     (n<<9)        // Parity enable (0=disable, 1=enable)
+#define QUICC_SMCMR_PM(n)     (n<<8)        // Parity mode (0=odd, 1=even)
+#define QUICC_SMCMR_UART      (2<<4)        // UART mode
+#define QUICC_SMCMR_TEN       (1<<1)        // Enable transmitter
+#define QUICC_SMCMR_REN       (1<<0)        // Enable receiver
+
+// SMC Events (interrupts)
+#define QUICC_SMCE_BRK 0x10  // Break received
+#define QUICC_SMCE_BSY 0x04  // Busy - receive buffer overrun
+#define QUICC_SMCE_TX  0x02  // Tx interrupt
+#define QUICC_SMCE_RX  0x01  // Rx interrupt
+
+// SMC Commands
+#define QUICC_SMC_CMD_InitTxRx  (0<<8)
+#define QUICC_SMC_CMD_InitTx    (1<<8)
+#define QUICC_SMC_CMD_InitRx    (2<<8)
+#define QUICC_SMC_CMD_StopTx    (4<<8)
+#define QUICC_SMC_CMD_RestartTx (6<<8)
+#define QUICC_SMC_CMD_Reset     0x8000
+#define QUICC_SMC_CMD_Go        0x0001
+
+
+static unsigned int smc_select_word_length[] = {
     QUICC_SMCMR_CLEN(5),  // 5 bits / word (char)
     QUICC_SMCMR_CLEN(6),
     QUICC_SMCMR_CLEN(7),
     QUICC_SMCMR_CLEN(8)
 };
 
-static unsigned int select_stop_bits[] = {
+static unsigned int smc_select_stop_bits[] = {
     0, 
     QUICC_SMCMR_SB(1),   // 1 stop bit
     QUICC_SMCMR_SB(1),   // 1.5 stop bit
     QUICC_SMCMR_SB(2)    // 2 stop bits
 };
 
-static unsigned int select_parity[] = {
+static unsigned int smc_select_parity[] = {
     QUICC_SMCMR_PE(0),                     // No parity
     QUICC_SMCMR_PE(1)|QUICC_SMCMR_PM(1),   // Even parity
     QUICC_SMCMR_PE(1)|QUICC_SMCMR_PM(0),   // Odd parity
     0,                                     // Mark parity
     0,                                     // Space parity
 };
 
+// SCC PSMR masks ....
+#define QUICC_SCC_PSMR_ASYNC   0x8000
+#define QUICC_SCC_PSMR_SB(n)   ((n-1)<<14)  // Stop bits (1=1sb, 2=2sb)
+#define QUICC_SCC_PSMR_CLEN(n) ((n-5)<<12)  // Character Length (5-8)
+#define QUICC_SCC_PSMR_PE(n)   (n<<4)       // Parity enable(0=disabled, 1=enabled)
+#define QUICC_SCC_PSMR_RPM(n)  (n<<2)       // Rx Parity mode (0=odd,  1=low, 2=even, 3=high)
+#define QUICC_SCC_PSMR_TPM(n)  (n)          // Tx Parity mode (0=odd,  1=low, 2=even, 3=high)
+
+// SCC DSR masks
+#define QUICC_SCC_DSR_FULL     0x7e7e
+#define QUICC_SCC_DSR_HALF     0x467e
+
+// SCC GSMR masks ...
+#define QUICC_SCC_GSMR_H_INIT  0x00000060 
+#define QUICC_SCC_GSMR_L_INIT  0x00028004 
+#define QUICC_SCC_GSMR_L_Tx    0x00000010
+#define QUICC_SCC_GSMR_L_Rx    0x00000020
+
+// SCC Events (interrupts)
+#define QUICC_SCCE_BRK         0x0040
+#define QUICC_SCCE_BSY         0x0004
+#define QUICC_SCCE_TX          0x0002
+#define QUICC_SCCE_RX          0x0001
+
+static unsigned int scc_select_word_length[] = {
+  QUICC_SCC_PSMR_CLEN(5),  // 5 bits / word (char)
+  QUICC_SCC_PSMR_CLEN(6),
+  QUICC_SCC_PSMR_CLEN(7),
+  QUICC_SCC_PSMR_CLEN(8)
+};
+
+static unsigned int scc_select_stop_bits[] = {
+  QUICC_SCC_PSMR_SB(1),   // 0.5 stop bit ??
+  QUICC_SCC_PSMR_SB(1),   // 1   stop bit
+  QUICC_SCC_PSMR_SB(2),   // 1.5 stop bit
+  QUICC_SCC_PSMR_SB(2)    // 2   stop bits
+};
+
+
+static unsigned int scc_select_parity[] = {
+  QUICC_SCC_PSMR_PE(0),                                               // No parity
+  QUICC_SCC_PSMR_PE(1)|QUICC_SCC_PSMR_TPM(2)|QUICC_SCC_PSMR_RPM(2), // Even parity
+  QUICC_SCC_PSMR_PE(1)|QUICC_SCC_PSMR_TPM(0)|QUICC_SCC_PSMR_RPM(0), // Odd parity
+  QUICC_SCC_PSMR_PE(1)|QUICC_SCC_PSMR_TPM(3)|QUICC_SCC_PSMR_RPM(3), // High (mark) parity
+  QUICC_SCC_PSMR_PE(1)|QUICC_SCC_PSMR_TPM(1)|QUICC_SCC_PSMR_RPM(1), // Low (space) parity
+};
+
 // Baud rate values, based on board clock
 
 static cyg_int32 select_baud[] = {
     0,      // Unused
     50,     // 50
@@ -106,7 +179,11 @@ static cyg_int32 select_baud[] = {
     0,      // 230400
 };
 
 #define UART_BITRATE(n) (((CYGHWR_HAL_POWERPC_BOARD_SPEED*1000000)/16)/n)
 #define UART_SLOW_BITRATE(n) ((CYGHWR_HAL_POWERPC_BOARD_SPEED*1000000)/n))
+
+// Channel type select
+#define _SCC_CHAN 0
+#define _SMC_CHAN 1
 
 #endif // CYGONCE_POWERPC_QUICC_SMC_SERIAL_H


-- 
------------------------------------------------------------
Gary Thomas                 |
MLB Associates              |  Consulting for the
+1 (970) 229-1963           |    Embedded world
http://www.mlbassoc.com/    |
email: <gary at mlbassoc dot com>  |
gpg: http://www.chez-thomas.org/gary/gpg_key.asc
------------------------------------------------------------


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]