Below is a patch to AM335x StarterWare_02_00_00_07 to support writing 16-bit BCH ECC data to NAND flash. Using this code I have managed to get an AM3354 processor to boot from flashing with ECC turned-on with a 4KiB/page NAND chip (Micron MT29F8G08ABACAWP).
Changes in the patch:
- Suport 16-bit BCH ECC algorithm
- Use ONFI to read NAND geometry
- Work out NAND geometry before initialising ECC
- Store OOB layout in NandInfo_t rather than using #defines
- Simplified GPMCBCHECCCheckAndCorrect to set ELM_SYNDROME_FRGMT_x direct from GPMC_BCH_RESULT_x
- Add #defines for OOB layout required by AM335x boot code
I've tested reading and writing 8-bit and 16-bit BCH. I don't think I've broken anything, but do check yourself!
Hope this is of some use to someone
Jonathan
diff -ur AM335X_StarterWare_02_00_00_07/nandlib/include/nandlib.h AM335X_StarterWare/nandlib/include/nandlib.h --- AM335X_StarterWare_02_00_00_07/nandlib/include/nandlib.h 2012-08-06 09:54:08.000000000 +0100 +++ AM335X_StarterWare/nandlib/include/nandlib.h 2013-01-24 10:26:17.000000000 +0000 @@ -86,20 +86,20 @@ #define NAND_ECC_RS_4BIT_UNUSED_BYTECNT (6) #define NAND_ECC_RS_4BIT_BYTECNT (10) +// OOB layout for booting from NAND with ECC as per AM335x TRM +// 'Figure 26-15. ECC Data Mapping for 2 KB Page and 8b BCH Encoding' #define NAND_ECC_BCH_8BIT_OOB_OFFSET (2) -#define NAND_ECC_BCH_8BIT_BYTECNT (14) -#define NAND_ECC_BCH_8BIT_UNUSED_BYTECNT (2) -#define NAND_ECC_BCH_8BIT_NIBBLECNT (26) - -/*****************************************************************************/ -/* -** Macros which defines the last data and ecc bit in diffrent ECC schemes. -** -*/ -/* 512 bytes of data plus 13 bytes ECC */ -#define NAND_ECC_BCH_8BIT_LASTDATABIT ((512 + 13) * 8) -/* 13 bytes of ECC data plus 1 byte of ECC for ECC data */ -#define NAND_ECC_BCH_8BIT_LASTECCBIT ((13 + 1) * 8) +#define NAND_ECC_BCH_8BIT_BYTECNT (13) +#define NAND_ECC_BCH_8BIT_UNUSED_BYTECNT (0) +// Original StarterWare OOB layout: 13-bytes ECC with one byte spare +//#define NAND_ECC_BCH_8BIT_BYTECNT (14) +//#define NAND_ECC_BCH_8BIT_UNUSED_BYTECNT (1) + +// OOB layout for booting from NAND with ECC as per AM335x TRM +// Figure 26-16. ECC Data Mapping for 4 KB Page and 16b BCH Encoding +#define NAND_ECC_BCH_16BIT_OOB_OFFSET (2) +#define NAND_ECC_BCH_16BIT_BYTECNT (26) +#define NAND_ECC_BCH_16BIT_UNUSED_BYTECNT (0) /*****************************************************************************/ /* @@ -109,7 +109,6 @@ #define NAND_BYTES_PER_TRNFS (512) #define NAND_MAX_ECC_BYTES_PER_TRNFS (16) - /*****************************************************************************/ /* ** Macro which defines the values stored in OOB as bad block info. @@ -265,6 +264,9 @@ /* Device ID */ unsigned char devId; + /* Device model */ + char deviceModel[21]; + /* Count of chip selects the nand device uses */ int chipSelectCnt; /* NAND die cnt - how many die in package */ @@ -277,6 +279,10 @@ NandBlockSize_t blkSize; /* Pages per block */ unsigned int pagesPerBlk; + /* Blocks per die */ + unsigned int blksPerDie; + /* Overall size of the device */ + unsigned int size; /* DATA Register address */ unsigned int dataRegAddr; @@ -337,6 +343,7 @@ unsigned int eccOffSet; /* Total number of ecc bytes. */ unsigned int eccByteCnt; + unsigned int eccUnusedByteCnt; /* Function to initialize the controller w.r.t ECC */ NandStatus_t (*ECCInit)(NandInfo_t *nandInfo); /* Function to enable the ECC */ @@ -398,6 +405,8 @@ volatile unsigned char *rxData, unsigned char *eccData); +extern NandStatus_t NANDReadONFIInfo(NandInfo_t *nandInfo); + #ifdef __cplusplus } #endif diff -ur AM335X_StarterWare_02_00_00_07/nandlib/nand_gpmc.c AM335X_StarterWare/nandlib/nand_gpmc.c --- AM335X_StarterWare_02_00_00_07/nandlib/nand_gpmc.c 2012-08-06 09:54:08.000000000 +0100 +++ AM335X_StarterWare/nandlib/nand_gpmc.c 2013-01-24 10:17:42.000000000 +0000 @@ -267,66 +267,85 @@ */ static NandStatus_t GPMCBCHECCInit(NandInfo_t *nandInfo) { - unsigned int baseAddr; - unsigned int elmBaseAddr; - unsigned int cs; - volatile unsigned int timeOut; - NandStatus_t retVal; - - timeOut = 0xFFF; - retVal = NAND_STATUS_PASSED; - cs = nandInfo->hNandCtrlInfo->currChipSelect; - baseAddr = nandInfo->hNandCtrlInfo->baseAddr; - elmBaseAddr = nandInfo->hNandEccInfo->baseAddr; + unsigned int baseAddr = nandInfo->hNandCtrlInfo->baseAddr; + unsigned int elmBaseAddr = nandInfo->hNandEccInfo->baseAddr; + unsigned int cs = nandInfo->hNandCtrlInfo->currChipSelect; + volatile unsigned int timeOut = 0xFFF; + NandStatus_t retVal = NAND_STATUS_PASSED; GPMCECCDisable(baseAddr); GPMCECCAlgoSelect(baseAddr, GPMC_ECC_ALGORITHM_BCH); - if(nandInfo->eccType != NAND_ECC_ALGO_BCH_8BIT) + GPMCECCColumnSelect(baseAddr, nandInfo->busWidth); + GPMCECCCSSelect(baseAddr, cs); + GPMCECCBCHNumOfSectorsSelect(baseAddr, GPMC_ECC_BCH_NUMOFSECTS_1); + GPMCECCBCHWrapModeValSet(baseAddr, 1); + + GPMCECCResultRegSelect(baseAddr, GPMC_ECCPOINTER_RESULT_1); + GPMCECCResultRegClear(baseAddr); + + GPMCECCSizeValSet(baseAddr, GPMC_ECC_SIZE_0, GPMC_ECC_SIZE0_VAL); + GPMCECCSizeValSet(baseAddr, GPMC_ECC_SIZE_1, GPMC_ECC_SIZE1_VAL); + GPMCECCResultSizeSelect(baseAddr, GPMC_ECC_RESULT_1, GPMC_ECC_SIZE_0); + + /* ELM Module configuration */ + ELMModuleReset(elmBaseAddr); + while((ELMModuleResetStatusGet(elmBaseAddr) != 1) && (timeOut != 0)) { - retVal = NAND_STATUS_ECC_UNSUPPORTED; + timeOut--; } - else + if(timeOut == 0) { - GPMCECCBCHErrCorrectionCapSelect(baseAddr, - GPMC_ECC_BCH_ERRCORRCAP_UPTO_8BITS); - GPMCECCColumnSelect(baseAddr, nandInfo->busWidth); - GPMCECCCSSelect(baseAddr, cs); - GPMCECCBCHNumOfSectorsSelect(baseAddr, GPMC_ECC_BCH_NUMOFSECTS_1); - GPMCECCBCHWrapModeValSet(baseAddr, 1); - - GPMCECCResultRegSelect(baseAddr, GPMC_ECCPOINTER_RESULT_1); - GPMCECCResultRegClear(baseAddr); - - GPMCECCSizeValSet(baseAddr, GPMC_ECC_SIZE_0, GPMC_ECC_SIZE0_VAL); - GPMCECCSizeValSet(baseAddr, GPMC_ECC_SIZE_1, GPMC_ECC_SIZE1_VAL); - GPMCECCResultSizeSelect(baseAddr, GPMC_ECC_RESULT_1, GPMC_ECC_SIZE_0); - - /* ELM Module configuration */ - ELMModuleReset(elmBaseAddr); - while((ELMModuleResetStatusGet(elmBaseAddr) != 1) && (timeOut != 0)) - { - timeOut--; - } - if(timeOut == 0) - { - retVal = NAND_STATUS_FAILED; - } - else - { - ELMCAutoGatingConfig(elmBaseAddr, ELM_AUTOGATING_OCP_FREE); - ELMCIdleModeSelect(elmBaseAddr, ELM_IDLEMODE_NOIDLE); - ELMOCPClkActivityConfig(elmBaseAddr, ELM_CLOCKACTIVITYOCP_OCP_ON); - ELMIntStatusClear(elmBaseAddr, ELM_LOC_VALID_0_STATUS); - ELMIntConfig(elmBaseAddr, ELM_LOC_VALID_0_STATUS, ELM_INT_ENALBLE); + return NAND_STATUS_FAILED; + } + + ELMCAutoGatingConfig(elmBaseAddr, ELM_AUTOGATING_OCP_FREE); + ELMCIdleModeSelect(elmBaseAddr, ELM_IDLEMODE_NOIDLE); + ELMOCPClkActivityConfig(elmBaseAddr, ELM_CLOCKACTIVITYOCP_OCP_ON); + ELMIntStatusClear(elmBaseAddr, ELM_LOC_VALID_0_STATUS); + ELMIntConfig(elmBaseAddr, ELM_LOC_VALID_0_STATUS, ELM_INT_ENALBLE); + ELMECCSizeSet(elmBaseAddr, 0x7FF); + ELMModeSet(elmBaseAddr, ELM_MODE_PAGE, ELM_PAGEMODE_SECTOR_0); + + // Algorithm specific configuration + switch (nandInfo->eccType) + { + case NAND_ECC_ALGO_NONE: + case NAND_ECC_ALGO_HAMMING_1BIT: + case NAND_ECC_ALGO_RS_4BIT: + // Shouldn't get here! + retVal = NAND_STATUS_ECC_UNSUPPORTED; + break; + + case NAND_ECC_ALGO_BCH_16BIT: + GPMCECCBCHErrCorrectionCapSelect(baseAddr, + GPMC_ECC_BCH_ERRCORRCAP_UPTO_16BITS); + ELMErrCorrectionLevelSet(elmBaseAddr, ELM_ECC_BCH_LEVEL_16BITS); + nandInfo->hNandEccInfo->eccOffSet = NAND_ECC_BCH_16BIT_OOB_OFFSET + nandInfo->pageSize; + nandInfo->hNandEccInfo->eccByteCnt = NAND_ECC_BCH_16BIT_BYTECNT; + nandInfo->hNandEccInfo->eccUnusedByteCnt = NAND_ECC_BCH_16BIT_UNUSED_BYTECNT; + break; + + case NAND_ECC_ALGO_BCH_4BIT: + GPMCECCBCHErrCorrectionCapSelect(baseAddr, + GPMC_ECC_BCH_ERRCORRCAP_UPTO_4BITS); + ELMErrCorrectionLevelSet(elmBaseAddr, ELM_ECC_BCH_LEVEL_4BITS); + // TODO What is the layout for 4bit ECC? + nandInfo->hNandEccInfo->eccOffSet = NAND_ECC_BCH_8BIT_OOB_OFFSET + nandInfo->pageSize; + nandInfo->hNandEccInfo->eccByteCnt = NAND_ECC_BCH_8BIT_BYTECNT; + nandInfo->hNandEccInfo->eccUnusedByteCnt = NAND_ECC_BCH_8BIT_UNUSED_BYTECNT; + break; + + case NAND_ECC_ALGO_BCH_8BIT: + GPMCECCBCHErrCorrectionCapSelect(baseAddr, + GPMC_ECC_BCH_ERRCORRCAP_UPTO_8BITS); ELMErrCorrectionLevelSet(elmBaseAddr, ELM_ECC_BCH_LEVEL_8BITS); - ELMECCSizeSet(elmBaseAddr, 0x7FF); - ELMModeSet(elmBaseAddr, ELM_MODE_PAGE, ELM_PAGEMODE_SECTOR_0); nandInfo->hNandEccInfo->eccOffSet = NAND_ECC_BCH_8BIT_OOB_OFFSET + nandInfo->pageSize; nandInfo->hNandEccInfo->eccByteCnt = NAND_ECC_BCH_8BIT_BYTECNT; - } + nandInfo->hNandEccInfo->eccUnusedByteCnt = NAND_ECC_BCH_8BIT_UNUSED_BYTECNT; + break; } - return (retVal); + return retVal; } /** @@ -339,21 +358,8 @@ */ static void GPMCBCHWriteSet(NandInfo_t *nandInfo) { - unsigned int size1; - unsigned int size0; - - size1 = 0; - size0 = 0; - - if(nandInfo->eccType == NAND_ECC_ALGO_BCH_4BIT) - { - /* Not Supported */ - } - else if(nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) - { - size1 = (NAND_ECC_BCH_8BIT_BYTECNT * 2); - size0 = 0; - } + unsigned int size1 = nandInfo->hNandEccInfo->eccByteCnt * 2; + unsigned int size0 = 0; GPMCECCSizeValSet(nandInfo->hNandCtrlInfo->baseAddr, GPMC_ECC_SIZE_0, size0); GPMCECCSizeValSet(nandInfo->hNandCtrlInfo->baseAddr, GPMC_ECC_SIZE_1, size1); } @@ -368,22 +374,8 @@ */ static void GPMCBCHReadSet(NandInfo_t *nandInfo) { - unsigned int size1; - unsigned int size0; - - size1 = 0; - size0 = 0; - - if(nandInfo->eccType == NAND_ECC_ALGO_BCH_4BIT) - { - /* Not Supported */ - } - else if(nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) - { - size0 = ((NAND_ECC_BCH_8BIT_BYTECNT * 2) - - NAND_ECC_BCH_8BIT_UNUSED_BYTECNT); - size1 = NAND_ECC_BCH_8BIT_UNUSED_BYTECNT; - } + unsigned int size0 = (nandInfo->hNandEccInfo->eccByteCnt - nandInfo->hNandEccInfo->eccUnusedByteCnt) * 2; + unsigned int size1 = nandInfo->hNandEccInfo->eccUnusedByteCnt * 2; GPMCECCSizeValSet(nandInfo->hNandCtrlInfo->baseAddr, GPMC_ECC_SIZE_0, size0); GPMCECCSizeValSet(nandInfo->hNandCtrlInfo->baseAddr, GPMC_ECC_SIZE_1, size1); } @@ -405,37 +397,56 @@ static void GPMCBCHECCCalculate(NandInfo_t *nandInfo, unsigned char *ptrEccData) { unsigned int eccRes; - unsigned int baseAddr; - unsigned int eccType; - unsigned int cs; - - cs = nandInfo->hNandCtrlInfo->currChipSelect; - baseAddr = nandInfo->hNandCtrlInfo->baseAddr; - eccType = nandInfo->eccType; + unsigned int baseAddr = nandInfo->hNandCtrlInfo->baseAddr; + unsigned int cs = nandInfo->hNandCtrlInfo->currChipSelect; + unsigned char *ptr = ptrEccData; - if(eccType == NAND_ECC_ALGO_BCH_4BIT) + switch (nandInfo->eccType) { - /* Not Supported */ - } - else if(eccType == NAND_ECC_ALGO_BCH_8BIT) - { - eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_3, cs); - ptrEccData[0] = (eccRes & 0xFF); - eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_2, cs); - ptrEccData[1] = ((eccRes >> 24) & 0xFF); - ptrEccData[2] = ((eccRes >> 16) & 0xFF); - ptrEccData[3] = ((eccRes >> 8) & 0xFF); - ptrEccData[4] = (eccRes & 0xFF); - eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_1, cs); - ptrEccData[5] = ((eccRes >> 24) & 0xFF); - ptrEccData[6] = ((eccRes >> 16) & 0xFF); - ptrEccData[7] = ((eccRes >> 8) & 0xFF); - ptrEccData[8] = (eccRes & 0xFF); - eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_0, cs); - ptrEccData[9] = ((eccRes >> 24) & 0xFF); - ptrEccData[10] = ((eccRes >> 16) & 0xFF); - ptrEccData[11] = ((eccRes >> 8) & 0xFF); - ptrEccData[12] = (eccRes & 0xFF); + case NAND_ECC_ALGO_HAMMING_1BIT: + case NAND_ECC_ALGO_RS_4BIT: + case NAND_ECC_ALGO_NONE: + // Wrong algorithm - shouldn't get here! + return; + + case NAND_ECC_ALGO_BCH_16BIT: + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_6, cs); + *ptr++ = ((eccRes >> 8) & 0xFF); + *ptr++ = (eccRes & 0xFF); + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_5, cs); + *ptr++ = ((eccRes >> 24) & 0xFF); + *ptr++ = ((eccRes >> 16) & 0xFF); + *ptr++ = ((eccRes >> 8) & 0xFF); + *ptr++ = (eccRes & 0xFF); + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_4, cs); + *ptr++ = ((eccRes >> 24) & 0xFF); + *ptr++ = ((eccRes >> 16) & 0xFF); + *ptr++ = ((eccRes >> 8) & 0xFF); + *ptr++ = (eccRes & 0xFF); + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_3, cs); + *ptr++ = ((eccRes >> 24) & 0xFF); + *ptr++ = ((eccRes >> 16) & 0xFF); + *ptr++ = ((eccRes >> 8) & 0xFF); + case NAND_ECC_ALGO_BCH_8BIT: + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_3, cs); + *ptr++ = (eccRes & 0xFF); + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_2, cs); + *ptr++ = ((eccRes >> 24) & 0xFF); + *ptr++ = ((eccRes >> 16) & 0xFF); + *ptr++ = ((eccRes >> 8) & 0xFF); + *ptr++ = (eccRes & 0xFF); + // fall through + case NAND_ECC_ALGO_BCH_4BIT: + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_1, cs); + *ptr++ = ((eccRes >> 24) & 0xFF); + *ptr++ = ((eccRes >> 16) & 0xFF); + *ptr++ = ((eccRes >> 8) & 0xFF); + *ptr++ = (eccRes & 0xFF); + eccRes = GPMCECCBCHResultGet(baseAddr, GPMC_BCH_RESULT_0, cs); + *ptr++ = ((eccRes >> 24) & 0xFF); + *ptr++ = ((eccRes >> 16) & 0xFF); + *ptr++ = ((eccRes >> 8) & 0xFF); + *ptr++ = (eccRes & 0xFF); } } @@ -462,75 +473,39 @@ unsigned char *eccRead, unsigned char *data) { - NandStatus_t retVal; - unsigned int elmBaseAddr; - unsigned int intStatus; - unsigned int eccVal; - unsigned int i; - unsigned int errNum; - unsigned int numOfErrs; - unsigned int errLoc; - unsigned int lastECCBit; - unsigned int lastDataBit; - unsigned int errBitMask; - unsigned int errBytePos; - unsigned int numBytes; - unsigned char eccCalc[NAND_ECC_BCH_8BIT_BYTECNT * 4]; - unsigned char syndrome[NAND_ECC_BCH_8BIT_BYTECNT * 4]; - unsigned int j; + NandStatus_t retVal = NAND_STATUS_PASSED; + unsigned int cs = nandInfo->hNandCtrlInfo->currChipSelect; + unsigned int elmBaseAddr = nandInfo->hNandEccInfo->baseAddr; + unsigned int ctrlBaseAddr = nandInfo->hNandCtrlInfo->baseAddr; unsigned int result; - retVal = NAND_STATUS_PASSED; - elmBaseAddr = nandInfo->hNandEccInfo->baseAddr; - intStatus = 0; - j = 0; - numBytes = 0; - - if(nandInfo->eccType == NAND_ECC_ALGO_BCH_4BIT) + switch (nandInfo->eccType) { - /* Not Supported */ - } - else if(nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) - { - numBytes = ((NAND_ECC_BCH_8BIT_BYTECNT) - 1); - lastECCBit = NAND_ECC_BCH_8BIT_LASTECCBIT; - lastDataBit = NAND_ECC_BCH_8BIT_LASTDATABIT; - } - (nandInfo->hNandEccInfo->ECCCalculate)(nandInfo, &eccCalc[0]); - /* while reading ECC result we read it in big endian. - * Hence while loading to ELM we have rotate to get the right endian. - */ - - /* Rotate the syndrome bytes */ - for (i = 0, j = (numBytes-1); i < numBytes; i++, j--) - syndrome[i] = eccCalc[j]; - - /* Load the BCH syndrome */ - eccVal = (syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | - (syndrome[3] << 24)); - ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_0, eccVal); - - eccVal = (syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | - (syndrome[7] << 24)); - ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_1, eccVal); - - if(nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) - { - eccVal = (syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | - (syndrome[11] << 24)); - ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_2, eccVal); - - eccVal = (syndrome[12] | (syndrome[13] << 8) | (syndrome[14] << 16) | - (syndrome[15] << 24)); - ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_3, eccVal); + case NAND_ECC_ALGO_HAMMING_1BIT: + case NAND_ECC_ALGO_RS_4BIT: + case NAND_ECC_ALGO_NONE: + // Wrong algorithm - shouldn't get here! + return NAND_STATUS_ECC_UNSUPPORTED; + + case NAND_ECC_ALGO_BCH_16BIT: + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_6, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_6, cs)); + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_5, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_5, cs)); + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_4, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_4, cs)); + // fall through + case NAND_ECC_ALGO_BCH_8BIT: + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_3, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_3, cs)); + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_2, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_2, cs)); + // fall through + case NAND_ECC_ALGO_BCH_4BIT: + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_1, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_1, cs)); + ELMSyndromeFrgmtSet(elmBaseAddr, ELM_SYNDROME_FRGMT_0, GPMCECCBCHResultGet(ctrlBaseAddr, GPMC_BCH_RESULT_0, cs)); + break; } ELMErrLocProcessingStart(elmBaseAddr); - while(intStatus == 0) - { - intStatus = ELMIntStatusGet(elmBaseAddr, ELM_LOC_VALID_0_STATUS); - } + while(!ELMIntStatusGet(elmBaseAddr, ELM_LOC_VALID_0_STATUS)) + ; ELMIntStatusClear(elmBaseAddr, ELM_LOC_VALID_0_STATUS); @@ -542,24 +517,29 @@ } else { - numOfErrs = ELMNumOfErrsGet(elmBaseAddr); + int numOfErrs = ELMNumOfErrsGet(elmBaseAddr); if(numOfErrs == 0) { retVal = NAND_STATUS_PASSED; } else { - errNum = ELM_ERROR_NUM_0; + int lastECCBit = nandInfo->hNandEccInfo->eccByteCnt * 8; + int lastDataBit = ( NAND_BYTES_PER_TRNFS + + nandInfo->hNandEccInfo->eccByteCnt + - nandInfo->hNandEccInfo->eccUnusedByteCnt) * 8; + int errNum = ELM_ERROR_NUM_0; + int i; /* Get the error location and correct the same */ for(i=0; i < numOfErrs; i++) { - errLoc = ELMErrLocBitAddrGet(elmBaseAddr, errNum); + int errLoc = ELMErrLocBitAddrGet(elmBaseAddr, errNum); if (errLoc >= (lastECCBit - 1)) { /* Error is at the Data bytes */ - errBytePos = ((lastDataBit - 1) - errLoc) / 8; + int errBytePos = ((lastDataBit - 1) - errLoc) / 8; /* Error Bit mask */ - errBitMask = 0x1 << (errLoc % 8); + int errBitMask = 0x1 << (errLoc % 8); /* Toggle the error bit to make the correction. */ data[errBytePos] ^= errBitMask; retVal = NAND_STATUS_READ_ECC_ERROR_CORRECTED; @@ -742,21 +722,28 @@ */ NandStatus_t GPMCNANDECCInit(NandInfo_t *nandInfo) { - NandStatus_t retVal; - - retVal = NAND_STATUS_PASSED; + NandStatus_t retVal = NAND_STATUS_ECC_UNSUPPORTED; - if(nandInfo->eccType == NAND_ECC_ALGO_HAMMING_1BIT) + switch (nandInfo->eccType) { - retVal = GPMCHammingCodeECCInit(nandInfo); - } - else if(nandInfo->eccType == NAND_ECC_ALGO_BCH_4BIT || - nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) - { - retVal = GPMCBCHECCInit(nandInfo); - } + case NAND_ECC_ALGO_NONE: + retVal = NAND_STATUS_PASSED; + break; - return(retVal); + case NAND_ECC_ALGO_HAMMING_1BIT: + retVal = GPMCHammingCodeECCInit(nandInfo); + break; + + case NAND_ECC_ALGO_RS_4BIT: + retVal = NAND_STATUS_ECC_UNSUPPORTED; + + case NAND_ECC_ALGO_BCH_16BIT: + case NAND_ECC_ALGO_BCH_8BIT: + case NAND_ECC_ALGO_BCH_4BIT: + retVal = GPMCBCHECCInit(nandInfo); + break; + } + return retVal; } /** @@ -847,15 +834,23 @@ */ void GPMCNANDECCCalculate(NandInfo_t *nandInfo, unsigned char *ptrEccData) { - if(nandInfo->eccType == NAND_ECC_ALGO_HAMMING_1BIT) + switch (nandInfo->eccType) { - GPMCHammingCodeECCCalculate(nandInfo->hNandCtrlInfo->baseAddr, - GPMC_ECC_RESULT_1, ptrEccData); - } - else if(nandInfo->eccType == NAND_ECC_ALGO_BCH_4BIT || - nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) - { - GPMCBCHECCCalculate(nandInfo, ptrEccData); + case NAND_ECC_ALGO_HAMMING_1BIT: + GPMCHammingCodeECCCalculate(nandInfo->hNandCtrlInfo->baseAddr, + GPMC_ECC_RESULT_1, ptrEccData); + break; + + case NAND_ECC_ALGO_RS_4BIT: + case NAND_ECC_ALGO_NONE: + // Not supported, do nothing + break; + + case NAND_ECC_ALGO_BCH_16BIT: + case NAND_ECC_ALGO_BCH_8BIT: + case NAND_ECC_ALGO_BCH_4BIT: + GPMCBCHECCCalculate(nandInfo, ptrEccData); + break; } } @@ -881,19 +876,24 @@ unsigned char *eccRead, unsigned char *data) { - NandStatus_t retVal; - - retVal = NAND_STATUS_PASSED; - - if(nandInfo->eccType == NAND_ECC_ALGO_HAMMING_1BIT) - { - retVal = GPMCHammingCodeECCCheckAndCorrect(nandInfo, eccRead, data); - } - else if(nandInfo->eccType == NAND_ECC_ALGO_BCH_4BIT || - nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT) + NandStatus_t retVal = NAND_STATUS_PASSED; + switch (nandInfo->eccType) { - retVal = GPMCBCHECCCheckAndCorrect(nandInfo, eccRead, data); + case NAND_ECC_ALGO_HAMMING_1BIT: + retVal = GPMCHammingCodeECCCheckAndCorrect(nandInfo, eccRead, data); + break; + + case NAND_ECC_ALGO_RS_4BIT: + case NAND_ECC_ALGO_NONE: + // Not supported, do nothing + break; + + case NAND_ECC_ALGO_BCH_16BIT: + case NAND_ECC_ALGO_BCH_8BIT: + case NAND_ECC_ALGO_BCH_4BIT: + retVal = GPMCBCHECCCheckAndCorrect(nandInfo, eccRead, data); + break; } return(retVal); Only in AM335X_StarterWare/nandlib/: .nand_gpmc.c.swp diff -ur AM335X_StarterWare_02_00_00_07/nandlib/nandlib.c AM335X_StarterWare/nandlib/nandlib.c --- AM335X_StarterWare_02_00_00_07/nandlib/nandlib.c 2012-08-06 09:54:08.000000000 +0100 +++ AM335X_StarterWare/nandlib/nandlib.c 2013-01-24 10:30:37.000000000 +0000 @@ -40,7 +40,7 @@ * */ - +#include <string.h> #include "nandlib.h" #include "hw_types.h" @@ -63,6 +63,7 @@ #define NAND_CMD_READ_STATUS (0x70u) #define NAND_CMD_READ_RANDOM (0x05u) #define NAND_CMD_READ_RANDOM_CYC2 (0xE0u) +#define NAND_CMD_READ_PARAMETER_PAGE (0xECu) /*****************************************************************************/ /* @@ -419,6 +420,26 @@ return retVal; } + /* Reset the device first */ + retVal = NANDReset(nandInfo); + if(retVal & NAND_STATUS_WAITTIMEOUT) + { + return retVal; + } + + /* + * Read the device ID (will update NAND device parameters if current + * parameters are invalid) + */ + retVal = NANDReadId(nandInfo); + if (retVal != NAND_STATUS_PASSED) + return retVal; + + memset(nandInfo->deviceModel, 0, sizeof(nandInfo->deviceModel)); + retVal = NANDReadONFIInfo(nandInfo); + if (retVal != NAND_STATUS_PASSED) + return retVal; + /* Init the ECC hardware/structures */ if (NAND_ECC_ALGO_NONE != nandInfo->eccType) { @@ -436,19 +457,6 @@ (nandInfo->hNandDmaInfo->DMAInit)(unused); } - /* Reset the device first */ - retVal = NANDReset(nandInfo); - if(retVal & NAND_STATUS_WAITTIMEOUT) - { - return retVal; - } - - /* - * Read the device ID (will update NAND device parameters if current - * parameters are invalid) - */ - retVal = NANDReadId(nandInfo); - return retVal; } @@ -589,10 +597,61 @@ /* Calculate the pagesPerBlock */ nandInfo->pagesPerBlk = (nandInfo->blkSize/nandInfo->pageSize); + + /* Can't work out these values, so set them to 0 */ + nandInfo->blksPerDie = 0; + nandInfo->size = 0; return retVal; } +NandStatus_t NANDReadONFIInfo(NandInfo_t *nandInfo) +{ + /* Send the read ID command for address 0x20 */ + NANDCommandWrite(nandInfo->cmdRegAddr, NAND_CMD_READID); + NANDAddressWrite(nandInfo->addrRegAddr, 0x20); + NANDDelay(10); + NANDWaitUntilReady(nandInfo); + + /* Check we get ONFI back */ + unsigned char onfi[] = { 0, 0, 0, 0 }; + int i; + for (i=0; i<4; i++) + onfi[i] = NANDDataReadByte(nandInfo->dataRegAddr); + if ( (onfi[0] != 'O') + || (onfi[1] != 'N') + || (onfi[2] != 'F') + || (onfi[3] != 'I')) + { + return NAND_STATUS_NOT_FOUND; + } + + /* Send the read parameter page command */ + NANDCommandWrite(nandInfo->cmdRegAddr, NAND_CMD_READ_PARAMETER_PAGE); + NANDAddressWrite(nandInfo->addrRegAddr, 0x00); + NANDDelay(10); + NANDWaitUntilReady(nandInfo); + + unsigned char onfi_info[256]; + for (i=0; i<256; i++) + onfi_info[i] = NANDDataReadByte(nandInfo->dataRegAddr); + + memset(nandInfo->deviceModel, 0, sizeof(nandInfo->deviceModel)); + memcpy(nandInfo->deviceModel, onfi_info + 44, 20); + + nandInfo->pageSize = (onfi_info[83] << 24) | (onfi_info[82] << 16) + | (onfi_info[81] << 8) | (onfi_info[80]); + nandInfo->pagesPerBlk = (onfi_info[95] << 24) | (onfi_info[94] << 16) + | (onfi_info[93] << 8) | (onfi_info[92]); + nandInfo->blksPerDie = (onfi_info[99] << 24) | (onfi_info[98] << 16) + | (onfi_info[97] << 8) | (onfi_info[96]); + nandInfo->dieCnt = onfi_info[100]; + nandInfo->blkSize = nandInfo->pageSize * nandInfo->pagesPerBlk; + nandInfo->size = nandInfo->blkSize * nandInfo->blksPerDie * nandInfo->dieCnt; + + return NAND_STATUS_PASSED; +} + /** * \brief Function to Erases The block.\n * @@ -774,21 +833,6 @@ retVal = NAND_STATUS_PASSED; eccCorFlag = 0; - (nandInfo->hNandEccInfo->ECCDisable)(nandInfo); - columnAddr = nandEccInfo->eccOffSet; - if(nandInfo->busWidth == NAND_BUSWIDTH_16BIT) - { - columnAddr = columnAddr/2; - } - retVal = NANDPageReadCmdSend(nandInfo, blkNum, pageNum, columnAddr); - if(retVal == NAND_STATUS_WAITTIMEOUT) - { - return (retVal); - } - - /* Read the ECC Data from spare area */ - NANDDataRead(nandInfo, eccData, (nandEccInfo->eccByteCnt)*((nandInfo->pageSize)/NAND_BYTES_PER_TRNFS)); - /* Set the column addr to start of the page */ columnAddr = 0; @@ -827,24 +871,23 @@ if (NAND_ECC_ALGO_NONE != nandInfo->eccType) { - if( nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT ) + // For hamming code, disable ECC calculation before reading ECC data + if (NAND_ECC_ALGO_HAMMING_1BIT == nandInfo->eccType) + (nandInfo->hNandEccInfo->ECCDisable)(nandInfo); + + /* Read the ECC data. */ + columnAddr = (nandEccInfo->eccOffSet) + (trnsCnt * nandEccInfo->eccByteCnt); + if(nandInfo->busWidth == NAND_BUSWIDTH_16BIT) { - /* Read the ECC data, as BCH algo reguires this for syndrome - * calculation. - */ - columnAddr = (nandEccInfo->eccOffSet) + (trnsCnt * nandEccInfo->eccByteCnt); - if(nandInfo->busWidth == NAND_BUSWIDTH_16BIT) - { - columnAddr = columnAddr/2; - } - retVal = NANDPageReadCmdSend(nandInfo, blkNum, pageNum, columnAddr); - if(retVal == NAND_STATUS_WAITTIMEOUT) - { - return (retVal); - } - /* Read the ECC Data from spare area */ - NANDDataRead(nandInfo, eccData, (nandEccInfo->eccByteCnt - 1)); - } + columnAddr = columnAddr/2; + } + retVal = NANDPageReadCmdSend(nandInfo, blkNum, pageNum, columnAddr); + if(retVal == NAND_STATUS_WAITTIMEOUT) + { + return (retVal); + } + /* Read the ECC Data from spare area */ + NANDDataRead(nandInfo, eccData, (nandEccInfo->eccByteCnt - nandEccInfo->eccUnusedByteCnt)); /* Check for ECC errors and correct if any errors */ retVal = (nandInfo->hNandEccInfo->ECCCheckAndCorrect)(nandInfo, eccData, @@ -858,29 +901,26 @@ { break; } - if( nandInfo->eccType == NAND_ECC_ALGO_BCH_8BIT ) - { - /* Reset the colomn pointer to appropariate position. */ + /* Reset the colomn pointer to appropariate position. */ - columnAddr = ((trnsCnt + 1) * NAND_BYTES_PER_TRNFS); - if(nandInfo->busWidth == NAND_BUSWIDTH_16BIT) - { - columnAddr = columnAddr/2; - } - NANDCommandWrite(nandInfo->cmdRegAddr, - NAND_CMD_READ_RANDOM); - /* Write 2 bytes of column addr */ - NANDAddressWrite(nandInfo->addrRegAddr, - (unsigned char)(columnAddr & 0xFF)); - NANDAddressWrite(nandInfo->addrRegAddr, - (unsigned char)((columnAddr >> 8) & 0xFF)); - NANDCommandWrite(nandInfo->cmdRegAddr, - NAND_CMD_READ_RANDOM_CYC2); - retVal = NANDWaitUntilReady(nandInfo); - if(retVal == NAND_STATUS_WAITTIMEOUT) - { - return (retVal); - } + columnAddr = ((trnsCnt + 1) * NAND_BYTES_PER_TRNFS); + if(nandInfo->busWidth == NAND_BUSWIDTH_16BIT) + { + columnAddr = columnAddr/2; + } + NANDCommandWrite(nandInfo->cmdRegAddr, + NAND_CMD_READ_RANDOM); + /* Write 2 bytes of column addr */ + NANDAddressWrite(nandInfo->addrRegAddr, + (unsigned char)(columnAddr & 0xFF)); + NANDAddressWrite(nandInfo->addrRegAddr, + (unsigned char)((columnAddr >> 8) & 0xFF)); + NANDCommandWrite(nandInfo->cmdRegAddr, + NAND_CMD_READ_RANDOM_CYC2); + retVal = NANDWaitUntilReady(nandInfo); + if(retVal == NAND_STATUS_WAITTIMEOUT) + { + return (retVal); } eccData += nandEccInfo->eccByteCnt; }