2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) 1996 Paul Mackerras .
*/
# include <linux/string.h>
# include <asm/machdep.h>
# include <asm/io.h>
# include <asm/page.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/sysrq.h>
# include <linux/bitops.h>
# include <asm/xmon.h>
# include <asm/machdep.h>
# include <asm/errno.h>
# include <asm/processor.h>
# include <asm/delay.h>
# include <asm/btext.h>
2006-09-07 13:27:58 -05:00
# include <asm/ibm4xx.h>
2005-04-16 15:20:36 -07:00
static volatile unsigned char * sccc , * sccd ;
unsigned int TXRDY , RXRDY , DLAB ;
static int xmon_expect ( const char * str , unsigned int timeout ) ;
static int via_modem ;
# define TB_SPEED 25000000
static inline unsigned int readtb ( void )
{
unsigned int ret ;
asm volatile ( " mftb %0 " : " =r " ( ret ) : ) ;
return ret ;
}
void buf_access ( void )
{
if ( DLAB )
sccd [ 3 ] & = ~ DLAB ; /* reset DLAB */
}
# ifdef CONFIG_MAGIC_SYSRQ
static void sysrq_handle_xmon ( int key , struct pt_regs * regs ,
struct tty_struct * tty )
{
xmon ( regs ) ;
}
static struct sysrq_key_op sysrq_xmon_op =
{
. handler = sysrq_handle_xmon ,
. help_msg = " Xmon " ,
. action_msg = " Entering xmon " ,
} ;
# endif
void
xmon_map_scc ( void )
{
2007-01-14 10:15:00 +01:00
# if defined(CONFIG_405GP)
2005-04-16 15:20:36 -07:00
sccd = ( volatile unsigned char * ) 0xef600300 ;
2006-09-07 13:27:58 -05:00
# elif defined(CONFIG_440EP)
sccd = ( volatile unsigned char * ) ioremap ( PPC440EP_UART0_ADDR , 8 ) ;
# elif defined(CONFIG_440SP)
sccd = ( volatile unsigned char * ) ioremap64 ( PPC440SP_UART0_ADDR , 8 ) ;
# elif defined(CONFIG_440SPE)
sccd = ( volatile unsigned char * ) ioremap64 ( PPC440SPE_UART0_ADDR , 8 ) ;
# elif defined(CONFIG_44x)
/* This is the default for 44x platforms. Any boards that have a
different UART address need to be put in cases before this or the
port will be mapped incorrectly */
sccd = ( volatile unsigned char * ) ioremap64 ( PPC440GP_UART0_ADDR , 8 ) ;
# endif /* platform */
# ifndef CONFIG_PPC_PREP
sccc = sccd + 5 ;
2005-04-16 15:20:36 -07:00
TXRDY = 0x20 ;
RXRDY = 1 ;
DLAB = 0x80 ;
2006-09-07 13:27:58 -05:00
# endif
2005-04-16 15:20:36 -07:00
register_sysrq_key ( ' x ' , & sysrq_xmon_op ) ;
}
2006-02-21 21:06:41 +01:00
static int scc_initialized ;
2005-04-16 15:20:36 -07:00
void xmon_init_scc ( void ) ;
int
xmon_write ( void * handle , void * ptr , int nb )
{
char * p = ptr ;
int i , c , ct ;
# ifdef CONFIG_SMP
static unsigned long xmon_write_lock ;
int lock_wait = 1000000 ;
int locked ;
while ( ( locked = test_and_set_bit ( 0 , & xmon_write_lock ) ) ! = 0 )
if ( - - lock_wait = = 0 )
break ;
# endif
if ( ! scc_initialized )
xmon_init_scc ( ) ;
ct = 0 ;
for ( i = 0 ; i < nb ; + + i ) {
while ( ( * sccc & TXRDY ) = = 0 )
2006-02-11 18:21:47 +01:00
;
2005-04-16 15:20:36 -07:00
c = p [ i ] ;
if ( c = = ' \n ' & & ! ct ) {
c = ' \r ' ;
ct = 1 ;
- - i ;
} else {
ct = 0 ;
}
buf_access ( ) ;
* sccd = c ;
eieio ( ) ;
}
# ifdef CONFIG_SMP
if ( ! locked )
clear_bit ( 0 , & xmon_write_lock ) ;
# endif
return nb ;
}
int xmon_wants_key ;
int
xmon_read ( void * handle , void * ptr , int nb )
{
char * p = ptr ;
int i ;
if ( ! scc_initialized )
xmon_init_scc ( ) ;
for ( i = 0 ; i < nb ; + + i ) {
while ( ( * sccc & RXRDY ) = = 0 )
2006-02-21 21:06:41 +01:00
;
2005-04-16 15:20:36 -07:00
buf_access ( ) ;
* p + + = * sccd ;
}
return i ;
}
int
xmon_read_poll ( void )
{
if ( ( * sccc & RXRDY ) = = 0 ) {
2006-02-21 21:06:41 +01:00
;
2005-04-16 15:20:36 -07:00
return - 1 ;
}
buf_access ( ) ;
return * sccd ;
}
void
xmon_init_scc ( void )
{
scc_initialized = 1 ;
if ( via_modem ) {
for ( ; ; ) {
xmon_write ( NULL , " ATE1V1 \r " , 7 ) ;
if ( xmon_expect ( " OK " , 5 ) ) {
xmon_write ( NULL , " ATA \r " , 4 ) ;
if ( xmon_expect ( " CONNECT " , 40 ) )
break ;
}
xmon_write ( NULL , " +++ " , 3 ) ;
xmon_expect ( " OK " , 3 ) ;
}
}
}
void * xmon_stdin ;
void * xmon_stdout ;
void * xmon_stderr ;
void
2005-10-11 22:08:12 +10:00
xmon_init ( int arg )
2005-04-16 15:20:36 -07:00
{
2005-10-11 22:08:12 +10:00
xmon_map_scc ( ) ;
2005-04-16 15:20:36 -07:00
}
int
xmon_putc ( int c , void * f )
{
char ch = c ;
if ( c = = ' \n ' )
xmon_putc ( ' \r ' , f ) ;
return xmon_write ( f , & ch , 1 ) = = 1 ? c : - 1 ;
}
int
xmon_putchar ( int c )
{
return xmon_putc ( c , xmon_stdout ) ;
}
int
xmon_fputs ( char * str , void * f )
{
int n = strlen ( str ) ;
return xmon_write ( f , str , n ) = = n ? 0 : - 1 ;
}
int
xmon_readchar ( void )
{
char ch ;
for ( ; ; ) {
switch ( xmon_read ( xmon_stdin , & ch , 1 ) ) {
case 1 :
return ch ;
case - 1 :
xmon_printf ( " read(stdin) returned -1 \r \n " , 0 , 0 ) ;
return - 1 ;
}
}
}
static char line [ 256 ] ;
static char * lineptr ;
static int lineleft ;
int xmon_expect ( const char * str , unsigned int timeout )
{
int c ;
unsigned int t0 ;
timeout * = TB_SPEED ;
t0 = readtb ( ) ;
do {
lineptr = line ;
for ( ; ; ) {
c = xmon_read_poll ( ) ;
if ( c = = - 1 ) {
if ( readtb ( ) - t0 > timeout )
return 0 ;
continue ;
}
if ( c = = ' \n ' )
break ;
if ( c ! = ' \r ' & & lineptr < & line [ sizeof ( line ) - 1 ] )
* lineptr + + = c ;
}
* lineptr = 0 ;
} while ( strstr ( line , str ) = = NULL ) ;
return 1 ;
}
int
xmon_getchar ( void )
{
int c ;
if ( lineleft = = 0 ) {
lineptr = line ;
for ( ; ; ) {
c = xmon_readchar ( ) ;
if ( c = = - 1 | | c = = 4 )
break ;
if ( c = = ' \r ' | | c = = ' \n ' ) {
* lineptr + + = ' \n ' ;
xmon_putchar ( ' \n ' ) ;
break ;
}
switch ( c ) {
case 0177 :
case ' \b ' :
if ( lineptr > line ) {
xmon_putchar ( ' \b ' ) ;
xmon_putchar ( ' ' ) ;
xmon_putchar ( ' \b ' ) ;
- - lineptr ;
}
break ;
case ' U ' & 0x1F :
while ( lineptr > line ) {
xmon_putchar ( ' \b ' ) ;
xmon_putchar ( ' ' ) ;
xmon_putchar ( ' \b ' ) ;
- - lineptr ;
}
break ;
default :
if ( lineptr > = & line [ sizeof ( line ) - 1 ] )
xmon_putchar ( ' \a ' ) ;
else {
xmon_putchar ( c ) ;
* lineptr + + = c ;
}
}
}
lineleft = lineptr - line ;
lineptr = line ;
}
if ( lineleft = = 0 )
return - 1 ;
- - lineleft ;
return * lineptr + + ;
}
char *
xmon_fgets ( char * str , int nb , void * f )
{
char * p ;
int c ;
for ( p = str ; p < str + nb - 1 ; ) {
c = xmon_getchar ( ) ;
if ( c = = - 1 ) {
if ( p = = str )
return NULL ;
break ;
}
* p + + = c ;
if ( c = = ' \n ' )
break ;
}
* p = 0 ;
return str ;
}
void
xmon_enter ( void )
{
}
void
xmon_leave ( void )
{
}