SAMV71 Xplained Ultra Software Package 1.5

smc.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /**
00031  *  \file
00032  *
00033  *  Implementation of NFC functions.
00034  */
00035 
00036 /*----------------------------------------------------------------------------
00037  *        Headers
00038  *----------------------------------------------------------------------------*/
00039 
00040 #include "chip.h"
00041 
00042 static SmcStatus smcStatus;
00043 /*----------------------------------------------------------------------------
00044  *        Local functions
00045  *----------------------------------------------------------------------------*/
00046 
00047 /**
00048  * \brief Counts and return the number of bits set to '1' in the given hsiao code .
00049  * \param code  Hsizo code.
00050  */
00051 static unsigned char CountBitsInByte(unsigned char byte)
00052 {
00053     unsigned char count = 0;
00054 
00055     while (byte > 0) {
00056         if (byte & 1)
00057             count++;
00058 
00059         byte >>= 1;
00060     }
00061 
00062     return count;
00063 }
00064 
00065 /**
00066  * \brief Counts and return the number of bits set to '1' in the given hsiao code.
00067  * \param code  Hsizo code.
00068  */
00069 static unsigned char CountBitsInCode(unsigned char *code)
00070 {
00071     return CountBitsInByte(code[0])
00072            + CountBitsInByte(code[1])
00073            + CountBitsInByte(code[2]);
00074 }
00075 
00076 /**
00077  * \brief Clear the corresponding interrupt flag.
00078  */
00079 static void SMC_Clear_Status (void)
00080 {
00081     smcStatus.BStatus = 0;
00082 }
00083 
00084 /**
00085  * \brief Check the STATUS and set the corresponding interrupt flag.
00086  */
00087 static void SMC_Handler(void)
00088 {
00089     uint32_t status;
00090     status = SMC->SMC_SR;
00091 #if 0
00092 
00093     if ((status & SMC_SR_SMCSTS) == SMC_SR_SMCSTS)
00094         /* NAND Flash Controller is enabled */
00095         smcStatus.bStatus.smcSts = 1;
00096 
00097 #endif
00098 
00099     if ((status & SMC_SR_XFRDONE) == SMC_SR_XFRDONE)
00100         /* When set to one, this flag indicates that the NFC has terminated the
00101             Data Transfer. This flag is reset after a status read operation. */
00102         smcStatus.bStatus.xfrDone = 1;
00103 
00104     if ((status & SMC_SR_CMDDONE) == SMC_SR_CMDDONE)
00105         /* When set to one, this flag indicates that the NFC has terminated the
00106             Command. This flag is reset after a status read operation.*/
00107         smcStatus.bStatus.cmdDone = 1;
00108 
00109     if ((status & (1 << 24)) == (1 << 24))
00110         /* If set to one, this flag indicates that an edge has been detected on
00111             the Ready/Busy Line x. Depending on the EDGE CTRL field located in
00112             the SMC_CFG register, only rising or falling edge is detected.
00113             This flag is reset after a status read operation. */
00114         smcStatus.bStatus.rbEdge = 1;
00115 
00116     if ((status & SMC_SR_ECCRDY) == SMC_SR_ECCRDY)
00117         /* When set to one, this flag indicates that the Hamming ECC
00118         computation is completed. This flag is reset after a status read
00119            operation.*/
00120         smcStatus.bStatus.hammingReady = 1;
00121 }
00122 
00123 /*----------------------------------------------------------------------------
00124  *        Exported functions
00125  *----------------------------------------------------------------------------*/
00126 
00127 /**
00128  * \brief Sets NFC configuration.
00129  * \param cfg  NFC configuration.
00130  */
00131 void SMC_NFC_Configure(uint32_t cfg)
00132 {
00133     SMC->SMC_CFG = cfg;
00134 }
00135 
00136 /**
00137  * \brief Reset NFC controller.
00138  */
00139 void SMC_NFC_Reset(void)
00140 {
00141     /* Disable all the SMC NFC interrupts */
00142     SMC->SMC_IDR = 0xFFFFFFFF;
00143     SMC->SMC_CTRL = 0;
00144 }
00145 
00146 /**
00147  * \brief Enable NFC controller.
00148  */
00149 void SMC_NFC_EnableNfc(void)
00150 {
00151     SMC->SMC_CTRL |= SMC_CTRL_NFCEN;
00152 }
00153 
00154 /**
00155  * \brief Enable NFC controller reads both main and spare area in read mode.
00156  */
00157 void SMC_NFC_EnableSpareRead(void)
00158 {
00159     SMC->SMC_CFG |= SMC_CFG_RSPARE;
00160 }
00161 
00162 /**
00163  * \brief The NFC controller skips spare area in read mode.
00164  */
00165 void SMC_NFC_DisableSpareRead(void)
00166 {
00167     SMC->SMC_CFG &= (~SMC_CFG_RSPARE);
00168 }
00169 
00170 /**
00171  * \brief Enables the NFC controller writes both main and spare area in write
00172  */
00173 void SMC_NFC_EnableSpareWrite(void)
00174 {
00175     SMC->SMC_CFG |= SMC_CFG_WSPARE;
00176 }
00177 
00178 /**
00179  * \brief The NFC controller skips spare area in write mode.
00180  */
00181 void SMC_NFC_DisableSpareWrite(void)
00182 {
00183     SMC->SMC_CFG &= (~SMC_CFG_WSPARE);
00184 }
00185 
00186 /**
00187  * \brief Check if spare area be read in read mode.
00188  *
00189  * \return Returns 1 if NFC controller reads both main and spare area in
00190  *         read mode, otherwise returns 0.
00191  */
00192 uint8_t SMC_NFC_isSpareRead(void)
00193 {
00194     return (((SMC->SMC_CFG) >> 9) & 0x1);
00195 }
00196 
00197 /**
00198  * \brief Check if spare area be written in write mode.
00199  *
00200  * \return Returns 1 if NFC controller writes both main and spare area in
00201  *         write mode, otherwise returns 0.
00202  */
00203 uint8_t SMC_NFC_isSpareWrite(void)
00204 {
00205     return (((SMC->SMC_CFG) >> 8) & 0x1);
00206 }
00207 
00208 /**
00209  * \brief Check if NFC transfer complete.
00210  * \return Returns 1 if NFC controller has terminated the data transmission,
00211  *         otherwise returns 0.
00212  */
00213 uint8_t SMC_NFC_isTransferComplete(void)
00214 {
00215     return ((SMC->SMC_SR & SMC_SR_XFRDONE) == SMC_SR_XFRDONE);
00216 }
00217 
00218 /**
00219  * \brief Check Ready/Busy line.
00220  *
00221  * \return Returns 1 if  edge has been detected on the Ready/Busy line,
00222  *         otherwise returns 0.
00223  */
00224 uint8_t SMC_NFC_isReadyBusy(void)
00225 {
00226     return ((SMC->SMC_SR & SMC_SR_RB_EDGE0) == SMC_SR_RB_EDGE0);
00227 }
00228 
00229 /**
00230  * \brief Check if NFC Controller is busy.
00231  *
00232  * \return Returns 1 if NFC Controller is activated and accesses the memory device,
00233  *         otherwise returns 0.
00234  */
00235 uint8_t SMC_NFC_isNfcBusy(void)
00236 {
00237     return ((SMC->SMC_SR & SMC_SR_NFCBUSY) == SMC_SR_NFCBUSY);
00238 }
00239 
00240 /**
00241  * \brief Get NFC Status.
00242  *
00243  * \return Returns the current status register of SMC NFC Status Register.
00244  *         This resets the internal value of the status register, so further
00245  *         read may yield different values.
00246  */
00247 uint32_t SMC_NFC_GetStatus(void)
00248 {
00249     return SMC->SMC_SR;
00250 }
00251 
00252 /*
00253  * HOST command functions
00254  */
00255 
00256 /**
00257  * \brief Check if the host controller is busy.
00258  * \return Returns 1 if the host controller is busy, otherwise returns 0.
00259  */
00260 static uint8_t SMC_NFC_isHostBusy(void)
00261 {
00262     return (((*((volatile uint32_t *) (NFC_CMD_BASE_ADDR + NFCADDR_CMD_NFCCMD)))
00263              & 0x8000000) == 0x8000000);
00264 }
00265 
00266 /**
00267  * \brief Wait for NFC command has done.
00268  */
00269 void SMC_NFC_Wait_CommandDone(void)
00270 {
00271     while (smcStatus.bStatus.cmdDone == 0)
00272         SMC_Handler();
00273 }
00274 
00275 /**
00276  * \brief Wait for NFC Data Transfer Terminated.
00277  */
00278 void SMC_NFC_Wait_XfrDone(void)
00279 {
00280     while (smcStatus.bStatus.xfrDone == 0)
00281         SMC_Handler();
00282 }
00283 
00284 /**
00285  * \brief Wait for NFC Data Transfer Terminated.
00286  */
00287 void SMC_NFC_Wait_HammingReady(void)
00288 {
00289     while (smcStatus.bStatus.hammingReady == 0)
00290         SMC_Handler();
00291 }
00292 
00293 /**
00294  * \brief Wait for NFC Ready/Busy Line 3 Edge Detected.
00295  */
00296 void SMC_NFC_Wait_RBbusy(void)
00297 {
00298     while (smcStatus.bStatus.rbEdge == 0)
00299         SMC_Handler();
00300 }
00301 
00302 /**
00303  * \brief Uses the HOST nandflash controller to send a command to the NFC.
00304  * \param cmd  command to send.
00305  * \param addressCycle  address cycle when command access id decoded.
00306  * \param cycle0  address at first cycle.
00307  */
00308 void SMC_NFC_SendCommand(uint32_t cmd, uint32_t addressCycle, uint32_t cycle0)
00309 {
00310     volatile uint32_t *pCommandAddress;
00311     SMC_Clear_Status();
00312 
00313     /* Wait until host controller is not busy. */
00314     while (SMC_NFC_isHostBusy());
00315 
00316     /* Send the command plus the ADDR_CYCLE */
00317     pCommandAddress = (volatile uint32_t *) (cmd + NFC_CMD_BASE_ADDR);
00318     SMC->SMC_ADDR = cycle0;
00319     *pCommandAddress = addressCycle;
00320     SMC_NFC_Wait_CommandDone();
00321 }
00322 
00323 /* ECC function */
00324 
00325 /**
00326  * \brief Get 24-bit ECC code for 8-bit data path NAND flash.
00327  * 24-bit ECC is generated in order to perform one bit correction
00328  * for 512 byte in page 512/1024/2048/4096 for 8-bit words
00329  *
00330  * \param size  Data size in bytes.
00331  * \param code  Codes buffer.
00332  */
00333 static void _smc_ecc_GetW9BitPer512Ecc(uint32_t pageDataSize, uint8_t *code)
00334 {
00335     uint8_t i;
00336     uint8_t numEcc;
00337     uint32_t eccParity;
00338     uint32_t ecc[16];
00339 
00340     SMC_ECC_GetValue(ecc);
00341     numEcc = pageDataSize / 512;
00342 
00343     /*  P2048' P1024' P512' P256' P128'   P64'  P32' P16'  ---  3rd. Ecc Byte to store */
00344     /*  P8'    P4'    P2'   P1'   P2048   P1024 P512 P256  ---  2nd. Ecc Byte to store */
00345     /*  P128   P64    P32   P16   P8      P4    P2   P1    ---  1st. Ecc Byte to store */
00346     for (i = 0; i < numEcc; i++) {
00347         /* Get Parity and NParity value. */
00348         eccParity = ecc[i];
00349         eccParity = ~eccParity;
00350         code[i * 3] = eccParity & 0xff;
00351         code[i * 3 + 1] = (eccParity >> 8) & 0xff;
00352         code[i * 3 + 2] = (eccParity >> 16) & 0xff;
00353     }
00354 }
00355 
00356 /**
00357  * \brief Get 24-bit ECC code for 8-bit data path NAND flash.
00358  * 24-bit ECC is generated in order to perform one bit correction
00359  * for 256 byte in page 512/1024/2048/4096 for 8-bit words
00360  *
00361  * \param size  Data size in bytes.
00362  * \param code  Codes buffer.
00363  */
00364 static void _smc_ecc_GetW8BitPer256Ecc(uint32_t pageDataSize, uint8_t *code)
00365 {
00366     uint8_t i;
00367     uint8_t numEcc;
00368     uint32_t eccParity;
00369     uint32_t ecc[16];
00370 
00371     SMC_ECC_GetValue(ecc);
00372     numEcc = pageDataSize / 256;
00373 
00374     /*  P2048' P1024' P512' P256' P128'   P64'  P32' P16'  ---  3rd. Ecc Byte to store */
00375     /*  P8'    P4'    P2'   P1'   P2048   P1024 P512 P256  ---  2nd. Ecc Byte to store */
00376     /*  P128   P64    P32   P16   P8      P4    P2   P1    ---  1st. Ecc Byte to store */
00377     for (i = 0; i < numEcc; i++) {
00378         /* Get Parity and NParity value. */
00379         eccParity = ecc[i];
00380         eccParity = ~eccParity;
00381         TRACE_DEBUG("ecc Parity%d is 0x%08x \n\r", (int)i, (uint32_t)eccParity);
00382         code[i * 3] = eccParity & 0xff;
00383         code[i * 3 + 1] = (eccParity >> 8) & 0xff;
00384         code[i * 3 + 2] = (eccParity >> 16) & 0xff;
00385     }
00386 }
00387 
00388 /**
00389  * \breif Get 32-bit ECC code for 16-bit data path NAND flash.
00390  * 32-bit ECC is generated in order to perform one bit correction
00391  * for a page in page 512/1024/2048/4096 for 16-bit words
00392  *
00393  * \param size  Data size in bytes.
00394  * \param code  Codes buffer.
00395  */
00396 static void _smc_ecc_GetW12BitPerPageEcc(uint32_t pageDataSize, uint8_t *code)
00397 {
00398     uint32_t eccParity;
00399     uint32_t eccNparity;
00400     uint32_t ecc[16];
00401 
00402     pageDataSize = pageDataSize; /* stop warning */
00403     /* Get Parity value. */
00404     SMC_ECC_GetValue(ecc);
00405 
00406     /*  ----   P16384'P8192'P4096'P2048'  P1024'P512'P256' ---  4th. Ecc Byte to store */
00407     /*  P128'  P64'   P32'  P16'  P8'     P4'   P2'  P1'   ---  3rd. Ecc Byte to store */
00408     /*  ----   P16384 P8192 P4096 P2048   P1024 P512 P256  ---  2nd. Ecc Byte to store */
00409     /*  P128   P64    P32   P16   P8      P4    P2   P1    ---  1st. Ecc Byte to store */
00410 
00411     /* Invert codes (linux compatibility) */
00412     eccParity = ecc[0];
00413     eccNparity = ecc[1];
00414     code[0] = eccParity & 0xff;
00415     code[1] = (eccParity >> 8) & 0xff;
00416     code[2] = eccNparity & 0xff;
00417     code[3] = (eccNparity >> 8) & 0xff;
00418 }
00419 
00420 
00421 /**
00422  * \brief Configures ECC mode.
00423  * \param type  Type of correction.
00424  * \param pageSize  Page size of NAND flash device.
00425  */
00426 void SMC_ECC_Configure(uint32_t type, uint32_t pageSize)
00427 {
00428     /* Software Reset ECC. */
00429     SMC->SMC_ECC_CTRL = (0x1 <<  1);
00430     SMC->SMC_ECC_MD = type | pageSize;
00431 }
00432 
00433 /**
00434  * \brief Get ECC correction type.
00435  *
00436  * \return Returns type of ECC correction setting.
00437  */
00438 uint32_t SMC_ECC_GetCorrectoinType(void)
00439 {
00440     return ((SMC->SMC_ECC_MD)& SMC_ECC_MD_TYPCORREC_Msk);
00441 }
00442 
00443 /**
00444  * \brief Get ECC status.
00445  * \param eccNumber  ecc parity number from 0 to 15.
00446  *
00447  * \return Returns ECC status by giving ecc number.
00448  */
00449 uint8_t SMC_ECC_GetStatus(uint8_t eccNumber)
00450 {
00451     uint32_t status;
00452 
00453     if (eccNumber < 8)
00454         status = SMC->SMC_ECC_SR1;
00455     else {
00456         status = SMC->SMC_ECC_SR2;
00457         eccNumber -= 8;
00458     }
00459 
00460     return ((status >> (eccNumber * 4)) & 0x07);
00461 }
00462 
00463 /**
00464  * \brief Get all ECC parity and Nparity value.
00465  */
00466 void SMC_ECC_GetValue(uint32_t *ecc)
00467 {
00468     ecc[0] = SMC->SMC_ECC_PR0;
00469     ecc[1] = SMC->SMC_ECC_PR1;
00470     ecc[2] = SMC->SMC_ECC_PR2;
00471     ecc[3] = SMC->SMC_ECC_PR3;
00472     ecc[4] = SMC->SMC_ECC_PR4;
00473     ecc[5] = SMC->SMC_ECC_PR5;
00474     ecc[6] = SMC->SMC_ECC_PR6;
00475     ecc[7] = SMC->SMC_ECC_PR7;
00476     ecc[8] = SMC->SMC_ECC_PR8;
00477     ecc[9] = SMC->SMC_ECC_PR9;
00478     ecc[10] = SMC->SMC_ECC_PR10;
00479     ecc[11] = SMC->SMC_ECC_PR11;
00480     ecc[12] = SMC->SMC_ECC_PR12;
00481     ecc[13] = SMC->SMC_ECC_PR13;
00482     ecc[14] = SMC->SMC_ECC_PR14;
00483     ecc[15] = SMC->SMC_ECC_PR15;
00484 }
00485 
00486 /**
00487  * \brief verifies 4-bytes hsiao codes for a data block whose size is a page Size
00488  * word. Page words block is verified between the given HSIAO code
00489  * generated by hardware and original HSIAO codes store has been previously stored.
00490  * Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
00491  * block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
00492  * or Hsiao_ERROR_MULTIPLEBITS.
00493  * \param data  Data buffer to verify.
00494  * \param originalCode  Original codes.
00495  * \param verifyCode  codes to be verified.
00496  */
00497 static uint8_t _smc_ecc_VerifyW12BitPerPageEcc(
00498     uint8_t *data,
00499     const uint8_t *originalCode,
00500     const uint8_t *verifyCode)
00501 {
00502     uint8_t correctionCode[4];
00503     uint8_t bitCount;
00504     // Xor both codes together
00505     correctionCode[0] = verifyCode[0] ^ originalCode[0];
00506     correctionCode[1] = verifyCode[1] ^ originalCode[1];
00507     correctionCode[2] = verifyCode[2] ^ originalCode[2];
00508     correctionCode[3] = verifyCode[3] ^ originalCode[3];
00509     TRACE_DEBUG("Correction code = %02X %02X %02X %02X\n\r",
00510                 correctionCode[0], correctionCode[1], correctionCode[2], correctionCode[3]);
00511 
00512     /* If all bytes are 0, there is no error */
00513     if ((correctionCode[0] == 0)
00514         && (correctionCode[1] == 0)
00515         && (correctionCode[2] == 0)
00516         && (correctionCode[3] == 0))
00517 
00518         return 0;
00519 
00520     /* If there is a single bit error, there are 15 bits set to 1 */
00521     bitCount = CountBitsInByte(correctionCode[0]) +
00522                CountBitsInByte(correctionCode[1]) +
00523                CountBitsInByte(correctionCode[2]) +
00524                CountBitsInByte(correctionCode[3]);
00525 
00526     if (bitCount == 15) {
00527         /* Get byte and bit indexes */
00528         uint16_t byte = (correctionCode[0] & 0xf0) >> 4;
00529         byte |= (correctionCode[1] & 0xff) << 4;
00530         uint8_t bit = correctionCode[0] & 0x0f;
00531         /* Correct bit */
00532         printf("Correcting byte #%d at bit %d\n\r", byte, bit);
00533         data[byte] ^= (1 << bit);
00534 
00535         return Hsiao_ERROR_SINGLEBIT;
00536     }
00537 
00538     /* Check if ECC has been corrupted */
00539     if (bitCount == 1)
00540         return Hsiao_ERROR_ECC;
00541     /* Otherwise, this is a multi-bit error */
00542     else
00543         return Hsiao_ERROR_MULTIPLEBITS;
00544 }
00545 
00546 /**
00547  * \brief verifies 3-bytes hsiao codes for a data block whose size is a page Size
00548  * word. Page words block is verified between the given HSIAO code
00549  * generated by hardware and original HSIAO codes store has been previously stored.
00550  * Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
00551  * block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
00552  * or Hsiao_ERROR_MULTIPLEBITS.
00553  * \param data  Data buffer to verify.
00554  * \param originalCode  Original codes.
00555  * \param verifyCode  codes to be verified.
00556  */
00557 static uint8_t _smc_ecc_VerifyW8BitPer256Ecc(
00558     uint8_t *data,
00559     uint32_t size,
00560     const uint8_t *originalCode,
00561     const uint8_t *verifyCode)
00562 {
00563     uint8_t correctionCode[3];
00564     uint32_t position = 0;
00565     uint8_t byte;
00566     uint8_t bit;
00567     uint8_t error = 0;
00568 
00569     TRACE_DEBUG("_smc_ecc_VerifyW8BitPer256Ecc()\n\r");
00570 
00571     while (position < size) {
00572         /* Xor both codes together */
00573         correctionCode[0] = verifyCode[0] ^ originalCode[0];
00574         correctionCode[1] = verifyCode[1] ^ originalCode[1];
00575         correctionCode[2] = verifyCode[2] ^ originalCode[2];
00576         TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
00577                     correctionCode[0], correctionCode[1], correctionCode[2]);
00578 
00579         /* If all bytes are 0, there is no error */
00580         if (correctionCode[0] || correctionCode[1] || correctionCode[2]) {
00581             /* If there is a single bit error, there are 11 bits set to 1 */
00582             if (CountBitsInCode(correctionCode) == 11) {
00583                 /* Get byte and bit indexes */
00584                 byte = (correctionCode[0] & 0xf8) >> 3;
00585                 byte |= (correctionCode[1] & 0x07) << 5;
00586                 bit = correctionCode[0] & 0x07;
00587                 /* Correct bit */
00588                 printf("Correcting byte #%u at bit %u\n\r", (unsigned int)(position + byte),
00589                        (unsigned int)bit);
00590                 data[byte] ^= (1 << bit);
00591                 error = Hsiao_ERROR_SINGLEBIT;
00592             }
00593             /* Check if ECC has been corrupted */
00594             else if (CountBitsInCode(correctionCode) == 1)
00595                 return Hsiao_ERROR_ECC;
00596             else {
00597                 /* Otherwise, this is a multi-bit error */
00598                 return Hsiao_ERROR_MULTIPLEBITS;
00599             }
00600         }
00601 
00602         data += 256;
00603         originalCode += 3;
00604         verifyCode += 3;
00605         position += 256;
00606     }
00607 
00608     return error;
00609 }
00610 
00611 /**
00612  * \brief 3-bytes hsiao codes for a data block whose size is multiple of
00613  * 512 bytes. Each 512-bytes block is verified between the given HSIAO code
00614  * generated by hardware and original HSIAO codes store has been previously stored.
00615  * Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
00616  * block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
00617  * or Hsiao_ERROR_MULTIPLEBITS.
00618  * \param data  Data buffer to verify.
00619  * \param originalCode  Original codes.
00620  * \param verifyCode  codes to be verified.
00621  */
00622 static uint8_t _smc_ecc_VerifyW9BitPer512Ecc(
00623     uint8_t *data,
00624     uint32_t size,
00625     const uint8_t *originalCode,
00626     const uint8_t *verifyCode)
00627 {
00628     uint8_t correctionCode[3];
00629     uint32_t position = 0;
00630     uint16_t byte;
00631     uint8_t bit;
00632     uint8_t error = 0;
00633 
00634     TRACE_DEBUG("_smc_ecc_VerifyW9BitPer512Ecc()\n\r");
00635 
00636     while (position < size) {
00637         /* Xor both codes together */
00638         correctionCode[0] = verifyCode[0] ^ originalCode[0];
00639         correctionCode[1] = verifyCode[1] ^ originalCode[1];
00640         correctionCode[2] = verifyCode[2] ^ originalCode[2];
00641         TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
00642                     correctionCode[0], correctionCode[1], correctionCode[2]);
00643 
00644         /* If all bytes are 0, there is no error */
00645         if (correctionCode[0] || correctionCode[1] || correctionCode[2]) {
00646             // If there is a single bit error, there are 11 bits set to 1
00647             if (CountBitsInCode(correctionCode) == 12) {
00648                 /* Get byte and bit indexes */
00649                 byte = (correctionCode[0] & 0xf8) >> 3;
00650                 byte |= (correctionCode[1] & 0x0f) << 5;
00651                 bit = correctionCode[0] & 0x07;
00652                 /* Correct bit */
00653                 printf("Correcting byte #%u at bit %u\n\r",
00654                        (unsigned int)(position + byte),  (unsigned int)bit);
00655                 data[byte] ^= (1 << bit);
00656                 error = Hsiao_ERROR_SINGLEBIT;
00657             }
00658             /* Check if ECC has been corrupted */
00659             else if (CountBitsInCode(correctionCode) == 1)
00660                 return Hsiao_ERROR_ECC;
00661             else {
00662                 /* Otherwise, this is a multi-bit error */
00663                 return Hsiao_ERROR_MULTIPLEBITS;
00664             }
00665         }
00666 
00667         data += 512;
00668         originalCode += 3;
00669         verifyCode += 3;
00670         position += 512;
00671     }
00672 
00673     return error;
00674 }
00675 
00676 /**
00677  * Get ECC code for 8bit/16-bit data path NAND flash by giving data path.
00678  * 24-bit or 32-bit ECC is generated in order to perform one bit correction
00679  * for a page in page 512/1024/2048/4096.
00680  *
00681  * \param size  Data size in bytes.
00682  * \param code  Codes buffer.
00683  * \param busWidth 8bit/16bit data path.
00684  */
00685 void SMC_ECC_GetEccParity(uint32_t pageDataSize, uint8_t *code,
00686                           uint8_t busWidth)
00687 {
00688     uint8_t correctionType;
00689 
00690     correctionType = SMC_ECC_GetCorrectoinType();
00691 
00692     /* For 16-bit data path */
00693     if (busWidth == 16 && correctionType == SMC_ECC_MD_TYPCORREC_CPAGE)
00694         _smc_ecc_GetW12BitPerPageEcc(pageDataSize, code);
00695     /* For 8-bit data path */
00696     else {
00697         switch (correctionType) {
00698         case SMC_ECC_MD_TYPCORREC_CPAGE:
00699             _smc_ecc_GetW12BitPerPageEcc(pageDataSize, code);
00700             break;
00701 
00702         case SMC_ECC_MD_TYPCORREC_C256B:
00703             _smc_ecc_GetW8BitPer256Ecc(pageDataSize, code);
00704             break;
00705 
00706         case SMC_ECC_MD_TYPCORREC_C512B:
00707             _smc_ecc_GetW9BitPer512Ecc(pageDataSize, code);
00708             break;
00709         }
00710     }
00711 }
00712 
00713 
00714 /**
00715  *  Verifies hsiao codes for a data block. The block is verified between the given
00716  *  HSIAO code generated by hardware and original HSIAO codes store has been
00717  *  previously stored.
00718  *  Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
00719  *  block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
00720  *  or Hsiao_ERROR_MULTIPLEBITS.
00721  *  \param data  Data buffer to verify.
00722  *  \param size  Size of the data in words.
00723  *  \param originalCode  Original codes.
00724  *  \param verifyCode  codes to be verified.
00725  *  \param dataPath 8bit/16bit data path.
00726  */
00727 uint8_t SMC_ECC_VerifyHsiao(
00728     uint8_t *data,
00729     uint32_t size,
00730     const uint8_t *originalCode,
00731     const uint8_t *verifyCode,
00732     uint8_t busWidth)
00733 {
00734     uint8_t correctionType;
00735     uint8_t error = 0;
00736     correctionType = SMC_ECC_GetCorrectoinType();
00737 
00738     /* For 16-bit data path */
00739     if (busWidth == 16 && (correctionType == SMC_ECC_MD_TYPCORREC_CPAGE))
00740         error = _smc_ecc_VerifyW12BitPerPageEcc((uint8_t *)data, originalCode,
00741                                                 verifyCode);
00742     /* For 8-bit data path */
00743     else {
00744         switch (correctionType) {
00745         case SMC_ECC_MD_TYPCORREC_CPAGE:
00746             error = _smc_ecc_VerifyW12BitPerPageEcc(data, originalCode, verifyCode);
00747             break;
00748 
00749         case SMC_ECC_MD_TYPCORREC_C256B:
00750             error = _smc_ecc_VerifyW8BitPer256Ecc(data, size, originalCode, verifyCode);
00751             break;
00752 
00753         case SMC_ECC_MD_TYPCORREC_C512B:
00754             error = _smc_ecc_VerifyW9BitPer512Ecc(data, size, originalCode, verifyCode);
00755             break;
00756         }
00757     }
00758 
00759     return error;
00760 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines