Nandflash driver porting (5)

Source: Internet
Author: User

Nandflash driver porting series Article Navigation:

Nandflash driver porting (1)

Nandflash driver porting (2)

Nandflash driver porting (III)

Nandflash driver porting (4)

Nandflash driver porting (5)

Nandflash driver porting (6)

Six in total

 

 

 

Next to the previous article

 

1. ecc_correctdata () finds and corrects ECC errors.

BOOL ECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc, ECC_CORRECT_TYPE nType){DWORD  nErrDataNo;DWORD  nErrBitNo;//BYTE Status;BYTE nErrDataNum;UINT8  nErrByteNum;UINT8 countdown = 155;BOOL bRet = TRUE;//RETAILMSG(1, (TEXT("#### FMD_DRIVER:::ECC_CorrectData %x, %x, %x\n"), sectoraddr, nRetEcc, nType));#if 0if( (nRetEcc & NF_ECC8ERR0_ECC_READY) )return TRUE;#endif// 8bit ECC error searching engine needs mini mum 372 cycles to find any errorcountdown = 372;while(countdown--);
// Wait until the ECC error search is complete while (nf_ecc8_err0 & 0x80000000 );
// Obtain the 8bit ECC decoding result nerrdatanum = nf_ecc8bit_num; // No error, if free page (all 0xff) if (g_pnfconreg-> nf8eccerr0> 29) & 0x1) {nerrdatanum = 0;} If (nerrdatanum = 0) {Bret = true; retailmsg (0, (text ("no error \ n"); goto finished ;} else if (nerrdatanum = 9) {Bret = false; retailmsg (1, (text ("more than 8-bit error, uncorrectable \ n"); goto finished ;} else if (nerrdatanum> 9) {Bret = false; retailmsg (1, (text ("Reserved \ n"); goto finished;} else {
// Obtain the location of the error bit for (nerrbytenum = 1; nerrbytenum <= nerrdatanum; nerrbytenum ++) {Switch (nerrbytenum) {Case 1: nerrdatano = nf_ecc8location_byte1; break; case 2: nerrdatano = break; Case 3: nerrdatano = break; Case 4: nerrdatano = break; Case 5: nerrdatano = nf_ecc8location_byte5; break; Case 6: nerrdatano = nf_ecc8location_byte6; break; Case 7: nerrdatano = nf_ecc8location_byte7; break; case 8: nerrdatano = nf_ecc8location_byte8; break; default: break ;}
// Locate the specific error bit: nerrbitno = nf_ecc8location_bit (nerrbytenum );
// Correct pdata [nerrdatano] ^ = (1 <nerrbitno); retailmsg (1, (text ("8bit ecc_correctdata % x, % x \ n "), nerrdatanum, nerrbytenum, nerrdatano, nerrbitno) ;}} finished: Return Bret ;}

Here is the modified one. 8-bit ECC verification is supported.

Note that
// No error, if free page (all 0xff)
If (g_pnfconreg-> nf8eccerr0> 29) & 0x1 ){
Nerrdatanum = 0;
}

Code? Let's compare the manual to see who this nf8eccerr0 [29] is.

As you can see, nf8eccerr0 [29] is a reserved bit. However, I refer to the BSP source code of MLC 6410 and find that this bit is used to determine whether it is all 0xff. This Reserved Bit is also found in the latest source code of 3.0 released by Apsara stack. It is still used for 8-bit ECC. The two source codes referenced support both nandflash. Why is it written as reserved bits in 6410 chip documents? Is it a written mistake or is it retained? Why is the BSP of Samsung MLC also used? Let's get down to the details. We haven't seen any adverse effects since we used the above.

 

 

2. fmd_lb_readsector ()

Original code:

BOOL FMD_LB_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors){    ULONG SectorAddr = (ULONG)startSectorAddr;    DWORD       i, j;    volatile DWORD        rddata;    UINT32 nRetEcc = 0;    DWORD MECCBuf[16],tempMECCBuf[2];  // gjl 8    UINT16 nSectorLoop,nSectorLoop1;    int NewSpareAddr = 4096;  //gjl 2048    int NewDataAddr = 0;    int NewSectorAddr = startSectorAddr;    int SectorSpareAddr;    UINT8 TempSectorInfo[40];BYTE *pSectorBuff1 = (BYTE *)pSectorBuff;UINT16 k=40;#if CHECK_SPAREECC    DWORD SECCBuf[4];   // gjl 2#endif#if (NAND_DEBUG)    RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR %x %x\n"),startSectorAddr,NewDataAddr));#endif    if (!pSectorBuff && !pSectorInfoBuff)    {        return(FALSE);    }    if ( dwNumSectors > 1 )    {        RETAILMSG(1, (TEXT("######## FATAL ERROR => FMD::FMD_ReadSector->dwNumsectors is bigger than 1. \n")));        return FALSE;    }if (!pSectorBuff)    {        if (!NAND_LB_ReadSectorInfo(startSectorAddr, pSectorInfoBuff))        {#if (NAND_DEBUG)    RETAILMSG(1,(TEXT("#### FMD_DRIVER:::54321\n")));#endif            return FALSE;        }#if (NAND_DEBUG)RETAILMSG(1,(TEXT("#### FMD_DRIVER:::12345\n")));#endif        return TRUE;    }NF_nFCE_L();    NF_CLEAR_RB();    NF_CMD(CMD_READ);                            // Send read command.    NF_ADDR((NewSpareAddr)&0xff);    NF_ADDR((NewSpareAddr>>8)&0xff);    NF_ADDR((NewSectorAddr) & 0xff);    NF_ADDR((NewSectorAddr >> 8) & 0xff);#if    LB_NEED_EXT_ADDR    NF_ADDR((NewSectorAddr >> 16) & 0xff);#endif    NF_CMD(CMD_READ3);                        // 2nd command    NF_DETECT_RB();                                // Wait for command to complete.    NF_MSGLENGTH_512();    NF_ECCTYPE_4BIT();    if (pSectorInfoBuff)    {        pSectorInfoBuff->bBadBlock = NF_RDDATA_BYTE();        pSectorInfoBuff->dwReserved1 = NF_RDDATA_WORD();        pSectorInfoBuff->bOEMReserved = NF_RDDATA_BYTE();        pSectorInfoBuff->wReserved2 = NF_RDDATA_BYTE();        pSectorInfoBuff->wReserved2 |= (NF_RDDATA_BYTE()<<8);    }    else    {         for(i=0; i<sizeof(SectorInfo)/sizeof(DWORD); i++)         {            rddata = (DWORD) NF_RDDATA_WORD();        // read and trash the data         }    }    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)    {        MECCBuf[nSectorLoop] = NF_RDDATA_WORD();    }#if DEBUG_WRITE_READ_EQUAL    for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++)    {    g_MECCBuf_R[nSectorLoop] = MECCBuf[nSectorLoop];    }#endif    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)    {        NewDataAddr = nSectorLoop * SECTOR_SIZE;        NF_CMD(CMD_RDO);                            // Send read command.        NF_ADDR((NewDataAddr)&0xff);        NF_ADDR((NewDataAddr>>8)&0xff);        NF_CMD(CMD_RDO2);    // 2nd commandNF_MSGLENGTH_512();NF_ECCTYPE_4BIT();        NF_RSTECC();        NF_MECC_UnLock();        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);            }        }        else        {            RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);                    // Read page/sector data.        }        SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8;NF_WRDATA_WORD(MECCBuf[2*nSectorLoop]);SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+4;NF_WRDATA_WORD(MECCBuf[2*nSectorLoop+1]);        NF_MECC_Lock();        //decode done        while (!(NF_RDSTAT & (1<<6)));        tempMECCBuf[0]= NF_RDMECC0();        tempMECCBuf[1] = NF_RDMECC1();pSectorBuff1 = pSectorBuff+nSectorLoop*SECTOR_SIZE;        if (!ECC_CorrectData(startSectorAddr, pSectorBuff1, nRetEcc, ECC_CORRECT_MAIN))        {RETAILMSG(1,(TEXT("ECC ERROR\n")));            return FALSE;        }    }    NF_nFCE_H();return TRUE;}

This is the source code in Fei Ling BSP. There are still a lot of changes in it.

First, let's look at the definition section
DWORD meccbuf [16], tempmeccbuf [2]; // gjl 8

Because 8-bit ECC verification is to be used, the buffer of this ECC should be 32, 1 page = 8*512 bytes, each byte of data is read and the ECC is stored in four 32-bit registers. Therefore, 8*4 buffers are required:

DWORD meccbuf [32];

As for tempmeccbuf, we can see from the above Code that it is a piece of garbage and it is useless at all. Here we delete it.

After the definition is complete, we need to enable some related interruptions (if this is not the case, we will find that the ECC cannot be properly verified. Please let us know the specific reasons)

In

If (! Psectorbuff &&! Psectorinfobuff)
{
Return (false );
}

Add the following code:

g_pNFConReg->NFCONT |= (1<<10);// Enable illegal access interrupt controlg_pNFConReg->NFCONT |= (1<<9);// Enable RnB interruptg_pNFConReg->NFCONT |= (1<<12);// Enable 4bit,8bit ECC decoding completion interrupt control

 

The following code is displayed: (the Part omitted in the middle will not be introduced. If you are free, refer to the loongembedded csdn blog)

Nf_msglength_512 ();

Nf_ecctype_4bit ();

We use 8bit ECC, So we modify nf_ecctype_4bit ();

NF_ECCTYPE_8BIT();

The next step is to read the sectorinfo data and then read the ECC data:
For (nsectorloop = 0; nsectorloop <sectors_per_page * 2; nsectorloop ++)
{
Meccbuf [nsectorloop] = nf_rddata_word ();
}

Because we use 8-bit ECC, which only reads 8*2*4 bytes of ECC, and 8-bit ECC requires 8*4*4 bytes, we modify it:

    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*4; nSectorLoop++)// 8bit ECC,4096/page = 8*512, it has 8*4(register) ECC data    {        MECCBuf[nSectorLoop] = NF_RDDATA_WORD();    }

