This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Patch for 16-bit BCH ECC in StarterWare

Other Parts Discussed in Thread: AM3354

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