OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/ecos-2.0/packages/devs/serial/powerpc/quicc2/v2_0
    from Rev 27 to Rev 174
    Reverse comparison

Rev 27 → Rev 174

/cdl/ser_quicc2_scc.cdl
0,0 → 1,289
# ====================================================================
#
# ser_quicc2_scc.cdl
#
# eCos serial PowerPC/QUICC2 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
##
## 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.
##
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
## for more details.
##
## You should have received a copy of the GNU General Public License along
## with eCos; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## As a special exception, if other files instantiate templates or use macros
## or inline functions from this file, or you compile this file and link it
## with other works to produce a work based on this file, this file does not
## by itself cause the resulting work to be covered by the GNU General Public
## License. However the source code for this file must still be made available
## in accordance with section (3) of the GNU General Public License.
##
## This exception does not invalidate any other reasons why a work based on
## this file might be covered by the GNU General Public License.
##
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
## at http://sources.redhat.com/ecos/ecos-license/
## -------------------------------------------
#####ECOSGPLCOPYRIGHTEND####
# ====================================================================
######DESCRIPTIONBEGIN####
#
# Author(s): mtek
# Original data: gthomas
# Contributors:
# Date: 2002-02-27
#
#####DESCRIPTIONEND####
#
# ====================================================================
 
 
cdl_package CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC {
display "PowerPC QUICC2/SCC serial device drivers"
 
parent CYGPKG_IO_SERIAL_DEVICES
active_if CYGPKG_IO_SERIAL
active_if CYGPKG_HAL_POWERPC_MPC8260
 
requires CYGPKG_ERROR
include_dir cyg/io
include_files ; # none _exported_ whatsoever
description "
This option enables the serial device drivers for the
PowerPC QUICC2/SCC."
 
compile -library=libextras.a quicc2_scc_serial.c
 
define_proc {
puts $::cdl_system_header "/***** serial driver proc output start *****/"
puts $::cdl_system_header "#define CYGDAT_IO_SERIAL_DEVICE_HEADER <pkgconf/io_serial_powerpc_quicc2_scc.h>"
puts $::cdl_system_header "/***** serial driver proc output end *****/"
}
 
cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1 {
display "PowerPC QUICC2/SCC serial port 1 driver"
flavor bool
default_value 1
description "
This option includes the serial device driver for the PowerPC
QUICC2/SCC port 1."
 
cdl_option CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_NAME {
display "Device name for PowerPC QUICC2/SCC serial port 1"
flavor data
default_value {"\"/dev/ser1\""}
description "
This option specifies the device name for the PowerPC
QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD {
display "Baud rate for the PowerPC QUICC2/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 9600
description "
This option specifies the default baud rate (speed) for the
PowerPC QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE {
display "Buffer size for the PowerPC QUICC2/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 QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BRG {
display "Which baud rate generator to use for the PowerPC QUICC2/SCC serial port 1"
flavor data
legal_values 1 to 4
default_value 1
description "
This option specifies which of the four baud rate generators
to use for the PowerPC QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE {
display "Output buffer size for the PowerPC QUICC2/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 QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM {
display "Number of output buffers for the PowerPC QUICC2/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 QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE {
display "Input buffer size for the PowerPC QUICC2/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 QUICC2/SCC port 1."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM {
display "Number of input buffers for the PowerPC QUICC2/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 QUICC2/SCC port 1."
}
}
 
cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2 {
display "PowerPC QUICC2/SCC serial port 2 driver"
flavor bool
default_value 1
description "
This option includes the serial device driver for the PowerPC
QUICC2/SCC port 2."
 
cdl_option CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_NAME {
display "Device name for PowerPC QUICC2/SCC serial port 2"
flavor data
default_value {"\"/dev/ser2\""}
description "
This option specifies the device name for the PowerPC
QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD {
display "Baud rate for the PowerPC QUICC2/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 9600
description "
This option specifies the default baud rate (speed) for the
PowerPC QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE {
display "Buffer size for the PowerPC QUICC2/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 QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BRG {
display "Which baud rate generator to use for the PowerPC QUICC2/SCC serial port 2"
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 QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE {
display "Output buffer size for the PowerPC QUICC2/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 QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM {
display "Number of output buffers for the PowerPC QUICC2/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 QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE {
display "Input buffer size for the PowerPC QUICC2/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 QUICC2/SCC port 2."
}
 
cdl_option CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM {
display "Number of output buffers for the PowerPC QUICC2/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 QUICC2/SCC port 2."
}
}
 
cdl_component CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_OPTIONS {
display "Serial device driver build options"
flavor none
description "
Package specific build options including control over
compiler flags used only in building this package,
and details of which tests are built."
 
 
cdl_option CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_CFLAGS_ADD {
display "Additional compiler flags"
flavor data
no_define
default_value { "" }
description "
This option modifies the set of compiler flags for
building these serial device drivers. These flags are used in addition
to the set of global flags."
}
 
cdl_option CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_CFLAGS_REMOVE {
display "Suppressed compiler flags"
flavor data
no_define
default_value { "" }
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."
}
}
}
 
# EOF ser_quicc_smc.cdl
/src/quicc2_scc_serial.h
0,0 → 1,209
#ifndef CYGONCE_POWERPC_QUICC2_SCC_SERIAL_H
#define CYGONCE_POWERPC_QUICC2_SCC_SERIAL_H
 
// ====================================================================
//
// quicc2_scc_serial.h
//
// Device I/O - Description of PowerPC QUICC2/SCC serial hardware
//
// ====================================================================
//####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.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
// ====================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): mtek
// Contributors: gthomas
// Date: 2002-2-27
// Purpose: Internal interfaces for serial I/O drivers
// Description:
//
//####DESCRIPTIONEND####
//
// ====================================================================
 
// Description of serial ports using QUICC2/SCC
 
// 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)))
 
#define UART_BIT_RATE(n) \
(((int)(CYGHWR_HAL_POWERPC_BOARD_SPEED*1000000))/(n * 64))
 
// SCC PSMR masks ....
#define QUICC2_SCC_PSMR_ASYNC 0x8000
#define QUICC2_SCC_PSMR_SB(n) ((n-1)<<14) // Stop bits (1=1sb, 2=2sb)
#define QUICC2_SCC_PSMR_CLEN(n) ((n-5)<<12) // Character Length (5-8)
#define QUICC2_SCC_PSMR_PE(n) (n<<4) // Parity enable(0=disabled, 1=enabled)
#define QUICC2_SCC_PSMR_RPM(n) (n<<2) // Rx Parity mode (0=odd, 1=low, 2=even, 3=high)
#define QUICC2_SCC_PSMR_TPM(n) (n) // Tx Parity mode (0=odd, 1=low, 2=even, 3=high)
 
// SCC DSR masks
#define QUICC2_SCC_DSR_FULL 0x7e7e
#define QUICC2_SCC_DSR_HALF 0x467e
 
// SCC GSMR masks ...
#define QUICC2_SCC_GSMR_H_INIT 0x00000060
#define QUICC2_SCC_GSMR_L_INIT 0x00028004
#define QUICC2_SCC_GSMR_L_ENT 0x00000010
#define QUICC2_SCC_GSMR_L_ENR 0x00000020
 
// SCC Events (interrupts)
#define QUICC2_SCCE_BRK 0x0040
#define QUICC2_SCCE_BSY 0x0004
#define QUICC2_SCCE_TX 0x0002
#define QUICC2_SCCE_RX 0x0001
 
// CP commands for SCC1 and SCC2
#define QUICC2_CPCR_SCC1 0x00800000
#define QUICC2_CPCR_SCC2 0x04A00000
#define QUICC2_CPCR_READY 0x00010000
#define QUICC2_CPCR_INIT_TX_RX 0x0
#define QUICC2_CPCR_INIT_RX 0x1
#define QUICC2_CPCR_INIT_TX 0x2
#define QUICC2_CPCR_STOP_TX 0x4
#define QUICC2_CPCR_RESTART_TX 0x6
#define QUICC2_CPCR_RESET 0x80000000
 
// SCC Buffer descriptor control bits
#define QUICC2_BD_CTL_Ready 0x8000 // Buffer contains data (tx) or is empty (rx)
#define QUICC2_BD_CTL_Wrap 0x2000 // Last buffer in list
#define QUICC2_BD_CTL_Int 0x1000 // Generate interrupt when empty (tx) or full (rx)
 
// PORT configuration masks for SCC1 and SCC2
#define QUICC2_SCC1_PORTC_PPAR (0x00020000)
#define QUICC2_SCC1_PORTD_PPAR (0x00000003)
#define QUICC2_SCC1_PORTD_PDIR (0x00000002)
 
#define QUICC2_SCC2_PORTC_PPAR (0x00080000)
#define QUICC2_SCC2_PORTD_PPAR (0x00000018)
#define QUICC2_SCC2_PORTD_PDIR (0x00000010)
 
// SCC clock Route register constants
#define QUICC2_CMX_SCC1_CLR 0x00ffffff
#define QUICC2_CMX_SCC1_BRG1 0x00000000
#define QUICC2_CMX_SCC1_BRG2 0x09000000
#define QUICC2_CMX_SCC1_BRG3 0x12000000
#define QUICC2_CMX_SCC1_BRG4 0x1b000000
 
#define QUICC2_CMX_SCC2_CLR 0xff00ffff
#define QUICC2_CMX_SCC2_BRG1 0x00000000
#define QUICC2_CMX_SCC2_BRG2 0x00090000
#define QUICC2_CMX_SCC2_BRG3 0x00120000
#define QUICC2_CMX_SCC2_BRG4 0x001b0000
 
static unsigned int select_word_length[] = {
QUICC2_SCC_PSMR_CLEN(5), // 5 bits / word (char)
QUICC2_SCC_PSMR_CLEN(6),
QUICC2_SCC_PSMR_CLEN(7),
QUICC2_SCC_PSMR_CLEN(8)
};
 
static unsigned int select_stop_bits[] = {
QUICC2_SCC_PSMR_SB(1), // 0.5 stop bit ??
QUICC2_SCC_PSMR_SB(1), // 1 stop bit
QUICC2_SCC_PSMR_SB(2), // 1.5 stop bit
QUICC2_SCC_PSMR_SB(2) // 2 stop bits
};
 
 
static unsigned int select_parity[] = {
QUICC2_SCC_PSMR_PE(0), // No parity
QUICC2_SCC_PSMR_PE(1)|QUICC2_SCC_PSMR_TPM(2)|QUICC2_SCC_PSMR_RPM(2), // Even parity
QUICC2_SCC_PSMR_PE(1)|QUICC2_SCC_PSMR_TPM(0)|QUICC2_SCC_PSMR_RPM(0), // Odd parity
QUICC2_SCC_PSMR_PE(1)|QUICC2_SCC_PSMR_TPM(3)|QUICC2_SCC_PSMR_RPM(3), // High (mark) parity
QUICC2_SCC_PSMR_PE(1)|QUICC2_SCC_PSMR_TPM(1)|QUICC2_SCC_PSMR_RPM(1), // Low (space) parity
};
 
 
// Baud rate values, will be used by the macro ...
#define QUICC2_BRG_EN 0x00010000
static unsigned long select_baud[] = {
0, // unused
50,
75,
110,
134,
150,
200,
300,
600,
1200,
1800,
2400,
3600,
4800,
7200,
9600,
14400,
19200,
38400,
57600,
115200,
230400
};
 
// Board control and status registers
#define QUICC2_BCSR_EN_SCC1 0x02000000
#define QUICC2_BCSR_EN_SCC2 0x01000000
 
typedef struct bcsr {
volatile unsigned long bcsr0;
volatile unsigned long bcsr1;
volatile unsigned long bcsr2;
volatile unsigned long bcsr3;
} t_BCSR;
 
 
typedef struct scc_bd{
cyg_int16 ctrl;
cyg_int16 length;
cyg_int8 *buffer;
} scc_bd;
 
typedef struct quicc2_scc_serial_info {
unsigned long scc_cpcr; // Selects scc for cpcr
volatile struct scc_regs_8260 *scc_regs; // Ptr to scc registers
volatile t_Scc_Pram *scc_pram; // Ptr to scc pram
volatile int *brg; // Ptr to baud rate generator
struct scc_bd *txbd, *rxbd; // Next Tx, Rx descriptor to use
struct scc_bd *tbase, *rbase; // First Tx, Rx descriptor
int txsize, rxsize; // Length of individual buffers
unsigned int int_vector;
cyg_interrupt serial_interrupt;
cyg_handle_t serial_interrupt_handle;
} quicc2_scc_serial_info;
 
#endif // CYGONCE_POWERPC_QUICC_SMC_SERIAL_H
/src/quicc2_scc_serial.c
0,0 → 1,851
//==========================================================================
//
// io/serial/powerpc/quicc2_scc_serial.c
//
// PowerPC QUICC2 (SCC) Serial I/O Interface Module (interrupt driven)
//
//==========================================================================
//####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.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): mtek
// Contributors: gthomas
// Date: 1999-06-20
// Purpose: QUICC2 SCC Serial I/O module (interrupt driven version)
// Description:
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/system.h>
#include <pkgconf/io_serial.h>
#include <pkgconf/io.h>
#include <cyg/io/io.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/hal/var_intr.h>
#include <cyg/io/devtab.h>
#include <cyg/io/serial.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_cache.h>
#include <cyg/hal/mpc8260.h>
#include CYGBLD_HAL_PLATFORM_H
 
#include "quicc2_scc_serial.h"
#define QUICC2_VADS_IMM_BASE 0x04700000
#define QUICC2_VADS_BCSR_BASE 0x04500000
 
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
 
static bool
quicc2_scc_serial_init(struct cyg_devtab_entry *tab);
static bool
quicc2_scc_serial_putc(serial_channel *chan,
unsigned char c);
static Cyg_ErrNo
quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name);
static unsigned char
quicc2_scc_serial_getc(serial_channel *chan);
static Cyg_ErrNo
quicc2_scc_serial_set_config(serial_channel *chan,
cyg_uint32 key, const void *xbuf,
cyg_uint32 *len);
static void
quicc2_scc_serial_start_xmit(serial_channel *chan);
static void
quicc2_scc_serial_stop_xmit(serial_channel *chan);
 
static cyg_uint32
quicc2_scc_serial_ISR(cyg_vector_t vector,
cyg_addrword_t data);
static void
quicc2_scc_serial_DSR(cyg_vector_t vector,
cyg_ucount32 count,
cyg_addrword_t data);
 
static SERIAL_FUNS(quicc2_scc_serial_funs,
quicc2_scc_serial_putc,
quicc2_scc_serial_getc,
quicc2_scc_serial_set_config,
quicc2_scc_serial_start_xmit,
quicc2_scc_serial_stop_xmit
);
 
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
static quicc2_scc_serial_info quicc2_scc_serial_info1;
 
#if CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE > 0
static unsigned char quicc2_scc_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE];
static unsigned char quicc2_scc_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE];
 
static SERIAL_CHANNEL_USING_INTERRUPTS(quicc2_scc_serial_channel1,
quicc2_scc_serial_funs,
quicc2_scc_serial_info1,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT,
&quicc2_scc_serial_out_buf1[0], sizeof(quicc2_scc_serial_out_buf1),
&quicc2_scc_serial_in_buf1[0], sizeof(quicc2_scc_serial_in_buf1)
);
#else
static SERIAL_CHANNEL(quicc2_scc_serial_channel1,
quicc2_scc_serial_funs,
quicc2_scc_serial_info1,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT
);
#endif
 
static unsigned char quicc2_scc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM]
[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
static unsigned char quicc2_scc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM]
[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
 
DEVTAB_ENTRY(quicc2_scc_serial_io1,
CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_NAME,
0, // Does not depend on a lower level interface
&cyg_io_serial_devio,
quicc2_scc_serial_init,
quicc2_scc_serial_lookup, // Serial driver may need initializing
&quicc2_scc_serial_channel1
);
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
 
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
static quicc2_scc_serial_info quicc2_scc_serial_info2;
 
#if CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE > 0
static unsigned char quicc2_scc_serial_out_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE];
static unsigned char quicc2_scc_serial_in_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE];
 
static SERIAL_CHANNEL_USING_INTERRUPTS(quicc2_scc_serial_channel2,
quicc2_scc_serial_funs,
quicc2_scc_serial_info2,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT,
&quicc2_scc_serial_out_buf2[0], sizeof(quicc2_scc_serial_out_buf2),
&quicc2_scc_serial_in_buf2[0], sizeof(quicc2_scc_serial_in_buf2)
);
#else
static SERIAL_CHANNEL(quicc2_scc_serial_channel2,
quicc2_scc_serial_funs,
quicc2_scc_serial_info2,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT
);
#endif
static unsigned char quicc2_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM]
[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
static unsigned char quicc2_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM]
[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
 
DEVTAB_ENTRY(quicc2_scc_serial_io2,
CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_NAME,
0, // Does not depend on a lower level interface
&cyg_io_serial_devio,
quicc2_scc_serial_init,
quicc2_scc_serial_lookup, // Serial driver may need initializing
&quicc2_scc_serial_channel2
);
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
 
#ifdef CYGDBG_DIAG_BUF
extern int enable_diag_uart;
#endif // CYGDBG_DIAG_BUF
 
// Internal function to actually configure the hardware to
// desired baud rate, stop bits and parity ...
static bool
quicc2_scc_serial_config_port(serial_channel *chan,
cyg_serial_info_t *new_config,
bool init)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
 
unsigned long b_rate = select_baud[new_config->baud];
 
if (b_rate == 0) return false;
 
// Stop the transmitter while changing baud rate
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_STOP_TX | QUICC2_CPCR_READY;
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
 
// Disable Tx, RX and put them in a reset state
scc_chan->scc_regs->gsmr_l &= ~(QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
 
// Set the baud rate
*(scc_chan->brg) = (UART_BIT_RATE(b_rate) << 1) | QUICC2_BRG_EN;
 
// Set stop bits, word length and parity
scc_chan->scc_regs->psmr = QUICC2_SCC_PSMR_ASYNC |
select_stop_bits[new_config->stop] |
select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
select_parity[new_config->parity];
 
// Support fractional stop bits
scc_chan->scc_regs->dsr = (new_config->stop & 1) ? QUICC2_SCC_DSR_FULL : QUICC2_SCC_DSR_HALF;
// Initialize the parameters
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
 
// Enable Tx and Rx
scc_chan->scc_regs->gsmr_l |= (QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
 
if (new_config != &chan->config) {
chan->config = *new_config;
}
return true;
}
 
// Function to set up internal tables for device.
static void
quicc2_scc_serial_init_info(quicc2_scc_serial_info *scc_chan,
int SCC_index,
int BRG_index,
int TxBD, int TxNUM, int TxSIZE,
cyg_uint8 *TxBUF,
int RxBD, int RxNUM, int RxSIZE,
cyg_uint8 *RxBUF)
{
volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
#ifdef CYGPKG_HAL_POWERPC_VADS
volatile t_BCSR *bcsr = (volatile t_BCSR *) QUICC2_VADS_BCSR_BASE;
#endif
t_UartScc_Pram *uart_pram;
scc_bd *txbd, *rxbd;
int i;
// Disable the channel, just in case
IMM->scc_regs[SCC_index-1].gsmr_l &= ~(QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
switch (SCC_index) {
case 1:
// Put the data into the info structure
scc_chan->scc_cpcr = QUICC2_CPCR_SCC1;
scc_chan->scc_regs = &(IMM->scc_regs[0]);
scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[0]);
scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC1;
// Set-up the PORT D pins
IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC1_PORTD_PPAR;
IMM->io_regs[PORT_D].psor |= QUICC2_SCC1_PORTD_PDIR;
IMM->io_regs[PORT_D].ppar |= QUICC2_SCC1_PORTD_PPAR;
IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC1_PORTD_PPAR;
IMM->io_regs[PORT_D].pdir |= QUICC2_SCC1_PORTD_PDIR;
IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC1_PORTD_PPAR;
 
// Set-up the PORT C pins
IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC1_PORTC_PPAR;
IMM->io_regs[PORT_C].ppar |= QUICC2_SCC1_PORTC_PPAR;
IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC1_PORTC_PPAR;
IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC1_PORTC_PPAR;
 
// Select the baud rate generator and connect it
IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC1_CLR;
 
switch (BRG_index) {
case 1:
scc_chan->brg = &(IMM->brgs_brgc1);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG1;
break;
case 2:
scc_chan->brg = &(IMM->brgs_brgc2);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG2;
break;
case 3:
scc_chan->brg = &(IMM->brgs_brgc3);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG3;
break;
case 4:
scc_chan->brg = &(IMM->brgs_brgc4);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG4;
break;
}
#ifdef CYGPKG_HAL_POWERPC_VADS
// Enable the transciever
bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC1);
#endif
break;
 
case 2:
// Put the data into the info structure
scc_chan->scc_cpcr = QUICC2_CPCR_SCC2;
scc_chan->scc_regs = &(IMM->scc_regs[1]);
scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[1]);
scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC2;
 
// Set-up the PORT D pins
IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC2_PORTD_PPAR;
IMM->io_regs[PORT_D].ppar |= QUICC2_SCC2_PORTD_PPAR;
IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC2_PORTD_PPAR;
IMM->io_regs[PORT_D].pdir |= QUICC2_SCC2_PORTD_PDIR;
IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC2_PORTD_PPAR;
 
// Set-up the PORT C pins
IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC2_PORTC_PPAR;
IMM->io_regs[PORT_C].ppar |= QUICC2_SCC2_PORTC_PPAR;
IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC2_PORTC_PPAR;
IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC2_PORTC_PPAR;
 
// Select the baud rate generator and connect it
IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC2_CLR;
 
switch (BRG_index) {
case 1:
scc_chan->brg = &(IMM->brgs_brgc1);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG1;
break;
case 2:
scc_chan->brg = &(IMM->brgs_brgc2);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG2;
break;
case 3:
scc_chan->brg = &(IMM->brgs_brgc3);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG3;
break;
case 4:
scc_chan->brg = &(IMM->brgs_brgc4);
IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG4;
break;
}
#ifdef CYGPKG_HAL_POWERPC_VADS
// Enable the transciever
bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC2);
#endif
break;
 
default:
diag_printf("Incorrect SCC index in quicc2_scc_serial_init_info \n");
break;
}
 
// Initialize common SCC PRAM
scc_chan->tbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
scc_chan->rbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
scc_chan->txbd = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
scc_chan->rxbd = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
scc_chan->txsize = TxSIZE;
scc_chan->rxsize = RxSIZE;
 
scc_chan->scc_pram->rbase = RxBD;
scc_chan->scc_pram->tbase = TxBD;
scc_chan->scc_pram->rfcr = 0x10;
scc_chan->scc_pram->tfcr = 0x10;
scc_chan->scc_pram->mrblr = RxSIZE;
 
// Initialize UART PRAM
uart_pram = &(scc_chan->scc_pram->SpecificProtocol.u);
uart_pram->max_idl = 4;
uart_pram->brkcr = 1;
uart_pram->brkln = 0;
uart_pram->parec = 0;
uart_pram->frmec = 0;
uart_pram->nosec = 0;
uart_pram->brkec = 0;
uart_pram->uaddr1 = 0;
uart_pram->uaddr2 = 0;
uart_pram->toseq = 0;
uart_pram->cc[0] = 0x8000;
uart_pram->cc[1] = 0x8000;
uart_pram->cc[2] = 0x8000;
uart_pram->cc[3] = 0x8000;
uart_pram->cc[4] = 0x8000;
uart_pram->cc[5] = 0x8000;
uart_pram->cc[6] = 0x8000;
uart_pram->cc[7] = 0x8000;
uart_pram->rccm = 0xC0FF;
 
// Initialize registers
scc_chan->scc_regs->gsmr_l = QUICC2_SCC_GSMR_L_INIT;
scc_chan->scc_regs->gsmr_h = QUICC2_SCC_GSMR_H_INIT;
// scc_chan->scc_regs->psmr = 0x8000; // Set by config
scc_chan->scc_regs->todr = 0;
// scc_chan->scc_regs->dsr = 0x7e7e; // Set by config
scc_chan->scc_regs->scce = 0xffff;
scc_chan->scc_regs->sccm = (QUICC2_SCCE_BSY | QUICC2_SCCE_TX | QUICC2_SCCE_RX);
 
/* setup RX buffer descriptors */
rxbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + RxBD);
 
