#include <string.h>
#include <stdlib.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
//#include "nand.h"
#define NF_MECC_UnLock() {rNFCONT&=~(1<<5);}
#define NF_MECC_Lock() {rNFCONT|=(1<<5);}
#define NF_CMD(cmd) {rNFCMD=cmd;}
#define NF_ADDR(addr) {rNFADDR=addr;}
#define NF_nFCE_L() {rNFCONT&=~(1<<1);}
#define NF_nFCE_H() {rNFCONT|=(1<<1);}
#define NF_RSTECC() {rNFCONT|=(1<<4);}
#define NF_RDDATA() (rNFDATA) //rNFDATA (*(volatile unsigned *)0x4E000010)
#define NF_RDDATA8() ((*(volatile unsigned char*)0x4E000010) ) //char
#define NF_WRDATA(data) {rNFDATA8=data;}
#define NF_WAITRB() {while(!(rNFSTAT&(1<<1)));}
//wait tWB and check F_RNB pin.
// RnB Signal
#define NF_CLEAR_RB() {rNFSTAT |= (1<<2);} // Have write '1' to clear this bit.
#define NF_DETECT_RB() {while(!(rNFSTAT&(1<<2)));}
#define TACLS 0 // 1-clk(0ns)
#define TWRPH0 6 // 3-clk(25ns)
#define TWRPH1 0 // 1-clk(10ns) //TACLS+TWRPH0+TWRPH1>=50ns
static void __RdPage512(U8 *buf)
{
unsigned i;
for (i = 0; i < 512; i++) {
buf[i] = NF_RDDATA8();
}
}
static void Nand_Reset(void)
{
volatile int i;
NF_nFCE_L();
NF_CLEAR_RB();
for (i=0; i<10; i++);
NF_CMD(0xFF); //reset command
NF_DETECT_RB();
NF_nFCE_H();
}
static U32 NF8_CheckId(void)
{
int i;
U8 Mid, Did, DontCare, id4th;
NF_nFCE_L();
NF_CMD(0x90);
NF_ADDR(0x0);
for (i=0; i<100; i++);
Mid = NF_RDDATA8();
Did = NF_RDDATA8();
DontCare = NF_RDDATA8();
id4th = NF_RDDATA8();
NF_nFCE_H();
switch(Did) {
case 0x76:
return 0;
case 0xF1:
case 0xD3:
case 0xDA:
case 0xDC:
return 1;
Uart_Printf("\nId=%x\n",Did);
default:
Uart_SendString("Unknown NAND type\r\n");
for(;;);
}
}
int 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();
return NF8_CheckId();
}
int Nand_IsBadBlock(U32 block)
{
U32 Page;
U8 BAD;
//每个block的第0或第一页的第2048列(OOB的第一列)!=0xff,为坏块
Page = block << 6; //block*64
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0x00);
NF_ADDR(2048&0xff);
NF_ADDR((2048>>8)&0xff); //the 2048th Byte of the block,which also is the OOB's 1th Byte
NF_ADDR(Page&0xff); //block左移6位,选择页中的第0列
NF_ADDR((Page>>8)&0xff);
NF_ADDR((Page>>16)&0xff);
NF_CMD(0x30);
NF_DETECT_RB();
BAD = NF_RDDATA8();
NF_nFCE_H();
return BAD != 0xff; //0:good , 1:bad
}
int Nand_ReadSector(U32 sector, U8 *buffer)
{
U32 page, data_addr;
Nand_Reset();
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0x00); // Read command
page = sector/4;
data_addr = 512 *(sector%4);
NF_ADDR(data_addr&0xff);
NF_ADDR((data_addr>>8)&0xff);
NF_ADDR(page&0xff);
NF_ADDR((page>>8)&0xff);
NF_ADDR((page>>16)&0xff);
NF_CMD(0x30);
NF_DETECT_RB();
__RdPage512(buffer);
NF_nFCE_H();
return OK;
}
int Nand_ReadPage(U32 page, U8 *buffer)
{
unsigned i;
Nand_Reset();
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0x00); // Read command
NF_ADDR(0x0);
NF_ADDR(0x0);
NF_ADDR(page&0xff);
NF_ADDR((page>>8)&0xff);
NF_ADDR((page>>16)&0xff);
NF_CMD(0x30);
NF_DETECT_RB();
for (i = 0; i < 2048; i++)
buffer[i] = NF_RDDATA8();
NF_nFCE_H();
return OK;
}
int Mark_BadBlock(U32 block)
{
U32 Page;
Page=block<<6;
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0x80);
NF_ADDR(2048&0xff);
NF_ADDR((2048>>8)&0xff);
NF_ADDR(Page&0xff);
NF_ADDR((Page>>8)&0xff);
NF_ADDR((Page>>16)&0xff);
NF_WRDATA(0);
NF_CMD(0x10);
NF_DETECT_RB();
NF_CMD(0x70);
if(NF_RDDATA()&0x1)
{
Uart_SendString("ERR:BadBlockMark1!");
NF_CLEAR_RB();
NF_CMD(0x80);
NF_ADDR(2049&0xff);
NF_ADDR((2049>>8)&0xff);
NF_ADDR(Page&0xff);
NF_ADDR((Page>>8)&0xff);
NF_ADDR((Page>>16)&0xff);
NF_WRDATA(0);
NF_CMD(0x10);
NF_DETECT_RB();
NF_CMD(0x70);
if(NF_RDDATA()&0x1)
{
NF_nFCE_H();
Uart_SendString("ERR:BadBlockMark2!");
return 0;
}
else
{
NF_nFCE_H();
return 1;
}
}
else
{
NF_nFCE_H();
return 1;
}
}
int Nand_EraseBlock(U32 block)
{
U32 blockPage=(block<<6);
if(Nand_IsBadBlock(block))
return 0;
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0x60);
NF_ADDR(blockPage&0xff);
NF_ADDR((blockPage>>8)&0xff);
NF_ADDR((blockPage>>16)&0xff);
NF_CMD(0xd0);
NF_DETECT_RB();
NF_CMD(0x70);
if(NF_RDDATA()&0x1)
{
NF_nFCE_H();
Uart_SendString("\n\nERR:blockErase!\n");
Mark_BadBlock(block);
return 0;
}
else
{
NF_nFCE_H();
return 1;
}
}
int Nand_WriteSector(U32 sector,U8 *buffer)
{
U32 page,data_addr;
U8 *bufPt=buffer;
int i;
page=sector/4;
data_addr=512*(sector%4);
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0x80);
NF_ADDR(data_addr&0xff);
NF_ADDR((data_addr>>8)&0xff);
NF_ADDR(page&0xff);
NF_ADDR((page>>8)&0xff);
NF_ADDR((page>>16)&0xff);
for(i=0;i<512;i++)
NF_WRDATA(*bufPt++);
NF_CMD(0x10);
NF_DETECT_RB();
NF_CMD(0x70);
if(NF_RDDATA()&0x1)
{
NF_nFCE_H();
Uart_SendString("ERR:WriteBlock!");
Mark_BadBlock(sector>>8);
return 0;
}
else
{
NF_nFCE_H();
return 1;
}
}
int Nand_WritePage(U32 page,U8 *buffer)
{
U8 *bufPt=buffer;
int i;
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(0);
NF_CMD(0x80);
NF_ADDR(0);
NF_ADDR(0);
NF_ADDR(page&0xff);
NF_ADDR((page>>8)&0xff);
NF_ADDR((page>>16)&0xff);
for(i=0;i<2048;i++)
NF_WRDATA(*bufPt++);
NF_CMD(0x10);
NF_DETECT_RB();
NF_CMD(0x70);
if(NF_RDDATA()&0x1)
{
NF_nFCE_H();
Uart_SendString("ERR:WritePage!");
Mark_BadBlock(page>>6);
return 0;
}
else
{
NF_nFCE_H();
return 1;
}
}
void CopyProgramFromNand(void)
{
const unsigned StartSector = 0, StopSector = 5120;
const unsigned byte_sector_shift = 9;
const unsigned sector_block_shift = 8;
unsigned char *RAM = (unsigned char *)0x32000000;
unsigned Sector, GoodSector;
Nand_Init();
for (Sector = StartSector, GoodSector = Sector; Sector < StopSector; Sector ++, GoodSector++) {
// begin of a block
if (GoodSector & ( (1 << sector_block_shift) - 1 ) == 0) {
// found a good block
for (;;) {
if (!Nand_IsBadBlock(GoodSector >> sector_block_shift)) {
// Is good Block
break;
}
// try next block
GoodSector += (1 << sector_block_shift); // +=256
}
}
Nand_ReadSector(GoodSector, RAM + (Sector << byte_sector_shift ));// *512
}
}