📄 nand_module.c
字号:
/* * nand_module.c * * Nand flash driver module for SAMSUNG S3C2410 * * Author: Wang Lihui * Date : $Date: 2006/06/05 09:00:00 $ * * $Revision: 1.1.1.0 $ * * Based on s3c2410-ts.c * * Copyright: * (C) HeBei Far East Harris Communications Company Limited. * * History: * * 2006-6-5 Wang Lihui - Initial version * */#include <linux/module.h>#include <asm/arch/S3C2410.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/arch/hardware.h>#include <asm/arch/irqs.h>#include <asm/io.h>//#include "2410addr.h"#include "k9f2808u0c.h"#include "nand_module.h"//#define DEBUG_NAND_FLASH#define DEVICE_NAME "nandflashdrv"#define NANDFLASH_MAJOR 230#define MAX_BUF_LEN 0x6 /* 6KB */int nandflashdevMajor = 0;#define NF_CMD(cmd) {NFCMD=cmd;}#define NF_ADDR(addr) {NFADDR=addr;}#define NF_nFCE_L() {NFCONF&=~(1<<11);}#define NF_nFCE_H() {NFCONF|=(1<<11);}#define NF_RSTECC() {NFCONF|=(1<<12);}#define NF_RDDATA() (NFDATA)#define NF_WRDATA(data) {NFDATA=data;}#define NF_WAITRB() {while(!(NFSTAT&(1<<0)));}//wait tWB and check F_RNB pin.#define ID_K9S1208V0M 0xec76#define ID_K9F2808U0C 0xec73#define NF_BLOCK_SIZE 0x4000#define NF_BLOCK_NUMBER 1024#if 1// HCLK=100Mhz#define TACLS 0//0 //1clk(0ns)#define TWRPH0 3//2 //3clk(25ns)#define TWRPH1 0//0 //1clk(10ns) //TACLS+TWRPH0+TWRPH1>=50ns#else// HCLK=50Mhz#define TACLS 0 //1clk(0ns)#define TWRPH0 1 //2clk(25ns)#define TWRPH1 0 //1clk(10ns)#endif#ifdef BAD_CHECK#undef BAD_CHECK#endifstatic U8 seBuf[16]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};int NF_ReadPage(U32 block,U32 page,U8 *buffer){ int i; register U8 * bufPt=buffer; unsigned int blockPage; U8 ecc0,ecc1,ecc2; U8 se[16]; U8 ReadTmp; //page=page&0x1f; blockPage=(block<<5)+page; NF_RSTECC(); // Initialize ECC NF_nFCE_L(); NF_CMD(0x00); // Read command NF_ADDR(0); // Column = 0 NF_ADDR(blockPage&0xff); // NF_ADDR((blockPage>>8)&0xff); // Block & Page num. NF_ADDR((blockPage>>16)&0xff); // for(i=0;i<10;i++); //wait tWB(100ns) NF_WAITRB(); // Wait tR(max 12us)#if 1 //0 i=NF_PAGE_SIZE; while(i--!=0) { *bufPt++=NF_RDDATA(); // Read one page }#elif 0 //DMA doens't work. rSRCPND=BIT_DMA0; rDISRC0=0x4e00000c; //NF_RDDATA() rDISRCC0=(1<<0); //arc=AHB,src_addr=fix rDIDST0=(unsigned)bufPt; rDIDSTC0=(0<<0); //dst=AHB,dst_addr=inc; rDCON0=(1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(0<<23)|(1<<22)|(0<<20)|(512/4); //Handshake,AHB,interrupt,(4-burst),whole,S/W,no_autoreload,byte,count=512; rDMASKTRIG0=(1<<1)|(1<<0); while(!(rSRCPND & BIT_DMA0)); rSRCPND=BIT_DMA0;#elif 0 __RdPage512(bufPt);#endif ecc0=rNFECC0; ecc1=rNFECC1; ecc2=rNFECC2; se[0]=NF_RDDATA(); se[1]=NF_RDDATA(); se[2]=NF_RDDATA(); ReadTmp = NF_RDDATA(); ReadTmp = NF_RDDATA(); se[5]=NF_RDDATA(); NF_nFCE_H(); if(ecc0==se[0] && ecc1==se[1] && ecc2==se[2] && se[5]==0xff) { return 1; } else { return 0; }}void NF_WritePage(U32 block,U32 page,U8 *buffer){ int i; U32 blockPage=(block<<5)+page; U8 *bufPt=buffer; NF_nFCE_L(); NF_CMD(0x0); NF_CMD(0x80); // Write 1st command NF_ADDR(0); // Column 0 NF_ADDR(blockPage&0xff); // NF_ADDR((blockPage>>8)&0xff); // Block & page num. NF_ADDR((blockPage>>16)&0xff); // for(i=0;i<NF_PAGE_SIZE;i++) { NF_WRDATA(*bufPt++); // Write one page to NFM from buffer } NF_CMD(0x10); // Write 2nd command //Delay(1); //tWB = 100ns. for(i=0;i<10;i++); NF_WAITRB(); //wait tPROG 200~500us; NF_CMD(0x70); // Read status command //Delay(1); //twhr=60ns if (NF_RDDATA()&0x1) // Page write error { NF_nFCE_H(); //return 0; } else { NF_nFCE_H(); //return 1; }}int NF_EraseBlock(U32 block){ int i; U32 blockPage=(block<<5);#if 0/*BAD_CHECK*/ if(NF_IsBadBlock(block) && block!=0) //block #0 can't be bad block for NAND boot return 0;#endif NF_nFCE_L(); NF_CMD(0x60); // Erase one block 1st command NF_ADDR(blockPage&0xff); // Page number=0 NF_ADDR((blockPage>>8)&0xff); NF_ADDR((blockPage>>16)&0xff); NF_CMD(0xd0); // Erase one blcok 2nd command //wait tWB(100ns) cacel by FHC-JISX for(i=0;i<10;i++); NF_WAITRB(); // Wait tBERS max 3ms. NF_CMD(0x70); // Read status command if (NF_RDDATA()&0x1) // Erase error { NF_nFCE_H(); //NF_MarkBadBlock(block);//???cacel the option by FHC-JISX return 0; } else { NF_nFCE_H(); return 1; }}int NF_IsBadBlock(U32 block){ int i; unsigned int blockPage; U8 data; blockPage=(block<<5); // For 2'nd cycle I/O[7:5] NF_nFCE_L(); NF_CMD(0x50); // Spare array read command NF_ADDR(517&0xf); // Read the mark of bad block in spare array(M addr=5) NF_ADDR(blockPage&0xff); // The mark of bad block is in 0 page NF_ADDR((blockPage>>8)&0xff); // For block number A[24:17] NF_ADDR((blockPage>>16)&0xff); // For block number A[25] for(i=0;i<10;i++); // wait tWB(100ns) //????? NF_WAITRB(); // Wait tR(max 12us) data=NF_RDDATA(); NF_nFCE_H(); if(data!=0xff) { return 1; } else { return 0; }}void NF_Reset(void){ int i; NF_nFCE_L(); NF_CMD(0xFF); //reset command for(i=0;i<10;i++); //tWB = 100ns. NF_WAITRB(); //wait 200~500us;shit NF_nFCE_H();}void NF_Init(void){ NFCONF=0xf830; //(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); // 1 1 1 1, 1 xxx, r xxx, r xxx // En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 NF_Reset();}/*by FHC-JISX for NAND FLASH TEST*/int NF_ReadId(void){ int i, mfr,id; /* Chip Enable */ NF_nFCE_L(); for(i=0; i<10; i++); /* read nand flash ID CMD */ NF_CMD(0x90); // Read ID command /* Write Address */ NF_ADDR(0 & 0xff); NF_ADDR((0 >> 9) & 0xff); NF_ADDR((0 >> 17) & 0xff); NF_ADDR((0 >> 25) & 0xff); /* wait the idle state */ for(i=0; i<10; i++); NF_WAITRB(); /* read the id data */ mfr = NF_RDDATA(); id = NF_RDDATA(); /* chip Disable */ NF_nFCE_H(); return 0;}int nandflash_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ /* char local_buffer[MAX_BUF_LEN]; */ char* local_buffer; int nRead; int block_index,page_index;#ifdef DEBUG_NAND_FLASH printk("\nnandflash_read,count:0x%x,blockindex:0x%x", count, (int)*ppos);#endif //bug... copy_from_user(&block_index, (int *)&buffer[0],4); copy_from_user(&page_index, (int *)&buffer[4],4); local_buffer = kmalloc(count,GFP_KERNEL); if(local_buffer == NULL) { return 0; } for(page_index = 0, nRead = 0; page_index < NF_PAGE_NUMBER; page_index++) { NF_ReadPage(block_index, page_index, local_buffer + nRead); nRead += NF_PAGE_SIZE; } copy_to_user(buffer+8, local_buffer, nRead); return nRead;}int nandflash_write(struct file *filp, char *buffer, size_t count, loff_t *ppos){ char* local_buffer; int nWrite; int i; int block_index,page_index;#ifdef DEBUG_NAND_FLASH //bug... printk("nandflash_write,count:0x%x,blockindex:0x%x\n", count,*(int*)buffer);#endif local_buffer = kmalloc(count+4,GFP_KERNEL); if(local_buffer == NULL) { printk("\nnandflash_write,kmalloc err"); return 0; } copy_from_user(local_buffer, buffer, count+sizeof(long)); //bug... //block_index = (int)buffer[0]; block_index = *(int*)buffer; // if( block_index < 0 || block_index > MAX_BLOCKS) // { // printk("nandflash_write,block index err:%x",block_index); // return 0; // }#ifdef DEBUG_NAND_FLASH printk("\nDRIVER:\n"); for (i=sizeof(long);i<count;i++) printk(" %x",local_buffer[i]); printk("\n"); printk("Index : %d\n",block_index);#endif nWrite = 0; for(page_index = 0, nWrite = 0; page_index < NF_PAGE_NUMBER; page_index++) { NF_WritePage(block_index, page_index,local_buffer+nWrite+sizeof(long)); nWrite += NF_PAGE_SIZE; } kfree(local_buffer); return nWrite;}/****************************** nandflash_eraseblock*******************************/static int nandflash_eraseblock(int blocknum){#ifdef DEBUG_NAND_FLASH printk("\nnandflash_eraseblock,blockindex:0x%x", blocknum);#endif return NF_EraseBlock(blocknum);}static int nandflash_poll(struct file *filp, struct poll_table_struct *wait){ return 0 ;}static int nandflash_open(struct inode *inode, struct file *filp){#ifdef DEBUG_NAND_FLASH printk("\nnandflash_open");#endif NFCONF=0xf830; NF_Reset(); //GPFCON = 0x5555; //GPFDAT = 0x00; MOD_INC_USE_COUNT; return 0;}static int nandflash_release(struct inode *inode, struct file *filp){ MOD_DEC_USE_COUNT; return 0;}static int nandflash_ioctl( struct inode *inode, struct file *filp, unsigned int nCmd, long argument ){ int retval = 0; int block_index;#ifdef DEBUG_NAND_FLASH printk("\nnandflash_ioctl,cmd:0x%x,blockindex:0x%x", nCmd, (int)argument);#endif block_index = argument; switch( nCmd ) { case CMD_NF_ERASE_BLOCK: retval = nandflash_eraseblock(block_index); break; default: retval = 1; break; } return retval;}static struct file_operations nandflash_fops = { owner: THIS_MODULE, open: nandflash_open, read: nandflash_read, write: nandflash_write, release: nandflash_release, ioctl: nandflash_ioctl, poll: nandflash_poll,};static int __init nandflash_init(void){ int ret; ret = register_chrdev(NANDFLASH_MAJOR, DEVICE_NAME, &nandflash_fops); //FHC-JISX if (ret < 0) { printk(DEVICE_NAME ":can't get major number\n"); return ret; } nandflashdevMajor = ret;#ifdef DEBUG_FLASH printk("\nnandflash_init,major:%x",ret);#endif return 0;}static void __exit nandflash_exit(void){ unregister_chrdev(nandflashdevMajor, DEVICE_NAME);}module_init(nandflash_init);module_exit(nandflash_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -