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;
}