@ -5,6 +5,7 @@
* Licensed under the GPL - 2 or later .
*/
# include <div64.h>
# include <common.h>
# include <malloc.h>
# include <spi_flash.h>
@ -312,6 +313,161 @@ static int do_spi_flash_erase(int argc, char * const argv[])
return 0 ;
}
# ifdef CONFIG_CMD_SF_TEST
enum {
STAGE_ERASE ,
STAGE_CHECK ,
STAGE_WRITE ,
STAGE_READ ,
STAGE_COUNT ,
} ;
static char * stage_name [ STAGE_COUNT ] = {
" erase " ,
" check " ,
" write " ,
" read " ,
} ;
struct test_info {
int stage ;
int bytes ;
unsigned base_ms ;
unsigned time_ms [ STAGE_COUNT ] ;
} ;
static void show_time ( struct test_info * test , int stage )
{
uint64_t speed ; /* KiB/s */
int bps ; /* Bits per second */
speed = ( long long ) test - > bytes * 1000 ;
do_div ( speed , test - > time_ms [ stage ] * 1024 ) ;
bps = speed * 8 ;
printf ( " %d %s: %d ticks, %d KiB/s %d.%03d Mbps \n " , stage ,
stage_name [ stage ] , test - > time_ms [ stage ] ,
( int ) speed , bps / 1000 , bps % 1000 ) ;
}
static void spi_test_next_stage ( struct test_info * test )
{
test - > time_ms [ test - > stage ] = get_timer ( test - > base_ms ) ;
show_time ( test , test - > stage ) ;
test - > base_ms = get_timer ( 0 ) ;
test - > stage + + ;
}
/**
* Run a test on the SPI flash
*
* @ param flash SPI flash to use
* @ param buf Source buffer for data to write
* @ param len Size of data to read / write
* @ param offset Offset within flash to check
* @ param vbuf Verification buffer
* @ return 0 if ok , - 1 on error
*/
static int spi_flash_test ( struct spi_flash * flash , char * buf , ulong len ,
ulong offset , char * vbuf )
{
struct test_info test ;
int i ;
printf ( " SPI flash test: \n " ) ;
memset ( & test , ' \0 ' , sizeof ( test ) ) ;
test . base_ms = get_timer ( 0 ) ;
test . bytes = len ;
if ( spi_flash_erase ( flash , offset , len ) ) {
printf ( " Erase failed \n " ) ;
return - 1 ;
}
spi_test_next_stage ( & test ) ;
if ( spi_flash_read ( flash , offset , len , vbuf ) ) {
printf ( " Check read failed \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < len ; i + + ) {
if ( vbuf [ i ] ! = 0xff ) {
printf ( " Check failed at %d \n " , i ) ;
print_buffer ( i , vbuf + i , 1 , min ( len - i , 0x40 ) , 0 ) ;
return - 1 ;
}
}
spi_test_next_stage ( & test ) ;
if ( spi_flash_write ( flash , offset , len , buf ) ) {
printf ( " Write failed \n " ) ;
return - 1 ;
}
memset ( vbuf , ' \0 ' , len ) ;
spi_test_next_stage ( & test ) ;
if ( spi_flash_read ( flash , offset , len , vbuf ) ) {
printf ( " Read failed \n " ) ;
return - 1 ;
}
spi_test_next_stage ( & test ) ;
for ( i = 0 ; i < len ; i + + ) {
if ( buf [ i ] ! = vbuf [ i ] ) {
printf ( " Verify failed at %d, good data: \n " , i ) ;
print_buffer ( i , buf + i , 1 , min ( len - i , 0x40 ) , 0 ) ;
printf ( " Bad data: \n " ) ;
print_buffer ( i , vbuf + i , 1 , min ( len - i , 0x40 ) , 0 ) ;
return - 1 ;
}
}
printf ( " Test passed \n " ) ;
for ( i = 0 ; i < STAGE_COUNT ; i + + )
show_time ( & test , i ) ;
return 0 ;
}
static int do_spi_flash_test ( int argc , char * const argv [ ] )
{
unsigned long offset ;
unsigned long len ;
char * buf = ( char * ) CONFIG_SYS_TEXT_BASE ;
char * endp ;
char * vbuf ;
int ret ;
offset = simple_strtoul ( argv [ 1 ] , & endp , 16 ) ;
if ( * argv [ 1 ] = = 0 | | * endp ! = 0 )
return - 1 ;
len = simple_strtoul ( argv [ 2 ] , & endp , 16 ) ;
if ( * argv [ 2 ] = = 0 | | * endp ! = 0 )
return - 1 ;
vbuf = malloc ( len ) ;
if ( ! vbuf ) {
printf ( " Cannot allocate memory \n " ) ;
return 1 ;
}
buf = malloc ( len ) ;
if ( ! buf ) {
free ( vbuf ) ;
printf ( " Cannot allocate memory \n " ) ;
return 1 ;
}
memcpy ( buf , ( char * ) CONFIG_SYS_TEXT_BASE , len ) ;
ret = spi_flash_test ( flash , buf , len , offset , vbuf ) ;
free ( vbuf ) ;
free ( buf ) ;
if ( ret ) {
printf ( " Test failed \n " ) ;
return 1 ;
}
return 0 ;
}
# endif /* CONFIG_CMD_SF_TEST */
static int do_spi_flash ( cmd_tbl_t * cmdtp , int flag , int argc , char * const argv [ ] )
{
const char * cmd ;
@ -341,6 +497,10 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
ret = do_spi_flash_read_write ( argc , argv ) ;
else if ( strcmp ( cmd , " erase " ) = = 0 )
ret = do_spi_flash_erase ( argc , argv ) ;
# ifdef CONFIG_CMD_SF_TEST
else if ( ! strcmp ( cmd , " test " ) )
ret = do_spi_flash_test ( argc , argv ) ;
# endif
else
ret = - 1 ;
@ -352,6 +512,13 @@ usage:
return CMD_RET_USAGE ;
}
# ifdef CONFIG_CMD_SF_TEST
# define SF_TEST_HELP "\nsf test offset len " \
" - run a very basic destructive test "
# else
# define SF_TEST_HELP
# endif
U_BOOT_CMD (
sf , 5 , 1 , do_spi_flash ,
" SPI flash sub-system " ,
@ -365,4 +532,5 @@ U_BOOT_CMD(
" `+len' round up `len' to block size \n "
" sf update addr offset len - erase and write `len' bytes from memory \n "
" at `addr' to flash at `offset' "
SF_TEST_HELP
) ;