[sky9x] Massstorage (still not working, but we see the drive)

This commit is contained in:
bsongis
2012-09-12 05:30:06 +00:00
parent fcf6f436b0
commit 46a0fe8533
27 changed files with 627 additions and 7217 deletions
+5 -2
View File
@@ -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
+617
View File
@@ -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
View File
@@ -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