www.pudn.com > LJD2440-II_MON_OK.rar > nand.c
/* create by hzh, support 512/page NAND Flash only */ #include#include "def.h" #include "2440addr.h" #include "2440lib.h" #include "2440slib.h" #include "Nand.h" //suppport boot params #define GLOBAL_PARAMS #include "bootpara.h" #define puts Uart_Printf #define printf Uart_Printf #define getch Uart_Getch #define putch Uart_SendByte #define EnNandFlash() (rNFCONT |= 1) #define DsNandFlash() (rNFCONT &= ~1) #define NFChipEn() (rNFCONT &= ~(1<<1)) #define NFChipDs() (rNFCONT |= (1<<1)) #define InitEcc() (rNFCONT |= (1<<4)) #define MEccUnlock() (rNFCONT &= ~(1<<5)) #define MEccLock() (rNFCONT |= (1<<5)) #define SEccUnlock() (rNFCONT &= ~(1<<6)) #define SEccLock() (rNFCONT |= (1<<6)) #define WrNFDat8(dat) (rNFDATA8 = (dat)) #define WrNFDat32(dat) (rNFDATA = (dat)) #define RdNFDat8() (rNFDATA8) //byte access #define RdNFDat32() (rNFDATA) //word access #define WrNFCmd(cmd) (rNFCMD = (cmd)) #define WrNFAddr(addr) (rNFADDR = (addr)) #define WrNFDat(dat) WrNFDat8(dat) #define RdNFDat() RdNFDat8() //for 8 bit nand flash, use byte access #define RdNFMEcc() (rNFMECC0) //for 8 bit nand flash, only use NFMECC0 #define RdNFSEcc() (rNFSECC) //for 8 bit nand flash, only use low 16 bits #define RdNFStat() (rNFSTAT) #define NFIsBusy() (!(rNFSTAT&1)) #define NFIsReady() (rNFSTAT&1) //#define WIAT_BUSY_HARD 1 //#define ER_BAD_BLK_TEST //#define WR_BAD_BLK_TEST #define READCMD0 0 #define READCMD1 1 #define READCMD2 0x50 #define ERASECMD0 0x60 #define ERASECMD1 0xd0 #define PROGCMD0 0x80 #define PROGCMD1 0x10 #define QUERYCMD 0x70 #define RdIDCMD 0x90 static U16 NandAddr; // HCLK=100Mhz #define TACLS 1//7 // 1-clk(0ns) #define TWRPH0 4//7 // 3-clk(25ns) #define TWRPH1 1//7 // 1-clk(10ns) //TACLS+TWRPH0+TWRPH1>=50ns static void InitNandCfg(void) { // for S3C2440 rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0); // TACLS [14:12] CLE&ALE duration = HCLK*TACLS. // TWRPH0 [10:8] TWRPH0 duration = HCLK*(TWRPH0+1) // TWRPH1 [6:4] TWRPH1 duration = HCLK*(TWRPH1+1) // AdvFlash(R) [3] Advanced NAND, 0:256/512, 1:1024/2048 // PageSize(R) [2] NAND memory page size // when [3]==0, 0:256, 1:512 bytes/page. // when [3]==1, 0:1024, 1:2048 bytes/page. // AddrCycle(R) [1] NAND flash addr size // when [3]==0, 0:3-addr, 1:4-addr. // when [3]==1, 0:4-addr, 1:5-addr. // BusWidth(R/W) [0] NAND bus width. 0:8-bit, 1:16-bit. rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); // Lock-tight [13] 0:Disable lock, 1:Enable lock. // Soft Lock [12] 0:Disable lock, 1:Enable lock. // EnablillegalAcINT[10] Illegal access interupt control. 0:Disable, 1:Enable // EnbRnBINT [9] RnB interrupt. 0:Disable, 1:Enable // RnB_TrandMode[8] RnB transition detection config. 0:Low to High, 1:High to Low // SpareECCLock [6] 0:Unlock, 1:Lock // MainECCLock [5] 0:Unlock, 1:Lock // InitECC(W) [4] 1:Init ECC decoder/encoder. // Reg_nCE [1] 0:nFCE=0, 1:nFCE=1. // NANDC Enable [0] operating mode. 0:Disable, 1:Enable. // rNFSTAT = 0; // Nand_Reset(); } #ifdef WIAT_BUSY_HARD #define WaitNFBusy() while(NFIsBusy()) #else static U32 WaitNFBusy(void) // R/B 未接好? { U8 stat; WrNFCmd(QUERYCMD); do { stat = RdNFDat(); //printf("%x\n", stat); }while(!(stat&0x40)); WrNFCmd(READCMD0); return stat&1; } #endif static U32 ReadChipId(void) { U32 id; NFChipEn(); WrNFCmd(RdIDCMD); WrNFAddr(0); while(NFIsBusy()); id = RdNFDat()<<8; id |= RdNFDat(); NFChipDs(); return id; } static U16 ReadStatus(void) { U16 stat; NFChipEn(); WrNFCmd(QUERYCMD); stat = RdNFDat(); NFChipDs(); return stat; } static U32 EraseBlock(U32 addr) { U8 stat; addr &= ~0x1f; NFChipEn(); WrNFCmd(ERASECMD0); WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); WrNFCmd(ERASECMD1); stat = WaitNFBusy(); NFChipDs(); #ifdef ER_BAD_BLK_TEST if(!((addr+0xe0)&0xff)) stat = 1; //just for test bad block #endif putch('.'); //printf("Erase block 0x%x %s\n", addr, stat?"fail":"ok"); return stat; } //addr = page address static void ReadPage(U32 addr, U8 *buf) { U16 i; NFChipEn(); WrNFCmd(READCMD0); WrNFAddr(0); WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); InitEcc(); WaitNFBusy(); for(i=0; i<512; i++) buf[i] = RdNFDat(); NFChipDs(); } static U32 WritePage(U32 addr, U8 *buf) { U32 i, mecc; U8 stat, tmp[7]; NFChipEn(); WrNFCmd(PROGCMD0); WrNFAddr(0); WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); InitEcc(); //reset mecc and secc MEccUnlock(); for(i=0; i<512; i++) WrNFDat(buf[i]); MEccLock(); mecc = RdNFMEcc(); tmp[0] = mecc&0xff; tmp[1] = (mecc>>8)&0xff; tmp[2] = (mecc>>16)&0xff; tmp[3] = (mecc>>24)&0xff; tmp[5] = 0xff; //mark good block SEccUnlock(); WrNFDat(tmp[0]); WrNFDat(tmp[1]); WrNFDat(tmp[2]); WrNFDat(tmp[3]); SEccLock(); WrNFDat(tmp[4]); WrNFDat(tmp[5]); WrNFCmd(PROGCMD1); stat = WaitNFBusy(); NFChipDs(); #ifdef WR_BAD_BLK_TEST if((addr&0xff)==0x17) stat = 1; //just for test bad block #endif if(stat) printf("Write nand flash 0x%x fail\n", addr); else { U8 RdDat[512]; ReadPage(addr, RdDat); for(i=0; i<512; i++) if(RdDat[i]!=buf[i]) { printf("Check data at page 0x%x, offset 0x%x fail\n", addr, i); stat = 1; break; } } return stat; } static void MarkBadBlk(U32 addr) { addr &= ~0x1f; NFChipEn(); WrNFCmd(READCMD2); //point to area c WrNFCmd(PROGCMD0); WrNFAddr(4); //mark offset 4,5,6,7 WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); WrNFDat(0); //mark with 0 WrNFDat(0); WrNFDat(0); //mark with 0 WrNFDat(0); WrNFCmd(PROGCMD1); WaitNFBusy(); //needn't check return status WrNFCmd(READCMD0); //point to area a NFChipDs(); } static int CheckBadBlk(U32 addr) { U8 dat; addr &= ~0x1f; NFChipEn(); WrNFCmd(READCMD2); //point to area c WrNFAddr(5); //mark offset 4,5,6,7 WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); WaitNFBusy(); dat = RdNFDat(); WrNFCmd(READCMD0); //point to area a NFChipDs(); return (dat!=0xff); } /************************************************************/ struct Partition{ U32 offset; U32 size; char *name; }; /* static struct Partition NandPart[] = { {0, 0x00030000, "boot"}, //256K {0x00030000, 0x001d0000, "kernel"}, {0x00200000, 0x01e00000, "rootfs"}, //30M {0x02000000, 0x02000000, "ext-fs1"}, //32M {0, 0 , 0} }; */ //modified by vontom //for AT2440EVB static struct Partition NandPart[] = { {0, 0x00040000, "boot"}, //256K {0x00040000, 0x001c0000, "kernel"}, {0x00200000, 0x03500000, "rootfs"}, //30M {0x03500000, 0x03500000, "ext-fs1"}, //32M {0, 0 , 0} }; /* static void TestFunc(void) { U32 i; U8 buf[512]; if(EraseBlock(0x180)) return; for(i=0; i<512; i++) buf[i] = i; WritePage(0x180, buf); for(i=0; i<512; i++) buf[i] = 0; ReadPage(0x180, buf); for(i=0; i<512; i++) printf("%4x", buf[i]); } */ static U32 StartPage, BlockCnt; extern U32 downloadAddress; extern U32 downloadFileSize; static int NandSelPart(char *info) { U16 i, max_sel; struct Partition *ptr = NandPart; printf("Please select which region to %s : Esc to abort\n", info); for(i=0; ptr->size!=0; i++, ptr++) printf("%d : offset 0x%-8x, size 0x%-8x [%s]\n", i, ptr->offset, ptr->size, ptr->name); max_sel = i; while(1) { i = getch(); if(i==0x1b) return -1; if((i>='0')&&(i<(max_sel+'0'))) { i -= '0'; StartPage = NandPart[i].offset>>9; BlockCnt = NandPart[i].size>>14; return i; } } } static void WrFileToNF(void) { int nf_part, i ,size, skip_blks; U32 ram_addr; nf_part = NandSelPart("write"); if(nf_part<0) return; if(downloadFileSize>NandPart[nf_part].size) { puts("Download file size is more large than selected partition size!!!\n"); // return; } printf("Now write nand flash page 0x%x from ram address 0x%x, filesize = %d\n", StartPage, downloadAddress, downloadFileSize); puts("Are you sure? [y/n]\n"); while(1) { char c = getch(); if((c=='y')||(c=='Y')) break; if((c=='n')||(c=='N')) return; } skip_blks = 0; ram_addr = downloadAddress; size = downloadFileSize; for(i=0; size>0; ) { if(!(i&0x1f)) { if(EraseBlock(i+StartPage)) { NandPart[nf_part].size -= 32<<9; //partition available size - 1 block size if(downloadFileSize>NandPart[nf_part].size) { puts("Program nand flash fail\n"); return; } MarkBadBlk(i+StartPage); skip_blks++; i += 32; continue; } } if(WritePage(i+StartPage, (U8 *)ram_addr)) { ram_addr -= (i&0x1f)<<9; size += (i&0x1f)<<9; i &= ~0x1f; NandPart[nf_part].size -= 32<<9; //partition available size - 1 block size if(downloadFileSize>NandPart[nf_part].size) { puts("Program nand flash fail\n"); return; } MarkBadBlk(i+StartPage); skip_blks++; i += 32; continue; } ram_addr += 512; size -= 512; i++; } puts("Program nand flash partition success\n"); if(skip_blks) printf("Skiped %d bad block(s)\n", skip_blks); } #define LINUX_PAGE_SHIFT 12 #define LINUX_PAGE_SIZE (1< >10, devfs_sel, boot_params.string); params->u1.s.page_size = LINUX_PAGE_SIZE; params->u1.s.nr_pages = (boot_params.mem_cfg.val >> LINUX_PAGE_SHIFT); memcpy(params->commandline, parameters, strlen(parameters)); printf("Set boot params = %s\n", params->commandline); } printf("Load Kernel...\n"); if(boot_params.osstor.val) //load program from NOR or NAND FLASH memcpy((void *)buf, (void *)(0x04000000+0x00020000), 0x001e0000); else { StartPage = NandPart[1].offset>>9; size = NandPart[1].size; ram_addr = buf; for(i=0; size>0; ) { if(!(i&0x1f)) { if(CheckBadBlk(i+StartPage)) { printf("Skipped bad block at 0x%x\n", i+StartPage); i += 32; size -= 32<<9; continue; } } ReadPage((i+StartPage), (U8 *)ram_addr); i++; size -= 512; ram_addr += 512; } } if(!boot_params.root_sel.val) { int ramdisk_sz; printf("Load Ramdisk...\n"); StartPage = NandPart[2].offset>>9; size = NandPart[1].size; ram_addr = boot_params.initrd_addr.val; ramdisk_sz = boot_params.initrd_len.val; for(i=0; size>0&&ramdisk_sz>0; ) { if(!(i&0x1f)) { if(CheckBadBlk(i+StartPage)) { printf("Skipped bad block at 0x%x\n", i+StartPage); i += 32; size -= 32<<9; continue; } } ReadPage((i+StartPage), (U8 *)ram_addr); i++; size -= 512; ram_addr += 512; ramdisk_sz -= 512; } } DsNandFlash(); //ChangeClockDivider(13,12); //ChangeMPllValue(67,1,1); //300MHz,2440A! //rCLKCON = 0x7fff0; call_linux(0, boot_params.machine.val, buf); } /************************************************************/ static int have_nandflash; static void InitNandFlash(int info) { U32 i; InitNandCfg(); i = ReadChipId(); if(info) printf("Read chip id = %x\n", i); if((i==0x9873)||(i==0xec75)) NandAddr = 0; else if(i==0xec76) NandAddr = 1; else { if(info) puts("Chip id error!!!\n"); have_nandflash = 0; return; } have_nandflash = 1; if(info) printf("Nand flash status = %x\n", ReadStatus()); } void NandErase(void) { int i, err = 0; InitNandFlash(1); if(!have_nandflash) return; i = NandSelPart("erase"); if(i<0) return; printf("Are you sure to erase nand flash from page 0x%x, block count 0x%x ? [y/n]\n", StartPage, BlockCnt); while(1) { char c; c = getch(); if((c=='y')||(c=='Y')) break; if((c=='n')||(c=='N')) return; } for(i=0; BlockCnt; BlockCnt--, i+=32) { if(EraseBlock(i+StartPage)) { err ++; puts("Press any key to continue...\n"); getch(); } } DsNandFlash(); //disable nand flash interface puts("Erase Nand partition completed "); if(err) printf("with %d bad block(s)\n", err); else puts("success\n"); } void NandWrite(void) { InitNandFlash(1); if(!have_nandflash) return; WrFileToNF(); DsNandFlash(); //disable nand flash interface } extern MemoryTest(void); int RelocateNKBIN(U32 img_src, U32 *pStart, U32 *pLength, U32 *pLaunch); static void LoadRunWince(void) { U32 i, ram_addr, buf = boot_params.initrd_addr.val; int size; MemoryTest(); printf("Load Kernel...\n"); if(boot_params.osstor.val) //load program from NOR or NAND FLASH memcpy((void *)buf, (void *)(0x04000000+0x00020000), 0x00fe0000); else { StartPage = NandPart[boot_params.start.val].offset>>9; //part 2,3... size = NandPart[boot_params.root_sel.val].size - 0x200000;//load 30M data ram_addr = buf; for(i=0; size>0; ) { if(!(i&0x1f)) { if(CheckBadBlk(i+StartPage)) { printf("Skipped bad block at 0x%x\n", i+StartPage); i += 32; //size -= 32<<9; continue; } } ReadPage((i+StartPage), (U8 *)ram_addr); i++; size -= 512; ram_addr += 512; } } printf("run 0x%08x...\n", boot_params.run_addr.val); //RelocateNKBIN(buf, &buf, &i, &boot_params.run_addr.val); call_linux(0, 0, boot_params.run_addr.val); } void NandLoadRun(void) { InitNandFlash(1); //if(!have_nandflash) // return; if(boot_params.start.val<2) //linux LoadRun(); LoadRunWince(); } /* void TestNandFlash(void) { InitNandFlash(); while(1) { U8 key = '2'; puts("\nNand flash operations, press ESC to exit\n"); puts("1.Write nand flash with download file\n"); puts("2.Load progam from nand flash and run\n"); puts("3.Erase nand flash partition\n"); puts("4.Test nand flash erase, write, read\n"); key = getch(); if(key==0x1b) goto TestNandExit; else if(key=='1') WrFileToNF(); else if(key=='2') LoadRun(); else if(key=='3') NandErase(); else if(key=='4') TestFunc(); } TestNandExit: DsNandFlash(); //disable nand flash interface }*/ #include "norflash.h" #define NOR_PARAMS_OFFSET 0x1c000 int search_params(void) { U32 page, page_cnt; U8 dat[528]; BootParams *pBP = (BootParams *)dat; int ret=-1; InitNandFlash(0); //don't show info in InitNandFlash! if(have_nandflash) { page = NandPart[0].offset>>9; page_cnt = NandPart[0].size>>9; //search from the last page while(page_cnt--) { ReadPage(page+page_cnt, dat); if(!strncmp(boot_params.start.flags, pBP->start.flags, 10)) { ret = 0; break; } } } else { memcpy(dat, (void *)(NOR_PARAMS_OFFSET), 512); //now mmu is not set, so use original address if(!strncmp(boot_params.start.flags, pBP->start.flags, 10)) ret = 0; } DsNandFlash(); if(!ret) { ParamItem *pPIS = &pBP->start, *pPID = &boot_params.start; for(; pPID<=&boot_params.user_params; pPIS++, pPID++) if(!strncmp(pPID->flags, pPIS->flags, sizeof(pPID->flags))) pPID->val = pPIS->val; strncpy(boot_params.string, pPIS->flags, boot_params.user_params.val+1); if(boot_params.user_params.val!=strlen(pPID->flags)) { memset(boot_params.string, 0, sizeof(boot_params.string)); boot_params.user_params.val = 0; } } else { //printf("Fail to find boot params! Use Default parameters.\n"); //don't printf anything before serial initialized! } return ret; } //保存在最后两个block,应确保程序(包括出现坏块时)不会覆盖到最后两块 int save_params(void) { U32 page, page_cnt; U8 dat[0x20000]; int ret = 0; InitNandFlash(1); have_nandflash=1; if(have_nandflash) { memset(dat, 0, sizeof(boot_params)); memcpy(dat, &boot_params, sizeof(boot_params)); page = (NandPart[1].offset>>9)-64; for(page_cnt=0; page_cnt<64; page_cnt++) { if(!(page_cnt%32)) EraseBlock(page); if(!WritePage(page+page_cnt, dat)) break; } if(page_cnt>=64) ret = -1; printf("Save boot params %s.\n", ret?"fail":"success"); } else { memcpy(dat, (void *)0x04000000, NOR_PARAMS_OFFSET); memcpy(dat+NOR_PARAMS_OFFSET, &boot_params, sizeof(boot_params)); ProgNorFlash(0, (U32)dat, sizeof(dat)); //28F128 } DsNandFlash(); return ret; } int set_params(void) { int i, key, chg=0; ParamItem *pPID; printf("\nConfig parameters\n"); do { pPID = &boot_params.start; for(i=0; pPID<=&boot_params.user_params; pPID++, i++) printf("[%d] : %s%-8s is 0x%08x (%d)\n", i, (i>9)?"":" ", pPID->flags, pPID->val, pPID->val); printf("[%d] : Exit\n", i); if(boot_params.user_params.val) printf("User parameters is : \"%s\"\n", boot_params.string); printf("\nplease select item:"); key = Uart_GetIntNum(); if(key>=0&&keyval = key; } } else break; } while(1); if(chg) { printf("Do you want to save parameters? press y or Y for save.\n"); key = getch(); if(key=='y'||key=='Y') save_params(); } return 0; }