This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
PowerPC 8xx - support SCC1 as serial console
- From: Gary Thomas <gary at chez-thomas dot org>
- To: eCos patches <ecos-patches at sources dot redhat dot com>
- Date: 11 Jul 2002 10:39:02 -0600
- Subject: PowerPC 8xx - support SCC1 as serial console
No interrupt driven serial driver yet :-)
Index: hal/powerpc/quicc/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/powerpc/quicc/current/ChangeLog,v
retrieving revision 1.22
diff -u -5 -p -r1.22 ChangeLog
--- hal/powerpc/quicc/current/ChangeLog 25 Jun 2002 23:15:50 -0000 1.22
+++ hal/powerpc/quicc/current/ChangeLog 11 Jul 2002 16:36:40 -0000
@@ -1,5 +1,12 @@
+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:
* cdl/hal_powerpc_quicc.cdl: Use more common CDL name for baudrate
CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD.
Index: hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl,v
retrieving revision 1.5
diff -u -5 -p -r1.5 hal_powerpc_quicc.cdl
--- hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl 25 Jun 2002 23:15:52 -0000 1.5
+++ hal/powerpc/quicc/current/cdl/hal_powerpc_quicc.cdl 10 Jul 2002 21:22:13 -0000
@@ -7,10 +7,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) 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
## Software Foundation; either version 2 or (at your option) any later version.
##
@@ -48,20 +49,28 @@
#####DESCRIPTIONEND####
#
# ====================================================================
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 {
display "Baud rate for the HAL diagnostic port"
Index: hal/powerpc/quicc/current/include/quicc_smc1.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/powerpc/quicc/current/include/quicc_smc1.h,v
retrieving revision 1.8
diff -u -5 -p -r1.8 quicc_smc1.h
--- hal/powerpc/quicc/current/include/quicc_smc1.h 23 May 2002 23:04:32 -0000 1.8
+++ hal/powerpc/quicc/current/include/quicc_smc1.h 11 Jul 2002 16:36:31 -0000
@@ -2,17 +2,18 @@
#define CYGONCE_HAL_PPC_QUICC_SMC1_H
//=============================================================================
//
// 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
// Software Foundation; either version 2 or (at your option) any later version.
//
@@ -41,15 +42,15 @@
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####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####
//
//=============================================================================
@@ -62,9 +63,7 @@
// This one should only be used by old-stub compatibility code!
externC void cyg_hal_plf_serial_init_channel(void);
#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 */
Index: hal/powerpc/quicc/current/src/quicc_smc1.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/powerpc/quicc/current/src/quicc_smc1.c,v
retrieving revision 1.19
diff -u -5 -p -r1.19 quicc_smc1.c
--- hal/powerpc/quicc/current/src/quicc_smc1.c 25 Jun 2002 23:15:53 -0000 1.19
+++ hal/powerpc/quicc/current/src/quicc_smc1.c 11 Jul 2002 16:32:37 -0000
@@ -1,16 +1,17 @@
//==========================================================================
//
// 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
// Software Foundation; either version 2 or (at your option) any later version.
//
@@ -41,13 +42,13 @@
//#####DESCRIPTIONBEGIN####
//
// 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
// to specify location.
//
@@ -76,53 +77,84 @@
#include <cyg/hal/drv_api.h> // CYG_ISR_HANDLED
#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
#define QUICC_SMCE_BSY 0x04 // Busy - receive buffer overrun
#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.
*
* Comments below reference Motorola's "MPC860 User Manual".
* 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.
* Set PAR and DIR to allow SMCTXD1 and SMRXD1
* (Table 16-39)
@@ -141,12 +173,12 @@ 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
* (Section 16.10.2.1)
*/
@@ -173,50 +205,51 @@ cyg_hal_plf_serial_init_channel(void)
/* 1 break char sent on top XMIT */
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 );
#endif
#endif
@@ -235,16 +268,18 @@ cyg_hal_plf_serial_init_channel(void)
#ifdef CYGDBG_DIAG_BUF
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();
/* tx buffer descriptor */
bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbptr);
@@ -279,13 +314,13 @@ cyg_hal_plf_serial_putc(void* __ch_data,
if (++timeout == 0x7FFFF) {
// A really long time!
#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
diag_printf("bd retry? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
first = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
@@ -305,184 +340,440 @@ cyg_hal_plf_serial_putc(void* __ch_data,
CYGARC_HAL_RESTORE_GP();
}
+/*
+ * 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;
*ch = bd->buffer[0];
bd->length = 0;
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);
if (cache_state) {
HAL_DCACHE_INVALIDATE(bd->buffer, uart_pram->mrblr); // Make sure no stale data
}
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;
CYGACC_CALL_IF_DELAY_US(100);
}
CYGARC_HAL_RESTORE_GP();
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:
{
va_list ap;
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);
}
default:
break;
}
CYGARC_HAL_RESTORE_GP();
return ret;
}
+/*
+ * Low-level interrupt (ISR) handler
+ * This function can be called on only an SMC port
+ */
+static int
+cyg_hal_smc1_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 smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
+ char ch;
+ int res = 0;
+ CYGARC_HAL_SAVE_GP();
+
+ *__ctrlc = 0;
+ if (regs->smc_smce & QUICC_SMCE_RX) {
+
+ regs->smc_smce = 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;
+}
+
+#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_plf_serial_isr(void *__ch_data, int* __ctrlc,
- CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+cyg_hal_scc1_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 scc_regs *regs = (volatile struct scc_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->scc_scce & QUICC_SMCE_RX) {
- eppc->smc_regs[0].smc_smce = QUICC_SMCE_RX;
+ regs->scc_scce = QUICC_SMCE_RX;
/* rx buffer descriptors */
- bd = next_rxbd;
+ 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 + 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;
}
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
* in _bsp_board_init().
@@ -495,25 +786,40 @@ cyg_hal_plf_serial_init(void)
static int init = 0; // It's wrong to do this more than once
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);
}
Index: hal/powerpc/viper/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/powerpc/viper/current/ChangeLog,v
retrieving revision 1.9
diff -u -5 -p -r1.9 ChangeLog
--- hal/powerpc/viper/current/ChangeLog 27 Jun 2002 20:27:19 -0000 1.9
+++ hal/powerpc/viper/current/ChangeLog 11 Jul 2002 16:36:56 -0000
@@ -1,5 +1,9 @@
+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.
2002-06-25 Gary Thomas <gary@chez-thomas.org>
Index: hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl,v
retrieving revision 1.4
diff -u -5 -p -r1.4 hal_powerpc_viper.cdl
--- hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl 25 Jun 2002 23:20:47 -0000 1.4
+++ hal/powerpc/viper/current/cdl/hal_powerpc_viper.cdl 11 Jul 2002 16:34:53 -0000
@@ -7,10 +7,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) 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
## Software Foundation; either version 2 or (at your option) any later version.
##
@@ -62,10 +63,11 @@ cdl_package CYGPKG_HAL_POWERPC_VIPER {
compile hal_diag.c hal_aux.c viper.S
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>"
puts $::cdl_system_header "#define CYGBLD_HAL_PLATFORM_H <pkgconf/hal_powerpc_viper.h>"
@@ -101,11 +103,11 @@ 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 {
display "Debug serial port"
active_if CYGPRI_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_CONFIGURABLE