@ -36,6 +36,15 @@
# include <jffs2/jffs2.h>
# include <nand.h>
# if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
/* parition handling routines */
int mtdparts_init ( void ) ;
int id_parse ( const char * id , const char * * ret_id , u8 * dev_type , u8 * dev_num ) ;
int find_dev_and_part ( const char * id , struct mtd_device * * dev ,
u8 * part_num , struct part_info * * part ) ;
# endif
extern nand_info_t nand_info [ ] ; /* info for NAND chips */
static int nand_dump_oob ( nand_info_t * nand , ulong off )
@ -83,50 +92,75 @@ static int nand_dump(nand_info_t *nand, ulong off)
/* ------------------------------------------------------------------------- */
static void
arg_off_size ( int argc , char * argv [ ] , ulong * off , ulong * size , ulong totsize )
static inline int str2long ( char * p , ulong * num )
{
* off = 0 ;
* size = 0 ;
char * endptr ;
# if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART)
if ( argc > = 1 & & strcmp ( argv [ 0 ] , " partition " ) = = 0 ) {
int part_num ;
struct part_info * part ;
const char * partstr ;
if ( argc > = 2 )
partstr = argv [ 1 ] ;
else
partstr = getenv ( " partition " ) ;
if ( partstr )
part_num = ( int ) simple_strtoul ( partstr , NULL , 10 ) ;
else
part_num = 0 ;
* num = simple_strtoul ( p , & endptr , 16 ) ;
return ( * p ! = ' \0 ' & & * endptr = = ' \0 ' ) ? 1 : 0 ;
}
part = jffs2_part_info ( part_num ) ;
if ( part = = NULL ) {
printf ( " \n Invalid partition %d \n " , part_num ) ;
return ;
static int
arg_off_size ( int argc , char * argv [ ] , nand_info_t * nand , ulong * off , ulong * size )
{
int idx = nand_curr_device ;
# if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
struct mtd_device * dev ;
struct part_info * part ;
u8 pnum ;
if ( argc > = 1 & & ! ( str2long ( argv [ 0 ] , off ) ) ) {
if ( ( mtdparts_init ( ) = = 0 ) & &
( find_dev_and_part ( argv [ 0 ] , & dev , & pnum , & part ) = = 0 ) ) {
if ( dev - > id - > type ! = MTD_DEV_TYPE_NAND ) {
puts ( " not a NAND device \n " ) ;
return - 1 ;
}
* off = part - > offset ;
if ( argc > = 2 ) {
if ( ! ( str2long ( argv [ 1 ] , size ) ) ) {
printf ( " '%s' is not a number \n " , argv [ 1 ] ) ;
return - 1 ;
}
if ( * size > part - > size )
* size = part - > size ;
} else {
* size = part - > size ;
}
idx = dev - > id - > num ;
* nand = nand_info [ idx ] ;
goto out ;
}
* size = part - > size ;
* off = ( ulong ) part - > offset ;
} else
}
# endif
{
if ( argc > = 1 )
* off = ( ulong ) simple_strtoul ( argv [ 0 ] , NULL , 16 ) ;
else
* off = 0 ;
if ( argc > = 2 )
* size = ( ulong ) simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
else
* size = totsize - * off ;
if ( argc > = 1 ) {
if ( ! ( str2long ( argv [ 0 ] , off ) ) ) {
printf ( " '%s' is not a number \n " , argv [ 0 ] ) ;
return - 1 ;
}
} else {
* off = 0 ;
}
if ( argc > = 2 ) {
if ( ! ( str2long ( argv [ 1 ] , size ) ) ) {
printf ( " '%s' is not a number \n " , argv [ 1 ] ) ;
return - 1 ;
}
} else {
* size = nand - > size - * off ;
}
# if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
out :
# endif
printf ( " device %d " , idx ) ;
if ( * size = = nand - > size )
puts ( " whole chip \n " ) ;
else
printf ( " offset 0x%x, size 0x%x \n " , * off , * size ) ;
return 0 ;
}
int do_nand ( cmd_tbl_t * cmdtp , int flag , int argc , char * argv [ ] )
@ -213,35 +247,22 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 0 ;
}
/*
* Syntax is :
* 0 1 2 3 4
* nand erase [ clean ] [ off size ]
*/
if ( strcmp ( cmd , " erase " ) = = 0 | | strcmp ( cmd , " scrub " ) = = 0 ) {
nand_erase_options_t opts ;
int clean = argc > = 3 & & ! strcmp ( " clean " , argv [ 2 ] ) ;
int rest_argc = argc - 2 ;
char * * rest_argv = argv + 2 ;
/* "clean" at index 2 means request to write cleanmarker */
int clean = argc > 2 & & ! strcmp ( " clean " , argv [ 2 ] ) ;
int o = clean ? 3 : 2 ;
int scrub = ! strcmp ( cmd , " scrub " ) ;
if ( clean ) {
rest_argc - - ;
rest_argv + + ;
}
if ( rest_argc = = 0 ) {
printf ( " \n NAND %s: device %d whole chip \n " ,
cmd ,
nand_curr_device ) ;
off = size = 0 ;
} else {
arg_off_size ( rest_argc , rest_argv , & off , & size ,
nand - > size ) ;
if ( off = = 0 & & size = = 0 )
return 1 ;
printf ( " \n NAND %s: device %d offset 0x%x, size 0x%x \n " ,
cmd , nand_curr_device , off , size ) ;
}
printf ( " \n NAND %s: " , scrub ? " scrub " : " erase " ) ;
/* skip first two or three arguments, look for offset and size */
if ( arg_off_size ( argc - o , argv + o , nand , & off , & size ) ! = 0 )
return 1 ;
memset ( & opts , 0 , sizeof ( opts ) ) ;
opts . offset = off ;
@ -250,23 +271,22 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
opts . quiet = quiet ;
if ( scrub ) {
printf ( " Warning: "
" scrub option will erase all factory set "
" bad blocks! \n "
" "
" There is no reliable way to recover them. \n "
" "
" Use this command only for testing purposes "
" if you \n "
" "
" are sure of what you are doing! \n "
" \n Really scrub this NAND flash? <y/N> \n "
) ;
puts ( " Warning: "
" scrub option will erase all factory set "
" bad blocks! \n "
" "
" There is no reliable way to recover them. \n "
" "
" Use this command only for testing purposes "
" if you \n "
" "
" are sure of what you are doing! \n "
" \n Really scrub this NAND flash? <y/N> \n " ) ;
if ( getc ( ) = = ' y ' & & getc ( ) = = ' \r ' ) {
opts . scrub = 1 ;
} else {
printf ( " scrub aborted \n " ) ;
puts ( " scrub aborted \n " ) ;
return - 1 ;
}
}
@ -301,13 +321,10 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
addr = ( ulong ) simple_strtoul ( argv [ 2 ] , NULL , 16 ) ;
arg_off_size ( argc - 3 , argv + 3 , & off , & size , nand - > size ) ;
if ( off = = 0 & & size = = 0 )
return 1 ;
read = strncmp ( cmd , " read " , 4 ) = = 0 ; /* 1 = read, 0 = write */
printf ( " \n NAND %s: device %d offset %u, size %u ... " ,
read ? " read " : " write " , nand_curr_device , off , size ) ;
printf ( " \n NAND %s: " , read ? " read " : " write " ) ;
if ( arg_off_size ( argc - 3 , argv + 3 , nand , & off , & size ) ! = 0 )
return 1 ;
s = strchr ( cmd , ' . ' ) ;
if ( s ! = NULL & &
@ -334,15 +351,13 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
opts . quiet = quiet ;
ret = nand_write_opts ( nand , & opts ) ;
}
printf ( " %s \n " , ret ? " ERROR " : " OK " ) ;
return ret = = 0 ? 0 : 1 ;
} else {
if ( read )
ret = nand_read ( nand , off , & size , ( u_char * ) addr ) ;
else
ret = nand_write ( nand , off , & size , ( u_char * ) addr ) ;
}
if ( read )
ret = nand_read ( nand , off , & size , ( u_char * ) addr ) ;
else
ret = nand_write ( nand , off , & size , ( u_char * ) addr ) ;
printf ( " %d bytes %s: %s \n " , size ,
read ? " read " : " written " , ret ? " ERROR " : " OK " ) ;
@ -412,9 +427,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
}
} else {
if ( ! nand_lock ( nand , tight ) ) {
printf ( " NAND flash successfully locked \n " ) ;
puts ( " NAND flash successfully locked \n " ) ;
} else {
printf ( " Error locking NAND flash. \n " ) ;
puts ( " Error locking NAND flash \n " ) ;
return 1 ;
}
}
@ -422,19 +437,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
}
if ( strcmp ( cmd , " unlock " ) = = 0 ) {
if ( argc = = 2 ) {
off = 0 ;
size = nand - > size ;
} else {
arg_off_size ( argc - 2 , argv + 2 , & off , & size ,
nand - > size ) ;
}
if ( arg_off_size ( argc - 2 , argv + 2 , nand , & off , & size ) < 0 )
return 1 ;
if ( ! nand_unlock ( nand , off , size ) ) {
printf ( " NAND flash successfully unlocked \n " ) ;
puts ( " NAND flash successfully unlocked \n " ) ;
} else {
printf ( " Error unlocking NAND flash. "
" W rite and erase will probably fail\n " ) ;
puts ( " Error unlocking NAND flash, "
" w rite and erase will probably fail\n " ) ;
return 1 ;
}
return 0 ;
@ -449,8 +459,8 @@ U_BOOT_CMD(nand, 5, 1, do_nand,
" nand - NAND sub-system \n " ,
" info - show available NAND devices \n "
" nand device [dev] - show or set current device \n "
" nand read[.jffs2] - addr off size \n "
" nand write[.jffs2] - addr off size - read/write `size' bytes starting \n "
" nand read[.jffs2] - addr off|partition size \n "
" nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting \n "
" at offset `off' to/from memory address `addr' \n "
" nand erase [clean] [off size] - erase `size' bytes from \n "
" offset `off' (entire device if not specified) \n "
@ -462,62 +472,20 @@ U_BOOT_CMD(nand, 5, 1, do_nand,
" nand lock [tight] [status] - bring nand to lock state or display locked pages \n "
" nand unlock [offset] [size] - unlock section \n " ) ;
int do_nandboot ( cmd_tbl_t * cmdtp , int flag , int argc , char * argv [ ] )
static int nand_load_image ( cmd_tbl_t * cmdtp , nand_info_t * nand ,
ulong offset , ulong addr , char * cmd )
{
char * boot_device = NULL ;
char * ep ;
int dev ;
int r ;
ulong addr , cnt , offset = 0 ;
char * ep ;
ulong cnt ;
image_header_t * hdr ;
nand_info_t * nand ;
switch ( argc ) {
case 1 :
addr = CFG_LOAD_ADDR ;
boot_device = getenv ( " bootdevice " ) ;
break ;
case 2 :
addr = simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
boot_device = getenv ( " bootdevice " ) ;
break ;
case 3 :
addr = simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
boot_device = argv [ 2 ] ;
break ;
case 4 :
addr = simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
boot_device = argv [ 2 ] ;
offset = simple_strtoul ( argv [ 3 ] , NULL , 16 ) ;
break ;
default :
printf ( " Usage: \n %s \n " , cmdtp - > usage ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
if ( ! boot_device ) {
puts ( " \n ** No boot device ** \n " ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
dev = simple_strtoul ( boot_device , & ep , 16 ) ;
if ( dev < 0 | | dev > = CFG_MAX_NAND_DEVICE | | ! nand_info [ dev ] . name ) {
printf ( " \n ** Device %d not available \n " , dev ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
nand = & nand_info [ dev ] ;
printf ( " \n Loading from device %d: %s (offset 0x%lx) \n " ,
dev , nand - > name , offset ) ;
printf ( " \n Loading from %s, offset 0x%lx \n " , nand - > name , offset ) ;
cnt = nand - > oobblock ;
r = nand_read ( nand , offset , & cnt , ( u_char * ) addr ) ;
if ( r ) {
printf ( " ** Read error on %d \n " , dev ) ;
puts ( " ** Read error \n " ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
@ -536,7 +504,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
r = nand_read ( nand , offset , & cnt , ( u_char * ) addr ) ;
if ( r ) {
printf ( " ** Read error on %d \n " , dev ) ;
puts ( " ** Read error \n " ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
@ -550,7 +518,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
char * local_args [ 2 ] ;
extern int do_bootm ( cmd_tbl_t * , int , int , char * [ ] ) ;
local_args [ 0 ] = argv [ 0 ] ;
local_args [ 0 ] = cmd ;
local_args [ 1 ] = NULL ;
printf ( " Automatic boot of image at addr 0x%08lx ... \n " , addr ) ;
@ -561,9 +529,83 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 0 ;
}
U_BOOT_CMD ( nboot , 4 , 1 , do_nandboot ,
" nboot - boot from NAND device \n " , " loadAddr dev \n " ) ;
int do_nandboot ( cmd_tbl_t * cmdtp , int flag , int argc , char * argv [ ] )
{
char * boot_device = NULL ;
int idx ;
ulong addr , offset = 0 ;
# if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
struct mtd_device * dev ;
struct part_info * part ;
u8 pnum ;
if ( argc > = 2 ) {
char * p = ( argc = = 2 ) ? argv [ 1 ] : argv [ 2 ] ;
if ( ! ( str2long ( p , & addr ) ) & & ( mtdparts_init ( ) = = 0 ) & &
( find_dev_and_part ( p , & dev , & pnum , & part ) = = 0 ) ) {
if ( dev - > id - > type ! = MTD_DEV_TYPE_NAND ) {
puts ( " Not a NAND device \n " ) ;
return 1 ;
}
if ( argc > 3 )
goto usage ;
if ( argc = = 3 )
addr = simple_strtoul ( argv [ 2 ] , NULL , 16 ) ;
else
addr = CFG_LOAD_ADDR ;
return nand_load_image ( cmdtp , & nand_info [ dev - > id - > num ] ,
part - > offset , addr , argv [ 0 ] ) ;
}
}
# endif
switch ( argc ) {
case 1 :
addr = CFG_LOAD_ADDR ;
boot_device = getenv ( " bootdevice " ) ;
break ;
case 2 :
addr = simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
boot_device = getenv ( " bootdevice " ) ;
break ;
case 3 :
addr = simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
boot_device = argv [ 2 ] ;
break ;
case 4 :
addr = simple_strtoul ( argv [ 1 ] , NULL , 16 ) ;
boot_device = argv [ 2 ] ;
offset = simple_strtoul ( argv [ 3 ] , NULL , 16 ) ;
break ;
default :
# if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
usage :
# endif
printf ( " Usage: \n %s \n " , cmdtp - > usage ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
if ( ! boot_device ) {
puts ( " \n ** No boot device ** \n " ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
idx = simple_strtoul ( boot_device , NULL , 16 ) ;
if ( idx < 0 | | idx > = CFG_MAX_NAND_DEVICE | | ! nand_info [ idx ] . name ) {
printf ( " \n ** Device %d not available \n " , idx ) ;
SHOW_BOOT_PROGRESS ( - 1 ) ;
return 1 ;
}
return nand_load_image ( cmdtp , & nand_info [ idx ] , offset , addr , argv [ 0 ] ) ;
}
U_BOOT_CMD ( nboot , 4 , 1 , do_nandboot ,
" nboot - boot from NAND device \n " ,
" [partition] | [[[loadAddr] dev] offset] \n " ) ;
# endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */