原创地址:http://blog.csdn.net/loongembedded/article/details/24176643
备注:处理器为S3C2451,flash为K9K8G08U0D
1. ECC分配标准
先来看三星NAND FLASH spare区域的分配标准:
图1
2. StepldrECC的处理
Stepldr的写采用自己的函数FMD_LB_WriteSector_Steploader,stepldr采用8bit的ECC纠错,为什么呢?S3C2451 FLASH控制器部分给出说明:
1. Auto boot by: The boot code istransferred into 8-KB Steppingstone after reset. After the boot code is
transfered, boot code will beexecuted on the Steppingstone.
Note: IROMboot support 8Bit ECC correction on Nand device booting
此函数通过设置NFCONF[24:23]=1来支持8bit ECC。还有需要注意的是,这里采用另一组参数:
- <SPAN style="FONT-SIZE: 14px">#define DEFAULT_TACLS (1) // 1 HCLK (7.5ns)
- #define DEFAULT_TWRPH0 (4) // 5 HCLK(37.5ns)
- #define DEFAULT_TWRPH1 (1) // 2 HCLK(15ns)</SPAN>
<span style="font-size:14px;">#define DEFAULT_TACLS (1) // 1 HCLK (7.5ns)
#define DEFAULT_TWRPH0 (4) // 5 HCLK(37.5ns)
#define DEFAULT_TWRPH1 (1) // 2 HCLK(15ns)</span>
2.1 写stepldr镜像文件时ECC的操作
当写入512字节(不包括spare数据)的数据后, 8bit ECC模块内部产生ECC奇偶校验码,这些校验码自动更新到NF8MECC0、NF8MECC1、NF8MECC2、NF8MECC3寄存器中,然后可以把校验码写入到spare区域,下面来看代码:
- <SPAN style="FONT-SIZE: 14px">typedef struct
- {
- UINT32 n8MECC0; // 8MECC0
- UINT32 n8MECC1; // 8MECC1
- UINT32 n8MECC2; // 8MECC2
- UINT8 n8MECC3; // 8MECC3
- } MECC8;</SPAN>
<span style="font-size:14px;">typedef struct
{
UINT32 n8MECC0; // 8MECC0
UINT32 n8MECC1; // 8MECC1
UINT32 n8MECC2; // 8MECC2
UINT8 n8MECC3; // 8MECC3
} MECC8;</span>
此结构体的定位,为什么n8MECC3需要定义为8位的,见寄存器的说明:
图2
- <SPAN style="FONT-SIZE: 14px">MECC8 t8MECC[4];
- // initializevariable.
- for(i = 0; i < 4; i++) {
- t8MECC[i].n8MECC0 = 0x0;
- t8MECC[i].n8MECC1 = 0x0;
- t8MECC[i].n8MECC2 = 0x0;
- t8MECC[i].n8MECC3 = 0x0;
- }</SPAN>
<span style="font-size:14px;">MECC8 t8MECC[4];
// initializevariable.
for(i = 0; i < 4; i++) {
t8MECC[i].n8MECC0 = 0x0;
t8MECC[i].n8MECC1 = 0x0;
t8MECC[i].n8MECC2 = 0x0;
t8MECC[i].n8MECC3 = 0x0;
}</span>
每往main区域写入512字节的数据,都产生ECC校验码并保存在t8MECC[nSectorLoop]中。
- <SPAN style="FONT-SIZE: 14px"> // Write each Sector in the Page. (4 Sectorper Page, Loop 4 times.)
- for (nSectorLoop = 0; nSectorLoop <SECTORS_PER_PAGE; nSectorLoop++)
- {
- // Initialize ECC register
- NF_MECC_UnLock();
- NF_RSTECC();
- // Special case to handle un-alignedbuffer pointer.
- if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
- {
- // Write the data
- for(i=0; i<SECTOR_SIZE/sizeof(DWORD);i++)
- {
- wrdata =(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
- wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
- wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
- wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
- NF_WRDATA_WORD(wrdata);
- }
- }
- else
- {
- WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
- }
- NF_MECC_Lock();
- while(!(s2450NAND->NFSTAT&(1<<7))) ;
- s2450NAND->NFSTAT|=(1<<7);
- // Read out the ECC value generated by HW
- t8MECC[nSectorLoop].n8MECC0 =NF_8MECC0();
- t8MECC[nSectorLoop].n8MECC1 =NF_8MECC1();
- t8MECC[nSectorLoop].n8MECC2 =NF_8MECC2();
- t8MECC[nSectorLoop].n8MECC3 =(NF_8MECC3() & 0xff);
- }</SPAN>
<span style="font-size:14px;"> // Write each Sector in the Page. (4 Sectorper Page, Loop 4 times.)
for (nSectorLoop = 0; nSectorLoop <SECTORS_PER_PAGE; nSectorLoop++)
{
// Initialize ECC register
NF_MECC_UnLock();
NF_RSTECC();
// Special case to handle un-alignedbuffer pointer.
if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
{
// Write the data
for(i=0; i<SECTOR_SIZE/sizeof(DWORD);i++)
{
wrdata =(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
wrdata |=(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
NF_WRDATA_WORD(wrdata);
}
}
else
{
WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
}
NF_MECC_Lock();
while(!(s2450NAND->NFSTAT&(1<<7))) ;
s2450NAND->NFSTAT|=(1<<7);
// Read out the ECC value generated by HW
t8MECC[nSectorLoop].n8MECC0 =NF_8MECC0();
t8MECC[nSectorLoop].n8MECC1 =NF_8MECC1();
t8MECC[nSectorLoop].n8MECC2 =NF_8MECC2();
t8MECC[nSectorLoop].n8MECC3 =(NF_8MECC3() & 0xff);
}</span>
这里要重点注意了,先来看数据手册的说明:
图3
也就是说,如果使用512字节的NAND FLASH memory,可以直接把校验码写入到spare区域,但如果使用多于512字节的NAND FLASH memory(上面的代码是写入4*512字节的数据),就需要先拷贝校验码到其他的存储空间(比如DRAM,这里对应局部变量数据t8MECC),等写完所有的main数据后,再把拷贝后的校验码写到spare区域。
//写完所有的main数据,现在写入到spare区域
- <SPAN style="FONT-SIZE: 14px"> for(nSectorLoop = 0; nSectorLoop < 4;nSectorLoop++)
- {
- NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC0); // 4 byte n8MECC0
- NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC1); // 4 byte n8MECC1
- NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC2); // 4 byte n8MECC2
- NF_WRDATA_BYTE((t8MECC[nSectorLoop].n8MECC3) & 0xff); // 1 byten8MECC3
- }</SPAN>
<span style="font-size:14px;"> for(nSectorLoop = 0; nSectorLoop < 4;nSectorLoop++)
{
NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC0); // 4 byte n8MECC0
NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC1); // 4 byte n8MECC1
NF_WRDATA_WORD(t8MECC[nSectorLoop].n8MECC2); // 4 byte n8MECC2
NF_WRDATA_BYTE((t8MECC[nSectorLoop].n8MECC3) & 0xff); // 1 byten8MECC3
}</span>
由此可知stepldr镜像文件对应的每页的16 字节spare区域安排如下:
图4
2.2 读stepldr镜像文件时ECC的操作
Sepldr内容是由S3C2451的IROM代码来读取的,读取时校验码的比较也是由IROM来完成的,为什么eboot在写入stepldr时采用8bit ECC,是因为:
Note: IROMboot support 8Bit ECC correction on Nand device booting
3. EbootECC的处理
Eboot中写eboot和NK镜像文件采用1bit ECC
3.1 写Eboot和NK镜像文件时ECC的操作
由FMD_LB_WriteSector函数来实现,首先是写入main区域,然后重生ECC码,再写入spare区域。
- <SPAN style="FONT-SIZE: 14px">// Write eachSector in the Page. (4 Sector per Page, Loop 4 times.)
- for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
- {
- // Initialize ECC register
- NF_RSTECC();
- NF_MECC_UnLock();
- // Special case tohandle un-aligned buffer pointer.
- if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
- {
- // Write the data
- for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)
- {
- wrdata= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
- wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
- wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
- wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
- NF_WRDATA_WORD(wrdata);
- }
- }
- else
- {
- WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
- }
- NF_MECC_Lock();
- // Read out the ECC value generated by HW
- MECCBuf[nSectorLoop]= NF_RDMECC0();
- }</SPAN>
<span style="font-size:14px;">// Write eachSector in the Page. (4 Sector per Page, Loop 4 times.)
for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
{
// Initialize ECC register
NF_RSTECC();
NF_MECC_UnLock();
// Special case tohandle un-aligned buffer pointer.
if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
{
// Write the data
for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)
{
wrdata= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
wrdata|= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
NF_WRDATA_WORD(wrdata);
}
}
else
{
WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
}
NF_MECC_Lock();
// Read out the ECC value generated by HW
MECCBuf[nSectorLoop]= NF_RDMECC0();
}</span>
当读或是写main数据(不包括spare数据)完成时,自动把ECC模块产生的校验码更新到NFMECC0、NFMECC1寄存器中,并且ECC状态寄存器的值不会改变。这时可以从这些寄存器中读取其值。
- <SPAN style="FONT-SIZE: 14px">// Write theSectorInfo data to the media
- // NOTE: This hardware is odd:only a byte can be written at a time and it must reside in the
- // upper byte of a USHORT.
- if(pSectorInfoBuff) // SectorInfoBuff啊 瞒 乐促搁, 角力 Sector Info甫持绰促.
- {
- #if CHECK_SPAREECC
- NF_RSTECC();
- NF_SECC_UnLock();
- #endif
- // Write the first reserved field (DWORD)
- NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);
- NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);
- NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);
- #if CHECK_SPAREECC
- NF_SECC_Lock();
- #endif
- NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);
- NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);
- }
- else // SectorInfoBuff啊 厚绢乐促搁, 歹固 data甫 持绰促. (0xffffffff ffffffff)
- {
- // Make sure weadvance the Flash's write pointer (even though we aren't writing the SectorInfodata)
- for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)
- {
- NF_WRDATA_WORD(0xffffffff);
- }
- }</SPAN>
<span style="font-size:14px;">// Write theSectorInfo data to the media
// NOTE: This hardware is odd:only a byte can be written at a time and it must reside in the
// upper byte of a USHORT.
if(pSectorInfoBuff) // SectorInfoBuff啊 瞒 乐促搁, 角力 Sector Info甫持绰促.
{
#if CHECK_SPAREECC
NF_RSTECC();
NF_SECC_UnLock();
#endif
// Write the first reserved field (DWORD)
NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);
NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);
NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);
#if CHECK_SPAREECC
NF_SECC_Lock();
#endif
NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);
NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);
}
else // SectorInfoBuff啊 厚绢乐促搁, 歹固 data甫 持绰促. (0xffffffff ffffffff)
{
// Make sure weadvance the Flash's write pointer (even though we aren't writing the SectorInfodata)
for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)
{
NF_WRDATA_WORD(0xffffffff);
}
}</span>
上面的内容是把SectorInfo结构体的数据写入到spare中,并且为这些数据产生ECC校验码,下面接着把main数据的ECC校验码接着写入spare中
- <SPAN style="FONT-SIZE: 14px"> // Write the ECC value to the flash
- NF_WRDATA_WORD(MECCBuf[0]);
- NF_WRDATA_WORD(MECCBuf[1]);
- NF_WRDATA_WORD(MECCBuf[2]);
- NF_WRDATA_WORD(MECCBuf[3]);</SPAN>
<span style="font-size:14px;"> // Write the ECC value to the flash
NF_WRDATA_WORD(MECCBuf[0]);
NF_WRDATA_WORD(MECCBuf[1]);
NF_WRDATA_WORD(MECCBuf[2]);
NF_WRDATA_WORD(MECCBuf[3]);</span>
上面在写入SectorInfo结构体bBadBlock、dwReserved1和bOEMReserved数据到spare的时候,为这三个数据产生ECC校验码,下面从NFSECC寄存器中读取出ECC校验码并写入到spare中
- <SPAN style="FONT-SIZE: 14px">#if CHECK_SPAREECC
- if(pSectorInfoBuff)
- {
- SECCBuf =NF_RDSECC();
- NF_WRDATA_WORD(SECCBuf);
- }
- #endif</SPAN>
<span style="font-size:14px;">#if CHECK_SPAREECC
if(pSectorInfoBuff)
{
SECCBuf =NF_RDSECC();
NF_WRDATA_WORD(SECCBuf);
}
#endif</span>
根据上面的代码,可以每页(2048字节=4*512)对应的spare区域安排如下:
图5
其中bBadBlock表示坏块信息,如果其值为0xFF表示是好块,如果不是则为坏块;dwReserved1用来保存逻辑页(2048字节)的数量,比如,如果是第1block的第1页,那么它的值=64页,因为我们的flash一个block=64页。bOEMReserved,我们可以用来设置block的属性,比如设置此block为预留block,或是只读block等。wReserved2用来为FAL只是数据是否有效(Indicates data is valid for the FAL( flash abstraction layer))。
3.2 读Eboot和NK镜像文件时ECC的操作
由FMD_LB_ReadSector函数来实现,先读取spare区域的数据
(1) 读取spare区域数据,并进行ECC校验
//读取图5中的前8字节的数据
- <SPAN style="FONT-SIZE: 14px"> if (pSectorInfoBuff)
- {
- #if CHECK_SPAREECC
- NF_RSTECC();
- NF_SECC_UnLock();
- #endif
- pSectorInfoBuff->bBadBlock= NF_RDDATA_BYTE();
- pSectorInfoBuff->dwReserved1= NF_RDDATA_WORD();
- pSectorInfoBuff->bOEMReserved= NF_RDDATA_BYTE();
- #if CHECK_SPAREECC
- NF_SECC_Lock();
- #endif
- pSectorInfoBuff->wReserved2= NF_RDDATA_BYTE();
- pSectorInfoBuff->wReserved2|= (NF_RDDATA_BYTE()<<8);
- }
- // If there is noSectorInfoBuffer, Just read and waste.
- else
- {
- for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)
- rddata = (DWORD)NF_RDDATA_WORD(); // readand trash the data
- }</SPAN>
<span style="font-size:14px;"> if (pSectorInfoBuff)
{
#if CHECK_SPAREECC
NF_RSTECC();
NF_SECC_UnLock();
#endif
pSectorInfoBuff->bBadBlock= NF_RDDATA_BYTE();
pSectorInfoBuff->dwReserved1= NF_RDDATA_WORD();
pSectorInfoBuff->bOEMReserved= NF_RDDATA_BYTE();
#if CHECK_SPAREECC
NF_SECC_Lock();
#endif
pSectorInfoBuff->wReserved2= NF_RDDATA_BYTE();
pSectorInfoBuff->wReserved2|= (NF_RDDATA_BYTE()<<8);
}
// If there is noSectorInfoBuffer, Just read and waste.
else
{
for(i=0;i<sizeof(SectorInfo)/sizeof(DWORD); i++)
rddata = (DWORD)NF_RDDATA_WORD(); // readand trash the data
}</span>
//接着读取保存MECC0校验数据(这是写入main数据时重生的ECC校验码)
- <SPAN style="FONT-SIZE: 14px"> for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
- {
- MECCBuf[nSectorLoop]= NF_RDDATA_WORD();
- }</SPAN>
<span style="font-size:14px;"> for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
{
MECCBuf[nSectorLoop]= NF_RDDATA_WORD();
}</span>
//读取出spare的ECC,然后写入到NFSECCD中,并校验
- <SPAN style="FONT-SIZE: 14px">#if CHECK_SPAREECC
- if (pSectorInfoBuff)
- {
- SECCBuf =NF_RDDATA_WORD();
- NF_WRSECCD((SECCBuf&0xff)|((SECCBuf<<8)&0xff0000));
- nRetEcc =NF_ECC_ERR0;
- if(!ECC_CorrectData(startSectorAddr, (LPBYTE)pSectorInfoBuff, nRetEcc,ECC_CORRECT_SPARE))
- returnFALSE;
- }
- #endif</SPAN>
<span style="font-size:14px;">#if CHECK_SPAREECC
if (pSectorInfoBuff)
{
SECCBuf =NF_RDDATA_WORD();
NF_WRSECCD((SECCBuf&0xff)|((SECCBuf<<8)&0xff0000));
nRetEcc =NF_ECC_ERR0;
if(!ECC_CorrectData(startSectorAddr, (LPBYTE)pSectorInfoBuff, nRetEcc,ECC_CORRECT_SPARE))
returnFALSE;
}
#endif</span>
上面代码依据于数据手册下面的部分:
图6
当把数据写入到NFSECCD后,通过NFECCERR0来定为ECC出错的具体信息,如下图:
图7
下面重点来看ECC_CorrectData函数
- <SPAN style="FONT-SIZE: 14px">BOOLECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc,ECC_CORRECT_TYPE nType)
- {
- DWORD nErrStatus;
- DWORD nErrDataNo;
- DWORD nErrBitNo;
- UINT32 nErrDataMask;
- UINT32 nErrBitMask = 0x7;
- BOOL bRet = TRUE;
- if (nType == ECC_CORRECT_MAIN)
- {
- //RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_MAIN\r\n")));
- nErrStatus = 0;
- nErrDataNo = 7;
- nErrBitNo = 4;
- nErrDataMask =0x7ff;
- }
- else if (nType ==ECC_CORRECT_SPARE)
- {
- //RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_SPARE\r\n")));
- nErrStatus = 2;
- nErrDataNo = 21;
- nErrBitNo = 18;
- nErrDataMask = 0xf;
- }
- else
- {
- //RETAILMSG(1,(TEXT("ECC_CorrectData()--->value=%d\r\n"),nType));
- return FALSE;
- }
- switch((nRetEcc>>nErrStatus)& 0x3)
- {
- case 0: // No Error
- //RETAILMSG(1,(TEXT("ECC_CorrectData()--->noerror\r\n")));
- bRet= TRUE;
- break;
- case 1: // 1-bit Error(Correctable)
- RETAILMSG(1,(TEXT("%cECCcorrectable error(0x%x). Byte:%d, bit:%d\r\n"),((nType==ECC_CORRECT_MAIN)?'M':'S'), sectoraddr,(nRetEcc>>nErrDataNo)&nErrDataMask,(nRetEcc>>nErrBitNo)&nErrBitMask));
- (pData)[(nRetEcc>>nErrDataNo)&nErrDataMask]^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));
- bRet= TRUE;
- break;
- case 2: // Multiple Error
- RETAILMSG(1,(TEXT("%cECCUncorrectable error(0x%x)\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S'),sectoraddr));
- bRet= FALSE;
- break;
- case 3: // ECC area Error
- RETAILMSG(1,(TEXT("%cECCarea error\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S')));
- default:
- bRet= FALSE;
- break;
- }
- return bRet;
- }</SPAN>
<span style="font-size:14px;">BOOLECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc,ECC_CORRECT_TYPE nType)
{
DWORD nErrStatus;
DWORD nErrDataNo;
DWORD nErrBitNo;
UINT32 nErrDataMask;
UINT32 nErrBitMask = 0x7;
BOOL bRet = TRUE;
if (nType == ECC_CORRECT_MAIN)
{
//RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_MAIN\r\n")));
nErrStatus = 0;
nErrDataNo = 7;
nErrBitNo = 4;
nErrDataMask =0x7ff;
}
else if (nType ==ECC_CORRECT_SPARE)
{
//RETAILMSG(1,(TEXT("ECC_CorrectData()--->ECC_CORRECT_SPARE\r\n")));
nErrStatus = 2;
nErrDataNo = 21;
nErrBitNo = 18;
nErrDataMask = 0xf;
}
else
{
//RETAILMSG(1,(TEXT("ECC_CorrectData()--->value=%d\r\n"),nType));
return FALSE;
}
switch((nRetEcc>>nErrStatus)& 0x3)
{
case 0: // No Error
//RETAILMSG(1,(TEXT("ECC_CorrectData()--->noerror\r\n")));
bRet= TRUE;
break;
case 1: // 1-bit Error(Correctable)
RETAILMSG(1,(TEXT("%cECCcorrectable error(0x%x). Byte:%d, bit:%d\r\n"),((nType==ECC_CORRECT_MAIN)?'M':'S'), sectoraddr,(nRetEcc>>nErrDataNo)&nErrDataMask,(nRetEcc>>nErrBitNo)&nErrBitMask));
(pData)[(nRetEcc>>nErrDataNo)&nErrDataMask]^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));
bRet= TRUE;
break;
case 2: // Multiple Error
RETAILMSG(1,(TEXT("%cECCUncorrectable error(0x%x)\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S'),sectoraddr));
bRet= FALSE;
break;
case 3: // ECC area Error
RETAILMSG(1,(TEXT("%cECCarea error\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S')));
default:
bRet= FALSE;
break;
}
return bRet;
}</span>
此函数需要密切结合NFECCERR0寄存器来理解,见下图:
图8
(2) 读取main区域数据,并进行ECC校验
这部分代码原理和上面的基本一样
- <SPAN style="FONT-SIZE: 14px">// Read eachSector in the Page. (4 Sector per Page, Loop 4 times.)
- for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
- {
- // calculate startaddress of each Sector
- NewDataAddr =nSectorLoop * SECTOR_SIZE;
- // Set address forrandom access
- NF_CMD(CMD_RDO);
- NF_ADDR((NewDataAddr)&0xff);
- NF_ADDR((NewDataAddr>>8)&0xff);
- NF_CMD(CMD_RDO2);
- // Initialize ECCmodule
- NF_RSTECC();
- NF_MECC_UnLock();
- // Special case to handle un-aligned bufferpointer.
- if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
- {
- for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)
- {
- rddata= (DWORD) NF_RDDATA_WORD();
- (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0]= (BYTE)(rddata & 0xff);
- (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]= (BYTE)(rddata>>8 & 0xff);
- (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]= (BYTE)(rddata>>16 & 0xff);
- (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]= (BYTE)(rddata>>24 & 0xff);
- }
- }
- // usual case tohandle 4byte aligned buffer pointer
- else
- {
- RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE); // Read page/sector data.
- }
- NF_MECC_Lock();
- // Check ECC aboutMain Data with MECC parity codel
- NF_WRMECCD0(((MECCBuf[nSectorLoop]&0xff00)<<8)|(MECCBuf[nSectorLoop]&0xff) );
- NF_WRMECCD1(((MECCBuf[nSectorLoop]&0xff000000)>>8)|((MECCBuf[nSectorLoop]&0xff0000)>>16));
- nRetEcc =NF_ECC_ERR0;
- if(!ECC_CorrectData(startSectorAddr, pSectorBuff+nSectorLoop*SECTOR_SIZE,nRetEcc, ECC_CORRECT_MAIN))
- {
- RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR 7\r\n")));
- returnFALSE;
- }
- }</SPAN>
<span style="font-size:14px;">// Read eachSector in the Page. (4 Sector per Page, Loop 4 times.)
for (nSectorLoop = 0; nSectorLoop< SECTORS_PER_PAGE; nSectorLoop++)
{
// calculate startaddress of each Sector
NewDataAddr =nSectorLoop * SECTOR_SIZE;
// Set address forrandom access
NF_CMD(CMD_RDO);
NF_ADDR((NewDataAddr)&0xff);
NF_ADDR((NewDataAddr>>8)&0xff);
NF_CMD(CMD_RDO2);
// Initialize ECCmodule
NF_RSTECC();
NF_MECC_UnLock();
// Special case to handle un-aligned bufferpointer.
if( ((DWORD)(pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
{
for(i=0;i<SECTOR_SIZE/sizeof(DWORD); i++)
{
rddata= (DWORD) NF_RDDATA_WORD();
(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0]= (BYTE)(rddata & 0xff);
(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]= (BYTE)(rddata>>8 & 0xff);
(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]= (BYTE)(rddata>>16 & 0xff);
(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]= (BYTE)(rddata>>24 & 0xff);
}
}
// usual case tohandle 4byte aligned buffer pointer
else
{
RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE); // Read page/sector data.
}
NF_MECC_Lock();
// Check ECC aboutMain Data with MECC parity codel
NF_WRMECCD0(((MECCBuf[nSectorLoop]&0xff00)<<8)|(MECCBuf[nSectorLoop]&0xff) );
NF_WRMECCD1(((MECCBuf[nSectorLoop]&0xff000000)>>8)|((MECCBuf[nSectorLoop]&0xff0000)>>16));
nRetEcc =NF_ECC_ERR0;
if(!ECC_CorrectData(startSectorAddr, pSectorBuff+nSectorLoop*SECTOR_SIZE,nRetEcc, ECC_CORRECT_MAIN))
{
RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR 7\r\n")));
returnFALSE;
}
}</span>