@ -28,6 +28,12 @@
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston ,
* MA 02111 - 1307 USA
*
* Copyright 2010 Freescale Semiconductor
* The portions of this file whose copyright is held by Freescale and which
* are not considered a derived work of GPL v2 - only code may be distributed
* and / or modified 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 .
*/
# include <common.h>
@ -423,36 +429,43 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
# endif
/**
* get_len_incl_bad
* check_skip_len
*
* Check if length including bad blocks fits into device .
* Check if there are any bad blocks , and whether length including bad
* blocks fits into device
*
* @ param nand NAND device
* @ param offset offset in flash
* @ param length image length
* @ return image length including bad blocks
* @ return 0 if the image fits and there are no bad blocks
* 1 if the image fits , but there are bad blocks
* - 1 if the image does not fit
*/
static size_t get_len_incl_bad ( nand_info_t * nand , loff_t offset ,
const size_t length )
static int check_skip_len ( nand_info_t * nand , loff_t offset , size_t length )
{
size_t len_incl_bad = 0 ;
size_t len_excl_bad = 0 ;
size_t block_len ;
int ret = 0 ;
while ( len_excl_bad < length ) {
block_len = nand - > erasesize - ( offset & ( nand - > erasesize - 1 ) ) ;
size_t block_len , block_off ;
loff_t block_start ;
if ( ! nand_block_isbad ( nand , offset & ~ ( nand - > erase size - 1 ) ) )
len_excl_bad + = block_len ;
if ( offset > = nand - > size )
return - 1 ;
len_incl_bad + = block_len ;
offset + = block_len ;
block_start = offset & ~ ( loff_t ) ( nand - > erasesize - 1 ) ;
block_off = offset & ( nand - > erasesize - 1 ) ;
block_len = nand - > erasesize - block_off ;
if ( offset > = nand - > size )
break ;
if ( ! nand_block_isbad ( nand , block_start ) )
len_excl_bad + = block_len ;
else
ret = 1 ;
offset + = block_len ;
}
return len_incl_bad ;
return ret ;
}
/**
@ -474,29 +487,41 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
{
int rval ;
size_t left_to_write = * length ;
size_t len_incl_bad ;
u_char * p_buffer = buffer ;
int need_skip ;
/* Reject writes, which are not page aligned */
if ( ( offset & ( nand - > writesize - 1 ) ) ! = 0 | |
( * length & ( nand - > writesize - 1 ) ) ! = 0 ) {
/*
* nand_write ( ) handles unaligned , partial page writes .
*
* We allow length to be unaligned , for convenience in
* using the $ filesize variable .
*
* However , starting at an unaligned offset makes the
* semantics of bad block skipping ambiguous ( really ,
* you should only start a block skipping access at a
* partition boundary ) . So don ' t try to handle that .
*/
if ( ( offset & ( nand - > writesize - 1 ) ) ! = 0 ) {
printf ( " Attempt to write non page aligned data \n " ) ;
* length = 0 ;
return - EINVAL ;
}
len_incl_bad = get_len_incl_bad ( nand , offset , * length ) ;
if ( ( offset + len_incl_bad ) > nand - > size ) {
need_skip = check_skip_len ( nand , offset , * length ) ;
if ( need_skip < 0 ) {
printf ( " Attempt to write outside the flash area \n " ) ;
* length = 0 ;
return - EINVAL ;
}
if ( len_incl_bad = = * length ) {
if ( ! need_skip ) {
rval = nand_write ( nand , offset , length , buffer ) ;
if ( rval ! = 0 )
printf ( " NAND write to offset %llx failed %d \n " ,
offset , rval ) ;
if ( rval = = 0 )
return 0 ;
* length = 0 ;
printf ( " NAND write to offset %llx failed %d \n " ,
offset , rval ) ;
return rval ;
}
@ -553,20 +578,28 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
{
int rval ;
size_t left_to_read = * length ;
size_t len_incl_bad ;
u_char * p_buffer = buffer ;
int need_skip ;
len_incl_bad = get_len_incl_bad ( nand , offset , * length ) ;
if ( ( offset & ( nand - > writesize - 1 ) ) ! = 0 ) {
printf ( " Attempt to read non page aligned data \n " ) ;
* length = 0 ;
return - EINVAL ;
}
if ( ( offset + len_incl_bad ) > nand - > size ) {
need_skip = check_skip_len ( nand , offset , * length ) ;
if ( need_skip < 0 ) {
printf ( " Attempt to read outside the flash area \n " ) ;
* length = 0 ;
return - EINVAL ;
}
if ( len_incl_bad = = * length ) {
if ( ! need_skip ) {
rval = nand_read ( nand , offset , length , buffer ) ;
if ( ! rval | | rval = = - EUCLEAN )
return 0 ;
* length = 0 ;
printf ( " NAND read from offset %llx failed %d \n " ,
offset , rval ) ;
return rval ;