Next, we can see the operation of reading one page of Data cyclically:

Yes
For (nsectorloop = 0; nsectorloop <sectors_per_page; nsectorloop ++)
{
Newdataaddr = nsectorloop * sector_size;

Nf_cmd (cmd_rdo); // send READ command.
Nf_addr (newdataaddr) & 0xff );
Nf_addr (newdataaddr> 8) & 0xff );
Nf_cmd (pai_rdo2); // 2nd Command

Nf_msglength_512 ();
Nf_ecctype_4bit ();

Here, change the above nf_ecctype_4bit ();:

NF_ECCTYPE_8BIT();

By the way, add the following two sentences to the above sentence:

NF_ECC_8BIT_STOP();// init 8bit ECC decodingNF_ECC_DIRECTION_IN();// 4/8BIT ECC Decoding, read page

Next, the original code is:

Nf_rstecc ();
Nf_mecc_unlock ();

Here I will change the order of the two operations:

        NF_MECC_UnLock();        NF_RSTECC();

You must set nf_ecc_8bit_stop (); before nf_rstecc (), because the document says: If you want to stop current work and start encoding/Decoding for new data, you must set 8 bitstop (nfcont [11]) before set initmecc (nfcont [5]) bit.

The following code reads 512 bytes of data:
If (DWORD) (effecctorbuff + nsectorloop * sector_size) & 0x3)
{
For (I = 0; I <sector_size/sizeof (DWORD); I ++)
{
Rddata = (DWORD) nf_rddata_word ();
(Export ctorbuff + nsectorloop * sector_size) [I * 4 + 0] = (byte) (rddata & 0xff );
(Export ctorbuff + nsectorloop * sector_size) [I * 4 + 1] = (byte) (rddata> 8 & 0xff );
(Export ctorbuff + nsectorloop * sector_size) [I * 4 + 2] = (byte) (rddata> 16 & 0xff );
(Export ctorbuff + nsectorloop * sector_size) [I * 4 + 3] = (byte) (rddata> 24 & 0xff );
}
}
Else
{
Rdpage512 (export ctorbuff + nsectorloop * sector_size); // read page/sector data.
}

Then, we can see that the Code writes the previously read ECC into it. Here we should compare the written ECC with the read ECC in the ECC module to find the error bit.
Sectorspareaddr = newspareaddr + 8 + nsectorloop * 8;
Nf_wrdata_word (meccbuf [2 * nsectorloop]);
Sectorspareaddr = newspareaddr + 8 + nsectorloop * 8 + 4;
Nf_wrdata_word (meccbuf [2 * nsectorloop + 1]);
Nf_mecc_lock ();

Here, you also need to change it to write an 8bit ECC:

SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8;NF_WRDATA_WORD(MECCBuf[4*nSectorLoop]);SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+4;NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+1]);SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+8;NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+2]);SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+12;NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+3]);NF_MECC_Lock();

After that, wait for the decoding operation to complete:
// Decode done
While (! (Nf_rdstat & (1 <6 )));
Tempmeccbuf [0] = nf_rdmecc0 ();
Tempmeccbuf [1] = nf_rdmecc1 ();

The operations containing tempmeccbuf in the following two sentences can be directly deleted, Which is useless. After processing this, the ECC error is found and corrected:

Repeated ctorbuff1 = repeated ctorbuff + nsectorloop * sector_size;

If (! Ecc_correctdata (startsectoraddr, effecctorbuff1, nretecc, ecc_correct_main ))
{
Retailmsg (1, (text ("ECC error \ n ")));
Return false;
}
}

 

Nf_nfce_h ();

Before nf_nfce_h ();, We need to disable some enable interruptions:

g_pNFConReg->NFCONT &= ~(1<<10);// Disable illegal access interrupt controlg_pNFConReg->NFCONT &= ~(1<<9);// Disable RnB interrupt

 

 

 

3. nand_lb_readsectorinfo ()

Original BSP code:

BOOL NAND_LB_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo){    BOOL bRet = TRUE;    int NewSpareAddr = 4096;  //gjl 2048    int NewSectorAddr = sectorAddr;    DWORD MECCBuf[16];  // gjl 8    UINT16 nSectorLoop, i;    UINT8 TempInfo[40];#if CHECK_SPAREECC    DWORD SECCBuf[4];   //gjl 2    UINT32 nRetEcc = 0;#endif    NF_nFCE_L();    NF_CLEAR_RB();    NF_CMD(CMD_READ);                            // Send read confirm command.    NF_ADDR((NewSpareAddr)&0xff);    NF_ADDR((NewSpareAddr>>8)&0xff);    NF_ADDR((NewSectorAddr)&0xff);    NF_ADDR((NewSectorAddr>>8) & 0xff);#if    LB_NEED_EXT_ADDR    NF_ADDR((NewSectorAddr >> 16) & 0xff);#endif    NF_CMD(CMD_READ3);    NF_DETECT_RB();    pInfo->bBadBlock = NF_RDDATA_BYTE();    pInfo->dwReserved1  = NF_RDDATA_WORD();    pInfo->bOEMReserved = NF_RDDATA_BYTE();    pInfo->wReserved2 = NF_RDDATA_BYTE();    pInfo->wReserved2 |= (NF_RDDATA_BYTE()<<8);    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)    {        MECCBuf[nSectorLoop] = NF_RDDATA_WORD();    }    NF_nFCE_H(); #if (NAND_DEBUG)    RETAILMSG(1,(TEXT("#### FMD_DRIVER:::56565656\n")));#endif    return bRet;}

Let's take a look at the defined DWORD meccbuf [16]; // gjl 8

This should be changed:

    DWORD MECCBuf[32];

 

Then, before the nf_nfce_l (); operation, add:

NF_ECCTYPE_8BIT();// use 8bit ECC typeNF_ECC_8BIT_STOP();// init 8bit ECC decoding

 

Then, we can see the operations to read ECC:
For (nsectorloop = 0; nsectorloop <sectors_per_page * 2; nsectorloop ++)
{
Meccbuf [nsectorloop] = nf_rddata_word ();
}

This should be changed:

    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*4; nSectorLoop++)    {        MECCBuf[nSectorLoop] = NF_RDDATA_WORD();    }

 

 

