#include <stdio.h>
#include <string.h>
#include "sys_res.h"
#include "sys_func.h"
#include "nand.h"
#define BLOCKBYTELENGTH (1024*128)
// Flags and pointers
#define BADBLOCKMARK 0x00
// VALIDADDR is 5 << 8
//
// Explain: 5 means the 6th byte in spare area (517 byte in the sector)
// Shift 8 bit to the left to form the correct address for 16bit port
//
#define VALIDADDR 0x05
#define OEMADDR 0x04 // 5th byte in spare area
BOOL g_ExtAddr; // Whether to need A25~A32
FlashInfo g_FlashInfo; // The information of flash
BYTE Command_Status = 0;
DWORD *g_BlockTable = NULL;
BYTE *BlockBuffer = NULL;
BOOL NAND_Exist = FALSE;
BOOL IsReady(DWORD dwLoops)
{
BOOL bStop = (dwLoops != (DWORD) -1);
while (1)
{
if(ISREADY) // Ready
return TRUE;
else // Busy
{
if (bStop && !dwLoops) // Non-infinite loop and we already pay our due
return FALSE;
}
dwLoops--;
}
}
// CheckStatus()
//
// Retrieve the status of the Chip. This function accept a loop number, which
// is used to do the loop if chip is not ready.
//
// dwLoops:
//
// 0: no loop
// 0xffffffff: loop forever
//
BOOL CheckStatus(DWORD dwLoops)
{
BOOL bStop = (dwLoops != (DWORD) -1);
BYTE usStatus;
CHIP_ENABLE; // Enable chip
CMD_ENABLE;
NAND_WRITE_PORT(CMD_STATUS);
CMD_DISABLE;
while(1)
{
usStatus = NAND_READ_PORT;
if(usStatus & STATUS_READY) // Status ready
{
CHIP_DISABLE; // Disable chip
return TRUE;
}
else
{
if (bStop && !dwLoops) // Non-infinite loop and we already pay our due
{
CHIP_DISABLE; // Disable chip
return FALSE;
}
}
dwLoops--;
}
}
// GetStatus()
//
// Retrieve the status of the Chip. This function accept a loop number, which
// is used to do the loop if chip is not ready.
//
// dwLoops:
//
// 0: no loop
// 0xffffffff: loop forever
//
BYTE GetStatus(DWORD dwLoops)
{
BOOL bStop = (dwLoops != (DWORD) -1);
BYTE usStatus;
CHIP_ENABLE; // Enable chip
// Issue read status command
CMD_ENABLE;
NAND_WRITE_PORT(CMD_STATUS);
CMD_DISABLE;
while(1)
{
usStatus = NAND_READ_PORT;
if( usStatus & STATUS_READY || // Status ready
(bStop && !dwLoops)) // Non-infinite loop and we already pay our due
{
break;
}
dwLoops--;
}
CHIP_DISABLE; // Disable chip
return usStatus;
}
DWORD ReadFlashID(void)
{
BYTE data1, data2, data3, data4;
CHIP_ENABLE; // Enable chip
IsReady((DWORD) -1); // check ready
CMD_ENABLE;
NAND_WRITE_PORT(CMD_READID);
CMD_DISABLE;
ADD_ENABLE;
NAND_WRITE_PORT(0x00);
ADD_DISABLE;
IsReady((DWORD) -1);
data1 = NAND_READ_PORT;
data2 = NAND_READ_PORT;
data3 = NAND_READ_PORT;
data4 = NAND_READ_PORT;
CHIP_DISABLE; // Disable chip
return ((DWORD)((data1 << 24) | (data2 << 16) | (data3 << 8) | data4));
}
//
// IsBlockBad
//
// Check to see if the given block is bad. A block is bad if the 517th byte on
// the first or second page is not 0xff.
//
// blockID: The block address. We need to convert this to page address
//
//
BOOL IsBlockBad(BLOCK_ID blockID)
{
BYTE addr1, addr2, addr3, wData;
DWORD dwPageID;
DWORD i;
for (i = 0; i < 2; i++)
{
dwPageID = blockID * g_FlashInfo.wSectorsPerBlock + i; // Get the first or second page of the blcok
addr1 = (BYTE)((dwPageID) & 0xff);
addr2 = (BYTE)((dwPageID >> 8) & 0xff);
addr3 = (BYTE)((dwPageID >> 16) & 0xff);
// For our NAND flash, we don't have to issue two read command. We just need
// to issue one read command and do contiquous read
CHIP_ENABLE; // Enable chip
IsReady((DWORD) -1); // check ready
// Check the first page.
CMD_ENABLE;
NAND_WRITE_PORT(CMD_READ2);
CMD_DISABLE;
ADD_ENABLE;
NAND_WRITE_PORT(VALIDADDR);
NAND_WRITE_PORT(addr1);
NAND_WRITE_PORT(addr2);
if(g_ExtAddr)
NAND_WRITE_PORT(addr3);
ADD_DISABLE;
IsReady((DWORD) -1);
Delay(1000);
wData = NAND_READ_PORT;
CHIP_DISABLE; // Disable chip
if (wData != 0xff)
{
return TRUE;
}
}
return FALSE;
}
SECTOR_ADDR GetActualAddress(SECTOR_ADDR secno)
{
BLOCK_ID BlockID;
BlockID = secno / g_FlashInfo.wSectorsPerBlock;
if (BlockID < g_FlashInfo.dwNumValidBlocks)
{
return (g_BlockTable[BlockID] * g_FlashInfo.wSectorsPerBlock + secno % g_FlashInfo.wSectorsPerBlock);
}
else
{
return 0xFFFFFFFF;
}
}
BOOL ReadBlock(BLOCK_ID blockID, BYTE *pBlockBuff)
{
SECTOR_ADDR secno = blockID * g_FlashInfo.wSectorsPerBlock;
DWORD i, count = g_FlashInfo.wSectorsPerBlock;
BYTE addr1, addr2, addr3, wData;
PageInfo pi;
while (count)
{
addr1 = (BYTE)((secno) & 0xff);
addr2 = (BYTE)((secno >> 8) & 0xff);
addr3 = (BYTE)((secno >> 16) & 0xff);
CHIP_ENABLE; // Enable chip
IsReady((DWORD) -1);
// Issue Read command
CMD_ENABLE;
NAND_WRITE_PORT(CMD_READ);
CMD_DISABLE;
ADD_ENABLE;
NAND_WRITE_PORT(0x00);
NAND_WRITE_PORT(addr1);
NAND_WRITE_PORT(addr2);
if(g_ExtAddr)
NAND_WRITE_PORT(addr3);
ADD_DISABLE;
IsReady((DWORD) -1);
Delay(1000);
// Read only data portion of the sector.
for(i = 0; i < SECTOR_SIZE; i++)
{
wData = NAND_READ_PORT;
// Copy the bytes directly into pSectorBuff
pBlockBuff[i] = wData;
}
// Read the page info
for (i = 0; i < PAGEINFO_STRLEN; i++)
{
wData = NAND_READ_PORT;
pi.identify[i] = wData;
}
wData = NAND_READ_PORT;
pi.bBadBlock = wData;
wData = NAND_READ_PORT;
pi.wReserved = (WORD)wData;
wData = NAND_READ_PORT;
pi.wReserved |= (WORD)wData << 8;
CHIP_DISABLE; // Disable chip
pBlockBuff += SECTOR_SIZE;
secno++;
count--;
}
return TRUE;
}
BOOL WriteBlock(BLOCK_ID blockID, BYTE *pBlockBuff)
{
SECTOR_ADDR secno = blockID * g_FlashInfo.wSectorsPerBlock;
DWORD i, count = g_FlashInfo.wSectorsPerBlock;
BYTE addr1, addr2, addr3, status;
PageInfo pi;
while (count)
{
addr1 = (BYTE)((secno) & 0xff);
addr2 = (BYTE)((secno >> 8) & 0xff);
addr3 = (BYTE)((secno >> 16) & 0xff);
CHIP_ENABLE; // Enable chip
IsReady((DWORD) -1);
// First we set the pointer to point to the data area
CMD_ENABLE;
NAND_WRITE_PORT(CMD_READ);
CMD_DISABLE;
IsReady((DWORD) -1);
// Next we issue the write command
CMD_ENABLE;
NAND_WRITE_PORT(CMD_WRITE);
CMD_DISABLE;
ADD_ENABLE;
NAND_WRITE_PORT(0x00);
NAND_WRITE_PORT(addr1);
NAND_WRITE_PORT(addr2);
if(g_ExtAddr)
NAND_WRITE_PORT(addr3);
ADD_DISABLE;
// Write the data
for(i = 0; i < SECTOR_SIZE; i++)
{
NAND_WRITE_PORT(pBlockBuff[i]);
}
memcpy(pi.identify, "EFLAG", PAGEINFO_STRLEN);
pi.bBadBlock = 0xFF;
pi.wReserved = 0xFFFF;
// Write the page info into the spare area
for (i = 0; i < PAGEINFO_STRLEN; i++)
{
NAND_WRITE_PORT(pi.identify[i]);
}
NAND_WRITE_PORT(pi.bBadBlock);
NAND_WRITE_PORT((BYTE)(pi.wReserved));
NAND_WRITE_PORT((BYTE)(pi.wReserved >> 8));
// Instruct the Flash to commit the data to the media
CMD_ENABLE;
NAND_WRITE_PORT(CMD_WRITE2);
CMD_DISABLE;
CHIP_DISABLE; // Disable chip
IsReady((DWORD) -1);
// Check the status of the write.
status = GetStatus((DWORD) -1);
if(status & STATUS_ERROR)
{
return FALSE;
}
pBlockBuff += SECTOR_SIZE;
secno++;
count--;
}
return TRUE;
}
/********************************************************
*
* 函数名 : NANDFLASH_write_data
* 函数功能 : 向nandflash的指定地址写指定长度的内容
* 函数输入参数 : 传入参数blockID是块的地址,从0、1、2...
* 函数输出 :
* 说明 : 不同的nandflash的页的大小和块的大小不相同,
* 现在市面上常见的nandflash的页为2K,块为64*2K=128k
* nandflash的读写单位为页,擦写单位为块,写前必须擦。
* (由于没