summaryrefslogtreecommitdiff
path: root/memories/nandflash
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-07-04 20:52:54 +0200
committerHarald Welte <laforge@gnumonks.org>2011-07-04 20:52:54 +0200
commit044ad7c3987460ede48ff27afd6bdb0ca05a0432 (patch)
tree924818cdb0d39ca08aec540d18da7bd406eaae8c /memories/nandflash
import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v1501120100901_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
Diffstat (limited to 'memories/nandflash')
-rw-r--r--memories/nandflash/EccNandFlash.c328
-rw-r--r--memories/nandflash/EccNandFlash.h101
-rw-r--r--memories/nandflash/ManagedNandFlash.c862
-rw-r--r--memories/nandflash/ManagedNandFlash.h154
-rw-r--r--memories/nandflash/MappedNandFlash.c661
-rw-r--r--memories/nandflash/MappedNandFlash.h116
-rw-r--r--memories/nandflash/NandCommon.h134
-rw-r--r--memories/nandflash/NandFlashModel.c403
-rw-r--r--memories/nandflash/NandFlashModel.h169
-rw-r--r--memories/nandflash/NandFlashModelList.c118
-rw-r--r--memories/nandflash/NandFlashModelList.h65
-rw-r--r--memories/nandflash/NandSpareScheme.c230
-rw-r--r--memories/nandflash/NandSpareScheme.h124
-rw-r--r--memories/nandflash/NfcRawNandFlash.c871
-rw-r--r--memories/nandflash/RawNandFlash.c792
-rw-r--r--memories/nandflash/RawNandFlash.h139
-rw-r--r--memories/nandflash/SkipBlockNandFlash.c444
-rw-r--r--memories/nandflash/SkipBlockNandFlash.h134
-rw-r--r--memories/nandflash/TranslatedNandFlash.c587
-rw-r--r--memories/nandflash/TranslatedNandFlash.h108
-rw-r--r--memories/nandflash/nandflash.dir44
21 files changed, 6584 insertions, 0 deletions
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 <utility/trace.h>
+#include <utility/hamming.h>
+#include <utility/assert.h>
+#ifdef HARDWARE_ECC
+#include <hsmc4/hsmc4_ecc.h>
+#endif
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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 <board.h>
+
+//------------------------------------------------------------------------------
+// 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 <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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 <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/math.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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 <hsmc4/hsmc4.h>
+#endif
+#include <utility/trace.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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; i<size; i++) {
+ if(modelList[i].deviceId == id2) {
+ found = 1;
+
+ if(model) {
+
+ memcpy(model, &modelList[i], sizeof(struct NandFlashModel));
+
+ if(model->blockSizeInKBytes == 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 <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// 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 <hsmc4/hsmc4.h>
+#include <dma/dma.h>
+#include <dmad/dmad.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+#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 <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+#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 <pio/pio.h>
+
+//------------------------------------------------------------------------------
+// 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 <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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 <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/math.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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
personal git repositories of Harald Welte. Your mileage may vary