[sky9x] Massstorage (still not working, but we see the drive)
This commit is contained in:
+5
-2
@@ -424,7 +424,7 @@ ifeq ($(PCB), ARM)
|
||||
# V4 ARM, so ...
|
||||
OPT = 2
|
||||
CPPDEFS += -DPCBARM -DAUDIO -DHAPTIC -DPXX -DDSM2 -DDSM2_PPM -DROTARY_ENCODERS=1
|
||||
# CPPDEFS += -DMASSSTORAGE -DDEBUG # Both must come together today!
|
||||
CPPDEFS += -DMASSSTORAGE
|
||||
EXTRAINCDIRS += ersky9x ersky9x/libraries ersky9x/libraries/drivers CoOS/kernel CoOS/portable
|
||||
BOARDSRC = board_ersky9x.cpp
|
||||
SRC += ersky9x/core_cm3.c ersky9x/board_lowlevel.c ersky9x/crt.c ersky9x/vectors_sam3s.c
|
||||
@@ -434,7 +434,7 @@ ifeq ($(PCB), ARM)
|
||||
SRC += ersky9x/libraries/usb/device/core/USBDCallbacks_Resumed.c ersky9x/libraries/usb/device/core/USBDCallbacks_Reset.c ersky9x/libraries/usb/device/core/USBDCallbacks_Suspended.c ersky9x/libraries/usb/device/core/USBDCallbacks_Initialized.c ersky9x/libraries/usb/device/core/USBDDriverCb_IfSettingChanged.c # TODO remove them
|
||||
SRC += ersky9x/libraries/usb/device/massstorage/MSDLun.c ersky9x/libraries/usb/device/massstorage/MSDDriverDescriptors.c
|
||||
SRC += ersky9x/syscalls.c
|
||||
SRC += ersky9x/libraries/usb/device/massstorage/SBCMethods.c
|
||||
SRC += ersky9x/libraries/usb/device/massstorage/SBCMethods.c ersky9x/libraries/memories/MEDSdcard.c
|
||||
EEPROMSRC = eeprom_arm.cpp
|
||||
PULSESSRC = pulses_arm.cpp
|
||||
CPPSRC += ersky9x/audio.cpp haptic.cpp
|
||||
@@ -884,6 +884,9 @@ clean_list :
|
||||
$(REMOVE) *.o
|
||||
$(REMOVE) */*.o
|
||||
$(REMOVE) */*/*.o
|
||||
$(REMOVE) */*/*/*.o
|
||||
$(REMOVE) */*/*/*/*.o
|
||||
$(REMOVE) */*/*/*/*/*.o
|
||||
$(REMOVE) *.d
|
||||
$(REMOVE) *.lst
|
||||
$(REMOVE) allsrc.cpp
|
||||
|
||||
@@ -1,510 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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 "MEDNandFlash.h"
|
||||
#include "nandflash/NandCommon.h"
|
||||
#include "nandflash/TranslatedNandFlash.h"
|
||||
#include "nandflash/NandFlashModel.h"
|
||||
#include <utility/trace.h>
|
||||
#include <utility/math.h>
|
||||
#include <utility/assert.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Casts
|
||||
#define MODEL(interface) ((struct NandFlashModel *) interface)
|
||||
#define TRANSLATED(interface) ((struct TranslatedNandFlash *) interface)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Internal variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static unsigned char pageWriteBuffer[NandCommon_MAXPAGEDATASIZE];
|
||||
static signed short currentWriteBlock;
|
||||
static signed short currentWritePage;
|
||||
|
||||
static unsigned char pageReadBuffer[NandCommon_MAXPAGEDATASIZE];
|
||||
static signed short currentReadBlock;
|
||||
static signed short currentReadPage;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Internal functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Writes the current page of data on the NandFlash.
|
||||
/// Returns 0 if successful; otherwise returns 1.
|
||||
/// \param tnf Pointer to a TranslatedNandFlash instance.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char FlushCurrentPage(Media *media)
|
||||
{
|
||||
// Make sure there is a page to flush
|
||||
if (currentWritePage == -1) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE_DEBUG("FlushCurrentPage(B#%d:P#%d)\n\r",
|
||||
currentWriteBlock, currentWritePage);
|
||||
|
||||
// Write page
|
||||
if (TranslatedNandFlash_WritePage(TRANSLATED(media->interface),
|
||||
currentWriteBlock,
|
||||
currentWritePage,
|
||||
pageWriteBuffer,
|
||||
0)) {
|
||||
|
||||
TRACE_ERROR("FlushCurrentPage: Failed to write page.\n\r");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// No current write page & block
|
||||
currentWriteBlock = -1;
|
||||
currentWritePage = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Writes data at an unaligned (page-wise) address and size. The address is
|
||||
/// provided as the block & page number plus an offset. The data to write MUST
|
||||
/// NOT span more than one page.
|
||||
/// Returns 0 if the data has been written; 1 otherwise.
|
||||
/// \param media Pointer to a nandflash Media instance.
|
||||
/// \param block Number of the block to write.
|
||||
/// \param page Number of the page to write.
|
||||
/// \param offset Write offset.
|
||||
/// \param buffer Data buffer.
|
||||
/// \param size Number of bytes to write.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char UnalignedWritePage(
|
||||
Media *media,
|
||||
unsigned short block,
|
||||
unsigned short page,
|
||||
unsigned short offset,
|
||||
unsigned char *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned char error;
|
||||
unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
|
||||
unsigned char writePage = ((size + offset) == pageDataSize);
|
||||
|
||||
TRACE_DEBUG("UnalignedWritePage(B%d:P%d@%d, %d)\n\r",
|
||||
block, page, offset, size);
|
||||
ASSERT((size + offset) <= pageDataSize,
|
||||
"UnalignedWrite: Write size and offset exceed page data size\n\r");
|
||||
|
||||
// If size is 0, return immediately
|
||||
if (size == 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If this is not the current page, flush the previous one
|
||||
if ((currentWriteBlock != block) || (currentWritePage != page)) {
|
||||
|
||||
// Flush and make page the new current page
|
||||
FlushCurrentPage(media);
|
||||
TRACE_DEBUG("Current write page: B#%d:P#%d\n\r", block, page);
|
||||
currentWriteBlock = block;
|
||||
currentWritePage = page;
|
||||
|
||||
// Read existing page data in a temporary buffer if the page is not
|
||||
// entirely written
|
||||
if (size != pageDataSize) {
|
||||
|
||||
error = TranslatedNandFlash_ReadPage(TRANSLATED(media->interface),
|
||||
block,
|
||||
page,
|
||||
pageWriteBuffer,
|
||||
0);
|
||||
if (error) {
|
||||
|
||||
TRACE_ERROR(
|
||||
"UnalignedWrite: Could not read existing page data\n\r");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy data in temporary buffer
|
||||
memcpy(&(pageWriteBuffer[offset]), buffer, size);
|
||||
// Update read buffer if necessary
|
||||
if ((currentReadPage == currentWritePage)
|
||||
&& (currentReadBlock == currentWriteBlock)) {
|
||||
|
||||
TRACE_DEBUG("Updating current read buffer\n\r");
|
||||
memcpy(&(pageReadBuffer[offset]), buffer, size);
|
||||
}
|
||||
|
||||
// Flush page if it is complete
|
||||
if (writePage) {
|
||||
|
||||
FlushCurrentPage(media);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Writes a data buffer at the specified address on a NandFlash media. An
|
||||
/// optional callback can be triggered after the transfer is completed.
|
||||
/// Returns MED_STATUS_SUCCESS if the transfer has been started successfully;
|
||||
/// otherwise returns MED_STATUS_ERROR.
|
||||
/// \param media Pointer to the NandFlash Media instance.
|
||||
/// \param address Address where the data shall be written.
|
||||
/// \param data Data buffer.
|
||||
/// \param length Number of bytes to write.
|
||||
/// \param callback Optional callback to call when the write is finished.
|
||||
/// \param argument Optional argument to the callback function.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDNandFlash_Write(
|
||||
Media *media,
|
||||
unsigned int address,
|
||||
void *data,
|
||||
unsigned int length,
|
||||
MediaCallback callback,
|
||||
void *argument)
|
||||
{
|
||||
unsigned short pageDataSize =
|
||||
NandFlashModel_GetPageDataSize(MODEL(media->interface));
|
||||
unsigned short blockSize =
|
||||
NandFlashModel_GetBlockSizeInPages(MODEL(media->interface));
|
||||
unsigned short block, page, offset;
|
||||
unsigned int writeSize;
|
||||
unsigned char *buffer = (unsigned char *) data;
|
||||
unsigned int remainingLength;
|
||||
unsigned char status;
|
||||
|
||||
TRACE_INFO("MEDNandFlash_Write(0x%08X, %d)\n\r", address, length);
|
||||
|
||||
// Translate access
|
||||
if (NandFlashModel_TranslateAccess(MODEL(media->interface),
|
||||
address,
|
||||
length,
|
||||
&block,
|
||||
&page,
|
||||
&offset)) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Write: Could not start write.\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
TRACE_DEBUG("MEDNandFlash_Write(B#%d:P#%d@%d, %d)\n\r",
|
||||
block, page, offset, length);
|
||||
|
||||
// Write pages
|
||||
remainingLength = length;
|
||||
status = MED_STATUS_SUCCESS;
|
||||
while ((status == MED_STATUS_SUCCESS) && (remainingLength > 0)) {
|
||||
|
||||
// Write one page
|
||||
writeSize = min(pageDataSize-offset, remainingLength);
|
||||
if (UnalignedWritePage(media, block, page, offset, buffer, writeSize)) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Write: Failed to write page\n\r");
|
||||
status = MED_STATUS_ERROR;
|
||||
}
|
||||
else {
|
||||
|
||||
// Update addresses
|
||||
remainingLength -= writeSize;
|
||||
buffer += writeSize;
|
||||
offset = 0;
|
||||
page++;
|
||||
if (page == blockSize) {
|
||||
|
||||
page = 0;
|
||||
block++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger callback
|
||||
if (callback) {
|
||||
|
||||
callback(argument, status, length - remainingLength, remainingLength);
|
||||
}
|
||||
|
||||
// Reset flush timer
|
||||
//AT91C_BASE_NANDFLUSHTIMER->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads data at an unaligned address and/or size. The address is provided as
|
||||
/// the block & page numbers plus an offset.
|
||||
/// Returns 0 if the data has been read; otherwise returns 1.
|
||||
/// \param media Pointer to a nandflash Media instance.
|
||||
/// \param block Number of the block to read.
|
||||
/// \param page Number of the page to read.
|
||||
/// \param offset Read offset.
|
||||
/// \param buffer Buffer for storing data.
|
||||
/// \param size Number of bytes to read.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char UnalignedReadPage(
|
||||
Media *media,
|
||||
unsigned short block,
|
||||
unsigned short page,
|
||||
unsigned short offset,
|
||||
unsigned char *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned char error;
|
||||
unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
|
||||
|
||||
TRACE_DEBUG("UnalignedReadPage(B%d:P%d@%d, %d)\n\r", block, page, offset, size);
|
||||
|
||||
// Check that one page is read at most
|
||||
ASSERT((size + offset) <= pageDataSize,
|
||||
"UnalignedReadPage: Read size & offset exceed page data size\n\r");
|
||||
|
||||
// Check if this is not the current read page
|
||||
if ((block != currentReadBlock) || (page != currentReadPage)) {
|
||||
|
||||
TRACE_DEBUG("Current read page: B#%d:P#%d\n\r", block, page);
|
||||
currentReadBlock = block;
|
||||
currentReadPage = page;
|
||||
|
||||
// Check if this is the current write page
|
||||
if ((currentReadBlock == currentWriteBlock)
|
||||
&& (currentReadPage == currentWritePage)) {
|
||||
|
||||
TRACE_DEBUG("Reading current write page\n\r");
|
||||
memcpy(pageReadBuffer, pageWriteBuffer, NandCommon_MAXPAGEDATASIZE);
|
||||
}
|
||||
else {
|
||||
|
||||
// Read whole page into a temporary buffer
|
||||
error = TranslatedNandFlash_ReadPage(TRANSLATED(media->interface),
|
||||
block,
|
||||
page,
|
||||
pageReadBuffer,
|
||||
0);
|
||||
if (error) {
|
||||
|
||||
TRACE_ERROR("UnalignedRead: Could not read page\n\r");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy data into buffer
|
||||
memcpy(buffer, &(pageReadBuffer[offset]), size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads data at the specified address of a NandFlash media. An optional
|
||||
/// callback is invoked when the transfer completes.
|
||||
/// Returns 1 if the transfer has been started; otherwise returns 0.
|
||||
/// \param media Pointer to the NandFlash Media to read.
|
||||
/// \param address Address at which the data shall be read.
|
||||
/// \param data Data buffer.
|
||||
/// \param length Number of bytes to read.
|
||||
/// \param callback Optional callback function.
|
||||
/// \param argument Optional argument to the callback function.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDNandFlash_Read(
|
||||
Media *media,
|
||||
unsigned int address,
|
||||
void *data,
|
||||
unsigned int length,
|
||||
MediaCallback callback,
|
||||
void *argument)
|
||||
{
|
||||
unsigned short block, page, offset;
|
||||
unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
|
||||
unsigned short blockSizeInPages = NandFlashModel_GetBlockSizeInPages(MODEL(media->interface));
|
||||
unsigned int remainingLength;
|
||||
unsigned int readSize;
|
||||
unsigned char *buffer = (unsigned char *) data;
|
||||
unsigned char status;
|
||||
|
||||
TRACE_INFO("MEDNandFlash_Read(0x%08X, %d)\n\r", address, length);
|
||||
|
||||
// Translate access into block, page and offset
|
||||
if (NandFlashModel_TranslateAccess(MODEL(media->interface),
|
||||
address,
|
||||
length,
|
||||
&block,
|
||||
&page,
|
||||
&offset)) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Read: Cannot perform access\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// Read
|
||||
remainingLength = length;
|
||||
status = MED_STATUS_SUCCESS;
|
||||
while ((status == MED_STATUS_SUCCESS) && (remainingLength > 0)) {
|
||||
|
||||
// Read page
|
||||
readSize = min(pageDataSize-offset, remainingLength);
|
||||
if (UnalignedReadPage(media, block, page, offset, buffer, readSize)) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Read: Could not read page\n\r");
|
||||
status = MED_STATUS_ERROR;
|
||||
}
|
||||
else {
|
||||
|
||||
// Update values
|
||||
remainingLength -= readSize;
|
||||
buffer += readSize;
|
||||
offset = 0;
|
||||
page++;
|
||||
if (page == blockSizeInPages) {
|
||||
|
||||
page = 0;
|
||||
block++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger callback
|
||||
if (callback) {
|
||||
|
||||
callback(argument, status, length - remainingLength, remainingLength);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Carries out all pending operations. Returns MED_STATUS_SUCCESS if
|
||||
/// succesful; otherwise, returns MED_STATUS_ERROR.
|
||||
/// \param media Pointer to a NandFlash Media instance.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDNandFlash_Flush(Media *media)
|
||||
{
|
||||
TRACE_INFO("MEDNandFlash_Flush()\n\r");
|
||||
|
||||
if (FlushCurrentPage(media)) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Flush: Could not flush current page\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (TranslatedNandFlash_Flush(TRANSLATED(media->interface))) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Flush: Could not flush translated nand\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (TranslatedNandFlash_SaveLogicalMapping(TRANSLATED(media->interface))) {
|
||||
|
||||
TRACE_ERROR("MEDNandFlash_Flush: Could not save the logical mapping\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return MED_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Interrupt handler for the nandflash media. Triggered when the flush timer
|
||||
/// expires, initiating a MEDNandFlash_Flush().
|
||||
/// \param media Pointer to a nandflash Media instance.
|
||||
//------------------------------------------------------------------------------
|
||||
static void MEDNandFlash_InterruptHandler(Media *media)
|
||||
{
|
||||
//volatile unsigned int dummy;
|
||||
|
||||
TRACE_DEBUG("Flush timer expired\n\r");
|
||||
MEDNandFlash_Flush(media);
|
||||
|
||||
// Acknowledge interrupt
|
||||
//dummy = AT91C_BASE_NANDFLUSHTIMER->TC_SR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes a media instance to operate on the given NandFlash device.
|
||||
/// \param media Pointer to a Media instance.
|
||||
/// \param tnf Pointer to the TranslatedNandFlash to use.
|
||||
//------------------------------------------------------------------------------
|
||||
void MEDNandFlash_Initialize(Media *media,
|
||||
struct TranslatedNandFlash *translated)
|
||||
{
|
||||
TRACE_INFO("MEDNandFlash_Initialize()\n\r");
|
||||
|
||||
media->write = MEDNandFlash_Write;
|
||||
media->read = MEDNandFlash_Read;
|
||||
media->lock = 0;
|
||||
media->unlock = 0;
|
||||
media->flush = MEDNandFlash_Flush;
|
||||
media->handler = MEDNandFlash_InterruptHandler;
|
||||
|
||||
media->interface = translated;
|
||||
|
||||
media->baseAddress = 0;
|
||||
media->blockSize = 1;
|
||||
media->size = TranslatedNandFlash_GetDeviceSizeInBytes(translated);
|
||||
|
||||
TRACE_INFO("NF Size: %d\n\r", media->size);
|
||||
|
||||
media->mappedRD = 0;
|
||||
media->mappedWR = 0;
|
||||
media->protected = 0;
|
||||
media->removable = 0;
|
||||
media->state = MED_STATE_READY;
|
||||
|
||||
currentWriteBlock = -1;
|
||||
currentWritePage = -1;
|
||||
currentReadBlock = -1;
|
||||
currentReadPage = -1;
|
||||
|
||||
// Configure flush timer
|
||||
/*
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_NANDFLUSHTIMER);
|
||||
AT91C_BASE_NANDFLUSHTIMER->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_NANDFLUSHTIMER->TC_IDR = 0xFFFFFFFF;
|
||||
AT91C_BASE_NANDFLUSHTIMER->TC_CMR = AT91C_TC_CLKS_TIMER_DIV5_CLOCK
|
||||
| AT91C_TC_CPCSTOP
|
||||
| AT91C_TC_CPCDIS
|
||||
| AT91C_TC_WAVESEL_UP_AUTO
|
||||
| AT91C_TC_WAVE;
|
||||
AT91C_BASE_NANDFLUSHTIMER->TC_RC = 0xFFFF;
|
||||
AT91C_BASE_NANDFLUSHTIMER->TC_IER = AT91C_TC_CPCS;
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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 MEDNANDFLASH_H
|
||||
#define MEDNANDFLASH_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "Media.h"
|
||||
#include "board.h"
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Timer Counter used to flush the nandflash after write operations.
|
||||
#define AT91C_BASE_NANDFLUSHTIMER AT91C_BASE_TC1
|
||||
#define AT91C_ID_NANDFLUSHTIMER AT91C_ID_TC1
|
||||
//------------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct TranslatedNandFlash;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void MEDNandFlash_Initialize(
|
||||
Media *media,
|
||||
struct TranslatedNandFlash *tnf);
|
||||
|
||||
#endif //#ifndef MEDNANDFLASH_H
|
||||
|
||||
@@ -0,0 +1,617 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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 <string.h>
|
||||
#include "Media.h"
|
||||
#include "debug.h"
|
||||
#include "board.h"
|
||||
#include "../FatFs/diskio.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Number of SD Slots
|
||||
#define NUM_SD_SLOTS 1
|
||||
#define SD_BLOCK_SIZE 512
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Checks if the device is write protected.
|
||||
/// \return 1 if protected.
|
||||
//------------------------------------------------------------------------------
|
||||
#if 0
|
||||
static unsigned char CardIsProtected(unsigned char slot)
|
||||
{
|
||||
if (slot == 0) {
|
||||
#ifdef BOARD_SD_PIN_WP
|
||||
PIO_Configure(&pinMciWriteProtect, 1);
|
||||
return (PIO_Get(&pinMciWriteProtect) != 0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (slot == 1) {
|
||||
#ifdef BOARD_SD_MCI1_PIN_WP
|
||||
PIO_Configure(&pinMciWriteProtect1, 1);
|
||||
return (PIO_Get(&pinMciWriteProtect1) != 0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configure the PIO for SD
|
||||
//------------------------------------------------------------------------------
|
||||
#if 0
|
||||
static void ConfigurePIO(unsigned char mciID)
|
||||
{
|
||||
#ifdef BOARD_SD_PINS
|
||||
const Pin pinSd0[] = {BOARD_SD_PINS};
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_SD_MCI1_PINS
|
||||
const Pin pinSd1[] = {BOARD_SD_MCI1_PINS};
|
||||
#endif
|
||||
|
||||
if(mciID == 0) {
|
||||
#ifdef BOARD_SD_PINS
|
||||
PIO_Configure(pinSd0, PIO_LISTSIZE(pinSd0));
|
||||
#endif
|
||||
} else {
|
||||
#ifdef BOARD_SD_MCI1_PINS
|
||||
PIO_Configure(pinSd1, PIO_LISTSIZE(pinSd1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//! \brief Reads a specified amount of data from a SDCARD memory
|
||||
//! \param media Pointer to a Media instance
|
||||
//! \param address Address of the data to read
|
||||
//! \param data Pointer to the buffer in which to store the retrieved
|
||||
//! data
|
||||
//! \param length Length of the buffer
|
||||
//! \param callback Optional pointer to a callback function to invoke when
|
||||
//! the operation is finished
|
||||
//! \param argument Optional pointer to an argument for the callback
|
||||
//! \return Operation result code
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDSdcard_Read(Media *media,
|
||||
unsigned int address,
|
||||
void *data,
|
||||
unsigned int length,
|
||||
MediaCallback callback,
|
||||
void *argument)
|
||||
{
|
||||
TRACE_DEBUG("MEDSdcard_Read(address=%d length=%d)\n\r", address, length);
|
||||
|
||||
// unsigned char error;
|
||||
|
||||
// Check that the media is ready
|
||||
if (media->state != MED_STATE_READY) {
|
||||
|
||||
TRACE_INFO("Media busy\n\r");
|
||||
return MED_STATUS_BUSY;
|
||||
}
|
||||
|
||||
// Check that the data to read is not too big
|
||||
if ((length + address) > media->size) {
|
||||
|
||||
TRACE_WARNING("MEDSdcard_Read: Data too big: %d, %d\n\r",
|
||||
(int)length, (int)address);
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// Enter Busy state
|
||||
media->state = MED_STATE_BUSY;
|
||||
|
||||
disk_read (0, data, address, length);
|
||||
|
||||
// SD_ReadBlock((SdCard*)media->interface, address, length, data);
|
||||
|
||||
// Leave the Busy state
|
||||
media->state = MED_STATE_READY;
|
||||
|
||||
// Invoke callback
|
||||
if (callback != 0) {
|
||||
|
||||
callback(argument, MED_STATUS_SUCCESS, 0, 0);
|
||||
}
|
||||
|
||||
return MED_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//! \brief Writes data on a SDRAM media
|
||||
//! \param media Pointer to a Media instance
|
||||
//! \param address Address at which to write
|
||||
//! \param data Pointer to the data to write
|
||||
//! \param length Size of the data buffer
|
||||
//! \param callback Optional pointer to a callback function to invoke when
|
||||
//! the write operation terminates
|
||||
//! \param argument Optional argument for the callback function
|
||||
//! \return Operation result code
|
||||
//! \see Media
|
||||
//! \see MediaCallback
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDSdcard_Write(Media *media,
|
||||
unsigned int address,
|
||||
void *data,
|
||||
unsigned int length,
|
||||
MediaCallback callback,
|
||||
void *argument)
|
||||
{
|
||||
|
||||
TRACE_DEBUG("MEDSdcard_Write(address=%d length=%d)\n\r", address, length);
|
||||
|
||||
unsigned char error;
|
||||
|
||||
// Check that the media if ready
|
||||
if (media->state != MED_STATE_READY) {
|
||||
|
||||
TRACE_WARNING("MEDSdcard_Write: Media is busy\n\r");
|
||||
return MED_STATUS_BUSY;
|
||||
}
|
||||
|
||||
// Check that the data to write is not too big
|
||||
if ((length + address) > media->size) {
|
||||
|
||||
TRACE_WARNING("MEDSdcard_Write: Data too big\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// Put the media in Busy state
|
||||
media->state = MED_STATE_BUSY;
|
||||
|
||||
// TODO BSS error = SD_WriteBlock((SdCard*)media->interface, address, length, data);
|
||||
|
||||
// Leave the Busy state
|
||||
media->state = MED_STATE_READY;
|
||||
|
||||
// Invoke the callback if it exists
|
||||
if (callback != 0) {
|
||||
|
||||
callback(argument, MED_STATUS_SUCCESS, 0, 0);
|
||||
}
|
||||
|
||||
return MED_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
//! \brief Callback invoked when SD/MMC transfer done
|
||||
//------------------------------------------------------------------------------
|
||||
static void SdMmcCallback( unsigned char status, void *pCommand )
|
||||
{
|
||||
SdCmd * pCmd = (SdCmd*)pCommand;
|
||||
Media * pMed = (Media *)pCmd->pArg;
|
||||
MEDTransfer * pXfr = &pMed->transfer;
|
||||
|
||||
TRACE_INFO_WP("SDCb ");
|
||||
|
||||
// Error
|
||||
if (status == SD_ERROR_BUSY) {
|
||||
status = MED_STATUS_BUSY;
|
||||
}
|
||||
else if (status) {
|
||||
status = MED_STATUS_ERROR;
|
||||
}
|
||||
|
||||
pMed->state = MED_STATE_READY;
|
||||
if (pXfr->callback) {
|
||||
pXfr->callback(pXfr->argument,
|
||||
status,
|
||||
pXfr->length * pMed->blockSize,
|
||||
0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
//! \brief Reads a specified amount of data from a SDCARD memory
|
||||
//! \param media Pointer to a Media instance
|
||||
//! \param address Address of the data to read
|
||||
//! \param data Pointer to the buffer in which to store the retrieved
|
||||
//! data
|
||||
//! \param length Length of the buffer
|
||||
//! \param callback Optional pointer to a callback function to invoke when
|
||||
//! the operation is finished
|
||||
//! \param argument Optional pointer to an argument for the callback
|
||||
//! \return Operation result code
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDSdusb_Read(Media *media,
|
||||
unsigned int address,
|
||||
void *data,
|
||||
unsigned int length,
|
||||
MediaCallback callback,
|
||||
void *argument)
|
||||
{
|
||||
MEDTransfer * pXfr;
|
||||
unsigned char error;
|
||||
|
||||
TRACE_INFO_WP("SDuRd(%d,%d) ", (int)address, (int)length);
|
||||
|
||||
// Check that the media is ready
|
||||
if (media->state != MED_STATE_READY) {
|
||||
TRACE_INFO("MEDSdusb_Read: Busy\n\r");
|
||||
return MED_STATUS_BUSY;
|
||||
}
|
||||
// Check that the data to read is not too big
|
||||
if ((length + address) > media->size) {
|
||||
TRACE_WARNING("MEDSdusb_Read: Data too big: %d, %d\n\r",
|
||||
(int)length, (int)address);
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
// Enter Busy state
|
||||
media->state = MED_STATE_BUSY;
|
||||
|
||||
// Start media transfer
|
||||
pXfr = &media->transfer;
|
||||
pXfr->data = data;
|
||||
pXfr->address = address;
|
||||
pXfr->length = length;
|
||||
pXfr->callback = callback;
|
||||
pXfr->argument = argument;
|
||||
|
||||
/* TODO BSS error = SD_Read((SdCard*)media->interface,
|
||||
address,
|
||||
data,
|
||||
length,
|
||||
SdMmcCallback,
|
||||
media); */
|
||||
|
||||
return (error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
//! \brief Writes data on a SDRAM media
|
||||
//! \param media Pointer to a Media instance
|
||||
//! \param address Address at which to write
|
||||
//! \param data Pointer to the data to write
|
||||
//! \param length Size of the data buffer
|
||||
//! \param callback Optional pointer to a callback function to invoke when
|
||||
//! the write operation terminates
|
||||
//! \param argument Optional argument for the callback function
|
||||
//! \return Operation result code
|
||||
//! \see Media
|
||||
//! \see MediaCallback
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char MEDSdusb_Write(Media *media,
|
||||
unsigned int address,
|
||||
void *data,
|
||||
unsigned int length,
|
||||
MediaCallback callback,
|
||||
void *argument)
|
||||
{
|
||||
MEDTransfer * pXfr;
|
||||
unsigned char error;
|
||||
TRACE_INFO_WP("SDuWr(%d,%d) ", (int)address, (int)length);
|
||||
|
||||
// Check that the media if ready
|
||||
if (media->state != MED_STATE_READY)
|
||||
{
|
||||
TRACE_INFO("MEDSdusb_Write: Busy\n\r");
|
||||
return MED_STATUS_BUSY;
|
||||
}
|
||||
|
||||
// Check that the data to write is not too big
|
||||
if ((length + address) > media->size)
|
||||
{
|
||||
TRACE_WARNING("MEDSdcard_Write: Data too big\n\r");
|
||||
return MED_STATUS_ERROR;
|
||||
}
|
||||
// Put the media in Busy state
|
||||
media->state = MED_STATE_BUSY;
|
||||
|
||||
// Start media transfer
|
||||
pXfr = &media->transfer;
|
||||
pXfr->data = data;
|
||||
pXfr->address = address;
|
||||
pXfr->length = length;
|
||||
pXfr->callback = callback;
|
||||
pXfr->argument = argument;
|
||||
|
||||
/* TODO BSS error = SD_Write((SdCard*)media->interface,
|
||||
address,
|
||||
data,
|
||||
length,
|
||||
SdMmcCallback,
|
||||
media); */
|
||||
|
||||
return (error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
/// Detect if there is SD card in socket
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MEDSdcard_Detect( Media * media, unsigned char mciID )
|
||||
{
|
||||
return CardIsConnected( ) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes a Media instance and the associated physical interface
|
||||
/// \param media Pointer to the Media instance to initialize
|
||||
/// \return 1 if success.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID)
|
||||
{
|
||||
TRACE_INFO("MEDSdcard init\n\r");
|
||||
|
||||
// Initialize SDcard
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
if ( !CardIsConnected( ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Configure SDcard pins
|
||||
// ConfigurePIO(mciID);
|
||||
|
||||
#if defined(MCI2_INTERFACE)
|
||||
// DMAD_Initialize(BOARD_MCI_DMA_CHANNEL, DMAD_NO_DEFAULT_IT);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Initialize the MCI driver
|
||||
if ( mciID == 0 )
|
||||
{
|
||||
IRQ_ConfigureIT(BOARD_SD_MCI_ID, 1, MCI0_IrqHandler);
|
||||
MCI_Init(mciDrv, BOARD_SD_MCI_BASE, BOARD_SD_MCI_ID, BOARD_SD_SLOT, BOARD_MCK );
|
||||
IRQ_EnableIT(BOARD_SD_MCI_ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef BOARD_SD_MCI1_ID
|
||||
IRQ_ConfigureIT(BOARD_SD_MCI1_ID, 1, MCI0_IrqHandler);
|
||||
MCI_Init(mciDrv, BOARD_SD_MCI1_BASE, BOARD_SD_MCI1_ID, BOARD_SD_MCI1_SLOT, BOARD_MCK );
|
||||
IRQ_EnableIT(BOARD_SD_MCI1_ID);
|
||||
#else
|
||||
TRACE_ERROR("SD/MMC card initialization failed (MCI1 not supported)\n\r");
|
||||
#endif
|
||||
}
|
||||
#if MCI_BUSY_CHECK_FIX && defined(BOARD_SD_DAT0)
|
||||
MCI_SetBusyFix(mciDrv, &pinSdDAT0);
|
||||
#endif
|
||||
|
||||
// Initialize the SD card driver
|
||||
if (SD_Init(sdDrv, (SdDriver *)mciDrv))
|
||||
{
|
||||
TRACE_ERROR("SD/MMC card initialization failed\n\r");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//SD_DisplayRegisterCSD(&sdDrv);
|
||||
TRACE_INFO("SD/MMC card initialization successful\n\r");
|
||||
TRACE_INFO("Card size: %d MB\n\r", (int)(MMC_GetTotalSizeKB(sdDrv)/1024));
|
||||
}
|
||||
MCI_SetSpeed(mciDrv, sdDrv->transSpeed, sdDrv->transSpeed, BOARD_MCK);
|
||||
#endif
|
||||
|
||||
// Initialize media fields
|
||||
//--------------------------------------------------------------------------
|
||||
// media->interface = sdDrv;
|
||||
#if !defined(OP_BOOTSTRAP_MCI_on)
|
||||
media->write = MEDSdcard_Write;
|
||||
#else
|
||||
media->write = 0;
|
||||
#endif
|
||||
media->read = MEDSdcard_Read;
|
||||
media->lock = 0;
|
||||
media->unlock = 0;
|
||||
media->handler = 0;
|
||||
media->flush = 0;
|
||||
|
||||
media->blockSize = SD_BLOCK_SIZE;
|
||||
media->baseAddress = 0;
|
||||
media->size = SD_BLOCK_SIZE * 1000; // TODO BSS SD_TOTAL_BLOCK(sdDrv);
|
||||
|
||||
media->mappedRD = 0;
|
||||
media->mappedWR = 0;
|
||||
media->protected = 0; // TODO BSS CardIsProtected(mciID);
|
||||
media->removable = 1;
|
||||
|
||||
media->state = MED_STATE_READY;
|
||||
|
||||
media->transfer.data = 0;
|
||||
media->transfer.address = 0;
|
||||
media->transfer.length = 0;
|
||||
media->transfer.callback = 0;
|
||||
media->transfer.argument = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes a Media instance and the associated physical interface
|
||||
/// \param media Pointer to the Media instance to initialize
|
||||
/// \return 1 if success.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MEDSdusb_Initialize(Media *media, unsigned char mciID)
|
||||
{
|
||||
TRACE_INFO("MEDSdusb init\n\r");
|
||||
|
||||
// Initialize SDcard
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
if (!CardIsConnected()) return 0;
|
||||
#if 0
|
||||
// Configure SDcard pins
|
||||
ConfigurePIO(mciID);
|
||||
|
||||
#if defined(MCI2_INTERFACE)
|
||||
DMAD_Initialize(BOARD_MCI_DMA_CHANNEL, DMAD_NO_DEFAULT_IT);
|
||||
#endif
|
||||
// Initialize the MCI driver
|
||||
if ( mciID == 0 )
|
||||
{
|
||||
IRQ_ConfigureIT(BOARD_SD_MCI_ID, 1, MCI0_IrqHandler);
|
||||
MCI_Init(mciDrv, BOARD_SD_MCI_BASE, BOARD_SD_MCI_ID, BOARD_SD_SLOT, BOARD_MCK );
|
||||
IRQ_EnableIT(BOARD_SD_MCI_ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef BOARD_SD_MCI1_ID
|
||||
IRQ_ConfigureIT(BOARD_SD_MCI1_ID, 1, MCI0_IrqHandler);
|
||||
MCI_Init(mciDrv, BOARD_SD_MCI1_BASE, BOARD_SD_MCI1_ID, BOARD_SD_SLOT, BOARD_MCK );
|
||||
IRQ_EnableIT(BOARD_SD_MCI1_ID);
|
||||
#else
|
||||
TRACE_ERROR("SD/MMC card initialization failed (MCI1 not supported)\n\r");
|
||||
#endif
|
||||
}
|
||||
#if MCI_BUSY_CHECK_FIX && defined(BOARD_SD_DAT0)
|
||||
MCI_SetBusyFix(mciDrv, &pinSdDAT0);
|
||||
#endif
|
||||
|
||||
// Initialize the SD card driver
|
||||
if (SD_Init(sdDrv, (SdDriver *)mciDrv))
|
||||
{
|
||||
TRACE_ERROR("SD/MMC card initialization failed\n\r");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_INFO("SD/MMC card initialization successful\n\r");
|
||||
TRACE_INFO("Card size: %d MB\n\r", (int)(MMC_GetTotalSizeKB(sdDrv)/1024));
|
||||
}
|
||||
MCI_SetSpeed(mciDrv, sdDrv->transSpeed, sdDrv->transSpeed, BOARD_MCK);
|
||||
#endif
|
||||
// Initialize media fields
|
||||
//--------------------------------------------------------------------------
|
||||
//media->interface = sdDrv;
|
||||
media->write = MEDSdusb_Write;
|
||||
media->read = MEDSdusb_Read;
|
||||
media->lock = 0;
|
||||
media->unlock = 0;
|
||||
media->handler = 0;
|
||||
media->flush = 0;
|
||||
|
||||
media->blockSize = SD_BLOCK_SIZE;
|
||||
media->baseAddress = 0;
|
||||
media->size = 1024*1024; // TODO BSS SD_TOTAL_BLOCK(sdDrv);
|
||||
|
||||
media->mappedRD = 0;
|
||||
media->mappedWR = 0;
|
||||
media->protectedd = false; // TODO BSS CardIsProtected(mciID);
|
||||
media->removable = 1;
|
||||
|
||||
media->state = MED_STATE_READY;
|
||||
|
||||
media->transfer.data = 0;
|
||||
media->transfer.address = 0;
|
||||
media->transfer.length = 0;
|
||||
media->transfer.callback = 0;
|
||||
media->transfer.argument = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
/// erase all the Sdcard
|
||||
/// \param media Pointer to the Media instance to initialize
|
||||
//------------------------------------------------------------------------------
|
||||
void MEDSdcard_EraseAll(Media *media)
|
||||
{
|
||||
unsigned char buffer[SD_BLOCK_SIZE];
|
||||
unsigned int block;
|
||||
unsigned int multiBlock = 1; // change buffer size for multiblocks
|
||||
unsigned char error;
|
||||
|
||||
TRACE_INFO("MEDSdcard Erase All ...\n\r");
|
||||
|
||||
// Clear the block buffer
|
||||
memset(buffer, 0, media->blockSize * multiBlock);
|
||||
|
||||
for (block=0;
|
||||
block < (SD_TOTAL_BLOCK((SdCard*)media->interface)-multiBlock);
|
||||
block += multiBlock)
|
||||
{
|
||||
// TODO BSS error = SD_WriteBlock((SdCard*)media->interface, block, multiBlock, buffer);
|
||||
assert( !error ); /* "\n\r-F- Failed to write block (%d) #%u\n\r", error, block */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// erase block
|
||||
/// \param media Pointer to the Media instance to initialize
|
||||
/// \param block to erase
|
||||
//------------------------------------------------------------------------------
|
||||
#if 0
|
||||
void MEDSdcard_EraseBlock(Media *media, unsigned int block)
|
||||
{
|
||||
unsigned char buffer[SD_BLOCK_SIZE];
|
||||
unsigned char error;
|
||||
|
||||
// Clear the block buffer
|
||||
memset(buffer, 0, media->blockSize);
|
||||
|
||||
// TODO BSS error = SD_WriteBlock((SdCard*)media->interface, block, 1, buffer);
|
||||
assert( !error ) ; /* "\n\r-F- Failed to write block (%d) #%u\n\r", error, block */
|
||||
}
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
/// Get driver pointer
|
||||
//------------------------------------------------------------------------------
|
||||
#if 0
|
||||
SdCard* MEDSdcard_GetDriver( unsigned int slot )
|
||||
{
|
||||
if (slot >= NUM_SD_SLOTS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &sdDrv[slot];
|
||||
}
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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 different memory access APIs and drivers
|
||||
///
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -1,263 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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(
|
||||
struct EccNandFlash *ecc,
|
||||
unsigned short block,
|
||||
unsigned short page,
|
||||
void *data,
|
||||
void *spare)
|
||||
{
|
||||
unsigned char error;
|
||||
unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
|
||||
unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
|
||||
unsigned char *pDataBuffer;
|
||||
unsigned char *pSpareBuffer;
|
||||
|
||||
TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);
|
||||
|
||||
pDataBuffer = (data) ? data : RawNandFlash_GetDataBuffer(RAW(ecc));
|
||||
pSpareBuffer = (spare) ? spare : RawNandFlash_GetSpareBuffer(RAW(ecc));
|
||||
|
||||
#ifndef HARDWARE_ECC
|
||||
// Start by reading the spare and the data
|
||||
error = RawNandFlash_ReadPage(RAW(ecc), block, page, pDataBuffer, pSpareBuffer);
|
||||
if (error) {
|
||||
TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
|
||||
block, page);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Retrieve ECC information from page and verify the data
|
||||
NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), pSpareBuffer, ecc->hamming);
|
||||
error = Hamming_Verify256x(pDataBuffer, pageDataSize, ecc->hamming);
|
||||
#else
|
||||
error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, tmpSpare);
|
||||
if (error) {
|
||||
TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
|
||||
block, page);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Retrieve ECC information from page
|
||||
NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, ecc->hsiaoInSpare);
|
||||
HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
|
||||
// Verify the data
|
||||
error = HSMC4_VerifyHsiao((unsigned char*) data,
|
||||
pageDataSize,
|
||||
ecc->hsiaoInSpare,
|
||||
ecc->hsiao,
|
||||
NandFlashModel_GetDataBusWidth(MODEL(ecc)));
|
||||
#endif
|
||||
if (error && (error != Hamming_ERROR_SINGLEBIT)) {
|
||||
error = NandCommon_ERROR_CORRUPTEDDATA;
|
||||
TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
|
||||
block, page);
|
||||
goto error;
|
||||
}
|
||||
#ifndef HARDWARE_ECC
|
||||
#else
|
||||
if (spare) {
|
||||
|
||||
memcpy(spare, pSpareBuffer, pageSpareSize);
|
||||
}
|
||||
#endif
|
||||
error:
|
||||
if (data == (unsigned char *) 0)
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(ecc));
|
||||
if (spare == (unsigned char *) 0)
|
||||
RawNandFlash_ReleaseSpareBuffer(RAW(ecc));
|
||||
return error;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Writes the data and/or spare area of a nandflash page, after calculating an
|
||||
/// ECC for the data area and storing it in the spare. If no data buffer is
|
||||
/// provided, the ECC is read from the existing page spare. If no spare buffer
|
||||
/// is provided, the spare area is still written with the ECC information
|
||||
/// calculated on the data buffer.
|
||||
/// Returns 0 if successful; otherwise returns an error code.
|
||||
/// \param ecc Pointer to an EccNandFlash instance.
|
||||
/// \param block Number of the block to write in.
|
||||
/// \param page Number of the page to write inside the given block.
|
||||
/// \param data Data area buffer, can be 0.
|
||||
/// \param spare Spare area buffer, can be 0.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char EccNandFlash_WritePage(
|
||||
struct EccNandFlash *ecc,
|
||||
unsigned short block,
|
||||
unsigned short page,
|
||||
void *data,
|
||||
void *spare)
|
||||
{
|
||||
unsigned char error;
|
||||
unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
|
||||
unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
|
||||
unsigned char *pSpareBuffer = RawNandFlash_GetSpareBuffer(RAW(ecc));
|
||||
|
||||
ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r");
|
||||
TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);
|
||||
#ifndef HARDWARE_ECC
|
||||
// Compute ECC on the new data, if provided
|
||||
// If not provided, hamming code set to 0xFFFF.. to keep existing bytes
|
||||
memset(ecc->hamming, 0xFF, NandCommon_MAXSPAREECCBYTES);
|
||||
if (data) {
|
||||
|
||||
// Compute hamming code on data
|
||||
Hamming_Compute256x(data, pageDataSize, ecc->hamming);
|
||||
}
|
||||
|
||||
// Store code in spare buffer (if no buffer provided, use a temp. one)
|
||||
if (!spare) {
|
||||
|
||||
spare = pSpareBuffer;
|
||||
memset(spare, 0xFF, pageSpareSize);
|
||||
}
|
||||
NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, ecc->hamming);
|
||||
|
||||
// Perform write operation
|
||||
error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
#else
|
||||
// Store code in spare buffer (if no buffer provided, use a temp. one)
|
||||
if (!spare) {
|
||||
spare = pSpareBuffer;
|
||||
memset(spare, 0xFF, pageSpareSize);
|
||||
}
|
||||
// Perform write operation
|
||||
error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
|
||||
// Perform write operation
|
||||
NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao);
|
||||
error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare);
|
||||
if (error)
|
||||
goto error;
|
||||
#endif
|
||||
RawNandFlash_ReleaseSpareBuffer(RAW(ecc));
|
||||
return 0;
|
||||
|
||||
error:
|
||||
RawNandFlash_ReleaseSpareBuffer(RAW(ecc));
|
||||
TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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;
|
||||
#ifndef HARDWARE_ECC
|
||||
unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
|
||||
#else
|
||||
unsigned char hsiaoInSpare[NandCommon_MAXSPAREECCBYTES];
|
||||
unsigned char hsiao[NandCommon_MAXSPAREECCBYTES];
|
||||
#endif
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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(
|
||||
struct EccNandFlash *ecc,
|
||||
unsigned short block,
|
||||
unsigned short page,
|
||||
void *data,
|
||||
void *spare);
|
||||
|
||||
extern unsigned char EccNandFlash_WritePage(
|
||||
struct EccNandFlash *ecc,
|
||||
unsigned short block,
|
||||
unsigned short page,
|
||||
void *data,
|
||||
void *spare);
|
||||
|
||||
#endif //#ifndef ECCNANDFLASH_H
|
||||
|
||||
@@ -1,860 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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;
|
||||
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));
|
||||
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) {
|
||||
|
||||
TRACE_ERROR("Block #%d(%d) is not managed\n\r", block, phyBlock);
|
||||
return NandCommon_ERROR_NOMAPPING;
|
||||
}
|
||||
// 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 *pDataBuffer = RawNandFlash_GetDataBuffer(RAW(managed));
|
||||
unsigned char *pSpareBuffer = RawNandFlash_GetSpareBuffer(RAW(managed));
|
||||
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) {
|
||||
|
||||
|
||||
// Read data & spare to copy
|
||||
error = EccNandFlash_ReadPage(ECC(managed),
|
||||
managed->baseBlock + sourceBlock,
|
||||
sourcePage,
|
||||
pDataBuffer, pSpareBuffer);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
// Write destination block status information in spare
|
||||
NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)),
|
||||
pSpareBuffer,
|
||||
&(managed->blockStatuses[destBlock]),
|
||||
4,
|
||||
0);
|
||||
|
||||
// Write page
|
||||
error = RawNandFlash_WritePage(RAW(managed),
|
||||
managed->baseBlock + destBlock,
|
||||
destPage,
|
||||
pDataBuffer, pSpareBuffer);
|
||||
if (error)
|
||||
goto error;
|
||||
}
|
||||
// Otherwise, a normal copy can be done
|
||||
else {
|
||||
|
||||
error = RawNandFlash_CopyPage(RAW(managed),
|
||||
managed->baseBlock + sourceBlock,
|
||||
sourcePage,
|
||||
managed->baseBlock + destBlock,
|
||||
destPage);
|
||||
}
|
||||
|
||||
error:
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(managed));
|
||||
RawNandFlash_ReleaseSpareBuffer(RAW(managed));
|
||||
return error;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// 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;
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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
|
||||
|
||||
@@ -1,666 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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 *pDataBuffer = RawNandFlash_GetDataBuffer(RAW(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, pDataBuffer, 0);
|
||||
if (!error) {
|
||||
|
||||
// Compare data with logical mapping pattern
|
||||
i = 0;
|
||||
found = 1;
|
||||
while ((i < pageDataSize) && found) {
|
||||
|
||||
if (pDataBuffer[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;
|
||||
}
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(mapped));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (error != NandCommon_ERROR_WRONGSTATUS) {
|
||||
|
||||
TRACE_ERROR(
|
||||
"FindLogicalMappingBlock: Failed to scan block #%d\n\r",
|
||||
block);
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(mapped));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
block++;
|
||||
}
|
||||
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(mapped));
|
||||
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 short pageDataSize =
|
||||
NandFlashModel_GetPageDataSize(MODEL(mapped));
|
||||
unsigned short numBlocks =
|
||||
ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
|
||||
unsigned char *pDataBuffer = RawNandFlash_GetDataBuffer(RAW(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,
|
||||
pDataBuffer,
|
||||
0);
|
||||
if (error) {
|
||||
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(mapped));
|
||||
TRACE_ERROR(
|
||||
"LoadLogicalMapping: Failed to load mapping\n\r");
|
||||
return error;
|
||||
}
|
||||
|
||||
// Copy page info
|
||||
memcpy(currentBuffer, pDataBuffer, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(mapped));
|
||||
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 char *pDataBuffer;
|
||||
//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;
|
||||
}
|
||||
pDataBuffer = RawNandFlash_GetDataBuffer(RAW(mapped));
|
||||
|
||||
// Allocate new block
|
||||
error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
|
||||
if (error) {
|
||||
goto 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(pDataBuffer, 0xFF, pageDataSize);
|
||||
memcpy(pDataBuffer, currentBuffer, writeSize);
|
||||
error = ManagedNandFlash_WritePage(MANAGED(mapped),
|
||||
physicalBlock,
|
||||
currentPage,
|
||||
pDataBuffer,
|
||||
0);
|
||||
if (error) {
|
||||
TRACE_ERROR(
|
||||
"MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r");
|
||||
goto 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++) {
|
||||
|
||||
pDataBuffer[i] = PATTERN(i);
|
||||
}
|
||||
error = ManagedNandFlash_WritePage(MANAGED(mapped),
|
||||
physicalBlock, 0,
|
||||
pDataBuffer, 0);
|
||||
if (error) {
|
||||
TRACE_ERROR(
|
||||
"MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r");
|
||||
goto 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) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock);
|
||||
|
||||
error:
|
||||
RawNandFlash_ReleaseDataBuffer(RAW(mapped));
|
||||
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;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* \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
|
||||
|
||||
@@ -1,414 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* \brief 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.
|
||||
*
|
||||
* \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.
|
||||
* \return 0 if a matching model has been found; otherwise returns NandCommon_ERROR_UNKNOWNMODEL.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Translates address/size access of a NandFlashModel to block, page and offset values.
|
||||
*
|
||||
* \param modelList List of NandFlashModel instances.
|
||||
* \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.
|
||||
* \return 0 if the access is correct; otherwise returns NandCommon_ERROR_OUTOFBOUNDS.
|
||||
* \note The values are stored in the provided variables if their pointer is not 0.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the size of the data area of a page in bytes.
|
||||
* take into account the spare zones size.
|
||||
*
|
||||
* \param model Pointer to a NandFlashModel instance.
|
||||
*/
|
||||
unsigned short NandFlashModel_GetPageDataSize(
|
||||
const struct NandFlashModel *model)
|
||||
{
|
||||
return model->pageSizeInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the given NandFlash model uses the "small blocks/pages"
|
||||
*
|
||||
* \param model Pointer to a NandFlashModel instance.
|
||||
* \return 1 if the model uses the "small blocks/pages"; otherwise return 0.
|
||||
*/
|
||||
unsigned char NandFlashModel_HasSmallBlocks(
|
||||
const struct NandFlashModel *model)
|
||||
{
|
||||
return (model->pageSizeInBytes <= 512 )? 1: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if if the device supports the copy-back operation.
|
||||
*
|
||||
* \param model Pointer to a NandFlashModel instance.
|
||||
* \return 1 if the model supports the copy-back operation; otherwise return 0.
|
||||
*/
|
||||
unsigned char NandFlashModel_SupportsCopyBack(
|
||||
const struct NandFlashModel *model)
|
||||
{
|
||||
return ((model->options & NandFlashModel_COPYBACK) != 0);
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \par Purpose
|
||||
*
|
||||
* Type and methods for manipulating NandFlash models.
|
||||
*
|
||||
* \par 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
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Static array of the various NandFlashModels which are supported.
|
||||
*
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* 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},
|
||||
};
|
||||
@@ -1,66 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \par Purpose
|
||||
*
|
||||
* Static array of the various NandFlashModels which are supported.
|
||||
*
|
||||
* \par 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
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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>
|
||||
#ifdef DMA_TRANSFER
|
||||
#include <dma/dma.h>
|
||||
#include <dmad/dmad.h>
|
||||
#endif
|
||||
#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 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)
|
||||
{
|
||||
#ifdef DMA_TRANSFER
|
||||
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++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/// 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)
|
||||
{
|
||||
|
||||
#ifdef DMA_TRANSFER
|
||||
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++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// 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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,840 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* SkipBlockNandFlash layer supplies application a set of interface to operate nandflash.
|
||||
*
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "RawNandFlash.h"
|
||||
#include "NandCommon.h"
|
||||
#include "NandFlashModelList.h"
|
||||
#include <pio/pio_it.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
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
while (pageDataSize > 0) {
|
||||
|
||||
if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
|
||||
WRITE_ADDRESS16(raw, columnAddress & 0xFF);
|
||||
}
|
||||
else {
|
||||
WRITE_ADDRESS(raw, columnAddress & 0xFF);
|
||||
}
|
||||
pageDataSize >>= 8;
|
||||
columnAddress >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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) {
|
||||
PIO_EnableIt(&(raw->pinReadyBusy));
|
||||
|
||||
while (!PIO_Get(&(raw->pinReadyBusy)));
|
||||
//if (!PIO_Get(&(raw->pinReadyBusy)) {
|
||||
|
||||
//}
|
||||
}
|
||||
else {
|
||||
WRITE_COMMAND(raw, COMMAND_STATUS);
|
||||
while ((READ_DATA8(raw) & STATUS_READY) != STATUS_READY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check for program or erase operation is completed.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \return 1 operation is completed; otherwise, return 0.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sends data to the NandFlash chip from the provided buffer.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads data from the NandFlash chip into the provided buffer.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param buffer Buffer where the data will be stored.
|
||||
* \param size Number of bytes that will be written.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Erases the specified block of the device.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param block Number of the physical block to erase.
|
||||
* \return 0 if successful; otherwise returns an error code.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes the data and/or the spare area of a page on a NandFlash chip.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param block Number of the physical block to erase.
|
||||
* \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.
|
||||
* \return 0 if successful; otherwise returns an error code.
|
||||
* \note If one of the buffer pointer is 0, the corresponding area is not written.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Copies the data in a page of the NandFlash device to an other page on that same chip.
|
||||
*
|
||||
* \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.
|
||||
* \return 0 if successful; otherwise returns an error code.
|
||||
* \note Both pages must have be even or odd; it is not possible to copy
|
||||
* and even page to an odd page and vice-versa.
|
||||
*/
|
||||
static unsigned char CopyPage(
|
||||
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
|
||||
if (RawNandFlash_ReadPage(raw, sourceBlock, sourcePage, RawNandFlash_GetDataBuffer(raw), RawNandFlash_GetSpareBuffer(raw))) {
|
||||
|
||||
TRACE_ERROR("CopyPage: Failed to read page to copy\n\r");
|
||||
error = NandCommon_ERROR_CANNOTREAD;
|
||||
}
|
||||
else if (RawNandFlash_WritePage(raw, destBlock, destPage, RawNandFlash_GetDataBuffer(raw), RawNandFlash_GetSpareBuffer(raw))) {
|
||||
|
||||
TRACE_ERROR("CopyPage: Failed to write dest. page\n\r");
|
||||
error = NandCommon_ERROR_CANNOTWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Exported functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* \brief Initializes a RawNandFlash instance based on the given model and physical interface.
|
||||
*
|
||||
* \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.
|
||||
* \return 0 if successful; otherwise returns NandCommon_ERROR_UNKNOWNMODEL.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
raw->dataLock = 0;
|
||||
raw->spareLock = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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_COMMAND(raw, COMMAND_RESET);
|
||||
//WRITE_COMMAND16(raw, COMMAND_RESET);
|
||||
WaitReady(raw);
|
||||
DISABLE_CE(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Erases the specified block of the device, retrying several time if it fails.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param block Number of the physical block to erase.
|
||||
* \return 0 if successful; otherwise returns NandCommon_ERROR_UNKNOWNMODEL.
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads the data and/or the spare areas of a page of a NandFlash into the provided buffers.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param block Number of the physical block to read.
|
||||
* \param page Number of the page to read inside the given block.
|
||||
* \param data Buffer where the data area will be read.
|
||||
* \param spare Buffer where the spare area will be read.
|
||||
* \return 0 if successful; otherwise returns 1.
|
||||
* \note If one of the buffer pointer is 0, the corresponding area is not read.
|
||||
*/
|
||||
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");
|
||||
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) {
|
||||
|
||||
WRITE_COMMAND(raw, COMMAND_READ_A);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes the data and/or the spare areas of a page of a NandFlash into the provided buffers.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param block Number of the physical block to write resides.
|
||||
* \param page Number of the page to write inside the given block.
|
||||
* \param data Buffer where the data area will be stored.
|
||||
* \param spare Buffer where the spare area will be stored.
|
||||
* \return 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
|
||||
* \note If one of the buffer pointer is 0, the corresponding area is not written.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Copy the data in a page of the NandFlash device to an other page on that same chip.
|
||||
*
|
||||
* \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.
|
||||
* \return 0 if successful; otherwise returns an NandCommon_ERROR_BADBLOCK.
|
||||
* \note Both pages must have be even or odd; it is not possible to copy
|
||||
* and even page to an odd page and vice-versa.
|
||||
*/
|
||||
unsigned char RawNandFlash_CopyPage(
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Copies the data of one whole block of a NandFlash device to another block.
|
||||
*
|
||||
* \param raw Pointer to a RawNandFlash instance.
|
||||
* \param sourceBlock Source block number.
|
||||
* \param destBlock Destination block number.
|
||||
* \return 0 if successful; otherwise returns an NandCommon_ERROR_BADBLOCK.
|
||||
*/
|
||||
unsigned char RawNandFlash_CopyBlock(
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char *RawNandFlash_GetDataBuffer(
|
||||
struct RawNandFlash *raw)
|
||||
{
|
||||
ASSERT(raw->dataLock == 0, "Data buffer is busy\n\r")
|
||||
raw->dataLock = 1;
|
||||
return raw->tmpData;
|
||||
}
|
||||
|
||||
void RawNandFlash_ReleaseDataBuffer(
|
||||
struct RawNandFlash *raw)
|
||||
{
|
||||
ASSERT(raw->dataLock == 1, "Data buffer is not busy\n\r")
|
||||
raw->dataLock = 0;
|
||||
}
|
||||
|
||||
unsigned char *RawNandFlash_GetSpareBuffer(
|
||||
struct RawNandFlash *raw)
|
||||
{
|
||||
ASSERT(raw->spareLock == 0, "Spare buffer is busy\n\r")
|
||||
raw->spareLock = 1;
|
||||
return raw->tmpSpare;
|
||||
}
|
||||
|
||||
void RawNandFlash_ReleaseSpareBuffer(
|
||||
struct RawNandFlash *raw)
|
||||
{
|
||||
ASSERT(raw->spareLock == 1, "Spare buffer is not busy\n\r")
|
||||
raw->spareLock = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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 RAWNANDFLASH_H
|
||||
#define RAWNANDFLASH_H
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "NandFlashModel.h"
|
||||
#include "NandCommon.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;
|
||||
|
||||
unsigned char dataLock;
|
||||
unsigned char spareLock;
|
||||
unsigned char tmpData[NandCommon_MAXPAGEDATASIZE];
|
||||
unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* 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(
|
||||
struct RawNandFlash *raw,
|
||||
unsigned short sourceBlock,
|
||||
unsigned short sourcePage,
|
||||
unsigned short destBlock,
|
||||
unsigned short destPage);
|
||||
|
||||
extern unsigned char RawNandFlash_CopyBlock(
|
||||
struct RawNandFlash *raw,
|
||||
unsigned short sourceBlock,
|
||||
unsigned short destBlock);
|
||||
|
||||
extern unsigned char *RawNandFlash_GetDataBuffer(struct RawNandFlash *raw);
|
||||
extern void RawNandFlash_ReleaseDataBuffer(struct RawNandFlash *raw);
|
||||
extern unsigned char *RawNandFlash_GetSpareBuffer(struct RawNandFlash *raw);
|
||||
extern void RawNandFlash_ReleaseSpareBuffer(struct RawNandFlash *raw);
|
||||
|
||||
|
||||
#endif //#ifndef RAWNANDFLASH_H
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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)
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Exported functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* \brief Check if the given block of a nandflash device is bad.
|
||||
*
|
||||
* \param skipBlock Pointer to a SkipBlockNandFlash instance.
|
||||
* \param block Number of block to check.
|
||||
* \return GOODBLOCK if the block is good; or returns a NandCommon_ERROR code.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Erases a block of a SkipBlock NandFlash.
|
||||
*
|
||||
* \param skipBlock Pointer to a SkipBlockNandFlash instance.
|
||||
* \param block Number of block to erase.
|
||||
* \return the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Reads the data and/or the spare area of a page on a SkipBlock nandflash.
|
||||
*
|
||||
* \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.
|
||||
* \note If one of the buffer pointer is 0, then the block MUST not be BAD.
|
||||
* \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage().
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads the data of a whole block on a SkipBlock nandflash.
|
||||
*
|
||||
* \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.
|
||||
* \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage().
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes the data and/or spare area of a page on a SkipBlock NandFlash.
|
||||
*
|
||||
* \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.
|
||||
* \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes the data of a whole block on a SkipBlock nandflash.
|
||||
*
|
||||
* \param skipBlock Pointer to a SkipBlockNandFlash instance.
|
||||
* \param block Number of the block to write.
|
||||
* \param data Data area buffer.
|
||||
* \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes the data of a whole block on a SkipBlock nandflash.
|
||||
*
|
||||
* \param skipBlock Pointer to a SkipBlockNandFlash instance.
|
||||
* \param block Number of the block to write.
|
||||
* \param pageOffsetInBlock Number of the page to write inside the given block.
|
||||
* \param data Data area buffer.
|
||||
* \param numPages number of pages to write.
|
||||
* \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
|
||||
*/
|
||||
unsigned char SkipBlockNandFlash_WriteBlockUnaligned(
|
||||
const struct SkipBlockNandFlash *skipBlock,
|
||||
unsigned short block,
|
||||
unsigned short pageOffsetInBlock,
|
||||
unsigned short numPages,
|
||||
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));
|
||||
|
||||
for (i = pageOffsetInBlock; i < pageOffsetInBlock + numPages; i++) {
|
||||
error = SkipBlockNandFlash_WritePage(skipBlock, block, i, data, 0);
|
||||
if (error == NandCommon_ERROR_BADBLOCK) {
|
||||
|
||||
TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Block is BAD.\n\r");
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read the data of a whole block on a SkipBlock nandflash.
|
||||
*
|
||||
* \param skipBlock Pointer to a SkipBlockNandFlash instance.
|
||||
* \param block Number of the block to read.
|
||||
* \param pageOffsetInBlock Number of the page to read inside the given block.
|
||||
* \param data Data area buffer.
|
||||
* \param numPages number of pages to read.
|
||||
* \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
|
||||
*/
|
||||
unsigned char SkipBlockNandFlash_ReadBlockUnaligned(
|
||||
const struct SkipBlockNandFlash *skipBlock,
|
||||
unsigned short block,
|
||||
unsigned short pageOffsetInBlock,
|
||||
unsigned short numPages,
|
||||
void *data
|
||||
)
|
||||
{
|
||||
// Number of pages per block
|
||||
unsigned int numPagesPerBlock;
|
||||
// Page size
|
||||
unsigned int pageSize;
|
||||
// Page index
|
||||
unsigned short i;
|
||||
// Error returned by SkipBlockNandFlash_ReadPage
|
||||
unsigned char error = 0;
|
||||
|
||||
// Retrieve model information
|
||||
pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
|
||||
numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));
|
||||
|
||||
for (i = pageOffsetInBlock; i < pageOffsetInBlock + numPages; i++) {
|
||||
error = SkipBlockNandFlash_ReadPage(skipBlock, block, i, data, 0);
|
||||
if (error == NandCommon_ERROR_BADBLOCK) {
|
||||
|
||||
TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
|
||||
return NandCommon_ERROR_BADBLOCK;
|
||||
}
|
||||
else if (error) {
|
||||
|
||||
TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
|
||||
return NandCommon_ERROR_CANNOTREAD;
|
||||
}
|
||||
data += pageSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
extern unsigned char SkipBlockNandFlash_WriteBlockUnaligned(
|
||||
const struct SkipBlockNandFlash *skipBlock,
|
||||
unsigned short block,
|
||||
unsigned short pageOffsetInBlock,
|
||||
unsigned short numPages,
|
||||
void *data
|
||||
);
|
||||
|
||||
extern unsigned char SkipBlockNandFlash_ReadBlockUnaligned(
|
||||
const struct SkipBlockNandFlash *skipBlock,
|
||||
unsigned short block,
|
||||
unsigned short pageOffsetInBlock,
|
||||
unsigned short numPages,
|
||||
void *data
|
||||
);
|
||||
|
||||
unsigned char SkipBlockNandFlash_WriteBlock(
|
||||
const struct SkipBlockNandFlash *skipBlock,
|
||||
unsigned short block,
|
||||
void *data);
|
||||
|
||||
|
||||
#endif //#ifndef SKIPBLOCKNANDFLASH_H
|
||||
|
||||
@@ -1,587 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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));
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* 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.
|
||||
//------------------------------------------------------------------------------
|
||||
+5
-12
@@ -3375,6 +3375,7 @@ MSDLun luns[MAX_LUNS];
|
||||
|
||||
char usbState;
|
||||
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes a Media instance and the associated physical interface
|
||||
/// \param media Pointer to the Media instance to initialize
|
||||
@@ -3493,24 +3494,15 @@ uint8_t MEDSdcard_Initialize(Media *media, uint8_t mciID)
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void MSDCallbacks_Data( unsigned char flowDirection, unsigned int dataLength,
|
||||
unsigned int fifoNullCount, unsigned int fifoFullCount )
|
||||
{
|
||||
TRACE_INFO("MSDCallbacks_Data\n\r");
|
||||
/* if ( flowDirection )
|
||||
{
|
||||
msdReadTotal += dataLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
msdWriteTotal += dataLength;
|
||||
}
|
||||
|
||||
msdFullCnt += fifoFullCount;
|
||||
msdNullCnt += fifoNullCount;*/
|
||||
}
|
||||
|
||||
unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID);
|
||||
|
||||
void usbMassStorage()
|
||||
{
|
||||
@@ -3583,7 +3575,8 @@ void menusTask(void * pdata)
|
||||
while (check_soft_power() != e_power_off) {
|
||||
#ifdef MASSSTORAGE
|
||||
if (PIOC->PIO_PDSR & PIO_PC25) {
|
||||
usbMassStorage();
|
||||
for (uint8_t i=0; i<10; i++)
|
||||
usbMassStorage();
|
||||
TRACE_DEBUG("Apres usbMassStorage\n\r");
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user