changeset 237:2b28abd155c7

Add support for SCC1 as a serial console.
author gthomas
date Thu, 11 Jul 2002 16:39:24 +0000
parents e7500517b4b4
children ee09240e2d36
files packages/hal/powerpc/quicc/current/ChangeLog packages/hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl packages/hal/powerpc/quicc/current/include/quicc_smc1.h packages/hal/powerpc/quicc/current/src/quicc_smc1.c packages/hal/powerpc/viper/current/ChangeLog packages/hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl
diffstat 6 files changed, 433 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/powerpc/quicc/current/ChangeLog
+++ b/packages/hal/powerpc/quicc/current/ChangeLog
@@ -1,3 +1,10 @@
+2002-07-11  Gary Thomas  <gary@chez-thomas.org>
+
+	* src/quicc_smc1.c: 
+	* include/quicc_smc1.h: 
+	* cdl/hal_powerpc_quicc.cdl: Add support for SCC1 as a serial
+	console (for newer chips which have this available).
+
 2002-06-25  Gary Thomas  <gary@chez-thomas.org>
 
 	* src/quicc_smc1.c: 
--- a/packages/hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl
+++ b/packages/hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl
@@ -9,6 +9,7 @@
 ## -------------------------------------------
 ## 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
 ##
 ## 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
@@ -50,17 +51,25 @@
 # ====================================================================
 
 cdl_package CYGPKG_HAL_QUICC {
-    display  "Motorola MBX PowerQUICC support"
+    display  "Motorola MPC8xx PowerQUICC support"
     parent        CYGPKG_HAL_POWERPC
     define_header hal_powerpc_quicc.h
     include_dir   cyg/hal/quicc
     description   "
            The QUICC package provides some of the support needed
-           to run eCos on a Motorola MBX board, using the QUICC
+           to run eCos on a Motorola MPC8xx (MBX) board, using the QUICC
            feature of the MPC860 and MPC821 CPUs.
-           Currently only serial IO via SMC1 is provided by
+           Currently only serial IO via SMC1 and SCC1 is provided by
            this package."
 
+    cdl_interface CYGNUM_HAL_QUICC_SCC1 {
+        display    "SCC1 is available for serial I/O"
+        description "
+          Most MPC8xx chipsets use SCC1 to drive the ethernet controller.
+        On some newer (e.g. 860T) chips, SCC1 can be used for general
+        serial since there is a separate ethernet machine."
+    }
+
     compile       quicc_smc1.c
 
     cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD {
--- a/packages/hal/powerpc/quicc/current/include/quicc_smc1.h
+++ b/packages/hal/powerpc/quicc/current/include/quicc_smc1.h
@@ -4,13 +4,14 @@
 //
 //      quicc_smc1.h
 //
-//      PowerPC QUICC basic Serial IO using port SMC1
+//      PowerPC QUICC basic Serial IO using port SMC1/SCC1
 //
 //=============================================================================
 //####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
 //
 // 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
@@ -43,11 +44,11 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    Red Hat
-// Contributors: hmt
+// Contributors: hmt, gthomas
 // Date:         1999-06-08
-// Purpose:      Provide basic Serial IO for MBX board
-// Description:  Serial IO for MBX boards which connect their debug channel
-//               to SMC1; or any QUICC user who wants to use SMC1.
+// Purpose:      Provide basic Serial IO for MPC8xx boards (like Motorola MBX)
+// Description:  Serial IO for MPC8xx boards which connect their debug channel
+//               to SMC1 or SCC1; or any QUICC user who wants to use SMC1/SCC1
 // Usage:
 //
 //####DESCRIPTIONEND####
@@ -64,7 +65,5 @@ externC void cyg_hal_plf_serial_init_cha
 #endif
 
 externC void cyg_hal_plf_serial_init(void);
-externC void cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 __ch);
-externC cyg_uint8 cyg_hal_plf_serial_getc(void* __ch_data);
 
 #endif /* CYGONCE_HAL_PPC_QUICC_SMC1_H */
--- a/packages/hal/powerpc/quicc/current/src/quicc_smc1.c
+++ b/packages/hal/powerpc/quicc/current/src/quicc_smc1.c
@@ -2,13 +2,14 @@
 //
 //      quicc_smc1.c
 //
-//      PowerPC QUICC basic Serial IO using port SMC1
+//      PowerPC QUICC basic Serial IO using port SMC1/SCC1
 //
 //==========================================================================
 //####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
 //
 // 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
@@ -43,9 +44,9 @@
 // Author(s):    Red Hat
 // Contributors: hmt, gthomas
 // Date:         1999-06-08
-// Purpose:      Provide basic Serial IO for MBX board
-// Description:  Serial IO for MBX boards which connect their debug channel
-//               to SMC1; or any QUICC user who wants to use SMC1.
+// Purpose:      Provide basic Serial IO for MPC8xx boards (like Motorola MBX)
+// Description:  Serial IO for MPC8xx boards which connect their debug channel
+//               to SMC1 or SCC1; or any QUICC user who wants to use SMC1/SCC1
 // Usage:
 // Notes:        The driver hooks itself up on procs channel 0. This should
 //               probably be made configurable, allowing the platform
@@ -78,11 +79,34 @@
 #define UART_BIT_RATE(n) (((int)(CYGHWR_HAL_POWERPC_BOARD_SPEED*1000000)/16)/n)
 #define UART_BAUD_RATE CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
 
-#define Txbd     0x2800       /* Tx Buffer Descriptor Offset */
-#define Txbuf    ((volatile char *)eppc + 0x2808)
-#define Rxbd     0x2810       /* Rx Buffer Descriptor Offset */
-#define NUM_Rxbd 4
-#define Rxbuf    ((volatile char *)eppc + Rxbd + (NUM_Rxbd*sizeof(struct cp_bufdesc)))
+// Note: buffers will be placed just after descriptors
+// Sufficient space should be provided between descrptors
+// for the buffers (single characters)
+struct port_info {
+    int                         Txbd;    // Offset to Tx descriptors
+    int                         Txnum;   // Number of Tx buffers
+    int                         Rxbd;    // Offset to Rx descriptors
+    int                         Rxnum;   // Number of Rx buffers
+    int                         intnum;  // Interrupt bit
+    int                         timeout; // Timeout in msec
+    int                         pram;    // [Pointer] to PRAM data
+    int                         regs;    // [Pointer] to control registers
+    volatile struct cp_bufdesc *next_rxbd;
+    int                         irq;     // Interrupt state
+};
+
+static struct port_info ports[] = {
+    { 0x2800, 1, 0x2810, 4, CYGNUM_HAL_INTERRUPT_CPM_SMC1, 1000,
+      (int)&((EPPC *)0)->pram[2].scc.pothers.smc_modem.psmc.u, 
+      (int)&((EPPC *)0)->smc_regs[0]
+    }, 
+#if CYGNUM_HAL_QUICC_SCC1 > 0
+    { 0x2700, 1, 0x2710, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC1, 1000,
+      (int)&((EPPC *)0)->pram[0].scc.pscc.u, 
+      (int)&((EPPC *)0)->scc_regs[0]
+    },
+#endif
+};
 
 // SMC Events (interrupts)
 #define QUICC_SMCE_BRK 0x10  // Break received
@@ -90,7 +114,23 @@
 #define QUICC_SMCE_TX  0x02  // Tx interrupt
 #define QUICC_SMCE_RX  0x01  // Rx interrupt
 
-static volatile struct cp_bufdesc *next_rxbd;
+/*
+ * Reset the communications processor
+ */
+static void
+reset_cpm(void)
+{
+    EPPC *eppc = eppc_base();
+    int i;
+    static int init_done = 0;
+
+    if (init_done) return;
+    init_done++;
+
+    eppc->cp_cr = QUICC_CPM_CR_RESET | QUICC_CPM_CR_BUSY;
+    for (i = 0; i < 100000; i++);
+
+}
 
 /*
  *  Initialize SMC1 as a uart.
@@ -99,28 +139,20 @@ static volatile struct cp_bufdesc *next_
  *  The basic initialization steps are from Section 16.15.8
  *  of that manual.
  */	
-void
-cyg_hal_plf_serial_init_channel(void)
+static void
+cyg_hal_smc1_init_channel(struct port_info *info)
 {
-    EPPC *eppc;
+    EPPC *eppc = eppc_base();
     int i;
-    volatile struct smc_uart_pram *uart_pram;
+    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
+    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
     struct cp_bufdesc *txbd, *rxbd;
 
     static int init_done = 0;
     if (init_done) return;
     init_done++;
 
-    eppc = eppc_base();
-
-    /*
-     *  Reset communications processor
-     */
-    eppc->cp_cr = QUICC_CPM_CR_RESET | QUICC_CPM_CR_BUSY;
-    for (i = 0; i < 100000; i++);
-
-    /* SMC1 Uart parameter ram */
-    uart_pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
+    reset_cpm();
 
     /*
      *  Set up the PortB pins for UART operation.
@@ -143,8 +175,8 @@ cyg_hal_plf_serial_init_channel(void)
      *  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;
+    uart_pram->rbase = info->Rxbd;
+    uart_pram->tbase = info->Txbd;
 
     /*
      *  SDMA & LCD bus request level 5
@@ -175,46 +207,47 @@ cyg_hal_plf_serial_init_channel(void)
     uart_pram->brkcr = 1;
 
     /* setup RX buffer descriptors */
-    rxbd = (struct cp_bufdesc *)((char *)eppc + Rxbd);
-    next_rxbd = rxbd;
-    for (i = 0;  i < NUM_Rxbd;  i++) {
+    rxbd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
+    info->next_rxbd = rxbd;
+    for (i = 0;  i < info->Rxnum;  i++) {
         rxbd->length = 0;
-        rxbd->buffer = Rxbuf+i;
+        rxbd->buffer = ((char *)eppc + (info->Rxbd+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
         rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
-        if (i == (NUM_Rxbd-1)) {
+        if (i == ((info->Rxnum)-1)) {
             rxbd->ctrl   |= QUICC_BD_CTL_Wrap;
         }
         rxbd++;
     }
     // Compiler bug: for whatever reason, the Wrap code above fails!
-    rxbd = (struct cp_bufdesc *)((char *)eppc + Rxbd);
-    rxbd[NUM_Rxbd-1].ctrl   |= QUICC_BD_CTL_Wrap;
+    rxbd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
+    rxbd[(info->Rxnum)-1].ctrl   |= QUICC_BD_CTL_Wrap;
 
     /* setup TX buffer descriptor */
-    txbd = (struct cp_bufdesc *)((char *)eppc + Txbd);
+    txbd = (struct cp_bufdesc *)((char *)eppc + info->Txbd);
     txbd->length = 1;
-    txbd->buffer = Txbuf;
+    txbd->buffer = ((char *)eppc + (info->Txbd+(info->Txnum*sizeof(struct cp_bufdesc))));
     txbd->ctrl   = 0x2000;
 
     /*
      *  Clear any previous events. Mask interrupts.
      *  (Section 16.15.7.14 and 16.15.7.15)
      */
-    eppc->smc_regs[0].smc_smce = 0xff;
-    eppc->smc_regs[0].smc_smcm = 5;
+    regs->smc_smce = 0xff;
+    regs->smc_smcm = 5;
 
     /*
      *  Set 8,n,1 characters, then also enable rx and tx.
      *  (Section 16.15.7.11)
      */
-    eppc->smc_regs[0].smc_smcmr = 0x4820;
-    eppc->smc_regs[0].smc_smcmr = 0x4823;
+    regs->smc_smcmr = 0x4820;
+    regs->smc_smcmr = 0x4823;
 
     /*
      *  Init Rx & Tx params for SMC1
      */
     eppc->cp_cr = 0x91;
 
+    info->irq = 0;  // Interrupts not enabled
 #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // remove below
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
     HAL_INTERRUPT_UNMASK( CYGNUM_HAL_INTERRUPT_CPM_SMC1 );
@@ -237,12 +270,14 @@ cyg_hal_plf_serial_init_channel(void)
 extern int enable_diag_uart;
 #endif // CYGDBG_DIAG_BUF
 
-void 
-cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 ch)
+static void 
+cyg_hal_smc1_putc(void* __ch_data, cyg_uint8 ch)
 {
     volatile struct cp_bufdesc *bd, *first;
-    EPPC *eppc = (EPPC*) __ch_data;
-    volatile struct smc_uart_pram *uart_pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
+    EPPC *eppc = eppc_base();
+    struct port_info *info = (struct port_info *)__ch_data;
+    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
+    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
     int timeout;
     CYGARC_HAL_SAVE_GP();
 
@@ -281,9 +316,9 @@ cyg_hal_plf_serial_putc(void* __ch_data,
 #ifdef CYGDBG_DIAG_BUF
             diag_printf("bd fail? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
 #endif // CYGDBG_DIAG_BUF
-            eppc->smc_regs[0].smc_smcmr &= ~QUICC_SMCMR_TEN;  // Disable transmitter
+            regs->smc_smcmr &= ~QUICC_SMCMR_TEN;  // Disable transmitter
             bd->ctrl &= ~QUICC_BD_CTL_Ready;
-            eppc->smc_regs[0].smc_smcmr |= QUICC_SMCMR_TEN;   // Enable transmitter
+            regs->smc_smcmr |= QUICC_SMCMR_TEN;   // Enable transmitter
             bd->ctrl |= QUICC_BD_CTL_Ready;
             timeout = 0;
 #ifdef CYGDBG_DIAG_BUF
@@ -307,16 +342,21 @@ cyg_hal_plf_serial_putc(void* __ch_data,
 }
 
 
+/*
+ * Get a character from a port, non-blocking
+ * This function can be called on either an SMC or SCC port
+ */
 static cyg_bool
-cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+cyg_hal_sxx_getc_nonblock(void* __ch_data, cyg_uint8* ch)
 {
     volatile struct cp_bufdesc *bd;
-    EPPC *eppc = (EPPC*) __ch_data;
-    volatile struct smc_uart_pram *uart_pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
+    EPPC *eppc = eppc_base();
+    struct port_info *info = (struct port_info *)__ch_data;
+    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
     int cache_state;
 
     /* rx buffer descriptor */
-    bd = next_rxbd;
+    bd = info->next_rxbd;
 
     if (bd->ctrl & QUICC_BD_CTL_Ready)
         return false;
@@ -327,11 +367,11 @@ cyg_hal_plf_serial_getc_nonblock(void* _
     bd->buffer[0] = '\0';
     bd->ctrl |= QUICC_BD_CTL_Ready;
     if (bd->ctrl & QUICC_BD_CTL_Wrap) {
-        bd = (struct cp_bufdesc *)((char *)eppc + Rxbd);
+        bd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
     } else {
         bd++;
     }
-    next_rxbd = bd;
+    info->next_rxbd = bd;
 
     // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
     HAL_DCACHE_IS_ENABLED(cache_state);
@@ -342,54 +382,64 @@ cyg_hal_plf_serial_getc_nonblock(void* _
     return true;
 }
 
-cyg_uint8
-cyg_hal_plf_serial_getc(void* __ch_data)
+/*
+ * Get a character from a port, blocking
+ * This function can be called on either an SMC or SCC port
+ */
+static cyg_uint8
+cyg_hal_sxx_getc(void* __ch_data)
 {
     cyg_uint8 ch;
     CYGARC_HAL_SAVE_GP();
 
-    while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
+    while(!cyg_hal_sxx_getc_nonblock(__ch_data, &ch));
 
     CYGARC_HAL_RESTORE_GP();
     return ch;
 }
 
 
-
 static void
-cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
+cyg_hal_smc1_write(void* __ch_data, const cyg_uint8* __buf, 
                          cyg_uint32 __len)
 {
     CYGARC_HAL_SAVE_GP();
 
     while(__len-- > 0)
-        cyg_hal_plf_serial_putc(__ch_data, *__buf++);
+        cyg_hal_smc1_putc(__ch_data, *__buf++);
 
     CYGARC_HAL_RESTORE_GP();
 }
 
+/*
+ * Read a sequence of characters from a port
+ * This function can be called on either an SMC or SCC port
+ */
 static void
-cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+cyg_hal_sxx_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
 {
     CYGARC_HAL_SAVE_GP();
 
     while(__len-- > 0)
-        *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
+        *__buf++ = cyg_hal_sxx_getc(__ch_data);
 
     CYGARC_HAL_RESTORE_GP();
 }
 
-cyg_int32 msec_timeout = 1000;
-
-cyg_bool
-cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
+/*
+ * Read a character from a port, with a timeout
+ * This function can be called on either an SMC or SCC port
+ */
+static cyg_bool
+cyg_hal_sxx_getc_timeout(void* __ch_data, cyg_uint8* ch)
 {
-    int delay_count = msec_timeout * 10; // delay in .1 ms steps
+    struct port_info *info = (struct port_info *)__ch_data;
+    int delay_count = info->timeout * 10; // delay in .1 ms steps
     cyg_bool res;
     CYGARC_HAL_SAVE_GP();
 
     for(;;) {
-        res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
+        res = cyg_hal_sxx_getc_nonblock(__ch_data, ch);
         if (res || 0 == delay_count--)
             break;
         
@@ -400,25 +450,29 @@ cyg_hal_plf_serial_getc_timeout(void* __
     return res;
 }
 
+/*
+ * Control/query the state of a port
+ * This function can be called on either an SMC or SCC port
+ */
 static int
-cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+cyg_hal_sxx_control(void *__ch_data, __comm_control_cmd_t __func, ...)
 {
-    static int irq_state = 0;
+    struct port_info *info = (struct port_info *)__ch_data;
     int ret = 0;
     CYGARC_HAL_SAVE_GP();
 
     switch (__func) {
     case __COMMCTL_IRQ_ENABLE:
-        HAL_INTERRUPT_UNMASK(CYGNUM_HAL_INTERRUPT_CPM_SMC1);
-        irq_state = 1;
+        HAL_INTERRUPT_UNMASK(info->intnum);
+        info->irq = 1;
         break;
     case __COMMCTL_IRQ_DISABLE:
-        ret = irq_state;
-        irq_state = 0;
-        HAL_INTERRUPT_MASK(CYGNUM_HAL_INTERRUPT_CPM_SMC1);
+        ret = info->irq;
+        info->irq = 0;
+        HAL_INTERRUPT_MASK(info->intnum);
         break;
     case __COMMCTL_DBG_ISR_VECTOR:
-        ret = CYGNUM_HAL_INTERRUPT_CPM_SMC1;
+        ret = info->intnum;
         break;
     case __COMMCTL_SET_TIMEOUT:
     {
@@ -426,8 +480,8 @@ cyg_hal_plf_serial_control(void *__ch_da
 
         va_start(ap, __func);
 
-        ret = msec_timeout;
-        msec_timeout = va_arg(ap, cyg_uint32);
+        ret = info->timeout;
+        info->timeout = va_arg(ap, cyg_uint32);
 
         va_end(ap);
     }        
@@ -438,23 +492,29 @@ cyg_hal_plf_serial_control(void *__ch_da
     return ret;
 }
 
+/*
+ * Low-level interrupt (ISR) handler
+ * This function can be called on only an SMC port
+ */
 static int
-cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
-                       CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+cyg_hal_smc1_isr(void *__ch_data, int* __ctrlc, 
+                 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
 {
-    EPPC *eppc = (EPPC*) __ch_data;
+    EPPC *eppc = eppc_base();
     volatile struct cp_bufdesc *bd;
+    struct port_info *info = (struct port_info *)__ch_data;
+    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
     char ch;
     int res = 0;
     CYGARC_HAL_SAVE_GP();
 
     *__ctrlc = 0;
-    if (eppc->smc_regs[0].smc_smce & QUICC_SMCE_RX) {
+    if (regs->smc_smce & QUICC_SMCE_RX) {
 
-        eppc->smc_regs[0].smc_smce = QUICC_SMCE_RX;
+        regs->smc_smce = QUICC_SMCE_RX;
 
         /* rx buffer descriptors */
-        bd = next_rxbd;
+        bd = info->next_rxbd;
 
         if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
             
@@ -463,18 +523,18 @@ cyg_hal_plf_serial_isr(void *__ch_data, 
             bd->length = 1;
             bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
             if (bd->ctrl & QUICC_BD_CTL_Wrap) {
-                bd = (struct cp_bufdesc *)((char *)eppc + Rxbd);
+                bd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
             } else {
                 bd++;
             }
-            next_rxbd = bd;
+            info->next_rxbd = bd;
         
             if( cyg_hal_is_break( &ch , 1 ) )
                 *__ctrlc = 1;
         }
 
         // Interrupt handled. Acknowledge it.
-        eppc->cpmi_cisr = 0x10;
+        HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
         res = CYG_ISR_HANDLED;
     }
 
@@ -482,6 +542,237 @@ cyg_hal_plf_serial_isr(void *__ch_data, 
     return res;
 }
 
+#if CYGNUM_HAL_QUICC_SCC1 > 0
+/*
+ *  Initialize SCC1 as a uart.
+ *
+ *  Comments below reference Motorola's "MPC860 User Manual".
+ *  The basic initialization steps are from Section 16.15.8
+ *  of that manual.
+ */	
+static void
+cyg_hal_scc1_init_channel(struct port_info *info)
+{
+    EPPC *eppc = eppc_base();
+    int i;
+    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
+    volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
+    struct cp_bufdesc *txbd, *rxbd;
+
+    static int init_done = 0;
+    if (init_done) return;
+    init_done++;
+
+    reset_cpm();
+
+    /*
+     *  Set up the PortA pins for UART operation.
+     */
+    eppc->pio_papar |= 0x03;
+    eppc->pio_padir &= ~0x03;
+    eppc->pio_paodr &= ~0x03;
+
+    /* CTS on PortC.11 */
+    eppc->pio_pcdir &= 0x800;
+    eppc->pio_pcpar &= 0x800;
+    eppc->pio_pcso  |= 0x800;
+
+    /* RTS on PortB.19 */
+    eppc->pip_pbpar |= 0x1000;
+    eppc->pip_pbdir |= 0x1000;
+
+    /* Configure baud rate generator (Section 16.13.2) */
+    eppc->brgc2 = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
+
+    /*
+     *  NMSI mode, BRG2 to SCC1
+     */
+    eppc->si_simode = 0;
+    eppc->si_sicr = (1<<3)|(1<<0);
+
+    /*
+     *  Set pointers to buffer descriptors.
+     */
+    uart_pram->rbase = info->Rxbd;
+    uart_pram->tbase = info->Txbd;
+
+    /*
+     *  SDMA & LCD bus request level 5
+     */
+    eppc->dma_sdcr = 1;
+
+    /*
+     *  Set Rx and Tx function code
+     */
+    uart_pram->rfcr = 0x18;
+    uart_pram->tfcr = 0x18;
+
+    /* max receive buffer length */
+    uart_pram->mrblr = 1;
+
+    /* disable max_idle feature */
+    uart_pram->max_idl = 0;
+
+    /* 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;
+
+    /* setup RX buffer descriptors */
+    rxbd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
+    info->next_rxbd = rxbd;
+    for (i = 0;  i < info->Rxnum;  i++) {
+        rxbd->length = 0;
+        rxbd->buffer = ((char *)eppc + (info->Rxbd+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
+        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
+        if (i == ((info->Rxnum)-1)) {
+            rxbd->ctrl   |= QUICC_BD_CTL_Wrap;
+        }
+        rxbd++;
+    }
+    // Compiler bug: for whatever reason, the Wrap code above fails!
+    rxbd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
+    rxbd[(info->Rxnum)-1].ctrl   |= QUICC_BD_CTL_Wrap;
+
+    /* setup TX buffer descriptor */
+    txbd = (struct cp_bufdesc *)((char *)eppc + info->Txbd);
+    txbd->length = 1;
+    txbd->buffer = ((char *)eppc + (info->Txbd+(info->Txnum*sizeof(struct cp_bufdesc))));
+    txbd->ctrl   = 0x2000;
+
+    /*
+     *  Init Rx & Tx params for SCC1
+     */
+    eppc->cp_cr = 0x41;
+
+    /*
+     *  Clear any previous events. Mask interrupts.
+     *  (Section 16.15.7.14 and 16.15.7.15)
+     */
+    regs->scc_scce = 0xff;
+    regs->scc_sccm = 5;
+
+    /*
+     *  Set 8,n,1 characters
+     */
+    regs->scc_psmr = (3<<12);
+    regs->scc_gsmr_h = 0x20;          // 8bit FIFO
+    regs->scc_gsmr_l = 0x00028004;    // 16x TxCLK, 16x RxCLK, UART
+    regs->scc_gsmr_l |= 0x30;         // Enable Rx, Tx
+
+    info->irq = 0;
+#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // remove below
+#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
+    HAL_INTERRUPT_UNMASK( CYGNUM_HAL_INTERRUPT_CPM_SCC1 );
+#endif
+#endif
+}
+
+static void 
+cyg_hal_scc1_putc(void* __ch_data, cyg_uint8 ch)
+{
+    volatile struct cp_bufdesc *bd, *first;
+    EPPC *eppc = eppc_base();
+    struct port_info *info = (struct port_info *)__ch_data;
+    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
+    CYGARC_HAL_SAVE_GP();
+
+    /* tx buffer descriptor */
+    bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbptr);
+
+    // Scan for a free buffer
+    first = bd;
+    while (bd->ctrl & QUICC_BD_CTL_Ready) {
+        if (bd->ctrl & QUICC_BD_CTL_Wrap) {
+            bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
+        } else {
+            bd++;
+        }
+        if (bd == first) break;
+    }
+
+    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait for buffer free
+    if (bd->ctrl & QUICC_BD_CTL_Int) {
+        // This buffer has just completed interrupt output.  Reset bits
+        bd->ctrl &= ~QUICC_BD_CTL_Int;
+        bd->length = 0;
+    }
+
+    bd->buffer[bd->length++] = ch;
+    bd->ctrl      |= QUICC_BD_CTL_Ready;
+
+    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait until buffer free
+    bd->length = 0;
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+static void
+cyg_hal_scc1_write(void* __ch_data, const cyg_uint8* __buf, 
+                         cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        cyg_hal_scc1_putc(__ch_data, *__buf++);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+static int
+cyg_hal_scc1_isr(void *__ch_data, int* __ctrlc, 
+                 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+    EPPC *eppc = eppc_base();
+    volatile struct cp_bufdesc *bd;
+    struct port_info *info = (struct port_info *)__ch_data;
+    volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
+    char ch;
+    int res = 0;
+    CYGARC_HAL_SAVE_GP();
+
+    *__ctrlc = 0;
+    if (regs->scc_scce & QUICC_SMCE_RX) {
+
+        regs->scc_scce = QUICC_SMCE_RX;
+
+        /* rx buffer descriptors */
+        bd = info->next_rxbd;
+
+        if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
+            
+            // then there be a character waiting
+            ch = bd->buffer[0];
+            bd->length = 1;
+            bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
+            if (bd->ctrl & QUICC_BD_CTL_Wrap) {
+                bd = (struct cp_bufdesc *)((char *)eppc + info->Rxbd);
+            } else {
+                bd++;
+            }
+            info->next_rxbd = bd;
+        
+            if( cyg_hal_is_break( &ch , 1 ) )
+                *__ctrlc = 1;
+        }
+
+        // Interrupt handled. Acknowledge it.
+        HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
+        res = CYG_ISR_HANDLED;
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+#endif // CYGNUM_HAL_QUICC_SCC1
+
 /*
  * Early initialization of comm channels. Must not rely
  * on interrupts, yet. Interrupt operation can be enabled
@@ -497,21 +788,36 @@ cyg_hal_plf_serial_init(void)
     if (init) return;
     init++;
 
-    cyg_hal_plf_serial_init_channel();
-
     // Setup procs in the vector table
 
-    // Set channel 0
+    // Set channel 0 - SMC1
+    cyg_hal_smc1_init_channel(&ports[0]);
     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);// Should be configurable!
     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
-    CYGACC_COMM_IF_CH_DATA_SET(*comm, eppc_base());
-    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
-    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
-    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
-    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
-    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
-    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
-    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[0]);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_smc1_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_smc1_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_smc1_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
+
+#if CYGNUM_HAL_QUICC_SCC1 > 0
+
+    // Set channel 1 - SCC1
+    cyg_hal_scc1_init_channel(&ports[1]);
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(1);// Should be configurable!
+    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[1]);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_scc1_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_scc1_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_scc1_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
+#endif
 
     // Restore original console
     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
--- a/packages/hal/powerpc/viper/current/ChangeLog
+++ b/packages/hal/powerpc/viper/current/ChangeLog
@@ -1,3 +1,7 @@
+2002-07-11  Gary Thomas  <gary@chez-thomas.org>
+
+	* cdl/hal_powerpc_viper.cdl: Add SCC1 as a serial console port.
+
 2002-06-27  Gary Thomas  <gary@chez-thomas.org>
 
 	* include/plf_regs.h: New file - platform overrides.
--- a/packages/hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl
+++ b/packages/hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl
@@ -9,6 +9,7 @@
 ## -------------------------------------------
 ## 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
 ##
 ## 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
@@ -64,6 +65,7 @@ cdl_package CYGPKG_HAL_POWERPC_VIPER {
     implements    CYGINT_HAL_DEBUG_GDB_STUBS
     implements    CYGINT_HAL_DEBUG_GDB_STUBS_BREAK
     implements    CYGINT_HAL_VIRTUAL_VECTOR_SUPPORT
+    implements    CYGNUM_HAL_QUICC_SCC1
 
     define_proc {
         puts $::cdl_system_header "#define CYGBLD_HAL_TARGET_H   <pkgconf/hal_powerpc_mpc8xx.h>"
@@ -103,7 +105,7 @@ cdl_package CYGPKG_HAL_POWERPC_VIPER {
    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS {
        display      "Number of communication channels on the board"
        flavor       data
-       calculated   1
+       calculated   1+CYGNUM_HAL_QUICC_SCC1
    }
 
    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL {