⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nandflash.c

📁 linux下nand flash驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -