@ -26,9 +26,10 @@
*/
# include <common.h>
# include <ppc4xx.h>
# include <asm/ ppc4xx.h>
# include <ns16550.h>
# include <asm/io.h>
# include <serial.h>
/*
* UART test
@ -46,299 +47,40 @@
* be overridden in the board config file
*/
# ifndef CONFIG_SYS_POST_UART_TABLE
# define CONFIG_SYS_POST_UART_TABLE {UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE}
# endif
# include <asm/processor.h>
# include <serial.h>
# if defined(CONFIG_440)
# if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
defined ( CONFIG_440EPX ) | | defined ( CONFIG_440GRX )
# define UART0_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000300
# define UART1_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000400
# define UART2_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000500
# define UART3_BASE CONFIG_SYS_PERIPHERAL_BASE + 0x00000600
# 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_440GP)
# define CR0_MASK 0x3fff0000
# define CR0_EXTCLK_ENA 0x00600000
# define CR0_UDIV_POS 16
# define UDIV_SUBTRACT 1
# define UART0_SDR CPC0_CR0
# define MFREG(a, d) d = mfdcr(a)
# define MTREG(a, d) mtdcr(a, d)
# else /* #if defined(CONFIG_440GP) */
/* all other 440 PPC's access clock divider via sdr register */
# define CR0_MASK 0xdfffffff
# define CR0_EXTCLK_ENA 0x00800000
# define CR0_UDIV_POS 0
# define UDIV_SUBTRACT 0
# define UART0_SDR SDR0_UART0
# define UART1_SDR SDR0_UART1
# if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
defined ( CONFIG_440GR ) | | defined ( CONFIG_440GRX ) | | \
defined ( CONFIG_440SP ) | | defined ( CONFIG_440SPE )
# define UART2_SDR SDR0_UART2
# endif
# if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
defined ( CONFIG_440GR ) | | defined ( CONFIG_440GRX )
# define UART3_SDR SDR0_UART3
# endif
# define MFREG(a, d) mfsdr(a, d)
# 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 CR0_MASK 0x000000ff
# define CR0_EXTCLK_ENA 0x00800000
# define CR0_UDIV_POS 0
# define UDIV_SUBTRACT 0
# define UART0_SDR SDR0_UART0
# define UART1_SDR SDR0_UART1
# define MFREG(a, d) mfsdr(a, d)
# define MTREG(a, d) mtsdr(a, d)
# 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
# define CONFIG_SYS_POST_UART_TABLE { CONFIG_SYS_NS16550_COM1, \
CONFIG_SYS_NS16550_COM2 , CONFIG_SYS_NS16550_COM3 , \
CONFIG_SYS_NS16550_COM4 }
# endif
DECLARE_GLOBAL_DATA_PTR ;
static void uart_post_init_common ( struct NS16550 * com_port , unsigned short bdiv )
{
volatile char val ;
out_8 ( & com_port - > lcr , 0x80 ) ; /* set DLAB bit */
out_8 ( & com_port - > dll , bdiv ) ; /* set baudrate divisor */
out_8 ( & com_port - > dlm , bdiv > > 8 ) ; /* set baudrate divisor */
out_8 ( & com_port - > lcr , 0x03 ) ; /* clear DLAB; set 8 bits, no parity */
out_8 ( & com_port - > fcr , 0x00 ) ; /* disable FIFO */
out_8 ( & com_port - > mcr , 0x10 ) ; /* enable loopback mode */
val = in_8 ( & com_port - > lsr ) ; /* clear line status */
val = in_8 ( & com_port - > rbr ) ; /* read receive buffer */
out_8 ( & com_port - > scr , 0x00 ) ; /* set scratchpad */
out_8 ( & com_port - > ier , 0x00 ) ; /* set interrupt enable reg */
}
# if defined(CONFIG_440) || defined(CONFIG_405EX)
# if !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
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 */
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 ;
}
# endif
static int uart_post_init ( struct NS16550 * com_port )
static int test_ctlr ( struct NS16550 * com_port , int index )
{
unsigned long reg = 0 ;
unsigned long udiv ;
unsigned short bdiv ;
# ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
unsigned long tmp ;
# endif
int res = - 1 ;
char test_str [ ] = " *** UART Test String *** \r \n " ;
int i ;
int divisor ;
for ( i = 0 ; i < 3500 ; i + + ) {
if ( in_8 ( & com_port - > lsr ) & UART_LSR_THRE )
break ;
udelay ( 100 ) ;
}
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 ) ;
# endif
reg | = ( udiv - UDIV_SUBTRACT ) < < CR0_UDIV_POS ; /* set the UART divisor */
divisor = ( get_serial_clock ( ) + ( gd - > baudrate * ( 16 / 2 ) ) ) /
( 16 * gd - > baudrate ) ;
NS16550_init ( com_port , divisor ) ;
/*
* Configure input clock to baudrate generator for all
* available serial ports here
* Set internal loopback mode in UART
*/
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
uart_post_init_common ( com_port , bdiv ) ;
return 0 ;
}
# else /* CONFIG_440 */
static int uart_post_init ( struct NS16550 * com_port )
{
unsigned long reg ;
unsigned long tmp ;
unsigned long clk ;
unsigned long udiv ;
unsigned short bdiv ;
int i ;
for ( i = 0 ; i < 3500 ; i + + ) {
if ( in_8 ( & com_port - > lsr ) & UART_LSR_THRE )
break ;
udelay ( 100 ) ;
}
# if 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 */
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
clk = gd - > cpu_clk ;
# ifdef CONFIG_SYS_405_UART_ERRATA_59
udiv = 31 ; /* Errata 59: stuck at 31 */
# else
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
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_405EZ */
uart_post_init_common ( com_port , bdiv ) ;
out_8 ( & com_port - > mcr , in_8 ( & com_port - > mcr ) | UART_MCR_LOOP ) ;
return 0 ;
}
# endif /* CONFIG_440 */
static void uart_post_putc ( struct NS16550 * com_port , char c )
{
int i ;
out_8 ( & com_port - > thr , c ) ; /* put character out */
/* Wait for transfer completion */
for ( i = 0 ; i < 3500 ; i + + ) {
if ( in_8 ( & com_port - > lsr ) & UART_LSR_THRE )
break ;
udelay ( 100 ) ;
}
}
static int uart_post_getc ( struct NS16550 * com_port )
{
int i ;
/* Wait for character available */
for ( i = 0 ; i < 3500 ; i + + ) {
if ( in_8 ( & com_port - > lsr ) & UART_LSR_DR )
break ;
udelay ( 100 ) ;
}
return 0xff & in_8 ( & com_port - > rbr ) ;
}
static int test_ctlr ( struct NS16550 * com_port , int index )
{
int res = - 1 ;
char test_str [ ] = " *** UART Test String *** \r \n " ;
int i ;
/* Reset FIFOs */
out_8 ( & com_port - > fcr , UART_FCR_RXSR | UART_FCR_TXSR ) ;
udelay ( 100 ) ;
uart_post_init ( com_port ) ;
/* Flush RX-FIFO */
while ( NS16550_tstc ( com_port ) )
NS16550_getc ( com_port ) ;
for ( i = 0 ; i < sizeof ( test_str ) - 1 ; i + + ) {
uart_post_putc ( com_port , test_str [ i ] ) ;
if ( uart_post_getc ( com_port ) ! = test_str [ i ] )
NS16550_putc ( com_port , test_str [ i ] ) ;
if ( NS16550_getc ( com_port ) ! = test_str [ i ] )
goto done ;
}
res = 0 ;