2005-04-17 02:20:36 +04:00
/*
* C interface for trapping into the standard LinuxSH BIOS .
*
* Copyright ( C ) 2000 Greg Banks , Mitch Davis
2010-01-12 09:31:20 +03:00
* Copyright ( C ) 1999 , 2000 Niibe Yutaka
* Copyright ( C ) 2002 M . R . Brown
* Copyright ( C ) 2004 - 2010 Paul Mundt
2005-04-17 02:20:36 +04:00
*
2010-01-12 09:31:20 +03:00
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
2005-04-17 02:20:36 +04:00
*/
2007-07-20 11:59:49 +04:00
# include <linux/module.h>
2010-01-12 09:31:20 +03:00
# include <linux/console.h>
# include <linux/tty.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/delay.h>
2005-04-17 02:20:36 +04:00
# include <asm/sh_bios.h>
2008-12-17 05:37:51 +03:00
# define BIOS_CALL_CONSOLE_WRITE 0
2005-04-17 02:20:36 +04:00
# define BIOS_CALL_ETH_NODE_ADDR 10
# define BIOS_CALL_SHUTDOWN 11
2008-12-17 05:37:51 +03:00
# define BIOS_CALL_GDB_DETACH 0xff
2005-04-17 02:20:36 +04:00
2010-01-12 12:42:52 +03:00
void * gdb_vbr_vector = NULL ;
2008-12-17 05:37:51 +03:00
static inline long sh_bios_call ( long func , long arg0 , long arg1 , long arg2 ,
long arg3 )
2005-04-17 02:20:36 +04:00
{
2008-12-17 05:37:51 +03:00
register long r0 __asm__ ( " r0 " ) = func ;
register long r4 __asm__ ( " r4 " ) = arg0 ;
register long r5 __asm__ ( " r5 " ) = arg1 ;
register long r6 __asm__ ( " r6 " ) = arg2 ;
register long r7 __asm__ ( " r7 " ) = arg3 ;
2005-04-17 02:20:36 +04:00
2010-01-12 12:42:52 +03:00
if ( ! gdb_vbr_vector )
return - ENOSYS ;
2008-12-17 05:37:51 +03:00
__asm__ __volatile__ ( " trapa #0x3f " : " =z " ( r0 )
: " 0 " ( r0 ) , " r " ( r4 ) , " r " ( r5 ) , " r " ( r6 ) , " r " ( r7 )
: " memory " ) ;
return r0 ;
}
2005-04-17 02:20:36 +04:00
void sh_bios_console_write ( const char * buf , unsigned int len )
{
2008-12-17 05:37:51 +03:00
sh_bios_call ( BIOS_CALL_CONSOLE_WRITE , ( long ) buf , ( long ) len , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
void sh_bios_gdb_detach ( void )
{
2008-12-17 05:37:51 +03:00
sh_bios_call ( BIOS_CALL_GDB_DETACH , 0 , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 05:39:33 +03:00
EXPORT_SYMBOL_GPL ( sh_bios_gdb_detach ) ;
2005-04-17 02:20:36 +04:00
2008-12-17 05:37:51 +03:00
void sh_bios_get_node_addr ( unsigned char * node_addr )
2005-04-17 02:20:36 +04:00
{
2008-12-17 05:37:51 +03:00
sh_bios_call ( BIOS_CALL_ETH_NODE_ADDR , 0 , ( long ) node_addr , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 05:39:33 +03:00
EXPORT_SYMBOL_GPL ( sh_bios_get_node_addr ) ;
2005-04-17 02:20:36 +04:00
void sh_bios_shutdown ( unsigned int how )
{
2008-12-17 05:37:51 +03:00
sh_bios_call ( BIOS_CALL_SHUTDOWN , how , 0 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2010-01-12 08:50:43 +03:00
/*
* Read the old value of the VBR register to initialise the vector
* through which debug and BIOS traps are delegated by the Linux trap
* handler .
*/
void sh_bios_vbr_init ( void )
{
unsigned long vbr ;
if ( unlikely ( gdb_vbr_vector ) )
return ;
__asm__ __volatile__ ( " stc vbr, %0 " : " =r " ( vbr ) ) ;
2010-01-12 12:42:52 +03:00
if ( vbr ) {
gdb_vbr_vector = ( void * ) ( vbr + 0x100 ) ;
printk ( KERN_NOTICE " Setting GDB trap vector to %p \n " ,
gdb_vbr_vector ) ;
} else
printk ( KERN_NOTICE " SH-BIOS not detected \n " ) ;
2010-01-12 08:50:43 +03:00
}
/**
* sh_bios_vbr_reload - Re - load the system VBR from the BIOS vector .
*
* This can be used by save / restore code to reinitialize the system VBR
* from the fixed BIOS VBR . A no - op if no BIOS VBR is known .
*/
void sh_bios_vbr_reload ( void )
{
if ( gdb_vbr_vector )
__asm__ __volatile__ (
" ldc %0, vbr "
:
: " r " ( ( ( unsigned long ) gdb_vbr_vector ) - 0x100 )
: " memory "
) ;
}
2010-01-12 09:31:20 +03:00
2013-04-30 03:17:18 +04:00
# ifdef CONFIG_EARLY_PRINTK
2010-01-12 09:31:20 +03:00
/*
* Print a string through the BIOS
*/
static void sh_console_write ( struct console * co , const char * s ,
unsigned count )
{
sh_bios_console_write ( s , count ) ;
}
/*
* Setup initial baud / bits / parity . We do two things here :
* - construct a cflag setting for the first rs_open ( )
* - initialize the serial port
* Return non - zero if we didn ' t find a serial port .
*/
static int __init sh_console_setup ( struct console * co , char * options )
{
int cflag = CREAD | HUPCL | CLOCAL ;
/*
* Now construct a cflag setting .
* TODO : this is a totally bogus cflag , as we have
* no idea what serial settings the BIOS is using , or
* even if its using the serial port at all .
*/
cflag | = B115200 | CS8 | /*no parity*/ 0 ;
co - > cflag = cflag ;
return 0 ;
}
static struct console bios_console = {
. name = " bios " ,
. write = sh_console_write ,
. setup = sh_console_setup ,
. flags = CON_PRINTBUFFER ,
. index = - 1 ,
} ;
static int __init setup_early_printk ( char * buf )
{
int keep_early = 0 ;
if ( ! buf )
return 0 ;
if ( strstr ( buf , " keep " ) )
keep_early = 1 ;
if ( ! strncmp ( buf , " bios " , 4 ) )
early_console = & bios_console ;
if ( likely ( early_console ) ) {
if ( keep_early )
early_console - > flags & = ~ CON_BOOT ;
else
early_console - > flags | = CON_BOOT ;
register_console ( early_console ) ;
}
return 0 ;
}
early_param ( " earlyprintk " , setup_early_printk ) ;
2013-04-30 03:17:18 +04:00
# endif