summaryrefslogtreecommitdiff
path: root/memories/nandflash/RawNandFlash.c
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/RawNandFlash.c
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/RawNandFlash.c')
-rw-r--r--memories/nandflash/RawNandFlash.c792
1 files changed, 792 insertions, 0 deletions
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
personal git repositories of Harald Welte. Your mileage may vary