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

📄 nand.c

📁 最近在國外網站抓到的作業系統 以Arm為基礎去開發的
💻 C
字号:
/*
 *  drivers/mtd/nand.c
 *
 *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
 *
 * $Id: nand.c,v 1.1.1.1 2004/12/22 10:02:10 zyu Exp $
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  Overview:
 *   This is the generic MTD driver for NAND flash devices. It should be
 *   capable of working with almost all NAND chips currently available.
 */

#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ids.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/kernel.h>
//#include  <linux/mtd/esram-command.h>                           		//GIII

typedef void (* TREAD)( void);					//GIII wuer
extern TREAD  gfdpread, gfdpwrite, gfdperase;


#undef CONFIG_MTD_NAND_ECC   				//GIII

#ifdef CONFIG_MTD_NAND_ECC
#include <linux/mtd/nand_ecc.h>
#endif

extern  pid_t wait;
/*
 * Macros for low-level register control
 */
#define NAND_CTRL (*(volatile unsigned char *) \
			((struct nand_chip *) mtd->priv)->CTRL_ADDR)

#define nand_select()	; //{nand_command(mtd, NAND_CMD_RESET, -1, -1); \
			//udelay (10);}
#define nand_deselect()  //{NAND_CTRL |= 0X00;}   //NAND_CTRL |= ~this->NCE;

/*
 * NAND low-level MTD interface functions
 */
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
			size_t *retlen, u_char *buf);
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
				size_t *retlen, u_char *buf, u_char *ecc_code);
static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
				size_t *retlen, u_char *buf);
static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
			size_t *retlen, const u_char *buf);
static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
				size_t *retlen, const u_char *buf,
				u_char *ecc_code);
static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
				size_t *retlen, const u_char *buf);
static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
				unsigned long count, loff_t to, size_t *retlen);
static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
static void nand_sync (struct mtd_info *mtd);



/***************************/
int abc(){
  int c = 1;
    c++;
   return c;
   }

/*
 * Send command to NAND device
 */
static void nand_command (struct mtd_info *mtd, unsigned command,
				int column, int page_addr)
{
	register struct nand_chip *this = mtd->priv;
	register unsigned long NAND_IO_ADDR = GFD_NAND_COM;

	printf("Garfield III: Entering nand_command{} and do 0x%x.\n",(unsigned long)command);
	
		
	*(RP)(NAND_IO_ADDR) = command;

	 //printf("nand_command(): jumping  out now.\n");
	/* Pause for 15us */
	udelay (15);
}

/*
 * NAND read
 */
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
			size_t *retlen, u_char *buf)
{
#ifdef CONFIG_MTD_NAND_ECC
	struct nand_chip *this = mtd->priv;
	
	return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf);
#else
	return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
#endif
}

/*
 * NAND read with ECC
 */
static int nand_read_ecc (U32 from, U32 len, U8 *buf)
{
	register int d = 1;
	int i,j, col, page, state, retlen;
	int erase_state = 0;
	U8 *tempbuf;
	U8 *tempbuf2;
	U8 *tempbuf_head;

	tempbuf_head = SysLmalloc (len+1024);
	if (!tempbuf_head) {
		printf("nand_read_ecc():Unable to allocate NAND data tempbuf_head for Garfield III.\n");
		return -1;
	}

	/* Do not allow reads past end of device */
	//printf("nand_read_ecc():Do not allow reads past end of device.\n");                          
	if ((from + len) > 4096*32*512) {
		printf("out of device");
		SysLfree(tempbuf_head);
		return -1;
	}

	/* First we calculate the starting page */
	page = from >> 9;			                 //page_shift SHOULD be 9 in GIII
	printf("nand_read_ecc():Now page is %x,\n",page);
	
	/* Get raw starting column */
	col = from & 0x1ff;                	             //lowest 9 bits -> column

	/* Initialize return value */
	retlen = 0;

	/* Record address of tempbuf head  */
	tempbuf = tempbuf_head ;

	//*(RP)(0x10003000) &= ~(0x10);			//GPT  DOWN
	//*(RP)(0x10000000)  = 0x0000000;			//shutdown inters


	/* Loop until all data read */
	while (retlen < len) {
		*(RP)GFD_NAND_ADDR = ((unsigned long)page)<<8;
		
		*(RP)GFD_NAND_CONF = 0x2200aaa;
		
		*(RP)DMACC0SrcAddr = GFD_NAND_DATA;					//read source = nand data register
	
		*(RP)DMACC0DestAddr = (unsigned int)tempbuf;
	
		*(RP)DMACC0Control = 0x20249b;
		
		*(RP)DMACC0Configuration = 0x31d;                      		//channel config finished!
		
		*(volatile unsigned int *)0x11000104 = (0x80000000 );

		j = *(volatile unsigned int *)0x11000124;
		while((j&0x1) != 0x1){
			j = *(volatile unsigned int *)0x11000124;
		}	

		retlen = retlen +512;                                //////////test////
		tempbuf += 512;
		page++;
		
	}

	
	
	
	tempbuf2 = tempbuf_head+col;
	for (j=0 ; j < len ; j++){
		buf[j] = *(tempbuf2);
		//printf("read buffer data[0x%x] is 0x%x.\n",j,buf[j]);
		tempbuf2++;
	}
	

	//printf("GIII Nand:  kfree (tempbuf_head).\n");
	SysLfree(tempbuf_head);
	
	//printf("GIII Nand:jumping out of read_ecc Now.\n");
	//printf("****************************************************\n");
	/* Return happy */
	return 0;
}

static int nand_read_page (U32 from,  U8 *buf)
{

	int j, pagenum;

	if ((from + 512) > 4096*32*512)
		printf("nand_write_page: Attempted read past end of device\n");
	
	/* First we calculate the starting page */
	pagenum = from >> 9;			                 
		
	*(RP)GFD_NAND_ADDR = ((unsigned long)pagenum)<<8;
		
	*(RP)GFD_NAND_CONF = 0x2200aaa;
			
	*(RP)DMACC0SrcAddr = GFD_NAND_DATA;					
	
	*(RP)DMACC0DestAddr = (unsigned int)buf;
				
	*(RP)DMACC0Control = 0x20249b;
		
	*(RP)DMACC0Configuration = 0x31d;                      		

	*(volatile unsigned int *)0x11000104 = (0x80000000 );

	j = *(volatile unsigned int *)0x11000124;
	while((j&0x1) != 0x1){
		j = *(volatile unsigned int *)0x11000124;
	}	
	return 0;
	
}

static int nand_read_block (U32 from,  U8 *buf)
{
	int i;
	U8 *tempbuf;

	tempbuf = buf;
	if ((from + 32*512) > 4096*32*512){
		printf("nand_read_block: Attempted read past end of device\n");
		return -1;
	}

	/* First we calculate the starting page */
	
	for(i=0; i<32; i++){
		nand_read_page (U32 from,  U8 *tempbuf);
		from += 512;
		tempbuf += 512;
	}

	return 0;
	
}


static int nand_write_page (U32 to, U8*buf)
{
	int i, j,page;

	/* Do not allow write past end of page */
	if ((to + len) > 4096*32*512) {
		printf("nand_write_page: Attempted write past end of device\n");
		return -1;
	}

	/* Shift to get page and block; one block has 32 pages */
	page = ((int) to) >> 9;				//page_shift = 9
	
	/* Select the NAND device */
	*(RP)GFD_NAND_COM = NAND_CMD_RESET;
		
	*(RP)GFD_NAND_ADDR = ((unsigned long)page)<<8;
	*(RP)GFD_NAND_CONF = 0x02200aaa;
	*(RP)DMACC0SrcAddr = buf ;			
	*(RP)DMACC0DestAddr = GFD_NAND_DATA;
	*(RP)DMACC0Control = 0x0020149B;
	*(RP)DMACC0Configuration = 0x301b;

	*(volatile unsigned int *)0x11000104 = (0x80000080);	
	j = *(volatile unsigned int *)0x11000124;
	while((j&0x1) != 0x1){
		j = *(volatile unsigned int *)0x11000124;
	}	
	return 0;
	
}


static int nand_write_block (U32 to, U8*buf)
{
	int i,tempto;
	U8 *tempbuf;

	tempbuf = buf;
	
	if ((to + 32*512) > 4096*32*512){
		printf("nand_write_block: Attempted read past end of device\n");
		return -1;
	}

	/*make sure block head address */
	tempto = (to >> 14)<<14;						

	/*we should erase one block before write something into it*/
	nand_erase_block(tempto);
	
	
	for(i=0; i<32; i++){
		nand_write_page ( tempto,  tempbuf);
		tempto+= 512;
		tempbuf += 512;
	}

	return 0;
	
}


/*
 * NAND write
 */
static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
			size_t *retlen, const u_char *buf)
{
#ifdef CONFIG_MTD_NAND_ECC
	struct nand_chip *this = mtd->priv;
	
	return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);
#else
	return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
#endif
}

/*
 * NAND write with ECC
 */
static int nand_write_ecc (U32 to, U32 len, U8*buf)
{
	int i, j; 
	int first_page, last_page,  start_block, end_block, blocknum, col, cnt, relative_addr;
	U32 retlen;
	U32 *data_buf;

	/* Do not allow write past end of page */
	if ((to + len) > 4096*32*512) {
		printf("nand_write_ecc: Attempted write past end of device\n");
		return -1;
	}

	data_buf = SysLmalloc (32*512);			//malloc one block memory for temp use
	if (!data_buf) {
		printf("nand_read_ecc():Unable to allocate NAND data tempbuf_head for Garfield III.\n");
		return -1;
	}

	/* Shift to get page and block; one block has 32 pages */
	first_page = ((int) to) >> 9;				//page_shift = 9
	start_block = first_page>>5;					//block_shift = 5

	last_page = ((int)(to + len))>>9;
	end_block = last_page>>5;

	blocknum = end_block - start_block;

	relative_addr = to-start_block*32*512;		//count the relative address in one block
	col = relative_addr;						
	retlen = len;
	cnt =0;
	
	for(blocknum=start_block; blocknum<=end_block; blocknum++)
	{

		//把这一块读到data_buf
		nand_read_block ((blocknum << 14),  data_buf);
		
		if(relative_addr+len<32*512)
		{
			for(i=0; i<len; i++)
				data_buf[col+i] = buf[i];
			
			// write data_buf into NANDFLASH (one block)
			nand_write_block ((blocknum << 14), data_buf);
		}else{
			if(retlen+col>=32*512)
			{
				for(i=col; i<32*512; i++,cnt++)
					data_buf[col+i] = buf[cnt];
				
				// write data_buf into NANDFLASH
				nand_write_block ((blocknum << 14), data_buf);
				
				col = 0;
				retlen -= 32*512;
			}else{
				for(i=0; i<retlen; i++,cnt++)
					data_buf[i] = buf[cnt];
				
				// write data_buf into NANDFLASH
				nand_write_block ((blocknum << 14), data_buf);
			}
		}

	}
		
	printf("****************************************************\n");
	printf("nand_write():jumping out of nand_write_ecc().\n");
	return 0;
}



/*
 * NAND erase a block
 */
static int nand_erase_block(U32 blockhead)
{
	int i,realadd;

	/* Do not allow erase past end of device */
	if (blockhead > 4096*32*512) {
		printf ("nand_erase_block: Erase past end of device\n");
		return -1;
	}
	
	/* Shift to get first page */
	realadd = (int) (realadd << 9);
	
	/*erase action now!*/
	*(RP)(GFD_NAND_CONF) = 0x00100aaa; 			// 3 addresses modle
	*(RP)GFD_NAND_ADDR = (realadd >> 9 );
	
	/*GPIO PH5 SET TO 1, unprotect write!!!!!!!!!*/
	*(RP)0x1000B06C = 0x00000020;
	*(RP)0x1000B07C = 0x00000020;
	*(RP)0x1000B068 = 0x00000000;
	
	*(RP)0x11000104 = 0x80000060;

	i = *(volatile unsigned int *)GFD_NAND_IDLE;
	while((i&0x1) != 0x1){
		i = *(volatile unsigned int *)GFD_NAND_IDLE;
	}
	
	return 0;
}


MODULE_LICENSE("GPL");
MODULE_AUTHOR("cnasic wuer changed");
MODULE_DESCRIPTION("Garfield NAND flash driver code");

⌨️ 快捷键说明

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