2009-06-24 13:12:57 +04:00
/*
* Carsten Langgaard , carstenl @ mips . com
* Copyright ( C ) 1999 , 2000 MIPS Technologies , Inc . All rights reserved .
*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License ( Version 2 ) as
* published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston MA 02111 - 1307 , USA .
*
* Putting things on the screen / serial line using YAMONs facilities .
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/serial_reg.h>
# include <linux/spinlock.h>
2017-01-29 05:05:57 +03:00
# include <linux/export.h>
2009-06-24 13:12:57 +04:00
# include <linux/string.h>
# include <linux/io.h>
# include <asm/bootinfo.h>
# include <asm/mach-ar7/ar7.h>
# include <asm/mach-ar7/prom.h>
# define MAX_ENTRY 80
struct env_var {
2010-01-31 22:38:19 +03:00
char * name ;
char * value ;
2009-06-24 13:12:57 +04:00
} ;
static struct env_var adam2_env [ MAX_ENTRY ] ;
char * prom_getenv ( const char * name )
{
int i ;
2010-01-31 22:38:19 +03:00
2009-06-24 13:12:57 +04:00
for ( i = 0 ; ( i < MAX_ENTRY ) & & adam2_env [ i ] . name ; i + + )
if ( ! strcmp ( name , adam2_env [ i ] . name ) )
return adam2_env [ i ] . value ;
return NULL ;
}
EXPORT_SYMBOL ( prom_getenv ) ;
static void __init ar7_init_cmdline ( int argc , char * argv [ ] )
{
2010-01-26 12:07:02 +03:00
int i ;
2009-06-24 13:12:57 +04:00
2010-01-26 12:07:02 +03:00
for ( i = 1 ; i < argc ; i + + ) {
strlcat ( arcs_cmdline , argv [ i ] , COMMAND_LINE_SIZE ) ;
if ( i < ( argc - 1 ) )
strlcat ( arcs_cmdline , " " , COMMAND_LINE_SIZE ) ;
2009-06-24 13:12:57 +04:00
}
}
struct psbl_rec {
2010-01-31 22:38:19 +03:00
u32 psbl_size ;
u32 env_base ;
u32 env_size ;
u32 ffs_base ;
u32 ffs_size ;
2009-06-24 13:12:57 +04:00
} ;
2011-11-15 23:23:43 +04:00
static const char psp_env_version [ ] __initconst = " TIENV0.8 " ;
2009-06-24 13:12:57 +04:00
struct psp_env_chunk {
2010-01-31 22:38:19 +03:00
u8 num ;
u8 ctrl ;
u16 csum ;
u8 len ;
char data [ 11 ] ;
2011-06-12 22:57:19 +04:00
} __packed ;
2009-06-24 13:12:57 +04:00
struct psp_var_map_entry {
2010-01-31 22:38:19 +03:00
u8 num ;
char * value ;
2009-06-24 13:12:57 +04:00
} ;
2011-11-15 23:23:43 +04:00
static const struct psp_var_map_entry psp_var_map [ ] = {
2010-01-31 22:38:19 +03:00
{ 1 , " cpufrequency " } ,
{ 2 , " memsize " } ,
{ 3 , " flashsize " } ,
{ 4 , " modetty0 " } ,
{ 5 , " modetty1 " } ,
{ 8 , " maca " } ,
{ 9 , " macb " } ,
{ 28 , " sysfrequency " } ,
{ 38 , " mipsfrequency " } ,
2009-06-24 13:12:57 +04:00
} ;
/*
Well - known variable ( num is looked up in table above for matching variable name )
Example : cpufrequency = 211968000
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
| 01 | CTRL | CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \ 0 | FF
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
Name = Value pair in a single chunk
Example : NAME = VALUE
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
| 00 | CTRL | CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \ 0
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
Name = Value pair in 2 chunks ( len is the number of chunks )
Example : bootloaderVersion = 1.3 .7 .15
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
| 00 | CTRL | CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
| _e | _r | _s | _i | _o | _n | \ 0 | _1 | _ . | _3 | _ . | _7 | _ . | _1 | _5 | \ 0
+ - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - -
Data is padded with 0xFF
*/
# define PSP_ENV_SIZE 4096
static char psp_env_data [ PSP_ENV_SIZE ] = { 0 , } ;
static char * __init lookup_psp_var_map ( u8 num )
{
int i ;
2009-07-30 00:02:53 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( psp_var_map ) ; i + + )
2009-06-24 13:12:57 +04:00
if ( psp_var_map [ i ] . num = = num )
return psp_var_map [ i ] . value ;
return NULL ;
}
static void __init add_adam2_var ( char * name , char * value )
{
int i ;
2010-01-31 22:38:19 +03:00
2009-06-24 13:12:57 +04:00
for ( i = 0 ; i < MAX_ENTRY ; i + + ) {
if ( ! adam2_env [ i ] . name ) {
adam2_env [ i ] . name = name ;
adam2_env [ i ] . value = value ;
return ;
} else if ( ! strcmp ( adam2_env [ i ] . name , name ) ) {
adam2_env [ i ] . value = value ;
return ;
}
}
}
static int __init parse_psp_env ( void * psp_env_base )
{
int i , n ;
char * name , * value ;
struct psp_env_chunk * chunks = ( struct psp_env_chunk * ) psp_env_data ;
memcpy_fromio ( chunks , psp_env_base , PSP_ENV_SIZE ) ;
i = 1 ;
n = PSP_ENV_SIZE / sizeof ( struct psp_env_chunk ) ;
while ( i < n ) {
if ( ( chunks [ i ] . num = = 0xff ) | | ( ( i + chunks [ i ] . len ) > n ) )
break ;
value = chunks [ i ] . data ;
if ( chunks [ i ] . num ) {
name = lookup_psp_var_map ( chunks [ i ] . num ) ;
} else {
name = value ;
value + = strlen ( name ) + 1 ;
}
if ( name )
add_adam2_var ( name , value ) ;
i + = chunks [ i ] . len ;
}
return 0 ;
}
static void __init ar7_init_env ( struct env_var * env )
{
int i ;
struct psbl_rec * psbl = ( struct psbl_rec * ) ( KSEG1ADDR ( 0x14000300 ) ) ;
void * psp_env = ( void * ) KSEG1ADDR ( psbl - > env_base ) ;
if ( strcmp ( psp_env , psp_env_version ) = = 0 ) {
parse_psp_env ( psp_env ) ;
} else {
for ( i = 0 ; i < MAX_ENTRY ; i + + , env + + )
if ( env - > name )
add_adam2_var ( env - > name , env - > value ) ;
}
}
static void __init console_config ( void )
{
# ifdef CONFIG_SERIAL_8250_CONSOLE
char console_string [ 40 ] ;
int baud = 0 ;
char parity = ' \0 ' , bits = ' \0 ' , flow = ' \0 ' ;
char * s , * p ;
2010-01-26 12:08:34 +03:00
if ( strstr ( arcs_cmdline , " console= " ) )
2009-06-24 13:12:57 +04:00
return ;
s = prom_getenv ( " modetty0 " ) ;
if ( s ) {
baud = simple_strtoul ( s , & p , 10 ) ;
s = p ;
if ( * s = = ' , ' )
s + + ;
if ( * s )
parity = * s + + ;
if ( * s = = ' , ' )
s + + ;
if ( * s )
bits = * s + + ;
if ( * s = = ' , ' )
s + + ;
if ( * s = = ' h ' )
flow = ' r ' ;
}
if ( baud = = 0 )
baud = 38400 ;
if ( parity ! = ' n ' & & parity ! = ' o ' & & parity ! = ' e ' )
parity = ' n ' ;
if ( bits ! = ' 7 ' & & bits ! = ' 8 ' )
bits = ' 8 ' ;
if ( flow = = ' r ' )
sprintf ( console_string , " console=ttyS0,%d%c%c%c " , baud ,
parity , bits , flow ) ;
else
sprintf ( console_string , " console=ttyS0,%d%c%c " , baud , parity ,
bits ) ;
2010-01-26 12:07:02 +03:00
strlcat ( arcs_cmdline , console_string , COMMAND_LINE_SIZE ) ;
2009-06-24 13:12:57 +04:00
# endif
}
void __init prom_init ( void )
{
ar7_init_cmdline ( fw_arg0 , ( char * * ) fw_arg1 ) ;
ar7_init_env ( ( struct env_var * ) fw_arg2 ) ;
console_config ( ) ;
2010-08-29 19:08:41 +04:00
ar7_gpio_init ( ) ;
2009-06-24 13:12:57 +04:00
}
# define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
static inline unsigned int serial_in ( int offset )
{
return readl ( ( void * ) PORT ( offset ) ) ;
}
static inline void serial_out ( int offset , int value )
{
writel ( value , ( void * ) PORT ( offset ) ) ;
}
int prom_putchar ( char c )
{
while ( ( serial_in ( UART_LSR ) & UART_LSR_TEMT ) = = 0 )
;
serial_out ( UART_TX , c ) ;
return 1 ;
}