@@ -1,506 +0,0 @@
/*
* (C) Copyright 2002
* Daniel Engstr<74> m, Omicron Ceti AB, daniel@omicron.se
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program 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 of
* the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*------------------------------------------------------------------------------+ */
/*
* This source code is dual-licensed. You may use it under the terms of the
* GNU General Public License version 2, or under the license below.
*
* This source code has been made available to you by IBM on an AS-IS
* basis. Anyone receiving this source is licensed under IBM
* copyrights to use it in any way he or she deems fit, including
* copying it, modifying it, compiling it, and redistributing it either
* with or without modifications. No license under IBM patents or
* patent applications is to be implied by the copyright license.
*
* Any user of this software should understand that IBM cannot provide
* technical support for this software and will not be responsible for
* any consequences resulting from the use of this software.
*
* Any person who transfers this source code or any derivative work
* must include the IBM copyright notice, this paragraph, and the
* preceding two paragraphs in the transferred software.
*
* COPYRIGHT I B M CORPORATION 1995
* LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
*/
/*------------------------------------------------------------------------------- */
# include <common.h>
# include <watchdog.h>
# include <asm/io.h>
# include <asm/ibmpc.h>
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
# include <malloc.h>
# endif
DECLARE_GLOBAL_DATA_PTR ;
# define UART_RBR 0x00
# define UART_THR 0x00
# define UART_IER 0x01
# define UART_IIR 0x02
# define UART_FCR 0x02
# define UART_LCR 0x03
# define UART_MCR 0x04
# define UART_LSR 0x05
# define UART_MSR 0x06
# define UART_SCR 0x07
# define UART_DLL 0x00
# define UART_DLM 0x01
/*-----------------------------------------------------------------------------+
| Line Status Register.
+-----------------------------------------------------------------------------*/
# define asyncLSRDataReady1 0x01
# define asyncLSROverrunError1 0x02
# define asyncLSRParityError1 0x04
# define asyncLSRFramingError1 0x08
# define asyncLSRBreakInterrupt1 0x10
# define asyncLSRTxHoldEmpty1 0x20
# define asyncLSRTxShiftEmpty1 0x40
# define asyncLSRRxFifoError1 0x80
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
/*-----------------------------------------------------------------------------+
| Fifo
+-----------------------------------------------------------------------------*/
typedef struct {
char * rx_buffer ;
ulong rx_put ;
ulong rx_get ;
int cts ;
} serial_buffer_t ;
volatile serial_buffer_t buf_info ;
static int serial_buffer_active = 0 ;
# endif
static int serial_div ( int baudrate )
{
switch ( baudrate ) {
case 1200 :
return 96 ;
case 9600 :
return 12 ;
case 19200 :
return 6 ;
case 38400 :
return 3 ;
case 57600 :
return 2 ;
case 115200 :
return 1 ;
}
return 12 ;
}
/*
* Minimal serial functions needed to use one of the SMC ports
* as serial console interface.
*/
int serial_init ( void )
{
volatile char val ;
int bdiv = serial_div ( gd - > baudrate ) ;
outb ( 0x80 , UART0_BASE + UART_LCR ) ; /* set DLAB bit */
outb ( bdiv , UART0_BASE + UART_DLL ) ; /* set baudrate divisor */
outb ( bdiv > > 8 , UART0_BASE + UART_DLM ) ; /* set baudrate divisor */
outb ( 0x03 , UART0_BASE + UART_LCR ) ; /* clear DLAB; set 8 bits, no parity */
outb ( 0x01 , UART0_BASE + UART_FCR ) ; /* enable FIFO */
outb ( 0x0b , UART0_BASE + UART_MCR ) ; /* Set DTR and RTS active */
val = inb ( UART0_BASE + UART_LSR ) ; /* clear line status */
val = inb ( UART0_BASE + UART_RBR ) ; /* read receive buffer */
outb ( 0x00 , UART0_BASE + UART_SCR ) ; /* set scratchpad */
outb ( 0x00 , UART0_BASE + UART_IER ) ; /* set interrupt enable reg */
return 0 ;
}
void serial_setbrg ( void )
{
unsigned short bdiv ;
bdiv = serial_div ( gd - > baudrate ) ;
outb ( 0x80 , UART0_BASE + UART_LCR ) ; /* set DLAB bit */
outb ( bdiv & 0xff , UART0_BASE + UART_DLL ) ; /* set baudrate divisor */
outb ( bdiv > > 8 , UART0_BASE + UART_DLM ) ; /* set baudrate divisor */
outb ( 0x03 , UART0_BASE + UART_LCR ) ; /* clear DLAB; set 8 bits, no parity */
}
void serial_putc ( const char c )
{
int i ;
if ( c = = ' \n ' )
serial_putc ( ' \r ' ) ;
/* check THRE bit, wait for transmiter available */
for ( i = 1 ; i < 3500 ; i + + ) {
if ( ( inb ( UART0_BASE + UART_LSR ) & 0x20 ) = = 0x20 ) {
break ;
}
udelay ( 100 ) ;
}
outb ( c , UART0_BASE + UART_THR ) ; /* put character out */
}
void serial_puts ( const char * s )
{
while ( * s ) {
serial_putc ( * s + + ) ;
}
}
int serial_getc ( void )
{
unsigned char status = 0 ;
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
if ( serial_buffer_active ) {
return serial_buffered_getc ( ) ;
}
# endif
while ( 1 ) {
# if defined(CONFIG_HW_WATCHDOG)
WATCHDOG_RESET ( ) ; /* Reset HW Watchdog, if needed */
# endif /* CONFIG_HW_WATCHDOG */
status = inb ( UART0_BASE + UART_LSR ) ;
if ( ( status & asyncLSRDataReady1 ) ! = 0x0 ) {
break ;
}
if ( ( status & ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ) ! = 0 ) {
outb ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 , UART0_BASE + UART_LSR ) ;
}
}
return ( 0x000000ff & ( int ) inb ( UART0_BASE ) ) ;
}
int serial_tstc ( void )
{
unsigned char status ;
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
if ( serial_buffer_active ) {
return serial_buffered_tstc ( ) ;
}
# endif
status = inb ( UART0_BASE + UART_LSR ) ;
if ( ( status & asyncLSRDataReady1 ) ! = 0x0 ) {
return ( 1 ) ;
}
if ( ( status & ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ) ! = 0 ) {
outb ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 , UART0_BASE + UART_LSR ) ;
}
return 0 ;
}
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
void serial_isr ( void * arg )
{
int space ;
int c ;
int rx_put = buf_info . rx_put ;
if ( buf_info . rx_get < = rx_put ) {
space = CONFIG_SERIAL_SOFTWARE_FIFO - ( rx_put - buf_info . rx_get ) ;
} else {
space = buf_info . rx_get - rx_put ;
}
while ( inb ( UART0_BASE + UART_LSR ) & 1 ) {
c = inb ( UART0_BASE ) ;
if ( space ) {
buf_info . rx_buffer [ rx_put + + ] = c ;
space - - ;
if ( rx_put = = buf_info . rx_get ) {
buf_info . rx_get + + ;
if ( rx_put = = CONFIG_SERIAL_SOFTWARE_FIFO ) {
buf_info . rx_get = 0 ;
}
}
if ( rx_put = = CONFIG_SERIAL_SOFTWARE_FIFO ) {
rx_put = 0 ;
if ( 0 = = buf_info . rx_get ) {
buf_info . rx_get = 1 ;
}
}
}
if ( space < CONFIG_SERIAL_SOFTWARE_FIFO / 4 ) {
/* Stop flow by setting RTS inactive */
outb ( inb ( UART0_BASE + UART_MCR ) & ( 0xFF ^ 0x02 ) ,
UART0_BASE + UART_MCR ) ;
}
}
buf_info . rx_put = rx_put ;
}
void serial_buffered_init ( void )
{
serial_puts ( " Switching to interrupt driven serial input mode. \n " ) ;
buf_info . rx_buffer = malloc ( CONFIG_SERIAL_SOFTWARE_FIFO ) ;
buf_info . rx_put = 0 ;
buf_info . rx_get = 0 ;
if ( inb ( UART0_BASE + UART_MSR ) & 0x10 ) {
serial_puts ( " Check CTS signal present on serial port: OK. \n " ) ;
buf_info . cts = 1 ;
} else {
serial_puts ( " WARNING: CTS signal not present on serial port. \n " ) ;
buf_info . cts = 0 ;
}
irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ ,
serial_isr /*interrupt_handler_t *handler */ ,
( void * ) & buf_info /*void *arg */ ) ;
/* Enable "RX Data Available" Interrupt on UART */
/* outb(inb(UART0_BASE + UART_IER) |0x01, UART0_BASE + UART_IER); */
outb ( 0x01 , UART0_BASE + UART_IER ) ;
/* Set DTR and RTS active, enable interrupts */
outb ( inb ( UART0_BASE + UART_MCR ) | 0x0b , UART0_BASE + UART_MCR ) ;
/* Setup UART FIFO: RX trigger level: 1 byte, Enable FIFO */
outb ( /*(1 << 6) |*/ 1 , UART0_BASE + UART_FCR ) ;
serial_buffer_active = 1 ;
}
void serial_buffered_putc ( const char c )
{
int i ;
/* Wait for CTS */
# if defined(CONFIG_HW_WATCHDOG)
while ( ! ( inb ( UART0_BASE + UART_MSR ) & 0x10 ) )
WATCHDOG_RESET ( ) ;
# else
if ( buf_info . cts ) {
for ( i = 0 ; i < 1000 ; i + + ) {
if ( ( inb ( UART0_BASE + UART_MSR ) & 0x10 ) ) {
break ;
}
}
if ( i ! = 1000 ) {
buf_info . cts = 0 ;
}
} else {
if ( ( inb ( UART0_BASE + UART_MSR ) & 0x10 ) ) {
buf_info . cts = 1 ;
}
}
# endif
serial_putc ( c ) ;
}
void serial_buffered_puts ( const char * s )
{
serial_puts ( s ) ;
}
int serial_buffered_getc ( void )
{
int space ;
int c ;
int rx_get = buf_info . rx_get ;
int rx_put ;
# if defined(CONFIG_HW_WATCHDOG)
while ( rx_get = = buf_info . rx_put )
WATCHDOG_RESET ( ) ;
# else
while ( rx_get = = buf_info . rx_put ) ;
# endif
c = buf_info . rx_buffer [ rx_get + + ] ;
if ( rx_get = = CONFIG_SERIAL_SOFTWARE_FIFO ) {
rx_get = 0 ;
}
buf_info . rx_get = rx_get ;
rx_put = buf_info . rx_put ;
if ( rx_get < = rx_put ) {
space = CONFIG_SERIAL_SOFTWARE_FIFO - ( rx_put - rx_get ) ;
} else {
space = rx_get - rx_put ;
}
if ( space > CONFIG_SERIAL_SOFTWARE_FIFO / 2 ) {
/* Start flow by setting RTS active */
outb ( inb ( UART0_BASE + UART_MCR ) | 0x02 , UART0_BASE + UART_MCR ) ;
}
return c ;
}
int serial_buffered_tstc ( void )
{
return ( buf_info . rx_get ! = buf_info . rx_put ) ? 1 : 0 ;
}
# endif /* CONFIG_SERIAL_SOFTWARE_FIFO */
# if defined(CONFIG_CMD_KGDB)
/*
AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
number 0 or number 1
- if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
configuration has been already done
- if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
*/
# if (CONFIG_KGDB_SER_INDEX & 2)
void kgdb_serial_init ( void )
{
volatile char val ;
bdiv = serial_div ( CONFIG_KGDB_BAUDRATE ) ;
/*
* Init onboard 16550 UART
*/
outb ( 0x80 , UART1_BASE + UART_LCR ) ; /* set DLAB bit */
outb ( ( bdiv & 0xff ) , UART1_BASE + UART_DLL ) ; /* set divisor for 9600 baud */
outb ( ( bdiv > > 8 ) , UART1_BASE + UART_DLM ) ; /* set divisor for 9600 baud */
outb ( 0x03 , UART1_BASE + UART_LCR ) ; /* line control 8 bits no parity */
outb ( 0x00 , UART1_BASE + UART_FCR ) ; /* disable FIFO */
outb ( 0x00 , UART1_BASE + UART_MCR ) ; /* no modem control DTR RTS */
val = inb ( UART1_BASE + UART_LSR ) ; /* clear line status */
val = inb ( UART1_BASE + UART_RBR ) ; /* read receive buffer */
outb ( 0x00 , UART1_BASE + UART_SCR ) ; /* set scratchpad */
outb ( 0x00 , UART1_BASE + UART_IER ) ; /* set interrupt enable reg */
}
void putDebugChar ( const char c )
{
if ( c = = ' \n ' )
serial_putc ( ' \r ' ) ;
outb ( c , UART1_BASE + UART_THR ) ; /* put character out */
/* check THRE bit, wait for transfer done */
while ( ( inb ( UART1_BASE + UART_LSR ) & 0x20 ) ! = 0x20 ) ;
}
void putDebugStr ( const char * s )
{
while ( * s ) {
serial_putc ( * s + + ) ;
}
}
int getDebugChar ( void )
{
unsigned char status = 0 ;
while ( 1 ) {
status = inb ( UART1_BASE + UART_LSR ) ;
if ( ( status & asyncLSRDataReady1 ) ! = 0x0 ) {
break ;
}
if ( ( status & ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ) ! = 0 ) {
outb ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 , UART1_BASE + UART_LSR ) ;
}
}
return ( 0x000000ff & ( int ) inb ( UART1_BASE ) ) ;
}
void kgdb_interruptible ( int yes )
{
return ;
}
# else /* ! (CONFIG_KGDB_SER_INDEX & 2) */
void kgdb_serial_init ( void )
{
serial_printf ( " [on serial] " ) ;
}
void putDebugChar ( int c )
{
serial_putc ( c ) ;
}
void putDebugStr ( const char * str )
{
serial_puts ( str ) ;
}
int getDebugChar ( void )
{
return serial_getc ( ) ;
}
void kgdb_interruptible ( int yes )
{
return ;
}
# endif /* (CONFIG_KGDB_SER_INDEX & 2) */
# endif