|
From: Erik M. <er...@us...> - 2001-10-07 19:04:28
|
Update of /cvsroot/blob/blob/src/blob
In directory usw-pr-cvs1:/tmp/cvs-serv26965/blob
Modified Files:
Makefile.am
Added Files:
chkmem.c clock.c debug.c flash.c flashasm.S linux.c main.c
memory.c param_block.c reboot.c rest-ld-script testmem2.S
trampoline.S uucodec.c
Log Message:
Move all files to either blob/ or lib/
--- NEW FILE: chkmem.c ---
/*-------------------------------------------------------------------------
* Filename: chkmem.c
* Version: $Id: chkmem.c,v 1.1 2001/10/07 19:04:25 erikm Exp $
* Copyright: Copyright (C) 2001, Stefan Eletzhofer
* Author: Stefan Eletzhofer <ste...@ww...>
* Description: memory test functions
* Created at: Mit Sep 26 19:20:24 CEST 2001
* Modified by:
* Modified at:
*-----------------------------------------------------------------------*/
/*
* chkmem.c: Utility to test memory integrity
*
* Copyright (C) 2001 Stefan Eletzhofer <ste...@ww...>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
#ident "$Id: chkmem.c,v 1.1 2001/10/07 19:04:25 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "main.h"
#include "command.h"
#include "types.h"
#include "sa1100.h"
#include "serial.h"
#include "time.h"
#include "util.h"
#include "memory.h"
/*********************************************************************/
/** DEFINES *********************************************************/
/*********************************************************************/
/* define this to 1 for debug */
#define CHKMEM_DEBUG 1
/* show every X bytes of memory during test */
#define CHKMEM_SHOWEVERY (1<<14)
/* more readable IMHO */
#define MEM( x ) (*((u32 *)x))
/* Optimization barrier */
/* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory")
#define MAKE32FROM8(X) (u32) (X | X << 8 | X << 16 | X << 24)
#define CHKMEM_ERR (-1)
#define CHKMEM_OK (0)
#if CHKMEM_DEBUG
# define SHOWFUNC() SerialOutputString("chkmem: method: "__FUNCTION__ "\n" ); \
SerialOutputString(" p1=0x"); \
SerialOutputHex((u32)bp1); \
SerialOutputString(" p2=0x"); \
SerialOutputHex((u32)bp2); \
SerialOutputString(" count=0x"); \
SerialOutputHex((u32)count); \
SerialOutputString("\n");
#else
# define SHOWFUNC() SerialOutputString("chkmem: method: "__FUNCTION__ "\n" );
#endif
#define SKIPBLOBMEM( STARTADR ) while ( STARTADR < (BLOB_RAM_BASE + 0x00100000) ) STARTADR++;
#define CHKMEM_MAXERR 64
#define CHKMEM_PUSHERR( ADR ) { chkmem_errlist[ chkmem_errs % CHKMEM_MAXERR ] = ADR; \
chkmem_errs++; }
/*********************************************************************/
/** MODULE GLOBALS *************************************************/
/*********************************************************************/
static u32 showevery;
/* list of failed adresses */
static u32 chkmem_errlist[ CHKMEM_MAXERR ];
static int chkmem_errs;
/*********************************************************************/
/** TYPES *********************************************************/
/*********************************************************************/
typedef int (*memtestfunc_t)( u32, u32, u32, u32 *);
/*********************************************************************/
/** FORWARDS *******************************************************/
/*********************************************************************/
static int ChkMemErr( void );
static int ChkMemMovInv( u32 start, u32 end, u32 pattern, u32 *badadr );
static int ChkMemAdrTst( u32 start, u32 end, u32 pattern, u32 *badadr );
static int ChkMemHardcore( u32 start, u32 end, u32 pattern, u32 *badadr );
static void showrun( u32 run );
static void showadr( volatile u32 *adr );
/* Charles Cazabon test methods */
static int test_or_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_and_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_seqinc_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_checkerboard_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_solidbits_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_blockseq_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_walkbits_comparison (u32 *bp1, u32 *bp2, u32 count, int mode);
static int test_bitspread_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_bitflip_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_stuck_address (u32 *bp1, u32 *bp2, u32 count);
/*********************************************************************/
/** EXPORTED FUNCTIONS ***********************************************/
/*********************************************************************/
/*********************************************************************
* ChkMem
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Command entry, memory test method dispatcher
*
*/
int ChkMem( int argc, char *argv[] )
{
memtestfunc_t method;
int area;
u32 start = 0L;
u32 end = 0L;
u32 badaddr = 0L;
u32 repcount = 0L;
/* check args */
if ( argc < 2 ) {
SerialOutputString("*** not enough arguments\n");
return CHKMEM_ERR;
}
/* reset error counter */
chkmem_errs = 0;
/* get verbosity level */
showevery = CHKMEM_SHOWEVERY;
if ( argc > 2 ) {
if(strtoval(argv[2], &showevery) < 0) {
SerialOutputString("*** not a value\n");
return CHKMEM_ERR;
}
if ( showevery > 0 ) {
showevery = 1<<showevery;
} else {
/* never show address */
showevery = 0xffffffff;
}
}
/* get repeat count */
repcount = 1;
if ( argc > 3 ) {
if ( strtoval(argv[3], &repcount ) < 0 ) {
SerialOutputString("*** not a value\n");
return CHKMEM_ERR;
}
}
SerialOutputString(argv[0]);
SerialOutputString(": display every 0x");
SerialOutputHex(showevery);
SerialOutputString(" bytes\n");
/* set memory test method */
switch ( *argv[1] ) {
case '0':
method = ChkMemMovInv;
break;
case '1':
method = ChkMemAdrTst;
break;
case '2':
method = ChkMemHardcore;
break;
default:
SerialOutputString("*** unknown method\n");
return CHKMEM_ERR;
break;
}
while ( repcount-- ) {
/* test all known memory areas */
for (area = 0; area < NUM_MEM_AREAS; area++) {
if(memory_map[area].used) {
start = memory_map[area].start;
end = start + memory_map[area].len;
if ( method(start, end, 0x5555aaaa, &badaddr) != CHKMEM_OK ) {
CHKMEM_PUSHERR( badaddr );
}
}
}
}
if ( chkmem_errs == 0 ) {
SerialOutputString("\n*** no error found\n");
} else {
ChkMemErr();
}
return CHKMEM_OK;
}
static char chkmemhelp[] = "chkmem [method] {verbosity:1..F} {repeat-count}\nmethod=0: move-inverse test\n"
"method=1: address test\n"
"method=2: hardcore test\n"
"verbosity: display every 2^n address during test\n";
__commandlist(ChkMem, "chkmem", chkmemhelp);
/*********************************************************************/
/** STATIC FUNCTIONS ************************************************/
/*********************************************************************/
/*********************************************************************
* showrun
*
* AUTOR: SELETZ
* REVISED:
*
* Shows current memory test run
*
*/
static void showrun( u32 run )
{
SerialOutputString( "\r\nrun " );
SerialOutputHex( run );
SerialOutputString( "\n" );
}
/*********************************************************************
* showadr
*
* AUTOR: SELETZ
* REVISED:
*
* display <adr> every <showevery> bytes.
*
*/
static void showadr( volatile u32 *adr )
{
if ( ((u32)adr) % showevery == 0 ) {
SerialOutputString("\r");
SerialOutputHex( (u32)adr );
}
}
/*********************************************************************
* ChkMemErr
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Reports memory check errors
*
*/
static int ChkMemErr( void )
{
int i;
SerialOutputString("\n*** memory errors:\n");
for ( i=0; i< chkmem_errs % CHKMEM_MAXERR; i++ ) {
SerialOutputHex( i );
SerialOutputString(": 0x");
SerialOutputHex(chkmem_errlist[i]);
SerialOutputString("\n");
}
return CHKMEM_OK;
}
/*********************************************************************
* ChkMemMovInv
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Moving-Inverse Memory Test
*
* Test method (from GNU/memtest86 utility):
* 1) Fill memory with a pattern
* 2) Starting at the lowest address
* 2a check that the pattern has not changed
* 2b write the patterns complement
* 2c increment the address
* repeat 2a - 2c
* 3) Starting at the highest address
* 3a check that the pattern has not changed
* 3b write the patterns complement
* 3c decrement the address
* repeat 3a - 3c
*
* returns 1 if memory failure, returns failed
* address in badadr
*
*/
static int ChkMemMovInv( u32 start, u32 end, u32 pattern, u32 *badadr )
{
int ret = 1;
register u32 p;
register u32 tst;
SerialOutputString("\nchkmem: move-inverse method\n");
SKIPBLOBMEM( start );
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: start(0x");
SerialOutputHex(start);
SerialOutputString(") - end(0x");
SerialOutputHex(end);
SerialOutputString(")\n");
#endif
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: fillup\n");
#endif
/* fill mem with pattern */
p=start;
while ( p<end ) {
MEM( p ) = pattern;
barrier();
p += 4;
}
#if CHKMEM_DEBUG
SerialOutputString("\rChkMem: bottom-up\n");
#endif
/* bottom-up test */
p=start;
while ( p<end ) {
showadr( (u32*)p );
tst = MEM( p );
if ( tst != pattern ) {
goto DONE;
}
MEM( p ) = ~pattern;
barrier();
p += 4;
}
pattern = ~pattern;
#if CHKMEM_DEBUG
SerialOutputString("\rChkMem: top-down\n");
#endif
/* top-down test */
p=end-4;
while ( p>=start ) {
showadr( (u32*)p );
tst = MEM( p );
if ( tst != pattern ) {
goto DONE;
}
MEM( p ) = ~pattern;
barrier();
p -= 4;
}
/* no error if we reach this point */
ret = 0;
DONE:
if ( ret != 0 && badadr ) {
*badadr = p;
}
return ret;
}
/*********************************************************************
* ChkMemAdrTst
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Writes every memory location with its adress, then checks address
*
* returns 1 if memory failure, returns failed
* address in badadr
*
*/
static int ChkMemAdrTst( u32 start, u32 end, u32 pattern, u32 *badadr )
{
int ret = 1;
register u32 p;
register u32 tst;
SerialOutputString("\nchkmem: address test method\n");
SKIPBLOBMEM( start );
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: start(0x");
SerialOutputHex(start);
SerialOutputString(") - end(0x");
SerialOutputHex(end);
SerialOutputString(")\n");
#endif
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: fillup\n");
#endif
/* fill mem with pattern */
p=start;
while ( p<end ) {
MEM( p ) = p;
barrier();
p += 4;
}
#if CHKMEM_DEBUG
SerialOutputString("\rChkMem: bottom-up\n");
#endif
/* bottom-up test */
p=start;
while ( p<end ) {
showadr( (u32*)p );
tst = MEM( p );
if ( tst != p ) {
goto DONE;
}
p += 4;
}
/* no error if we reach this point */
ret = 0;
DONE:
if ( ret != 0 && badadr ) {
*badadr = p;
}
return ret;
}
/*********************************************************************
* ChkMemHardcore
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Hardcore memory test. Test methods based on memtest
* by Charles Cazabon <me...@di...>
*
* returns 1 if memory failure, returns failed
* address in badadr
*
*/
static int ChkMemHardcore( u32 start, u32 end, u32 pattern, u32 *badadr )
{
register u32 count;
SerialOutputString("\nchkmem: hardcore test method\n");
SKIPBLOBMEM( start );
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: start(0x");
SerialOutputHex(start);
SerialOutputString(") - end(0x");
SerialOutputHex(end);
SerialOutputString(")\n");
#endif
count = end - start;
SerialOutputHex(count);
SerialOutputString("\n");
count = (count >> 1);
SerialOutputHex(count);
SerialOutputString("\n");
test_or_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_and_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_seqinc_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_checkerboard_comparison ((u32 *)start, (u32 *)(start+count), count>>2);
test_solidbits_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_blockseq_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_walkbits_comparison((u32 *)start, (u32 *)(start+count), count>>2, 0);
test_walkbits_comparison((u32 *)start, (u32 *)(start+count), count>>2, 1);
test_bitspread_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_bitflip_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_stuck_address((u32 *)start, (u32 *)(start+count), count>>2);
/* no error if we reach this point */
if ( badadr ) {
*badadr = 0L;
}
return 0;
}
/*********************************************************************/
/** MEMTESTER FUNCTIONS *********************************************/
/*********************************************************************/
/**********************************************************************
* Original Authors of following memory test functions:
*
* Charles Cazabon <me...@di...>
*
* Copyright © 1999 Simon Kirby.
* Version 2 Copyright © 1999 Charles Cazabon.
*
*/
int
test_verify_success (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i;
for (i = 0; i < count; i++, p1++, p2++)
{
if ( MEM( p1 ) != MEM( p2 ) )
{
SerialOutputString("\nchkmem: contents differ:\n");
SerialOutputHex((u32)p1);
SerialOutputString("\n");
SerialOutputHex((u32)p2);
SerialOutputString("\n");
CHKMEM_PUSHERR( (u32)p1 );
CHKMEM_PUSHERR( (u32)p2 );
}
}
return (CHKMEM_OK);
}
int
test_or_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i;
u32 q = 0xdeadbeef;
SHOWFUNC();
for (i = 0; i < count; i++)
{
showadr( p2 );
MEM( p1++ ) |= q;
barrier();
MEM( p2++ ) |= q;
barrier();
}
return (test_verify_success (bp1, bp2, count));
}
int
test_and_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i;
u32 q = 0xdeadbeef;
SHOWFUNC();
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) &= q;
barrier();
MEM( p2++ ) &= q;
barrier();
}
return (test_verify_success (bp1, bp2, count));
}
int
test_seqinc_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i;
u32 q = 0xdeadbeef;
SHOWFUNC();
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) = MEM( p2++ ) = (i + q);
barrier();
}
return (test_verify_success (bp1, bp2, count));
}
int
test_solidbits_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 q, i, j;
SHOWFUNC();
for (j = 0; j < 64; j++)
{
showrun( j );
q = (j % 2) == 0 ? 0xFFFFFFFF : 0x00000000;
p1 = (volatile u32 *) bp1;
p2 = (volatile u32 *) bp2;
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) = MEM( p2++ ) = (i % 2) == 0 ? q : ~q;
barrier();
}
if (test_verify_success (bp1, bp2, count) == CHKMEM_ERR)
{
return (CHKMEM_ERR);
}
}
return (CHKMEM_OK);
}
int
test_checkerboard_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 q, i, j;
SHOWFUNC();
for (j = 0; j < 64; j++)
{
showrun( j );
q = (j % 2) == 0 ? 0x55555555 : 0xAAAAAAAA;
p1 = (volatile u32 *) bp1;
p2 = (volatile u32 *) bp2;
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) = MEM( p2++ ) = (i % 2) == 0 ? q : ~q;
barrier();
}
if (test_verify_success (bp1, bp2, count) == CHKMEM_ERR)
{
return (CHKMEM_ERR);
}
}
return (CHKMEM_OK);
}
int
test_blockseq_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i, j;
SHOWFUNC();
for (j = 0; j < 256; j++)
{
showrun( j );
p1 = (volatile u32 *) bp1;
p2 = (volatile u32 *) bp2;
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) = MEM( p2++ ) = MAKE32FROM8 (j);
barrier();
}
if (test_verify_success (bp1, bp2, count) == CHKMEM_ERR)
{
return (CHKMEM_ERR);
}
}
return (CHKMEM_OK);
}
int
test_walkbits_comparison (u32 *bp1, u32 *bp2, u32 count, int m)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i, j;
SHOWFUNC();
for (j = 0; j < 64; j++)
{
showrun( j );
p1 = (volatile u32 *) bp1;
p2 = (volatile u32 *) bp2;
for (i = 0; i < count; i++)
{
if (j < 32) /* Walk it up. */
{
showadr( p1 );
MEM( p1++ ) = MEM( p2++ ) = (m == 0) ? 0x00000001 << j :
0xFFFFFFFF ^ (0x00000001 << j);
barrier();
}
else /* Walk it back down. */
{
MEM( p1++ ) = MEM( p2++ ) = (m == 0)
? 0x00000001 << (64 - j - 1)
: 0xFFFFFFFF ^ (0x00000001 << (64 - j - 1));
barrier();
}
}
if (test_verify_success (bp1, bp2, count) == CHKMEM_ERR)
{
return (CHKMEM_ERR);
}
}
return (CHKMEM_OK);
}
int
test_bitspread_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i, j;
SHOWFUNC();
for (j = 0; j < 64; j++)
{
showrun( j );
p1 = (volatile u32 *) bp1;
p2 = (volatile u32 *) bp2;
for (i = 0; i < count; i++)
{
showadr( p1 );
if (j < 32) /* Walk it up. */
{
MEM( p1++ ) = MEM( p2++ ) = (i % 2 == 0)
? (0x00000001 << j) | (0x00000001 << (j + 2))
: 0xFFFFFFFF ^ ((0x00000001 << j)
| (0x00000001 << (j + 2)));
barrier();
}
else /* Walk it back down. */
{
MEM( p1++ ) = MEM( p2++ ) = (i % 2 == 0)
? (0x00000001 << (63 - j)) | (0x00000001 << (65 - j))
: 0xFFFFFFFF ^ (0x00000001 << (63 - j)
| (0x00000001 << (65 - j)));
barrier();
}
}
if (test_verify_success (bp1, bp2, count) == CHKMEM_ERR)
{
return (CHKMEM_ERR);
}
}
return (CHKMEM_OK);
}
int
test_bitflip_comparison (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1 = (volatile u32 *) bp1;
volatile u32 *p2 = (volatile u32 *) bp2;
u32 i, j, k;
u32 q;
SHOWFUNC();
for (k = 0; k < 32; k++)
{
showrun( k*8 );
q = 0x00000001 << k;
for (j = 0; j < 8; j++)
{
q = ~q;
p1 = (volatile u32 *) bp1;
p2 = (volatile u32 *) bp2;
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) = MEM( p2++ ) = (i % 2) == 0 ? q : ~q;
barrier();
}
if (test_verify_success (bp1, bp2, count) == CHKMEM_ERR)
{
return (CHKMEM_ERR);
}
}
}
return (CHKMEM_OK);
}
int
test_stuck_address (u32 *bp1, u32 *bp2, u32 count)
{
volatile u32 *p1;
/* second argument is not used; just gives it a compatible signature. */
u32 i, j;
SHOWFUNC();
count <<= 1;
for (j = 0; j < 16; j++)
{
showrun( j );
p1 = (volatile u32 *) bp1;
for (i = 0; i < count; i++)
{
showadr( p1 );
MEM( p1++ ) = ((j + i) % 2) == 0 ? (u32) p1 : ~((u32) p1);
barrier();
}
p1 = (volatile u32 *) bp1;
for (i = 0; i < count; i++, p1++)
{
showadr( p1 );
if (*p1 != (((j + i) % 2) == 0 ? (u32) p1 : ~((u32) p1)))
{
return (CHKMEM_ERR);
}
}
}
return (CHKMEM_OK);
}
--- NEW FILE: clock.c ---
/*-------------------------------------------------------------------------
* Filename: clock.c
* Version: $Id: clock.c,v 1.1 2001/10/07 19:04:25 erikm Exp $
* Copyright: Copyright (C) 2000, Johan Pouwelse
* Author: Johan Pouwelse <pou...@tw...>
* Description: Clock switching functions
* Created at: Sat Mar 25 14:11:22 2000
* Modified by: Erik Mouw <J.A...@it...>
* Modified at: Sat Mar 25 14:12:42 2000
*-----------------------------------------------------------------------*/
/*
* clock.c: Utility to set clock speed and DRAM parameters
*
* Copyright (C) 2000 Johan Pouwelse (pou...@tw...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
#ident "$Id: clock.c,v 1.1 2001/10/07 19:04:25 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "command.h"
#include "errno.h"
#include "error.h"
#include "types.h"
#include "sa1100.h"
#include "serial.h"
#include "time.h"
#include "util.h"
/* Struct with the SA-1100 PLL + DRAM parameter registers */
enum {
SA_PPCR,
SA_MDCNFG,
SA_MDCAS0,
SA_MDCAS1,
SA_MDCAS2
};
int SetClock(int argc, char *argv[])
{
int i;
u32 regs[5];
u32 startTime, currentTime;
if(argc < 6)
return -ENOPARAMS;
for(i = 0; i < 5; i++) {
if(strtoval(argv[i + 1], ®s[i]) < 0) {
printerror(ENAN, argv[i + 1]);
return 0;
}
}
/* we go slower, so first set PLL register */
PPCR = regs[SA_PPCR];
MDCNFG = regs[SA_MDCNFG];
MDCAS0 = regs[SA_MDCAS0];
MDCAS1 = regs[SA_MDCAS1];
MDCAS2 = regs[SA_MDCAS2];
/* sleep for a second */
startTime = TimerGetTime();
for(;;) {
currentTime = TimerGetTime();
if((currentTime - startTime) > (u32)TICKS_PER_SECOND)
return 0;
}
} /* SetClock */
static char clockhelp[] = "clock PPCR MDCNFG MDCAS0 MDCAS1 MDCAS2\n"
"Set the SA1100 core clock and DRAM timings\n"
"WARNING: dangerous command!\n";
__commandlist(SetClock, "clock", clockhelp);
--- NEW FILE: debug.c ---
/*
* debug.c: Debugging command functions
*
* Copyright (C) 2001 Stefan Eletzhofer <ste...@ww...>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
#ident "$Id: debug.c,v 1.1 2001/10/07 19:04:25 erikm Exp $"
/**********************************************************************
* Includes
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "errno.h"
#include "error.h"
#include "types.h"
#include "util.h"
#include "serial.h"
#include "command.h"
/**********************************************************************
* defines
*/
/* this will send a cold shiver through erik's spine ... */
#define ERR( x ) { ret = x; goto DONE; }
/* more readable IMHO */
#define MEM( x ) (*((u32 *)x))
/**********************************************************************
* program globals
*/
/**********************************************************************
* module globals
*/
/**********************************************************************
* prototypes
*/
void perror( int errno, char *func )
{
printerrprefix();
if ( errno < 0 )
errno = -errno;
if ( func != NULL) {
SerialOutputString(func);
SerialOutputString(": ");
}
SerialOutputString(strerror(errno));
SerialOutputByte('\n');
}
/**********************************************************************
* exported functions
*/
/**********************************************************************
* static functions
*/
/*********************************************************************
* CmdMemcpy
*
* AUTOR: SELETZ
* REVISED:
*
* Command wrapper for memcpy utility function.
*
*/
static int CmdMemcpy( int argc, char *argv[] )
{
int ret = 0;
u32 src = 0L;
u32 dest = 0L;
u32 len = 0L;
if ( argc < 4 ) ERR( -EINVAL );
ret = strtoval( argv[1], &src );
if ( ret < 0 ) ERR( -EINVAL );
ret = strtoval( argv[2], &dest );
if ( ret < 0 ) ERR( -EINVAL );
ret = strtoval( argv[3], &len );
if ( ret < 0 ) ERR( -EINVAL );
/* counted in words */
if ( len & 0x00000003 ) {
len = ( len >> 2 ) + 1;
} else {
len = len >> 2;
}
SerialOutputString("\n### Now copying 0x");
SerialOutputHex(len);
SerialOutputString(" words from 0x");
SerialOutputHex((int)src);
SerialOutputString(" to 0x");
SerialOutputHex((int)dest);
SerialOutputByte('\n');
MyMemCpy( (u32 *)dest, (const u32 *)src, len);
SerialOutputString(" done\n");
ret = 0;
DONE:
if ( ret != 0 ) {
perror( ret, __FUNCTION__ );
}
return ret;
}
static char memcpyhelp[] = "memcpy [source] [dest] [len]\n"
"copy memory blocks\n";
__commandlist(CmdMemcpy, "memcpy", memcpyhelp);
/*********************************************************************
* Poke
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Poke values to memory
*
*/
int Poke( int argc, char *argv[] )
{
int ret = 0;
u32 address;
u32 value;
if ( argc < 3 ) ERR( -EINVAL );
ret = strtoval(argv[1], &address);
if ( ret < 0 ) ERR( -EINVAL );
ret = strtoval(argv[2], &value);
if ( ret < 0 ) ERR( -EINVAL );
#if CHKMEM_DEBUG
SerialOutputString("adr=0x");
SerialOutputHex(address);
SerialOutputString(" val=0x");
SerialOutputHex(value);
SerialOutputString("\n");
#endif
MEM( address ) = value;
ret = 0;
DONE:
if ( ret != 0 ) {
perror( ret, __FUNCTION__ );
}
return ret;
}
static char pokehelp[] = "poke address value\n";
__commandlist(Poke, "poke", pokehelp );
/*********************************************************************
* Peek
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Poke values to memory
*
*/
int Peek( int argc, char *argv[] )
{
int ret = 0;
u32 address;
u32 value;
if ( argc < 2 ) ERR( -EINVAL );
ret = strtoval(argv[1], &address);
if ( ret < 0 ) ERR( -EINVAL );
#if CHKMEM_DEBUG
SerialOutputString("adr=0x");
SerialOutputHex(address);
SerialOutputString("\n");
#endif
value = MEM( address );
SerialOutputHex(value);
SerialOutputString("\n");
ret = 0;
DONE:
if ( ret != 0 ) {
perror( ret, __FUNCTION__ );
}
return ret;
}
static char peekhelp[] = "peek address\n";
__commandlist(Peek, "peek", peekhelp );
/*********************************************************************
* BitChange
*
* AUTOR: SELETZ
* REVISED:
*
* Modifies bits of an given memory location
*
*/
int BitChange( int argc, char *argv[] )
{
int ret = 0;
u32 adr = 0L;
u32 value = 0L;
if ( argc < 4 ) ERR( -EINVAL );
ret = strtoval( argv[1], &adr );
if ( ret < 0 ) ERR( -EINVAL );
ret = strtoval( argv[2], &value );
if ( ret < 0 ) ERR( -EINVAL );
SerialOutputHex( MEM( adr ) );
switch ( argv[3][0] & (~0x20) ) {
case 'A':
MEM( adr ) &= value;
break;
case 'S':
case 'O':
MEM( adr ) |= value;
break;
case 'X':
MEM( adr ) ^= value;
break;
case 'C':
MEM( adr ) &= ~value;
break;
default:
ERR( -EINVAL );
break;
}
SerialOutputString( "->" );
SerialOutputHex( MEM( adr ) );
SerialOutputString( "\n" );
ret = 0;
DONE:
if ( ret != 0 ) {
perror( ret, __FUNCTION__ );
}
return ret;
}
static char bitchghelp[] = "bitchg address value {and|or|xor|set|clear}\n";
__commandlist(BitChange, "bitchg", bitchghelp );
--- NEW FILE: flash.c ---
/*-------------------------------------------------------------------------
* Filename: flash.c
* Version: $Id: flash.c,v 1.1 2001/10/07 19:04:25 erikm Exp $
* Copyright: Copyright (C) 1999, Jan-Derk Bakker
* Author: Jan-Derk Bakker <J.D...@it...>
* Description: Flash I/O functions for blob
* Created at: Mon Aug 23 20:00:00 1999
* Modified by: Erik Mouw <J.A...@it...>
* Modified at: Sat Jan 15 19:16:34 2000
*-----------------------------------------------------------------------*/
/*
* flash.c: Flash I/O functions for blob
*
* Copyright (C) 1999 Jan-Derk Bakker (J.D...@it...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
#ident "$Id: flash.c,v 1.1 2001/10/07 19:04:25 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "errno.h"
#include "error.h"
#include "led.h"
#include "main.h"
#include "util.h"
#include "serial.h"
#include "flash.h"
/* define for advanced flash functionality (not that it works) -- Erik */
/* #define ADVANCED_FLASH 1 */
/* Static function defs */
static u32 EraseOne(const char *whichOne);
#ifdef ADVANCED_FLASH
static void GetBlockOrder(tBlkInfo *blocksInfo, u8 which,
u8 blockOrder[NUM_FLASH_BLOCKS]);
#endif
#ifdef ADVANCED_FLASH
void ScanFlash(tBlkInfo *blocksInfo)
{
/* Scans the flash for headers in the main blocks. Maybe in the future we will
put the headers in one of the parameter blocks. */
int i,j;
j = 0;
for(i = 0; i < NUM_FLASH_BLOCKS; i++) {
MyMemCpy((u32 *) &(blocksInfo->headers[i]),
FLASH_BLOCK_BASE + i * FLASH_BLOCK_SIZE,
sizeof(tBlkHdr) / 4);
/* Is this a 'first' block ? */
if(BLOCK_IN_USE(blocksInfo->headers[i])
&& (blocksInfo->headers[i].seqNum == 0))
blocksInfo->firstBlockIndex[j++] = i;
}
for(; j < NUM_FLASH_BLOCKS; j++)
blocksInfo->firstBlockIndex[j] = NO_BLOCK;
} /* ScanFlash */
#endif
#ifdef ADVANCED_FLASH
void LoadBlocksToMem(tBlkInfo *blocksInfo, u8 which, u32 *baseAddr)
{
/* Load a series of blocks to memory */
u8 blockOrder[NUM_FLASH_BLOCKS];
int numBlocks = blocksInfo->headers[which].totSeq;
int i;
u32 *srcAddr, *dstAddr = baseAddr;
/* If the block isn't in use, fail silently. */
if(!BLOCK_IN_USE(blocksInfo->headers[which]))
return;
GetBlockOrder(blocksInfo, which, blockOrder);
for(i = 0; i < numBlocks; i++) {
srcAddr = FLASH_BLOCK_BASE +
blockOrder[i] * FLASH_BLOCK_SIZE + sizeof(tBlkHdr);
MyMemCpy(dstAddr, srcAddr, blocksInfo->headers[i].bytesInBlock / 4);
dstAddr += blocksInfo->headers[i].bytesInBlock / 4;
}
} /* LoadBlocksToMem */
#endif
/* The spooky functions that write to the same flash that we're executing from */
u32 data_from_flash(u32 what);
u32 data_to_flash(u32 what);
#if defined SHANNON || defined NESA
#define READ_ARRAY 0x00F000F0
#define UNLOCK1 0x00AA00AA
#define UNLOCK2 0x00550055
#define ERASE_SETUP 0x00800080
#define ERASE_CONFIRM 0x00300030
#define PGM_SETUP 0x00A000A0
#define UNLOCK_BYPASS 0x00200020
#define FLASH_ADDR1 (0x00000555 << 2)
#define FLASH_ADDR2 (0x000002AA << 2)
#define ERASE_DONE 0x00800080
#define RDY_MASK 0x00800080
#define STATUS_PGM_ERR 0x00200020
#define STATUS_ERASE_ERR 0x00000001
#else
#define READ_ARRAY 0x00FF00FF
#define ERASE_SETUP 0x00200020
#define ERASE_CONFIRM 0x00D000D0
#define PGM_SETUP 0x00400040
#define STATUS_READ 0x00700070
#define STATUS_CLEAR 0x00500050
#define STATUS_BUSY 0x00800080
#define STATUS_ERASE_ERR 0x00200020
#define STATUS_PGM_ERR 0x00100010
#endif
void EraseBlocks(tBlockType which)
{
char *thisBlock;
int numBlocks, i;
switch(which) {
case blBlob:
thisBlock = (char *)BLOB_START;
numBlocks = NUM_BLOB_BLOCKS;
break;
#ifdef PARAM_START
case blParam:
thisBlock = (char *)PARAM_START;
numBlocks = NUM_PARAM_BLOCKS;
break;
#endif
case blKernel:
thisBlock = (char *)KERNEL_START;
numBlocks = NUM_KERNEL_BLOCKS;
break;
case blRamdisk:
thisBlock = (char *)INITRD_START;
numBlocks = NUM_INITRD_BLOCKS;
break;
default:
/* this should not happen */
return;
}
for(i = 0; i < numBlocks; i++, thisBlock += MAIN_BLOCK_SIZE) {
SerialOutputByte('.');
led_toggle();
if((EraseOne(thisBlock) & STATUS_ERASE_ERR) != 0) {
printerrprefix();
SerialOutputString("erase error at address 0x");
SerialOutputHex((u32)thisBlock);
SerialOutputByte('\n');
return;
}
}
} /* EraseBlocks */
void WriteBlocksFromMem(tBlockType type, const u32 *source, int length)
{
volatile u32 *flashBase;
u32 result;
int maxLength, i;
#if defined SHANNON || defined NESA
#define READY 1
#define ERR 2
int chip1, chip2;
#endif
if((u32)source & 0x03) {
printerror(EALIGN, NULL);
#ifdef BLOB_DEBUG
printerrprefix();
SerialOutputString("Address = 0x");
SerialOutputHex((u32)source);
SerialOutputByte('\n');
#endif
return;
}
if(length & 0x03)
length += 0x04;
length &= ~((u32) 0x03);
switch(type) {
case blBlob:
flashBase = (u32 *)BLOB_START;
maxLength = BLOB_LEN;
break;
#ifdef PARAM_START
case blParam:
flashBase = (u32 *)PARAM_START;
maxLength = PARAM_LEN;
break;
#endif
case blKernel:
flashBase = (u32 *)KERNEL_START;
maxLength = KERNEL_LEN;
break;
case blRamdisk:
flashBase = (u32 *)INITRD_START;
maxLength = INITRD_LEN;
break;
default:
/* this should not happen */
return;
}
if(length > maxLength)
length = maxLength;
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ "(): Flashing 0x");
SerialOutputHex((u32)length);
SerialOutputString(" bytes from 0x");
SerialOutputHex((u32)source);
SerialOutputString(" to 0x");
SerialOutputHex((u32)flashBase);
SerialOutputByte('\n');
#endif
#if defined SHANNON || defined NESA
*(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1);
*(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2);
*(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK_BYPASS);
#endif
for(i = 0; i < length; i+= 4, flashBase++, source++) {
if((i % MAIN_BLOCK_SIZE) == 0) {
SerialOutputByte('.');
led_toggle();
}
*flashBase = data_to_flash(PGM_SETUP);
*flashBase = *source;
#if defined SHANNON || defined NESA
/* This is a pretty similar situation to the erasing status below
* Bit 7 is ~(data bit 7) until the flash is complete. If bit 5
* gets set before this happens, there is an error, but this could
* happen near the clock edge, and bit 5 could be the actual data
* before bit 7 changes, so we have to read again.
*/
chip1 = chip2 = 0;
do {
result = data_from_flash(*flashBase);
if (!chip1 && ((result & 0x80) == (*source & 0x80))) chip1 = READY;
if (!chip1 && ((result & 0xFFFF) & STATUS_PGM_ERR)) {
result = data_from_flash(*flashBase);
if ((result & 0x80) == (*source & 0x80)) chip1 = READY;
else chip1 = ERR;
}
if (!chip2 && ((result & (0x80 << 16)) == (*source & (0x80 << 16)))) chip2 = READY;
if (!chip2 && ((result >> 16) & STATUS_PGM_ERR)) {
result = data_from_flash(*flashBase);
if ((result & (0x80 << 16)) == (*source & (0x80 << 16))) chip2 = READY;
else chip2 = ERR;
}
} while (!chip1 || !chip2);
if (chip1 == ERR || chip2 == ERR || *flashBase != *source) {
#else
do {
*flashBase = data_to_flash(STATUS_READ);
result = data_from_flash(*flashBase);
} while((~result & STATUS_BUSY) != 0);
*flashBase = data_to_flash(READ_ARRAY);
if((result & STATUS_PGM_ERR) != 0 || *flashBase != *source) {
#endif
printerrprefix();
SerialOutputString("Write error at address 0x");
SerialOutputHex((u32)flashBase);
SerialOutputByte('\n');
return;
}
}
#if defined SHANNON || defined NESA
*(u32 *)FLASH_ADDR1 = data_to_flash(READ_ARRAY);
#endif
} /* WriteBlocksFromMem */
static u32 EraseOne(const char *whichOne)
{
/* Routine to erase one block of flash */
volatile u32 *writeMe = (u32 *)whichOne;
u32 result;
#if defined SHANNON || defined NESA
int chip1, chip2;
#endif
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ "(): erasing block at address 0x");
SerialOutputHex((u32)whichOne);
SerialOutputByte('\n');
#endif
#if defined SHANNON || defined NESA
*(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1);
*(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2);
*(u32 *)FLASH_ADDR1 = data_to_flash(ERASE_SETUP);
*(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1);
*(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2);
*writeMe = data_to_flash(ERASE_CONFIRM);
/* I just can't find clean ways of dealing with this flash...
* The error bit is a *set* bit, so if its read, and bit 7 is 0,
* but bit 5 is 1, its an error, however, after these status reads
* are done, erased flash goes to 0xff...sooo...each chip has to
* be caught where the bits are the status bits */
chip1 = chip2 = 0;
do {
result = data_from_flash(*writeMe);
if (!chip1 && (result & 0xFFFF) & ERASE_DONE) chip1 = READY;
if (!chip1 && (result & 0xFFFF) & STATUS_PGM_ERR) chip1 = ERR;
if (!chip2 && (result >> 16) & ERASE_DONE) chip2 = READY;
if (!chip2 && (result >> 16) & STATUS_PGM_ERR) chip2 = ERR;
} while(!chip1 || !chip2);
*(u32 *)FLASH_ADDR1 = data_to_flash(READ_ARRAY);
if (chip1 == ERR || chip2 == ERR) return 1;
return 0;
#else
*writeMe = data_to_flash(ERASE_SETUP);
*writeMe = data_to_flash(ERASE_CONFIRM);
do {
*writeMe = data_to_flash(STATUS_READ);
result = data_from_flash(*writeMe);
} while((~result & STATUS_BUSY) != 0);
*writeMe = data_to_flash(READ_ARRAY);
return result;
#endif
} /* EraseOne */
#ifdef ADVANCED_FLASH
static void GetBlockOrder(tBlkInfo *blocksInfo, u8 which,
u8 blockOrder[NUM_FLASH_BLOCKS])
{
tBlockType type = blocksInfo->headers[which].type;
char *name = blocksInfo->headers[which].name;
int i;
/* If the block isn't in use, fail silently. */
if(!BLOCK_IN_USE(blocksInfo->headers[which]))
return;
for(i = 0; i < NUM_FLASH_BLOCKS; i++) {
if(BLOCK_IN_USE(blocksInfo->headers[i]) &&
(blocksInfo->headers[i].type == type) &&
!MyStrNCmp(blocksInfo->headers[i].name, name, BLOCK_NAME_LEN)) {
blockOrder[blocksInfo->headers[i].seqNum] = i;
}
}
} /* GetBlockOrder */
#endif
--- NEW FILE: flashasm.S ---
/*
* flashasm.S: flash magic for LART
*
* Copyright (C) 1999 2000 2001 Jan-Derk bakker (J.D...@it...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
.ident "$Id: flashasm.S,v 1.1 2001/10/07 19:04:25 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
.text
.globl data_to_flash
.globl data_from_flash
/* Subroutine that takes data in r0 and formats it so it will be in */
/* the correct order for the internal flash */
/* used for LART only */
data_to_flash:
#if defined LART
mov r1, #0x0
tst r0, #0x00000001
orrne r1, r1, #0x00001000
tst r0, #0x00000002
orrne r1, r1, #0x00004000
tst r0, #0x00000004
orrne r1, r1, #0x00000800
tst r0, #0x00000008
orrne r1, r1, #0x00000200
tst r0, #0x00000010
orrne r1, r1, #0x00000001
tst r0, #0x00000020
orrne r1, r1, #0x00000004
tst r0, #0x00000040
orrne r1, r1, #0x00000080
tst r0, #0x00000080
orrne r1, r1, #0x00000020
tst r0, #0x00000100
orrne r1, r1, #0x00002000
tst r0, #0x00000200
orrne r1, r1, #0x00008000
tst r0, #0x00000400
orrne r1, r1, #0x00000400
tst r0, #0x00000800
orrne r1, r1, #0x00000100
tst r0, #0x00001000
orrne r1, r1, #0x00000002
tst r0, #0x00002000
orrne r1, r1, #0x00000008
tst r0, #0x00004000
orrne r1, r1, #0x00000040
tst r0, #0x00008000
orrne r1, r1, #0x00000010
tst r0, #0x00010000
orrne r1, r1, #0x00100000
tst r0, #0x00020000
orrne r1, r1, #0x00400000
tst r0, #0x00040000
orrne r1, r1, #0x00080000
tst r0, #0x00080000
orrne r1, r1, #0x00020000
tst r0, #0x00100000
orrne r1, r1, #0x01000000
tst r0, #0x00200000
orrne r1, r1, #0x04000000
tst r0, #0x00400000
orrne r1, r1, #0x80000000
tst r0, #0x00800000
orrne r1, r1, #0x20000000
tst r0, #0x01000000
orrne r1, r1, #0x00200000
tst r0, #0x02000000
orrne r1, r1, #0x00800000
tst r0, #0x04000000
orrne r1, r1, #0x00040000
tst r0, #0x08000000
orrne r1, r1, #0x00010000
tst r0, #0x10000000
orrne r1, r1, #0x02000000
tst r0, #0x20000000
orrne r1, r1, #0x08000000
tst r0, #0x40000000
orrne r1, r1, #0x40000000
tst r0, #0x80000000
orrne r1, r1, #0x10000000
mov r0, r1
#endif
mov pc, r14
/* Takes data received from the flash, and unshuffles it. */
data_from_flash:
#if defined LART
mov r1, #0x00
tst r0, #0x00000001
orrne r1, r1, #0x00000010
tst r0, #0x00000002
orrne r1, r1, #0x00001000
tst r0, #0x00000004
orrne r1, r1, #0x00000020
tst r0, #0x00000008
orrne r1, r1, #0x00002000
tst r0, #0x00000010
orrne r1, r1, #0x00008000
tst r0, #0x00000020
orrne r1, r1, #0x00000080
tst r0, #0x00000040
orrne r1, r1, #0x00004000
tst r0, #0x00000080
orrne r1, r1, #0x00000040
tst r0, #0x00000100
orrne r1, r1, #0x00000800
tst r0, #0x00000200
orrne r1, r1, #0x00000008
tst r0, #0x00000400
orrne r1, r1, #0x00000400
tst r0, #0x00000800
orrne r1, r1, #0x00000004
tst r0, #0x00001000
orrne r1, r1, #0x00000001
tst r0, #0x00002000
orrne r1, r1, #0x00000100
tst r0, #0x00004000
orrne r1, r1, #0x00000002
tst r0, #0x00008000
orrne r1, r1, #0x00000200
tst r0, #0x00010000
orrne r1, r1, #0x08000000
tst r0, #0x00020000
orrne r1, r1, #0x00080000
tst r0, #0x00040000
orrne r1, r1, #0x04000000
tst r0, #0x00080000
orrne r1, r1, #0x00040000
tst r0, #0x00100000
orrne r1, r1, #0x00010000
tst r0, #0x00200000
orrne r1, r1, #0x01000000
tst r0, #0x00400000
orrne r1, r1, #0x00020000
tst r0, #0x00800000
orrne r1, r1, #0x02000000
tst r0, #0x01000000
orrne r1, r1, #0x00100000
tst r0, #0x02000000
orrne r1, r1, #0x10000000
tst r0, #0x04000000
orrne r1, r1, #0x00200000
tst r0, #0x08000000
orrne r1, r1, #0x20000000
tst r0, #0x10000000
orrne r1, r1, #0x80000000
tst r0, #0x20000000
orrne r1, r1, #0x00800000
tst r0, #0x40000000
orrne r1, r1, #0x40000000
tst r0, #0x80000000
orrne r1, r1, #0x00400000
mov r0, r1
#endif
mov pc, r14
--- NEW FILE: linux.c ---
/*
* linux.c: support functions for booting a kernel
*
* Copyright (C) 2001 Erik Mouw (J.A...@it...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
#ident "$Id: linux.c,v 1.1 2001/10/07 19:04:25 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "linux.h"
#include "command.h"
#include "main.h"
#include "flash.h"
#include "init.h"
#include "memory.h"
#include "serial.h"
#include "util.h"
#include <asm-arm/setup.h>
static void setup_start_tag(void);
static void setup_memory_tags(void);
static void setup_commandline_tag(int argc, char *argv[]);
static void setup_ramdisk_tag(void);
static void setup_initrd_tag(void);
static void setup_end_tag(void);
static struct tag *params;
static int boot_linux(int argc, char *argv[])
{
register u32 i;
void (*theKernel)(int zero, int arch) = (void (*)(int, int))KERNEL_RAM_BASE;
setup_start_tag();
setup_memory_tags();
setup_commandline_tag(argc, argv);
setup_initrd_tag();
setup_ramdisk_tag();
setup_end_tag();
/* we assume that the kernel is in place */
SerialOutputString("\nStarting kernel ...\n\n");
/* disable subsystems that want to be disabled before kernel boot */
exit_subsystems();
/* start kernel */
theKernel(0, ARCH_NUMBER);
SerialOutputString("Hey, the kernel returned! This should not happen.\n");
return 0;
}
static char boothelp[] = "boot [kernel options]\n"
"Boot Linux with optional kernel options\n";
__commandlist(boot_linux, "boot", boothelp);
static void setup_start_tag(void)
{
params = (struct tag *)BOOT_PARAMS;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size(tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next(params);
}
static void setup_memory_tags(void)
{
int i;
for(i = 0; i < NUM_MEM_AREAS; i++) {
if(memory_map[i].used) {
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size(tag_mem32);
params->u.mem.start = memory_map[i].start;
params->u.mem.size = memory_map[i].len;
params = tag_next(params);
}
}
}
static void setup_commandline_tag(int argc, char *argv[])
{
char *p;
int i;
/* initialise commandline */
params->u.cmdline.cmdline[0] = '\0';
/* copy default commandline from parameter block */
if(blob_status.cmdline[0] != '\0')
strcpy(params->u.cmdline.cmdline, blob_status.cmdline);
/* copy commandline */
if(argc >= 2) {
p = params->u.cmdline.cmdline;
for(i = 1; i < argc; i++) {
strcpy(p, argv[i]);
p += strlen(argv[i]);
*p++ = ' ';
}
p--;
*p = '\0';
}
if(strlen(params->u.cmdline.cmdline) > 0) {
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = (sizeof(struct tag_header) +
strlen(params->u.cmdline.cmdline) + 1 + 4) >> 2;
params = tag_next(params);
}
}
static void setup_initrd_tag(void)
{
/* an ATAG_INITRD node tells the kernel where the compressed
* ramdisk can be found. ATAG_RDIMG is a better name, actually.
*/
params->hdr.tag = ATAG_INITRD;
params->hdr.size = tag_size(tag_initrd);
params->u.initrd.start = RAMDISK_RAM_BASE;
params->u.initrd.size = INITRD_LEN;
params = tag_next(params);
}
static void setup_ramdisk_tag(void)
{
/* an ATAG_RAMDISK node tells the kernel how large the
* decompressed ramdisk will become.
*/
params->hdr.tag = ATAG_RAMDISK;
params->hdr.size = tag_size(tag_ramdisk);
params->u.ramdisk.start = 0;
params->u.ramdisk.size = RAMDISK_SIZE;
params->u.ramdisk.flags = 1; /* automatically load ramdisk */
params = tag_next(params);
}
static void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
--- NEW FILE: main.c ---
/*-------------------------------------------------------------------------
* Filename: main.c
* Version: $Id: main.c,v 1.1 2001/10/07 19:04:25 erikm Exp $
* Copyright: Copyright (C) 1999, Jan-Derk Bakker
* Author: Jan-Derk Bakker <J.D...@it...>
* Description: Main file for the trivially simple bootloader for the
* LART boards
* Created at: Mon Aug 23 20:00:00 1999
* Modified by: Erik Mouw <J.A...@it...>
* Modified at: Sat Mar 25 14:31:16 2000
*-----------------------------------------------------------------------*/
/*
* main.c: main file for the blob bootloader
*
* Copyright (C) 1999 2000 2001
* Jan-Derk Bakker (J.D...@it...) and
* Erik Mouw (J.A...@it...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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
*
*/
#ident "$Id: main.c,v 1.1 2001/10/07 19:04:25 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "command.h"
#include "errno.h"
#include "error.h"
#include "flash.h"
#include "init.h"
#include "led.h"
#include "main.h"
#include "memory.h"
#include "param_block.h"
#include "sa1100.h"
#include "serial.h"
#include "time.h"
#include "util.h"
#include "uucodec.h"
static int do_reload(char *what);
static void PrintSerialSpeed(eBauds speed);
blob_status_t blob_status;
int main(void)
{
u32 blockSize = 0x00800000;
int numRead = 0;
char commandline[MAX_COMMANDLINE_LENGTH];
int i;
int retval = 0;
u32 conf;
/* call subsystems */
init_subsystems();
/* initialise status */
blob_status.paramSize = 0;
blob_status.paramType = fromFlash;
blob_status.kernelSize = 0;
blob_status.kernelType = fromFlash;
blob_status.ramdiskSize = 0;
blob_status.ramdiskType = fromFlash;
blob_status.blockSize = blockSize;
blob_status.downloadSpeed = baud115k2;
blob_status.terminalSpeed = baud9k6;
blob_status.load_ramdisk = 1;
blob_status.cmdline[0] = '\0';
blob_status.boot_delay = 10;
/* call SerialInit() because the default 9k6 speed might not
be what the user requested */
SerialInit(blob_status.terminalSpeed);
/* parse the core tag, for critical things like terminal speed */
#ifdef PARAM_START
parse_ptag((void *) PARAM_START, &conf);
#endif
/* Print the required GPL string */
SerialOutputString("\nConsider yourself LARTed!\n\n");
SerialOutputString(PACKAGE " version " VERSION "\n"
"Copyright (C) 1999 2000 2001 "
"Jan-Derk Bakker and Erik Mouw\n");
SerialOutputString(PACKAGE " comes with ABSOLUTELY NO WARRANTY; "
"read the GNU GPL for details.\n");
SerialOutputString("This is free software, and you are welcome "
"to redistribute it\n");
SerialOutputString("under certain conditions; "
"read the GNU GPL for details.\n");
/* get the amount of memory */
get_memory_map();
/* Parse all the tags in the paramater block */
#ifdef PARAM_START
parse_ptags((void *) PARAM_START, &conf);
#endif
/* Load kernel and ramdisk from flash to RAM */
do_reload("blob");
do_reload("kernel");
if(blob_status.load_ramdisk)
do_reload("ramdisk");
#ifdef BLOB_DEBUG
/* print some information */
SerialOutputString("Running from ");
if(RunningFromInternal())
SerialOutputString("internal");
else
SerialOutputString("external");
SerialOutputString(" flash, blockSize = 0x");
SerialOutputHex(blockSize);
SerialOutputByte('\n');
#endif
/* wait 10 seconds before starting autoboot */
SerialOutputString("Autoboot in progress, press any key to stop ");
for(i = 0; i < blob_status.boot_delay; i++) {
SerialOutputByte('.');
retval = SerialInputBlock(commandline, 1, 1);
if(retval > 0)
break;
}
/* no key was pressed, so proceed booting the kernel */
if(retval == 0) {
commandline[0] = '\0';
parse_command("boot");
}
SerialOutputString("\nAutoboot aborted\n");
SerialOutputString("Type \"help\" to get a list of commands\n");
/* the command loop. endless, of course */
for(;;) {
DisplayPrompt(NULL);
/* wait 10 minutes for a command */
numRead = GetCommand(commandline, MAX_COMMANDLINE_LENGTH, 600);
if(numRead > 0) {
if((retval = parse_command(commandline)) < 0 )
printerror(retval, NULL);
}
}
return 0;
} /* main */
static int Download(int argc, char *argv[])
{
u32 startAddress = 0;
int bufLen;
int *numRead = 0;
int retval;
if(argc < 2)
return -ENOPARAMS;
if(strncmp(argv[1], "blob", 4) == 0) {
/* download blob */
startAddress = BLOB_RAM_BASE;
bufLen = blob_status.blockSize - BLOB_BLOCK_OFFSET;
numRead = &blob_status.blobSize;
blob_status.blobType = fromDownload;
#ifdef PARAM_START
} else if(strncmp(argv[1], "param", 5) == 0) {
/* download kernel */
startAddress = PARAM_RAM_BASE;
bufLen = PARAM_LEN;
numRead = &blob_status.paramSize;
blob_status.paramType = fromDownload;
#endif
} else if(strncmp(argv[1], "kernel", 6) == 0) {
/* download kernel */
startAddress = KERNEL_RAM_BASE;
bufLen = blob_status.blockSize - KERNEL_BLOCK_OFFSET;
numRead = &blob_status.kernelSize;
blob_status.kernelType = fromDownload;
} else if(strncmp(argv[1], "ramdisk", 7) == 0) {
/* download ramdisk */
startAddress = RAMDISK_RAM_BASE;
bufLen = blob_status.blockSize - RAMDISK_BLOCK_OFFSET;
numRead = &blob_status.ramdiskSize;
blob_status.ramdiskType = fromDownload;
} else {
printerror(EINVAL, argv[1]);
return 0;
}
SerialOutputString("Switching to ");
PrintSerialSpeed(blob_status.downloadSpeed);
SerialOutputString(" baud\n");
SerialOutputString("You have 60 seconds to switch your terminal emulator to the same speed and\n");
SerialOutputString("start downloading. After that " PACKAGE " will switch back to ");
PrintSerialSpeed(blob_status.terminalSpeed);
SerialOutputString(" baud.\n");
SerialInit(blob_status.downloadSpeed);
*numRead = UUDecode((char *)startAddress, bufLen);
SerialOutputString("\n(Please switch your terminal emulator back to ");
PrintSerialSpeed(blob_status.terminalSpeed);
SerialOutputString(" baud)\n");
if(*numRead < 0) {
/* something went wrong */
retval = *numRead;
/* reload the correct memory */
do_reload(argv[1]);
SerialInit(blob_status.terminalSpeed);
return retval;
}
SerialOutputString("Received ");
SerialOutputDec(*numRead);
SerialOutputString(" (0x");
SerialOutputHex(*numRead);
SerialOutputString(") bytes.\n");
SerialInit(blob_status.terminalSpeed);
return 0;
}
static char downloadhelp[] = "download {blob|param|kernel|ramdisk}\n"
"Download <argument> image to RAM\n";
__commandlist(Download, "download", downloadhelp);
static int Flash(int argc, char *argv[])
{
u32 startAddress = 0;
tBlockType block;
int numBytes = 0;
int maxSize = 0;
block_source_t type = fromFlash;
if(argc < 2)
return -ENOPARAMS;
if(strncmp(argv[1], "blob", 4) == 0) {
startAddress = BLOB_RAM_BASE;
block = blBlob;
numBytes = blob_status.blobSize;
maxSize = BLOB_LEN;
type = blob_status.blobType;
#ifdef PARAM_START
} else if(strncmp(argv[1], "param", 5) == 0) {
startAddress = PARAM_RAM_BASE;
block = blParam;
numBytes = blob_status.paramSize;
maxSize = PARAM_LEN;
type = blob_status.paramType;
#endif
} else if(strncmp(argv[1], "kernel", 6) == 0) {
startAddress = KERNEL_RAM_BASE;
block = blKernel;
numBytes = blob_status.kernelSize;
maxSize = KERNEL_LEN;
type = blob_status.kernelType;
} else if(strncmp(argv[1], "ramdisk", 7) == 0) {
startAddress = RAMDISK_RAM_BASE;
block = blRamdisk;
numBytes = blob_status.ramdiskSize;
maxSize = INITRD_LEN;
type = blob_status.ramdiskType;
} else {
printerror(EINVAL, argv[1]);
return 0;
}
if(type == fromFlash) {
/* error */
printerrprefix();
SerialOutputString(argv[1]);
SerialOutputString(" not downloaded\n");
return -EINVAL;
}
if(numBytes > maxSize) {
printerrprefix();
SerialOutputString("image too large for flash: 0x");
SerialOutputHex(numBytes);
SerialOutputString(" > 0x");
SerialOutputHex(maxSize);
SerialOutputByte('\n');
return -ETOOLONG;
}
SerialOutputString("Saving ");
SerialOutputString(argv[1]);
SerialOutputString(" to flash ");
EraseBlocks(block);
SerialOutputByte(' ');
WriteBlocksFromMem(block, (u32 *)startAddress, numBytes);
SerialOutputString(" done\n");
return 0;
}
static char flashhelp[] = "flash {blob|param|kernel|ramdisk}\n"
"Write <argument> image to flash\n";
__commandlist(Flash, "flash", flashhelp);
static int SetDownloadSpeed(int argc, char *argv[])
{
if(argc < 2)
return -ENOPARAMS;
if(strcmp(argv[1], "1200") == 0) {
blob_status.downloadSpeed = baud1k2;
} else if(strcmp(argv[1], "1k2") == 0) {
blob_status.downloadSpeed = baud1k2;
} else if(strcmp(argv[1], "9600") == 0) {
blob_status.downloadSpeed = baud9k6;
} else if(strcmp(argv[1], "9k6") == 0) {
blob_status.downloadSpeed = baud9k6;
} else if(strcmp(argv[1], "19200") == 0) {
blob_status.downloadSpeed = baud19k2;
} else if(strcmp(argv[1], "19k2") == 0) {
blob_status.downloadSpeed = baud19k2;
} else if(strcmp(argv[1], "38400") == 0) {
blob_status.downloadSpeed = baud38k4;
} else if(strcmp(argv[1], "38k4") == 0) {
blob_status.downloadSpeed = baud38k4;
} else if(strcmp(argv[1], "57600") == 0) {
blob_status.downloadSpeed = baud57k6;
} else if(strcmp(argv[1], "57k6") == 0) {
blob_status.downloadSpeed = baud57k6;
} else if(strcmp(argv[1], "115200") == 0) {
blob_status.downloadSpeed = baud115k2;
} else if(strcmp(argv[1], "115k2") == 0) {
blob_status.downloadSpeed = baud115k2;
} else if(strcmp(argv[1], "230400") == 0) {
blob_status.downloadSpeed = baud230k4;
} else if(strcmp(argv[1], "230k4") == 0) {
blob_status.downloadSpeed = baud230k4;
} else {
return -EINVAL;
}
SerialOutputString("Download speed set to ");
PrintSerialSpeed(blob_status.downloadSpeed);
SerialOutputString(" baud\n");
return 0;
}
static char speedhelp[] = "speed [baudrate]\n"
"Set download speed. Valid baudrates are:\n"
"1200, 9600, 19200, 38400, 57600, 115200, 230400,\n"
" 1k2, 9k6, 19k2, 38k4, 57k6, 115k2, 230k4\n";
__commandlist(SetDownloadSpeed, "speed", speedhelp);
static int PrintStatus(int argc, char *argv[])
{
SerialOutputString("Bootloader : " PACKAGE "\n");
SerialOutputString("Version : " VERSION "\n");
SerialOutputString("Running from : ");
if(RunningFromInternal())
SerialOutputString("internal");
else
SerialOutputString("external");
SerialOutputString(" flash\nBlocksize : 0x");
SerialOutputHex(blob_status.blockSize);
SerialOutputString("\nDownload speed: ");
PrintSerialSpeed(blob_status.downloadSpeed);
SerialOutputString(" baud\n");
SerialOutputString("Terminal speed: ");
PrintSerialSpeed(blob_status.terminalSpeed);
SerialOutputString(" baud\n");
SerialOutputString("Blob : ");
if(blob_status.blobType == fromFlash) {
SerialOutputString("from flash\n");
} else {
SerialOutputString("downloaded, ");
SerialOutputDec(blob_status.blobSize);
SerialOutputString(" bytes\n");
}
#ifdef PARAM_START
SerialOutputString("Param Block : ");
if(blob_status.paramType == fromFlash) {
SerialOutputString("from flash\n");
} else {
SerialOutputString("downloaded, ");
SerialOutputDec(blob_status.blobSize);
SerialOutputString(" bytes\n");
}
#else
SerialOutputString("Param Block : Not available\n");
#endif
SerialOutputString("Kernel : ");
if(blob_status.kernelType == fromFlash) {
SerialOutputString("from flash\n");
} else {
SerialOutputString("downloaded, ");
SerialOutputDec(blob_status.kernelSize);
SerialOutputString(" bytes\n");
}
SerialOutputString("Ramdisk : ");
if(blob_status....
[truncated message content] |