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] |