4. fmd_sb_readsector ()

BOOL FMD_SB_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors){    ULONG SectorAddr = (ULONG)startSectorAddr;    ULONG MECC;    UINT32 nRet = TRUE;    UINT32 nRetEcc = 0;#if (NAND_DEBUG)    RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbreadT \n")));#endif    if (!pSectorBuff && !pSectorInfoBuff)    {        RETAILMSG(1,(TEXT("[FMD:ERR] FMD_SB_ReadSector(0x%08x, 0x%08x) : Invalid Parameter\n"), pSectorBuff, pSectorInfoBuff));        return(FALSE);    }    while (dwNumSectors--)    {        NF_RSTECC();        NF_MECC_UnLock();        NF_nFCE_L();        if (!pSectorBuff)        {            NF_CLEAR_RB();            NF_CMD(CMD_READ2);            // Send read confirm command.            NF_ADDR(0);                                    // Ignored.            NF_ADDR(SectorAddr         & 0xff);            // Page address.            NF_ADDR((SectorAddr >>  8) & 0xff);#if    SB_NEED_EXT_ADDR            NF_ADDR((SectorAddr >> 16) & 0xff);#endif            NF_DETECT_RB();            RdPageInfo((PBYTE)pSectorInfoBuff);    // Read page/sector information.            pSectorInfoBuff++;        }        else        {            NF_CLEAR_RB();            NF_CMD(CMD_READ);                    // Send read command.            NF_ADDR(0);                                    // Column = 0.            NF_ADDR(SectorAddr         & 0xff);            // Page address.            NF_ADDR((SectorAddr >>  8) & 0xff);#if    SB_NEED_EXT_ADDR            NF_ADDR((SectorAddr >> 16) & 0xff);#endif            NF_DETECT_RB();                    // Wait for command to complete.            if( ((DWORD) pSectorBuff) & 0x3)            {                RdPage512Unalign (pSectorBuff);            }            else            {                RdPage512(pSectorBuff);                    // Read page/sector data.            }            NF_MECC_Lock();            if (pSectorInfoBuff)            {                RdPageInfo((PBYTE)pSectorInfoBuff);        // Read page/sector information.                pSectorInfoBuff ++;            }            else            {                BYTE TempInfo[8];                RdPageInfo(TempInfo);                       // Read page/sector information.            }            MECC  = NF_RDDATA_BYTE() << 0;            MECC |= NF_RDDATA_BYTE() << 8;            MECC |= NF_RDDATA_BYTE() << 16;            MECC |= (NF_RDMECC0() &0xff000000);            //MECC |= NF_RDDATA_BYTE() << 24;            NF_WRMECCD0( ((MECC&0xff00)<<8)|(MECC&0xff) );             NF_WRMECCD1( ((MECC&0xff000000)>>8)|((MECC&0xff0000)>>16) );             nRetEcc = NF_ECC_ERR0;            switch(nRetEcc & 0x3)            {                case 0:    // No Error                    nRet = TRUE;                    break;                case 1:    // 1-bit Error(Correctable)                    RETAILMSG(1,(TEXT("ECC correctable error(0x%x)\n"), SectorAddr));                    (pSectorBuff)[(nRetEcc>>7)&0x7ff] ^= (1<<((nRetEcc>>4)&0x7));                    nRet = TRUE;                    break;                case 2:    // Multiple Error                    RETAILMSG(1,(TEXT("ECC Uncorrectable error(0x%x)\n"), SectorAddr));                    nRet = FALSE;                    break;                case 3:    // ECC area Error                    RETAILMSG(1,(TEXT("ECC area error\n")));                default:                    nRet = FALSE;                    break;            }            pSectorBuff += NAND_SECTOR_SIZE;        }        NF_nFCE_H();        ++SectorAddr;    }    return(nRet);}

Fmd_sb_readsector () describes SLC read operations. You do not need to modify them here.
 

 

At this point, this article will introduce the ECC correction and reading data. Next, we will introduce the data writing section.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.