📄 nandflash.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support - ROUSSET -
* ----------------------------------------------------------------------------
* Copyright (c) 2006, 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.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* 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 Name : nandflash.c
* Object :
* Creation : NLe Sep 28th 2006
*-----------------------------------------------------------------------------
*/
#include <includes.h>
#ifdef CFG_NANDFLASH
/*----------------------------------------------------------------------------*/
/* NAND Commands */
/*----------------------------------------------------------------------------*/
/* 8 bits devices */
#define WRITE_NAND_COMMAND(d) do{ *(volatile unsigned char *)((unsigned long)AT91C_SMARTMEDIA_BASE | AT91_SMART_MEDIA_CLE) = (unsigned char)(d); } while(0)
#define WRITE_NAND_ADDRESS(d) do{ *(volatile unsigned char *)((unsigned long)AT91C_SMARTMEDIA_BASE | AT91_SMART_MEDIA_ALE) = (unsigned char)(d); } while(0)
#define WRITE_NAND(d) do{ *(volatile unsigned char *)((unsigned long)AT91C_SMARTMEDIA_BASE) = (unsigned char)d; } while(0)
#define READ_NAND() ((unsigned char)(*(volatile unsigned char *)(unsigned long)AT91C_SMARTMEDIA_BASE))
/* 16 bits devices */
#define WRITE_NAND16(d) do{ *(volatile unsigned short *)((unsigned long)AT91C_SMARTMEDIA_BASE) = (unsigned short)d; } while(0)
#define READ_NAND16() ((volatile unsigned short)(*(volatile unsigned short *)(unsigned long)AT91C_SMARTMEDIA_BASE))
/*------------------------------------------------------------------------------*/
/* \fn AT91F_NandInit */
/* \brief Initialize NandFlash informations */
/* */
/* TCL_PAGE_BUF[1] = NF_NbBlocks */
/* TCL_PAGE_BUF[2] = NF_BlockSize */
/* TCL_PAGE_BUF[3] = NF_SectorSize */
/* TCL_PAGE_BUF[4] = NF_SpareSize */
/* TCL_PAGE_BUF[5] = NF_DataBusWidth */
/*------------------------------------------------------------------------------*/
static void AT91F_NandInit(PSNandInfo pNandInfo, PSNandInitInfo pNandInitInfo)
{
unsigned int uSectorSize, i=0;
pNandInfo->uNbBlocks = pNandInitInfo->uNandNbBlocks; /* Nb of blocks in device */
pNandInfo->uBlockNbData = pNandInitInfo->uNandBlockSize; /* Nb of DataBytes in a block */
pNandInfo->uDataNbBytes = pNandInitInfo->uNandSectorSize; /* Nb of bytes in data section */
pNandInfo->uSpareNbBytes = pNandInitInfo->uNandSpareSize; /* Nb of bytes in spare section */
pNandInfo->uSectorNbBytes = pNandInfo->uDataNbBytes +
pNandInfo->uSpareNbBytes; /* Total nb of bytes in a sector */
pNandInfo->uBlockNbSectors = pNandInfo->uBlockNbData / pNandInfo->uDataNbBytes; /* Nb of sector in a block */
pNandInfo->uBlockNbSpares = pNandInfo->uSpareNbBytes * pNandInfo->uBlockNbSectors; /* Nb of SpareBytes in a block */
pNandInfo->uBlockNbBytes = pNandInfo->uSectorNbBytes * pNandInfo->uBlockNbSectors; /* Total nb of bytes in a block */
pNandInfo->uNbSectors = pNandInfo->uBlockNbSectors * pNandInfo->uNbBlocks; /* Total nb of sectors in device */
pNandInfo->uNbData = pNandInfo->uBlockNbBytes * pNandInfo->uNbBlocks; /* Nb of DataBytes in device */
pNandInfo->uNbSpares = pNandInfo->uBlockNbSpares * pNandInfo->uNbBlocks; /* Nb of SpareBytes in device */
pNandInfo->uNbBytes = pNandInfo->uNbData + pNandInfo->uNbSpares; /* Total nb of bytes in device */
pNandInfo->uDataBusWidth = pNandInitInfo->uNandBusWidth; /* Data Bus Width (8/16 bits) */
uSectorSize = pNandInfo->uDataNbBytes - 1;
pNandInfo->uOffset = 0;
while (uSectorSize >> i)
{
pNandInfo->uOffset++;
i++;
}
}
/*------------------------------------------------------------------------------*/
/* \fn AT91F_NandReadID */
/* \brief Read Nand ID */
/*------------------------------------------------------------------------------*/
static PSNandInitInfo AT91F_NandReadID(void)
{
unsigned int uChipID, i=0;
unsigned char bManufacturerID, bDeviceID;
/* Enable chipset */
NAND_ENABLE_CE();
/* Ask the Nand its IDs */
WRITE_NAND_COMMAND(CMD_READID);
WRITE_NAND_ADDRESS(0x00);
/* Read answer */
bManufacturerID = READ_NAND();
bDeviceID = READ_NAND();
/* Disable chipset before returning */
NAND_DISABLE_CE();
uChipID = (bManufacturerID << 8) | bDeviceID;
/* Search in NandFlash_InitInfo[] */
while (NandFlash_InitInfo[i].uNandID != 0)
{
if (NandFlash_InitInfo[i].uNandID == uChipID)
return &NandFlash_InitInfo[i];
i++;
}
return 0;
}
/*------------------------------------------------------------------------------*/
/* \fn AT91F_NandEraseBlock0 */
/* \brief Erase Block 0 */
/*------------------------------------------------------------------------------*/
BOOL AT91F_NandEraseBlock0(void)
{
unsigned int uPhySecNb = 0;
BOOL bRet = TRUE;
/* Chip enable */
NAND_ENABLE_CE();
/* Push Erase_1 command */
WRITE_NAND_COMMAND(CMD_ERASE_1);
/* Push sector address in three cycles */
WRITE_NAND_ADDRESS((uPhySecNb >> 0) & 0xFF);
WRITE_NAND_ADDRESS((uPhySecNb >> 8) & 0xFF);
WRITE_NAND_ADDRESS((uPhySecNb >> 16) & 0xFF);
/* Push Erase_2 command */
WRITE_NAND_COMMAND(CMD_ERASE_2);
/* Wait for nand to be ready */
NAND_WAIT_READY();
NAND_WAIT_READY();
/* Check status bit for error notification */
WRITE_NAND_COMMAND(CMD_STATUS);
NAND_WAIT_READY();
if (READ_NAND() & STATUS_ERROR)
{
/* Error during block erasing */
bRet = FALSE;
goto exit;
}
exit:
/* Chip disable */
NAND_DISABLE_CE();
return bRet;
}
#ifdef NANDFLASH_SMALL_BLOCKS
/*------------------------------------------------------------------------------*/
/* \fn AT91F_NandReadSector */
/* \brief Read a Sector */
/*------------------------------------------------------------------------------*/
BOOL AT91F_NandReadSector(PSNandInfo pNandInfo, unsigned int uSectorAddr, char *pOutBuffer, unsigned int fZone)
{
BOOL bRet = TRUE;
unsigned int uBytesToRead, i;
unsigned char Cmd;
/* WARNING : During a read procedure you can't call the ReadStatus flash cmd */
/* The ReadStatus fill the read register with 0xC0 and then corrupt the read.*/
/* Push offset address */
switch(fZone)
{
case ZONE_DATA:
uBytesToRead = pNandInfo->uDataNbBytes;
Cmd = CMD_READ_A;
break;
case ZONE_INFO:
uBytesToRead = pNandInfo->uSpareNbBytes;
pOutBuffer += pNandInfo->uDataNbBytes;
Cmd = CMD_READ_C;
break;
case ZONE_DATA | ZONE_INFO:
uBytesToRead = pNandInfo->uSectorNbBytes;
Cmd = CMD_READ_A;
break;
default:
bRet = FALSE;
goto exit;
}
/* Enable the chip */
NAND_ENABLE_CE();
/* Write specific command, Read from start */
WRITE_NAND_COMMAND(Cmd);
/* Push sector address */
uSectorAddr >>= pNandInfo->uOffset;
WRITE_NAND_ADDRESS(0x00);
WRITE_NAND_ADDRESS((uSectorAddr >> 0) & 0xFF);
WRITE_NAND_ADDRESS((uSectorAddr >> 8) & 0xFF);
WRITE_NAND_ADDRESS((uSectorAddr >> 16) & 0xFF);
/* Wait for flash to be ready (can't pool on status, read upper WARNING) */
NAND_WAIT_READY();
NAND_WAIT_READY(); /* Need to be done twice, READY detected too early the first time? */
/* Read loop */
if (pNandInfo->uDataBusWidth)
{ /* 16 bits */
for(i=0; i<uBytesToRead/2; i++) // Div2 because of 16bits
{
*((short*)pOutBuffer) = READ_NAND16();
pOutBuffer+=2;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -