@ -2,6 +2,9 @@
* ( C ) Copyright 2000 - 2006
* Wolfgang Denk , DENX Software Engineering , wd @ denx . de .
*
* ( C ) Copyright 2010
* Stefan Roese , DENX Software Engineering , sr @ denx . de .
*
* See file CREDITS for list of people who contributed to this
* project .
*
@ -51,14 +54,6 @@
# include <watchdog.h>
# include <asm/ppc4xx.h>
# ifdef CONFIG_SERIAL_MULTI
# include <serial.h>
# endif
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
# include <malloc.h>
# endif
DECLARE_GLOBAL_DATA_PTR ;
# if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
@ -66,24 +61,6 @@ DECLARE_GLOBAL_DATA_PTR;
defined ( CONFIG_405EX ) | | defined ( CONFIG_440 )
# if defined(CONFIG_440)
# if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
defined ( CONFIG_440EPX ) | | defined ( CONFIG_440GRX ) | | \
defined ( CONFIG_460EX ) | | defined ( CONFIG_460GT )
# define UART0_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000300)
# define UART1_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000400)
# else
# define UART0_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000200)
# define UART1_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000300)
# endif
# if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
# define UART2_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000600)
# endif
# if defined(CONFIG_460EX) || defined(CONFIG_460GT)
# define UART2_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000500)
# define UART3_BASE (CONFIG_SYS_PERIPHERAL_BASE + 0x00000600)
# endif
# if defined(CONFIG_440GP)
# define CR0_MASK 0x3fff0000
@ -116,16 +93,14 @@ DECLARE_GLOBAL_DATA_PTR;
# define MTREG(a, d) mtsdr(a, d)
# endif /* #if defined(CONFIG_440GP) */
# elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
# define UART0_BASE 0xef600300
# define UART1_BASE 0xef600400
# define UCR0_MASK 0x0000007f
# define UCR1_MASK 0x00007f00
# define UCR0_UDIV_POS 0
# define UCR1_UDIV_POS 8
# define UDIV_MAX 127
# elif defined(CONFIG_405EX)
# define UART0_BASE 0xef600200
# define UART1_BASE 0xef600300
# define MFREG(a, d) mfsdr(a, d)
# define MTREG(a, d) mtsdr(a, d)
# define CR0_MASK 0x000000ff
# define CR0_EXTCLK_ENA 0x00800000
# define CR0_UDIV_POS 0
@ -133,748 +108,198 @@ DECLARE_GLOBAL_DATA_PTR;
# define UART0_SDR SDR0_UART0
# define UART1_SDR SDR0_UART1
# else /* CONFIG_405GP || CONFIG_405CR */
# define UART0_BASE 0xef600300
# define UART1_BASE 0xef600400
# define CR0_MASK 0x00001fff
# define CR0_EXTCLK_ENA 0x000000c0
# define CR0_UDIV_POS 1
# define UDIV_MAX 32
# endif
/* using serial port 0 or 1 as U-Boot console ? */
# if defined(CONFIG_UART1_CONSOLE)
# define ACTING_UART0_BASE UART1_BASE
# define ACTING_UART1_BASE UART0_BASE
# else
# define ACTING_UART0_BASE UART0_BASE
# define ACTING_UART1_BASE UART1_BASE
# endif
# if defined(CONFIG_405EP) && defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
# error "External serial clock not supported on AMCC PPC405EP!"
# endif
# 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 ;
} serial_buffer_t ;
volatile static serial_buffer_t buf_info ;
# endif
static void serial_init_common ( u32 base , u32 udiv , u16 bdiv )
{
PPC4xx_SYS_INFO sys_info ;
u8 val ;
get_sys_info ( & sys_info ) ;
/* Correct UART frequency in bd-info struct now that
* the UART divisor is available
*/
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
gd - > uart_clk = CONFIG_SYS_EXT_SERIAL_CLOCK ;
# else
gd - > uart_clk = sys_info . freqUART / udiv ;
# endif
out_8 ( ( u8 * ) base + UART_LCR , 0x80 ) ; /* set DLAB bit */
out_8 ( ( u8 * ) base + UART_DLL , bdiv ) ; /* set baudrate divisor */
out_8 ( ( u8 * ) base + UART_DLM , bdiv > > 8 ) ; /* set baudrate divisor */
out_8 ( ( u8 * ) base + UART_LCR , 0x03 ) ; /* clear DLAB; set 8 bits, no parity */
out_8 ( ( u8 * ) base + UART_FCR , 0x00 ) ; /* disable FIFO */
out_8 ( ( u8 * ) base + UART_MCR , 0x00 ) ; /* no modem control DTR RTS */
val = in_8 ( ( u8 * ) base + UART_LSR ) ; /* clear line status */
val = in_8 ( ( u8 * ) base + UART_RBR ) ; /* read receive buffer */
out_8 ( ( u8 * ) base + UART_SCR , 0x00 ) ; /* set scratchpad */
out_8 ( ( u8 * ) base + UART_IER , 0x00 ) ; /* set interrupt enable reg */
}
# if (defined(CONFIG_440) || defined(CONFIG_405EX)) && \
! defined ( CONFIG_SYS_EXT_SERIAL_CLOCK )
static void serial_divs ( int baudrate , unsigned long * pudiv ,
unsigned short * pbdiv )
# if (defined(CONFIG_405EX) || defined(CONFIG_405EZ) || \
defined ( CONFIG_440 ) ) & & ! defined ( CONFIG_SYS_EXT_SERIAL_CLOCK )
/*
* For some SoC ' s , the cpu clock is on divider chain A , UART on
* divider chain B . . . so cpu clock is irrelevant . Get the
* " optimized " values that are subject to the 1 / 2 opb clock
* constraint .
*/
static u16 serial_bdiv ( int baudrate , u32 * udiv )
{
sys_info_t sysinfo ;
unsigned long div ; /* total divisor udiv * bdiv */
unsigned long umin ; /* minimum udiv */
unsigned short diff ; /* smallest diff */
unsigned long udiv ; /* best udiv */
unsigned short idiff ; /* current diff */
unsigned short ibdiv ; /* current bdiv */
unsigned long i ;
unsigned long est ; /* current estimate */
u32 div ; /* total divisor udiv * bdiv */
u32 umin ; /* minimum udiv */
u16 diff ; /* smallest diff */
u16 idiff ; /* current diff */
u16 ibdiv ; /* current bdiv */
u32 i ;
u32 est ; /* current estimate */
u32 max ;
# if defined(CONFIG_405EZ)
u32 cpr_pllc ;
u32 plloutb ;
u32 reg ;
# endif
get_sys_info ( & sysinfo ) ;
udiv = 32 ; /* Assume lowest possible serial clk */
div = sysinfo . freqPLB / ( 16 * baudrate ) ; /* total divisor */
umin = sysinfo . pllOpbDiv < < 1 ; /* 2 x OPB divisor */
diff = 32 ; /* highest possible */
/* i is the test udiv value -- start with the largest
* possible ( 32 ) to minimize serial clock and constrain
* search to umin .
*/
for ( i = 32 ; i > umin ; i - - ) {
ibdiv = div / i ;
est = i * ibdiv ;
idiff = ( est > div ) ? ( est - div ) : ( div - est ) ;
if ( idiff = = 0 ) {
udiv = i ;
break ; /* can't do better */
} else if ( idiff < diff ) {
udiv = i ; /* best so far */
diff = idiff ; /* update lowest diff*/
}
}
* pudiv = udiv ;
* pbdiv = div / udiv ;
}
# elif defined(CONFIG_405EZ)
static void serial_divs ( int baudrate , unsigned long * pudiv ,
unsigned short * pbdiv )
{
sys_info_t sysinfo ;
unsigned long div ; /* total divisor udiv * bdiv */
unsigned long umin ; /* minimum udiv */
unsigned short diff ; /* smallest diff */
unsigned long udiv ; /* best udiv */
unsigned short idiff ; /* current diff */
unsigned short ibdiv ; /* current bdiv */
unsigned long i ;
unsigned long est ; /* current estimate */
unsigned long plloutb ;
unsigned long cpr_pllc ;
u32 reg ;
# if defined(CONFIG_405EZ)
/* check the pll feedback source */
mfcpr ( CPR0_PLLC , cpr_pllc ) ;
get_sys_info ( & sysinfo ) ;
plloutb = ( ( CONFIG_SYS_CLK_FREQ * ( ( cpr_pllc & PLLC_SRC_MASK ) ?
sysinfo . pllFwdDivB : sysinfo . pllFwdDiv ) *
sysinfo . pllFbkDiv ) / sysinfo . pllFwdDivB ) ;
udiv = 256 ; /* Assume lowest possible serial clk */
div = plloutb / ( 16 * baudrate ) ; /* total divisor */
umin = ( plloutb / get_OPB_freq ( ) ) < < 1 ; /* 2 x OPB divisor */
diff = 256 ; /* highest possible */
max = 256 ; /* highest possible */
# else /* 405EZ */
div = sysinfo . freqPLB / ( 16 * baudrate ) ; /* total divisor */
umin = sysinfo . pllOpbDiv < < 1 ; /* 2 x OPB divisor */
max = 32 ; /* highest possible */
# endif /* 405EZ */
* udiv = diff = max ;
/* i is the test udiv value -- start with the largest
* possible ( 256 ) to minimize serial clock and constrain
/*
* i is the test udiv value - - start with the largest
* possible ( max ) to minimize serial clock and constrain
* search to umin .
*/
for ( i = 256 ; i > umin ; i - - ) {
for ( i = max ; i > umin ; i - - ) {
ibdiv = div / i ;
est = i * ibdiv ;
idiff = ( est > div ) ? ( est - div ) : ( div - est ) ;
idiff = ( est > div ) ? ( est - div ) : ( div - est ) ;
if ( idiff = = 0 ) {
udiv = i ;
break ; /* can't do better */
* udiv = i ;
break ; /* can't do better */
} else if ( idiff < diff ) {
udiv = i ; /* best so far */
diff = idiff ; /* update lowest diff*/
* udiv = i ; /* best so far */
diff = idiff ; /* update lowest diff*/
}
}
* pudiv = udiv ;
# if defined(CONFIG_405EZ)
mfcpr ( CPR0_PERD0 , reg ) ;
reg & = ~ 0x0000ffff ;
reg | = ( ( udiv - 0 ) < < 8 ) | ( udiv - 0 ) ;
reg | = ( ( * udiv - 0 ) < < 8 ) | ( * udiv - 0 ) ;
mtcpr ( CPR0_PERD0 , reg ) ;
* pbdiv = div / udiv ;
# endif
return div / * udiv ;
}
# endif /* defined(CONFIG_440) && !defined(CONFIG_SYS_EXT_SERIAL_CLK) */
# endif /* #if (defined(CONFIG_405EP) ... */
/*
* Minimal serial functions needed to use one of the SMC ports
* as serial console interface .
* This function returns the UART clock used by the common
* NS16550 driver . Additionally the SoC internal divisors for
* optimal UART baudrate are configured .
*/
# if defined(CONFIG_440)
int serial_init_dev ( unsigned long base )
int get_serial_clock ( void )
{
unsigned long reg ;
unsigned long udiv ;
unsigned short bdiv ;
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
unsigned long tmp ;
# endif
MFREG ( UART0_SDR , reg ) ;
reg & = ~ CR0_MASK ;
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
reg | = CR0_EXTCLK_ENA ;
udiv = 1 ;
tmp = gd - > baudrate * 16 ;
bdiv = ( CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2 ) / tmp ;
# else
/* For 440, the cpu clock is on divider chain A, UART on divider
* chain B . . . so cpu clock is irrelevant . Get the " optimized "
* values that are subject to the 1 / 2 opb clock constraint
*/
serial_divs ( gd - > baudrate , & udiv , & bdiv ) ;
u32 clk ;
u32 udiv ;
# if defined(CONFIG_405CR) || defined(CONFIG_405EP) || defined(CONFIG_405GP)
u32 tmp ;
# endif
reg | = ( udiv - UDIV_SUBTRACT ) < < CR0_UDIV_POS ; /* set the UART divisor */
/*
* Configure input clock to baudrate generator for all
* available serial ports here
*/
MTREG ( UART0_SDR , reg ) ;
# if defined(UART1_SDR)
MTREG ( UART1_SDR , reg ) ;
# endif
# if defined(UART2_SDR)
MTREG ( UART2_SDR , reg ) ;
# endif
# if defined(UART3_SDR)
MTREG ( UART3_SDR , reg ) ;
# if !defined(CONFIG_405EZ)
u32 reg ;
# endif
serial_init_common ( base , udiv , bdiv ) ;
return ( 0 ) ;
}
# else /* !defined(CONFIG_440) */
int serial_init_dev ( unsigned long base )
{
unsigned long reg ;
unsigned long tmp ;
unsigned long clk ;
unsigned long udiv ;
unsigned short bdiv ;
# ifdef CONFIG_405EX
clk = tmp = 0 ;
mfsdr ( UART0_SDR , reg ) ;
reg & = ~ CR0_MASK ;
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
reg | = CR0_EXTCLK_ENA ;
udiv = 1 ;
tmp = gd - > baudrate * 16 ;
bdiv = ( CONFIG_SYS_EXT_SERIAL_CLOCK + tmp / 2 ) / tmp ;
# else
serial_divs ( gd - > baudrate , & udiv , & bdiv ) ;
# if !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
PPC4xx_SYS_INFO sys_info ;
# endif
reg | = ( udiv - UDIV_SUBTRACT ) < < CR0_UDIV_POS ; /* set the UART divisor */
/*
* Configure input clock to baudrate generator for all
* available serial ports here
* Programming of the internal divisors is SoC specific .
* Let ' s handle this in some # ifdef ' s for the SoC ' s .
*/
mtsdr ( UART0_SDR , reg ) ;
# if defined(UART1_SDR)
mtsdr ( UART1_SDR , reg ) ;
# endif
# elif defined(CONFIG_405EZ)
serial_divs ( gd - > baudrate , & udiv , & bdiv ) ;
clk = tmp = reg = 0 ;
# else
# ifdef CONFIG_405EP
reg = mfdcr ( CPC0_UCR ) & ~ ( UCR0_MASK | UCR1_MASK ) ;
clk = gd - > cpu_clk ;
tmp = CONFIG_SYS_BASE_BAUD * 16 ;
udiv = ( clk + tmp / 2 ) / tmp ;
if ( udiv > UDIV_MAX ) /* max. n bits for udiv */
udiv = UDIV_MAX ;
reg | = ( udiv ) < < UCR0_UDIV_POS ; /* set the UART divisor */
reg | = ( udiv ) < < UCR1_UDIV_POS ; /* set the UART divisor */
mtdcr ( CPC0_UCR , reg ) ;
# else /* CONFIG_405EP */
# if defined(CONFIG_405CR) || defined(CONFIG_405GP)
tmp = 0 ;
reg = mfdcr ( CPC0_CR0 ) & ~ CR0_MASK ;
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
clk = CONFIG_SYS_EXT_SERIAL_CLOCK ;
udiv = 1 ;
reg | = CR0_EXTCLK_ENA ;
# else
# else /* CONFIG_SYS_EXT_SERIAL_CLOCK */
clk = gd - > cpu_clk ;
# ifdef CONFIG_SYS_405_UART_ERRATA_59
udiv = 31 ; /* Errata 59: stuck at 31 */
# else
# else /* CONFIG_SYS_405_UART_ERRATA_59 */
tmp = CONFIG_SYS_BASE_BAUD * 16 ;
udiv = ( clk + tmp / 2 ) / tmp ;
if ( udiv > UDIV_MAX ) /* max. n bits for udiv */
udiv = UDIV_MAX ;
# endif
# endif
# endif /* CONFIG_SYS_405_UART_ERRATA_59 */
# endif /* CONFIG_SYS_EXT_SERIAL_CLOCK */
reg | = ( udiv - 1 ) < < CR0_UDIV_POS ; /* set the UART divisor */
mtdcr ( CPC0_CR0 , reg ) ;
# endif /* CONFIG_405EP */
tmp = gd - > baudrate * udiv * 16 ;
bdiv = ( clk + tmp / 2 ) / tmp ;
# endif /* CONFIG_405EX */
serial_init_common ( base , udiv , bdiv ) ;
return ( 0 ) ;
}
# endif /* if defined(CONFIG_440) */
void serial_setbrg_dev ( unsigned long base )
{
serial_init_dev ( base ) ;
}
void serial_putc_dev ( unsigned long base , const char c )
{
int i ;
if ( c = = ' \n ' )
serial_putc_dev ( base , ' \r ' ) ;
/* check THRE bit, wait for transmiter available */
for ( i = 1 ; i < 3500 ; i + + ) {
if ( ( in_8 ( ( u8 * ) base + UART_LSR ) & 0x20 ) = = 0x20 )
break ;
udelay ( 100 ) ;
}
out_8 ( ( u8 * ) base + UART_THR , c ) ; /* put character out */
}
void serial_puts_dev ( unsigned long base , const char * s )
{
while ( * s )
serial_putc_dev ( base , * s + + ) ;
}
int serial_getc_dev ( unsigned long base )
{
unsigned char status = 0 ;
while ( 1 ) {
# if defined(CONFIG_HW_WATCHDOG)
WATCHDOG_RESET ( ) ; /* Reset HW Watchdog, if needed */
# endif /* CONFIG_HW_WATCHDOG */
status = in_8 ( ( u8 * ) base + UART_LSR ) ;
if ( ( status & asyncLSRDataReady1 ) ! = 0x0 )
break ;
if ( ( status & ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ) ! = 0 ) {
out_8 ( ( u8 * ) base + UART_LSR ,
asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ;
}
}
return ( 0x000000ff & ( int ) in_8 ( ( u8 * ) base ) ) ;
}
int serial_tstc_dev ( unsigned long base )
{
unsigned char status ;
status = in_8 ( ( u8 * ) base + UART_LSR ) ;
if ( ( status & asyncLSRDataReady1 ) ! = 0x0 )
return ( 1 ) ;
if ( ( status & ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ) ! = 0 ) {
out_8 ( ( u8 * ) base + UART_LSR ,
asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ;
}
return 0 ;
}
# ifdef CONFIG_SERIAL_SOFTWARE_FIFO
void serial_isr ( void * arg )
{
int space ;
int c ;
const int rx_get = buf_info . rx_get ;
int 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 ;
while ( serial_tstc_dev ( ACTING_UART0_BASE ) ) {
c = serial_getc_dev ( ACTING_UART0_BASE ) ;
if ( space ) {
buf_info . rx_buffer [ rx_put + + ] = c ;
space - - ;
}
if ( rx_put = = CONFIG_SERIAL_SOFTWARE_FIFO )
rx_put = 0 ;
if ( space < CONFIG_SERIAL_SOFTWARE_FIFO / 4 ) {
/* Stop flow by setting RTS inactive */
out_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MCR ,
in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MCR ) &
( 0xFF ^ 0x02 ) ) ;
}
}
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 ( in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MSR ) & 0x10 )
serial_puts ( " Check CTS signal present on serial port: OK. \n " ) ;
else
serial_puts ( " WARNING: CTS signal not present on serial port. \n " ) ;
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 */
out_8 ( ACTING_UART0_BASE + UART_IER , 0x01 ) ;
/* Set DTR active */
out_8 ( ACTING_UART0_BASE + UART_MCR ,
in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MCR ) | 0x01 ) ;
/* Start flow by setting RTS active */
out_8 ( ACTING_UART0_BASE + UART_MCR ,
in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MCR ) | 0x02 ) ;
/* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */
out_8 ( ACTING_UART0_BASE + UART_FCR , ( 1 < < 6 ) | 1 ) ;
}
void serial_buffered_putc ( const char c )
{
/* Wait for CTS */
# if defined(CONFIG_HW_WATCHDOG)
while ( ! ( in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MSR ) & 0x10 ) )
WATCHDOG_RESET ( ) ;
# else
while ( ! ( in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MSR ) & 0x10 ) ) ;
# 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 ( ) ;
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
clk = CONFIG_SYS_EXT_SERIAL_CLOCK ;
# else
while ( rx_get = = buf_info . rx_put ) ;
clk = CONFIG_SYS_BASE_BAUD * 16 ;
# 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 */
out_8 ( ACTING_UART0_BASE + UART_MCR ,
in_8 ( ( u8 * ) ACTING_UART0_BASE + UART_MCR ) | 0x02 ) ;
}
# endif /* CONFIG_405CR */
return c ;
}
# if defined(CONFIG_405EP)
reg = mfdcr ( CPC0_UCR ) & ~ ( UCR0_MASK | UCR1_MASK ) ;
clk = gd - > cpu_clk ;
tmp = CONFIG_SYS_BASE_BAUD * 16 ;
udiv = ( clk + tmp / 2 ) / tmp ;
if ( udiv > UDIV_MAX ) /* max. n bits for udiv */
udiv = UDIV_MAX ;
reg | = udiv < < UCR0_UDIV_POS ; /* set the UART divisor */
reg | = udiv < < UCR1_UDIV_POS ; /* set the UART divisor */
mtdcr ( CPC0_UCR , reg ) ;
clk = CONFIG_SYS_BASE_BAUD * 16 ;
# endif /* CONFIG_405EP */
int serial_buffered_tstc ( void )
{
return ( buf_info . rx_get ! = buf_info . rx_put ) ? 1 : 0 ;
}
# if defined(CONFIG_405EX) || defined(CONFIG_440)
MFREG ( UART0_SDR , reg ) ;
reg & = ~ CR0_MASK ;
# endif /* CONFIG_SERIAL_SOFTWARE_FIFO */
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
reg | = CR0_EXTCLK_ENA ;
udiv = 1 ;
clk = CONFIG_SYS_EXT_SERIAL_CLOCK ;
# else /* CONFIG_SYS_EXT_SERIAL_CLOCK */
clk = gd - > baudrate * serial_bdiv ( gd - > baudrate , & udiv ) * 16 ;
# endif /* CONFIG_SYS_EXT_SERIAL_CLOCK */
# 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 )
{
u8 val ;
u16 br_reg ;
reg | = ( udiv - UDIV_SUBTRACT ) < < CR0_UDIV_POS ; /* set the UART divisor */
get_clocks ( ) ;
br_reg = ( ( ( ( ( gd - > cpu_clk / 16 ) / 18 ) * 10 ) / CONFIG_KGDB_BAUDRATE ) +
5 ) / 10 ;
/*
* Init onboard 16550 UART
* Configure input clock to baudrate generator for all
* available serial ports here
*/
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_LCR , 0x80 ) ; /* set DLAB bit */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_DLL , ( br_reg & 0x00ff ) ) ; /* set divisor for 9600 baud */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_DLM , ( ( br_reg & 0xff00 ) > > 8 ) ) ; /* set divisor for 9600 baud */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_LCR , 0x03 ) ; /* line control 8 bits no parity */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_FCR , 0x00 ) ; /* disable FIFO */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_MCR , 0x00 ) ; /* no modem control DTR RTS */
val = in_8 ( ( u8 * ) ACTING_UART1_BASE + UART_LSR ) ; /* clear line status */
val = in_8 ( ( u8 * ) ACTING_UART1_BASE + UART_RBR ) ; /* read receive buffer */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_SCR , 0x00 ) ; /* set scratchpad */
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_IER , 0x00 ) ; /* set interrupt enable reg */
}
void putDebugChar ( const char c )
{
if ( c = = ' \n ' )
serial_putc ( ' \r ' ) ;
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_THR , c ) ; /* put character out */
/* check THRE bit, wait for transfer done */
while ( ( in_8 ( ( u8 * ) ACTING_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 = in_8 ( ( u8 * ) ACTING_UART1_BASE + UART_LSR ) ;
if ( ( status & asyncLSRDataReady1 ) ! = 0x0 )
break ;
if ( ( status & ( asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ) ! = 0 ) {
out_8 ( ( u8 * ) ACTING_UART1_BASE + UART_LSR ,
asyncLSRFramingError1 |
asyncLSROverrunError1 |
asyncLSRParityError1 |
asyncLSRBreakInterrupt1 ) ;
}
}
return ( 0x000000ff & ( int ) in_8 ( ( u8 * ) ACTING_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) */
MTREG ( UART0_SDR , reg ) ;
# if defined(UART1_SDR)
MTREG ( UART1_SDR , reg ) ;
# endif
# if defined(UART2_SDR)
MTREG ( UART2_SDR , reg ) ;
# endif
# if defined(UART3_SDR)
MTREG ( UART3_SDR , reg ) ;
# endif
# endif /* CONFIG_405EX ... */
# if defined(CONFIG_405EZ)
clk = gd - > baudrate * serial_bdiv ( gd - > baudrate , & udiv ) * 16 ;
# endif /* CONFIG_405EZ */
# if defined(CONFIG_SERIAL_MULTI)
int serial0_init ( void )
{
return ( serial_init_dev ( UART0_BASE ) ) ;
}
int serial1_init ( void )
{
return ( serial_init_dev ( UART1_BASE ) ) ;
}
void serial0_setbrg ( void )
{
serial_setbrg_dev ( UART0_BASE ) ;
}
void serial1_setbrg ( void )
{
serial_setbrg_dev ( UART1_BASE ) ;
}
void serial0_putc ( const char c )
{
serial_putc_dev ( UART0_BASE , c ) ;
}
void serial1_putc ( const char c )
{
serial_putc_dev ( UART1_BASE , c ) ;
}
void serial0_puts ( const char * s )
{
serial_puts_dev ( UART0_BASE , s ) ;
}
void serial1_puts ( const char * s )
{
serial_puts_dev ( UART1_BASE , s ) ;
}
int serial0_getc ( void )
{
return ( serial_getc_dev ( UART0_BASE ) ) ;
}
int serial1_getc ( void )
{
return ( serial_getc_dev ( UART1_BASE ) ) ;
}
int serial0_tstc ( void )
{
return ( serial_tstc_dev ( UART0_BASE ) ) ;
}
int serial1_tstc ( void )
{
return ( serial_tstc_dev ( UART1_BASE ) ) ;
}
struct serial_device serial0_device =
{
" serial0 " ,
" UART0 " ,
serial0_init ,
NULL ,
serial0_setbrg ,
serial0_getc ,
serial0_tstc ,
serial0_putc ,
serial0_puts ,
} ;
struct serial_device serial1_device =
{
" serial1 " ,
" UART1 " ,
serial1_init ,
NULL ,
serial1_setbrg ,
serial1_getc ,
serial1_tstc ,
serial1_putc ,
serial1_puts ,
} ;
/*
* Correct UART frequency in bd - info struct now that
* the UART divisor is available
*/
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
gd - > uart_clk = CONFIG_SYS_EXT_SERIAL_CLOCK ;
# else
/*
* Wrapper functions
*/
int serial_init ( void )
{
return serial_init_dev ( ACTING_UART0_BASE ) ;
}
void serial_setbrg ( void )
{
serial_setbrg_dev ( ACTING_UART0_BASE ) ;
}
void serial_putc ( const char c )
{
serial_putc_dev ( ACTING_UART0_BASE , c ) ;
}
void serial_puts ( const char * s )
{
serial_puts_dev ( ACTING_UART0_BASE , s ) ;
}
int serial_getc ( void )
{
return serial_getc_dev ( ACTING_UART0_BASE ) ;
}
get_sys_info ( & sys_info ) ;
gd - > uart_clk = sys_info . freqUART / udiv ;
# endif
int serial_tstc ( void )
{
return serial_tstc_dev ( ACTING_UART0_BASE ) ;
return clk ;
}
# endif /* CONFIG_SERIAL_MULTI */
# endif /* CONFIG_405GP || CONFIG_405CR */