/** * \brief Reads the data and/or the spare area of a page on a translated nandflash. * If the block is not currently mapped but could be (i.e. there are available * physical blocks), then the data/spare is filled with 0xFF. * * \param translated Pointer to a TranslatedNandFlash instance. * \param block Logical block number. * \param page Number of page to read inside logical block. * \param data Data area buffer, can be 0. * \param spare Spare area buffer, can be 0. * \return 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS */ unsigned char TranslatedNandFlash_ReadPage( const struct TranslatedNandFlash *translated, unsigned short block, unsigned short page, void *data, void *spare ) { unsigned char error ; TRACE_INFO("TranslatedNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); /* If the page to read is in the current block, there is a previous physical block and the page is clean -> read the page in the old block since the new one does not contain meaningful data*/ if ( (block == translated->currentLogicalBlock) && (translated->previousPhysicalBlock != -1) && (PageIsClean(translated, page)) ) { TRACE_DEBUG("Reading page from current block\n\r"); return ManagedNandFlash_ReadPage( MANAGED( translated ), translated->previousPhysicalBlock, page, data, spare ) ; } else { /* Try to read the page from the logical block*/ error = MappedNandFlash_ReadPage(MAPPED(translated), block, page, data, spare); /* Block was not mapped*/ if ( error == NandCommon_ERROR_BLOCKNOTMAPPED ) { assert( !spare ) ; /* "Cannot read the spare information of an unmapped block\n\r" */ /* Check if a block can be allocated*/ if ( BlockCanBeAllocated( translated ) ) { /* Return 0xFF in buffers with no error*/ TRACE_DEBUG("Block #%d is not mapped but can be allocated, filling buffer with 0xFF\n\r", block); if (data) { memset(data, 0xFF, NandFlashModel_GetPageDataSize(MODEL(translated))); } if (spare) { memset(spare, 0xFF, NandFlashModel_GetPageSpareSize(MODEL(translated))); } } else { TRACE_ERROR("Block #%d is not mapped and there are no more blocks available\n\r", block); return NandCommon_ERROR_NOMOREBLOCKS; } } /* Error*/ else { if (error) { return error; } } } return 0; }
//------------------------------------------------------------------------------ /// Returns BADBLOCK if the given block of a nandflash device is bad; returns /// GOODBLOCK if the block is good; or returns a NandCommon_ERROR code. /// \param managed Pointer to a ManagedNandFlash instance. /// \param block Raw block to check. /// \param spare Pointer to allocated spare area (must be assigned) //------------------------------------------------------------------------------ static unsigned char CheckBlock( const struct ManagedNandFlash *managed, unsigned short block, unsigned char *spare) { unsigned char error; unsigned int i; unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed)); ASSERT(spare, "ManagedNandFlash_CheckBlock: spare\n\r"); // Read spare area of first page of block error = RawNandFlash_ReadPage(RAW(managed), block, 0, 0, spare); if (error) { TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block); return error; } // Make sure it is all 0xFF for (i=0; i < pageSpareSize; i++) { if (spare[i] != 0xFF) { return BADBLOCK; } } // Read spare area of second page of block error = RawNandFlash_ReadPage(RAW(managed), block, 1, 0, spare); if (error) { TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block); return error; } // Make sure it is all 0xFF for (i=0; i < pageSpareSize; i++) { if (spare[i] != 0xFF) { return BADBLOCK; } } return GOODBLOCK; }
//------------------------------------------------------------------------------ /// Reads the data and/or spare of a page of a nandflash chip, and verify that /// the data is valid using the ECC information contained in the spare. If one /// buffer pointer is 0, the corresponding area is not saved. /// Returns 0 if the data has been read and is valid; otherwise returns either /// NandCommon_ERROR_CORRUPTEDDATA or ... /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of block to read from. /// \param page Number of page to read inside given block. /// \param data Data area buffer. /// \param spare Spare area buffer. //------------------------------------------------------------------------------ unsigned char EccNandFlash_ReadPage( const struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char tmpData[NandCommon_MAXPAGEDATASIZE]; unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE]; unsigned char error; unsigned char hamming[NandCommon_MAXSPAREECCBYTES]; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); // Start by reading the spare and the data error = RawNandFlash_ReadPage(RAW(ecc), block, page, tmpData, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r"); return error; } // Retrieve ECC information from page and verify the data NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming); error = Hamming_Verify256x(tmpData, pageDataSize, hamming); if (error && (error != Hamming_ERROR_SINGLEBIT)) { TRACE_ERROR("EccNandFlash_ReadPage: Unrecoverable data\n\r"); return NandCommon_ERROR_CORRUPTEDDATA; } // Copy data and/or spare into final buffers if (data) { memcpy(data, tmpData, pageDataSize); } if (spare) { memcpy(spare, tmpSpare, pageSpareSize); } return 0; }
//------------------------------------------------------------------------------ /// Writes the data and/or spare area of a nandflash page, after calculating an /// ECC for the data area and storing it in the spare. If no data buffer is /// provided, the ECC is read from the existing page spare. If no spare buffer /// is provided, the spare area is still written with the ECC information /// calculated on the data buffer. /// Returns 0 if successful; otherwise returns an error code. /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of the block to write in. /// \param page Number of the page to write inside the given block. /// \param data Data area buffer, can be 0. /// \param spare Spare area buffer, can be 0. //------------------------------------------------------------------------------ unsigned char EccNandFlash_WritePage( const struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char error; unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE]; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); unsigned char hamming[NandCommon_MAXSPAREECCBYTES]; ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r"); TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page); // Compute ECC on the new data, if provided // If not provided, hamming code set to 0xFFFF.. to keep existing bytes memset(hamming, 0xFF, NandCommon_MAXSPAREECCBYTES); if (data) { // Compute hamming code on data Hamming_Compute256x(data, pageDataSize, hamming); } // Store code in spare buffer (if no buffer provided, use a temp. one) if (!spare) { spare = tmpSpare; memset(spare, 0xFF, pageSpareSize); } NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hamming); // Perform write operation error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) { TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r"); return error; } return 0; }
//------------------------------------------------------------------------------ /// Writes the data and/or spare area of a nandflash page, after calculating an /// ECC for the data area and storing it in the spare. If no data buffer is /// provided, the ECC is read from the existing page spare. If no spare buffer /// is provided, the spare area is still written with the ECC information /// calculated on the data buffer. /// Returns 0 if successful; otherwise returns an error code. /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of the block to write in. /// \param page Number of the page to write inside the given block. /// \param data Data area buffer, can be 0. /// \param spare Spare area buffer, can be 0. //------------------------------------------------------------------------------ unsigned char EccNandFlash_WritePage( struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char error; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); unsigned char *pSpareBuffer = RawNandFlash_GetSpareBuffer(RAW(ecc)); ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r"); TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page); #ifndef HARDWARE_ECC // Compute ECC on the new data, if provided // If not provided, hamming code set to 0xFFFF.. to keep existing bytes memset(ecc->hamming, 0xFF, NandCommon_MAXSPAREECCBYTES); if (data) { // Compute hamming code on data Hamming_Compute256x(data, pageDataSize, ecc->hamming); } // Store code in spare buffer (if no buffer provided, use a temp. one) if (!spare) { spare = pSpareBuffer; memset(spare, 0xFF, pageSpareSize); } NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, ecc->hamming); // Perform write operation error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) goto error; #else // Store code in spare buffer (if no buffer provided, use a temp. one) if (!spare) { spare = pSpareBuffer; memset(spare, 0xFF, pageSpareSize); } // Perform write operation error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) goto error; HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); // Perform write operation NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao); error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare); if (error) goto error; #endif RawNandFlash_ReleaseSpareBuffer(RAW(ecc)); return 0; error: RawNandFlash_ReleaseSpareBuffer(RAW(ecc)); TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r"); return error; }
//------------------------------------------------------------------------------ /// Reads the data and/or spare of a page of a nandflash chip, and verify that /// the data is valid using the ECC information contained in the spare. If one /// buffer pointer is 0, the corresponding area is not saved. /// Returns 0 if the data has been read and is valid; otherwise returns either /// NandCommon_ERROR_CORRUPTEDDATA or ... /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of block to read from. /// \param page Number of page to read inside given block. /// \param data Data area buffer. /// \param spare Spare area buffer. //------------------------------------------------------------------------------ unsigned char EccNandFlash_ReadPage( struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char error; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); unsigned char *pDataBuffer; unsigned char *pSpareBuffer; TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); pDataBuffer = (data) ? data : RawNandFlash_GetDataBuffer(RAW(ecc)); pSpareBuffer = (spare) ? spare : RawNandFlash_GetSpareBuffer(RAW(ecc)); #ifndef HARDWARE_ECC // Start by reading the spare and the data error = RawNandFlash_ReadPage(RAW(ecc), block, page, pDataBuffer, pSpareBuffer); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); goto error; } // Retrieve ECC information from page and verify the data NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), pSpareBuffer, ecc->hamming); error = Hamming_Verify256x(pDataBuffer, pageDataSize, ecc->hamming); #else error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); goto error; } // Retrieve ECC information from page NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, ecc->hsiaoInSpare); HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); // Verify the data error = HSMC4_VerifyHsiao((unsigned char*) data, pageDataSize, ecc->hsiaoInSpare, ecc->hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); #endif if (error && (error != Hamming_ERROR_SINGLEBIT)) { error = NandCommon_ERROR_CORRUPTEDDATA; TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); goto error; } #ifndef HARDWARE_ECC #else if (spare) { memcpy(spare, pSpareBuffer, pageSpareSize); } #endif error: if (data == (unsigned char *) 0) RawNandFlash_ReleaseDataBuffer(RAW(ecc)); if (spare == (unsigned char *) 0) RawNandFlash_ReleaseSpareBuffer(RAW(ecc)); return error; }
/** * \brief Applet main entry. This function decodes received command and executes it. * * \param argc always 1 * \param argv Address of the argument area.. */ int main(int argc, char **argv) { struct _Mailbox *pMailbox = (struct _Mailbox *) argv; unsigned int bufferSize, bufferAddr, memoryOffset, bytesToWrite; unsigned int bytesRead = 0; unsigned int nbBadBlocks = 0; unsigned int nbBlocks = 0; /* Temporary buffer used for non block aligned read / write */ unsigned int tempBufferAddr; unsigned short block, page, offset, i; /* Index in source buffer during buffer copy */ unsigned int offsetInSourceBuff; /* Index in destination buffer during buffer copy */ unsigned int offsetInTargetBuff; /* Errors returned by SkipNandFlash functions */ unsigned char error = 0; /* Communication type with SAM-BA GUI. */ unsigned char comType; /* current pmecc parameter header value */ unsigned int currentPmeccHeaderValue; /* Index and value of pmecc command */ unsigned int nIndex, nValue; /* Number of ECC bits required */ unsigned char eccBitReq2TT [5] = {2, 4, 8, 12, 24}; /* Ecc mode to be swtich */ unsigned int eccMode; unsigned int trimPage; /* Save communication link type */ comType = pMailbox->argument.inputInit.comType; /* ---------------------------------------------------------- */ /* INIT: */ /* ---------------------------------------------------------- */ if (pMailbox->command == APPLET_CMD_INIT) { #if (DYN_TRACES == 1) dwTraceLevel = pMailbox->argument.inputInit.traceLevel; #endif TRACE_INFO("-- NandFlash SAM-BA applet %s --\n\r", SAM_BA_APPLETS_VERSION); TRACE_INFO("-- %s\n\r", BOARD_NAME); TRACE_INFO("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); TRACE_INFO("INIT command\n\r"); /* Configure SMC for Nandflash accesses (done each time applet is launched because of old ROM codes) */ BOARD_ConfigureNandFlash(nfBusWidth); PIO_Configure(pPinsNf, PIO_LISTSIZE(pPinsNf)); /* Tries to detect NAND Flash device connected to EBI CS3, with data lines connected to D0-D7, then on NAND Flash connected to D16-D23. */ if (!NandEbiDetect()) { pMailbox->status = APPLET_DEV_UNKNOWN; TRACE_INFO("\tDevice Unknown\n\r"); goto exit; } memset(&skipBlockNf, 0, sizeof(skipBlockNf)); NandGetOnfiPageParam (&OnfiPageParameter); if (SkipBlockNandFlash_Initialize(&skipBlockNf, 0, cmdBytesAddr, addrBytesAddr, dataBytesAddr, nfCePin, nfRbPin)) { pMailbox->status = APPLET_DEV_UNKNOWN; pMailbox->argument.outputInit.bufferSize = 0; pMailbox->argument.outputInit.memorySize = 0; TRACE_INFO("\tDevice Unknown\n\r"); } else { /* Check the data bus width of the NandFlash */ nfBusWidth = NandFlashModel_GetDataBusWidth((struct NandFlashModel *)&skipBlockNf); /* Reconfigure bus width */ if ( nfBusWidth != 8) { SMC->SMC_CS_NUMBER[3].SMC_MODE = SMC_MODE_READ_MODE | SMC_MODE_WRITE_MODE | SMC_MODE_DBW(nfBusWidth/16) | SMC_MODE_TDF_CYCLES(1); } TRACE_INFO("\tNandflash driver initialized\n\r"); pMailbox->argument.outputInit.bufferAddress = (unsigned int) &_end; /* Get device parameters */ memSize = NandFlashModel_GetDeviceSizeInBytes(&skipBlockNf.ecc.raw.model); blockSize = NandFlashModel_GetBlockSizeInBytes(&skipBlockNf.ecc.raw.model); numBlocks = NandFlashModel_GetDeviceSizeInBlocks(&skipBlockNf.ecc.raw.model); pageSize = NandFlashModel_GetPageDataSize(&skipBlockNf.ecc.raw.model); spareSize = NandFlashModel_GetPageSpareSize(&skipBlockNf.ecc.raw.model); numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(&skipBlockNf.ecc.raw.model); pMailbox->status = APPLET_SUCCESS; pMailbox->argument.outputInit.bufferSize = blockSize; pMailbox->argument.outputInit.memorySize = memSize; pMailbox->argument.outputInit.pmeccParamHeader = 0; TRACE_INFO("\tpageSize : 0x%x blockSize : 0x%x blockNb : 0x%x \n\r", pageSize, blockSize, numBlocks); } /* By default, we use pmecc, except MICRON MLC nand with internal ECC controller */ eccOffset = 2; /* By defaut, 2 error bit correction, eccOffset = 2 */ PMECC_Initialize(&pmeccDesc, 0, eccCorrectability, pageSize, spareSize, eccOffset, 0); TRACE_INFO("\tNandflash PMECC initialized\n\r"); DMAD_Initialize( &dmad, POLLING_MODE ); if ( NandFlashConfigureDmaChannels( &dmad )) { pMailbox->status =APPLET_DEV_UNKNOWN; goto exit; } /* Initialize current pmecc parameter header, This 32-bit word is configured below */ currentPmeccHeader.usePmecc = 1; currentPmeccHeader.nbSectorPerPage = pmeccDesc.pageSize >> 8; currentPmeccHeader.spareSize = spareSize; currentPmeccHeader.eccBitReq = pmeccDesc.errBitNbrCapability; currentPmeccHeader.sectorSize = pmeccDesc.sectorSize; currentPmeccHeader.eccOffset = pmeccDesc.eccStartAddr; currentPmeccHeader.reserved = 0; currentPmeccHeader.key = 12; memcpy(&backupPmeccHeader, ¤tPmeccHeader, sizeof(nfParamHeader_t)); memcpy(¤tPmeccHeaderValue, ¤tPmeccHeader, sizeof(nfParamHeader_t)); pMailbox->argument.outputInit.pmeccParamHeader = currentPmeccHeaderValue; /* The Boot Program reads the first page without ECC check, to determine if the NAND parameter header is present. The header is made of 52 times the same 32-bit word (for redundancy reasons) which must contain NAND and PMECC parameters used to correctly perform the read of the rest of the data in the NAND. */ for (i = 0; i< 52; i++) memcpy(&bootNfParamHeader[i], ¤tPmeccHeader, sizeof(nfParamHeader_t)); NandSwitchEcc(ECC_PMECC); pMailbox->status = APPLET_SUCCESS; }
//------------------------------------------------------------------------------ /// Reads the data and/or spare of a page of a nandflash chip, and verify that /// the data is valid using the ECC information contained in the spare. If one /// buffer pointer is 0, the corresponding area is not saved. /// Returns 0 if the data has been read and is valid; otherwise returns either /// NandCommon_ERROR_CORRUPTEDDATA or ... /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of block to read from. /// \param page Number of page to read inside given block. /// \param data Data area buffer. /// \param spare Spare area buffer. //------------------------------------------------------------------------------ unsigned char EccNandFlash_ReadPage( const struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE]; unsigned char error; #ifndef HARDWARE_ECC unsigned char tmpData[NandCommon_MAXPAGEDATASIZE]; unsigned char hamming[NandCommon_MAXSPAREECCBYTES]; #else unsigned char hsiaoInSpare[NandCommon_MAXSPAREECCBYTES]; unsigned char hsiao[NandCommon_MAXSPAREECCBYTES]; #endif unsigned char tmpNoEcc; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); #ifndef HARDWARE_ECC // Start by reading the spare data error = RawNandFlash_ReadPage(RAW(ecc), block, page, 0, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r"); return error; } // Then reading the data error = RawNandFlash_ReadPage(RAW(ecc), block, page, tmpData, 0); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r"); return error; } tmpNoEcc = EccNandlfash_GetNoECC(); if(!tmpNoEcc){ // Retrieve ECC information from page and verify the data NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming); error = Hamming_Verify256x(tmpData, pageDataSize, hamming); } #else // Start by reading the spare area // Note: Can't read data and spare at the same time, otherwise, the ECC parity generation will be incorrect. error = RawNandFlash_ReadPage(RAW(ecc), block, page, 0, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); return error; } // Retrieve ECC information from page and verify the data NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hsiaoInSpare); // Reading the main data area error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, 0); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); return error; } HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); error = HSMC4_VerifyHsiao((unsigned char*) data, pageDataSize, hsiaoInSpare, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); #endif if (error && (error != Hamming_ERROR_SINGLEBIT) && (!tmpNoEcc)) { TRACE_ERROR("EccNandFlash_ReadPage: at B%d.P%d Unrecoverable data\n\r", block, page); return NandCommon_ERROR_CORRUPTEDDATA; } #ifndef HARDWARE_ECC // Copy data and/or spare into final buffers if (data) { memcpy(data, tmpData, pageDataSize); } if (spare) { memcpy(spare, tmpSpare, pageSpareSize); } #else if (spare) { memcpy(spare, tmpSpare, pageSpareSize); } #endif return 0; }
/** * \brief Writes the data and/or spare area of a nandflash page, after calculating an * ECC for the data area and storing it in the spare. If no data buffer is * provided, the ECC is read from the existing page spare. If no spare buffer * is provided, the spare area is still written with the ECC information * calculated on the data buffer. * \param ecc Pointer to an EccNandFlash instance. * \param block Number of block to read from. * \param page Number of page to read inside given block. * \param data Data area buffer. * \param spare Spare area buffer. * \return 0 if successful; otherwise returns an error code. */ unsigned char EccNandFlash_WritePage( const struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char error; unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE]; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); #ifndef HARDWARE_ECC unsigned char hamming[NandCommon_MAXSPAREECCBYTES]; #else unsigned char hsiao[NandCommon_MAXSPAREECCBYTES]; #endif assert( (data != NULL) || (spare != NULL) ) ; // TRACE_DEBUG( "EccNandFlash_WritePage: At least one area must be written\n\r" ) ; TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page); #ifndef HARDWARE_ECC /* Compute ECC on the new data, if provided */ /* If not provided, hamming code set to 0xFFFF.. to keep existing bytes */ memset(hamming, 0xFF, NandCommon_MAXSPAREECCBYTES); if (data) { /* Compute hamming code on data */ Hamming_Compute256x(data, pageDataSize, hamming); } /* Store code in spare buffer (if no buffer provided, use a temp. one) */ if (!spare) { spare = tmpSpare; memset(spare, 0xFF, pageSpareSize); } NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hamming); /* Perform write operation */ error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) { TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r"); return error; } #else /* Store code in spare buffer (if no buffer provided, use a temp. one) */ if (!spare) { spare = tmpSpare; memset(spare, 0xFF, pageSpareSize); } /* Perform write operation */ error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) { TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r"); return error; } HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); /* Perform write operation */ NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao); error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare); if (error) { TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r"); return error; } #endif return 0; }
/** * \brief Reads the data and/or spare of a page of a nandflash chip, and verify that * the data is valid using the ECC information contained in the spare. If one * buffer pointer is 0, the corresponding area is not saved. * \param ecc Pointer to an EccNandFlash instance. * \param block Number of block to read from. * \param page Number of page to read inside given block. * \param data Data area buffer. * \param spare Spare area buffer. * \return 0 if the data has been read and is valid; otherwise returns either * NandCommon_ERROR_CORRUPTEDDATA or ... */ unsigned char EccNandFlash_ReadPage( const struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE]; unsigned char error; #ifndef HARDWARE_ECC // unsigned char tmpData[NandCommon_MAXPAGEDATASIZE]; unsigned char hamming[NandCommon_MAXSPAREECCBYTES]; #else unsigned char hsiaoInSpare[NandCommon_MAXSPAREECCBYTES]; unsigned char hsiao[NandCommon_MAXSPAREECCBYTES]; #endif unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); #ifndef HARDWARE_ECC /* Start by reading the spare and the data */ error = RawNandFlash_ReadPage(RAW(ecc), block, page, gdwNandFlashTempBuffer, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r"); return error; } /* Retrieve ECC information from page and verify the data */ NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming); error = Hamming_Verify256x(gdwNandFlashTempBuffer, pageDataSize, hamming); #else error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); return error; } /* Retrieve ECC information from page */ NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hsiaoInSpare); HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); /* Verify the data */ error = HSMC4_VerifyHsiao((unsigned char*) data, pageDataSize, hsiaoInSpare, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); #endif if (error && (error != Hamming_ERROR_SINGLEBIT)) { TRACE_ERROR("EccNandFlash_ReadPage: at B%d.P%d Unrecoverable data\n\r", block, page); return NandCommon_ERROR_CORRUPTEDDATA; } #ifndef HARDWARE_ECC /* Copy data and/or spare into final buffers */ if (data) { memcpy(data, gdwNandFlashTempBuffer, pageDataSize); } if (spare) { memcpy(spare, tmpSpare, pageSpareSize); } #else if (spare) { memcpy(spare, tmpSpare, pageSpareSize); } #endif return 0; }