首页 > 代码库 > Tiny6410之NAND FLASH驱动

Tiny6410之NAND FLASH驱动

一、NAND FLASH的特点

S3C6410的NAND FLASH控制器有如下特点

1、自导入模式:复位后,引导代码被送入到8KB的STEPPINGSTONE中,引导代码移动完毕,引导代码将在STEPPINGSTONE中执行。导入期间,NAND FLASH控制器不支持ECC矫正。

2、NAND FLSH 控制器I/F:支持512字节和2KB页

3、软件模式:用户可以直接访问nand flash 控制器,该特性可以用于读/檫/编程nand flash 存储器。

1)写命令寄存器=NAND FLASH存储器命令周期

2)写地址寄存器=NAND FLASH存储器地址周期

3)写数据寄存器=写数据到NAND FLASH存储器(写周期)

4)读数据寄存器=从NAND FLASH 存储器数据(读周期)

5)读主ECC寄存器和备用ECC寄存器=从NAND FLASH存储器读数据

4、接口:8位NAND FLASH存储器接口总线

5、硬件:ECC产生、检测和标志(软件纠正)

6、支持SLC和MLC的NAND FLASH控制器:1位ECC用于SLC,4位ECC用于MLC的NAND FLASH

7、特殊功能寄存器I/F:支持字节/半字/字数据访问ECC的数据寄存器,用字来访问其他寄存器

8、STEPPINGSTONE I/F:支持字节/半字/字数据的访问

9、8KB的内部SRAM的缓冲器STEPPINGSTONE,在NAND FLASH引导后可做其他用途使用

该Tiny6410 开发板使用的NAND FLASH的类型为MLC大小为2G,型号K9GA08U0E-S

二、驱动设计

第一步:设置NAND FLASH的控制寄存器

  通过S3C6410数据手册可知NNAD FLASH的控制寄存器为NFCONF

寄存器       地址

NFCONF   0x70200000

  在NFCONF寄存器中主要用到TACLS、TWRPH0、TWRPH1,这三个变量。这三个变量用于配置nand flash 的时序。通过时序图

技术分享

  由上图可知,TACLS为CLE/ALE 有效到nWE有效之间的持续时间。TWRPH0 位nWE的有效持续时间。TWRPH1为nWE无效到CLE/ALE 无效之间的持续时间。这些时间都是以HCLK为单位的。

  通过K9F2G08U0E数据手册(如下图)可知tWp 和TWRPH0相对应,(tcls-twp)与TALS相对应,tCLH与TWRPH1相对应。

技术分享

  K9F2G08U0给出的值都是最小值。故在取值是只要满足该最小值就可以了。因此在这里我将TACLS、TWRPH0、TWRPH1分别取值为0x2、0xF和0x7。

故将NFCONF寄存器的设值为((0x2<<12)|(0xf<<8)|(0x7<<4))

第二步:使能NAND FLASH

  通过S3C6410的诗句手册可以知道使能NAND FLASH的寄存器为NFCONT

寄存器      地址

NFCONT   0x7020004

  由寄存器的描述可知,NFCONT的bit0位是控制NAND FLASH的。故将NFCONT的第零位设值为1即使能了NAND FLASH。

第三步:读操作(页读)

如下图可知读操作主要分五步走

技术分享

  1、发片选:即设置NFCONT的bit1为0

  2、发命令:0x00,即往NFCMD写0x00

  3、发地址:由下图知地址需要分5个时钟周期来发送的,即往NFADDR写入地址,因为NFADDR一次只能接受8bit的数据

技术分享

  4、发读命令:0x30,即往NFCMD写0x30

  5、连续读2048个字节,即连续读NFDATA寄存器2048次。

第四步:拷贝

  调用NAND FLASH的读操作,直到把.bin文件完全的从NAND FLASH中拷贝到 DRAM中。

第五步:编码运行

主要代码实现如下

//start.S
.global _start
_start
	//把外设告诉CPU
	ldr r0, =0x70000000
	orr r0,r0,#0x13
	mcr p15,0,r0,c15,c2,4
	//官看门狗
	ldr r0,=0x7E004000
	mov r1,#0
	str r1,[r0]
	//设置栈
	ldr sp,=0x0c002000
	//开启icaches
#ifdef CONFIG_SYS_ICACHE_OFF
	bic r0,r0,#0x00001000
#else
	orr r0,r0,#0x00001000
	mcr p15,0,r0,c1,c0,0x00001000
#endif
	//设置时钟
	bl clock_init
	
	//初始换sdram
	bl sdram_init
	
	//初始化nand flash
	
	bl nand_init
	
	//重定位,把代码、数据复制到他的链接中去
	adr r0,_start    @_start的当前地址
	ldr r1,=_star    @_start的链接地址
	ldr r2,=bss_start
	sub r2,r2,r1
	cmp r0,r1
	beq clean_bss
	
	bl copy2ddr
	
	cmp r0,#0
	bne halt
	
	//清理bss段,把bss对应的内存清零
clean_bss:
		ldr r0,=bss_start
		ldr r1,=bss_end
		mov r3,#0
		cmp r0,r1
		beq on_ddr
clean_loop:
	str r3,[r0],#4
	cmp r0,r1
	bne clean_loop
	
	//跳转
on_ddr:
	ldr pc,=main
halt:
	b halt

 

//nand.c
#include "Tiny6410Addr.h"
//nand flash 的命令
#define NAND_CMD_READ0		0
#define NAND_CMD_READ1		1
#define NAND_CMD_RNDOUT		5
#define NAND_CMD_PAGEPROG	0x10
#define NAND_CMD_READOOB	0x50
#define NAND_CMD_ERASE1		0x60
#define NAND_CMD_STATUS		0x70
#define NAND_CMD_STATUS_MULTI	0x71
#define NAND_CMD_SEQIN		0x80
#define NAND_CMD_RNDIN		0x85
#define NAND_CMD_READID		0x90
#define NAND_CMD_ERASE2		0xd0
#define NAND_CMD_RESET		0xff
/*
typedef struct{
	void (*nand_reset)(void);
	void (*nand_select_chip)(void);
	void (*nand_deselect_chip)(void);
	void (*write_cmd)(int Cmd);
	void (*read_cmd)(int Cmd);
	void (*wait_idle)(void);
	void (*write_addr)(unsigned int addr);
	 
}NAND_CHIP;
static NAND_CHIP nand_chip;
*/
void nand_init(void);
 



//Tiny6410 nand Flash 的操作函数申明
static void Tiny6410_nand_reset(void); 				//重启
static void Tiny6410_nand_select_chip(void); 		//片选使能
static void Tiny6410_nand_diselect_chip(void);		//关闭片选
static void Tiny6410_write_cmd(int cmd); 			//写命令
static void Tiny6410_read_cmd(int cmd); 			//读命令
static void Tiny6410_wait_idle(void);  				//等待
static void Tiny6410_write_addr(unsigned int addr); //写地址
/////////////////////////////////////////

//Tiny6410 nand Flash 的操作函数实现
static void Tiny6410_nand_reset(void)
{
	Tiny6410_nand_select_chip();
	Tiny6410_write_cmd(int cmd);
	Tiny6410_wait_idle();
	Tiny6410_nand_diselect_chip();
	
}
//片选使能
static void Tiny6410_nand_select_chip(void)
{
	NFCONT &= ~(1 << 1);
}
//取消片选
static void Tiny6410_nand_diselect_chip(void)
{
	NFCONT |= (1 << 1);
}
static void Tiny6410_write_cmd(int cmd)
{
	
}
//等待数据
static void Tiny6410_wait_idle(void)
{
	do { 
	while(!(NFSTAT & (1 << 0))); 
	} while(0)
	
}
//读命令
static void Tiny6410_read_cmd(int cmd)
{
	NFCMD = cmd;
}
//写命令
static void Tiny6410_write_cmd(int cmd)
{
	//NFCMD = cmd;
}
static void Tiny6410_write_addr(unsigned long addr)
{
	NFADDR = 0;
	NFADDR = 0;
	NFADDR = (addr) & 0xff;
	NFADDR = (addr >> 8) & 0xff;
	NFADDR = (addr >> 16) & 0xff;
}

///////////////////////////////////////
//nand flash 初始化
void init_nand(void)
{
	//设置NAND FLASH 控制器
	NFCONF = ((0x2 << 12)|(0xf << 8)|(0x7 << 4));
	NFCONT |= ((0x3 << 0));
	
}
 
//读以页数据
static int nand_read_page(unsigned char *buf,unsigned long addr)
{
	int i;

	
	//发出片选
	Tiny6410_nand_select_chip();
	//发送读命令
	Tiny6410_read_cmd(NAND_CMD_READ0);
	//发送地址
	Tiny6410_write_addr(addr);
	//发送读命令
	Tiny6410_read_cmd(NAND_CMD_READSTART);
	//等待数据
	Tiny6410_wait_idle();
	//连续读取2048个字节
	for(i=0; i < page_size; i++)
	{
		*buf++ = NFDATA8_REG;
	}
	//取消片选
	Tiny6410_nand_diselect_chip();
	return 0;
}

//从NAND 中拷贝到DRAM
int copy2dram(unsigned int nand_start,unsigned int dram_start,unsigned int len)
{
	unsigned char *buf = (unsigned char *)ddr_start;
	int i;
	unsigned int page_shift = 11;
	//发片选
	Tiny6410_nand_select_chip();
		
	// 使len为2048的整数倍
	len = (len/2048+1)*2048;
	
	// 循环拷贝,每次拷贝一页数据
	for (i = 0; i < (len>>page_shift); i++, buf+=(1<<page_shift))
	{
		// 读一页,即2048byte
		nandll_read_page(buf, i);
	}

	return 0;
}

 

//nand.lds
SECTIONS {
    . = 0x50000000;
    
	.text : {
			start.o
			clock.o
			sdram.o
			nand.o
			* (.text)
	}

	.rodata : {
			* (.rodata)
	}

	.data : {
			* (.data)
	}

    bss_start = .;
    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
    bss_end = .;
}

 

//TinyAddr.h
#ifndef _Tiny6410Addr_H
#define _Tiny6410Addr_H
//GPK 
#define GPKIO_BASE (0x7F008800)
#define rGPKCON0 		(*((volatile unsigned long *)(GPKIO_BASE+0x00)))
#define rGPKDAT  		(*((volatile unsigned long *)(GPKIO_BASE+0x08)))

//CLOCK
#define APLL_LOCK 		(*((volatile unsigned long *)0x7E00F000))
#define MPLL_LOCK 		(*((volatile unsigned long *)0x7E00F004))
#define EPLL_LOCK 		(*((volatile unsigned long *)0x7E00F008))
#define OTHERS    		(*((volatile unsigned long *)0x7e00f900))
#define CLK_DIV0  		(*((volatile unsigned long *)0x7E00F020))
#define APLL_CON  		(*((volatile unsigned long *)0x7E00F00C))
#define MPLL_CON  		(*((volatile unsigned long *)0x7E00F010))
#define CLK_SRC   		(*((volatile unsigned long *)0x7E00F01C))



//GPA /uart
#define ULCON0     		(*((volatile unsigned long *)0x7F005000))
#define UCON0      		(*((volatile unsigned long *)0x7F005004))
#define UFCON0     		(*((volatile unsigned long *)0x7F005008))
#define UMCON0     		(*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0   		(*((volatile unsigned long *)0x7F005010))
#define UFSTAT0    		(*((volatile unsigned long *)0x7F005018))
#define UTXH0      		(*((volatile unsigned char *)0x7F005020))
#define URXH0      		(*((volatile unsigned char *)0x7F005024))
#define UBRDIV0    		(*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0  		(*((volatile unsigned short *)0x7F00502C))
#define GPACON     		(*((volatile unsigned long *)0x7F008000))

//Sdram
#define P1MEMSTAT		(*((volatile unsigned long *)0x7e001000))
#define P1MEMCCMD		(*((volatile unsigned long *)0x7e001004))
#define P1DIRECTCMD		(*((volatile unsigned long *)0x7e001008))
//#define MEMCCMD		(*((volatile unsigned long *)0x7e001004))
#define P1REFRESH		(*((volatile unsigned long *)0x7e001010))
#define P1CASLAT		(*((volatile unsigned long *)0x7e001014))
#define MEM_SYS_CFG		(*((volatile unsigned long *)0x7e00f120))
#define P1MEMCFG		(*((volatile unsigned long *)0x7e00100c))
#define P1T_DQSS		(*((volatile unsigned long *)0x7e001018))
#define P1T_MRD			(*((volatile unsigned long *)0x7e00101c))
#define P1T_RAS			(*((volatile unsigned long *)0x7e001020))
#define P1T_RC			(*((volatile unsigned long *)0x7e001024))
#define P1T_RCD			(*((volatile unsigned long *)0x7e001028))
#define P1T_RFC			(*((volatile unsigned long *)0x7e00102c))
#define P1T_RP			(*((volatile unsigned long *)0x7e001030))
#define P1T_RRD			(*((volatile unsigned long *)0x7e001034))
#define P1T_WR			(*((volatile unsigned long *)0x7e001038))
#define P1T_WTR			(*((volatile unsigned long *)0x7e00103c))
#define P1T_XP			(*((volatile unsigned long *)0x7e001040))
#define P1T_XSR			(*((volatile unsigned long *)0x7e001044))
#define P1T_ESR			(*((volatile unsigned long *)0x7e001048))
#define P1MEMCFG2		(*((volatile unsigned long *)0X7e00104c))
#define P1_chip_0_cfg	(*((volatile unsigned long *)0x7e001200))

//Nand
#define NAND_BASE (0x70200000)
#define NFCONF      	(*((volatile unsigned long *)NAND_BASE + 0x00)) 
#define NFCONT      	(*((volatile unsigned long *)NAND_BASE + 0x04))
#define NFCMMD      	(*((volatile unsigned long *)NAND_BASE + 0x08))
#define NFADDR      	(*((volatile unsigned long *)NAND_BASE + 0x0c))
#define NFDATA      	(*((volatile unsigned long *)NAND_BASE + 0x10))
#define NFMECCDATA0     (*((volatile unsigned long *)NAND_BASE + 0x14))
#define NFMECCDATA1     (*((volatile unsigned long *)NAND_BASE + 0x18))
#define NFSECCDATA0     (*((volatile unsigned long *)NAND_BASE + 0x1c))
#define NFSBLK      	(*((volatile unsigned long *)NAND_BASE + 0x20))
#define NFEBLK      	(*((volatile unsigned long *)NAND_BASE + 0x24))
#define NFSTAT      	(*((volatile unsigned long *)NAND_BASE + 0x28))
#define NFESTAT0      	(*((volatile unsigned long *)NAND_BASE + 0x2c))
#define NFESTAT1      	(*((volatile unsigned long *)NAND_BASE + 030))
#define NFMECC0      	(*((volatile unsigned long *)NAND_BASE + 0x34))
#define NFMECC1      	(*((volatile unsigned long *)NAND_BASE + 0x38))
#define NFSECC      	(*((volatile unsigned long *)NAND_BASE + 0x3c))
#define NFMLCBITPT      (*((volatile unsigned long *)NAND_BASE + 0x40)) 
/*#define NF8ECCERR0      (*((volatile unsigned long *)NAND_BASE + 0x44)) 
#define NF8ECCERR1      (*((volatile unsigned long *)NAND_BASE + 0x48)) 
#define NF8ECCERR2      (*((volatile unsigned long *)NAND_BASE + 0x4c)) 
#define NFM8ECC0      	(*((volatile unsigned long *)NAND_BASE + 0x50)) 
#define NFM8ECC1      	(*((volatile unsigned long *)NAND_BASE + 0x54)) 
#define NFM8ECC2      	(*((volatile unsigned long *)NAND_BASE + 0x58)) 
#define NFM8ECC3      	(*((volatile unsigned long *)NAND_BASE + 0x5c)) 
#define NFMLC8BITPT0    (*((volatile unsigned long *)NAND_BASE + 0x60)) 
#define NFMLC8BITPT1    (*((volatile unsigned long *)NAND_BASE + 0x64)) 
 */


#endif

总结:

  综上所述主要分为两个大步。

  第一步:读S3C6410数据手册,了解NANDfLASH 的操作流程。

  第二步:读NAND FLASH数据手册,了解各个寄存器的具体设置。

  

 

Tiny6410之NAND FLASH驱动