From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- memories/nandflash/EccNandFlash.c | 328 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 memories/nandflash/EccNandFlash.c (limited to 'memories/nandflash/EccNandFlash.c') diff --git a/memories/nandflash/EccNandFlash.c b/memories/nandflash/EccNandFlash.c new file mode 100644 index 0000000..dad5c95 --- /dev/null +++ b/memories/nandflash/EccNandFlash.c @@ -0,0 +1,328 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "EccNandFlash.h" +#include "NandCommon.h" +#include "NandSpareScheme.h" +#include +#include +#include +#ifdef HARDWARE_ECC +#include +#endif +#include + +//------------------------------------------------------------------------------ +// Variables +//------------------------------------------------------------------------------ +/// Not using ECC +static unsigned char noEcc = 0; + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +/// Casts +#define MODEL(ecc) ((struct NandFlashModel *) ecc) +#define RAW(ecc) ((struct RawNandFlash *) ecc) + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes an EccNandFlash instance. +/// \param ecc Pointer to an EccNandFlash instance. +/// \param model Pointer to the underlying nand chip model. Can be 0. +/// \param commandAddress Address at which commands are sent. +/// \param addressAddress Address at which addresses are sent. +/// \param dataAddress Address at which data is sent. +/// \param pinChipEnable Pin controlling the CE signal of the NandFlash. +/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand. +//------------------------------------------------------------------------------ +unsigned char EccNandFlash_Initialize( + struct EccNandFlash *ecc, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy) +{ + unsigned char rc; + rc = RawNandFlash_Initialize(RAW(ecc), + model, + commandAddress, + addressAddress, + dataAddress, + pinChipEnable, + pinReadyBusy); +#if defined(HARDWARE_ECC) + { unsigned int ecc_page; + switch(NandFlashModel_GetPageDataSize(MODEL(ecc))) { + case 512: ecc_page = AT91C_HSMC4_PAGESIZE_528_Bytes; break; + case 1024: ecc_page = AT91C_HSMC4_PAGESIZE_1056_Bytes; break; + case 2048: ecc_page = AT91C_HSMC4_PAGESIZE_2112_Bytes; break; + case 4096: ecc_page = AT91C_HSMC4_PAGESIZE_4224_Bytes; break; + default: + TRACE_ERROR("PageSize %d not compatible with ECC\n\r", + NandFlashModel_GetPageDataSize(MODEL(ecc))); + return NandCommon_ERROR_ECC_NOT_COMPATIBLE; + } + HSMC4_EccConfigure(AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES, + ecc_page); + } +#endif + return rc; +} + +//------------------------------------------------------------------------------ +/// 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; +} + +//------------------------------------------------------------------------------ +/// 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 tmpNoEcc; +#ifndef HARDWARE_ECC + unsigned char hamming[NandCommon_MAXSPAREECCBYTES]; +#else + unsigned char hsiao[NandCommon_MAXSPAREECCBYTES]; +#endif + + 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 + + tmpNoEcc = EccNandlfash_GetNoECC(); + // 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 && !tmpNoEcc) { + + // 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; +} + +//------------------------------------------------------------------------------ +/// Set no ecc flag. +//------------------------------------------------------------------------------ +void EccNandlfash_SetNoECC(void) +{ + noEcc = 1; +} + +//------------------------------------------------------------------------------ +/// Clear no ecc flag. +//------------------------------------------------------------------------------ +void EccNandlfash_ClearNoECC(void) +{ + noEcc = 0; +} + +//------------------------------------------------------------------------------ +/// Get no ecc flag. +//------------------------------------------------------------------------------ +unsigned char EccNandlfash_GetNoECC(void) +{ + return noEcc; +} + -- cgit v1.2.3