for (i = 0; i < RxNUM; i++) {
rxbd->ctrl = QUICC2_BD_CTL_Ready | QUICC2_BD_CTL_Int;
rxbd->length = 0;
rxbd->buffer = RxBUF;
 
RxBUF += RxSIZE;
rxbd++;
}
 
rxbd--;
rxbd->ctrl |= QUICC2_BD_CTL_Wrap; // Last buffer
 
/* setup TX buffer descriptors */
txbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + TxBD);
 
for (i = 0; i < TxNUM; i++) {
txbd->ctrl = 0;
txbd->length = 0;
txbd->buffer = TxBUF;
TxBUF += TxSIZE;
txbd++;
}
 
txbd--;
txbd->ctrl |= QUICC2_BD_CTL_Wrap; // Last buffer
// Issue Init RX & TX Parameters Command
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
 
return;
 
}
 
// Function to initialize the device. Called at bootstrap time.
static bool
quicc2_scc_serial_init(struct cyg_devtab_entry *tab)
{
serial_channel *chan = (serial_channel *)tab->priv;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_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("QUICC2_SCC SERIAL init - dev: %x\n",
scc_chan->channel);
#endif
if (first_init) {
// Set up tables since many fields are dynamic [computed at runtime]
first_init = 0;
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
 
// Totally reset the CP
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
 
TxBD = 0x2800; // Note: this should be configurable
RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM*8;
quicc2_scc_serial_init_info(&quicc2_scc_serial_info1,
1, // indicates SCC1
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BRG,
TxBD,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE,
ALIGN_TO_CACHELINES(&quicc2_scc1_txbuf[0][0]),
RxBD,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE,
ALIGN_TO_CACHELINES(&quicc2_scc1_rxbuf[0][0])
);
#else
#ifdef CYGPKG_HAL_POWERPC_MPC8260
// Ensure that SCC1 side is initialized first
diag_init(); // (pull in constructor that inits diag channel)
TxBD = 0x2900; // Note : this should be inferred from the
// chip state
#else
// there is no diag device wanting to use the QUICC, so prepare it
// for SCC2 use only.
while (IMM->cpm_cpcr & QUICC2_CPCR_READY); // Totally reset the CP
IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
TxBD = 0x2800; // Note: this should be configurable
#endif
#endif
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
 
RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM*8;
quicc2_scc_serial_init_info(&quicc2_scc_serial_info2,
2, // indicates SCC2
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BRG,
TxBD,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE,
ALIGN_TO_CACHELINES(&quicc2_scc2_txbuf[0][0]),
RxBD,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM,
CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE,
ALIGN_TO_CACHELINES(&quicc2_scc2_rxbuf[0][0])
);
#endif
}
 
// Really only required for interrupt driven devices
(chan->callbacks->serial_init)(chan);
if (chan->out_cbuf.len != 0) {
cyg_drv_interrupt_create(scc_chan->int_vector,
0, // CYGARC_SIU_PRIORITY_HIGH, - unused
(cyg_addrword_t)chan, // Data item passed to interrupt handler
quicc2_scc_serial_ISR,
quicc2_scc_serial_DSR,
&scc_chan->serial_interrupt_handle,
&scc_chan->serial_interrupt);
cyg_drv_interrupt_attach(scc_chan->serial_interrupt_handle);
cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
cyg_drv_interrupt_unmask(scc_chan->int_vector);
}
quicc2_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
quicc2_scc_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
quicc2_scc_serial_flush(quicc2_scc_serial_info *scc_chan)
{
volatile struct scc_bd *txbd = scc_chan->txbd;
int cache_state;
HAL_DCACHE_IS_ENABLED(cache_state);
if (cache_state) {
HAL_DCACHE_FLUSH(txbd->buffer, scc_chan->txsize);
}
 
if ((txbd->length > 0) &&
((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0)) {
txbd->ctrl |= QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int; // Signal buffer ready
if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
txbd = scc_chan->tbase;
} else {
txbd++;
}
scc_chan->txbd = (scc_bd *) txbd;
}
}
 
// Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
quicc2_scc_serial_putc(serial_channel *chan, unsigned char c)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile struct scc_bd *txbd, *txfirst;
bool res;
 
cyg_drv_dsr_lock(); // Avoid race condition testing pointers
 
txbd = (scc_bd *)(QUICC2_VADS_IMM_BASE + ((int) scc_chan->scc_pram->tbptr));
txfirst = txbd;
 
// Scan for a non-busy buffer
while (txbd->ctrl & QUICC2_BD_CTL_Ready) {
// This buffer is busy, move to next one
if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
txbd = scc_chan->tbase;
} else {
txbd++;
}
if (txbd == txfirst) break; // Went all the way around
}
scc_chan->txbd = (scc_bd *) txbd;
if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0) {
// Transmit buffer is not full/busy
txbd->buffer[txbd->length++] = c;
if (txbd->length == scc_chan->txsize) {
// This buffer is now full, tell SCC to start processing it
quicc2_scc_serial_flush(scc_chan);
}
res = true;
} else {
// No space
res = false;
}
 
cyg_drv_dsr_unlock();
return res;
}
 
// Fetch a character from the device input buffer, waiting if necessary
static unsigned char
quicc2_scc_serial_getc(serial_channel *chan)
{
unsigned char c;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile scc_bd *rxbd = scc_chan->rxbd;
 
while ((rxbd->ctrl & QUICC2_BD_CTL_Ready) != 0) ; // WAIT ...
 
c = rxbd->buffer[0];
rxbd->length = scc_chan->rxsize;
rxbd->ctrl |= QUICC2_BD_CTL_Ready;
if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
rxbd = scc_chan->rbase;
} else {
rxbd++;
}
scc_chan->rxbd = (scc_bd *) rxbd;
return c;
}
 
// Set up the device characteristics; baud rate, etc.
static Cyg_ErrNo
quicc2_scc_serial_set_config(serial_channel *chan, cyg_uint32 key,
const void *xbuf, cyg_uint32 *len)
{
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.
cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
if ( *len < sizeof(cyg_serial_info_t) ) {
return -EINVAL;
}
*len = sizeof(cyg_serial_info_t);
if ( true != quicc2_scc_serial_config_port(chan, config, false) )
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return ENOERR;
}
 
// Enable the transmitter (interrupt) on the device
static void
quicc2_scc_serial_start_xmit(serial_channel *chan)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
 
cyg_drv_dsr_lock();
 
if (scc_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 (scc_chan->txbd->length != 0) {
// Make sure it gets started
quicc2_scc_serial_flush(scc_chan);
}
 
cyg_drv_dsr_unlock();
}
 
// Disable the transmitter on the device
static void
quicc2_scc_serial_stop_xmit(serial_channel *chan)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
// If anything is in the last buffer, need to get it started
if (scc_chan->txbd->length != 0) {
quicc2_scc_serial_flush(scc_chan);
}
}
 
// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32
quicc2_scc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
cyg_drv_interrupt_mask(scc_chan->int_vector);
return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Cause DSR to be run
}
 
// Serial I/O - high level interrupt handler (DSR)
static void
quicc2_scc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile struct scc_regs_8260 *regs = scc_chan->scc_regs;
volatile scc_bd *txbd;
volatile scc_bd *rxbd = scc_chan->rxbd;
scc_bd *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",
regs->scce, _stime, _time);
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
 
if (regs->scce & QUICC2_SCCE_TX) { // Tx Event
 
#ifdef XX_CYGDBG_DIAG_BUF
enable_diag_uart = 0;
txbd = scc_chan->tbase;
for (i = 0; i < CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_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
 
regs->scce = QUICC2_SCCE_TX; // Reset Tx Event
txbd = scc_chan->tbase; // First buffer
while (true) {
if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == QUICC2_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 &= ~QUICC2_BD_CTL_Int; // Reset interrupt bit
}
 
if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
txbd = scc_chan->tbase;
break;
} else {
txbd++;
}
}
(chan->callbacks->xmt_char)(chan);
}
 
while (regs->scce & QUICC2_SCCE_RX) { // Rx Event
 
regs->scce = QUICC2_SCCE_RX; // Reset interrupt state;
rxlast = (scc_bd *) ((char *)QUICC2_VADS_IMM_BASE + scc_chan->scc_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
while (rxbd != rxlast) {
if ((rxbd->ctrl & QUICC2_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);
if (cache_state) {
HAL_DCACHE_INVALIDATE(rxbd->buffer, scc_chan->rxsize); // Make sure no stale data
}
rxbd->length = 0;
rxbd->ctrl |= QUICC2_BD_CTL_Ready;
}
if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
rxbd = scc_chan->rbase;
} else {
rxbd++;
}
}
#ifdef CYGDBG_DIAG_BUF
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
scc_chan->rxbd = (scc_bd *) rxbd;
}
 
if (regs->scce & QUICC2_SCCE_BSY) {
#ifdef CYGDBG_DIAG_BUF
enable_diag_uart = 0;
diag_printf("RX BUSY interrupt\n");
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
regs->scce = QUICC2_SCCE_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",
regs->scce, _stime, _time);
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
cyg_drv_interrupt_unmask(scc_chan->int_vector);
#ifdef CYGDBG_DIAG_BUF
cyg_drv_isr_unlock();
#endif // CYGDBG_DIAG_BUF
}
 
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
 
// ------------------------------------------------------------------------
// EOF powerpc/quicc2_scc_serial.c
/ChangeLog
0,0 → 1,52
2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
 
* cdl/ser_quicc2_scc.cdl: Remove irrelevant doc link.
 
2003-01-24 Gary Thomas <gary@mlbassoc.com> (inspired by)
2003-01-24 Christoph Csebits <christoph.csebits@frequentis.com>
 
* src/quicc2_scc_serial.h: Remove invalid ";" from #defines
 
2002-12-12 Gary Thomas <gthomas@ecoscentric.com>
2002-12-12 Patrick Doyle <wpd@delcomsys.com>
 
* src/quicc2_scc_serial.h:
* src/quicc2_scc_serial.c:
* cdl/ser_quicc2_scc.cdl: New package - serial I/O suport on
PowerPC/QUICC2 based systems (like MPC8260).
 
//===========================================================================
//####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.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//===========================================================================

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.