📄 nand.c
字号:
/*
*******************************************************************************
* file name: nand.c
* description: nand driver
* author: xzChen(chxzh123@163.com)
* QQ / msn: 36725175 / chxzh123@hotmail.com
*******************************************************************************
*/
#ifndef __NAND_C__
#define __NAND_C__
#include "Includes.h"
void Nand_Reset(void)
{
NF_CE_L();
NF_CLEAR_RB();
NF_CMD(CMD_RESET);
NF_CE_H();
}
void Nand_init(void)
{
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0);
rNFSTAT = 0;
// Nand_Reset();
}
void Nand_ReadID(void)
{
USHORT wData1,wData2;
NF_CE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READID);
NF_ADDR(0x00);
// NF_DETECT_RB();
wData1 = (BYTE)NF_DATA_R();
wData2 = (BYTE)NF_DATA_R();
NF_CE_H();
UartPutStr(SHL_PRT,"Nand Mfg: ");
Uart_SendDWORD(SHL_PRT,(DWORD)wData1);
UartPutStr(SHL_PRT,"Nand Dev: ");
Uart_SendDWORD(SHL_PRT,(DWORD)wData2);
}
#ifdef READ_SECTOR_INFO
void NAND_ReadSectorInfo(SECTOR_ADDR sectorAddr,PSectorInfo pInfo)
{
NF_CE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READ2);
NF_ADDR(0x00);
NF_ADDR(sectorAddr & 0xff);
NF_ADDR((sectorAddr >> 8) & 0xff);
NF_ADDR((sectorAddr >> 16) & 0xff);
NF_DETECT_RB();
// Read the SectorInfo data (we only need to read first 8 bytes)
pInfo->dwReserved1 = (DWORD) ((BYTE) NF_DATA_R()) << 24;
pInfo->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R()) << 16;
pInfo->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R()) << 8;
pInfo->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R());
// OEM byte
pInfo->bOEMReserved = (BYTE) NF_DATA_R();
// Read the bad block mark
pInfo->bBadBlock = (BYTE) NF_DATA_R();
// Second reserved field (WORD)
pInfo->wReserved2 = ((BYTE) NF_DATA_R() << 8);
pInfo->wReserved2 |= ((BYTE) NF_DATA_R());
NF_CE_H();
}
#endif
// FMD_ReadSector
// Read the content of the sector.
// startSectorAddr: Starting page address
// pSectorBuff : Buffer for the data portion
// pSectorInfoBuff: Buffer for Sector Info structure
// dwNumSectors : Number of sectors
BOOL FMD_ReadSector(
SECTOR_ADDR startSectorAddr,
LPBYTE pSectorBuff,
PSectorInfo pSectorInfoBuff,
DWORD dwNumSectors
)
{
DWORD i, r = 0;
BYTE ecc0,ecc1,ecc2;
BOOL rc = TRUE;
ECCRegVal eccRegVal;
// BUGBUGBUG: I need to come back to support dwNumSectors > 1
// Sanity check
if (!pSectorBuff &&
!pSectorInfoBuff ||
dwNumSectors > 1 ||
!pSectorBuff)
{
UartPutStr(SHL_PRT,"ERROR_INVALID_PARAMETER\n");
return FALSE;
}
_retry:
// Initialize ECC register
NF_RSTECC();
NF_MECC_UnLock();
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READ0);
NF_ADDR(0x00);
NF_ADDR((startSectorAddr) & 0xff);
NF_ADDR((startSectorAddr >> 8) & 0xff);
NF_ADDR((startSectorAddr >> 16) & 0xff);
for (i = 0; i < 5; i++); // wait tWB(100ns)
NF_DETECT_RB(); // wait tR(max 12us)
__RdPage512(pSectorBuff);
NF_MECC_Lock();
#if (LCD_TYPE == LTV350QVF04)
if (++len > 180)
{
len = 0;
if (progress < 320)
{
Glib_Line(progress,220,progress,240,0x001f);
progress++;
}
if (++p > 3)
{
p = 0;
gPrintf(140,222,0xFFFF,0,"%d%%",++pers);
}
}
#elif (LCD_TYPE == MT502TML8B)
#endif
// Delay(0x010000);
// Read the ECC from ECC Register
eccRegVal.dwECCVal = NF_ECC();
// Skip first 8 bytes
for(i=0; i<8; i++)
ecc0 = (BYTE)NF_DATA_R();
ecc0 = (BYTE)NF_DATA_R();
ecc1 = (BYTE)NF_DATA_R();
ecc2 = (BYTE)NF_DATA_R();
NF_nFCE_H();
if ( !rc && r++ < 3 )
{
UartPutStr(SHL_PRT,"FMD_ReadSector: ");
Uart_SendDWORD(SHL_PRT,startSectorAddr);
Nand_Reset();
for (i=0; i<5; i++); // delay
rc = TRUE;
goto _retry;
}
if( ecc0 != eccRegVal.bECCBuf[0] ||
ecc0 != eccRegVal.bECCBuf[0] ||
ecc0 != eccRegVal.bECCBuf[0] )
rc = FALSE;
return rc;
}
U08 NF08_EraseBlk(U32 pNumber)
{
U08 err;
NF_nFCE_L();
NF_CMD(CMD_ERASE0);
NF_ADDR((U08)(pNumber&0xff));
NF_ADDR((U08)((pNumber>>8)&0xff));
NF_ADDR((U08)((pNumber>>16)&0xff));
NF_CMD(CMD_ERASE1);
Delay(1); //wait tWB(100ns)
NF_WAITRB();
NF_CMD(CMD_STATUS);
if (NF_RDDATA()&0x1) // Erase error
// NF_MarkBadBlock(block);
err = FAIL;
else
err = OK;
NF_nFCE_H();
return err;
}
U08 NF08_Page_R(U32 pStart,U08 *buf)
{
U08 result;
U32 i;
UNION ecc,se[4];
NF_RSTECC();
NF_MECC_UnLock();
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READ0);
NF_ADDR(0); //Column = 0
NF_ADDR(pStart&0xff);
NF_ADDR((pStart>>8)&0xff);
NF_ADDR((pStart>>16)&0xff);
Delay(1); //wait tWB(100ns)
NF_WAITRB();
for(i=0; i<512; i++)
*buf++ = NF_RDDATA();
NF_MECC_Lock();
ecc.B32 = rNFMECC0;
NF_nFCE_H();
if( (ecc.B08[0] == se[0].B08[0]) &&
(ecc.B08[1] == se[0].B08[1]) &&
(ecc.B08[2] == se[0].B08[2]))
result = OK;
else
result = FAIL;
return OK;
}
void NF08_Read(U32 pStart,U08 *buf,U32 len)
{
U32 i,ipage,pagelen;
ipage = pStart;
pagelen = (len + 512 - 1)/512;
for (i=0; i<pagelen; i++)
{
if (NF08_Page_R(ipage,buf) == OK)
{
buf += 512;
ipage++;
}
Delay(100);
}
}
U08 NF08_Page_W(U32 pStart,U08 *buf)
{
U32 i;
U08 err;
NF_nFCE_L();
NF_CMD(CMD_READ0);
NF_CMD(CMD_WRITE0);
NF_ADDR(0x00); //Column 0
NF_ADDR(pStart&0xff);
NF_ADDR((pStart>>8)&0xff);
NF_ADDR((pStart>>16)&0xff);
for(i=0; i<512; i++)
NF_WRDATA(*buf++);
NF_CMD(CMD_WRITE1);
Delay(1); // tWB = 100ns.
NF_WAITRB();
NF_CMD(CMD_STATUS);
Delay(1); // twhr = 60ns
if (NF_RDDATA()&0x1) // Page write error
err = FAIL;
else
err = OK;
NF_nFCE_H();
return err;
}
void NF08_Write(U32 pStart,U08 *buf,U32 len)
{
U08 ipage;
U32 i,pagelen;
ipage = pStart;
pagelen = (len + 512 - 1)/512;
for (i=0; i<pagelen; i++)
{
if ((ipage%32) == 0)
NF08_EraseBlk(ipage);
if (NF08_Page_W(ipage,buf) == OK)
{
buf += 512;
ipage++;
}
}
}
int NF08_ChkBadBlk(U32 pStart)
{
U08 data;
U32 tmp;
// blockPage=(block<<5); // For 2'nd cycle I/O[7:5]
NF_nFCE_L();
NF_CMD(CMD_READ2); // Spare array read command
NF_ADDR(517&0xf); // Read the mark of bad block in spare array(M addr=5)
NF_ADDR(pStart&0xff); // The mark of bad block is in 0 page
NF_ADDR((pStart>>8)&0xff); // For block number A[24:17]
NF_ADDR((pStart>>16)&0xff); // For block number A[25]
Delay(1); // wait tWB(100ns)
NF_WAITRB(); // Wait tR(max 12us)
data = NF_RDDATA();
NF_nFCE_H();
if(data != 0xff)
{
tmp = pStart>>5;
UartPrintf(SHL_PRT,"\r\n[block %d:bad block(%x)]",tmp,data);
return 1;
}
else
{
UartPrintf(SHL_PRT,".");
return 0;
}
}
int NF08_MarkBadBlk(U32 pStart)
{
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READ2);
NF_CMD(CMD_WRITE0);
NF_ADDR(517&0xf);
NF_ADDR(pStart&0xff); // marked 5th spare array
NF_ADDR((pStart>>8)&0xff); // in the 1st page.
NF_ADDR((pStart>>16)&0xff);
NF_WRDATA(BADBLKMARK); // Write spare array
NF_CMD(CMD_WRITE1); // Write 2nd command
Delay(1); // tWB = 100ns.
NF_DETECT_RB(); // Wait tR(max 12us)
// NF_WAITRB(); // Wait tPROG(200~500us)
NF_CMD(CMD_STATUS);
if (NF_RDDATA()&0x1) // Spare arrray write error
{
NF_nFCE_H();
// printf("[Program error is occurred but ignored]\n");
}
else
NF_nFCE_H();
// printf("[block #%d is marked as a bad block]\n",block);
return 1;
}
DWORD ReadImageFromNand(DWORD dwEntry, DWORD dwSig)
{
DWORD dwSectorsNeeded;
DWORD dwSector,dwLength; // Start Sector & Length
DWORD dwRAM,i;
// TOC_SECTOR = 32
if ( !FMD_ReadSector(TOC_SECTOR,(LPBYTE)&toc,NULL, 1) )
{
UartPutStr(SHL_PRT,"ERR_DISK_OP_FAIL1\n");
return ERR_DISK_OP_FAIL1;
}
if ( !VALID_TOC(&toc) )
{
UartPutStr(SHL_PRT,"ERR_INVALID_TOC: ");
Uart_SendDWORD(SHL_PRT,toc.dwSignature);
return ERR_INVALID_TOC;
}
if ( !(toc.id[dwEntry].dwImageType & IMAGE_TYPE_RAMIMAGE) )
{
UartPutStr(SHL_PRT,"ERR_INVALID_FILE_TYPE: ");
Uart_SendDWORD(SHL_PRT,toc.id[dwEntry].dwImageType);
return ERR_INVALID_FILE_TYPE;
}
// ??
// if ( !(toc.id[dwEntry].dwImageType & IMAGE_TYPE_BINFS) ) {
// dwSectorsNeeded = toc.id[dwEntry].dwTtlSectors;
// } else {
dwSectorsNeeded = toc.id[dwEntry].dwTtlSectors; // xipkernel size = 0x9B4
// }
dwRAM = VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwLoadAddress);
JumpAddr = toc.id[0].dwJumpAddress ?
VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwJumpAddress):
VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwLoadAddress);
// Load the disk image directly into RAM
// BUG: recover from read failures
i = 0;
while (dwSectorsNeeded && i < MAX_SG_SECTORS) // 14
{
dwSector = toc.id[dwEntry].sgList[i].dwSector;
dwLength = toc.id[dwEntry].sgList[i].dwLength;
// read each sg segment
while (dwLength)
{
if ( !FMD_ReadSector(dwSector,(LPBYTE)dwRAM,NULL,1) )
{
dwSector++;
continue;
}
dwSector++;
dwLength--;
dwRAM += SECTOR_SIZE;
}
dwSectorsNeeded -= toc.id[dwEntry].sgList[i].dwLength;
i++;
}
return 1 ;// ERR_SUCCESS;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -