?? managednandflash.c
字號:
/* ----------------------------------------------------------------------------
* 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
//------------------------------------------------------------------------------
// Customn trace levels for the current file
#define DEBUG trace_DEBUG
#define INFO trace_INFO
#define IMPORTANT trace_FATAL
// 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.
//------------------------------------------------------------------------------
static unsigned char IsDeviceVirgin(const struct ManagedNandFlash *managed)
{
struct NandBlockStatus blockStatus;
const struct NandSpareScheme *scheme = NandFlashModel_GetScheme(MODEL(managed));
unsigned char spare[NandCommon_MAXPAGESPARESIZE];
unsigned char badBlockMarker;
unsigned char error;
// Read spare area of page #0
error = RawNandFlash_ReadPage(RAW(managed), 0, 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 Number of block to check.
//------------------------------------------------------------------------------
static unsigned char CheckBlock(
const struct ManagedNandFlash *managed,
unsigned short block)
{
unsigned char spare[NandCommon_MAXPAGESPARESIZE];
unsigned char error;
unsigned int i;
unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed));
// Read spare area of first page of block
error = RawNandFlash_ReadPage(RAW(managed), block, 0, 0, spare);
if (error) {
trace_LOG(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_LOG(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 Block number.
//------------------------------------------------------------------------------
static unsigned char WriteBlockStatus(
const struct ManagedNandFlash *managed,
unsigned short block)
{
unsigned char spare[NandCommon_MAXPAGESPARESIZE];
memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE);
NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)),
spare,
&(managed->blockStatuses[block]),
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.
//------------------------------------------------------------------------------
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 char error;
unsigned char spare[NandCommon_MAXPAGESPARESIZE];
unsigned int numBlocks;
unsigned int pageSpareSize;
const struct NandSpareScheme *scheme;
unsigned int block;
struct NandBlockStatus blockStatus;
unsigned char badBlockMarker;
unsigned int eraseCount, minEraseCount, maxEraseCount;
trace_LOG(DEBUG, "ManagedNandFlash_Initialize()\n\r");
// Initialize EccNandFlash
error = EccNandFlash_Initialize(ECC(managed),
model,
commandAddress,
addressAddress,
dataAddress,
pinChipEnable,
pinReadyBusy);
if (error) {
return error;
}
// Retrieve model information
numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(managed));
pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed));
scheme = NandFlashModel_GetScheme(MODEL(managed));
// Initialize block statuses
// First, check if device is virgin
if (IsDeviceVirgin(managed)) {
trace_LOG(IMPORTANT, "Device is virgin, doing initial block scanning ...\n\r");
// Perform initial scan of the device
for (block=0; block < numBlocks; block++) {
// Check if block is bad
error = CheckBlock(managed, block);
if (error == BADBLOCK) {
// Mark block as bad
trace_LOG(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_LOG(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, block);
if (error) {
trace_LOG(trace_ERROR,
"ManagedNandFlash_Initialize: Failed to write spare area\n\r");
return error;
}
}
else {
trace_LOG(trace_ERROR,
"ManagedNandFlash_Initialize: Cannot scan device\n\r");
return error;
}
}
}
else {
trace_LOG(DEBUG, "Device is already 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 < numBlocks; block++) {
// Read spare of first page
error = RawNandFlash_ReadPage(RAW(managed), block, 0, 0, spare);
if (error) {
trace_LOG(trace_ERROR,
"ManagedNandFlash_Initialize: Cannot retrieve info from block #%d\n\r",
block);
}
// 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_LOG(DEBUG, "Block #%d is bad\n\r", block);
managed->blockStatuses[block].status = NandBlockStatus_BAD;
}
// Check that block status is not default (meaning block is not managed)
else if (blockStatus.status == NandBlockStatus_DEFAULT) {
ASSERT(0, "Block #%d is not managed\n\r", block);
}
// Otherwise block status is accurate
else {
trace_LOG(DEBUG, "Block #%03d : status = %2d | eraseCount = %d\n\r",
block, 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_LOG(IMPORTANT, "|--------|------------|--------|--------|--------|\n\r");
trace_LOG(IMPORTANT, "| Wear | Count | Free | Live | Dirty |\n\r");
trace_LOG(IMPORTANT, "|--------|------------|--------|--------|--------|\n\r");
for (eraseCount=minEraseCount; eraseCount <= maxEraseCount; eraseCount++) {
unsigned int count = 0, live = 0, dirty = 0, free = 0;
for (block=0; block < numBlocks; 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_LOG(IMPORTANT, "| %4d | %8d | %4d | %4d | %4d |\n\r",
eraseCount, count, free, live, dirty);
}
}
trace_LOG(IMPORTANT, "|--------|------------|--------|--------|--------|\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.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -