📄 nandflash.c
字号:
/*
* NandFlash底层代码
*/
#include <linux/kernel.h>
#include <asm/MC68VZ328.h>
#include <linux/fs.h>
#include <linux/param.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include "DataType.h"
#include "NandFlash.h"
extern UCHAR *nand_cache_start;
static ULONG nand_cache_tick_count = 0;
static int sgnWriteBackDelay = WRITEBACK_DELAY * HZ / 1000;
struct timer_list gstTimerList;
// ################# Prototype ###################
void
InitNandFlashPin(void);
UCHAR
InitNandFlash(void);
void
ResetNandFlash(void);
UWORD
ReadID(void);
UCHAR
ReadStatus(void);
UCHAR
EraseBlock(ULONG);
UCHAR
ProgramSector(UCHAR *, ULONG, UWORD);
void
EraseNandFlash(void);
UCHAR
WriteSector1(UCHAR *, ULONG , UWORD);
UCHAR
ReadSector1(UCHAR *, ULONG, UWORD);
// Following routines was which written by J.G. Lv.
void
NandBufferCopy(UCHAR *pbyDst, UCHAR *pbySrc, ULONG nCopySize);
void
NandWriteBack(void);
SWORD
IsBlockInCache(ULONG nBlockNum);
UCHAR
LRUSearchBlock(void);
UCHAR
NandReadBlock(UCHAR *pbyBuf, ULONG nBlockNum);
UCHAR
NandProgramBlock(UCHAR *pbyBuf, ULONG nBlockNum);
void
NandBufferCopy(UCHAR *pbyDst, UCHAR *pbySrc, ULONG nCopySize)
{
ULONG nSize = nCopySize >> 1;
UCHAR bRemain = nCopySize & 1;
UWORD i, *pwDst = (UWORD *) pbyDst, *pwSrc = (UWORD *) pbySrc;
for (i = 0; i < nSize; i++)
*pwDst++ = *pwSrc++;
if (bRemain)
*((UCHAR *) pwDst) = *((UCHAR *) pwSrc);
}
/** 初始化NandFlash 管脚.
**
** 输入参数: 无
**
** 返回值: 无
**
** @return whatever
** @author 武东宏
** @version v0.1 beta
** @see InitNandFlash
*/
void
InitNandFlashPin(void)
{
PDSEL |= 0x0F;
PDDIR = PDSEL & 0xF0 | 0x0B;
NANDFLASH_DISABLE();
CMD_LATCH_DISABLE;
ADD_LATCH_DISABLE();
}
/** 初始化NandFlash .
**
** 输入参数: 无
**
** 返回值: 0
**
** @return whatever
** @author 武东宏、吕剑国
** @version v0.2 beta
** @see InitNandFlashPin
*/
UCHAR
InitNandFlash(void)
{
UWORD i;
NAND_CACHE_HEADER *pstHeader = (NAND_CACHE_HEADER *) nand_cache_start;
UCHAR *pbySectorData = (UCHAR *) (nand_cache_start + 64 * MAX_NAND_CACHE_COUNT);
InitNandFlashPin();
NANDFLASH_ENABLE();
ResetNandFlash();
NANDFLASH_DISABLE();
for (i = 0; i < MAX_NAND_CACHE_COUNT; i++) {
pstHeader->bUsed = 0;
pstHeader->nUseCount = 0;
pstHeader->nTickCount = 0;
pstHeader->bDirty = 0;
pstHeader->nBlockNum = 0xffffffff;
pstHeader->pSectorBuf = pbySectorData;
pstHeader = (NAND_CACHE_HEADER *) ((ULONG) pstHeader + 64);
pbySectorData += BLOCK_SIZE1;
}
// Initialize timer list
init_timer(&gstTimerList);
gstTimerList.expires = sgnWriteBackDelay;
gstTimerList.function = (void*) NandWriteBack;
add_timer(&gstTimerList);
return (0);
}
/**
**
*/
void
NandWriteBack(void)
{
UWORD i;
NAND_CACHE_HEADER *pstHeader = (NAND_CACHE_HEADER *) nand_cache_start;
for (i = 0; i < MAX_NAND_CACHE_COUNT; i++) {
if (pstHeader->bDirty) {
if (NandProgramBlock(pstHeader->pSectorBuf, pstHeader->nBlockNum) == NOERR)
pstHeader->bDirty = 0;
};
pstHeader = (NAND_CACHE_HEADER *) ((ULONG) pstHeader + 64);
}
// Initialize timer list
init_timer(&gstTimerList);
gstTimerList.expires = jiffies + sgnWriteBackDelay;
gstTimerList.function = (void*) NandWriteBack;
add_timer(&gstTimerList);
return;
}
/** 检查所请求的块是否在Cache 中.
**
** 输入参数: ULONG nBlockNum -- 所请求的块号
**
** 返回值: -1 -- 所请求的块不在Cache中
** 其他值 -- 表示所在的Cache的索引值
**
** @param nBlockNum 所请求的块号
** @return whatever
** @author 吕剑国
** @version v0.1 beta
** @see
*/
SWORD
IsBlockInCache(ULONG nBlockNum)
{
UWORD i;
NAND_CACHE_HEADER *pstHeader = (NAND_CACHE_HEADER *) nand_cache_start;
for (i = 0; i < MAX_NAND_CACHE_COUNT; i++) {
if (pstHeader->nBlockNum == nBlockNum)
return (i);
pstHeader = (NAND_CACHE_HEADER *) ((ULONG) pstHeader + 64);
}
return (-1);
}
/** 采用LRU(最近最少用)算法确定要淘汰的块.
**
** 输入参数: 无
**
** 返回值: 要淘汰的Cache中的块索引
**
** @return whatever
** @author 吕剑国
** @version v0.1 beta
** @see
*/
UCHAR
LRUSearchBlock(void)
{
UCHAR cIndex = 0;
UWORD i;
ULONG nMinUse = 0x1fffffff, nMinTick = 0x1fffffff;
NAND_CACHE_HEADER *pstHeader = (NAND_CACHE_HEADER *) nand_cache_start;
for (i = 0; i < MAX_NAND_CACHE_COUNT; i++) {
if (pstHeader->bUsed == 0) {
return (i);
}
if (pstHeader->nUseCount < nMinUse) {
cIndex = i;
nMinUse = pstHeader->nUseCount;
nMinTick = pstHeader->nTickCount;
}
else if (pstHeader->nUseCount == nMinUse && pstHeader->nTickCount < nMinTick) {
cIndex = i;
nMinUse = pstHeader->nUseCount;
nMinTick = pstHeader->nTickCount;
}
pstHeader = (NAND_CACHE_HEADER *) ((ULONG) pstHeader + 64);
}
return (cIndex);
}
/** 从NandFlash中读取一块数据.
**
** 输入参数: UCHAR *pbyBuf -- 接收数据的缓冲区
** ULONG nBlockNum -- 所请求的块号
**
** 返回值: 0 -- 读成功; 其他 -- 读失败
**
** @param pbyBuf 接收数据的缓冲区
** @param nBlockNum 所请求的块号
** @return whatever
** @author 吕剑国
** @version v0.1 beta
** @see
*/
UCHAR
NandReadBlock(UCHAR *pbyBuf, ULONG nBlockNum)
{
UWORD i, j;
UCHAR t;
ULONG nSector;
nSector = nBlockNum << 5;
NANDFLASH_ENABLE();
WRITE_CMD(READ1_CMD);
ADD_LATCH_ENABLE();
WRITE_BYTE(0);
WRITE_BYTE((UCHAR) nSector);
WRITE_BYTE((UCHAR) (nSector >> 8));
ADD_LATCH_DISABLE();
for (i = 0; i < SECTOR_PER_BLOCK; i++) {
while(!NANDFLASH_READY());
for (j = 0; j < 512; j++)
*pbyBuf++ = READ_BYTE();
for(j = 0; j < 16; j++)
t=READ_BYTE();
}
NANDFLASH_DISABLE();
return (NOERR);
}
/*
UCHAR
ReadSector1(UCHAR *buf, ULONG startsector, UWORD sectornum)
{
UWORD i, j, k;
UCHAR t;
//UCHAR Status;
NANDFLASH_ENABLE();
//ResetNandFlash();
WRITE_CMD(READ1_CMD);
ADD_LATCH_ENABLE();
WRITE_BYTE(0);
WRITE_BYTE((UCHAR)startsector);
WRITE_BYTE((UCHAR)(startsector>>8));
ADD_LATCH_DISABLE();
for(i=0; i<sectornum; i++)
{
while(!NANDFLASH_READY());
for(j=0; j<512; j++)
{
*buf = READ_BYTE();
buf++;
}
for(k=0;k<16;k++)
{
t=READ_BYTE();
}
}
NANDFLASH_DISABLE();
return NOERR;
}
*/
UCHAR
ReadSector1(UCHAR *buf, ULONG startsector, UWORD sectornum)
{
NAND_CACHE_HEADER *pstHeader;
ULONG nBlockNum, nSectorNum = startsector, nSectorOffsetInBlock, nSectors;
SWORD sIndex;
UCHAR cIndex, *pbyBuf = buf;
do {
nBlockNum = nSectorNum >> 5;
nSectorOffsetInBlock = nSectorNum & (SECTOR_PER_BLOCK - 1);
nSectors = (sectornum > (SECTOR_PER_BLOCK - nSectorOffsetInBlock) ?
(SECTOR_PER_BLOCK - nSectorOffsetInBlock) : sectornum);
sIndex = IsBlockInCache(nBlockNum);
// Found!!!
if (sIndex >= 0) {
pstHeader = (NAND_CACHE_HEADER *) (nand_cache_start + (sIndex << 6));
}
// Not Found!!!
else {
cIndex = LRUSearchBlock();
pstHeader = (NAND_CACHE_HEADER *) (nand_cache_start + (cIndex << 6));
if (pstHeader->bDirty) {
NandProgramBlock(pstHeader->pSectorBuf, pstHeader->nBlockNum);
}
pstHeader->bUsed = 1;
pstHeader->nUseCount = 0;
pstHeader->bDirty = 0;
pstHeader->nBlockNum = nBlockNum;
NandReadBlock(pstHeader->pSectorBuf, nBlockNum);
}
NandBufferCopy(pbyBuf, (UCHAR *) (pstHeader->pSectorBuf + (nSectorOffsetInBlock << 9)),
nSectors << 9);
pbyBuf += nSectors << 9;
sectornum -= nSectors;
nSectorNum += nSectors;
pstHeader->nTickCount = nand_cache_tick_count++;
pstHeader->nUseCount++;
} while (sectornum > 0);
return (NOERR);
}
void
ResetNandFlash(void)
{
WRITE_CMD(RESET_CMD);
while(!NANDFLASH_READY());
}
UWORD
ReadID(void)
{
UWORD ID = 0;
NANDFLASH_ENABLE();
WRITE_CMD(READ_ID_CMD);
ADD_LATCH_ENABLE();
WRITE_BYTE(0);
WRITE_BYTE(0);
ADD_LATCH_DISABLE();
ID = READ_BYTE()<<8;
ID += READ_BYTE();
NANDFLASH_DISABLE();
return ID;
}
UCHAR ReadStatus(void)
{
UCHAR Status = 0;
WRITE_CMD(READ_STATUS_CMD);
Status = READ_BYTE();
return Status&0x01;
}
UCHAR
EraseBlock(ULONG block)
{
UCHAR ADD3, ADD2;
ULONG startsector = block*(SECTOR_PER_BLOCK);
ADD3=(UCHAR)(startsector>>8);
ADD2=(UCHAR)startsector;
NANDFLASH_ENABLE();
WRITE_CMD(BLOCK_ERASE_CMD);
ADD_LATCH_ENABLE();
WRITE_BYTE(ADD2);
WRITE_BYTE(ADD3);
ADD_LATCH_DISABLE();
//CMD_LATCH_ENABLE();
WRITE_CMD(BLOCK_ERASE_CONFIRM_CMD);
//CMD_LATCH_DISABLE();
while(!NANDFLASH_READY());
NANDFLASH_DISABLE();
return ReadStatus();
}
UCHAR
ProgramSector(UCHAR *buf, ULONG startsector, UWORD sectornum)
{
UWORD i, j;
UCHAR Status = 0;
NANDFLASH_ENABLE();
for (i=0; i<sectornum; i++)
{
WRITE_CMD(SDATA_INPUT_CMD);
ADD_LATCH_ENABLE();
WRITE_BYTE(0);
WRITE_BYTE((UCHAR)startsector);
WRITE_BYTE((UCHAR)(startsector>>8));
startsector++;
ADD_LATCH_DISABLE();
for(j=0; j<512; j++)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -