⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand1.c

📁 学习Linux编程的源代码。包括各种系统调用如何使用等。
💻 C
字号:
#include "nand.h"



#define MAJOR_NR 31
/* #define MAJOR_NR 60 */

#define ROM_MINOR   8   /* ro ROM card */
#define FLASH_MINOR 16  /* rw Flash card */

/* Don't touch the MAX_CHIPS until the hardcoded chip0 and chip1 are
   removed from the code.  */

#define MAX_CHIPS 2
#define MAX_PARTITIONS 8

#define EWP 100
#define EIO 200
#define EINVAL 400

void udelay(int tick)
{
	int i;
	for(i=0; i<tick*100;i++);
}

void set_cs()
{
	*(unsigned char *)0x8080000c=0x00;
}

void clear_cs()
{
	*(unsigned char *)0x8080000c=0x01;
}

void set_addr()
{
	*(unsigned char *)0x80800004=0x01;
    *(unsigned char *)0x80800008=0x00;
}
void clear_addr()
{
	*(unsigned char *)0x80800004=0x00;
}
void set_command()
{
	*(unsigned char *)0x80800008=0x01;
    *(unsigned char *)0x80800004=0x00;
}
void clear_command()
{
	*(unsigned char *)0x80800008=0x00;
}

void read_nandid()
{
	unsigned char id[2];
    set_cs();
    set_command();
	*(unsigned char *)DATA_ADDR = NAND_CMD_READID;
    clear_command();
    set_addr();
	*(unsigned char *)DATA_ADDR = 0x00;
   //*(unsigned char *)0x80800004=0x00;
    clear_addr();
	id[0]=*(unsigned char *)DATA_ADDR;
	id[1]=*(unsigned char *)DATA_ADDR;
    clear_cs();
}

int nand_write(unsigned long to, int len,int *retlen, unsigned char *buf)
{
	int i,cnt,status;
	unsigned char tmpbuf[OOBBLOCK+OOBSIZE];
	unsigned long page;
	unsigned long col;
	unsigned short tmpvalue=0;
    set_cs();
	
	page = ((int) to) >> PAGE_SHIFT;

	/* Get the starting column */
	col = to & (OOBBLOCK - 1);
	
 	// set_cs();
 	 
	/* Check the WP bit */
	nand_command (NAND_CMD_STATUS, -1, -1);
    if (!(*(unsigned char *)DATA_ADDR &0x80)){
		return -EWP;
	}

	*retlen = 0;

	/* Loop until all data is written */
	while (*retlen < len) {
		/* 将数据写到缓冲区中,判断是否超出一页 */
		if ((col + len) >= OOBBLOCK)
			for(i=col, cnt=0 ; i < OOBBLOCK ; i++, cnt++)
				tmpbuf[i] = buf[(*retlen + cnt)];
		else
			for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)
				tmpbuf[i] = buf[(*retlen + cnt)];
		

		/* Write ones for partial page programming */
		for (i=OOBBLOCK ; i < (OOBBLOCK+OOBSIZE) ; i++)
			tmpbuf[i] = 0xff;

		/* Write pre-padding bytes into buffer */
		for (i=0 ; i < col ; i++)
			tmpbuf[i] = 0xff;

		/* Write post-padding bytes into buffer */
		if ((col + (len - *retlen)) < OOBBLOCK) {
			for(i=(col + cnt) ; i < OOBBLOCK ; i++)
				tmpbuf[i] = 0xff;
		}


		/* Send command to begin auto page programming */
		nand_command (NAND_CMD_SEQIN, 0x00, page);

		/* Write out complete page of data */
		for (i=0 ; i < (OOBBLOCK+OOBSIZE) ; i++)
            *(unsigned char *)DATA_ADDR=tmpbuf[i];

		/* Send command to actually program the data */
		nand_command (NAND_CMD_PAGEPROG, -1, -1);

		/*
		 * Wait for program operation to complete. This could
		 * take up to 3000us (3ms) on some devices, so we try
		 * and exit as quickly as possible.
		 */
		status = 0;
		for (i=0 ; i<24 ; i++) {
			/* Delay for 125us */
			udelay (12500);

			/* Check the status */
			nand_command (NAND_CMD_STATUS, -1, -1);
//			status = (int) readb (nand->io_addr);
            status = (int) *(unsigned char* )DATA_ADDR;
			if (status & 0x40)
				break;
		}

		/* See if device thinks it succeeded */
		if (status & 0x01) {
			return -EIO;
		}

		/*验证写的是否正确*/
		/* Send command to read back the page */
		if (col < ECCSIZE)
			nand_command (NAND_CMD_READ0, col, page);
		else
			nand_command (NAND_CMD_READ1, col - 256, page);

		/* Loop through and verify the data */
		for (i=col ; i < cnt ; i++) {
			tmpvalue=*(unsigned char* )DATA_ADDR;
//			if (tmpbuf[i] != *(unsigned char* )DATA_ADDR) {
//				return -EIO;
//			}
		}



		/*
		 * If we are writing a large amount of data and/or it
		 * crosses page or half-page boundaries, we set the
		 * the column to zero. It simplifies the program logic.
		 */
		if (col)
			col = 0x00;

		/* Update written bytes count */
		*retlen += cnt;

		/* Increment page address */
		page++;
	}


	/* Return happy */
	*retlen = len;
	return 0;
}

int nand_read (unsigned long from, int len, int *retlen, unsigned char *buf)
{

	int j, state;
	unsigned long page;
	unsigned long col;
	int erase_state = 0;
	unsigned char oobvalue;

	/* Do not allow reads past end of device */
	if ((from + len) > NAND_SIZE) {
		*retlen = 0;
		return -EINVAL;
	}

	/* First we calculate the starting page */
	page = from >> PAGE_SHIFT;

	/* Get raw starting column */
	col = from & (OOBBLOCK - 1);

	/* State machine for devices having pages larger than 256 bytes */
	state = (col < ECCSIZE) ? 0 : 1;

	/* Calculate column address within ECC block context */
	col = (col >= ECCSIZE) ? (col - ECCSIZE) : col;

	/* Initialize return value */
	*retlen = 0;
    set_cs();
	/* Loop until all data read */
	while (*retlen < len) {


		/* Send the read command */
		if (!state)
			nand_command (NAND_CMD_READ0, col, page);
		else 
			nand_command (NAND_CMD_READ1, col, page);

		/* Read the data directly into the return buffer */ //第一个256字节
		if ((*retlen + (ECCSIZE - col)) >= len) {
			while (*retlen < len)
            {

//                *(nand->io_addr)=from+(*retlen);
/*				oobvalue=*(unsigned char*)DATA_ADDR;
				(*retlen)++;
				if(oobvalue ==0xff)
				{
					buf[(*retlen)]=oobvalue;
				}
*/            	buf[(*retlen)++] =*(unsigned char*)DATA_ADDR;
            }
//				buf[(*retlen)++] = readb (nand->IO_ADDR);
			/* We're done */
			continue;
		}
		else//第二个256字节
		{
        	for (j=col ; j < ECCSIZE ; j++)
            {
/*           		oobvalue=*(unsigned char*)DATA_ADDR;
				(*retlen)++;				
*/            	buf[(*retlen)++] =*(unsigned char*)DATA_ADDR;
            }
        }


		/*
		 * If the amount of data to be read is greater than
		 * (256 - col), then all subsequent reads will take
		 * place on page or half-page (in the case of 512 byte
		 * page devices) aligned boundaries and the column
		 * address will be zero. Setting the column address to
		 * to zero after the first read allows us to simplify
		 * the reading of data and the if/else statements above.
		 */
		if (col)
			col = 0x00;

		/* Increment page address */
		if ((OOBBLOCK == 256) || state)
			page++;

		/* Toggle state machine */
		if (OOBBLOCK == 512)
			state = state ? 0 : 1;
	}
	clear_cs();
	/* Return happy */
	return 0;
}


