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 ++++++++++++ memories/nandflash/EccNandFlash.h | 101 ++++ memories/nandflash/ManagedNandFlash.c | 862 ++++++++++++++++++++++++++++++ memories/nandflash/ManagedNandFlash.h | 154 ++++++ memories/nandflash/MappedNandFlash.c | 661 +++++++++++++++++++++++ memories/nandflash/MappedNandFlash.h | 116 ++++ memories/nandflash/NandCommon.h | 134 +++++ memories/nandflash/NandFlashModel.c | 403 ++++++++++++++ memories/nandflash/NandFlashModel.h | 169 ++++++ memories/nandflash/NandFlashModelList.c | 118 +++++ memories/nandflash/NandFlashModelList.h | 65 +++ memories/nandflash/NandSpareScheme.c | 230 ++++++++ memories/nandflash/NandSpareScheme.h | 124 +++++ memories/nandflash/NfcRawNandFlash.c | 871 +++++++++++++++++++++++++++++++ memories/nandflash/RawNandFlash.c | 792 ++++++++++++++++++++++++++++ memories/nandflash/RawNandFlash.h | 139 +++++ memories/nandflash/SkipBlockNandFlash.c | 444 ++++++++++++++++ memories/nandflash/SkipBlockNandFlash.h | 134 +++++ memories/nandflash/TranslatedNandFlash.c | 587 +++++++++++++++++++++ memories/nandflash/TranslatedNandFlash.h | 108 ++++ memories/nandflash/nandflash.dir | 44 ++ 21 files changed, 6584 insertions(+) create mode 100644 memories/nandflash/EccNandFlash.c create mode 100644 memories/nandflash/EccNandFlash.h create mode 100644 memories/nandflash/ManagedNandFlash.c create mode 100644 memories/nandflash/ManagedNandFlash.h create mode 100644 memories/nandflash/MappedNandFlash.c create mode 100644 memories/nandflash/MappedNandFlash.h create mode 100644 memories/nandflash/NandCommon.h create mode 100644 memories/nandflash/NandFlashModel.c create mode 100644 memories/nandflash/NandFlashModel.h create mode 100644 memories/nandflash/NandFlashModelList.c create mode 100644 memories/nandflash/NandFlashModelList.h create mode 100644 memories/nandflash/NandSpareScheme.c create mode 100644 memories/nandflash/NandSpareScheme.h create mode 100644 memories/nandflash/NfcRawNandFlash.c create mode 100644 memories/nandflash/RawNandFlash.c create mode 100644 memories/nandflash/RawNandFlash.h create mode 100644 memories/nandflash/SkipBlockNandFlash.c create mode 100644 memories/nandflash/SkipBlockNandFlash.h create mode 100644 memories/nandflash/TranslatedNandFlash.c create mode 100644 memories/nandflash/TranslatedNandFlash.h create mode 100644 memories/nandflash/nandflash.dir (limited to 'memories/nandflash') 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; +} + diff --git a/memories/nandflash/EccNandFlash.h b/memories/nandflash/EccNandFlash.h new file mode 100644 index 0000000..39358e8 --- /dev/null +++ b/memories/nandflash/EccNandFlash.h @@ -0,0 +1,101 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "EccNandFlash" +/// +/// !!!Purpose +/// +/// EccNandFlash layer is called by SkipBlockNandFlash driver, it will call the bl driver (RawNandFlash) +/// to do write/read operations, and do ECC check to the write/read result, it then will feedback the +/// ecc check result to the upper SkipBlockNandFlash layer driver. +/// +/// !!!Usage +/// +/// -# EccNandFlash_Initialize is used to initializes an EccNandFlash instance. +/// -# EccNandFlash_WritePage is used to write a Nandflash page with ecc result, the function +/// will calculate ecc for the data that is going to be written, and write data and spare(with +/// calculated ecc) to Nandflash device. +/// -# EccNandFlash_ReadPage is uese to read a Nandflash page with ecc check, the function +/// will read out data and spare first, then it calculates ecc with data and then compare with +/// the readout ecc, and feedback the ecc check result to dl driver. +//------------------------------------------------------------------------------ + +#ifndef ECCNANDFLASH_H +#define ECCNANDFLASH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "RawNandFlash.h" +#include + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +struct EccNandFlash { + + struct RawNandFlash raw; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern 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); + +extern unsigned char EccNandFlash_ReadPage( + const struct EccNandFlash *ecc, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char EccNandFlash_WritePage( + const struct EccNandFlash *ecc, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern void EccNandlfash_SetNoECC(void); +extern void EccNandlfash_ClearNoECC(void); +extern unsigned char EccNandlfash_GetNoECC(void); + +#endif //#ifndef ECCNANDFLASH_H + diff --git a/memories/nandflash/ManagedNandFlash.c b/memories/nandflash/ManagedNandFlash.c new file mode 100644 index 0000000..dcc39d6 --- /dev/null +++ b/memories/nandflash/ManagedNandFlash.c @@ -0,0 +1,862 @@ +/* ---------------------------------------------------------------------------- + * 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 "ManagedNandFlash.h" +#include "NandSpareScheme.h" +#include "NandFlashModel.h" +#include "RawNandFlash.h" +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +// Casts +#define ECC(managed) ((struct EccNandFlash *) managed) +#define RAW(managed) ((struct RawNandFlash *) managed) +#define MODEL(managed) ((struct NandFlashModel *) managed) + +// Values returned by the CheckBlock() function +#define BADBLOCK 255 +#define GOODBLOCK 254 + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns 1 if a nandflash device is virgin (i.e. has never been used as a +/// managed nandflash); otherwise return 0. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param spare Pointer to allocated spare area (must be assigned) +//------------------------------------------------------------------------------ +static unsigned char IsDeviceVirgin(const struct ManagedNandFlash *managed, + unsigned char *spare) +{ + struct NandBlockStatus blockStatus; + const struct NandSpareScheme *scheme = + NandFlashModel_GetScheme(MODEL(managed)); + unsigned short baseBlock = managed->baseBlock; + unsigned char badBlockMarker; + + unsigned char error; + + ASSERT(spare, "ManagedNandFlash_IsDeviceVirgin: spare\n\r"); + + // Read spare area of page #0 + error = RawNandFlash_ReadPage(RAW(managed), baseBlock, 0, 0, spare); + ASSERT(!error, "ManagedNandFlash_IsDeviceVirgin: Failed to read page #0\n\r"); + + // Retrieve bad block marker and block status from spare area + NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); + NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0); + + // Check if block is marked as bad + if (badBlockMarker != 0xFF) { + + // Device is not virgin, since page #0 is guaranteed to be good + return 0; + } + // If device is not virgin, then block status will be set to either + // FREE, DIRTY or LIVE + else if (blockStatus.status != NandBlockStatus_DEFAULT) { + + // Device is not virgin + return 0; + } + + return 1; +} + +//------------------------------------------------------------------------------ +/// 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; +} + +//------------------------------------------------------------------------------ +/// Physically writes the status of a block inside its first page spare area. +/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xx code. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block Raw block number. +/// \param pStatus Pointer to status data. +/// \param spare Pointer to allocated spare area (must be assigned). +//------------------------------------------------------------------------------ +static unsigned char WriteBlockStatus( + const struct ManagedNandFlash *managed, + unsigned short block, + struct NandBlockStatus *pStatus, + unsigned char *spare) +{ + ASSERT(spare, "ManagedNandFlash_WriteBlockStatus: spare\n\r"); + + memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE); + NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)), + spare, + pStatus, + 4, + 0); + return RawNandFlash_WritePage(RAW(managed), + block, 0, 0, spare); +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a ManagedNandFlash instance. Scans the device to retrieve or +/// create block status information. +/// \param managed Pointer to a ManagedNandFlash 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. +/// \param baseBlock Base physical block address of managed area, managed 0. +/// \param sizeInBlocks Number of blocks that is managed. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_Initialize( + struct ManagedNandFlash *managed, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy, + unsigned short baseBlock, + unsigned short sizeInBlocks) +{ + unsigned char error; + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + unsigned int numBlocks; + unsigned int pageSpareSize; + const struct NandSpareScheme *scheme; + unsigned int block, phyBlock; + struct NandBlockStatus blockStatus; + unsigned char badBlockMarker; + unsigned int eraseCount, minEraseCount, maxEraseCount; + + TRACE_DEBUG("ManagedNandFlash_Initialize()\n\r"); + + // Initialize EccNandFlash + error = EccNandFlash_Initialize(ECC(managed), + model, + commandAddress, + addressAddress, + dataAddress, + pinChipEnable, + pinReadyBusy); + if (error) { + + return error; + } + + // Retrieve model information + numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(managed)); + pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed)); + scheme = NandFlashModel_GetScheme(MODEL(managed)); + + // Initialize base & size + if (sizeInBlocks == 0) sizeInBlocks = numBlocks; + if (baseBlock > numBlocks) { + baseBlock = 0; + } + else if (baseBlock + sizeInBlocks > numBlocks) { + sizeInBlocks = numBlocks - baseBlock; + } + TRACE_INFO("Managed NF area: %d + %d\n\r", baseBlock, sizeInBlocks); + + if (sizeInBlocks > NandCommon_MAXNUMBLOCKS) { + TRACE_ERROR("Out of Maxmized Managed Size: %d > %d\n\r", + sizeInBlocks, NandCommon_MAXNUMBLOCKS); + TRACE_INFO("Change NandCommon_MAXNUMBLOCKS or sizeInBlocks\n\r"); + return NandCommon_ERROR_OUTOFBOUNDS; + } + + managed->baseBlock = baseBlock; + managed->sizeInBlocks = sizeInBlocks; + + // Initialize block statuses + // First, check if device is virgin + if (IsDeviceVirgin(managed, spare)) { + + TRACE_WARNING("Device is virgin, doing initial block scanning ...\n\r"); + + // Perform initial scan of the device area + for (block=0; block < sizeInBlocks; block++) { + + phyBlock = baseBlock + block; + + // Check if physical block is bad + error = CheckBlock(managed, phyBlock, spare); + if (error == BADBLOCK) { + + // Mark block as bad + TRACE_DEBUG("Block #%d is bad\n\r", block); + managed->blockStatuses[block].status = NandBlockStatus_BAD; + } + else if (error == GOODBLOCK) { + + // Mark block as free with erase count 0 + TRACE_DEBUG("Block #%d is free\n\r", block); + managed->blockStatuses[block].status = NandBlockStatus_FREE; + managed->blockStatuses[block].eraseCount = 0; + + // Write status in spare of block first page + error = WriteBlockStatus(managed, + phyBlock, + &(managed->blockStatuses[block]), + spare); + if (error) { + + TRACE_ERROR("ManagedNandFlash_Initialize: WR spare\n\r"); + return error; + } + } + else { + + TRACE_ERROR("ManagedNandFlash_Initialize: Scan device\n\r"); + return error; + } + } + } + else { + + TRACE_INFO("Managed, retrieving information ...\n\r"); + + // Retrieve block statuses from their first page spare area + // (find maximum and minimum wear at the same time) + minEraseCount = 0xFFFFFFFF; + maxEraseCount = 0; + for (block=0; block < sizeInBlocks; block++) { + + phyBlock = baseBlock + block; + + // Read spare of first page + error = RawNandFlash_ReadPage(RAW(managed), phyBlock, 0, 0, spare); + if (error) { + + TRACE_ERROR("ManagedNandFlash_Initialize: Read block #%d(%d)\n\r", + block, phyBlock); + } + + // Retrieve bad block marker and block status + NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); + NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0); + + // If they do not match, block must be bad + if ( (badBlockMarker != 0xFF) + && (blockStatus.status != NandBlockStatus_BAD)) { + + TRACE_DEBUG("Block #%d(%d) is bad\n\r", block, phyBlock); + managed->blockStatuses[block].status = NandBlockStatus_BAD; + } + // Check that block status is not default + // (meaning block is not managed) + else if (blockStatus.status == NandBlockStatus_DEFAULT) { + + ASSERT(0, "Block #%d(%d) is not managed\n\r", block, phyBlock); + } + // Otherwise block status is accurate + else { + + TRACE_DEBUG("Block #%03d(%d) : status = %2d | eraseCount = %d\n\r", + block, phyBlock, + blockStatus.status, blockStatus.eraseCount); + managed->blockStatuses[block] = blockStatus; + + // Check for min/max erase counts + if (blockStatus.eraseCount < minEraseCount) { + + minEraseCount = blockStatus.eraseCount; + } + if (blockStatus.eraseCount > maxEraseCount) { + + maxEraseCount = blockStatus.eraseCount; + } + + //// Clean block + //// Release LIVE blocks + //if (managed->blockStatuses[block].status == NandBlockStatus_LIVE) { + // + // ManagedNandFlash_ReleaseBlock(managed, block); + //} + //// Erase DIRTY blocks + //if (managed->blockStatuses[block].status == NandBlockStatus_DIRTY) { + // + // ManagedNandFlash_EraseBlock(managed, block); + //} + } + } + + // Display erase count information + TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r"); + TRACE_ERROR_WP("| Wear | Count | Free | Live | Dirty |\n\r"); + TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r"); + + for (eraseCount=minEraseCount; eraseCount <= maxEraseCount; eraseCount++) { + + unsigned int count = 0, live = 0, dirty = 0, free = 0; + for (block=0; block < sizeInBlocks; block++) { + + if ((managed->blockStatuses[block].eraseCount == eraseCount) + && (managed->blockStatuses[block].status != NandBlockStatus_BAD)) { + + count++; + + switch (managed->blockStatuses[block].status) { + case NandBlockStatus_LIVE: live++; break; + case NandBlockStatus_DIRTY: dirty++; break; + case NandBlockStatus_FREE: free++; break; + } + } + } + + if (count > 0) { + + TRACE_ERROR_WP("| %4d | %8d | %4d | %4d | %4d |\n\r", + eraseCount, count, free, live, dirty); + } + } + TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r"); + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Allocates a FREE block of a managed nandflash and marks it as LIVE. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if +/// the block is not FREE. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block Block to allocate, in managed area. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_AllocateBlock( + struct ManagedNandFlash *managed, + unsigned short block) +{ + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + TRACE_INFO("ManagedNandFlash_AllocateBlock(%d)\n\r", block); + + // Check that block is FREE + if (managed->blockStatuses[block].status != NandBlockStatus_FREE) { + + TRACE_ERROR("ManagedNandFlash_AllocateBlock: Block must be FREE\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + + // Change block status to LIVE + managed->blockStatuses[block].status = NandBlockStatus_LIVE; + return WriteBlockStatus(managed, + managed->baseBlock + block, + &(managed->blockStatuses[block]), + spare); +} + +//------------------------------------------------------------------------------ +/// Releases a LIVE block of a nandflash and marks it as DIRTY. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if +/// the block is not LIVE, or a RawNandFlash_WritePage error. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block Block to release, based on managed area. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_ReleaseBlock( + struct ManagedNandFlash *managed, + unsigned short block) +{ + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + TRACE_INFO("ManagedNandFlash_ReleaseBlock(%d)\n\r", block); + + // Check that block is LIVE + if (managed->blockStatuses[block].status != NandBlockStatus_LIVE) { + + TRACE_ERROR("ManagedNandFlash_ReleaseBlock: Block must be LIVE\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + + // Change block status to DIRTY + managed->blockStatuses[block].status = NandBlockStatus_DIRTY; + return WriteBlockStatus(managed, + managed->baseBlock + block, + &(managed->blockStatuses[block]), + spare); +} + +//------------------------------------------------------------------------------ +/// Erases a DIRTY block of a managed NandFlash. +/// Returns the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block Block to erase, in managed area. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_EraseBlock( + struct ManagedNandFlash *managed, + unsigned short block) +{ + unsigned int phyBlock = managed->baseBlock + block; + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + unsigned char error; + TRACE_INFO("ManagedNandFlash_EraseBlock(%d)\n\r", block); + + // Check block status + if (managed->blockStatuses[block].status != NandBlockStatus_DIRTY) { + + TRACE_ERROR("ManagedNandFlash_EraseBlock: Block must be DIRTY\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + + // Erase block + error = RawNandFlash_EraseBlock(RAW(managed), phyBlock); + if (error) { + + return error; + } + + // Update block status + managed->blockStatuses[block].status = NandBlockStatus_FREE; + managed->blockStatuses[block].eraseCount++; + return WriteBlockStatus(managed, + phyBlock, + &(managed->blockStatuses[block]), + spare); +} + +//------------------------------------------------------------------------------ +/// Reads the data and/or the spare area of a page on a managed nandflash. If +/// the data pointer is not 0, then the block MUST be LIVE. +/// Returns NandCommon_ERROR_WRONGSTATUS if the block is not LIVE and the data +/// pointer is not null; Otherwise, returns EccNandFlash_ReadPage(). +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block Block to read page from, based on managed area. +/// \param page Number of page to read inside the given block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_ReadPage( + const struct ManagedNandFlash *managed, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + // Check that the block is LIVE if data is requested + if ((managed->blockStatuses[block].status != NandBlockStatus_LIVE) + && (managed->blockStatuses[block].status != NandBlockStatus_DIRTY)) { + + TRACE_ERROR("ManagedNandFlash_ReadPage: Block must be LIVE or DIRTY.\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + + // Read data with ECC verification + return EccNandFlash_ReadPage(ECC(managed), + managed->baseBlock + block, + page, data, spare); +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or spare area of a LIVE page on a managed NandFlash. +/// Returns NandCommon_ERROR_WRONGSTATUS if the page is not LIVE; otherwise, +/// returns EccNandFlash_WritePage(). +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block The block to write, in managed area. +/// \param page Number of the page to write inside the given block. +/// \param data Data area buffer. +/// \param spare Spare area buffer. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_WritePage( + const struct ManagedNandFlash *managed, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + // Check that the block is LIVE + if (managed->blockStatuses[block].status != NandBlockStatus_LIVE) { + + TRACE_ERROR("ManagedNandFlash_WritePage: Block must be LIVE.\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + + // Write data with ECC calculation + return EccNandFlash_WritePage(ECC(managed), + managed->baseBlock + block, + page, data, spare); +} + +//------------------------------------------------------------------------------ +/// Copy the data & spare area of one page to another page. The source block +/// can be either LIVE or DIRTY, and the destination block must be LIVE; they +/// must both have the same parity. +/// Returns 0 if successful; NandCommon_ERROR_WRONGSTATUS if one or more page +/// is not live; otherwise returns an NandCommon_ERROR_xxx code. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param sourceBlock Source block number based on managed area. +/// \param sourcePage Number of source page inside the source block. +/// \param destBlock Destination block number based on managed area. +/// \param destPage Number of destination page inside the dest block. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_CopyPage( + const struct ManagedNandFlash *managed, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage) +{ + unsigned char error; + + ASSERT((sourcePage & 1) == (destPage & 1), + "ManagedNandFlash_CopyPage: source & dest pages must have the same parity\n\r"); + + TRACE_INFO("ManagedNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r", + sourceBlock, sourcePage, destBlock, destPage); + + // Check block statuses + if ((managed->blockStatuses[sourceBlock].status != NandBlockStatus_LIVE) + && (managed->blockStatuses[sourceBlock].status != NandBlockStatus_DIRTY)) { + + TRACE_ERROR("ManagedNandFlash_CopyPage: Source block must be LIVE or DIRTY.\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + if (managed->blockStatuses[destBlock].status != NandBlockStatus_LIVE) { + + TRACE_ERROR("ManagedNandFlash_CopyPage: Destination block must be LIVE.\n\r"); + return NandCommon_ERROR_WRONGSTATUS; + } + + // If destination page is page #0, block status information must not be + // overwritten + if (destPage == 0) { + + unsigned char data[NandCommon_MAXPAGEDATASIZE]; + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + + // Read data & spare to copy + error = EccNandFlash_ReadPage(ECC(managed), + managed->baseBlock + sourceBlock, + sourcePage, + data, spare); + if (error) { + + return error; + } + + // Write destination block status information in spare + NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)), + spare, + &(managed->blockStatuses[destBlock]), + 4, + 0); + + // Write page + error = RawNandFlash_WritePage(RAW(managed), + managed->baseBlock + destBlock, + destPage, + data, spare); + if (error) { + + return error; + } + } + // Otherwise, a normal copy can be done + else { + + return RawNandFlash_CopyPage(RAW(managed), + managed->baseBlock + sourceBlock, + sourcePage, + managed->baseBlock + destBlock, + destPage); + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Copies the data from a whole block to another block on a nandflash. Both +/// blocks must be LIVE. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if +/// at least one of the blocks is not free, or a NandCommon_ERROR_xxx code. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param sourceBlock Source block number. +/// \param destBlock Destination block number. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_CopyBlock( + const struct ManagedNandFlash *managed, + unsigned short sourceBlock, + unsigned short destBlock) +{ + unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(managed)); + unsigned char error; + unsigned short page; + + ASSERT(sourceBlock != destBlock, + "ManagedNandFlash_CopyBlock: Source block must be different from dest. block\n\r"); + + TRACE_INFO("ManagedNandFlash_CopyBlock(B#%d->B#%d)\n\r", + sourceBlock, destBlock); + + // Copy all pages + for (page=0; page < numPages; page++) { + + error = ManagedNandFlash_CopyPage(managed, + sourceBlock, + page, + destBlock, + page); + if (error) { + + TRACE_ERROR("ManagedNandFlash_CopyPage: Failed to copy page %d\n\r", page); + return error; + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Erases all the blocks which are currently marked as DIRTY. +/// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code. +/// \param managed Pointer to a ManagedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_EraseDirtyBlocks( + struct ManagedNandFlash *managed) +{ + unsigned int i; + unsigned char error; + + // Erase all dirty blocks + for (i=0; i < managed->sizeInBlocks; i++) { + + if (managed->blockStatuses[i].status == NandBlockStatus_DIRTY) { + + error = ManagedNandFlash_EraseBlock(managed, i); + if (error) { + + return error; + } + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Looks for the youngest block having the desired status among the blocks +/// of a managed nandflash. If a block is found, its index is stored inside +/// the provided variable (if pointer is not 0). +/// Returns 0 if a block has been found; otherwise returns either +/// NandCommon_ERROR_NOBLOCKFOUND if there are no blocks having the desired +/// status. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param block Pointer to the block number variable, based on managed area. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_FindYoungestBlock( + const struct ManagedNandFlash *managed, + unsigned char status, + unsigned short *block) +{ + unsigned char found = 0; + unsigned short bestBlock = 0; + unsigned int i; + + // Go through the block array + for (i=0; i < managed->sizeInBlocks; i++) { + + // Check status + if (managed->blockStatuses[i].status == status) { + + // If no block was found, i becomes the best block + if (!found) { + + found = 1; + bestBlock = i; + } + // Compare the erase counts otherwise + else if (managed->blockStatuses[i].eraseCount + < managed->blockStatuses[bestBlock].eraseCount) { + + bestBlock = i; + } + } + } + + if (found) { + + if (block) { + + *block = bestBlock; + } + return 0; + } + else { + + return NandCommon_ERROR_NOBLOCKFOUND; + } +} + +//------------------------------------------------------------------------------ +/// Counts and returns the number of blocks having the given status in a +/// managed nandflash. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param status Desired block status. +//------------------------------------------------------------------------------ +unsigned short ManagedNandFlash_CountBlocks( + const struct ManagedNandFlash *managed, + unsigned char status) +{ + unsigned int i; + unsigned short count = 0; + + // Examine each block + for (i=0; i < managed->sizeInBlocks; i++) { + + if (managed->blockStatuses[i].status == status) { + + count++; + } + } + + return count; +} + +//------------------------------------------------------------------------------ +/// Returns the number of available blocks in a managed nandflash. +/// \param managed Pointer to a ManagedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned short ManagedNandFlash_GetDeviceSizeInBlocks( + const struct ManagedNandFlash *managed) +{ + return managed->sizeInBlocks; +} + +//------------------------------------------------------------------------------ +/// Erase all blocks in the managed area of nand flash. +/// \param managed Pointer to a ManagedNandFlash instance. +/// \param level Erase level. +//------------------------------------------------------------------------------ +unsigned char ManagedNandFlash_EraseAll(struct ManagedNandFlash *managed, + unsigned char level) +{ + unsigned int i; + unsigned char error = 0; + + if (level == NandEraseFULL) { + for (i=0; i < managed->sizeInBlocks; i++) { + error = RawNandFlash_EraseBlock(RAW(managed), + managed->baseBlock + i); + // Reset block status + managed->blockStatuses[i].eraseCount = 0; + if (error) { + TRACE_WARNING("Managed_FullErase: %d(%d)\n\r", + i, managed->baseBlock + i); + managed->blockStatuses[i].status = NandBlockStatus_BAD; + continue; + } + managed->blockStatuses[i].status = NandBlockStatus_FREE; + } + } + else if (level == NandEraseDATA) { + for (i=0; i < managed->sizeInBlocks; i++) { + error = ManagedNandFlash_EraseBlock(managed, i); + if (error) { + TRACE_WARNING("Managed_DataErase: %d(%d)\n\r", + i, managed->baseBlock + i); + } + } + } + else { + for (i=0; i < managed->sizeInBlocks; i++) { + if (managed->blockStatuses[i].status == NandBlockStatus_DIRTY) { + error = ManagedNandFlash_EraseBlock(managed, i); + if (error) { + TRACE_WARNING("Managed_DirtyErase: %d(%d)\n\r", + i, managed->baseBlock + i); + } + } + } + } + + return error; +} diff --git a/memories/nandflash/ManagedNandFlash.h b/memories/nandflash/ManagedNandFlash.h new file mode 100644 index 0000000..2a3f054 --- /dev/null +++ b/memories/nandflash/ManagedNandFlash.h @@ -0,0 +1,154 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "ManagedNandFlash" +/// +/// !!!Purpose +/// +/// The lower layer of nandflash block management, it is called by MappedNandFlash layer, and +/// it will call EccNandFlash layer. +//------------------------------------------------------------------------------ + +#ifndef MANAGEDNANDFLASH_H +#define MANAGEDNANDFLASH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "NandCommon.h" +#include "EccNandFlash.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +#define NandBlockStatus_DEFAULT 0xF +#define NandBlockStatus_FREE 0xE +#define NandBlockStatus_LIVE 0xC +#define NandBlockStatus_DIRTY 0x8 +#define NandBlockStatus_BAD 0x0 + +#define NandEraseDIRTY 0 // Erase dirty blocks only +#define NandEraseDATA 1 // Erase all data, calculate count +#define NandEraseFULL 2 // Erase all, reset erase count + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +struct NandBlockStatus { + + unsigned int status:4, + eraseCount:28; +}; + +struct ManagedNandFlash { + + struct EccNandFlash ecc; + struct NandBlockStatus blockStatuses[NandCommon_MAXNUMBLOCKS]; + unsigned short baseBlock; + unsigned short sizeInBlocks; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char ManagedNandFlash_Initialize( + struct ManagedNandFlash *managed, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy, + unsigned short baseBlock, + unsigned short sizeInBlocks); + +extern unsigned char ManagedNandFlash_AllocateBlock( + struct ManagedNandFlash *managed, + unsigned short block); + +extern unsigned char ManagedNandFlash_ReleaseBlock( + struct ManagedNandFlash *managed, + unsigned short block); + +extern unsigned char ManagedNandFlash_EraseBlock( + struct ManagedNandFlash *managed, + unsigned short block); + +extern unsigned char ManagedNandFlash_ReadPage( + const struct ManagedNandFlash *managed, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char ManagedNandFlash_WritePage( + const struct ManagedNandFlash *managed, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char ManagedNandFlash_CopyPage( + const struct ManagedNandFlash *managed, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage); + +extern unsigned char ManagedNandFlash_CopyBlock( + const struct ManagedNandFlash *managed, + unsigned short sourceBlock, + unsigned short destBlock); + +extern unsigned char ManagedNandFlash_EraseDirtyBlocks( + struct ManagedNandFlash *managed); + +extern unsigned char ManagedNandFlash_FindYoungestBlock( + const struct ManagedNandFlash *managed, + unsigned char status, + unsigned short *block); + +extern unsigned short ManagedNandFlash_CountBlocks( + const struct ManagedNandFlash *managed, + unsigned char status); + +extern unsigned short ManagedNandFlash_GetDeviceSizeInBlocks( + const struct ManagedNandFlash *managed); + +extern unsigned char ManagedNandFlash_EraseAll( + struct ManagedNandFlash *managed, + unsigned char level); + +#endif //#ifndef MANAGEDNANDFLASH_H + diff --git a/memories/nandflash/MappedNandFlash.c b/memories/nandflash/MappedNandFlash.c new file mode 100644 index 0000000..9baf83e --- /dev/null +++ b/memories/nandflash/MappedNandFlash.c @@ -0,0 +1,661 @@ +/* ---------------------------------------------------------------------------- + * 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 "MappedNandFlash.h" +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +/// Casts +#define MANAGED(mapped) ((struct ManagedNandFlash *) mapped) +#define ECC(mapped) ((struct EccNandFlash *) mapped) +#define RAW(mapped) ((struct RawNandFlash *) mapped) +#define MODEL(mapped) ((struct NandFlashModel *) mapped) + +/// Logical block mapping pattern +#define PATTERN(i) ((i << 1) & 0x73) + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Scans a mapped nandflash to find an existing logical block mapping. If a +/// block contains the mapping, its index is stored in the provided variable (if +/// pointer is not 0). +/// Returns 0 if mapping has been found; otherwise returns +/// NandCommon_ERROR_NOMAPPING if no mapping exists, or another +/// NandCommon_ERROR_xxx code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param logicalMappingBlock Pointer to a variable for storing the block +/// number. +//------------------------------------------------------------------------------ +static unsigned char FindLogicalMappingBlock( + const struct MappedNandFlash *mapped, + signed short *logicalMappingBlock) +{ + unsigned short block; + unsigned char found; + unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); + unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); + unsigned char error; + unsigned char data[NandCommon_MAXPAGEDATASIZE]; + unsigned int i; + + TRACE_INFO("FindLogicalMappingBlock()~%d\n\r", numBlocks); + + // Search each LIVE block + found = 0; + block = 0; + while (!found && (block < numBlocks)) { + + // Check that block is LIVE + if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) { + + // Read block + TRACE_INFO("Checking LIVE block #%d\n\r", block); + error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0); + if (!error) { + + // Compare data with logical mapping pattern + i = 0; + found = 1; + while ((i < pageDataSize) && found) { + + if (data[i] != PATTERN(i)) { + + found = 0; + } + i++; + } + + // If this is the mapping, stop looking + if (found) { + + TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r", + block); + if (logicalMappingBlock) { + + *logicalMappingBlock = block; + } + return 0; + } + } + else if (error != NandCommon_ERROR_WRONGSTATUS) { + + TRACE_ERROR( + "FindLogicalMappingBlock: Failed to scan block #%d\n\r", + block); + return error; + } + } + + block++; + } + + TRACE_WARNING("No logical mapping found in device\n\r"); + return NandCommon_ERROR_NOMAPPING; +} + +//------------------------------------------------------------------------------ +/// Loads the logical mapping contained in the given physical block. +/// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param physicalBlock Physical block number. +//------------------------------------------------------------------------------ +static unsigned char LoadLogicalMapping( + struct MappedNandFlash *mapped, + unsigned short physicalBlock) +{ + unsigned char error; + unsigned char data[NandCommon_MAXPAGEDATASIZE]; + unsigned short pageDataSize = + NandFlashModel_GetPageDataSize(MODEL(mapped)); + unsigned short numBlocks = + ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); + unsigned int remainingSize; + unsigned char *currentBuffer; + unsigned short currentPage; + unsigned int readSize; + unsigned int i; + unsigned char status; + signed short logicalBlock; + //signed short firstBlock, lastBlock; + + TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock); + + // Load mapping from pages #1 - #XXX of block + currentBuffer = (unsigned char *) mapped->logicalMapping; + remainingSize = sizeof(mapped->logicalMapping); + currentPage = 1; + while (remainingSize > 0) { + + // Read page + readSize = min(remainingSize, pageDataSize); + error = ManagedNandFlash_ReadPage(MANAGED(mapped), + physicalBlock, + currentPage, + data, + 0); + if (error) { + + TRACE_ERROR( + "LoadLogicalMapping: Failed to load mapping\n\r"); + return error; + } + + // Copy page info + memcpy(currentBuffer, data, readSize); + + currentBuffer += readSize; + remainingSize -= readSize; + currentPage++; + } + + // Store mapping block index + mapped->logicalMappingBlock = physicalBlock; + + // Power-loss recovery + for (i=0; i < numBlocks; i++) { + + // Check that this is not the logical mapping block + if (i != physicalBlock) { + + status = mapped->managed.blockStatuses[i].status; + logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i); + + // Block is LIVE + if (status == NandBlockStatus_LIVE) { + + // Block is not mapped -> release it + if (logicalBlock == -1) { + + TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r", + i); + ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i); + } + } + // Block is DIRTY + else if (status == NandBlockStatus_DIRTY) { + + // Block is mapped -> fake it as live + if (logicalBlock != -1) { + + TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r", + i); + mapped->managed.blockStatuses[i].status = + NandBlockStatus_LIVE; + } + } + // Block is FREE or BAD + else { + + // Block is mapped -> remove it from mapping + if (logicalBlock != -1) { + + TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i); + mapped->logicalMapping[logicalBlock] = -1; + } + } + } + } + + TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock); + + return 0; +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a MappedNandFlash instance. Scans the device to look for and +/// existing logical block mapping; otherwise starts from scratch (no block +/// mapped). +/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. +/// \param mapped Pointer to a MappedNandFlash 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. +/// \param baseBlock Basic physical block address of mapped area. +/// \param sizeInBlocks Number of blocks that is mapped. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_Initialize( + struct MappedNandFlash *mapped, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy, + unsigned short baseBlock, + unsigned short sizeInBlocks) +{ + unsigned char error; + unsigned short numBlocks; + unsigned short block; + signed short logicalMappingBlock = 0; + + TRACE_INFO("MappedNandFlash_Initialize()\n\r"); + + // Initialize ManagedNandFlash + error = ManagedNandFlash_Initialize(MANAGED(mapped), + model, + commandAddress, + addressAddress, + dataAddress, + pinChipEnable, + pinReadyBusy, + baseBlock, + sizeInBlocks); + if (error) { + + return error; + } + + // Scan to find logical mapping + mapped->mappingModified = 0; + error = FindLogicalMappingBlock(mapped, &logicalMappingBlock); + if (!error) { + + // Extract mapping from block + mapped->logicalMappingBlock = logicalMappingBlock; + return LoadLogicalMapping(mapped, logicalMappingBlock); + } + else if (error == NandCommon_ERROR_NOMAPPING) { + + // Start with no block mapped + mapped->logicalMappingBlock = -1; + numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); + for (block=0; block < numBlocks; block++) { + + mapped->logicalMapping[block] = -1; + } + } + else { + + TRACE_ERROR("MappedNandFlash_Initialize: Initialize device\n\r"); + return error; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Reads the data and/or spare area of a page in a mapped logical block. +/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED +/// if the block is not mapped, or a NandCommon_ERROR_xxx code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param block Number of logical block to read page from. +/// \param page Number of page to read inside given block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_ReadPage( + const struct MappedNandFlash *mapped, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + signed short physicalBlock; + + TRACE_INFO("MappedNandFlash_ReadPage(LB#%d:P#%d)\n\r", block, page); + + // Check if block is mapped + physicalBlock = mapped->logicalMapping[block]; + if (physicalBlock == -1) { + + TRACE_INFO( "MappedNandFlash_ReadPage: Block %d not mapped\n\r", block); + return NandCommon_ERROR_BLOCKNOTMAPPED; + } + + // Read page from corresponding physical block + return ManagedNandFlash_ReadPage(MANAGED(mapped), + physicalBlock, + page, + data, + spare); +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or spare area of a page in the given mapped logical +/// block. +/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED +/// (indicating the block is not logically mapped) or another NandCommon_ERROR +/// code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param block Number of logical block to write on. +/// \param page Number of page to write inside given block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_WritePage( + const struct MappedNandFlash *mapped, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + signed short physicalBlock; + + TRACE_INFO("MappedNandFlash_WritePage(LB#%d:P#%d)\n\r", block, page); + + // Check if block is mapped + physicalBlock = mapped->logicalMapping[block]; + if (physicalBlock == -1) { + + TRACE_ERROR("MappedNandFlash_WritePage: Block must be mapped\n\r"); + return NandCommon_ERROR_BLOCKNOTMAPPED; + } + + // Write page on physical block + return ManagedNandFlash_WritePage(MANAGED(mapped), + physicalBlock, + page, + data, + spare); +} + +//------------------------------------------------------------------------------ +/// Maps a logical block number to an actual physical block. This allocates +/// the physical block (meaning it must be FREE), and releases the previous +/// block being replaced (if any). +/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param logicalBlock Logical block number to map. +/// \param physicalBlock Physical block to map to the logical one. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_Map( + struct MappedNandFlash *mapped, + unsigned short logicalBlock, + unsigned short physicalBlock) +{ + unsigned char error; + signed short oldPhysicalBlock; + + TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\n\r", + logicalBlock, physicalBlock); + ASSERT( + logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), + "MappedNandFlash_Map: logicalBlock out-of-range\n\r"); + ASSERT( + physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), + "MappedNandFlash_Map: physicalBlock out-of-range\n\r"); + + // Allocate physical block + error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); + if (error) { + + return error; + } + + // Release currently mapped block (if any) + oldPhysicalBlock = mapped->logicalMapping[logicalBlock]; + if (oldPhysicalBlock != -1) { + + error = + ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock); + if (error) { + + return error; + } + } + + // Set mapping + mapped->logicalMapping[logicalBlock] = physicalBlock; + mapped->mappingModified = 1; + + return 0; +} + +//------------------------------------------------------------------------------ +/// Unmaps a logical block by releasing the corresponding physical block (if +/// any). +/// Returns 0 if successful; otherwise returns a NandCommon_ERROR code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param logicalBlock Number of logical block to unmap. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_Unmap( + struct MappedNandFlash *mapped, + unsigned short logicalBlock) +{ + signed short physicalBlock = mapped->logicalMapping[logicalBlock]; + unsigned char error; + + TRACE_INFO("MappedNandFlash_Unmap(LB#%d)\n\r", logicalBlock); + ASSERT( + logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), + "MappedNandFlash_Unmap: logicalBlock out-of-range\n\r"); + + if (physicalBlock != -1) { + + error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), physicalBlock); + if (error) { + + return error; + } + } + mapped->logicalMapping[logicalBlock] = -1; + mapped->mappingModified = 1; + + return 0; +} + +//------------------------------------------------------------------------------ +/// Returns the physical block mapped with the given logical block, or -1 if it +/// is not mapped. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param logicalBlock Logical block number. +//------------------------------------------------------------------------------ +signed short MappedNandFlash_LogicalToPhysical( + const struct MappedNandFlash *mapped, + unsigned short logicalBlock) +{ + ASSERT( + logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), + "MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\n\r"); + + return mapped->logicalMapping[logicalBlock]; +} + +//------------------------------------------------------------------------------ +/// Returns the logical block which is mapped to given physical block, or -1 if +/// the latter is not mapped. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param physicalBlock Physical block number. +//------------------------------------------------------------------------------ +signed short MappedNandFlash_PhysicalToLogical( + const struct MappedNandFlash *mapped, + unsigned short physicalBlock) +{ + unsigned short numBlocks = + ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); + signed short logicalBlock; + + ASSERT( + physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), + "MappedNandFlash_PhysicalToLogical: physicalBlock out-of-range\n\r"); + + // Search the mapping for the desired physical block + for (logicalBlock=0; logicalBlock < numBlocks; logicalBlock++) { + + if (mapped->logicalMapping[logicalBlock] == physicalBlock) { + + return logicalBlock; + } + } + + return -1; +} + +//------------------------------------------------------------------------------ +/// Saves the logical mapping on a FREE, unmapped physical block. Allocates the +/// new block, releases the previous one (if any) and save the mapping. +/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS +/// if the block is not LIVE, or a NandCommon_ERROR code. +/// \param mapped Pointer to a MappedNandFlash instance. +/// \param physicalBlock Physical block number. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_SaveLogicalMapping( + struct MappedNandFlash *mapped, + unsigned short physicalBlock) +{ + unsigned char error; + unsigned char data[NandCommon_MAXPAGEDATASIZE]; + unsigned short pageDataSize = + NandFlashModel_GetPageDataSize(MODEL(mapped)); + //unsigned short numBlocks = + // ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); + unsigned int i; + unsigned int remainingSize; + unsigned char *currentBuffer; + unsigned short currentPage; + unsigned int writeSize; + signed short previousPhysicalBlock; + + TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\n\r", physicalBlock); + + // If mapping has not been modified, do nothing + if (!mapped->mappingModified) { + + return 0; + } + + // Allocate new block + error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); + if (error) { + + return error; + } + + // Save mapping + previousPhysicalBlock = mapped->logicalMappingBlock; + mapped->logicalMappingBlock = physicalBlock; + + // Save actual mapping in pages #1-#XXX + currentBuffer = (unsigned char *) mapped->logicalMapping; + remainingSize = sizeof(mapped->logicalMapping); + currentPage = 1; + while (remainingSize > 0) { + + writeSize = min(remainingSize, pageDataSize); + memset(data, 0xFF, pageDataSize); + memcpy(data, currentBuffer, writeSize); + error = ManagedNandFlash_WritePage(MANAGED(mapped), + physicalBlock, + currentPage, + data, + 0); + if (error) { + + TRACE_ERROR( + "MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r"); + return error; + } + + currentBuffer += writeSize; + remainingSize -= writeSize; + currentPage++; + } + + // Mark page #0 of block with a distinguishible pattern, so the mapping can + // be retrieved at startup + for (i=0; i < pageDataSize; i++) { + + data[i] = PATTERN(i); + } + error = ManagedNandFlash_WritePage(MANAGED(mapped), + physicalBlock, 0, + data, 0); + if (error) { + + TRACE_ERROR( + "MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r"); + return error; + } + + // Mapping is not modified anymore + mapped->mappingModified = 0; + + // Release previous block (if any) + if (previousPhysicalBlock != -1) { + + TRACE_DEBUG("Previous physical block was #%d\n\r", + previousPhysicalBlock); + error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), + previousPhysicalBlock); + if (error) { + + return error; + } + } + + TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock); + + return 0; +} + +//------------------------------------------------------------------------------ +/// Erase all blocks in the mapped area of nand flash. +/// \param managed Pointer to a MappedNandFlash instance. +/// \param level Erase level. +//------------------------------------------------------------------------------ +unsigned char MappedNandFlash_EraseAll( + struct MappedNandFlash *mapped, + unsigned char level) +{ + unsigned int block; + ManagedNandFlash_EraseAll(MANAGED(mapped), level); + // Reset to no block mapped + if (level > NandEraseDIRTY) { + mapped->logicalMappingBlock = -1; + mapped->mappingModified = 0; + for (block=0; + block < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); + block++) { + mapped->logicalMapping[block] = -1; + } + } + return 0; +} diff --git a/memories/nandflash/MappedNandFlash.h b/memories/nandflash/MappedNandFlash.h new file mode 100644 index 0000000..c34bfc1 --- /dev/null +++ b/memories/nandflash/MappedNandFlash.h @@ -0,0 +1,116 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "MappedNandFlash" +/// +/// !!!Purpose +/// +/// MappedNandFlash layer will do operations on logical blocks of nandflash, it is called by +/// TranslatedNandFlash layer +//------------------------------------------------------------------------------ + +#ifndef MAPPEDNANDFLASH_H +#define MAPPEDNANDFLASH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "ManagedNandFlash.h" + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +struct MappedNandFlash { + + struct ManagedNandFlash managed; + signed short logicalMapping[NandCommon_MAXNUMBLOCKS]; + signed short logicalMappingBlock; + unsigned char mappingModified; + unsigned char reserved; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char MappedNandFlash_Initialize( + struct MappedNandFlash *mapped, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy, + unsigned short baseBlock, + unsigned short sizeInBlocks); + +extern unsigned char MappedNandFlash_ReadPage( + const struct MappedNandFlash *mapped, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char MappedNandFlash_WritePage( + const struct MappedNandFlash *mapped, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char MappedNandFlash_Map( + struct MappedNandFlash *mapped, + unsigned short logicalBlock, + unsigned short physicalBlock); + +extern unsigned char MappedNandFlash_Unmap( + struct MappedNandFlash *mapped, + unsigned short logicalBlock); + +extern signed short MappedNandFlash_LogicalToPhysical( + const struct MappedNandFlash *mapped, + unsigned short logicalBlock); + +extern signed short MappedNandFlash_PhysicalToLogical( + const struct MappedNandFlash *mapped, + unsigned short physicalBlock); + +extern unsigned char MappedNandFlash_SaveLogicalMapping( + struct MappedNandFlash *mapped, + unsigned short physicalBlock); + +extern unsigned char MappedNandFlash_EraseAll( + struct MappedNandFlash *mapped, + unsigned char level); + +#endif //#ifndef MAPPEDNANDFLASH_H + diff --git a/memories/nandflash/NandCommon.h b/memories/nandflash/NandCommon.h new file mode 100644 index 0000000..47fefa7 --- /dev/null +++ b/memories/nandflash/NandCommon.h @@ -0,0 +1,134 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +#ifndef NANDCOMMON_H +#define NANDCOMMON_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#if defined(at91sam3u1) || defined(at91sam3u2) || defined(at91sam7se32) +#define NF_MAXPAGESIZE_SUPPORT_2K +#endif + +//------------------------------------------------------------------------------ +/// \page "NandFlash Maximum Supported Values" +/// Since no memory allocation is available, limits have been set on various +/// characteristics of a NandFlash chip: +/// +/// !Maximums +/// - NandCommon_MAXNUMBLOCKS +/// - NandCommon_MAXNUMPAGESPERBLOCK +/// - NandCommon_MAXPAGESIZE + +/// Maximum number of blocks in a device +#define NandCommon_MAXNUMBLOCKS 1024 //2048 + +/// Maximum number of pages in one block +#define NandCommon_MAXNUMPAGESPERBLOCK 256 //64 + +/// Maximum size of the data area of one page, in bytes. +#if !defined(NF_MAXPAGESIZE_SUPPORT_2K) +#define NandCommon_MAXPAGEDATASIZE 4096 //2048 +#else +#define NandCommon_MAXPAGEDATASIZE 2048 +#endif + +/// Maximum size of the spare area of one page, in bytes. +#define NandCommon_MAXPAGESPARESIZE 128 //64 + +/// Maximum number of ecc bytes stored in the spare for one single page. +#define NandCommon_MAXSPAREECCBYTES 48 //24 + +/// Maximum number of extra free bytes inside the spare area of a page. +#define NandCommon_MAXSPAREEXTRABYTES 78 //38 + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "NandFlash Error Codes" +/// NandFlash API methods return either 0 (indicating that there was no error), +/// or one of the following error codes: +/// +/// !Codes +/// - NandCommon_ERROR_NOMOREBLOCKS +/// - NandCommon_ERROR_BLOCKNOTMAPPED +/// - NandCommon_ERROR_OUTOFBOUNDS +/// - NandCommon_ERROR_MAPPINGNOTFOUND +/// - NandCommon_ERROR_CANNOTREAD + +/// No more blocks can be allocated for a write operation. +#define NandCommon_ERROR_NOMOREBLOCKS 1 + +/// The desired logical block has no current physical mapping. +#define NandCommon_ERROR_BLOCKNOTMAPPED 2 + +/// Access if out-of-bounds. +#define NandCommon_ERROR_OUTOFBOUNDS 3 + +/// There are no block having the desired property. +#define NandCommon_ERROR_NOBLOCKFOUND 4 + +/// The nandflash device has no logical mapping information on it. +#define NandCommon_ERROR_MAPPINGNOTFOUND 5 + +/// A read operation cannot be carried out. +#define NandCommon_ERROR_CANNOTREAD 6 + +/// A write operation cannot be carried out. +#define NandCommon_ERROR_CANNOTWRITE 7 + +/// NandFlash chip model cannot be recognized. +#define NandCommon_ERROR_UNKNOWNMODEL 8 + +/// Page data is corrupted according to ECC +#define NandCommon_ERROR_CORRUPTEDDATA 9 + +/// Block is not in the required status. +#define NandCommon_ERROR_WRONGSTATUS 10 + +/// Device has no logical mapping stored in it +#define NandCommon_ERROR_NOMAPPING 11 + +/// The block being accessed is bad and must be replaced +#define NandCommon_ERROR_BADBLOCK 12 + +/// Failed to perform an erase operation +#define NandCommon_ERROR_CANNOTERASE 13 + +/// A hardware copyback operation failed. +#define NandCommon_ERROR_CANNOTCOPY 14 + +/// HW Ecc Not compatible with the Nand Model +#define NandCommon_ERROR_ECC_NOT_COMPATIBLE 15 + +//------------------------------------------------------------------------------ + +#endif //#ifndef NANDCOMMON_H + diff --git a/memories/nandflash/NandFlashModel.c b/memories/nandflash/NandFlashModel.c new file mode 100644 index 0000000..759a4ca --- /dev/null +++ b/memories/nandflash/NandFlashModel.c @@ -0,0 +1,403 @@ +/* ---------------------------------------------------------------------------- + * 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 "NandFlashModel.h" +#include "NandCommon.h" +#if defined(CHIP_NAND_CTRL) +#include +#endif +#include + +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// Get the power of input, given a certain result, i.e. input^(power) = result. +/// returns the value of "power" if succesfully find the power. +/// \param result a certain output we want to calculate. +/// \param input the input of the power. +//------------------------------------------------------------------------------ +#if defined(OP_BOOTSTRAP_on) +unsigned int CALPOW(unsigned int result, unsigned int input) +{ + unsigned int i=0; + + while(i<32) + { + if(result == (input << i)) + return i; + i++; + } + + return 0; +} +#endif + +//------------------------------------------------------------------------------ +/// Get the interger part of input, given a certain result, i.e. return = result / input. +/// returns the value of interger part of the result/input. +/// \param result a certain output we want to calculate. +/// \param input the input of the division. +//------------------------------------------------------------------------------ +#if defined(OP_BOOTSTRAP_on) +unsigned int CALINT(unsigned int result, unsigned int input) +{ + unsigned int i=0; + unsigned int tmpInput=0; + + while(1) + { + tmpInput +=input; + i++; + if(tmpInput == result) + return i; + else if (tmpInput > result) + return (i-1); + } + +} +#endif + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Looks for a NandFlashModel corresponding to the given ID inside a list of +/// model. If found, the model variable is filled with the correct values. +/// This function returns 0 if a matching model has been found; otherwise it +/// returns NandCommon_ERROR_UNKNOWNMODEL. +/// \param modelList List of NandFlashModel instances. +/// \param size Number of models in list. +/// \param chipId Identifier returned by the Nand(id1|(id2<<8)|(id3<<16)|(id4<<24)). +/// \param model NandFlashModel instance to update with the model parameters. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_Find( + const struct NandFlashModel *modelList, + unsigned int size, + unsigned int chipId, + struct NandFlashModel *model) +{ + unsigned char found = 0, id2, id4; + unsigned int i; + #if defined(CHIP_NAND_CTRL) + unsigned char pageSize = 0; + #endif + id2 = (unsigned char)(chipId>>8); + id4 = (unsigned char)(chipId>>24); + + TRACE_INFO("Nandflash ID is 0x%08X\n\r", chipId); + + for(i=0; iblockSizeInKBytes == 0 || model->pageSizeInBytes == 0) { + TRACE_DEBUG("Fetch from ID4(0x%.2x):\r\n", id4); + /// Fetch from the extended ID4 + /// ID4 D5 D4 BlockSize || D1 D0 PageSize + /// 0 0 64K || 0 0 1K + /// 0 1 128K || 0 1 2K + /// 1 0 256K || 1 0 4K + /// 1 1 512K || 1 1 8k + #if !defined(OP_BOOTSTRAP_on) + switch(id4 & 0x03) { + case 0x00: model->pageSizeInBytes = 1024; break; + case 0x01: model->pageSizeInBytes = 2048; break; + case 0x02: model->pageSizeInBytes = 4096; break; + case 0x03: model->pageSizeInBytes = 8192; break; + } + switch(id4 & 0x30) { + case 0x00: model->blockSizeInKBytes = 64; break; + case 0x10: model->blockSizeInKBytes = 128; break; + case 0x20: model->blockSizeInKBytes = 256; break; + case 0x30: model->blockSizeInKBytes = 512; break; + } + #else + model->pageSizeInBytes = 1024 << (id4 & 0x03); + model->blockSizeInKBytes = (64) << ((id4 & 0x30) >>4); + #endif + } + #if defined(CHIP_NAND_CTRL) + switch(model->pageSizeInBytes) { + case 1024: pageSize = AT91C_HSMC4_PAGESIZE_1056_Bytes; break; + case 2048: pageSize = AT91C_HSMC4_PAGESIZE_2112_Bytes; break; + case 4096: pageSize = AT91C_HSMC4_PAGESIZE_4224_Bytes; break; + default: TRACE_ERROR("Unsupportted page size for NAND Flash Controller\n\r"); + } + HSMC4_SetMode(pageSize | AT91C_HSMC4_DTOMUL_1048576 | AT91C_HSMC4_EDGECTRL |AT91C_HSMC4_DTOCYC | AT91C_HSMC4_RSPARE); + #endif + } + TRACE_DEBUG("NAND Model found:\r\n"); + TRACE_DEBUG(" * deviceId = 0x%02X\r\n", model->deviceId); + TRACE_DEBUG(" * deviceSizeInMegaBytes = %d\r\n", model->deviceSizeInMegaBytes); + TRACE_DEBUG(" * blockSizeInkBytes = %d\r\n", model->blockSizeInKBytes); + TRACE_DEBUG(" * pageSizeInBytes = %d\r\n", model->pageSizeInBytes); + TRACE_DEBUG(" * options = 0x%02X\r\n", model->options); + break; + } + } + + // Check if chip has been detected + if (found) { + + return 0; + } + else { + + return NandCommon_ERROR_UNKNOWNMODEL; + } +} + +//------------------------------------------------------------------------------ +/// Translates address/size access of a NandFlashModel to block, page and +/// offset values. The values are stored in the provided variables if their +/// pointer is not 0. +/// Returns 0 if the access is correct; otherwise returns +/// NandCommon_ERROR_OUTOFBOUNDS. +/// \param model Pointer to a NandFlashModel instance. +/// \param address Access address. +/// \param size Access size in bytes. +/// \param block Stores the first accessed block number. +/// \param page Stores the first accessed page number inside the first block. +/// \param offset Stores the byte offset inside the first accessed page. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_TranslateAccess( + const struct NandFlashModel *model, + unsigned int address, + unsigned int size, + unsigned short *block, + unsigned short *page, + unsigned short *offset) +{ + // Check that access is not too big + #if !defined(OP_BOOTSTRAP_on) + if ((address + size) > NandFlashModel_GetDeviceSizeInBytes(model)) { + + TRACE_DEBUG("NandFlashModel_TranslateAccess: out-of-bounds access.\n\r"); + return NandCommon_ERROR_OUTOFBOUNDS; + } + #endif + + // Get Nand info + unsigned int blockSize = NandFlashModel_GetBlockSizeInBytes(model); + unsigned int pageSize = NandFlashModel_GetPageDataSize(model); + + // Translate address + #if !defined(OP_BOOTSTRAP_on) + unsigned short tmpBlock = address / blockSize; + address -= tmpBlock * blockSize; + unsigned short tmpPage = address / pageSize; + address -= tmpPage * pageSize; + unsigned short tmpOffset = address; + #else + unsigned short tmpBlock = CALINT(address, blockSize); + address -= tmpBlock * blockSize; + unsigned short tmpPage = CALINT(address, pageSize); + address -= tmpPage * pageSize; + unsigned short tmpOffset= address; + #endif + + // Save results + if (block) { + + *block = tmpBlock; + } + if (page) { + + *page = tmpPage; + } + if (offset) { + + *offset = tmpOffset; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Returns the spare area placement scheme used by a particular nandflash +/// model. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +const struct NandSpareScheme * NandFlashModel_GetScheme( + const struct NandFlashModel *model) +{ + return model->scheme; +} + +//------------------------------------------------------------------------------ +/// Returns the device ID of a particular NandFlash model. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_GetDeviceId( + const struct NandFlashModel *model) +{ + return model->deviceId; +} + +//------------------------------------------------------------------------------ +/// Returns the number of blocks in the entire device. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned short NandFlashModel_GetDeviceSizeInBlocks( + const struct NandFlashModel *model) +{ + #if !defined(OP_BOOTSTRAP_on) + return ((1024) / model->blockSizeInKBytes) * model->deviceSizeInMegaBytes; + #else + unsigned int pow; + pow = CALPOW((1024 * model->deviceSizeInMegaBytes), model->blockSizeInKBytes); + return (0x1 << pow); + #endif +} + +//------------------------------------------------------------------------------ +/// Returns the number of pages in the entire device. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned int NandFlashModel_GetDeviceSizeInPages( + const struct NandFlashModel *model) +{ + return (unsigned int) NandFlashModel_GetDeviceSizeInBlocks(model) //* 8 // HACK + * NandFlashModel_GetBlockSizeInPages(model); +} + +//------------------------------------------------------------------------------ +/// Returns the size of the whole device in bytes (this does not include the +/// size of the spare zones). +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned long long NandFlashModel_GetDeviceSizeInBytes( + const struct NandFlashModel *model) +{ + return ((unsigned long long) model->deviceSizeInMegaBytes) << 20; +} + +//------------------------------------------------------------------------------ +/// Returns the size of the whole device in Mega bytes (this does not include the +/// size of the spare zones). +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned int NandFlashModel_GetDeviceSizeInMBytes( + const struct NandFlashModel *model) +{ + return ((unsigned int) model->deviceSizeInMegaBytes); +} + + +//------------------------------------------------------------------------------ +/// Returns the number of pages in one single block of a device. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned short NandFlashModel_GetBlockSizeInPages( + const struct NandFlashModel *model) +{ + #if !defined(OP_BOOTSTRAP_on) + return model->blockSizeInKBytes * 1024 / model->pageSizeInBytes; + #else + unsigned int pow; + pow = CALPOW((model->blockSizeInKBytes * 1024), model->pageSizeInBytes); + return (0x1 << pow); + #endif +} + +//------------------------------------------------------------------------------ +/// Returns the size in bytes of one single block of a device. This does not +/// take into account the spare zones size. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned int NandFlashModel_GetBlockSizeInBytes( + const struct NandFlashModel *model) +{ + return (model->blockSizeInKBytes *1024); +} + +//------------------------------------------------------------------------------ +/// Returns the size of the data area of a page in bytes. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned short NandFlashModel_GetPageDataSize( + const struct NandFlashModel *model) +{ + return model->pageSizeInBytes; +} + +//------------------------------------------------------------------------------ +/// Returns the size of the spare area of a page in bytes. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_GetPageSpareSize( + const struct NandFlashModel *model) +{ + return (model->pageSizeInBytes>>5); /// Spare size is 16/512 of data size +} + +//------------------------------------------------------------------------------ +/// Returns the number of bits used by the data bus of a NandFlash device. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_GetDataBusWidth( + const struct NandFlashModel *model) +{ + return (model->options&NandFlashModel_DATABUS16)? 16: 8; +} + +//------------------------------------------------------------------------------ +/// Returns 1 if the given NandFlash model uses the "small blocks/pages" +/// command set; otherwise returns 0. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_HasSmallBlocks( + const struct NandFlashModel *model) +{ + return (model->pageSizeInBytes <= 512 )? 1: 0; +} + +//------------------------------------------------------------------------------ +/// Returns 1 if the device supports the copy-back operation. Otherwise returns +/// 0. +/// \param model Pointer to a NandFlashModel instance. +//------------------------------------------------------------------------------ +unsigned char NandFlashModel_SupportsCopyBack( + const struct NandFlashModel *model) +{ + return ((model->options & NandFlashModel_COPYBACK) != 0); +} diff --git a/memories/nandflash/NandFlashModel.h b/memories/nandflash/NandFlashModel.h new file mode 100644 index 0000000..9c21a45 --- /dev/null +++ b/memories/nandflash/NandFlashModel.h @@ -0,0 +1,169 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Type and methods for manipulating NandFlash models. +/// +/// !Usage +/// +/// -# Find the model of a NandFlash using its device ID with the +/// NandFlashModel_Find function. +/// +/// -# Retrieve parameters of a NandFlash model using the following functions: +/// - NandFlashModel_GetDeviceId +/// - NandFlashModel_GetDeviceSizeInBlocks +/// - NandFlashModel_GetDeviceSizeInPages +/// - NandFlashModel_GetDeviceSizeInBytes +/// - NandFlashModel_GetBlockSizeInPages +/// - NandFlashModel_GetBlockSizeInBytes +/// - NandFlashModel_GetPageDataSize +/// - NandFlashModel_GetPageSpareSize +/// - NandFlashModel_GetDataBusWidth +/// - NandFlashModel_UsesSmallBlocksRead +/// - NandFlashModel_UsesSmallBlocksWrite +//------------------------------------------------------------------------------ + +#ifndef NANDFLASHMODEL_H +#define NANDFLASHMODEL_H + +//------------------------------------------------------------------------------ +// Forward declarations +//------------------------------------------------------------------------------ + +struct NandSpareScheme; + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "NandFlashModel options" +/// This page lists the possible options for a NandFlash chip. +/// +/// !Options +/// - NandFlashModel_DATABUS8 +/// - NandFlashModel_DATABUS16 +/// - NandFlashModel_COPYBACK + +/// Indicates the Nand uses an 8-bit databus. +#define NandFlashModel_DATABUS8 (0 << 0) + +/// Indicates the Nand uses a 16-bit databus. +#define NandFlashModel_DATABUS16 (1 << 0) + +/// The Nand supports the copy-back function (internal page-to-page copy). +#define NandFlashModel_COPYBACK (1 << 1) + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Describes a particular model of NandFlash device. +//------------------------------------------------------------------------------ +struct NandFlashModel { + + /// Identifier for the device. + unsigned char deviceId; + /// Special options for the NandFlash. + unsigned char options; + /// Size of the data area of a page, in bytes. + unsigned short pageSizeInBytes; + /// Size of the device in MB. + unsigned short deviceSizeInMegaBytes; + /// Size of one block in kilobytes. + unsigned short blockSizeInKBytes; + /// Spare area placement scheme + const struct NandSpareScheme *scheme; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char NandFlashModel_Find( + const struct NandFlashModel *modelList, + unsigned int size, + unsigned int id, + struct NandFlashModel *model); + +extern unsigned char NandFlashModel_TranslateAccess( + const struct NandFlashModel *model, + unsigned int address, + unsigned int size, + unsigned short *block, + unsigned short *page, + unsigned short *offset); + +extern const struct NandSpareScheme * NandFlashModel_GetScheme( + const struct NandFlashModel *model); + +extern unsigned char NandFlashModel_GetDeviceId( + const struct NandFlashModel *model); + +extern unsigned short NandFlashModel_GetDeviceSizeInBlocks( + const struct NandFlashModel *model); + +extern unsigned int NandFlashModel_GetDeviceSizeInPages( + const struct NandFlashModel *model); + +extern unsigned long long NandFlashModel_GetDeviceSizeInBytes( + const struct NandFlashModel *model); + +extern unsigned int NandFlashModel_GetDeviceSizeInMBytes( + const struct NandFlashModel *model); + +extern unsigned short NandFlashModel_GetBlockSizeInPages( + const struct NandFlashModel *model); + +extern unsigned int NandFlashModel_GetBlockSizeInBytes( + const struct NandFlashModel *model); + +extern unsigned short NandFlashModel_GetPageDataSize( + const struct NandFlashModel *model); + +extern unsigned char NandFlashModel_GetPageSpareSize( + const struct NandFlashModel *model); + +extern unsigned char NandFlashModel_GetDataBusWidth( + const struct NandFlashModel *model); + +extern unsigned char NandFlashModel_HasSmallBlocks( + const struct NandFlashModel *model); + +extern unsigned char NandFlashModel_SupportsCopyBack( + const struct NandFlashModel *model); + +#endif //#ifndef NANDFLASHMODEL_H + diff --git a/memories/nandflash/NandFlashModelList.c b/memories/nandflash/NandFlashModelList.c new file mode 100644 index 0000000..78b25f6 --- /dev/null +++ b/memories/nandflash/NandFlashModelList.c @@ -0,0 +1,118 @@ +/* ---------------------------------------------------------------------------- + * 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 "NandFlashModelList.h" +#include "NandSpareScheme.h" + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of NandFlash models which can be recognized by the software. +const struct NandFlashModel nandFlashModelList[NandFlashModelList_SIZE] = { + +// | ID | Options | Page | Mo | Block |BlkPg |DevBlk + {0x6e, NandFlashModel_DATABUS8, 256, 1, 4, &nandSpareScheme256}, + {0x64, NandFlashModel_DATABUS8, 256, 2, 4, &nandSpareScheme256}, + {0x6b, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512}, + {0xe8, NandFlashModel_DATABUS8, 256, 1, 4, &nandSpareScheme256}, + {0xec, NandFlashModel_DATABUS8, 256, 1, 4, &nandSpareScheme256}, + {0xea, NandFlashModel_DATABUS8, 256, 2, 4, &nandSpareScheme256}, + {0xd5, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512}, + {0xe3, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512}, + {0xe5, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512}, + {0xd6, NandFlashModel_DATABUS8, 512, 8, 8, &nandSpareScheme512}, + + {0x39, NandFlashModel_DATABUS8, 512, 8, 8, &nandSpareScheme512}, + {0xe6, NandFlashModel_DATABUS8, 512, 8, 8, &nandSpareScheme512}, + {0x49, NandFlashModel_DATABUS16, 512, 8, 8, &nandSpareScheme512}, + {0x59, NandFlashModel_DATABUS16, 512, 8, 8, &nandSpareScheme512}, + + {0x33, NandFlashModel_DATABUS8, 512, 16, 16, &nandSpareScheme512}, + {0x73, NandFlashModel_DATABUS8, 512, 16, 16, &nandSpareScheme512}, + {0x43, NandFlashModel_DATABUS16, 512, 16, 16, &nandSpareScheme512}, + {0x53, NandFlashModel_DATABUS16, 512, 16, 16, &nandSpareScheme512}, + + {0x35, NandFlashModel_DATABUS8, 512, 32, 16, &nandSpareScheme512}, + {0x75, NandFlashModel_DATABUS8, 512, 32, 16, &nandSpareScheme512}, + {0x45, NandFlashModel_DATABUS16, 512, 32, 16, &nandSpareScheme512}, + {0x55, NandFlashModel_DATABUS16, 512, 32, 16, &nandSpareScheme512}, + + {0x36, NandFlashModel_DATABUS8, 512, 64, 16, &nandSpareScheme512}, + {0x76, NandFlashModel_DATABUS8, 512, 64, 16, &nandSpareScheme512}, + {0x46, NandFlashModel_DATABUS16, 512, 64, 16, &nandSpareScheme512}, + {0x56, NandFlashModel_DATABUS16, 512, 64, 16, &nandSpareScheme512}, + + {0x78, NandFlashModel_DATABUS8, 512, 128, 16, &nandSpareScheme512}, + {0x39, NandFlashModel_DATABUS8, 512, 128, 16, &nandSpareScheme512}, + {0x79, NandFlashModel_DATABUS8, 512, 128, 16, &nandSpareScheme512}, + {0x72, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512}, + {0x49, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512}, + {0x74, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512}, + {0x59, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512}, + + {0x71, NandFlashModel_DATABUS8, 512, 256, 16, &nandSpareScheme512}, + +// Large blocks devices. Parameters must be fetched from the extended I +#define OPTIONS NandFlashModel_COPYBACK + + {0xA2, NandFlashModel_DATABUS8 | OPTIONS, 0, 64, 0, &nandSpareScheme2048}, + {0xF2, NandFlashModel_DATABUS8 | OPTIONS, 0, 64, 0, &nandSpareScheme2048}, + {0xB2, NandFlashModel_DATABUS16 | OPTIONS, 0, 64, 0, &nandSpareScheme2048}, + {0xC2, NandFlashModel_DATABUS16 | OPTIONS, 0, 64, 0, &nandSpareScheme2048}, + + {0xA1, NandFlashModel_DATABUS8 | OPTIONS, 0, 128, 0, &nandSpareScheme2048}, + {0xF1, NandFlashModel_DATABUS8 | OPTIONS, 0, 128, 0, &nandSpareScheme2048}, + {0xB1, NandFlashModel_DATABUS16 | OPTIONS, 0, 128, 0, &nandSpareScheme2048}, + {0xC1, NandFlashModel_DATABUS16 | OPTIONS, 0, 128, 0, &nandSpareScheme2048}, + + {0xAA, NandFlashModel_DATABUS8 | OPTIONS, 0, 256, 0, &nandSpareScheme2048}, + {0xDA, NandFlashModel_DATABUS8 | OPTIONS, 0, 256, 0, &nandSpareScheme2048}, + {0xBA, NandFlashModel_DATABUS16 | OPTIONS, 0, 256, 0, &nandSpareScheme2048}, + {0xCA, NandFlashModel_DATABUS16 | OPTIONS, 0, 256, 0, &nandSpareScheme2048}, + + {0xAC, NandFlashModel_DATABUS8 | OPTIONS, 0, 512, 0, &nandSpareScheme2048}, + {0xDC, NandFlashModel_DATABUS8 | OPTIONS, 0, 512, 0, &nandSpareScheme2048}, + {0xBC, NandFlashModel_DATABUS16 | OPTIONS, 0, 512, 0, &nandSpareScheme2048}, + {0xCC, NandFlashModel_DATABUS16 | OPTIONS, 0, 512, 0, &nandSpareScheme2048}, + + {0xA3, NandFlashModel_DATABUS8 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048}, + {0xD3, NandFlashModel_DATABUS8 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048}, + {0xB3, NandFlashModel_DATABUS16 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048}, + {0xC3, NandFlashModel_DATABUS16 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048}, + + {0xA5, NandFlashModel_DATABUS8 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048}, + {0xD5, NandFlashModel_DATABUS8 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048}, + {0xB5, NandFlashModel_DATABUS16 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048}, + {0xC5, NandFlashModel_DATABUS16 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048}, +}; diff --git a/memories/nandflash/NandFlashModelList.h b/memories/nandflash/NandFlashModelList.h new file mode 100644 index 0000000..e451271 --- /dev/null +++ b/memories/nandflash/NandFlashModelList.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Static array of the various NandFlashModels which are supported. +/// +/// !Usage +/// +/// -# Uses the NandFlashModel_Find function to look for a particular model in +/// the nandFlashModelList array. +//------------------------------------------------------------------------------ + +#ifndef NANDFLASHMODELLIST_H +#define NANDFLASHMODELLIST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "NandFlashModel.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Number of NandFlash models inside the list. +#define NandFlashModelList_SIZE 58 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +extern const struct NandFlashModel nandFlashModelList[NandFlashModelList_SIZE]; + +#endif //#ifndef NANDFLASHMODELLIST_H + diff --git a/memories/nandflash/NandSpareScheme.c b/memories/nandflash/NandSpareScheme.c new file mode 100644 index 0000000..a816f9c --- /dev/null +++ b/memories/nandflash/NandSpareScheme.c @@ -0,0 +1,230 @@ +/* ---------------------------------------------------------------------------- + * 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 "NandSpareScheme.h" +#include + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +/// Spare area placement scheme for 256 byte pages. +const struct NandSpareScheme nandSpareScheme256 = { + + // Bad block marker is at position #5 + 5, + // 3 ecc bytes + 3, + // Ecc bytes positions + {0, 1, 2}, + // 4 extra bytes + 4, + // Extra bytes positions + {3, 4, 6, 7} +}; + +/// Spare area placement scheme for 512 byte pages. +const struct NandSpareScheme nandSpareScheme512 = { + + // Bad block marker is at position #5 + 5, + // 6 ecc bytes + 6, + // Ecc bytes positions + {0, 1, 2, 3, 6, 7}, + // 8 extra bytes + 8, + // Extra bytes positions + {8, 9, 10, 11, 12, 13, 14, 15} +}; + +/// Spare area placement scheme for 2048 byte pages. +const struct NandSpareScheme nandSpareScheme2048 = { + + // Bad block marker is at position #0 + 0, + // 24 ecc bytes + 24, + // Ecc bytes positions + {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63}, + // 38 extra bytes + 38, + // Extra bytes positions + { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39} +}; + +/// Spare area placement scheme for 4096 byte pages. +const struct NandSpareScheme nandSpareScheme4096 = { + + // Bad block marker is at position #0 + 0, + // 48 ecc bytes + 48, + // Ecc bytes positions + { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127}, + // 78 extra bytes + 78, + // Extra bytes positions + { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79} +}; + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Reads the bad block marker inside a spare area buffer using the provided +/// scheme. +/// \param scheme Pointer to a NandSpareScheme instance. +/// \param spare Spare area buffer. +/// \param marker Pointer to the variable to store the bad block marker. +//------------------------------------------------------------------------------ +void NandSpareScheme_ReadBadBlockMarker( + const struct NandSpareScheme *scheme, + const unsigned char *spare, + unsigned char *marker) +{ + *marker = spare[scheme->badBlockMarkerPosition]; +} + +//------------------------------------------------------------------------------ +/// Modifies the bad block marker inside a spare area, using the given scheme. +/// \param scheme Pointer to a NandSpareScheme instance. +/// \param spare Spare area buffer. +/// \param marker Bad block marker to write. +//------------------------------------------------------------------------------ +void NandSpareScheme_WriteBadBlockMarker( + const struct NandSpareScheme *scheme, + unsigned char *spare, + unsigned char marker) +{ + spare[scheme->badBlockMarkerPosition] = marker; +} + +//------------------------------------------------------------------------------ +/// Reads ECC information from a spare area using the provided scheme. +/// \param scheme Pointer to a NandSpareScheme instance. +/// \param spare Spare area buffer. +/// \param ecc ECC buffer. +//------------------------------------------------------------------------------ +void NandSpareScheme_ReadEcc( + const struct NandSpareScheme *scheme, + const unsigned char *spare, + unsigned char *ecc) +{ + unsigned int i; + for (i=0; i < scheme->numEccBytes; i++) { + + ecc[i] = spare[scheme->eccBytesPositions[i]]; + } +} + +//------------------------------------------------------------------------------ +/// Writes ECC information in a spare area, using a particular scheme. +/// \param scheme Pointer to a NandSpareScheme instance. +/// \param spare Spare area buffer. +/// \param ecc ECC buffer. +//------------------------------------------------------------------------------ +void NandSpareScheme_WriteEcc( + const struct NandSpareScheme *scheme, + unsigned char *spare, + const unsigned char *ecc) +{ + unsigned int i; + for (i=0; i < scheme->numEccBytes; i++) { + + spare[scheme->eccBytesPositions[i]] = ecc[i]; + } +} + +//------------------------------------------------------------------------------ +/// Reads extra bytes of information from a spare area, using the provided +/// scheme. +/// \param scheme Pointer to a NandSpareScheme instance. +/// \param spare Spare area buffer. +/// \param extra Extra bytes buffer. +/// \param size Number of extra bytes to read. +/// \param offset Index where to read the first extra byte. +//------------------------------------------------------------------------------ +void NandSpareScheme_ReadExtra( + const struct NandSpareScheme *scheme, + const unsigned char *spare, + void *extra, + unsigned char size, + unsigned char offset) +{ + ASSERT((size + offset) < scheme->numExtraBytes, + "NandSpareScheme_ReadExtra: Too many bytes\n\r"); + + unsigned int i; + for (i=0; i < size; i++) { + + ((unsigned char *) extra)[i] = spare[scheme->extraBytesPositions[i+offset]]; + } +} + +//------------------------------------------------------------------------------ +/// Write extra bytes of information inside a spare area, using the provided +/// scheme. +/// \param scheme Pointer to a NandSpareScheme instance. +/// \param spare Spare area buffer. +/// \param extra Extra bytes to write. +/// \param size Number of extra bytes to write. +/// \param offset Index where to write the first extra byte. +//------------------------------------------------------------------------------ +void NandSpareScheme_WriteExtra( + const struct NandSpareScheme *scheme, + unsigned char *spare, + const void *extra, + unsigned char size, + unsigned char offset) +{ + ASSERT((size + offset) < scheme->numExtraBytes, + "NandSpareScheme_WriteExtra: Too many bytes\n\r"); + + unsigned int i; + for (i=0; i < size; i++) { + + spare[scheme->extraBytesPositions[i+offset]] = ((unsigned char *) extra)[i]; + } +} + diff --git a/memories/nandflash/NandSpareScheme.h b/memories/nandflash/NandSpareScheme.h new file mode 100644 index 0000000..8bdb1c6 --- /dev/null +++ b/memories/nandflash/NandSpareScheme.h @@ -0,0 +1,124 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "NandSpareScheme" +/// +/// !!!Purpose +/// +/// NandSpareScheme layer is used to do Nandflash device's spare area operations. It is called by +/// upper layer drivers, such as SkipBlockNandFlash layer. +/// +/// !!!Usage +/// +/// -# NandSpareScheme_WriteBadBlockMarker is used to mark a badblock marker inside a spare +/// area. +/// -# NandSpareScheme_ReadBadBlockMarker is used to readout the marker. +/// -# NandSpareScheme_ReadEcc is used to read out ecc from spare area using the provided +/// spare scheme. +/// -# NandSpareScheme_WriteEcc is used to write ecc to spare area using the provided +/// spare scheme. +/// -# NandSpareScheme_ReadExtra is used to read extra bytes from spare area using the provided +/// spare scheme. +/// -# NandSpareScheme_WriteExtra is used to write extra bytes to spare area using the provided +/// spare scheme. +//------------------------------------------------------------------------------ + + +#ifndef NANDSPARESCHEME_H +#define NANDSPARESCHEME_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "NandCommon.h" + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +struct NandSpareScheme { + + unsigned char badBlockMarkerPosition; + unsigned char numEccBytes; + unsigned char eccBytesPositions[NandCommon_MAXSPAREECCBYTES]; + unsigned char numExtraBytes; + unsigned char extraBytesPositions[NandCommon_MAXSPAREEXTRABYTES]; +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +extern const struct NandSpareScheme nandSpareScheme256; +extern const struct NandSpareScheme nandSpareScheme512; +extern const struct NandSpareScheme nandSpareScheme2048; +extern const struct NandSpareScheme nandSpareScheme4096; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void NandSpareScheme_ReadBadBlockMarker( + const struct NandSpareScheme *scheme, + const unsigned char *spare, + unsigned char *marker); + +extern void NandSpareScheme_WriteBadBlockMarker( + const struct NandSpareScheme *scheme, + unsigned char *spare, + unsigned char marker); + +extern void NandSpareScheme_ReadEcc( + const struct NandSpareScheme *scheme, + const unsigned char *spare, + unsigned char *ecc); + +extern void NandSpareScheme_WriteEcc( + const struct NandSpareScheme *scheme, + unsigned char *spare, + const unsigned char *ecc); + +extern void NandSpareScheme_ReadExtra( + const struct NandSpareScheme *scheme, + const unsigned char *spare, + void *extra, + unsigned char size, + unsigned char offset); + +extern void NandSpareScheme_WriteExtra( + const struct NandSpareScheme *scheme, + unsigned char *spare, + const void *extra, + unsigned char size, + unsigned char offset); + +#endif //#ifndef NANDSPARESCHEME_H + diff --git a/memories/nandflash/NfcRawNandFlash.c b/memories/nandflash/NfcRawNandFlash.c new file mode 100644 index 0000000..6dc015f --- /dev/null +++ b/memories/nandflash/NfcRawNandFlash.c @@ -0,0 +1,871 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ +//#define DMA_TRANSFER + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "RawNandFlash.h" +#include "NandCommon.h" +#include "NandFlashModelList.h" +#include +#include +#include +#include +#include + +#include +#if defined(CHIP_NAND_CTRL) + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +/// Nand flash chip status codes +#define STATUS_READY (1 << 6) +#define STATUS_ERROR (1 << 0) + +/// Nand flash commands +#define COMMAND_READ_1 0x00 +#define COMMAND_READ_2 0x30 +#define COMMAND_COPYBACK_READ_1 0x00 +#define COMMAND_COPYBACK_READ_2 0x35 +#define COMMAND_COPYBACK_PROGRAM_1 0x85 +#define COMMAND_COPYBACK_PROGRAM_2 0x10 +#define COMMAND_RANDOM_OUT 0x05 +#define COMMAND_RANDOM_OUT_2 0xE0 +#define COMMAND_RANDOM_IN 0x85 +#define COMMAND_READID 0x90 +#define COMMAND_WRITE_1 0x80 +#define COMMAND_WRITE_2 0x10 +#define COMMAND_ERASE_1 0x60 +#define COMMAND_ERASE_2 0xD0 +#define COMMAND_STATUS 0x70 +#define COMMAND_RESET 0xFF + +/// Nand flash commands (small blocks) +#define COMMAND_READ_A 0x00 +#define COMMAND_READ_C 0x50 + +/// Using DMA +static unsigned int bNfcDMA = 0; + +//------------------------------------------------------------------------------ +// Internal macros +//------------------------------------------------------------------------------ +#define READ_DATA8(raw) \ + (*((volatile unsigned char *) raw->dataAddress)) +#define READ_DATA16(raw) \ + (*((volatile unsigned short *) raw->dataAddress)) + +/// Internal cast macros +#define MODEL(raw) ((struct NandFlashModel *) raw) + +/// Number of tries for erasing a block +#define NUMERASETRIES 2 +/// Number of tries for writing a block +#define NUMWRITETRIES 2 +/// Number of tries for copying a block +#define NUMCOPYTRIES 2 + + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Translates the given column and row address into first and other (1-4) address +/// cycles. The resulting values are stored in the provided variables if they are not null. +/// \param columnAddress Column address to translate. +/// \param rowAddress Row address to translate. +/// \param pAddressCycle0 First address cycle. +/// \param pAddressCycle1234 four address cycles. +//------------------------------------------------------------------------------ +void NFC_TranslateAddress( + const struct RawNandFlash *raw, + unsigned short columnAddress, + unsigned int rowAddress, + unsigned int *pAddressCycle0, + unsigned int *pAddressCycle1234, + unsigned char useFiveAddress) +{ + unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw)); + unsigned int numPages = NandFlashModel_GetDeviceSizeInPages(MODEL(raw)); + unsigned char numAddressCycles = 0; + unsigned int addressCycle0 = 0; + unsigned int addressCycle1234 = 0; + + // Check the data bus width of the NandFlash + if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) { + // Div 2 is because we address in word and not in byte + columnAddress >>= 1; + } + // When 5 address cycle are used. + if (useFiveAddress) { + + while (pageDataSize > 0) { + if (numAddressCycles == 0) { + addressCycle0 = (columnAddress & 0xFF); + } + else { + addressCycle1234 |= (columnAddress & 0xFF) << ((numAddressCycles - 1) * 8); + } + pageDataSize >>= 8; + columnAddress >>= 8; + numAddressCycles ++; + } + while (numPages > 0) { + if (numAddressCycles == 0) { + addressCycle0 = (rowAddress & 0xFF); + } + else { + addressCycle1234 |= (rowAddress & 0xFF) << ((numAddressCycles - 1) * 8); + } + numPages >>= 8; + rowAddress >>= 8; + numAddressCycles ++; + } + } + // When less than 5 address cycle are used. + else { + while (numPages > 0) { + addressCycle1234 |= (rowAddress & 0xFF) << ((numAddressCycles) * 8); + numPages >>= 8; + rowAddress >>= 8; + numAddressCycles ++; + } + } + // Store values + if (pAddressCycle0) { + *pAddressCycle0 = addressCycle0; + } + if (pAddressCycle1234) { + *pAddressCycle1234 = addressCycle1234; + } + return; +} + + +//------------------------------------------------------------------------------ +/// Return 1 if program or erase operation is completed. +/// and the program or erase operation is completed successfully, otherwise return 0. +/// \param raw Pointer to a RawNandFlash instance. +//------------------------------------------------------------------------------ +static unsigned char IsOperationComplete(const struct RawNandFlash *raw) +{ + unsigned char status; + + HSMC4_SendCommand(AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read data. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_NONE | // No address cycle. + (COMMAND_STATUS << 2), // CMD1 (COMMAND_STATUS). + 0, // Dummy address cylce 1,2,3,4. + 0 // Dummy address cylce 0. + ); + status = READ_DATA8(raw); + if (((status & STATUS_READY) != STATUS_READY) || ((status & STATUS_ERROR) != 0)) { + return 0; + } + return 1; +} + +//------------------------------------------------------------------------------ +/// Sends data to the NandFlash chip from the provided buffer. +/// \param raw Pointer to a RawNandFlash instance. +/// \param buffer Buffer where the data area will be stored. +/// \param sramOffset NFC internal sram start offset. +/// \param size Number of data bytes to send. +//------------------------------------------------------------------------------ +static void CopyDataToNfcInternalSram( + const struct RawNandFlash *raw, + unsigned char *data, + unsigned short sramOffset, + unsigned short size) +{ + if(bNfcDMA){ + unsigned int startSourceAddr; + unsigned int startDestAddr; + // Initialize DMA controller. + DMAD_Initialize(BOARD_NAND_DMA_CHANNEL, 0); + startSourceAddr = (unsigned int)data; + startDestAddr = (unsigned int)(NFC_SRAM_BASE_ADDRESS + sramOffset); + // Configure transfer size and width per transfer. + DMAD_Configure_TransferController(BOARD_NAND_DMA_CHANNEL, size / 4, 2, 2, startSourceAddr, startDestAddr); + // Configure single buffer transfer. + DMAD_Configure_Buffer(BOARD_NAND_DMA_CHANNEL, DMA_TRANSFER_SINGLE, DMA_TRANSFER_SINGLE, 0, 0); + // Start channel 0 transfer. + DMAD_BufferTransfer(BOARD_NAND_DMA_CHANNEL, size / 4, 0 , 1); + + }else { + unsigned char * pBuffer; + unsigned int i; + pBuffer = (unsigned char *)(NFC_SRAM_BASE_ADDRESS + sramOffset); + for (i = 0; i < size; i++) { + *pBuffer++ = *data++; + } + } +} +//------------------------------------------------------------------------------ +/// Sends data to the NandFlash chip from the provided buffer. +/// \param raw Pointer to a RawNandFlash instance. +/// \param data Buffer where the data area will be stored. +/// \param sramOffset NFC internal sram start offset. +/// \param size Number of data bytes to receive. +//------------------------------------------------------------------------------ +static void CopyDataFromNfcInternalSram( + const struct RawNandFlash *raw, + unsigned char *data, + unsigned short sramOffset, + unsigned short size) +{ + if(bNfcDMA){ + + unsigned int startSourceAddr; + unsigned int startDestAddr; + + // Initialize DMA controller. + DMAD_Initialize(BOARD_NAND_DMA_CHANNEL, 0); + + startSourceAddr = (unsigned int)(NFC_SRAM_BASE_ADDRESS + sramOffset); + startDestAddr = (unsigned int)data; + + // Configure transfer size and width per transfer. + DMAD_Configure_TransferController(BOARD_NAND_DMA_CHANNEL, size / 4, 2, 2, startSourceAddr, startDestAddr); + // Configure single buffer transfer. + DMAD_Configure_Buffer(BOARD_NAND_DMA_CHANNEL, DMA_TRANSFER_SINGLE, DMA_TRANSFER_SINGLE, 0, 0); + // Start channel 0 transfer. + DMAD_BufferTransfer(BOARD_NAND_DMA_CHANNEL, size / 4, 0 , 1); + }else { + unsigned char * pBuffer; + unsigned int i; + pBuffer = (unsigned char *)(NFC_SRAM_BASE_ADDRESS + sramOffset); + for (i = 0; i < size; i++) { + *data++ = *pBuffer++; + } + } +} + +//------------------------------------------------------------------------------ +/// Erases the specified block of the device. Returns 0 if the operation was +/// successful; otherwise returns an error code. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the physical block to erase. +//------------------------------------------------------------------------------ +static unsigned char EraseBlock( + const struct RawNandFlash *raw, + unsigned short block) +{ + unsigned char error = 0; + unsigned int rowAddress; + unsigned int addressCycle1234; + + TRACE_DEBUG("EraseBlock(%d)\r\n", block); + + // Calculate address used for erase + rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)); + + NFC_TranslateAddress(raw, 0, rowAddress, 0, &addressCycle1234, 0); + + // Start erase + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read data. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_THREE | // Number of address cycle. + AT91C_HSMC4_VCMD2 | // CMD2 enabled. + (COMMAND_ERASE_2 << 10) | // CMD2 (ERASE CONFIRME). + (COMMAND_ERASE_1 << 2), // CMD1 (ERASE). + addressCycle1234, // Address cylce 1, 2, 3, 4. + 0 // Dummy address cylce 0. + ); + + while( !HSMC4_isReadyBusy() ); + #if !defined (OP_BOOTSTRAP_on) + if (!IsOperationComplete(raw)) { + TRACE_ERROR( + "EraseBlock: Could not erase block %d.\n\r", + block); + error = NandCommon_ERROR_CANNOTERASE; + } + #endif + return error; +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or the spare area of a page on a NandFlash chip. If one +/// of the buffer pointer is 0, the corresponding area is not written. +/// Returns 0 if the write operation is successful; otherwise returns 1. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the block where the page to write resides. +/// \param page Number of the page to write inside the given block. +/// \param data Buffer containing the data area. +/// \param spare Buffer containing the spare area. +//------------------------------------------------------------------------------ +static unsigned char WritePage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + + unsigned char error = 0; + unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw)); + unsigned int spareDataSize = NandFlashModel_GetPageSpareSize(MODEL(raw)); + unsigned int rowAddress; + unsigned int addressCycle0; + unsigned int addressCycle1234; + + TRACE_DEBUG("WritePage(B#%d:P#%d)\r\n", block, page); + + // Calculate physical address of the page + rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page; + /* + if (spare){ + HSMC4_EnableSpareWrite(); + } + else { + HSMC4_DisableSpareWrite(); + } + */ + // Note: special case when ECC parity generation. + // ECC results are available as soon as the counter reaches the end of the main area. + // But when reach PageSize for an example, it could not generate last ECC_PR, The + // workaround enable SPARE_WRITE, whatever real spare area write or not. + HSMC4_EnableSpareWrite(); + + // Write data area if needed + if (data) { + CopyDataToNfcInternalSram(raw, (unsigned char *) data, 0, pageDataSize); + if (spare) { + CopyDataToNfcInternalSram(raw, (unsigned char *) spare, pageDataSize, spareDataSize); + } + NFC_TranslateAddress(raw, 0, rowAddress, &addressCycle0, &addressCycle1234, 1); + } + if (spare && !data) { + CopyDataToNfcInternalSram(raw, (unsigned char *) spare, 0, spareDataSize); + NFC_TranslateAddress(raw, pageDataSize, rowAddress, &addressCycle0, &addressCycle1234, 1); + } + + if (data || spare) { + // Start write operation + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + AT91C_HSMC4_HOST_WR | // Host write data. + AT91C_HSMC4_HOST_EN | // Host is enabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle. + 0 | // CMD2 disabled. + 0 | // CMD2. + (COMMAND_WRITE_1 << 2), // CMD1. + addressCycle1234, // Address cylce 1, 2, 3, 4. + addressCycle0 // Address cylce 0. + ); + while( !HSMC4_TransferComplete()); + + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + 0 | // No data Transfer. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_NONE | // No address cycle. + 0 | // CMD2 disabled. + 0 | // CMD2. + (COMMAND_WRITE_2 << 2), // CMD1. + 0, // Dummy address cylce 1, 2, 3, 4. + 0 // Dummy address cylce 0. + ); + while( !HSMC4_isReadyBusy()); + if (!IsOperationComplete(raw)) { + TRACE_ERROR("WritePage: Failed writing data area.\n\r"); + error = NandCommon_ERROR_CANNOTWRITE; + } + } + HSMC4_DisableSpareWrite(); + return error; +} + + +//------------------------------------------------------------------------------ +/// Copies the data in a page of the NandFlash device to an other page on that +/// same chip. Both pages must have be even or odd; it is not possible to copy +/// and even page to an odd page and vice-versa. +/// Returns 0 if the operation is successful; otherwise returns a +/// NandCommon_ERROR code. +/// \param raw Pointer to a RawNandFlash instance. +/// \param sourceBlock Source block number. +/// \param sourcePage Source page number inside the source block. +/// \param destBlock Destination block number. +/// \param destPage Destination page number inside the destination block. +//------------------------------------------------------------------------------ +static unsigned char CopyPage( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage) +{ + unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw)); + unsigned int sourceRow = sourceBlock * numPages + sourcePage; + unsigned int destRow = destBlock * numPages + destPage; + unsigned char error = 0; + unsigned int addressCycle0; + unsigned int addressCycle1234; + + ASSERT((sourcePage & 1) == (destPage & 1), + "CopyPage: Source and destination page must have the same parity.\n\r"); + + TRACE_DEBUG("CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r", + sourceBlock, sourcePage, destBlock, destPage); + + // Use the copy-back facility if available + if (NandFlashModel_SupportsCopyBack(MODEL(raw))) { + + // Start operation + NFC_TranslateAddress(raw, 0, sourceRow, &addressCycle0, &addressCycle1234, 1); + // Start copy-back read + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read data. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle. + AT91C_HSMC4_VCMD2 | // CMD2 enabled. + (COMMAND_COPYBACK_READ_2 << 10)| // CMD2. + (COMMAND_COPYBACK_READ_1 << 2), // CMD1. + addressCycle1234, // Address cylce 1, 2, 3, 4. + addressCycle0 // Address cylce 0. + ); + while( !HSMC4_isReadyBusy() ); + + // Start copy-back write + NFC_TranslateAddress(raw, 0, destRow, &addressCycle0, &addressCycle1234, 1); + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + 0 | // No data transfer. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle. + AT91C_HSMC4_VCMD2 | // CMD2 enabled. + (COMMAND_COPYBACK_PROGRAM_2 << 10)| // CMD2. + (COMMAND_COPYBACK_PROGRAM_1 << 2), // CMD1. + addressCycle1234, // Address cylce 1, 2, 3, 4. + addressCycle0 // Address cylce 0. + ); + while( !HSMC4_isReadyBusy() ); + + // Check status + if (!IsOperationComplete(raw)) { + TRACE_ERROR("CopyPage: Failed to copy page.\n\r"); + error = NandCommon_ERROR_CANNOTCOPY; + } + } + else { + + // Software copy + unsigned char data[NandCommon_MAXPAGEDATASIZE]; + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + if (RawNandFlash_ReadPage(raw, sourceBlock, sourcePage, data, spare)) { + + TRACE_ERROR("CopyPage: Failed to read page to copy\n\r"); + error = NandCommon_ERROR_CANNOTREAD; + } + else if (RawNandFlash_WritePage(raw, destBlock, destPage, data, spare)) { + + TRACE_ERROR("CopyPage: Failed to write dest. page\n\r"); + error = NandCommon_ERROR_CANNOTWRITE; + } + } + + return error; +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a RawNandFlash instance based on the given model and physical +/// interface. If no model is provided, then the function tries to autodetect +/// it. +/// Returns 0 if initialization is successful; otherwise returns +/// NandCommon_ERROR_UNKNOWNMODEL. +/// \param raw Pointer to a RawNandFlash 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 RawNandFlash_Initialize( + struct RawNandFlash *raw, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy) +{ + TRACE_DEBUG("RawNandFlash_Initialize()\r\n"); + // Initialize fields + raw->commandAddress = commandAddress; + raw->addressAddress = addressAddress; + raw->dataAddress = dataAddress; + raw->pinChipEnable = pinChipEnable; + raw->pinReadyBusy = pinReadyBusy; + + // Reset + RawNandFlash_Reset(raw); + + // If model is not provided, autodetect it + if (!model) { + + TRACE_DEBUG("No model provided, trying autodetection ...\n\r"); + if (NandFlashModel_Find(nandFlashModelList, + NandFlashModelList_SIZE, + RawNandFlash_ReadId(raw), + &(raw->model))) { + + TRACE_ERROR( + "RawNandFlash_Initialize: Could not autodetect chip.\n\r"); + return NandCommon_ERROR_UNKNOWNMODEL; + } + } + else { + + // Copy provided model + raw->model = *model; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Resets a NandFlash device. +/// \param raw Pointer to a RawNandFlash instance. +//------------------------------------------------------------------------------ +void RawNandFlash_Reset(const struct RawNandFlash *raw) +{ + TRACE_DEBUG("RawNandFlash_Reset()\n\r"); + HSMC4_SendCommand(AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read data. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_NONE | // No address Cycle. + (COMMAND_RESET << 2), // CMD1 (COMMAND_RESET). + 0, // Dummy address cylce 1,2,3,4. + 0 // Dummy address cylce 0. + ); + while( !HSMC4_isReadyBusy() ); +} + +//------------------------------------------------------------------------------ +/// Reads and returns the identifiers of a NandFlash chip. +/// \param raw Pointer to a RawNandFlash instance. +/// \return id1|(id2<<8)|(id3<<16)|(id4<<24) +//------------------------------------------------------------------------------ +unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw) +{ + unsigned int chipId; + + TRACE_DEBUG("RawNandFlash_ReadId()\n\r"); + HSMC4_SendCommand(AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read Data. + 0 | // Host is disabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_ONE | // One address Cycle. + (COMMAND_READID << 2), // CMD1 (COMMAND_READID). + 0, // Dummy address cylce 1,2,3,4. + 0 // Dummy address cylce 0. + ); + chipId = READ_DATA8(raw); + chipId |= READ_DATA8(raw) << 8; + chipId |= READ_DATA8(raw) << 16; + chipId |= READ_DATA8(raw) << 24; + return chipId; +} + +//------------------------------------------------------------------------------ +/// Erases the specified block of the device, retrying several time if it fails. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the physical block to erase. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_EraseBlock( + const struct RawNandFlash *raw, + unsigned short block) +{ + #if !defined(OP_BOOTSTRAP_on) + unsigned char numTries = NUMERASETRIES; + + TRACE_DEBUG("RawNandFlash_EraseBlock(B#%d)\n\r", block); + + while (numTries > 0) { + + if (!EraseBlock(raw, block)) { + + return 0; + } + numTries--; + } + + TRACE_ERROR("RawNandFlash_EraseBlock: Failed to erase block after %d tries\n\r", NUMERASETRIES); + return NandCommon_ERROR_BADBLOCK; + #else + return EraseBlock(raw, block); + #endif +} + +//------------------------------------------------------------------------------ +/// Reads the data and/or the spare areas of a page of a NandFlash into the +/// provided buffers. If a buffer pointer is 0, the corresponding area is not +/// read. +/// Returns 0 if the operation has been successful; otherwise returns 1. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the block where the page to read resides. +/// \param page Number of the page to read inside the given block. +/// \param data Buffer where the data area will be stored. +/// \param spare Buffer where the spare area will be stored. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_ReadPage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + volatile unsigned int cntTry = 0; + + unsigned char hasSmallBlocks = NandFlashModel_HasSmallBlocks(MODEL(raw)); + unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw)); + unsigned int pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(raw)); + unsigned int colAddress; + unsigned int rowAddress; + unsigned int addressCycle0; + unsigned int addressCycle1234; + ASSERT(data || spare, "RawNandFlash_ReadPage: At least one area must be read\n\r"); + TRACE_DEBUG("RawNandFlash_ReadPage(B#%d:P#%d)\r\n", block, page); + // Calculate actual address of the page + rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page; + // Start operation + if (data) { + colAddress = 0; + } + else { + // to read spare area in sequential access + colAddress = pageDataSize; + } + + if (spare) { + HSMC4_EnableSpareRead(); + } + else { + HSMC4_DisableSpareRead(); + } + NFC_TranslateAddress(raw, colAddress, rowAddress, &addressCycle0, &addressCycle1234, 1); + // Use either small blocks or large blocks data area read + if (hasSmallBlocks) { + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read data. + AT91C_HSMC4_HOST_EN | // Host is enable. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle. + 0 | // CMD2 disabled. + 0 | // CMD2. + (COMMAND_READ_A << 2), // CMD1. + addressCycle1234, // Address cylce 1, 2, 3, 4. + addressCycle0 // Address cylce 0. + ); + } + else { + HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command. + 0 | // Host read data. + AT91C_HSMC4_HOST_EN | // Host is enabled. + AT91C_HSMC4_CSID_1 | // CSID. + AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle. + AT91C_HSMC4_VCMD2 | // CMD2 enabled. + (COMMAND_READ_2 << 10)| // CMD2. + (COMMAND_READ_1 << 2), // CMD1. + addressCycle1234, // Address cylce 1, 2, 3, 4. + addressCycle0 // Address cylce 0. + ); + } + // Wait for the nand to be ready + cntTry = 0; + while( !HSMC4_isReadyBusy() && (cntTry++) < 1000000); + cntTry = 0; + while( !HSMC4_TransferComplete() && (cntTry++) < 1000000); + // Read data area if needed + if (data) { + CopyDataFromNfcInternalSram(raw, (unsigned char *) data, 0, pageDataSize); + if (spare) { + CopyDataFromNfcInternalSram(raw, (unsigned char *) spare, pageDataSize, pageSpareSize); + } + } + else { + // Read spare area only + CopyDataFromNfcInternalSram(raw, (unsigned char *) spare, 0, pageSpareSize); + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or the spare area of a page on a NandFlash chip. If one +/// of the buffer pointer is 0, the corresponding area is not written. Retries +/// several time if there is an error. +/// Returns 0 if the write operation is successful; otherwise returns +/// NandCommon_ERROR_BADBLOCK. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the block where the page to write resides. +/// \param page Number of the page to write inside the given block. +/// \param data Buffer containing the data area. +/// \param spare Buffer containing the spare area. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_WritePage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + unsigned char numTries = NUMWRITETRIES; + + TRACE_DEBUG("RawNandFlash_WritePage(B#%d:P#%d)\r\n", block, page); + + while (numTries > 0) { + + if (!WritePage(raw, block, page, data, spare)) { + + return 0; + } + numTries--; + } + + TRACE_ERROR("RawNandFlash_WritePage: Failed to write page after %d tries\n\r", NUMWRITETRIES); + return NandCommon_ERROR_BADBLOCK; +} + +//------------------------------------------------------------------------------ +/// Copy the data in a page of the NandFlash device to an other page on that +/// same chip. Both pages must have be even or odd; it is not possible to copy +/// and even page to an odd page and vice-versa. Several retries are attempted +/// if errors are encountered. +/// Returns 0 if the operation is successful; otherwise returns +/// NandCommon_ERROR_BADBLOCK indicating that the destination block is bad. +/// \param raw Pointer to a RawNandFlash instance. +/// \param sourceBlock Source block number. +/// \param sourcePage Source page number inside the source block. +/// \param destBlock Destination block number. +/// \param destPage Destination page number inside the destination block. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_CopyPage( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage) +{ + unsigned char numTries = NUMCOPYTRIES; + + TRACE_DEBUG("RawNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r", + sourceBlock, sourcePage, destBlock, destPage); + + while (numTries) { + + if (!CopyPage(raw, sourceBlock, sourcePage, destBlock, destPage)) { + + return 0; + } + numTries--; + } + + TRACE_ERROR("RawNandFlash_CopyPage: Failed to copy page after %d tries\n\r", NUMCOPYTRIES); + return NandCommon_ERROR_BADBLOCK; +} + +//------------------------------------------------------------------------------ +/// Copies the data of one whole block of a NandFlash device to another block. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK. +/// \param raw Pointer to a RawNandFlash instance. +/// \param sourceBlock Source block number. +/// \param destBlock Destination block number. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_CopyBlock( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short destBlock) +{ + unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw)); + unsigned int i; + + ASSERT(sourceBlock != destBlock, + "RawNandFlash_CopyBlock: Source block must be different from dest block\n\r"); + TRACE_DEBUG("RawNandFlash_CopyBlock(B#%d->B#%d)\n\r", + sourceBlock, destBlock); + + // Copy all pages + for (i=0; i < numPages; i++) { + + if (RawNandFlash_CopyPage(raw, sourceBlock, i, destBlock, i)) { + + TRACE_ERROR( + "RawNandFlash_CopyBlock: Failed to copy page %u\n\r", + i); + return NandCommon_ERROR_BADBLOCK; + } + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Set use DMA flag. +//------------------------------------------------------------------------------ +void RawNandlfash_SetDma(void) +{ + bNfcDMA = 1; +} + +//------------------------------------------------------------------------------ +/// Clear use DMA flag. +//------------------------------------------------------------------------------ +void RawNandlfash_ClearDma(void) +{ + bNfcDMA = 0; +} + +//------------------------------------------------------------------------------ +/// Get use DMA flag. +//------------------------------------------------------------------------------ +unsigned char RawNandlfash_GetDma(void) +{ + return bNfcDMA; +} + +#endif + diff --git a/memories/nandflash/RawNandFlash.c b/memories/nandflash/RawNandFlash.c new file mode 100644 index 0000000..74105ce --- /dev/null +++ b/memories/nandflash/RawNandFlash.c @@ -0,0 +1,792 @@ +/* ---------------------------------------------------------------------------- + * 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 "RawNandFlash.h" +#include "NandCommon.h" +#include "NandFlashModelList.h" +#include +#include + +#include + +#if !defined(CHIP_NAND_CTRL) +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +/// Nand flash chip status codes +#define STATUS_READY (1 << 6) +#define STATUS_ERROR (1 << 0) + +/// Nand flash commands +#define COMMAND_READ_1 0x00 +#define COMMAND_READ_2 0x30 +#define COMMAND_COPYBACK_READ_1 0x00 +#define COMMAND_COPYBACK_READ_2 0x35 +#define COMMAND_COPYBACK_PROGRAM_1 0x85 +#define COMMAND_COPYBACK_PROGRAM_2 0x10 +#define COMMAND_RANDOM_OUT 0x05 +#define COMMAND_RANDOM_OUT_2 0xE0 +#define COMMAND_RANDOM_IN 0x85 +#define COMMAND_READID 0x90 +#define COMMAND_WRITE_1 0x80 +#define COMMAND_WRITE_2 0x10 +#define COMMAND_ERASE_1 0x60 +#define COMMAND_ERASE_2 0xD0 +#define COMMAND_STATUS 0x70 +#define COMMAND_RESET 0xFF + + +/// Nand flash commands (small blocks) +#define COMMAND_READ_A 0x00 +#define COMMAND_READ_C 0x50 + +//------------------------------------------------------------------------------ +// Internal macros +//------------------------------------------------------------------------------ +#define ENABLE_CE(raw) PIO_Clear(&(raw->pinChipEnable)) +#define DISABLE_CE(raw) PIO_Set(&(raw->pinChipEnable)) + +#define WRITE_COMMAND(raw, command) \ + {*((volatile unsigned char *) raw->commandAddress) = (unsigned char) command;} +#define WRITE_COMMAND16(raw, command) \ + {*((volatile unsigned short *) raw->commandAddress) = (unsigned short) command;} +#define WRITE_ADDRESS(raw, address) \ + {*((volatile unsigned char *) raw->addressAddress) = (unsigned char) address;} +#define WRITE_ADDRESS16(raw, address) \ + {*((volatile unsigned short *) raw->addressAddress) = (unsigned short) address;} +#define WRITE_DATA8(raw, data) \ + {*((volatile unsigned char *) raw->dataAddress) = (unsigned char) data;} +#define READ_DATA8(raw) \ + (*((volatile unsigned char *) raw->dataAddress)) +#define WRITE_DATA16(raw, data) \ + {*((volatile unsigned short *) raw->dataAddress) = (unsigned short) data;} +#define READ_DATA16(raw) \ + (*((volatile unsigned short *) raw->dataAddress)) + +/// Internal cast macros +#define MODEL(raw) ((struct NandFlashModel *) raw) + +/// Number of tries for erasing a block +#define NUMERASETRIES 2 +/// Number of tries for writing a block +#define NUMWRITETRIES 2 +/// Number of tries for copying a block +#define NUMCOPYTRIES 2 + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Sends the column address to the NandFlash chip. +/// \param raw Pointer to a RawNandFlash instance. +/// \param columnAddress Column address to send. +//------------------------------------------------------------------------------ +static void WriteColumnAddress( + const struct RawNandFlash *raw, + unsigned short columnAddress) +{ + unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw)); + + /* Check the data bus width of the NandFlash */ + if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) { + /* Div 2 is because we address in word and not in byte */ + columnAddress >>= 1; + } + /* Send single column address byte for small block devices, or two column address bytes for large block devices*/ + while (pageDataSize > 2) { + + if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) { + WRITE_ADDRESS16(raw, columnAddress & 0xFF); + } + else { + WRITE_ADDRESS(raw, columnAddress & 0xFF); + } + pageDataSize >>= 8; + columnAddress >>= 8; + } +} + +//------------------------------------------------------------------------------ +/// Sends the row address to the NandFlash chip. +/// \param raw Pointer to a RawNandFlash instance. +/// \param rowAddress Row address to send. +//------------------------------------------------------------------------------ +static void WriteRowAddress( + const struct RawNandFlash *raw, + unsigned int rowAddress) +{ + unsigned int numPages = NandFlashModel_GetDeviceSizeInPages(MODEL(raw)); + + while (numPages > 0) { + + if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) { + WRITE_ADDRESS16(raw, rowAddress & 0xFF); + } + else { + WRITE_ADDRESS(raw, rowAddress & 0xFF); + } + numPages >>= 8; + rowAddress >>= 8; + } +} + +//------------------------------------------------------------------------------ +/// Waiting for the completion of a page program, erase and random read completion. +/// \param raw Pointer to a RawNandFlash instance. +//------------------------------------------------------------------------------ +static void WaitReady(const struct RawNandFlash *raw) +{ + if (raw->pinReadyBusy.mask) { + while (!PIO_Get(&(raw->pinReadyBusy))); + } + else { + WRITE_COMMAND(raw, COMMAND_STATUS); + while ((READ_DATA8(raw) & STATUS_READY) != STATUS_READY); + } +} + +//------------------------------------------------------------------------------ +/// Return 1 if program or erase operation is completed. +/// and the program or erase operation is completed successfully, otherwise return 0. +/// \param raw Pointer to a RawNandFlash instance. +//------------------------------------------------------------------------------ +static unsigned char IsOperationComplete(const struct RawNandFlash *raw) +{ + unsigned char status; + + WRITE_COMMAND(raw, COMMAND_STATUS); + + status = READ_DATA8(raw); + + if (((status & STATUS_READY) != STATUS_READY) || ((status & STATUS_ERROR) != 0)) { + return 0; + } + return 1; +} + +//------------------------------------------------------------------------------ +/// Sends data to the NandFlash chip from the provided buffer. +/// \param raw Pointer to a RawNandFlash instance. +/// \param buffer Buffer where the data is stored. +/// \param size Number of bytes that will be written +//------------------------------------------------------------------------------ +static void WriteData( + const struct RawNandFlash *raw, + unsigned char *buffer, + unsigned int size) +{ + unsigned int i; + + // Check the data bus width of the NandFlash + if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) { + + unsigned short *buffer16 = (unsigned short *) buffer; + size >>= 1; + + for(i=0; i < size; i++) { + + WRITE_DATA16(raw, buffer16[i]); + } + } + else { + + for(i=0; i < size; i++) { + + WRITE_DATA8(raw, buffer[i]); + } + } +} + +//------------------------------------------------------------------------------ +/// Reads data from the NandFlash chip into the provided buffer. +/// \param nand Pointer to a RawNandFlash instance. +/// \param buffer Buffer where the data will be stored. +/// \param size Number of bytes that will be read +//------------------------------------------------------------------------------ +static void ReadData( + const struct RawNandFlash *raw, + unsigned char *buffer, + unsigned int size) +{ + unsigned int i; + + // Check the chip data bus width + if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) { + + unsigned short *buffer16 = (unsigned short *) buffer; + size >>= 1; + + for (i=0; i < size; i++) { + + buffer16[i] = READ_DATA16(raw); + } + } + else { + + for (i=0; i < size; i++) { + + buffer[i] = READ_DATA8(raw); + } + } +} + +//------------------------------------------------------------------------------ +/// Erases the specified block of the device. Returns 0 if the operation was +/// successful; otherwise returns an error code. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the physical block to erase. +//------------------------------------------------------------------------------ +static unsigned char EraseBlock( + const struct RawNandFlash *raw, + unsigned short block) +{ + unsigned char error = 0; + unsigned int rowAddress; + + TRACE_DEBUG("EraseBlock(%d)\r\n", block); + + // Calculate address used for erase + rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)); + + // Start erase + ENABLE_CE(raw); + WRITE_COMMAND(raw, COMMAND_ERASE_1); + WriteRowAddress(raw, rowAddress); + WRITE_COMMAND(raw, COMMAND_ERASE_2); + + WaitReady(raw); + #if !defined (OP_BOOTSTRAP_on) + if (!IsOperationComplete(raw)) { + TRACE_ERROR( + "EraseBlock: Could not erase block %d.\n\r", + block); + error = NandCommon_ERROR_CANNOTERASE; + } + #endif + + DISABLE_CE(raw); + + return error; +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or the spare area of a page on a NandFlash chip. If one +/// of the buffer pointer is 0, the corresponding area is not written. +/// Returns 0 if the write operation is successful; otherwise returns 1. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the block where the page to write resides. +/// \param page Number of the page to write inside the given block. +/// \param data Buffer containing the data area. +/// \param spare Buffer containing the spare area. +//------------------------------------------------------------------------------ +static unsigned char WritePage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + unsigned char error = 0; + unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw)); + unsigned int spareDataSize = NandFlashModel_GetPageSpareSize(MODEL(raw)); + unsigned short dummyByte; + unsigned int rowAddress; + + TRACE_DEBUG("WritePage(B#%d:P#%d)\r\n", block, page); + // Calculate physical address of the page + rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page; + + // Start write operation + ENABLE_CE(raw); + + // Write data area if needed + if (data) { + + WRITE_COMMAND(raw, COMMAND_WRITE_1); + WriteColumnAddress(raw, 0); + WriteRowAddress(raw, rowAddress); + WriteData(raw, (unsigned char *) data, pageDataSize); + + // Spare is written here as well since it is more efficient + if (spare) { + + WriteData(raw, (unsigned char *) spare, spareDataSize); + } + else { + // Note: special case when ECC parity generation. + // ECC results are available as soon as the counter reaches the end of the main area. + // But when reach PageSize for an example, it could not generate last ECC_PR, The + // workaround is to receive PageSize+1 word. + ReadData(raw, (unsigned char *) (&dummyByte), 2); + } + WRITE_COMMAND(raw, COMMAND_WRITE_2); + + WaitReady(raw); + if (!IsOperationComplete(raw)) { + TRACE_ERROR("WritePage: Failed writing data area.\n\r"); + error = NandCommon_ERROR_CANNOTWRITE; + } + } + + // Write spare area alone if needed + if (spare && !data) { + + WRITE_COMMAND(raw, COMMAND_WRITE_1); + WriteColumnAddress(raw, pageDataSize); + WriteRowAddress(raw, rowAddress); + WriteData(raw, (unsigned char *) spare, spareDataSize); + WRITE_COMMAND(raw, COMMAND_WRITE_2); + + WaitReady(raw); + if (!IsOperationComplete(raw)) { + TRACE_ERROR("WritePage: Failed writing data area.\n\r"); + error = NandCommon_ERROR_CANNOTWRITE; + } + } + + // Disable chip + DISABLE_CE(raw); + + return error; +} + + +//------------------------------------------------------------------------------ +/// Copies the data in a page of the NandFlash device to an other page on that +/// same chip. Both pages must have be even or odd; it is not possible to copy +/// and even page to an odd page and vice-versa. +/// Returns 0 if the operation is successful; otherwise returns a +/// NandCommon_ERROR code. +/// \param raw Pointer to a RawNandFlash instance. +/// \param sourceBlock Source block number. +/// \param sourcePage Source page number inside the source block. +/// \param destBlock Destination block number. +/// \param destPage Destination page number inside the destination block. +//------------------------------------------------------------------------------ +static unsigned char CopyPage( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage) +{ + unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw)); + unsigned int sourceRow = sourceBlock * numPages + sourcePage; + unsigned int destRow = destBlock * numPages + destPage; + unsigned char error = 0; + + ASSERT((sourcePage & 1) == (destPage & 1), + "CopyPage: Source and destination page must have the same parity.\n\r"); + + TRACE_DEBUG("CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r", + sourceBlock, sourcePage, destBlock, destPage); + + // Use the copy-back facility if available + if (NandFlashModel_SupportsCopyBack(MODEL(raw))) { + + // Start operation + ENABLE_CE(raw); + + // Start copy-back read + WRITE_COMMAND(raw, COMMAND_COPYBACK_READ_1); + WriteColumnAddress(raw, 0); + WriteRowAddress(raw, sourceRow); + WRITE_COMMAND(raw, COMMAND_COPYBACK_READ_2); + WaitReady(raw); + + // Start copy-back write + WRITE_COMMAND(raw, COMMAND_COPYBACK_PROGRAM_1); + WriteColumnAddress(raw, 0); + WriteRowAddress(raw, destRow); + WRITE_COMMAND(raw, COMMAND_COPYBACK_PROGRAM_2); + WaitReady(raw); + + // Check status + if (!IsOperationComplete(raw)) { + TRACE_ERROR("CopyPage: Failed to copy page.\n\r"); + error = NandCommon_ERROR_CANNOTCOPY; + } + + // Finish operation + DISABLE_CE(raw); + } + else { + + // Software copy + unsigned char data[NandCommon_MAXPAGEDATASIZE]; + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + if (RawNandFlash_ReadPage(raw, sourceBlock, sourcePage, data, spare)) { + + TRACE_ERROR("CopyPage: Failed to read page to copy\n\r"); + error = NandCommon_ERROR_CANNOTREAD; + } + else if (RawNandFlash_WritePage(raw, destBlock, destPage, data, spare)) { + + TRACE_ERROR("CopyPage: Failed to write dest. page\n\r"); + error = NandCommon_ERROR_CANNOTWRITE; + } + } + + return error; +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a RawNandFlash instance based on the given model and physical +/// interface. If no model is provided, then the function tries to autodetect +/// it. +/// Returns 0 if initialization is successful; otherwise returns +/// NandCommon_ERROR_UNKNOWNMODEL. +/// \param raw Pointer to a RawNandFlash 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 RawNandFlash_Initialize( + struct RawNandFlash *raw, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy) +{ + TRACE_DEBUG("RawNandFlash_Initialize()\n\r"); + + // Initialize fields + raw->commandAddress = commandAddress; + raw->addressAddress = addressAddress; + raw->dataAddress = dataAddress; + raw->pinChipEnable = pinChipEnable; + raw->pinReadyBusy = pinReadyBusy; + + // Reset + RawNandFlash_Reset(raw); + + // If model is not provided, autodetect it + if (!model) { + + TRACE_DEBUG("No model provided, trying autodetection ...\n\r"); + if (NandFlashModel_Find(nandFlashModelList, + NandFlashModelList_SIZE, + RawNandFlash_ReadId(raw), + &(raw->model))) { + + TRACE_ERROR( + "RawNandFlash_Initialize: Could not autodetect chip.\n\r"); + return NandCommon_ERROR_UNKNOWNMODEL; + } + } + else { + + // Copy provided model + raw->model = *model; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Resets a NandFlash device. +/// \param raw Pointer to a RawNandFlash instance. +//------------------------------------------------------------------------------ +void RawNandFlash_Reset(const struct RawNandFlash *raw) +{ + TRACE_DEBUG("RawNandFlash_Reset()\n\r"); + + ENABLE_CE(raw); + WRITE_COMMAND16(raw, COMMAND_RESET); + WaitReady(raw); + DISABLE_CE(raw); +} + +//------------------------------------------------------------------------------ +/// Reads and returns the identifiers of a NandFlash chip. +/// \param raw Pointer to a RawNandFlash instance. +/// \return id1|(id2<<8)|(id3<<16)|(id4<<24) +//------------------------------------------------------------------------------ +unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw) +{ + unsigned int chipId; + + TRACE_DEBUG("RawNandFlash_ReadId()\n\r"); + + ENABLE_CE(raw); + WRITE_COMMAND16(raw, COMMAND_READID); + //WRITE_COMMAND(raw, COMMAND_READID); + WRITE_ADDRESS(raw, 0); + chipId = READ_DATA8(raw); + chipId |= READ_DATA8(raw) << 8; + chipId |= READ_DATA8(raw) << 16; + chipId |= READ_DATA8(raw) << 24; + DISABLE_CE(raw); + + return chipId; +} + +//------------------------------------------------------------------------------ +/// Erases the specified block of the device, retrying several time if it fails. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the physical block to erase. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_EraseBlock( + const struct RawNandFlash *raw, + unsigned short block) +{ + #if !defined(OP_BOOTSTRAP_on) + unsigned char numTries = NUMERASETRIES; + + TRACE_DEBUG("RawNandFlash_EraseBlock(B#%d)\n\r", block); + + while (numTries > 0) { + + if (!EraseBlock(raw, block)) { + + return 0; + } + numTries--; + } + + TRACE_ERROR("RawNandFlash_EraseBlock: Failed to erase %d after %d tries\n\r", + block, NUMERASETRIES); + return NandCommon_ERROR_BADBLOCK; + #else + return EraseBlock(raw, block); + #endif +} + +//------------------------------------------------------------------------------ +/// Reads the data and/or the spare areas of a page of a NandFlash into the +/// provided buffers. If a buffer pointer is 0, the corresponding area is not +/// read. +/// Returns 0 if the operation has been successful; otherwise returns 1. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the block where the page to read resides. +/// \param page Number of the page to read inside the given block. +/// \param data Buffer where the data area will be stored. +/// \param spare Buffer where the spare area will be stored. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_ReadPage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + unsigned char hasSmallBlocks = NandFlashModel_HasSmallBlocks(MODEL(raw)); + unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw)); + unsigned int pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(raw)); + unsigned int colAddress; + unsigned int rowAddress; + + ASSERT(data || spare, "RawNandFlash_ReadPage: At least one area must be read\n\r"); + // Shorten the time handling the debug message + TRACE_DEBUG("RdPg(B#%d:P#%d)\r\n", block, page); + //TRACE_DEBUG("RawNandFlash_ReadPage(B#%d:P#%d)\r\n", block, page); + + // Calculate actual address of the page + rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page; + + // Start operation + ENABLE_CE(raw); + + if (data) { + colAddress = 0; + } + else { + // to read spare area in sequential access + colAddress = pageDataSize; + } + + // Use either small blocks or large blocks data area read + if (hasSmallBlocks) { + if(colAddress == 0) { + WRITE_COMMAND(raw, COMMAND_READ_A); + } + else if(colAddress == pageDataSize) { + WRITE_COMMAND(raw, COMMAND_READ_C); + } + WriteColumnAddress(raw, colAddress); + WriteRowAddress(raw, rowAddress); + } + else { + + WRITE_COMMAND(raw, COMMAND_READ_1); + WriteColumnAddress(raw, colAddress); + WriteRowAddress(raw, rowAddress); + WRITE_COMMAND(raw, COMMAND_READ_2); + } + + // Wait for the nand to be ready + WaitReady(raw); + + // Read data area if needed + if (data) { + WRITE_COMMAND(raw, COMMAND_READ_1); + ReadData(raw, (unsigned char *) data, pageDataSize); + + if (spare) { + ReadData(raw, (unsigned char *) spare, pageSpareSize); + } + } + else { + // Read spare area only + WRITE_COMMAND(raw, COMMAND_READ_1); + ReadData(raw, (unsigned char *) spare, pageSpareSize); + } + + // Disable CE + DISABLE_CE(raw); + + return 0; +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or the spare area of a page on a NandFlash chip. If one +/// of the buffer pointer is 0, the corresponding area is not written. Retries +/// several time if there is an error. +/// Returns 0 if the write operation is successful; otherwise returns +/// NandCommon_ERROR_BADBLOCK. +/// \param raw Pointer to a RawNandFlash instance. +/// \param block Number of the block where the page to write resides. +/// \param page Number of the page to write inside the given block. +/// \param data Buffer containing the data area. +/// \param spare Buffer containing the spare area. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_WritePage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + unsigned char numTries = NUMWRITETRIES; + + TRACE_DEBUG("RawNandFlash_WritePage(B#%d:P#%d)\r\n", block, page); + + while (numTries > 0) { + + if (!WritePage(raw, block, page, data, spare)) { + + return 0; + } + numTries--; + } + + TRACE_ERROR("RawNandFlash_WritePage: Failed to write page after %d tries\n\r", NUMWRITETRIES); + return NandCommon_ERROR_BADBLOCK; +} + +//------------------------------------------------------------------------------ +/// Copy the data in a page of the NandFlash device to an other page on that +/// same chip. Both pages must have be even or odd; it is not possible to copy +/// and even page to an odd page and vice-versa. Several retries are attempted +/// if errors are encountered. +/// Returns 0 if the operation is successful; otherwise returns +/// NandCommon_ERROR_BADBLOCK indicating that the destination block is bad. +/// \param raw Pointer to a RawNandFlash instance. +/// \param sourceBlock Source block number. +/// \param sourcePage Source page number inside the source block. +/// \param destBlock Destination block number. +/// \param destPage Destination page number inside the destination block. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_CopyPage( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage) +{ + unsigned char numTries = NUMCOPYTRIES; + + TRACE_DEBUG("RawNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r", + sourceBlock, sourcePage, destBlock, destPage); + + while (numTries) { + + if (!CopyPage(raw, sourceBlock, sourcePage, destBlock, destPage)) { + + return 0; + } + numTries--; + } + + TRACE_ERROR("RawNandFlash_CopyPage: Failed to copy page after %d tries\n\r", NUMCOPYTRIES); + return NandCommon_ERROR_BADBLOCK; +} + +//------------------------------------------------------------------------------ +/// Copies the data of one whole block of a NandFlash device to another block. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK. +/// \param raw Pointer to a RawNandFlash instance. +/// \param sourceBlock Source block number. +/// \param destBlock Destination block number. +//------------------------------------------------------------------------------ +unsigned char RawNandFlash_CopyBlock( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short destBlock) +{ + unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw)); + unsigned int i; + + ASSERT(sourceBlock != destBlock, + "RawNandFlash_CopyBlock: Source block must be different from dest block\n\r"); + TRACE_DEBUG("RawNandFlash_CopyBlock(B#%d->B#%d)\n\r", + sourceBlock, destBlock); + + // Copy all pages + for (i=0; i < numPages; i++) { + + if (RawNandFlash_CopyPage(raw, sourceBlock, i, destBlock, i)) { + + TRACE_ERROR( + "RawNandFlash_CopyBlock: Failed to copy page %u\n\r", + i); + return NandCommon_ERROR_BADBLOCK; + } + } + + return 0; +} + +#endif diff --git a/memories/nandflash/RawNandFlash.h b/memories/nandflash/RawNandFlash.h new file mode 100644 index 0000000..64a48dd --- /dev/null +++ b/memories/nandflash/RawNandFlash.h @@ -0,0 +1,139 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "RawNandflash" +/// +/// !!!Purpose +/// +/// RawNandflash is a bl Nandflash driver, it directly interacts with hardware's register to +/// operate Nandflash interface, and it is called by upper layer drivers, such as EccNandFlash +/// +/// !!!Usage +/// +/// -# RawNandFlash_Initialize is used to initializes a RawNandFlash instance based on the given +/// model and physical interface. If no model is provided, then the function tries to autodetect +/// it. +/// -# RawNandFlash_Reset is used to reset a Nandflash device. +/// -# RawNandFlash_ReadId is used to read a Nandflash's id. +/// -# RawNandFlash_EraseBlock is used to erase a certain Nandflash device's block. +/// -# RawNandFlash_ReadPage and RawNandFlash_WritePage is used to do read/write operation. +/// -# RawNandFlash_CopyPage is used to issue copypage command to Nandflash device. +/// -# RawNandFlash_CopyBlock calls RawNandFlash_CopyPage to do a Nandflash block copy. +//------------------------------------------------------------------------------ + + +#ifndef RAWNANDFLASH_H +#define RAWNANDFLASH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "NandFlashModel.h" +#include + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Describes a physical NandFlash chip connected to the SAM microcontroller. +//------------------------------------------------------------------------------ +struct RawNandFlash { + + /// Model describing this NandFlash characteristics. + struct NandFlashModel model; + /// Address for sending commands to the NandFlash. + unsigned int commandAddress; + /// Address for sending addresses to the NandFlash + unsigned int addressAddress; + /// Address for sending data to the NandFlash. + unsigned int dataAddress; + /// Pin used to enable the NandFlash chip. + Pin pinChipEnable; + /// Pin used to monitor the ready/busy signal from the NandFlash. + Pin pinReadyBusy; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char RawNandFlash_Initialize( + struct RawNandFlash *raw, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy); + +extern void RawNandFlash_Reset(const struct RawNandFlash *raw); + +extern unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw); + +extern unsigned char RawNandFlash_EraseBlock( + const struct RawNandFlash *raw, + unsigned short block); + +extern unsigned char RawNandFlash_ReadPage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char RawNandFlash_WritePage( + const struct RawNandFlash *raw, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char RawNandFlash_CopyPage( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short sourcePage, + unsigned short destBlock, + unsigned short destPage); + +extern unsigned char RawNandFlash_CopyBlock( + const struct RawNandFlash *raw, + unsigned short sourceBlock, + unsigned short destBlock); + +#if defined(CHIP_NAND_CTRL) +extern void RawNandlfash_SetDma(void); +extern void RawNandlfash_ClearDma(void); +extern unsigned char RawNandlfash_GetDma(void); +#endif + +#endif //#ifndef RAWNANDFLASH_H + diff --git a/memories/nandflash/SkipBlockNandFlash.c b/memories/nandflash/SkipBlockNandFlash.c new file mode 100644 index 0000000..a29795f --- /dev/null +++ b/memories/nandflash/SkipBlockNandFlash.c @@ -0,0 +1,444 @@ +/* ---------------------------------------------------------------------------- + * 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 "SkipBlockNandFlash.h" +#include "NandSpareScheme.h" +#include "NandFlashModel.h" +#include "RawNandFlash.h" +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +// Casts +#define ECC(skipBlock) ((struct EccNandFlash *) skipBlock) +#define RAW(skipBlock) ((struct RawNandFlash *) skipBlock) +#define MODEL(skipBlock) ((struct NandFlashModel *) skipBlock) + + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// 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 skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of block to check. +//------------------------------------------------------------------------------ +unsigned char SkipBlockNandFlash_CheckBlock( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block) +{ + #if !defined (OP_BOOTSTRAP_on) + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + unsigned char error; + unsigned char badBlockMarker; + const struct NandSpareScheme *scheme; + + + // Retrieve model scheme + scheme = NandFlashModel_GetScheme(MODEL(skipBlock)); + + // Read spare area of first page of block + error = RawNandFlash_ReadPage(RAW(skipBlock), block, 0, 0, spare); + if (error) { + + TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block); + return error; + } + + NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); + if (badBlockMarker != 0xFF) { + + return BADBLOCK; + } + + // Read spare area of second page of block + error = RawNandFlash_ReadPage(RAW(skipBlock), block, 1, 0, spare); + if (error) { + + TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block); + return error; + } + + NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); + if (badBlockMarker != 0xFF) { + + return BADBLOCK; + } + #endif + + return GOODBLOCK; +} + + +//------------------------------------------------------------------------------ +/// Initializes a SkipBlockNandFlash instance. Scans the device to retrieve or +/// create block status information. +/// \param skipBlock Pointer to a SkipBlockNandFlash 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 SkipBlockNandFlash_Initialize( + struct SkipBlockNandFlash *skipBlock, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy) +{ + unsigned char error; + #if !defined(OP_BOOTSTRAP_on) + unsigned int numBlocks; + unsigned int block; + #endif + + TRACE_DEBUG("SkipBlockNandFlash_Initialize()\n\r"); + + // Initialize SkipBlockNandFlash + #if !defined(OP_BOOTSTRAP_on) + error = EccNandFlash_Initialize(ECC(skipBlock), + model, + commandAddress, + addressAddress, + dataAddress, + pinChipEnable, + pinReadyBusy); + #else + error = RawNandFlash_Initialize(RAW(skipBlock), + model, + commandAddress, + addressAddress, + dataAddress, + pinChipEnable, + pinReadyBusy); + #endif + + #if !defined(OP_BOOTSTRAP_on) + if (error) { + + return error; + } + + // Retrieve model information + numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(skipBlock)); + + // Initialize block statuses + TRACE_DEBUG("Retrieving bad block information ...\n\r"); + + // Retrieve block status from their first page spare area + for (block = 0; block < numBlocks; block++) { + + // Read spare of first page + error = SkipBlockNandFlash_CheckBlock(skipBlock, block); + + if (error != GOODBLOCK) { + + if (error == BADBLOCK) { + + TRACE_DEBUG("Block #%d is bad\n\r", block); + } + else { + + TRACE_ERROR( + "SkipBlockNandFlash_Initialize: Cannot retrieve info from block #%u\n\r", block); + } + } + } + #endif + + return 0; +} + + +//------------------------------------------------------------------------------ +/// Erases a block of a SkipBlock NandFlash. +/// Returns the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS. +/// \param skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of block to erase. +//------------------------------------------------------------------------------ +unsigned char SkipBlockNandFlash_EraseBlock( + struct SkipBlockNandFlash *skipBlock, + unsigned short block, + unsigned int eraseType) +{ + unsigned char error; + const struct NandSpareScheme *scheme; + unsigned char spare[NandCommon_MAXPAGESPARESIZE]; + +// TRACE_INFO("SkipBlockNandFlash_EraseBlock(%d)\n\r", block); + + if (eraseType != SCRUB_ERASE) { + // Check block status + if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { + + TRACE_INFO("SkipBlockNandFlash_EraseBlock: Block is BAD\n\r"); + return NandCommon_ERROR_BADBLOCK; + } + } + + // Erase block + error = RawNandFlash_EraseBlock(RAW(skipBlock), block); + if (error) { + + // Try to mark the block as BAD + TRACE_ERROR("SkipBlockNandFlash_EraseBlock: Cannot erase block, try to mark it BAD\n\r"); + + // Retrieve model scheme + scheme = NandFlashModel_GetScheme(MODEL(skipBlock)); + + memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE); + NandSpareScheme_WriteBadBlockMarker(scheme, spare, NandBlockStatus_BAD); + return RawNandFlash_WritePage(RAW(skipBlock), block, 0, 0, spare); + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Reads the data and/or the spare area of a page on a SkipBlock nandflash. If +/// the data pointer is not 0, then the block MUST not be BAD +/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns +/// EccNandFlash_ReadPage(). +/// \param skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of block to read page from. +/// \param page Number of page to read inside the given block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char SkipBlockNandFlash_ReadPage( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + #if !defined(OP_BOOTSTRAP_on) + // Check that the block is not BAD if data is requested + if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { + + TRACE_ERROR("SkipBlockNandFlash_ReadPage: Block is BAD.\n\r"); + return NandCommon_ERROR_BADBLOCK; + } + + // Read data with ECC verification + return EccNandFlash_ReadPage(ECC(skipBlock), block, page, data, spare); + #else + return RawNandFlash_ReadPage(RAW(skipBlock), block, page, data, spare); + #endif +} + +//------------------------------------------------------------------------------ +/// Reads the data of a whole block on a SkipBlock nandflash. +/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns +/// EccNandFlash_ReadPage(). +/// \param skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of block to read page from. +/// \param page Number of page to read inside the given block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char SkipBlockNandFlash_ReadBlock( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + void *data) +{ + /// Number of pages per block + unsigned int numPagesPerBlock, pageSize; + // Page index + unsigned short i; + // Error returned by SkipBlockNandFlash_WritePage + unsigned char error = 0; + + // Retrieve model information + pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock)); + numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock)); + + // Check that the block is not BAD if data is requested + if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { + + TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r"); + return NandCommon_ERROR_BADBLOCK; + } + + // Read all the pages of the block + for (i = 0; i < numPagesPerBlock; i++) { + error = EccNandFlash_ReadPage(ECC(skipBlock), block, i, data, 0); + if (error) { + + TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block); + return error; + } + data = (void *) ((unsigned char *) data + pageSize); + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or spare area of a page on a SkipBlock NandFlash. +/// Returns NandCommon_ERROR_BADBLOCK if the page is BAD; otherwise, +/// returns EccNandFlash_WritePage(). +/// \param skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of the block to write. +/// \param page Number of the page to write inside the given block. +/// \param data Data area buffer. +/// \param spare Spare area buffer. +//------------------------------------------------------------------------------ +unsigned char SkipBlockNandFlash_WritePage( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + // Check that the block is LIVE + if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { + + TRACE_ERROR("SkipBlockNandFlash_WritePage: Block is BAD.\n\r"); + return NandCommon_ERROR_BADBLOCK; + } + + // Write data with ECC calculation + return EccNandFlash_WritePage(ECC(skipBlock), block, page, data, spare); +} + +//------------------------------------------------------------------------------ +/// Writes the data of a whole block on a SkipBlock nandflash. +/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns +/// EccNandFlash_ReadPage(). +/// \param skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of block to read page from. +/// \param data Data area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char SkipBlockNandFlash_WriteBlock( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + void *data) +{ + // Number of pages per block + unsigned int numPagesPerBlock; + // Page size + unsigned int pageSize; + // Page index + unsigned short i; + // Error returned by SkipBlockNandFlash_WritePage + unsigned char error = 0; + + // Retrieve model information + pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock)); + numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock)); + + // Check that the block is LIVE + if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) { + + TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Block is BAD.\n\r"); + return NandCommon_ERROR_BADBLOCK; + } + + for (i = 0; i < numPagesPerBlock; i++) { + error = EccNandFlash_WritePage(ECC(skipBlock), block, i, data, 0); + if (error) { + + TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block); + return NandCommon_ERROR_CANNOTWRITE; + } + data = (void *) ((unsigned char *) data + pageSize); + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Writes the data of a whole block on a SkipBlock nandflash. +/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns +/// EccNandFlash_ReadPage(). +/// \param skipBlock Pointer to a SkipBlockNandFlash instance. +/// \param block Number of block to read page from. +/// \param page Number of page to read inside the given block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +//unsigned char SkipBlockNandFlash_WriteBlockUnaligned( +// const struct SkipBlockNandFlash *skipBlock, +// unsigned short block, +// void *data, +// void *tmpBuffer, +// ) +//{ +// // Number of pages per block +// unsigned int numPagesPerBlock; +// // Page size +// unsigned int pageSize; +// // Page index +// unsigned short i; +// // Error returned by SkipBlockNandFlash_WritePage +// unsigned char error = 0; +// +// // Retrieve model information +// pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock)); +// numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock)); +// +// for (i = 0; i < numPagesPerBlock; i++) { +// error = SkipBlockNandFlash_WritePage(skipBlock, block, i, data, 0); +// if (error == NandCommon_ERROR_BADBLOCK) { +// +// TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block); +// return NandCommon_ERROR_BADBLOCK; +// } +// else if (error) { +// +// TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block); +// return NandCommon_ERROR_CANNOTWRITE; +// } +// data += pageSize; +// } +// +// return 0; +//} + diff --git a/memories/nandflash/SkipBlockNandFlash.h b/memories/nandflash/SkipBlockNandFlash.h new file mode 100644 index 0000000..26fbd2d --- /dev/null +++ b/memories/nandflash/SkipBlockNandFlash.h @@ -0,0 +1,134 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "SkipBlockNandFlash" +/// +/// !!!Purpose +/// +/// SkipBlockNandFlash layer supplies application a set of interface to operate nandflash, which include +/// initialize, block erase, block write/read, page write/read. This layer is called by upper layer +/// applications, and it will call lower layer drivers, such as EccNandFlash, RawNandFlash. +/// +/// !!!Usage +/// -# SkipBlockNandFlash_Initialize is used to initializes a SkipBlockNandFlash instance. Scans +/// the device to retrieve or create block status information. +/// -# SkipBlockNandFlash_EraseBlock is used to erase a certain block in the device, user can +/// select "check block status before erase" or "erase without check" +/// -# User can use SkipBlockNandFlash_WriteBlock to write a certain block and SkipBlockNandFlash_WritePage +/// to write a certain page. The functions will check the block status before write, if the block +/// is not a good block, the write command will not be issued. +/// -# User can use SkipBlockNandFlash_ReadBlock to read a certain block and SkipBlockNandFlash_ReadPage +/// to read a certain page. The functions will check the block status before read, if the block +/// is not a good block, the read command will not be issued. ECC is also checked after read +/// operation is finished, an error will be reported if ecc check got errors. +//------------------------------------------------------------------------------ + +#ifndef SKIPBLOCKNANDFLASH_H +#define SKIPBLOCKNANDFLASH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "NandCommon.h" +#include "EccNandFlash.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +#define NandBlockStatus_BAD 0xBA + +// Erase types +/// Check block before erase +#define NORMAL_ERASE 0x00000000 +/// Do NOT check the block status before erasing it +#define SCRUB_ERASE 0x0000EA11 +// Values returned by the CheckBlock() function +#define BADBLOCK 255 +#define GOODBLOCK 254 + + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +struct SkipBlockNandFlash { + struct EccNandFlash ecc; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char SkipBlockNandFlash_CheckBlock( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block); + +extern unsigned char SkipBlockNandFlash_Initialize( + struct SkipBlockNandFlash *skipBlock, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy); + +extern unsigned char SkipBlockNandFlash_EraseBlock( + struct SkipBlockNandFlash *skipBlock, + unsigned short block, + unsigned int eraseType); + +extern unsigned char SkipBlockNandFlash_ReadPage( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +unsigned char SkipBlockNandFlash_ReadBlock( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + void *data); + +extern unsigned char SkipBlockNandFlash_WritePage( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +unsigned char SkipBlockNandFlash_WriteBlock( + const struct SkipBlockNandFlash *skipBlock, + unsigned short block, + void *data); + +#endif //#ifndef SKIPBLOCKNANDFLASH_H + diff --git a/memories/nandflash/TranslatedNandFlash.c b/memories/nandflash/TranslatedNandFlash.c new file mode 100644 index 0000000..8200d42 --- /dev/null +++ b/memories/nandflash/TranslatedNandFlash.c @@ -0,0 +1,587 @@ +/* ---------------------------------------------------------------------------- + * 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 "TranslatedNandFlash.h" +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +/// Casts +#define MAPPED(translated) ((struct MappedNandFlash *) translated) +#define MANAGED(translated) ((struct ManagedNandFlash *) translated) +#define ECC(translated) ((struct EccNandFlash *) translated) +#define RAW(translated) ((struct RawNandFlash *) translated) +#define MODEL(translated) ((struct NandFlashModel *) translated) + +/// Minimum number of blocks that should be kept unallocated +#define MINNUMUNALLOCATEDBLOCKS 32 + +/// Maximum allowed erase count difference +#define MAXERASEDIFFERENCE 5 + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns 1 if there are enough free blocks to perform a single block +/// allocation; otherwise returns 0. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +static unsigned char BlockCanBeAllocated( + const struct TranslatedNandFlash *translated) +{ + unsigned short count; + + // Count number of free and dirty blocks (unallocated blocks) + count = ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_DIRTY) + + ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE); + + // Check that count is greater than minimum number of unallocated blocks + if (count > MINNUMUNALLOCATEDBLOCKS) { + + return 1; + } + else { + + return 0; + } +} + +//------------------------------------------------------------------------------ +/// Returns 1 if the given page inside the currently written block is clean (has +/// not been written yet); otherwise returns 0. +/// \param translated Pointer to a TranslatedNandFlash instance. +/// \param page Page number. +//------------------------------------------------------------------------------ +static unsigned char PageIsClean( + const struct TranslatedNandFlash *translated, + unsigned short page) +{ + ASSERT(page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)), + "PageIsClean: Page out-of-bounds\n\r"); + + return ((translated->currentBlockPageStatuses[page / 8] >> (page % 8)) & 1) == 0; +} + +//------------------------------------------------------------------------------ +/// Marks the given page as being dirty (i.e. written). +/// \param translated Pointer to a TranslatedNandFlash instance. +/// \param page Page number. +//------------------------------------------------------------------------------ +static void MarkPageDirty( + struct TranslatedNandFlash *translated, + unsigned short page) +{ + ASSERT(page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)), + "PageIsClean: Page out-of-bounds\n\r"); + + translated->currentBlockPageStatuses[page / 8] |= 1 << (page % 8); +} + +//------------------------------------------------------------------------------ +/// Marks all pages as being clean. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +static void MarkAllPagesClean(struct TranslatedNandFlash *translated) +{ + memset(translated->currentBlockPageStatuses, 0, + sizeof(translated->currentBlockPageStatuses)); +} + +//------------------------------------------------------------------------------ +/// Allocates the best-fitting physical block for the given logical block. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_NOBLOCKFOUND if +/// there are no more free blocks, or a NandCommon_ERROR code. +/// \param translated Pointer to a TranslatedNandFlash instance. +/// \param block Logical block number. +//------------------------------------------------------------------------------ +static unsigned char AllocateBlock( + struct TranslatedNandFlash *translated, + unsigned short block) +{ + unsigned short freeBlock, liveBlock; + unsigned char error; + signed int eraseDifference; + + TRACE_DEBUG("Allocating a new block\n\r"); + + // Find youngest free block and youngest live block + if (ManagedNandFlash_FindYoungestBlock(MANAGED(translated), + NandBlockStatus_FREE, + &freeBlock)) { + + TRACE_ERROR("AllocateBlock: Could not find a free block\n\r"); + return NandCommon_ERROR_NOBLOCKFOUND; + } + + // If this is the last free block, save the logical mapping in it and + // clean dirty blocks + TRACE_DEBUG("Number of FREE blocks: %d\n\r", + ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE)); + if (ManagedNandFlash_CountBlocks(MANAGED(translated), + NandBlockStatus_FREE) == 1) { + + // Save mapping and clean dirty blocks + TRACE_DEBUG("Last FREE block, cleaning up ...\n\r"); + + error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock); + if (error) { + + TRACE_ERROR("AllocateBlock: Failed to save mapping\n\r"); + return error; + } + error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated)); + if (error) { + + TRACE_ERROR("AllocatedBlock: Failed to erase dirty blocks\n\r"); + return error; + } + + // Allocate new block + return AllocateBlock(translated, block); + } + + // Find youngest LIVE block to check the erase count difference + if (!ManagedNandFlash_FindYoungestBlock(MANAGED(translated), + NandBlockStatus_LIVE, + &liveBlock)) { + + // Calculate erase count difference + TRACE_DEBUG("Free block erase count = %d\n\r", MANAGED(translated)->blockStatuses[freeBlock].eraseCount); + TRACE_DEBUG("Live block erase count = %d\n\r", MANAGED(translated)->blockStatuses[liveBlock].eraseCount); + eraseDifference = absv(MANAGED(translated)->blockStatuses[freeBlock].eraseCount + - MANAGED(translated)->blockStatuses[liveBlock].eraseCount); + + // Check if it is too big + if (eraseDifference > MAXERASEDIFFERENCE) { + + TRACE_WARNING("Erase difference too big, switching blocks\n\r"); + MappedNandFlash_Map( + MAPPED(translated), + MappedNandFlash_PhysicalToLogical( + MAPPED(translated), + liveBlock), + freeBlock); + ManagedNandFlash_CopyBlock(MANAGED(translated), + liveBlock, + freeBlock); + + // Allocate a new block + return AllocateBlock(translated, block); + } + } + + // Map block + TRACE_DEBUG("Allocating PB#%d for LB#%d\n\r", freeBlock, block); + MappedNandFlash_Map(MAPPED(translated), block, freeBlock); + + return 0; +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a TranslatedNandFlash instance. +/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. +/// \param translated Pointer to a TranslatedNandFlash 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. +/// \param baseBlock Basic physical block address of mapped area. +/// \param sizeInBlocks Number of blocks that is mapped. +//------------------------------------------------------------------------------ +unsigned char TranslatedNandFlash_Initialize( + struct TranslatedNandFlash *translated, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy, + unsigned short baseBlock, + unsigned short sizeInBlocks) +{ + translated->currentLogicalBlock = -1; + translated->previousPhysicalBlock = -1; + MarkAllPagesClean(translated); + + // Initialize MappedNandFlash + return MappedNandFlash_Initialize(MAPPED(translated), + model, + commandAddress, + addressAddress, + dataAddress, + pinChipEnable, + pinReadyBusy, + baseBlock, + sizeInBlocks); +} + +//------------------------------------------------------------------------------ +/// 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. +/// Returns 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS +/// if no more block can be allocated, or a NandCommon_ERROR code. +/// \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. +//------------------------------------------------------------------------------ +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; +} + +//------------------------------------------------------------------------------ +/// Writes the data and/or spare area of a page on a translated nandflash. +/// Allocates block has needed to keep the wear even between all blocks. +/// \param translated Pointer to a TranslatedNandFlash instance. +/// \param block Logical block number. +/// \param page Number of page to write inside logical block. +/// \param data Data area buffer, can be 0. +/// \param spare Spare area buffer, can be 0. +//------------------------------------------------------------------------------ +unsigned char TranslatedNandFlash_WritePage( + struct TranslatedNandFlash *translated, + unsigned short block, + unsigned short page, + void *data, + void *spare) +{ + unsigned char allocate = 1; + unsigned char error; + + TRACE_INFO("TranslatedNandFlash_WritePage(B#%d:P#%d)\n\r", block, page); + + // A new block must be allocated unless: + // 1. the block is not mapped and there are no more blocks to allocate + if (MappedNandFlash_LogicalToPhysical(MAPPED(translated), block) == -1) { + + // Block is not mapped, check if it can be + if (!BlockCanBeAllocated(translated)) { + + TRACE_ERROR("TranslatedNandFlash_WritePage: Not enough free blocks\n\r"); + return NandCommon_ERROR_NOMOREBLOCKS; + } + TRACE_DEBUG("Allocate because block not mapped\n\r"); + } + // or 2. the block to write is the current one and the page to write is + // clean + else if (translated->currentLogicalBlock == block) { + + if (PageIsClean(translated, page)) { + + TRACE_DEBUG("NO allocate because write in current block\n\r"); + allocate = 0; + } + else { + + TRACE_DEBUG("Allocate because page DIRTY in current block\n\r"); + } + } + else { + + TRACE_DEBUG("Allocate because block is mapped and different from current block\n\r"); + } + + // Allocate block if needed + if (allocate) { + + // Flush current block write (if any) and then allocate block + error = TranslatedNandFlash_Flush(translated); + if (error) { + + return error; + } + translated->previousPhysicalBlock = MappedNandFlash_LogicalToPhysical( + MAPPED(translated), + block); + TRACE_DEBUG("Previous physical block is now #%d\n\r", + translated->previousPhysicalBlock); + error = AllocateBlock(translated, block); + if (error) { + + return error; + } + + // Block becomes the current block with all pages clean + translated->currentLogicalBlock = block; + MarkAllPagesClean(translated); + } + + // Start writing page + error = MappedNandFlash_WritePage(MAPPED(translated), + block, + page, + data, + spare); + if (error) { + + return error; + } + + // If write went through, mark page as written + MarkPageDirty(translated, page); + return 0; +} + +//------------------------------------------------------------------------------ +/// Terminates the current write operation by copying all the missing pages from +/// the previous physical block. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned char TranslatedNandFlash_Flush(struct TranslatedNandFlash *translated) +{ + unsigned int i; + unsigned char error; + unsigned int currentPhysicalBlock; + + // Check if there is a current block and a previous block + if ((translated->currentLogicalBlock == -1) + || (translated->previousPhysicalBlock == -1)) { + + return 0; + } + + TRACE_INFO("TranslatedNandFlash_Flush(PB#%d -> LB#%d)\n\r", + translated->previousPhysicalBlock, translated->currentLogicalBlock); + + // Copy missing pages in the current block + currentPhysicalBlock = MappedNandFlash_LogicalToPhysical( + MAPPED(translated), + translated->currentLogicalBlock); + + for (i=0; i < NandFlashModel_GetBlockSizeInPages(MODEL(translated)); i++) { + + if (PageIsClean(translated, i)) { + + TRACE_DEBUG("Copying back page #%d of block #%d\n\r", i, + translated->previousPhysicalBlock); + + // Copy page + error = ManagedNandFlash_CopyPage(MANAGED(translated), + translated->previousPhysicalBlock, + i, + currentPhysicalBlock, + i); + if (error) { + + TRACE_ERROR("FinishCurrentWrite: copy page #%d\n\r", i); + return error; + } + } + } + + translated->currentLogicalBlock = -1; + translated->previousPhysicalBlock = -1; + return 0; +} + +//------------------------------------------------------------------------------ +/// Erase all blocks in the tranalated area of nand flash. +/// \param managed Pointer to a TranslatedNandFlash instance. +/// \param level Erase level. +//------------------------------------------------------------------------------ +unsigned char TranslatedNandFlash_EraseAll( + struct TranslatedNandFlash *translated, + unsigned char level) +{ + MappedNandFlash_EraseAll(MAPPED(translated), level); + if (level > NandEraseDIRTY) { + translated->currentLogicalBlock = -1; + translated->previousPhysicalBlock = -1; + MarkAllPagesClean(translated); + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Allocates a free block to save the current logical mapping on it. +/// Returns 0 if successful; otherwise returns a NandCommon_ERROR code. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned char TranslatedNandFlash_SaveLogicalMapping( + struct TranslatedNandFlash *translated) +{ + unsigned char error; + unsigned short freeBlock; + + TRACE_INFO("TranslatedNandFlash_SaveLogicalMapping()\n\r"); + + // Save logical mapping in the youngest free block + // Find the youngest block + error = ManagedNandFlash_FindYoungestBlock(MANAGED(translated), + NandBlockStatus_FREE, + &freeBlock); + if (error) { + + TRACE_ERROR("TranNF_SaveLogicalMapping: No free block\n\r"); + return error; + } + + // Check if this is the last free block, in which case dirty blocks are wiped + // prior to saving the mapping + if (ManagedNandFlash_CountBlocks(MANAGED(translated), + NandBlockStatus_FREE) == 1) { + + TranslatedNandFlash_Flush(translated); + error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated)); + if (error) { + + TRACE_ERROR("TranNF_Flush: Could not erase dirty blocks\n\r"); + return error; + } + } + + // Save the mapping + error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock); + if (error) { + + TRACE_ERROR("TranNF_Flush: Failed to save mapping in #%d\n\r", + freeBlock); + return error; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// Returns the number of available blocks in a translated nandflash. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned short TranslatedNandFlash_GetDeviceSizeInBlocks( + const struct TranslatedNandFlash *translated) +{ + return ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(translated)) + - MINNUMUNALLOCATEDBLOCKS + - ManagedNandFlash_CountBlocks(MANAGED(translated), + NandBlockStatus_BAD) + - 1; // Logical mapping block +} + +//------------------------------------------------------------------------------ +/// Returns the number of available pages in a translated nandflash. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned int TranslatedNandFlash_GetDeviceSizeInPages( + const struct TranslatedNandFlash *translated) +{ + return TranslatedNandFlash_GetDeviceSizeInBlocks(translated) + * NandFlashModel_GetBlockSizeInPages(MODEL(translated)); +} + +//------------------------------------------------------------------------------ +/// Returns the number of available data bytes in a translated nandflash. +/// \param translated Pointer to a TranslatedNandFlash instance. +//------------------------------------------------------------------------------ +unsigned long long TranslatedNandFlash_GetDeviceSizeInBytes( + const struct TranslatedNandFlash *translated) +{ + return TranslatedNandFlash_GetDeviceSizeInPages(translated) + * NandFlashModel_GetPageDataSize(MODEL(translated)); +} + diff --git a/memories/nandflash/TranslatedNandFlash.h b/memories/nandflash/TranslatedNandFlash.h new file mode 100644 index 0000000..88bbf38 --- /dev/null +++ b/memories/nandflash/TranslatedNandFlash.h @@ -0,0 +1,108 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \page "TranslatedNandFlash" +/// +/// !!!Purpose +/// +/// Translate a nandflash physical block to logical block, it will call lower layer such as MappedNandFlash +//------------------------------------------------------------------------------ + +#ifndef TRANSLATEDNANDFLASH_H +#define TRANSLATEDNANDFLASH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "MappedNandFlash.h" + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +struct TranslatedNandFlash { + + struct MappedNandFlash mapped; + signed short currentLogicalBlock; + signed short previousPhysicalBlock; + unsigned char currentBlockPageStatuses[NandCommon_MAXNUMPAGESPERBLOCK / 8]; +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char TranslatedNandFlash_Initialize( + struct TranslatedNandFlash *translated, + const struct NandFlashModel *model, + unsigned int commandAddress, + unsigned int addressAddress, + unsigned int dataAddress, + const Pin pinChipEnable, + const Pin pinReadyBusy, + unsigned short baseBlock, + unsigned short sizeInBlocks); + +extern unsigned char TranslatedNandFlash_ReadPage( + const struct TranslatedNandFlash *translated, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char TranslatedNandFlash_WritePage( + struct TranslatedNandFlash *translated, + unsigned short block, + unsigned short page, + void *data, + void *spare); + +extern unsigned char TranslatedNandFlash_Flush( + struct TranslatedNandFlash *translated); + +extern unsigned char TranslatedNandFlash_EraseAll( + struct TranslatedNandFlash *translated, + unsigned char level); + +extern unsigned char TranslatedNandFlash_SaveLogicalMapping( + struct TranslatedNandFlash *translated); + +extern unsigned short TranslatedNandFlash_GetDeviceSizeInBlocks( + const struct TranslatedNandFlash *translated); + +extern unsigned int TranslatedNandFlash_GetDeviceSizeInPages( + const struct TranslatedNandFlash *translated); + +extern unsigned long long TranslatedNandFlash_GetDeviceSizeInBytes( + const struct TranslatedNandFlash *translated); + +#endif //#ifndef TRANSLATEDNANDFLASH_H + diff --git a/memories/nandflash/nandflash.dir b/memories/nandflash/nandflash.dir new file mode 100644 index 0000000..d20aa6a --- /dev/null +++ b/memories/nandflash/nandflash.dir @@ -0,0 +1,44 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory contains nandflash drivers +/// +/// !!!Description +/// - Nandflash drivers: SkipBlockNandFlash layer, EccNandFlash and NandSpareScheme layer, +/// RawNandflash layer. +/// - Nandflash parameter interface : NandFlashModel. +/// - Supported Nandflash device list : NandFlashModelList. +/// - Nandflash block management drivers : TranslatedNandFlash layer, MappedNandFlash layer, +/// ManagedNandFlash layer. +//------------------------------------------------------------------------------ \ No newline at end of file -- cgit v1.2.3