Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""\
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions src/nandcmd_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
Expand Down
172 changes: 154 additions & 18 deletions src/spi_nand_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/spi_nand_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down