/*
 * Send command to NAND device
 */
void nand_command (unsigned int command,	unsigned char column, unsigned short page_addr)
{
	/*
	 * Write out the command to the device.
     
	 */
     set_command();
	if (command != NAND_CMD_SEQIN)	
        *(unsigned char*)CTRL_ADDR = command;
//		writeb (command, NAND_IO_ADDR);
	else {
		if (OOBBLOCK == 256 && column >= 256) {
			column -= 256;
            *(unsigned char*)CTRL_ADDR=NAND_CMD_RESET;
            *(unsigned char*)(CTRL_ADDR)=NAND_CMD_READOOB;
             *(unsigned char*)(CTRL_ADDR)=NAND_CMD_SEQIN;
/*			writeb(NAND_CMD_RESET, NAND_IO_ADDR);
			writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
*/		}
		else if (OOBBLOCK == 512 && column >= 256) {
			if (column < 512) {
				column -= 256;
                 *(unsigned char*)(CTRL_ADDR)=NAND_CMD_READ1;
                 *(unsigned char*)(CTRL_ADDR)=NAND_CMD_SEQIN;
/*				writeb(NAND_CMD_READ1, NAND_IO_ADDR);
				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
*/			}
			else {
				column -= 512;
                 *(unsigned char*)(CTRL_ADDR)=NAND_CMD_READOOB;
                 *(unsigned char*)(CTRL_ADDR)=NAND_CMD_SEQIN;
/*				writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
*/			}
		}
		else {
             *(unsigned char*)(CTRL_ADDR)=NAND_CMD_READ0;
             *(unsigned char*)(CTRL_ADDR)=NAND_CMD_SEQIN;
/*			writeb(NAND_CMD_READ0, NAND_IO_ADDR);
			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
*/		}

	}
	clear_command();
    set_addr();
	/* Serially input address */
	if (column != -1)
         *(unsigned char*)(IO_ADDR)=column;
//		writeb (column, NAND_IO_ADDR);
	if (page_addr != -1) {
         *(unsigned char*)(IO_ADDR)=(unsigned char) (page_addr & 0xff);
         *(unsigned char*)(IO_ADDR)=(unsigned char) ((page_addr >> 8) & 0xff);
/*		writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
		writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
*/		/* One more address cycle for higher density devices */
//			writeb ((unsigned char) ((page_addr >> 16) & 0x0f),
//					NAND_IO_ADDR);
	}
    clear_addr();
	/* Pause for 15us */
	udelay (15);
}
/*
 * NAND erase a block
 */
int nand_erase (unsigned long startaddr,int eraselen)
{
	int i, len, status, pages_per_block;
	unsigned long page;

	/* Start address must align on block boundary */
	if (startaddr & (EARSE_SIZE - 1)) {
		return -EINVAL;
	}

	/* Length must align on block boundary */
	if (eraselen & (EARSE_SIZE - 1)) {
		return -EINVAL;
	}

	/* Do not allow erase past end of device */
	if ((eraselen + startaddr) > NAND_SIZE) {
		return -EINVAL;
	}


	/* Shift to get first page */
	page = (int) (startaddr >> PAGE_SHIFT);

	/* Calculate pages in each block */
	pages_per_block = EARSE_SIZE / OOBBLOCK;


	/* Check the WP bit */
	nand_command (NAND_CMD_STATUS, -1, -1);
	if (!(*(unsigned char*)(DATA_ADDR) & 0x8080)) {
		return -EIO;
	}

	/* Loop through the pages */
	len = eraselen;
	while (len) {
		/* Send commands to erase a page */
		nand_command( NAND_CMD_ERASE1, -1, page);
		nand_command( NAND_CMD_ERASE2, -1, -1);

		/*
		 * Wait for program operation to complete. nand could
		 * take up to 4000us (4ms) on some devices, so we try
		 * and exit as quickly as possible.
		 */
		status = 0;
		for (i=0 ; i<32 ; i++) {
			/* Delay for 125us */
			udelay (125);

			/* Check the status */
			nand_command ( NAND_CMD_STATUS, -1, -1);
			//status = (int) readb (nand->io_addr);
            status = (int) *(unsigned char*)(DATA_ADDR);
			if (status & 0x40)
				break;
		}

		/* See if block erase succeeded */
		if (status & 0x01) {
			return -EIO;
		}

		/* Increment page address and decrement length */
		len -= EARSE_SIZE;
		page += pages_per_block;
	}
	/* Return happy */
	return 0;
}
/*
 * NAND read out-of-band
 */
int nand_read_oob (unsigned long from, int len, int *retlen, unsigned char *buf)
{

	int i, col, page;
	unsigned char oobvalue[16];
	/* Shift to get page */
	page = ((int) from) >> PAGE_SHIFT;
		/* Mask to get column */
	col = from & 0x0000000f;
	
		/* Initialize return length value */
	*retlen = 0;

	if ((col + len) > OOBSIZE) {
		return -EINVAL;
	}
	
	for (i = 0 ; i < len ; i++)
	{
		oobvalue[i]=0xaa;
	}
		/* Send the read command */
	nand_command ( NAND_CMD_READOOB, col, page);	


	/* Read the data */
	for (i = 0 ; i < len ; i++)
	{
		
		buf[i] = *(unsigned char*)(DATA_ADDR);
	}
//		
	/* Return happy */
	*retlen = len;
	return 0;



}

/*test program for nand driver*/
void main()
{
	unsigned char wdbuf[64],rdbuf[528];
	int i;
	unsigned long startaddr,oobaddr;
    int  retlen[1] ;
    int earsesize=EARSE_SIZE;
    unsigned char ch[2];
    *(unsigned short *)0x00c20002=0x3c03;
 
 #if 0
    for(;;)
    {
    *(unsigned char *)0x80800000=0x55;
    *(unsigned char *)0x80800000=0xaa;
       *(unsigned char *)0x80800004=0x55;
    *(unsigned char *)0x80800008=0xaa;
       *(unsigned char *)0x8080000c=0x55;
    *(unsigned char *)0x8080000c=0xaa;
    
    ch[0]=*(unsigned char *)0x80800000;
    ch[2]=*(unsigned char *)0x80800000;
    }
  
 # endif
    * retlen = 0;
	for (i=0;i<64 ;i++ )
	{
		wdbuf[i]=0x31+i%10; 
		rdbuf[i]=0;
	}


	startaddr = 512;
    
   //for(;;)
	
	read_nandid();
    set_cs();
	
	for (i=0;i<528 ;i++ )
	{
		rdbuf[i]=2;
	}
	oobaddr=1024;
//	nand_read_oob(oobaddr,16,retlen,&rdbuf[0]);
	nand_write( startaddr, 64, retlen, &wdbuf[0]);
	nand_read( startaddr, 128, retlen, &rdbuf[0]);

	for (i=0;i<16 ;i++ )
	{
		if(rdbuf[i]!=0xff)
            rdbuf[i]=0;
	}

/*	startaddr = 0x0100;
//	nand_write( startaddr, 64, retlen, wdbuf);
	nand_read( startaddr, 64, retlen, rdbuf);

	for (i=0;i<64 ;i++ )
	{
		rdbuf[i]=0;
	}

	startaddr = 0x0200;
	nand_write( startaddr, 64, retlen, wdbuf);
	nand_read( startaddr, 64, retlen, rdbuf);

	startaddr = 0x0000;
	nand_erase( startaddr, earsesize);
*/
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -