@ -40,6 +40,13 @@
# if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
# include <linux/mtd/mtd.h>
/*
* NAND - SPL has no sofware ECC for now , so don ' t include nand_calculate_ecc ( ) ,
* only nand_correct_data ( ) is needed
*/
# ifndef CONFIG_NAND_SPL
/*
* Pre - calculated 256 - way 1 byte column parity
*/
@ -62,90 +69,75 @@ static const u_char nand_ecc_precalc_table[] = {
0x00 , 0x55 , 0x56 , 0x03 , 0x59 , 0x0c , 0x0f , 0x5a , 0x5a , 0x0f , 0x0c , 0x59 , 0x03 , 0x56 , 0x55 , 0x00
} ;
/**
* nand_trans_result - [ GENERIC ] create non - inverted ECC
* @ reg2 : line parity reg 2
* @ reg3 : line parity reg 3
* @ ecc_code : ecc
*
* Creates non - inverted ECC code from line parity
*/
static void nand_trans_result ( u_char reg2 , u_char reg3 ,
u_char * ecc_code )
{
u_char a , b , i , tmp1 , tmp2 ;
/* Initialize variables */
a = b = 0x80 ;
tmp1 = tmp2 = 0 ;
/* Calculate first ECC byte */
for ( i = 0 ; i < 4 ; i + + ) {
if ( reg3 & a ) /* LP15,13,11,9 --> ecc_code[0] */
tmp1 | = b ;
b > > = 1 ;
if ( reg2 & a ) /* LP14,12,10,8 --> ecc_code[0] */
tmp1 | = b ;
b > > = 1 ;
a > > = 1 ;
}
/* Calculate second ECC byte */
b = 0x80 ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( reg3 & a ) /* LP7,5,3,1 --> ecc_code[1] */
tmp2 | = b ;
b > > = 1 ;
if ( reg2 & a ) /* LP6,4,2,0 --> ecc_code[1] */
tmp2 | = b ;
b > > = 1 ;
a > > = 1 ;
}
/* Store two of the ECC bytes */
ecc_code [ 0 ] = tmp1 ;
ecc_code [ 1 ] = tmp2 ;
}
/**
* nand_calculate_ecc - [ NAND Interface ] Calculate 3 byte ECC code for 256 byte block
* nand_calculate_ecc - [ NAND Interface ] Calculate 3 - byte ECC for 256 - byte block
* @ mtd : MTD block structure
* @ dat : raw data
* @ ecc_code : buffer for ECC
*/
int nand_calculate_ecc ( struct mtd_info * mtd , const u_char * dat , u_char * ecc_code )
int nand_calculate_ecc ( struct mtd_info * mtd , const u_char * dat ,
u_char * ecc_code )
{
u_char idx , reg1 , reg2 , reg3 ;
int j ;
uint8_t idx , reg1 , reg2 , reg3 , tmp1 , tmp2 ;
int i ;
/* Initialize variables */
reg1 = reg2 = reg3 = 0 ;
ecc_code [ 0 ] = ecc_code [ 1 ] = ecc_code [ 2 ] = 0 ;
/* Build up column parity */
for ( j = 0 ; j < 256 ; j + + ) {
for ( i = 0 ; i < 256 ; i + + ) {
/* Get CP0 - CP5 from table */
idx = nand_ecc_precalc_table [ dat [ j ] ] ;
idx = nand_ecc_precalc_table [ * dat + + ] ;
reg1 ^ = ( idx & 0x3f ) ;
/* All bit XOR = 1 ? */
if ( idx & 0x40 ) {
reg3 ^ = ( u_char ) j ;
reg2 ^ = ~ ( ( u_char ) j ) ;
reg3 ^ = ( uint8_t ) i ;
reg2 ^ = ~ ( ( uint8_t ) i ) ;
}
}
/* Create non-inverted ECC code from line parity */
nand_trans_result ( reg2 , reg3 , ecc_code ) ;
tmp1 = ( reg3 & 0x80 ) > > 0 ; /* B7 -> B7 */
tmp1 | = ( reg2 & 0x80 ) > > 1 ; /* B7 -> B6 */
tmp1 | = ( reg3 & 0x40 ) > > 1 ; /* B6 -> B5 */
tmp1 | = ( reg2 & 0x40 ) > > 2 ; /* B6 -> B4 */
tmp1 | = ( reg3 & 0x20 ) > > 2 ; /* B5 -> B3 */
tmp1 | = ( reg2 & 0x20 ) > > 3 ; /* B5 -> B2 */
tmp1 | = ( reg3 & 0x10 ) > > 3 ; /* B4 -> B1 */
tmp1 | = ( reg2 & 0x10 ) > > 4 ; /* B4 -> B0 */
tmp2 = ( reg3 & 0x08 ) < < 4 ; /* B3 -> B7 */
tmp2 | = ( reg2 & 0x08 ) < < 3 ; /* B3 -> B6 */
tmp2 | = ( reg3 & 0x04 ) < < 3 ; /* B2 -> B5 */
tmp2 | = ( reg2 & 0x04 ) < < 2 ; /* B2 -> B4 */
tmp2 | = ( reg3 & 0x02 ) < < 2 ; /* B1 -> B3 */
tmp2 | = ( reg2 & 0x02 ) < < 1 ; /* B1 -> B2 */
tmp2 | = ( reg3 & 0x01 ) < < 1 ; /* B0 -> B1 */
tmp2 | = ( reg2 & 0x01 ) < < 0 ; /* B7 -> B0 */
/* Calculate final ECC code */
ecc_code [ 0 ] = ~ ecc_code [ 0 ] ;
ecc_code [ 1 ] = ~ ecc_code [ 1 ] ;
# ifdef CONFIG_MTD_NAND_ECC_SMC
ecc_code [ 0 ] = ~ tmp2 ;
ecc_code [ 1 ] = ~ tmp1 ;
# else
ecc_code [ 0 ] = ~ tmp1 ;
ecc_code [ 1 ] = ~ tmp2 ;
# endif
ecc_code [ 2 ] = ( ( ~ reg1 ) < < 2 ) | 0x03 ;
return 0 ;
}
# endif /* CONFIG_NAND_SPL */
static inline int countbits ( uint32_t byte )
{
int res = 0 ;
for ( ; byte ; byte > > = 1 )
res + = byte & 0x01 ;
return res ;
}
/**
* nand_correct_data - [ NAND Interface ] Detect and correct bit error ( s )
@ -156,88 +148,52 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code
*
* Detect and correct a 1 bit error for 256 byte block
*/
int nand_correct_data ( struct mtd_info * mtd , u_char * dat , u_char * read_ecc , u_char * calc_ecc )
int nand_correct_data ( struct mtd_info * mtd , u_char * dat ,
u_char * read_ecc , u_char * calc_ecc )
{
u_char a , b , c , d1 , d2 , d3 , add , bit , i ;
uint8_t s0 , s1 , s2 ;
# ifdef CONFIG_MTD_NAND_ECC_SMC
s0 = calc_ecc [ 0 ] ^ read_ecc [ 0 ] ;
s1 = calc_ecc [ 1 ] ^ read_ecc [ 1 ] ;
s2 = calc_ecc [ 2 ] ^ read_ecc [ 2 ] ;
# else
s1 = calc_ecc [ 0 ] ^ read_ecc [ 0 ] ;
s0 = calc_ecc [ 1 ] ^ read_ecc [ 1 ] ;
s2 = calc_ecc [ 2 ] ^ read_ecc [ 2 ] ;
# endif
if ( ( s0 | s1 | s2 ) = = 0 )
return 0 ;
/* Do error detection */
d1 = calc_ecc [ 0 ] ^ read_ecc [ 0 ] ;
d2 = calc_ecc [ 1 ] ^ read_ecc [ 1 ] ;
d3 = calc_ecc [ 2 ] ^ read_ecc [ 2 ] ;
/* Check for a single bit error */
if ( ( ( s0 ^ ( s0 > > 1 ) ) & 0x55 ) = = 0x55 & &
( ( s1 ^ ( s1 > > 1 ) ) & 0x55 ) = = 0x55 & &
( ( s2 ^ ( s2 > > 1 ) ) & 0x54 ) = = 0x54 ) {
if ( ( d1 | d2 | d3 ) = = 0 ) {
/* No errors */
return 0 ;
}
else {
a = ( d1 ^ ( d1 > > 1 ) ) & 0x55 ;
b = ( d2 ^ ( d2 > > 1 ) ) & 0x55 ;
c = ( d3 ^ ( d3 > > 1 ) ) & 0x54 ;
/* Found and will correct single bit error in the data */
if ( ( a = = 0x55 ) & & ( b = = 0x55 ) & & ( c = = 0x54 ) ) {
c = 0x80 ;
add = 0 ;
a = 0x80 ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( d1 & c )
add | = a ;
c > > = 2 ;
a > > = 1 ;
}
c = 0x80 ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( d2 & c )
add | = a ;
c > > = 2 ;
a > > = 1 ;
}
bit = 0 ;
b = 0x04 ;
c = 0x80 ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( d3 & c )
bit | = b ;
c > > = 2 ;
b > > = 1 ;
}
b = 0x01 ;
a = dat [ add ] ;
a ^ = ( b < < bit ) ;
dat [ add ] = a ;
return 1 ;
} else {
i = 0 ;
while ( d1 ) {
if ( d1 & 0x01 )
+ + i ;
d1 > > = 1 ;
}
while ( d2 ) {
if ( d2 & 0x01 )
+ + i ;
d2 > > = 1 ;
}
while ( d3 ) {
if ( d3 & 0x01 )
+ + i ;
d3 > > = 1 ;
}
if ( i = = 1 ) {
/* ECC Code Error Correction */
read_ecc [ 0 ] = calc_ecc [ 0 ] ;
read_ecc [ 1 ] = calc_ecc [ 1 ] ;
read_ecc [ 2 ] = calc_ecc [ 2 ] ;
return 2 ;
}
else {
/* Uncorrectable Error */
return - 1 ;
}
}
uint32_t byteoffs , bitnum ;
byteoffs = ( s1 < < 0 ) & 0x80 ;
byteoffs | = ( s1 < < 1 ) & 0x40 ;
byteoffs | = ( s1 < < 2 ) & 0x20 ;
byteoffs | = ( s1 < < 3 ) & 0x10 ;
byteoffs | = ( s0 > > 4 ) & 0x08 ;
byteoffs | = ( s0 > > 3 ) & 0x04 ;
byteoffs | = ( s0 > > 2 ) & 0x02 ;
byteoffs | = ( s0 > > 1 ) & 0x01 ;
bitnum = ( s2 > > 5 ) & 0x04 ;
bitnum | = ( s2 > > 4 ) & 0x02 ;
bitnum | = ( s2 > > 3 ) & 0x01 ;
dat [ byteoffs ] ^ = ( 1 < < bitnum ) ;
return 1 ;
}
/* Should never happen */
if ( countbits ( s0 | ( ( uint32_t ) s1 < < 8 ) | ( ( uint32_t ) s2 < < 16 ) ) = = 1 )
return 1 ;
return - 1 ;
}