@ -224,6 +224,19 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
eccsize1 = 2 ; /* non-ECC bits in nibbles per sector */
}
break ;
case OMAP_ECC_BCH16_CODE_HW :
ecc_algo = 0x1 ;
bch_type = 0x2 ;
if ( mode = = NAND_ECC_WRITE ) {
bch_wrapmode = 0x01 ;
eccsize0 = 0 ; /* extra bits in nibbles per sector */
eccsize1 = 52 ; /* OOB bits in nibbles per sector */
} else {
bch_wrapmode = 0x01 ;
eccsize0 = 52 ; /* ECC bits in nibbles per sector */
eccsize1 = 0 ; /* non-ECC bits in nibbles per sector */
}
break ;
default :
return ;
}
@ -290,6 +303,29 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
ptr - - ;
}
break ;
case OMAP_ECC_BCH16_CODE_HW :
val = readl ( & gpmc_cfg - > bch_result_4_6 [ 0 ] . bch_result_x [ 2 ] ) ;
ecc_code [ i + + ] = ( val > > 8 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 0 ) & 0xFF ;
val = readl ( & gpmc_cfg - > bch_result_4_6 [ 0 ] . bch_result_x [ 1 ] ) ;
ecc_code [ i + + ] = ( val > > 24 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 16 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 8 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 0 ) & 0xFF ;
val = readl ( & gpmc_cfg - > bch_result_4_6 [ 0 ] . bch_result_x [ 0 ] ) ;
ecc_code [ i + + ] = ( val > > 24 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 16 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 8 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 0 ) & 0xFF ;
for ( j = 3 ; j > = 0 ; j - - ) {
val = readl ( & gpmc_cfg - > bch_result_0_3 [ 0 ] . bch_result_x [ j ]
) ;
ecc_code [ i + + ] = ( val > > 24 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 16 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 8 ) & 0xFF ;
ecc_code [ i + + ] = ( val > > 0 ) & 0xFF ;
}
break ;
default :
return - EINVAL ;
}
@ -308,6 +344,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
case OMAP_ECC_BCH8_CODE_HW :
ecc_code [ chip - > ecc . bytes - 1 ] = 0x00 ;
break ;
case OMAP_ECC_BCH16_CODE_HW :
break ;
default :
return - EINVAL ;
}
@ -333,7 +371,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
struct omap_nand_info * info = chip - > priv ;
struct nand_ecc_ctrl * ecc = & chip - > ecc ;
uint32_t error_count = 0 , error_max ;
uint32_t error_loc [ 8 ] ;
uint32_t error_loc [ ELM_MAX_ERROR_COUNT ] ;
enum bch_level bch_type ;
uint32_t i , ecc_flag = 0 ;
uint8_t count , err = 0 ;
@ -365,6 +403,10 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
bch_type = BCH_8_BIT ;
omap_reverse_list ( calc_ecc , ecc - > bytes - 1 ) ;
break ;
case OMAP_ECC_BCH16_CODE_HW :
bch_type = BCH_16_BIT ;
omap_reverse_list ( calc_ecc , ecc - > bytes ) ;
break ;
default :
return - EINVAL ;
}
@ -381,6 +423,9 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
/* 14th byte in ECC is reserved to match ROM layout */
error_max = SECTOR_BYTES + ( ecc - > bytes - 1 ) ;
break ;
case OMAP_ECC_BCH16_CODE_HW :
error_max = SECTOR_BYTES + ecc - > bytes ;
break ;
default :
return - EINVAL ;
}
@ -666,6 +711,38 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
return - EINVAL ;
# endif
case OMAP_ECC_BCH16_CODE_HW :
# ifdef CONFIG_NAND_OMAP_ELM
debug ( " nand: using OMAP_ECC_BCH16_CODE_HW \n " ) ;
/* check ecc-scheme requirements before updating ecc info */
if ( ( 26 * eccsteps ) + BADBLOCK_MARKER_LENGTH > oobsize ) {
printf ( " nand: error: insufficient OOB: require=%d \n " , (
( 26 * eccsteps ) + BADBLOCK_MARKER_LENGTH ) ) ;
return - EINVAL ;
}
/* intialize ELM for ECC error detection */
elm_init ( ) ;
/* populate ecc specific fields */
nand - > ecc . mode = NAND_ECC_HW ;
nand - > ecc . size = SECTOR_BYTES ;
nand - > ecc . bytes = 26 ;
nand - > ecc . strength = 16 ;
nand - > ecc . hwctl = omap_enable_hwecc ;
nand - > ecc . correct = omap_correct_data_bch ;
nand - > ecc . calculate = omap_calculate_ecc ;
nand - > ecc . read_page = omap_read_page_bch ;
/* define ecc-layout */
ecclayout - > eccbytes = nand - > ecc . bytes * eccsteps ;
for ( i = 0 ; i < ecclayout - > eccbytes ; i + + )
ecclayout - > eccpos [ i ] = i + BADBLOCK_MARKER_LENGTH ;
ecclayout - > oobfree [ 0 ] . offset = i + BADBLOCK_MARKER_LENGTH ;
ecclayout - > oobfree [ 0 ] . length = oobsize - nand - > ecc . bytes -
BADBLOCK_MARKER_LENGTH ;
break ;
# else
printf ( " nand: error: CONFIG_NAND_OMAP_ELM required for ECC \n " ) ;
return - EINVAL ;
# endif
default :
debug ( " nand: error: ecc scheme not enabled or supported \n " ) ;
return - EINVAL ;