2005-07-27 11:44:44 -07:00
/*
* Copyright ( C ) 2003 , Axis Communications AB .
*/
# include <linux/console.h>
# include <linux/init.h>
# include <linux/major.h>
# include <linux/delay.h>
# include <linux/tty.h>
# include <asm/system.h>
# include <asm/io.h>
# include <asm/arch/hwregs/ser_defs.h>
# include <asm/arch/hwregs/dma_defs.h>
# include <asm/arch/pinmux.h>
# include <asm/irq.h>
# include <asm/arch/hwregs/intr_vect_defs.h>
struct dbg_port
{
unsigned char nbr ;
unsigned long instance ;
unsigned int started ;
unsigned long baudrate ;
unsigned char parity ;
unsigned int bits ;
} ;
struct dbg_port ports [ ] =
{
{
0 ,
regi_ser0 ,
0 ,
115200 ,
' N ' ,
8
} ,
{
1 ,
regi_ser1 ,
0 ,
115200 ,
' N ' ,
8
} ,
{
2 ,
regi_ser2 ,
0 ,
115200 ,
' N ' ,
8
} ,
{
3 ,
regi_ser3 ,
0 ,
115200 ,
' N ' ,
8
}
} ;
static struct dbg_port * port =
# if defined(CONFIG_ETRAX_DEBUG_PORT0)
& ports [ 0 ] ;
# elif defined(CONFIG_ETRAX_DEBUG_PORT1)
& ports [ 1 ] ;
# elif defined(CONFIG_ETRAX_DEBUG_PORT2)
& ports [ 2 ] ;
# elif defined(CONFIG_ETRAX_DEBUG_PORT3)
& ports [ 3 ] ;
# else
NULL ;
# endif
# ifdef CONFIG_ETRAX_KGDB
static struct dbg_port * kgdb_port =
# if defined(CONFIG_ETRAX_KGDB_PORT0)
& ports [ 0 ] ;
# elif defined(CONFIG_ETRAX_KGDB_PORT1)
& ports [ 1 ] ;
# elif defined(CONFIG_ETRAX_KGDB_PORT2)
& ports [ 2 ] ;
# elif defined(CONFIG_ETRAX_KGDB_PORT3)
& ports [ 3 ] ;
# else
NULL ;
# endif
# endif
# ifdef CONFIG_ETRAXFS_SIM
extern void print_str ( const char * str ) ;
static char buffer [ 1024 ] ;
static char msg [ ] = " Debug: " ;
static int buffer_pos = sizeof ( msg ) - 1 ;
# endif
extern struct tty_driver * serial_driver ;
static void
start_port ( struct dbg_port * p )
{
if ( ! p )
return ;
if ( p - > started )
return ;
p - > started = 1 ;
if ( p - > nbr = = 1 )
crisv32_pinmux_alloc_fixed ( pinmux_ser1 ) ;
else if ( p - > nbr = = 2 )
crisv32_pinmux_alloc_fixed ( pinmux_ser2 ) ;
else if ( p - > nbr = = 3 )
crisv32_pinmux_alloc_fixed ( pinmux_ser3 ) ;
/* Set up serial port registers */
reg_ser_rw_tr_ctrl tr_ctrl = { 0 } ;
reg_ser_rw_tr_dma_en tr_dma_en = { 0 } ;
reg_ser_rw_rec_ctrl rec_ctrl = { 0 } ;
reg_ser_rw_tr_baud_div tr_baud_div = { 0 } ;
reg_ser_rw_rec_baud_div rec_baud_div = { 0 } ;
tr_ctrl . base_freq = rec_ctrl . base_freq = regk_ser_f29_493 ;
tr_dma_en . en = rec_ctrl . dma_mode = regk_ser_no ;
tr_baud_div . div = rec_baud_div . div = 29493000 / p - > baudrate / 8 ;
tr_ctrl . en = rec_ctrl . en = 1 ;
if ( p - > parity = = ' O ' )
{
tr_ctrl . par_en = regk_ser_yes ;
tr_ctrl . par = regk_ser_odd ;
rec_ctrl . par_en = regk_ser_yes ;
rec_ctrl . par = regk_ser_odd ;
}
else if ( p - > parity = = ' E ' )
{
tr_ctrl . par_en = regk_ser_yes ;
tr_ctrl . par = regk_ser_even ;
rec_ctrl . par_en = regk_ser_yes ;
rec_ctrl . par = regk_ser_odd ;
}
if ( p - > bits = = 7 )
{
tr_ctrl . data_bits = regk_ser_bits7 ;
rec_ctrl . data_bits = regk_ser_bits7 ;
}
REG_WR ( ser , p - > instance , rw_tr_baud_div , tr_baud_div ) ;
REG_WR ( ser , p - > instance , rw_rec_baud_div , rec_baud_div ) ;
REG_WR ( ser , p - > instance , rw_tr_dma_en , tr_dma_en ) ;
REG_WR ( ser , p - > instance , rw_tr_ctrl , tr_ctrl ) ;
REG_WR ( ser , p - > instance , rw_rec_ctrl , rec_ctrl ) ;
}
/* No debug */
# ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
static void
console_write ( struct console * co , const char * buf , unsigned int len )
{
return ;
}
/* Target debug */
# elif !defined(CONFIG_ETRAXFS_SIM)
static void
console_write_direct ( struct console * co , const char * buf , unsigned int len )
{
int i ;
reg_ser_r_stat_din stat ;
reg_ser_rw_tr_dma_en tr_dma_en , old ;
/* Switch to manual mode */
tr_dma_en = old = REG_RD ( ser , port - > instance , rw_tr_dma_en ) ;
if ( tr_dma_en . en = = regk_ser_yes ) {
tr_dma_en . en = regk_ser_no ;
REG_WR ( ser , port - > instance , rw_tr_dma_en , tr_dma_en ) ;
}
/* Send data */
for ( i = 0 ; i < len ; i + + ) {
/* LF -> CRLF */
if ( buf [ i ] = = ' \n ' ) {
do {
stat = REG_RD ( ser , port - > instance , r_stat_din ) ;
} while ( ! stat . tr_rdy ) ;
REG_WR_INT ( ser , port - > instance , rw_dout , ' \r ' ) ;
}
/* Wait until transmitter is ready and send.*/
do {
stat = REG_RD ( ser , port - > instance , r_stat_din ) ;
} while ( ! stat . tr_rdy ) ;
REG_WR_INT ( ser , port - > instance , rw_dout , buf [ i ] ) ;
}
/* Restore mode */
if ( tr_dma_en . en ! = old . en )
REG_WR ( ser , port - > instance , rw_tr_dma_en , old ) ;
}
static void
console_write ( struct console * co , const char * buf , unsigned int len )
{
if ( ! port )
return ;
console_write_direct ( co , buf , len ) ;
}
# else
/* VCS debug */
static void
console_write ( struct console * co , const char * buf , unsigned int len )
{
char * pos ;
pos = memchr ( buf , ' \n ' , len ) ;
if ( pos ) {
int l = + + pos - buf ;
memcpy ( buffer + buffer_pos , buf , l ) ;
memcpy ( buffer , msg , sizeof ( msg ) - 1 ) ;
buffer [ buffer_pos + l ] = ' \0 ' ;
print_str ( buffer ) ;
buffer_pos = sizeof ( msg ) - 1 ;
if ( pos - buf ! = len ) {
memcpy ( buffer + buffer_pos , pos , len - l ) ;
buffer_pos + = len - l ;
}
} else {
memcpy ( buffer + buffer_pos , buf , len ) ;
buffer_pos + = len ;
}
}
# endif
int raw_printk ( const char * fmt , . . . )
{
static char buf [ 1024 ] ;
int printed_len ;
va_list args ;
va_start ( args , fmt ) ;
printed_len = vsnprintf ( buf , sizeof ( buf ) , fmt , args ) ;
va_end ( args ) ;
console_write ( NULL , buf , strlen ( buf ) ) ;
return printed_len ;
}
void
stupid_debug ( char * buf )
{
console_write ( NULL , buf , strlen ( buf ) ) ;
}
# ifdef CONFIG_ETRAX_KGDB
/* Use polling to get a single character from the kernel debug port */
int
getDebugChar ( void )
{
reg_ser_rs_status_data stat ;
reg_ser_rw_ack_intr ack_intr = { 0 } ;
do {
stat = REG_RD ( ser , kgdb_instance , rs_status_data ) ;
} while ( ! stat . data_avail ) ;
/* Ack the data_avail interrupt. */
ack_intr . data_avail = 1 ;
REG_WR ( ser , kgdb_instance , rw_ack_intr , ack_intr ) ;
return stat . data ;
}
/* Use polling to put a single character to the kernel debug port */
void
putDebugChar ( int val )
{
reg_ser_r_status_data stat ;
do {
stat = REG_RD ( ser , kgdb_instance , r_status_data ) ;
} while ( ! stat . tr_ready ) ;
REG_WR ( ser , kgdb_instance , rw_data_out , REG_TYPE_CONV ( reg_ser_rw_data_out , int , val ) ) ;
}
# endif /* CONFIG_ETRAX_KGDB */
static int __init
console_setup ( struct console * co , char * options )
{
char * s ;
if ( options ) {
port = & ports [ co - > index ] ;
port - > baudrate = 115200 ;
port - > parity = ' N ' ;
port - > bits = 8 ;
port - > baudrate = simple_strtoul ( options , NULL , 10 ) ;
s = options ;
while ( * s > = ' 0 ' & & * s < = ' 9 ' )
s + + ;
if ( * s ) port - > parity = * s + + ;
if ( * s ) port - > bits = * s + + - ' 0 ' ;
port - > started = 0 ;
start_port ( port ) ;
}
return 0 ;
}
/* This is a dummy serial device that throws away anything written to it.
* This is used when no debug output is wanted .
*/
static struct tty_driver dummy_driver ;
static int dummy_open ( struct tty_struct * tty , struct file * filp )
{
return 0 ;
}
static void dummy_close ( struct tty_struct * tty , struct file * filp )
{
}
static int dummy_write ( struct tty_struct * tty ,
const unsigned char * buf , int count )
{
return count ;
}
static int
dummy_write_room ( struct tty_struct * tty )
{
return 8192 ;
}
void __init
init_dummy_console ( void )
{
memset ( & dummy_driver , 0 , sizeof ( struct tty_driver ) ) ;
dummy_driver . driver_name = " serial " ;
dummy_driver . name = " ttyS " ;
dummy_driver . major = TTY_MAJOR ;
dummy_driver . minor_start = 68 ;
dummy_driver . num = 1 ; /* etrax100 has 4 serial ports */
dummy_driver . type = TTY_DRIVER_TYPE_SERIAL ;
dummy_driver . subtype = SERIAL_TYPE_NORMAL ;
dummy_driver . init_termios = tty_std_termios ;
dummy_driver . init_termios . c_cflag =
B115200 | CS8 | CREAD | HUPCL | CLOCAL ; /* is normally B9600 default... */
2005-06-20 21:15:16 -07:00
dummy_driver . flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV ;
2005-07-27 11:44:44 -07:00
dummy_driver . open = dummy_open ;
dummy_driver . close = dummy_close ;
dummy_driver . write = dummy_write ;
dummy_driver . write_room = dummy_write_room ;
if ( tty_register_driver ( & dummy_driver ) )
panic ( " Couldn't register dummy serial driver \n " ) ;
}
static struct tty_driver *
crisv32_console_device ( struct console * co , int * index )
{
if ( port )
* index = port - > nbr ;
return port ? serial_driver : & dummy_driver ;
}
static struct console sercons = {
name : " ttyS " ,
write : console_write ,
read : NULL ,
device : crisv32_console_device ,
unblank : NULL ,
setup : console_setup ,
flags : CON_PRINTBUFFER ,
index : - 1 ,
cflag : 0 ,
next : NULL
} ;
static struct console sercons0 = {
name : " ttyS " ,
write : console_write ,
read : NULL ,
device : crisv32_console_device ,
unblank : NULL ,
setup : console_setup ,
flags : CON_PRINTBUFFER ,
index : 0 ,
cflag : 0 ,
next : NULL
} ;
static struct console sercons1 = {
name : " ttyS " ,
write : console_write ,
read : NULL ,
device : crisv32_console_device ,
unblank : NULL ,
setup : console_setup ,
flags : CON_PRINTBUFFER ,
index : 1 ,
cflag : 0 ,
next : NULL
} ;
static struct console sercons2 = {
name : " ttyS " ,
write : console_write ,
read : NULL ,
device : crisv32_console_device ,
unblank : NULL ,
setup : console_setup ,
flags : CON_PRINTBUFFER ,
index : 2 ,
cflag : 0 ,
next : NULL
} ;
static struct console sercons3 = {
name : " ttyS " ,
write : console_write ,
read : NULL ,
device : crisv32_console_device ,
unblank : NULL ,
setup : console_setup ,
flags : CON_PRINTBUFFER ,
index : 3 ,
cflag : 0 ,
next : NULL
} ;
/* Register console for printk's, etc. */
int __init
init_etrax_debug ( void )
{
static int first = 1 ;
if ( ! first ) {
unregister_console ( & sercons ) ;
register_console ( & sercons0 ) ;
register_console ( & sercons1 ) ;
register_console ( & sercons2 ) ;
register_console ( & sercons3 ) ;
init_dummy_console ( ) ;
return 0 ;
}
first = 0 ;
register_console ( & sercons ) ;
start_port ( port ) ;
# ifdef CONFIG_ETRAX_KGDB
start_port ( kgdb_port ) ;
# endif /* CONFIG_ETRAX_KGDB */
return 0 ;
}
__initcall ( init_etrax_debug ) ;