diff --git a/src/main.c b/src/main.c index 9eec715..3e58f35 100644 --- a/src/main.c +++ b/src/main.c @@ -66,6 +66,7 @@ void usage(void) " -h display this message\n"\ " -d disable internal ECC(use read and write page size + OOB size)\n"\ " -I ECC ignore errors(for read test only)\n"\ + " -k Skip BAD pages, try read or write in to next page\n"\ " -L print list support chips\n"\ " -i read the chip ID info\n"\ "" EHELP ""\ @@ -91,9 +92,9 @@ int main(int argc, char* argv[]) title(); #ifdef EEPROM_SUPPORT - while ((c = getopt(argc, argv, "diIhveLl:a:w:r:E:f:8")) != -1) + while ((c = getopt(argc, argv, "diIhveLkl:a:w:r:E:f:8")) != -1) #else - while ((c = getopt(argc, argv, "diIhveuLl:a:w:r:")) != -1) + while ((c = getopt(argc, argv, "diIhveukLl:a:w:r:")) != -1) #endif { switch(c) @@ -145,6 +146,9 @@ int main(int argc, char* argv[]) case 'I': ECC_ignore = 1; break; + case 'k': + Skip_BAD_page = 1; + break; case 'd': ECC_fcheck = 0; _ondie_ecc_flag = 0; @@ -189,7 +193,7 @@ int main(int argc, char* argv[]) if (op == 0) usage(); - if (op == 'x' || (ECC_ignore && !ECC_fcheck) || (op == 'w' && ECC_ignore)) { + if (op == 'x' || (ECC_ignore && !ECC_fcheck) || (ECC_ignore && Skip_BAD_page) || (op == 'w' && ECC_ignore)) { printf("Conflicting options, only one option at a time.\n\n"); return -1; } diff --git a/src/nandcmd_api.h b/src/nandcmd_api.h index 27f4aee..8d257ab 100644 --- a/src/nandcmd_api.h +++ b/src/nandcmd_api.h @@ -23,6 +23,7 @@ void support_snand_list(void); extern int ECC_fcheck; extern int ECC_ignore; +extern int Skip_BAD_page; extern unsigned char _ondie_ecc_flag; #endif /* __NANDCMD_API_H__ */ diff --git a/src/spi_nand_flash.c b/src/spi_nand_flash.c index 5f1a7f6..de8a941 100644 --- a/src/spi_nand_flash.c +++ b/src/spi_nand_flash.c @@ -131,10 +131,16 @@ #define _SPI_NAND_DEVICE_ID_F50L1G41A0 0x21 #define _SPI_NAND_DEVICE_ID_F50L1G41LB 0x01 #define _SPI_NAND_DEVICE_ID_F50L2G41LB 0x0A -#define _SPI_NAND_DEVICE_ID_W25N01GV 0xAA -#define _SPI_NAND_DEVICE_ID_W25M02GV 0xAB +#define _SPI_NAND_DEVICE_ID_1_W25N01GV 0xAA +#define _SPI_NAND_DEVICE_ID_2_W25N01GV 0x21 +#define _SPI_NAND_DEVICE_ID_1_W25N02KV 0xAA +#define _SPI_NAND_DEVICE_ID_2_W25N02KV 0x22 +#define _SPI_NAND_DEVICE_ID_1_W25M02GV 0xAB +#define _SPI_NAND_DEVICE_ID_2_W25M02GV 0x21 #define _SPI_NAND_DEVICE_ID_MXIC35LF1GE4AB 0x12 #define _SPI_NAND_DEVICE_ID_MXIC35LF2GE4AB 0x22 +#define _SPI_NAND_DEVICE_ID_1_MXIC35LF2GE4AD 0x26 +#define _SPI_NAND_DEVICE_ID_2_MXIC35LF2GE4AD 0x03 #define _SPI_NAND_DEVICE_ID_MXIC35LF4GE4AB 0x32 #define _SPI_NAND_DEVICE_ID_A5U12A21ASC 0x20 #define _SPI_NAND_DEVICE_ID_A5U1GA21BWS 0x21 @@ -179,6 +185,7 @@ #define _SPI_NAND_DEVICE_ID_FM25G02 0xF2 #define _SPI_NAND_DEVICE_ID_FM25G02C 0x92 #define _SPI_NAND_DEVICE_ID_XT26G02B 0xF2 +#define _SPI_NAND_DEVICE_ID_XT26G01C 0x11 #define _SPI_NAND_DEVICE_ID_XT26G01A 0xE1 #define _SPI_NAND_DEVICE_ID_XT26G02A 0xE2 #define _SPI_NAND_DEVICE_ID_PSU1GS20BN 0x21 @@ -241,6 +248,7 @@ int ECC_fcheck = 1; int ECC_ignore = 0; +int Skip_BAD_page = 0; static unsigned char _plane_select_bit = 0; static unsigned char _die_id = 0; @@ -706,7 +714,8 @@ static const struct SPI_NAND_FLASH_INFO_T spi_nand_flash_tables[] = { { mfr_id: _SPI_NAND_MANUFACTURER_ID_WINBOND, - dev_id: _SPI_NAND_DEVICE_ID_W25N01GV, + dev_id: _SPI_NAND_DEVICE_ID_1_W25N01GV, + dev_id_2: _SPI_NAND_DEVICE_ID_2_W25N01GV, ptr_name: "WINBOND W25N01G", device_size: _SPI_NAND_CHIP_SIZE_1GBIT, page_size: _SPI_NAND_PAGE_SIZE_2KBYTE, @@ -721,7 +730,24 @@ static const struct SPI_NAND_FLASH_INFO_T spi_nand_flash_tables[] = { { mfr_id: _SPI_NAND_MANUFACTURER_ID_WINBOND, - dev_id: _SPI_NAND_DEVICE_ID_W25M02GV, + dev_id: _SPI_NAND_DEVICE_ID_1_W25N02KV, + dev_id_2: _SPI_NAND_DEVICE_ID_2_W25N02KV, + ptr_name: "WINBOND W25N02KV", + device_size: _SPI_NAND_CHIP_SIZE_2GBIT, + page_size: _SPI_NAND_PAGE_SIZE_2KBYTE, + oob_size: _SPI_NAND_OOB_SIZE_128BYTE, + erase_size: _SPI_NAND_BLOCK_SIZE_128KBYTE, + dummy_mode: SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND, + read_mode: SPI_NAND_FLASH_READ_SPEED_MODE_DUAL, + write_mode: SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE, + oob_free_layout: &ooblayout_winbond, + feature: SPI_NAND_FLASH_FEATURE_NONE, + }, + + { + mfr_id: _SPI_NAND_MANUFACTURER_ID_WINBOND, + dev_id: _SPI_NAND_DEVICE_ID_1_W25M02GV, + dev_id_2: _SPI_NAND_DEVICE_ID_2_W25M02GV, ptr_name: "WINBOND W25M02G", device_size: _SPI_NAND_CHIP_SIZE_2GBIT, page_size: _SPI_NAND_PAGE_SIZE_2KBYTE, @@ -764,6 +790,22 @@ static const struct SPI_NAND_FLASH_INFO_T spi_nand_flash_tables[] = { feature: SPI_NAND_FLASH_PLANE_SELECT_HAVE, }, + { + mfr_id: _SPI_NAND_MANUFACTURER_ID_MXIC, + dev_id: _SPI_NAND_DEVICE_ID_1_MXIC35LF2GE4AD, + dev_id_2: _SPI_NAND_DEVICE_ID_2_MXIC35LF2GE4AD, + ptr_name: "MXIC MX35LF2GE4AD", + device_size: _SPI_NAND_CHIP_SIZE_2GBIT, + page_size: _SPI_NAND_PAGE_SIZE_2KBYTE, + oob_size: _SPI_NAND_OOB_SIZE_128BYTE, + erase_size: _SPI_NAND_BLOCK_SIZE_128KBYTE, + dummy_mode: SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND, + read_mode: SPI_NAND_FLASH_READ_SPEED_MODE_DUAL, + write_mode: SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE, + oob_free_layout: &ooblayout_mxic, + feature: SPI_NAND_FLASH_PLANE_SELECT_HAVE, + }, + { mfr_id: _SPI_NAND_MANUFACTURER_ID_ZENTEL, dev_id: _SPI_NAND_DEVICE_ID_A5U12A21ASC, @@ -1396,6 +1438,20 @@ static const struct SPI_NAND_FLASH_INFO_T spi_nand_flash_tables[] = { oob_free_layout: &ooblayout_type1, feature: SPI_NAND_FLASH_FEATURE_NONE, }, + { + ptr_name: "XTX XT26G01C", + mfr_id: _SPI_NAND_MANUFACTURER_ID_XTX, + dev_id: _SPI_NAND_DEVICE_ID_XT26G01C, + device_size: _SPI_NAND_CHIP_SIZE_1GBIT, + page_size: _SPI_NAND_PAGE_SIZE_2KBYTE, + oob_size: _SPI_NAND_OOB_SIZE_128BYTE, + erase_size: _SPI_NAND_BLOCK_SIZE_128KBYTE, + dummy_mode: SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND, + read_mode: SPI_NAND_FLASH_READ_SPEED_MODE_DUAL, + write_mode: SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE, + oob_free_layout: &ooblayout_type19, + feature: SPI_NAND_FLASH_FEATURE_NONE, + }, { ptr_name: "XTX XT26G01A", @@ -2077,11 +2133,13 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_read_id ( struct SPI_NAND_FLASH_IN /* 4. Read data (Manufacture ID and Device ID) */ _SPI_NAND_READ_NBYTE( &(ptr_rtn_flash_id->mfr_id), _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); _SPI_NAND_READ_NBYTE( &(ptr_rtn_flash_id->dev_id), _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); + _SPI_NAND_READ_NBYTE( &(ptr_rtn_flash_id->dev_id_2), _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); /* 5. Chip Select High */ _SPI_NAND_READ_CHIP_SELECT_HIGH(); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_read_id : mfr_id = 0x%x, dev_id = 0x%x\n", ptr_rtn_flash_id->mfr_id, ptr_rtn_flash_id->dev_id); + _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_read_id : mfr_id = 0x%x, dev_id = 0x%x, dev_id_2 = 0x%x\n", + ptr_rtn_flash_id->mfr_id, ptr_rtn_flash_id->dev_id, ptr_rtn_flash_id->dev_id_2); return (rtn_status); } @@ -2116,11 +2174,13 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_read_id_2 ( struct SPI_NAND_FLASH_ /* 3. Read data (Manufacture ID and Device ID) */ _SPI_NAND_READ_NBYTE( &(ptr_rtn_flash_id->mfr_id), _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); _SPI_NAND_READ_NBYTE( &(ptr_rtn_flash_id->dev_id), _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); + _SPI_NAND_READ_NBYTE( &(ptr_rtn_flash_id->dev_id_2), _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); /* 4. Chip Select High */ _SPI_NAND_READ_CHIP_SELECT_HIGH(); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_read_id_2 : mfr_id = 0x%x, dev_id = 0x%x\n", ptr_rtn_flash_id->mfr_id, ptr_rtn_flash_id->dev_id); + _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_read_id_2 : mfr_id = 0x%x, dev_id = 0x%x, dev_id_2 = 0x%x\n", + ptr_rtn_flash_id->mfr_id, ptr_rtn_flash_id->dev_id, ptr_rtn_flash_id->dev_id_2); return (rtn_status); } @@ -2689,6 +2749,13 @@ static SPI_NAND_FLASH_RTN_T ecc_fail_check( u32 page_number ) rtn_status = SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; } } + else if (((ptr_dev_info_t->mfr_id == _SPI_NAND_MANUFACTURER_ID_XTX) && (ptr_dev_info_t->dev_id == _SPI_NAND_DEVICE_ID_XT26G01C))) + { + if(((status & 0xF0) >> 4) == 0xF) + { + rtn_status = SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; + } + } else if (((ptr_dev_info_t->mfr_id == _SPI_NAND_MANUFACTURER_ID_XTX) && (ptr_dev_info_t->dev_id == _SPI_NAND_DEVICE_ID_XT26G01A))) { if(((status & 0x3C) >> 2) == 0x8) @@ -3110,7 +3177,10 @@ static SPI_NAND_FLASH_RTN_T spi_nand_write_page( u32 page_number, u32 data_offse ptr_dev_info_t = _SPI_NAND_GET_DEVICE_INFO_PTR; /* Read Current page data to software cache buffer */ - spi_nand_read_page(page_number, speed_mode); + rtn_status = spi_nand_read_page(page_number, speed_mode); + if (Skip_BAD_page && (rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK)) { /* skip BAD page, go to next page */ + return SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; + } /* Rewirte the software cahe buffer */ if(data_len > 0) @@ -3284,6 +3354,13 @@ static SPI_NAND_FLASH_RTN_T spi_nand_write_internal( u32 dst_addr, u32 len, u32 } rtn_status = spi_nand_write_page(page_number, addr_offset, &(ptr_buf[len - remain_len]), data_len, 0, NULL, 0 , speed_mode); + /* skip BAD page or internal error on write page, go to next page */ + if( Skip_BAD_page && ((rtn_status == SPI_NAND_FLASH_RTN_PROGRAM_FAIL) || (rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK)) ) { + if( ((addr_offset + remain_len ) < (ptr_dev_info_t->page_size)) ) + break; + write_addr += data_len; + continue; + } /* 8. Write remain data if neccessary */ write_addr += data_len; @@ -3355,8 +3432,15 @@ static SPI_NAND_FLASH_RTN_T spi_nand_read_internal ( u32 addr, u32 len, u8 *ptr_ rtn_status = spi_nand_read_page(page_number, speed_mode); if(rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK) { - *status = SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; - return (rtn_status); + if (!Skip_BAD_page) { + *status = SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; + return (rtn_status); + } + /* skip BAD page, go to next page */ + if( (data_offset + remain_len) < ptr_dev_info_t->page_size ) + break; + read_addr += (ptr_dev_info_t->page_size - data_offset); + continue; } /* 3. Retrieve the request data */ @@ -3777,6 +3861,55 @@ static void spi_nand_manufacute_init( struct SPI_NAND_FLASH_INFO_T *ptr_device_t } } +/*------------------------------------------------------------------------------------ + * FUNCTION: SPI_NAND_FLASH_RTN_T spi_nand_compare( const struct SPI_NAND_FLASH_INFO_T *ptr_rtn_device_t, + * const struct SPI_NAND_FLASH_INFO_T *spi_nand_flash_table ) + * PURPOSE : Compare a read SPI NAND flash ID with a flash table entry ID. + * AUTHOR : + * CALLED BY + * - + * CALLS + * - + * PARAMs : + * INPUT : ptr_rtn_device_t - The pointer to a read SPI NAND flash description. + * spi_nand_flash_table - The pointer to a flash table entry. + * OUTPUT: None. + * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. + * NOTES : + * MODIFICTION HISTORY: + * + *------------------------------------------------------------------------------------ + */ +static SPI_NAND_FLASH_RTN_T spi_nand_compare( const struct SPI_NAND_FLASH_INFO_T *ptr_rtn_device_t, + const struct SPI_NAND_FLASH_INFO_T *spi_nand_flash_table ) +{ + if ( spi_nand_flash_table->dev_id_2 == 0 ) + { + _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_compare: mfr_id = 0x%x, dev_id = 0x%x\n", + spi_nand_flash_table->mfr_id, spi_nand_flash_table->dev_id); + + if ( ( (ptr_rtn_device_t->mfr_id) == spi_nand_flash_table->mfr_id) && + ( (ptr_rtn_device_t->dev_id) == spi_nand_flash_table->dev_id) ) + { + return SPI_NAND_FLASH_RTN_NO_ERROR; + } + } + else + { + _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_compare: mfr_id = 0x%x, dev_id = 0x%x, dev_id_2 = 0x%x\n", + spi_nand_flash_table->mfr_id, spi_nand_flash_table->dev_id, spi_nand_flash_table->dev_id_2); + + if ( ( (ptr_rtn_device_t->mfr_id) == spi_nand_flash_table->mfr_id) && + ( (ptr_rtn_device_t->dev_id) == spi_nand_flash_table->dev_id) && + ( (ptr_rtn_device_t->dev_id_2) == spi_nand_flash_table->dev_id_2) ) + { + return SPI_NAND_FLASH_RTN_NO_ERROR; + } + } + + return SPI_NAND_FLASH_RTN_PROBE_ERROR; +} + /*------------------------------------------------------------------------------------ * FUNCTION: static SPI_NAND_FLASH_RTN_T spi_nand_probe( struct SPI_NAND_FLASH_INFO_T *ptr_rtn_device_t ) * PURPOSE : To probe SPI NAND flash id. @@ -3808,10 +3941,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_probe( struct SPI_NAND_FLASH_INFO_T *ptr_rt for ( i = 0; i < (sizeof(spi_nand_flash_tables)/sizeof(struct SPI_NAND_FLASH_INFO_T)); i++) { - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1,"spi_nand_probe: table[%d]: mfr_id = 0x%x, dev_id = 0x%x\n", i, spi_nand_flash_tables[i].mfr_id, spi_nand_flash_tables[i].dev_id ); - - if ( ( (ptr_rtn_device_t->mfr_id) == spi_nand_flash_tables[i].mfr_id) && - ( (ptr_rtn_device_t->dev_id) == spi_nand_flash_tables[i].dev_id) ) + if ( spi_nand_compare( ptr_rtn_device_t, &spi_nand_flash_tables[i] ) == SPI_NAND_FLASH_RTN_NO_ERROR ) { ecc_size = ((spi_nand_flash_tables[i].device_size / spi_nand_flash_tables[i].erase_size) * ((spi_nand_flash_tables[i].erase_size / spi_nand_flash_tables[i].page_size) * spi_nand_flash_tables[i].oob_size)); ptr_rtn_device_t->device_size = ECC_fcheck ? spi_nand_flash_tables[i].device_size : spi_nand_flash_tables[i].device_size + ecc_size; @@ -3841,10 +3971,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_probe( struct SPI_NAND_FLASH_INFO_T *ptr_rt for ( i = 0; i < (sizeof(spi_nand_flash_tables) / sizeof(struct SPI_NAND_FLASH_INFO_T)); i++) { - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1,"spi_nand_probe: table[%d]: mfr_id = 0x%x, dev_id = 0x%x\n", i, spi_nand_flash_tables[i].mfr_id, spi_nand_flash_tables[i].dev_id ); - - if ( ( (ptr_rtn_device_t->mfr_id) == spi_nand_flash_tables[i].mfr_id) && - ( (ptr_rtn_device_t->dev_id) == spi_nand_flash_tables[i].dev_id) ) + if ( spi_nand_compare( ptr_rtn_device_t, &spi_nand_flash_tables[i] ) == SPI_NAND_FLASH_RTN_NO_ERROR ) { ecc_size = ((spi_nand_flash_tables[i].device_size / spi_nand_flash_tables[i].erase_size) * ((spi_nand_flash_tables[i].erase_size / spi_nand_flash_tables[i].page_size) * spi_nand_flash_tables[i].oob_size)); ptr_rtn_device_t->device_size = ECC_fcheck ? spi_nand_flash_tables[i].device_size : spi_nand_flash_tables[i].device_size + ecc_size; @@ -3900,7 +4027,16 @@ static SPI_NAND_FLASH_RTN_T spi_nand_probe( struct SPI_NAND_FLASH_INFO_T *ptr_rt } } - _SPI_NAND_PRINTF("spi_nand_probe: mfr_id = 0x%x, dev_id = 0x%x\n", ptr_rtn_device_t->mfr_id, ptr_rtn_device_t->dev_id); + if ( ptr_rtn_device_t->dev_id_2 == 0 ) + { + _SPI_NAND_PRINTF("spi_nand_probe: mfr_id = 0x%x, dev_id = 0x%x\n", ptr_rtn_device_t->mfr_id, ptr_rtn_device_t->dev_id); + } + else + { + _SPI_NAND_PRINTF("spi_nand_probe: mfr_id = 0x%x, dev_id = 0x%x, dev_id_2 = 0x%x\n", + ptr_rtn_device_t->mfr_id, ptr_rtn_device_t->dev_id, ptr_rtn_device_t->dev_id_2); + } + if(rtn_status == SPI_NAND_FLASH_RTN_NO_ERROR) { unsigned char feature = 0; diff --git a/src/spi_nand_flash.h b/src/spi_nand_flash.h index c953952..3121f5c 100644 --- a/src/spi_nand_flash.h +++ b/src/spi_nand_flash.h @@ -92,6 +92,7 @@ struct spi_nand_flash_ooblayout struct SPI_NAND_FLASH_INFO_T { u8 mfr_id; u8 dev_id; + u8 dev_id_2; const char *ptr_name; u32 device_size; /* Flash total Size */ u32 page_size; /* Page Size */