2005-07-27 11:44:44 -07:00
/*
* misc . c
*
* This is a collection of several routines from gzip - 1.0 .3
* adapted for Linux .
*
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
* puts by Nick Holloway 1993 , better puts by Martin Mares 1995
2007-10-20 01:08:50 +02:00
* adaptation for Linux / CRIS Axis Communications AB , 1999
2005-07-27 11:44:44 -07:00
*
*/
/* where the piggybacked kernel image expects itself to live.
* it is the same address we use when we network load an uncompressed
* image into DRAM , and it is the address the kernel is linked to live
* at by vmlinux . lds . S
*/
# define KERNEL_LOAD_ADR 0x40004000
# include <linux/types.h>
2009-04-21 11:44:57 +02:00
# ifdef CONFIG_ETRAX_ARCH_V32
2007-11-30 17:16:09 +01:00
# include <hwregs/reg_rdwr.h>
# include <hwregs/reg_map.h>
# include <hwregs/ser_defs.h>
# include <hwregs/pinmux_defs.h>
# ifdef CONFIG_CRIS_MACH_ARTPEC3
# include <hwregs/clkgen_defs.h>
# endif
2009-04-21 11:44:57 +02:00
# else
# include <arch/svinto.h>
# endif
2005-07-27 11:44:44 -07:00
/*
* gzip declarations
*/
# define OF(args) args
# define STATIC static
2009-04-21 11:44:57 +02:00
void * memset ( void * s , int c , size_t n ) ;
void * memcpy ( void * __dest , __const void * __src , size_t __n ) ;
2005-07-27 11:44:44 -07:00
2009-04-21 11:44:57 +02:00
# define memzero(s, n) memset((s), 0, (n))
2005-07-27 11:44:44 -07:00
typedef unsigned char uch ;
typedef unsigned short ush ;
typedef unsigned long ulg ;
# define WSIZE 0x8000 /* Window size must be at least 32k, */
/* and a power of two */
static uch * inbuf ; /* input buffer */
static uch window [ WSIZE ] ; /* Sliding window buffer */
unsigned inptr = 0 ; /* index of next byte to be processed in inbuf
* After decompression it will contain the
* compressed size , and head . S will read it .
*/
static unsigned outcnt = 0 ; /* bytes in output buffer */
/* gzip flag byte */
# define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
# define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
# define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
# define ORIG_NAME 0x08 /* bit 3 set: original file name present */
# define COMMENT 0x10 /* bit 4 set: file comment present */
# define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
# define RESERVED 0xC0 /* bit 6,7: reserved */
2009-04-21 11:44:57 +02:00
# define get_byte() (inbuf[inptr++])
2005-07-27 11:44:44 -07:00
/* Diagnostic functions */
# ifdef DEBUG
2009-04-21 11:44:57 +02:00
# define Assert(cond, msg) do { \
if ( ! ( cond ) ) \
error ( msg ) ; \
} while ( 0 )
2005-07-27 11:44:44 -07:00
# define Trace(x) fprintf x
2009-04-21 11:44:57 +02:00
# define Tracev(x) do { \
if ( verbose ) \
fprintf x ; \
} while ( 0 )
# define Tracevv(x) do { \
if ( verbose > 1 ) \
fprintf x ; \
} while ( 0 )
# define Tracec(c, x) do { \
if ( verbose & & ( c ) ) \
fprintf x ; \
} while ( 0 )
# define Tracecv(c, x) do { \
if ( verbose > 1 & & ( c ) ) \
fprintf x ; \
} while ( 0 )
2005-07-27 11:44:44 -07:00
# else
2009-04-21 11:44:57 +02:00
# define Assert(cond, msg)
2005-07-27 11:44:44 -07:00
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
2009-04-21 11:44:57 +02:00
# define Tracec(c, x)
# define Tracecv(c, x)
2005-07-27 11:44:44 -07:00
# endif
static void flush_window ( void ) ;
static void error ( char * m ) ;
2010-08-03 18:12:47 +02:00
static void aputs ( const char * s ) ;
2005-07-27 11:44:44 -07:00
extern char * input_data ; /* lives in head.S */
2008-07-25 01:45:44 -07:00
static long bytes_out ;
2005-07-27 11:44:44 -07:00
static uch * output_data ;
2008-07-25 01:45:44 -07:00
static unsigned long output_ptr ;
2005-07-27 11:44:44 -07:00
/* the "heap" is put directly after the BSS ends, at end */
extern int _end ;
static long free_mem_ptr = ( long ) & _end ;
2008-07-25 01:45:44 -07:00
static long free_mem_end_ptr ;
2005-07-27 11:44:44 -07:00
# include "../../../../../lib/inflate.c"
/* decompressor info and error messages to serial console */
2009-04-21 11:44:57 +02:00
# ifdef CONFIG_ETRAX_ARCH_V32
static inline void serout ( const char * s , reg_scope_instances regi_ser )
2005-07-27 11:44:44 -07:00
{
reg_ser_rs_stat_din rs ;
reg_ser_rw_dout dout = { . data = * s } ;
do {
rs = REG_RD ( ser , regi_ser , rs_stat_din ) ;
}
2007-10-20 01:08:50 +02:00
while ( ! rs . tr_rdy ) ; /* Wait for transceiver. */
2005-07-27 11:44:44 -07:00
REG_WR ( ser , regi_ser , rw_dout , dout ) ;
}
2010-08-03 18:12:47 +02:00
# define SEROUT(S, N) \
do { \
serout ( S , regi_ser # # N ) ; \
s + + ; \
} while ( 0 )
# else
# define SEROUT(S, N) do { \
while ( ! ( * R_SERIAL # # N # # _STATUS & ( 1 < < 5 ) ) ) \
; \
* R_SERIAL # # N # # _TR_DATA = * s + + ; \
} while ( 0 )
2009-04-21 11:44:57 +02:00
# endif
2005-07-27 11:44:44 -07:00
2010-08-03 18:12:47 +02:00
static void aputs ( const char * s )
2005-07-27 11:44:44 -07:00
{
# ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
while ( * s ) {
# ifdef CONFIG_ETRAX_DEBUG_PORT0
2010-08-03 18:12:47 +02:00
SEROUT ( s , 0 ) ;
2005-07-27 11:44:44 -07:00
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT1
2010-08-03 18:12:47 +02:00
SEROUT ( s , 1 ) ;
2005-07-27 11:44:44 -07:00
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT2
2010-08-03 18:12:47 +02:00
SEROUT ( s , 2 ) ;
2005-07-27 11:44:44 -07:00
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT3
2010-08-03 18:12:47 +02:00
SEROUT ( s , 3 ) ;
2009-04-21 11:44:57 +02:00
# endif
2005-07-27 11:44:44 -07:00
}
2010-08-03 18:12:47 +02:00
# endif /* CONFIG_ETRAX_DEBUG_PORT_NULL */
2005-07-27 11:44:44 -07:00
}
2009-04-21 11:44:57 +02:00
void * memset ( void * s , int c , size_t n )
2005-07-27 11:44:44 -07:00
{
int i ;
char * ss = ( char * ) s ;
for ( i = 0 ; i < n ; i + + ) ss [ i ] = c ;
2007-11-30 17:16:09 +01:00
return s ;
2005-07-27 11:44:44 -07:00
}
2009-04-21 11:44:57 +02:00
void * memcpy ( void * __dest , __const void * __src , size_t __n )
2005-07-27 11:44:44 -07:00
{
int i ;
char * d = ( char * ) __dest , * s = ( char * ) __src ;
2009-04-21 11:44:57 +02:00
for ( i = 0 ; i < __n ; i + + )
d [ i ] = s [ i ] ;
2007-11-30 17:16:09 +01:00
return __dest ;
2005-07-27 11:44:44 -07:00
}
/* ===========================================================================
* Write the output window window [ 0. . outcnt - 1 ] and update crc and bytes_out .
* ( Used for the decompressed data only . )
*/
2009-04-21 11:44:57 +02:00
static void flush_window ( void )
2005-07-27 11:44:44 -07:00
{
2009-04-21 11:44:57 +02:00
ulg c = crc ; /* temporary variable */
unsigned n ;
uch * in , * out , ch ;
in = window ;
out = & output_data [ output_ptr ] ;
for ( n = 0 ; n < outcnt ; n + + ) {
ch = * out = * in ;
out + + ;
in + + ;
c = crc_32_tab [ ( ( int ) c ^ ch ) & 0xff ] ^ ( c > > 8 ) ;
}
crc = c ;
bytes_out + = ( ulg ) outcnt ;
output_ptr + = ( ulg ) outcnt ;
outcnt = 0 ;
2005-07-27 11:44:44 -07:00
}
2009-04-21 11:44:57 +02:00
static void error ( char * x )
2005-07-27 11:44:44 -07:00
{
2010-08-03 18:12:47 +02:00
aputs ( " \n \n " ) ;
aputs ( x ) ;
aputs ( " \n \n -- System halted \n " ) ;
2005-07-27 11:44:44 -07:00
while ( 1 ) ; /* Halt */
}
2009-04-21 11:44:57 +02:00
void setup_normal_output_buffer ( void )
2005-07-27 11:44:44 -07:00
{
output_data = ( char * ) KERNEL_LOAD_ADR ;
}
2009-04-21 11:44:57 +02:00
# ifdef CONFIG_ETRAX_ARCH_V32
static inline void serial_setup ( reg_scope_instances regi_ser )
2005-07-27 11:44:44 -07:00
{
reg_ser_rw_xoff xoff ;
reg_ser_rw_tr_ctrl tr_ctrl ;
reg_ser_rw_rec_ctrl rec_ctrl ;
reg_ser_rw_tr_baud_div tr_baud ;
reg_ser_rw_rec_baud_div rec_baud ;
/* Turn off XOFF. */
xoff = REG_RD ( ser , regi_ser , rw_xoff ) ;
xoff . chr = 0 ;
xoff . automatic = regk_ser_no ;
REG_WR ( ser , regi_ser , rw_xoff , xoff ) ;
/* Set baudrate and stopbits. */
tr_ctrl = REG_RD ( ser , regi_ser , rw_tr_ctrl ) ;
rec_ctrl = REG_RD ( ser , regi_ser , rw_rec_ctrl ) ;
tr_baud = REG_RD ( ser , regi_ser , rw_tr_baud_div ) ;
rec_baud = REG_RD ( ser , regi_ser , rw_rec_baud_div ) ;
tr_ctrl . stop_bits = 1 ; /* 2 stop bits. */
2007-11-30 17:16:09 +01:00
tr_ctrl . en = 1 ; /* enable transmitter */
rec_ctrl . en = 1 ; /* enabler receiver */
2005-07-27 11:44:44 -07:00
/*
2007-11-30 17:16:09 +01:00
* The baudrate setup used to be a bit fishy , but now transmitter and
* receiver are both set to the intended baud rate , 115200.
* The magic value is 29.493 MHz .
2005-07-27 11:44:44 -07:00
*/
tr_ctrl . base_freq = regk_ser_f29_493 ;
rec_ctrl . base_freq = regk_ser_f29_493 ;
2007-11-30 17:16:09 +01:00
tr_baud . div = ( 29493000 / 8 ) / 115200 ;
2005-07-27 11:44:44 -07:00
rec_baud . div = ( 29493000 / 8 ) / 115200 ;
REG_WR ( ser , regi_ser , rw_tr_ctrl , tr_ctrl ) ;
REG_WR ( ser , regi_ser , rw_tr_baud_div , tr_baud ) ;
REG_WR ( ser , regi_ser , rw_rec_ctrl , rec_ctrl ) ;
REG_WR ( ser , regi_ser , rw_rec_baud_div , rec_baud ) ;
}
2009-04-21 11:44:57 +02:00
# endif
2005-07-27 11:44:44 -07:00
2009-04-21 11:44:57 +02:00
void decompress_kernel ( void )
2005-07-27 11:44:44 -07:00
{
char revision ;
2009-04-21 11:44:57 +02:00
char compile_rev ;
2005-07-27 11:44:44 -07:00
2009-04-21 11:44:57 +02:00
# ifdef CONFIG_ETRAX_ARCH_V32
/* Need at least a CRISv32 to run. */
compile_rev = 32 ;
2007-11-30 17:16:09 +01:00
# if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
defined ( CONFIG_ETRAX_DEBUG_PORT2 ) | | \
defined ( CONFIG_ETRAX_DEBUG_PORT3 )
reg_pinmux_rw_hwprot hwprot ;
# ifdef CONFIG_CRIS_MACH_ARTPEC3
reg_clkgen_rw_clk_ctrl clk_ctrl ;
/* Enable corresponding clock region when serial 1..3 selected */
clk_ctrl = REG_RD ( clkgen , regi_clkgen , rw_clk_ctrl ) ;
clk_ctrl . sser_ser_dma6_7 = regk_clkgen_yes ;
REG_WR ( clkgen , regi_clkgen , rw_clk_ctrl , clk_ctrl ) ;
# endif
/* pinmux setup for ports 1..3 */
hwprot = REG_RD ( pinmux , regi_pinmux , rw_hwprot ) ;
# endif
2005-07-27 11:44:44 -07:00
2009-04-21 11:44:57 +02:00
2005-07-27 11:44:44 -07:00
# ifdef CONFIG_ETRAX_DEBUG_PORT0
serial_setup ( regi_ser0 ) ;
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT1
2007-11-30 17:16:09 +01:00
hwprot . ser1 = regk_pinmux_yes ;
2005-07-27 11:44:44 -07:00
serial_setup ( regi_ser1 ) ;
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT2
2007-11-30 17:16:09 +01:00
hwprot . ser2 = regk_pinmux_yes ;
2005-07-27 11:44:44 -07:00
serial_setup ( regi_ser2 ) ;
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT3
2007-11-30 17:16:09 +01:00
hwprot . ser3 = regk_pinmux_yes ;
2005-07-27 11:44:44 -07:00
serial_setup ( regi_ser3 ) ;
# endif
2007-11-30 17:16:09 +01:00
# if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
defined ( CONFIG_ETRAX_DEBUG_PORT2 ) | | \
defined ( CONFIG_ETRAX_DEBUG_PORT3 )
REG_WR ( pinmux , regi_pinmux , rw_hwprot , hwprot ) ;
# endif
/* input_data is set in head.S */
inbuf = input_data ;
2009-04-21 11:44:57 +02:00
# else /* CRISv10 */
/* Need at least a crisv10 to run. */
compile_rev = 10 ;
/* input_data is set in head.S */
inbuf = input_data ;
# ifdef CONFIG_ETRAX_DEBUG_PORT0
* R_SERIAL0_XOFF = 0 ;
* R_SERIAL0_BAUD = 0x99 ;
* R_SERIAL0_TR_CTRL = 0x40 ;
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT1
* R_SERIAL1_XOFF = 0 ;
* R_SERIAL1_BAUD = 0x99 ;
* R_SERIAL1_TR_CTRL = 0x40 ;
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT2
* R_GEN_CONFIG = 0x08 ;
* R_SERIAL2_XOFF = 0 ;
* R_SERIAL2_BAUD = 0x99 ;
* R_SERIAL2_TR_CTRL = 0x40 ;
# endif
# ifdef CONFIG_ETRAX_DEBUG_PORT3
* R_GEN_CONFIG = 0x100 ;
* R_SERIAL3_XOFF = 0 ;
* R_SERIAL3_BAUD = 0x99 ;
* R_SERIAL3_TR_CTRL = 0x40 ;
# endif
# endif
2005-07-27 11:44:44 -07:00
setup_normal_output_buffer ( ) ;
makecrc ( ) ;
__asm__ volatile ( " move $vr,%0 " : " =rm " ( revision ) ) ;
2009-04-21 11:44:57 +02:00
if ( revision < compile_rev ) {
# ifdef CONFIG_ETRAX_ARCH_V32
2010-08-03 18:12:47 +02:00
aputs ( " You need at least ETRAX FS to run Linux 2.6/crisv32 \n " ) ;
2009-04-21 11:44:57 +02:00
# else
2010-08-03 18:12:47 +02:00
aputs ( " You need an ETRAX 100LX to run linux 2.6/crisv10 \n " ) ;
2009-04-21 11:44:57 +02:00
# endif
2005-07-27 11:44:44 -07:00
while ( 1 ) ;
}
2010-08-03 18:12:47 +02:00
aputs ( " Uncompressing Linux... \n " ) ;
2005-07-27 11:44:44 -07:00
gunzip ( ) ;
2010-08-03 18:12:47 +02:00
aputs ( " Done. Now booting the kernel \n " ) ;
2005-07-27 11:44:44 -07:00
}