@ -45,17 +45,6 @@
# include <asm/io.h>
# include <asm/io.h>
# include <asm/errno.h>
# include <asm/errno.h>
/*
* CONFIG_SYS_NAND_RESET_CNT is used as a timeout mechanism when resetting
* a flash . NAND flash is initialized prior to interrupts so standard timers
* can ' t be used . CONFIG_SYS_NAND_RESET_CNT should be set to a value
* which is greater than ( max NAND reset time / NAND status read time ) .
* A conservative default of 200000 ( 500 us / 25 ns ) is used as a default .
*/
# ifndef CONFIG_SYS_NAND_RESET_CNT
# define CONFIG_SYS_NAND_RESET_CNT 200000
# endif
static bool is_module_text_address ( unsigned long addr ) { return 0 ; }
static bool is_module_text_address ( unsigned long addr ) { return 0 ; }
/* Define default oob placement schemes for large and small page devices */
/* Define default oob placement schemes for large and small page devices */
@ -162,7 +151,6 @@ uint8_t nand_read_byte(struct mtd_info *mtd)
/**
/**
* nand_read_byte16 - [ DEFAULT ] read one byte endianness aware from the chip
* nand_read_byte16 - [ DEFAULT ] read one byte endianness aware from the chip
* nand_read_byte16 - [ DEFAULT ] read one byte endianness aware from the chip
* @ mtd : MTD device structure
* @ mtd : MTD device structure
*
*
* Default read function for 16 bit buswidth with endianness conversion .
* Default read function for 16 bit buswidth with endianness conversion .
@ -427,7 +415,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
uint8_t buf [ 2 ] = { 0 , 0 } ;
uint8_t buf [ 2 ] = { 0 , 0 } ;
int ret = 0 , res , i = 0 ;
int ret = 0 , res , i = 0 ;
ops . datbuf = NULL ;
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . oobbuf = buf ;
ops . oobbuf = buf ;
ops . ooboffs = chip - > badblockpos ;
ops . ooboffs = chip - > badblockpos ;
if ( chip - > options & NAND_BUSWIDTH_16 ) {
if ( chip - > options & NAND_BUSWIDTH_16 ) {
@ -525,11 +513,11 @@ static int nand_check_wp(struct mtd_info *mtd)
}
}
/**
/**
* nand_block_checkba d - [ GENERIC ] Check if a block is marked bad
* nand_block_isreserve d - [ GENERIC ] Check if a block is marked reserved .
* @ mtd : MTD device structure
* @ mtd : MTD device structure
* @ ofs : offset from device start
* @ ofs : offset from device start
*
*
* Check if the block is mark as reserved .
* Check if the block is marked as reserved .
*/
*/
static int nand_block_isreserved ( struct mtd_info * mtd , loff_t ofs )
static int nand_block_isreserved ( struct mtd_info * mtd , loff_t ofs )
{
{
@ -587,6 +575,27 @@ void nand_wait_ready(struct mtd_info *mtd)
EXPORT_SYMBOL_GPL ( nand_wait_ready ) ;
EXPORT_SYMBOL_GPL ( nand_wait_ready ) ;
/**
/**
* nand_wait_status_ready - [ GENERIC ] Wait for the ready status after commands .
* @ mtd : MTD device structure
* @ timeo : Timeout in ms
*
* Wait for status ready ( i . e . command done ) or timeout .
*/
static void nand_wait_status_ready ( struct mtd_info * mtd , unsigned long timeo )
{
register struct nand_chip * chip = mtd - > priv ;
u32 time_start ;
timeo = ( CONFIG_SYS_HZ * timeo ) / 1000 ;
time_start = get_timer ( 0 ) ;
while ( get_timer ( time_start ) < timeo ) {
if ( ( chip - > read_byte ( mtd ) & NAND_STATUS_READY ) )
break ;
WATCHDOG_RESET ( ) ;
}
} ;
/**
* nand_command - [ DEFAULT ] Send command to NAND device
* nand_command - [ DEFAULT ] Send command to NAND device
* @ mtd : MTD device structure
* @ mtd : MTD device structure
* @ command : the command to be sent
* @ command : the command to be sent
@ -601,7 +610,6 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
{
{
register struct nand_chip * chip = mtd - > priv ;
register struct nand_chip * chip = mtd - > priv ;
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE ;
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE ;
uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT ;
/* Write out the command to the device */
/* Write out the command to the device */
if ( command = = NAND_CMD_SEQIN ) {
if ( command = = NAND_CMD_SEQIN ) {
@ -665,8 +673,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
NAND_CTRL_CLE | NAND_CTRL_CHANGE ) ;
NAND_CTRL_CLE | NAND_CTRL_CHANGE ) ;
chip - > cmd_ctrl ( mtd ,
chip - > cmd_ctrl ( mtd ,
NAND_CMD_NONE , NAND_NCE | NAND_CTRL_CHANGE ) ;
NAND_CMD_NONE , NAND_NCE | NAND_CTRL_CHANGE ) ;
while ( ! ( chip - > read_byte ( mtd ) & NAND_STATUS_READY ) & &
/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
( rst_sts_cnt - - ) ) ;
nand_wait_status_ready ( mtd , 250 ) ;
return ;
return ;
/* This applies to read commands */
/* This applies to read commands */
@ -704,7 +712,6 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
int column , int page_addr )
int column , int page_addr )
{
{
register struct nand_chip * chip = mtd - > priv ;
register struct nand_chip * chip = mtd - > priv ;
uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT ;
/* Emulate NAND_CMD_READOOB */
/* Emulate NAND_CMD_READOOB */
if ( command = = NAND_CMD_READOOB ) {
if ( command = = NAND_CMD_READOOB ) {
@ -742,7 +749,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
/*
/*
* Program and erase have their own busy handlers status , sequential
* Program and erase have their own busy handlers status , sequential
* in , and deplete1 need no delay .
* in and status need no delay .
*/
*/
switch ( command ) {
switch ( command ) {
@ -763,8 +770,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE ) ;
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE ) ;
chip - > cmd_ctrl ( mtd , NAND_CMD_NONE ,
chip - > cmd_ctrl ( mtd , NAND_CMD_NONE ,
NAND_NCE | NAND_CTRL_CHANGE ) ;
NAND_NCE | NAND_CTRL_CHANGE ) ;
while ( ! ( chip - > read_byte ( mtd ) & NAND_STATUS_READY ) & &
/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
( rst_sts_cnt - - ) ) ;
nand_wait_status_ready ( mtd , 250 ) ;
return ;
return ;
case NAND_CMD_RNDOUT :
case NAND_CMD_RNDOUT :
@ -1062,8 +1069,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
* ecc . pos . Let ' s make sure that there are no gaps in ECC positions .
* ecc . pos . Let ' s make sure that there are no gaps in ECC positions .
*/
*/
for ( i = 0 ; i < eccfrag_len - 1 ; i + + ) {
for ( i = 0 ; i < eccfrag_len - 1 ; i + + ) {
if ( eccpos [ i + start_step * chip - > ecc . bytes ] + 1 ! =
if ( eccpos [ i + index ] + 1 ! = eccpos [ i + index + 1 ] ) {
eccpos [ i + start_step * chip - > ecc . bytes + 1 ] ) {
gaps = 1 ;
gaps = 1 ;
break ;
break ;
}
}
@ -1359,6 +1365,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
mtd - > oobavail : mtd - > oobsize ;
mtd - > oobavail : mtd - > oobsize ;
uint8_t * bufpoi , * oob , * buf ;
uint8_t * bufpoi , * oob , * buf ;
int use_bufpoi ;
unsigned int max_bitflips = 0 ;
unsigned int max_bitflips = 0 ;
int retry_mode = 0 ;
int retry_mode = 0 ;
bool ecc_fail = false ;
bool ecc_fail = false ;
@ -1382,9 +1389,18 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
bytes = min ( mtd - > writesize - col , readlen ) ;
bytes = min ( mtd - > writesize - col , readlen ) ;
aligned = ( bytes = = mtd - > writesize ) ;
aligned = ( bytes = = mtd - > writesize ) ;
if ( ! aligned )
use_bufpoi = 1 ;
else
use_bufpoi = 0 ;
/* Is the current page in the buffer? */
/* Is the current page in the buffer? */
if ( realpage ! = chip - > pagebuf | | oob ) {
if ( realpage ! = chip - > pagebuf | | oob ) {
bufpoi = aligned ? buf : chip - > buffers - > databuf ;
bufpoi = use_bufpoi ? chip - > buffers - > databuf : buf ;
if ( use_bufpoi & & aligned )
pr_debug ( " %s: using read bounce buffer for buf@%p \n " ,
__func__ , buf ) ;
read_retry :
read_retry :
chip - > cmdfunc ( mtd , NAND_CMD_READ0 , 0x00 , page ) ;
chip - > cmdfunc ( mtd , NAND_CMD_READ0 , 0x00 , page ) ;
@ -1406,7 +1422,7 @@ read_retry:
ret = chip - > ecc . read_page ( mtd , chip , bufpoi ,
ret = chip - > ecc . read_page ( mtd , chip , bufpoi ,
oob_required , page ) ;
oob_required , page ) ;
if ( ret < 0 ) {
if ( ret < 0 ) {
if ( ! aligned )
if ( use_bufpoi )
/* Invalidate page cache */
/* Invalidate page cache */
chip - > pagebuf = - 1 ;
chip - > pagebuf = - 1 ;
break ;
break ;
@ -1415,7 +1431,7 @@ read_retry:
max_bitflips = max_t ( unsigned int , max_bitflips , ret ) ;
max_bitflips = max_t ( unsigned int , max_bitflips , ret ) ;
/* Transfer not aligned data */
/* Transfer not aligned data */
if ( ! aligned ) {
if ( use_bufpoi ) {
if ( ! NAND_HAS_SUBPAGE_READ ( chip ) & & ! oob & &
if ( ! NAND_HAS_SUBPAGE_READ ( chip ) & & ! oob & &
! ( mtd - > ecc_stats . failed - ecc_failures ) & &
! ( mtd - > ecc_stats . failed - ecc_failures ) & &
( ops - > mode ! = MTD_OPS_RAW ) ) {
( ops - > mode ! = MTD_OPS_RAW ) ) {
@ -1529,9 +1545,9 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
int ret ;
int ret ;
nand_get_device ( mtd , FL_READING ) ;
nand_get_device ( mtd , FL_READING ) ;
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . len = len ;
ops . len = len ;
ops . datbuf = buf ;
ops . datbuf = buf ;
ops . oobbuf = NULL ;
ops . mode = MTD_OPS_PLACE_OOB ;
ops . mode = MTD_OPS_PLACE_OOB ;
ret = nand_do_read_ops ( mtd , from , & ops ) ;
ret = nand_do_read_ops ( mtd , from , & ops ) ;
* retlen = ops . retlen ;
* retlen = ops . retlen ;
@ -1563,11 +1579,10 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
static int nand_read_oob_syndrome ( struct mtd_info * mtd , struct nand_chip * chip ,
static int nand_read_oob_syndrome ( struct mtd_info * mtd , struct nand_chip * chip ,
int page )
int page )
{
{
uint8_t * buf = chip - > oob_poi ;
int length = mtd - > oobsize ;
int length = mtd - > oobsize ;
int chunk = chip - > ecc . bytes + chip - > ecc . prepad + chip - > ecc . postpad ;
int chunk = chip - > ecc . bytes + chip - > ecc . prepad + chip - > ecc . postpad ;
int eccsize = chip - > ecc . size ;
int eccsize = chip - > ecc . size ;
uint8_t * bufpoi = buf ;
uint8_t * bufpoi = chip - > oob_poi ;
int i , toread , sndrnd = 0 , pos ;
int i , toread , sndrnd = 0 , pos ;
chip - > cmdfunc ( mtd , NAND_CMD_READ0 , chip - > ecc . size , page ) ;
chip - > cmdfunc ( mtd , NAND_CMD_READ0 , chip - > ecc . size , page ) ;
@ -1940,7 +1955,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
/**
* nand_write_subpage_hwecc - [ REPLACABLE ] hardware ECC based subpage write
* nand_write_subpage_hwecc - [ REPLACE ABLE ] hardware ECC based subpage write
* @ mtd : mtd info structure
* @ mtd : mtd info structure
* @ chip : nand chip info structure
* @ chip : nand chip info structure
* @ offset : column address of subpage within the page
* @ offset : column address of subpage within the page
@ -2223,8 +2238,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
blockmask = ( 1 < < ( chip - > phys_erase_shift - chip - > page_shift ) ) - 1 ;
blockmask = ( 1 < < ( chip - > phys_erase_shift - chip - > page_shift ) ) - 1 ;
/* Invalidate the page cache, when we write to the cached page */
/* Invalidate the page cache, when we write to the cached page */
if ( to < = ( chip - > pagebuf < < chip - > page_shift ) & &
if ( to < = ( ( loff_t ) chip - > pagebuf < < chip - > page_shift ) & &
( chip - > pagebuf < < chip - > page_shift ) < ( to + ops - > len ) )
( ( loff_t ) chip - > pagebuf < < chip - > page_shift ) < ( to + ops - > len ) )
chip - > pagebuf = - 1 ;
chip - > pagebuf = - 1 ;
/* Don't allow multipage oob writes with offset */
/* Don't allow multipage oob writes with offset */
@ -2237,12 +2252,22 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
int bytes = mtd - > writesize ;
int bytes = mtd - > writesize ;
int cached = writelen > bytes & & page ! = blockmask ;
int cached = writelen > bytes & & page ! = blockmask ;
uint8_t * wbuf = buf ;
uint8_t * wbuf = buf ;
int use_bufpoi ;
int part_pagewr = ( column | | writelen < ( mtd - > writesize - 1 ) ) ;
if ( part_pagewr )
use_bufpoi = 1 ;
else
use_bufpoi = 0 ;
WATCHDOG_RESET ( ) ;
WATCHDOG_RESET ( ) ;
/* Partial page write? */
/* Partial page write?, or need to use bounce buffer */
if ( unlikely ( column | | writelen < ( mtd - > writesize - 1 ) ) ) {
if ( use_bufpoi ) {
pr_debug ( " %s: using write bounce buffer for buf@%p \n " ,
__func__ , buf ) ;
cached = 0 ;
cached = 0 ;
bytes = min_t ( int , bytes - column , ( int ) writelen ) ;
if ( part_pagewr )
bytes = min_t ( int , bytes - column , writelen ) ;
chip - > pagebuf = - 1 ;
chip - > pagebuf = - 1 ;
memset ( chip - > buffers - > databuf , 0xff , mtd - > writesize ) ;
memset ( chip - > buffers - > databuf , 0xff , mtd - > writesize ) ;
memcpy ( & chip - > buffers - > databuf [ column ] , buf , bytes ) ;
memcpy ( & chip - > buffers - > databuf [ column ] , buf , bytes ) ;
@ -2313,9 +2338,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Grab the device */
/* Grab the device */
panic_nand_get_device ( chip , mtd , FL_WRITING ) ;
panic_nand_get_device ( chip , mtd , FL_WRITING ) ;
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . len = len ;
ops . len = len ;
ops . datbuf = ( uint8_t * ) buf ;
ops . datbuf = ( uint8_t * ) buf ;
ops . oobbuf = NULL ;
ops . mode = MTD_OPS_PLACE_OOB ;
ops . mode = MTD_OPS_PLACE_OOB ;
ret = nand_do_write_ops ( mtd , to , & ops ) ;
ret = nand_do_write_ops ( mtd , to , & ops ) ;
@ -2341,9 +2366,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
int ret ;
int ret ;
nand_get_device ( mtd , FL_WRITING ) ;
nand_get_device ( mtd , FL_WRITING ) ;
memset ( & ops , 0 , sizeof ( ops ) ) ;
ops . len = len ;
ops . len = len ;
ops . datbuf = ( uint8_t * ) buf ;
ops . datbuf = ( uint8_t * ) buf ;
ops . oobbuf = NULL ;
ops . mode = MTD_OPS_PLACE_OOB ;
ops . mode = MTD_OPS_PLACE_OOB ;
ret = nand_do_write_ops ( mtd , to , & ops ) ;
ret = nand_do_write_ops ( mtd , to , & ops ) ;
* retlen = ops . retlen ;
* retlen = ops . retlen ;
@ -2480,18 +2505,20 @@ out:
}
}
/**
/**
* single_erase_cmd - [ GENERIC ] NAND standard block erase command function
* single_erase - [ GENERIC ] NAND standard block erase command function
* @ mtd : MTD device structure
* @ mtd : MTD device structure
* @ page : the page address of the block which will be erased
* @ page : the page address of the block which will be erased
*
*
* Standard erase command for NAND chips .
* Standard erase command for NAND chips . Returns NAND status .
*/
*/
static void single_erase_cmd ( struct mtd_info * mtd , int page )
static int single_erase ( struct mtd_info * mtd , int page )
{
{
struct nand_chip * chip = mtd - > priv ;
struct nand_chip * chip = mtd - > priv ;
/* Send commands to erase a block */
/* Send commands to erase a block */
chip - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page ) ;
chip - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page ) ;
chip - > cmdfunc ( mtd , NAND_CMD_ERASE2 , - 1 , - 1 ) ;
chip - > cmdfunc ( mtd , NAND_CMD_ERASE2 , - 1 , - 1 ) ;
return chip - > waitfunc ( mtd , chip ) ;
}
}
/**
/**
@ -2574,9 +2601,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
( page + pages_per_block ) )
( page + pages_per_block ) )
chip - > pagebuf = - 1 ;
chip - > pagebuf = - 1 ;
chip - > erase_cmd ( mtd , page & chip - > pagemask ) ;
status = chip - > erase ( mtd , page & chip - > pagemask ) ;
status = chip - > waitfunc ( mtd , chip ) ;
/*
/*
* See if operation failed and additional status checks are
* See if operation failed and additional status checks are
@ -2729,7 +2754,6 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
return 0 ;
return 0 ;
}
}
/* Set default functions */
/* Set default functions */
static void nand_set_defaults ( struct nand_chip * chip , int busw )
static void nand_set_defaults ( struct nand_chip * chip , int busw )
{
{
@ -3388,6 +3412,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
chip - > options | = type - > options ;
chip - > options | = type - > options ;
chip - > ecc_strength_ds = NAND_ECC_STRENGTH ( type ) ;
chip - > ecc_strength_ds = NAND_ECC_STRENGTH ( type ) ;
chip - > ecc_step_ds = NAND_ECC_STEP ( type ) ;
chip - > ecc_step_ds = NAND_ECC_STEP ( type ) ;
chip - > onfi_timing_mode_default =
type - > onfi_timing_mode_default ;
* busw = type - > options & NAND_BUSWIDTH_16 ;
* busw = type - > options & NAND_BUSWIDTH_16 ;
@ -3460,7 +3486,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip - > onfi_version = 0 ;
chip - > onfi_version = 0 ;
if ( ! type - > name | | ! type - > pagesize ) {
if ( ! type - > name | | ! type - > pagesize ) {
/* Check is chip is ONFI compliant */
/* Check if the chip is ONFI compliant */
if ( nand_flash_detect_onfi ( mtd , chip , & busw ) )
if ( nand_flash_detect_onfi ( mtd , chip , & busw ) )
goto ident_done ;
goto ident_done ;
@ -3538,7 +3564,7 @@ ident_done:
}
}
chip - > badblockbits = 8 ;
chip - > badblockbits = 8 ;
chip - > erase_cmd = single_erase_cmd ;
chip - > erase = single_erase ;
/* Do not replace user supplied command function! */
/* Do not replace user supplied command function! */
if ( mtd - > writesize > 512 & & chip - > cmdfunc = = nand_command )
if ( mtd - > writesize > 512 & & chip - > cmdfunc = = nand_command )
@ -3569,9 +3595,9 @@ ident_done:
type - > name ) ;
type - > name ) ;
# endif
# endif
pr_info ( " %dMiB, %s, page size: %d, OOB size: %d \n " ,
pr_info ( " %d MiB, %s, erase size: %d KiB , page size: %d, OOB size: %d \n " ,
( int ) ( chip - > chipsize > > 20 ) , nand_is_slc ( chip ) ? " SLC " : " MLC " ,
( int ) ( chip - > chipsize > > 20 ) , nand_is_slc ( chip ) ? " SLC " : " MLC " ,
mtd - > writesize , mtd - > oobsize ) ;
mtd - > erasesize > > 10 , mtd - > writesize , mtd - > oobsize ) ;
return type ;
return type ;
}
}
@ -3638,6 +3664,39 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
}
}
EXPORT_SYMBOL ( nand_scan_ident ) ;
EXPORT_SYMBOL ( nand_scan_ident ) ;
/*
* Check if the chip configuration meet the datasheet requirements .
* If our configuration corrects A bits per B bytes and the minimum
* required correction level is X bits per Y bytes , then we must ensure
* both of the following are true :
*
* ( 1 ) A / B > = X / Y
* ( 2 ) A > = X
*
* Requirement ( 1 ) ensures we can correct for the required bitflip density .
* Requirement ( 2 ) ensures we can correct even when all bitflips are clumped
* in the same sector .
*/
static bool nand_ecc_strength_good ( struct mtd_info * mtd )
{
struct nand_chip * chip = mtd - > priv ;
struct nand_ecc_ctrl * ecc = & chip - > ecc ;
int corr , ds_corr ;
if ( ecc - > size = = 0 | | chip - > ecc_step_ds = = 0 )
/* Not enough information */
return true ;
/*
* We get the number of corrected bits per page to compare
* the correction density .
*/
corr = ( mtd - > writesize * ecc - > strength ) / ecc - > size ;
ds_corr = ( mtd - > writesize * chip - > ecc_strength_ds ) / chip - > ecc_step_ds ;
return corr > = ds_corr & & ecc - > strength > = chip - > ecc_strength_ds ;
}
/**
/**
* nand_scan_tail - [ NAND Interface ] Scan for the NAND device
* nand_scan_tail - [ NAND Interface ] Scan for the NAND device
@ -3705,8 +3764,7 @@ int nand_scan_tail(struct mtd_info *mtd)
case NAND_ECC_HW_OOB_FIRST :
case NAND_ECC_HW_OOB_FIRST :
/* Similar to NAND_ECC_HW, but a separate read_page handle */
/* Similar to NAND_ECC_HW, but a separate read_page handle */
if ( ! ecc - > calculate | | ! ecc - > correct | | ! ecc - > hwctl ) {
if ( ! ecc - > calculate | | ! ecc - > correct | | ! ecc - > hwctl ) {
pr_warn ( " No ECC functions supplied; "
pr_warn ( " No ECC functions supplied; hardware ECC not possible \n " ) ;
" hardware ECC not possible \n " ) ;
BUG ( ) ;
BUG ( ) ;
}
}
if ( ! ecc - > read_page )
if ( ! ecc - > read_page )
@ -3737,8 +3795,7 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc - > read_page = = nand_read_page_hwecc | |
ecc - > read_page = = nand_read_page_hwecc | |
! ecc - > write_page | |
! ecc - > write_page | |
ecc - > write_page = = nand_write_page_hwecc ) ) {
ecc - > write_page = = nand_write_page_hwecc ) ) {
pr_warn ( " No ECC functions supplied; "
pr_warn ( " No ECC functions supplied; hardware ECC not possible \n " ) ;
" hardware ECC not possible \n " ) ;
BUG ( ) ;
BUG ( ) ;
}
}
/* Use standard syndrome read/write page function? */
/* Use standard syndrome read/write page function? */
@ -3762,9 +3819,8 @@ int nand_scan_tail(struct mtd_info *mtd)
}
}
break ;
break ;
}
}
pr_warn ( " %d byte HW ECC not possible on "
pr_warn ( " %d byte HW ECC not possible on %d byte page size, fallback to SW ECC \n " ,
" %d byte page size, fallback to SW ECC \n " ,
ecc - > size , mtd - > writesize ) ;
ecc - > size , mtd - > writesize ) ;
ecc - > mode = NAND_ECC_SOFT ;
ecc - > mode = NAND_ECC_SOFT ;
case NAND_ECC_SOFT :
case NAND_ECC_SOFT :
@ -3798,27 +3854,28 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc - > read_oob = nand_read_oob_std ;
ecc - > read_oob = nand_read_oob_std ;
ecc - > write_oob = nand_write_oob_std ;
ecc - > write_oob = nand_write_oob_std ;
/*
/*
* Board driver should supply ecc . size and ecc . bytes values to
* Board driver should supply ecc . size and ecc . strength values
* select how many bits are correctable ; see nand_bch_init ( )
* to select how many bits are correctable . Otherwise , default
* for details . Otherwise , default to 4 bits for large page
* to 4 bits for large page devices .
* devices .
*/
*/
if ( ! ecc - > size & & ( mtd - > oobsize > = 64 ) ) {
if ( ! ecc - > size & & ( mtd - > oobsize > = 64 ) ) {
ecc - > size = 512 ;
ecc - > size = 512 ;
ecc - > bytes = 7 ;
ecc - > strength = 4 ;
}
}
/* See nand_bch_init() for details. */
ecc - > bytes = DIV_ROUND_UP (
ecc - > strength * fls ( 8 * ecc - > size ) , 8 ) ;
ecc - > priv = nand_bch_init ( mtd , ecc - > size , ecc - > bytes ,
ecc - > priv = nand_bch_init ( mtd , ecc - > size , ecc - > bytes ,
& ecc - > layout ) ;
& ecc - > layout ) ;
if ( ! ecc - > priv ) {
if ( ! ecc - > priv ) {
pr_warn ( " BCH ECC initialization failed! \n " ) ;
pr_warn ( " BCH ECC initialization failed! \n " ) ;
BUG ( ) ;
BUG ( ) ;
}
}
ecc - > strength = ecc - > bytes * 8 / fls ( 8 * ecc - > size ) ;
break ;
break ;
case NAND_ECC_NONE :
case NAND_ECC_NONE :
pr_warn ( " NAND_ECC_NONE selected by board driver. "
pr_warn ( " NAND_ECC_NONE selected by board driver. This is not recommended! \n " ) ;
" This is not recommended! \n " ) ;
ecc - > read_page = nand_read_page_raw ;
ecc - > read_page = nand_read_page_raw ;
ecc - > write_page = nand_write_page_raw ;
ecc - > write_page = nand_write_page_raw ;
ecc - > read_oob = nand_read_oob_std ;
ecc - > read_oob = nand_read_oob_std ;
@ -3851,6 +3908,11 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc - > layout - > oobavail + = ecc - > layout - > oobfree [ i ] . length ;
ecc - > layout - > oobavail + = ecc - > layout - > oobfree [ i ] . length ;
mtd - > oobavail = ecc - > layout - > oobavail ;
mtd - > oobavail = ecc - > layout - > oobavail ;
/* ECC sanity check: warn if it's too weak */
if ( ! nand_ecc_strength_good ( mtd ) )
pr_warn ( " WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip \n " ,
mtd - > name ) ;
/*
/*
* Set the number of read / write steps for one page depending on ECC
* Set the number of read / write steps for one page depending on ECC
* mode .
* mode .
@ -3884,8 +3946,16 @@ int nand_scan_tail(struct mtd_info *mtd)
chip - > pagebuf = - 1 ;
chip - > pagebuf = - 1 ;
/* Large page NAND with SOFT_ECC should support subpage reads */
/* Large page NAND with SOFT_ECC should support subpage reads */
if ( ( ecc - > mode = = NAND_ECC_SOFT ) & & ( chip - > page_shift > 9 ) )
switch ( ecc - > mode ) {
chip - > options | = NAND_SUBPAGE_READ ;
case NAND_ECC_SOFT :
case NAND_ECC_SOFT_BCH :
if ( chip - > page_shift > 9 )
chip - > options | = NAND_SUBPAGE_READ ;
break ;
default :
break ;
}
/* Fill in remaining MTD driver data */
/* Fill in remaining MTD driver data */
mtd - > type = nand_is_slc ( chip ) ? MTD_NANDFLASH : MTD_MLCNANDFLASH ;
mtd - > type = nand_is_slc ( chip ) ? MTD_NANDFLASH : MTD_MLCNANDFLASH ;
@ -3915,7 +3985,7 @@ int nand_scan_tail(struct mtd_info *mtd)
* properly set .
* properly set .
*/
*/
if ( ! mtd - > bitflip_threshold )
if ( ! mtd - > bitflip_threshold )
mtd - > bitflip_threshold = mtd - > ecc_strength ;
mtd - > bitflip_threshold = DIV_ROUND_UP ( mtd - > ecc_strength * 3 , 4 ) ;
return 0 ;
return 0 ;
}
}