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数据手册,了解各个寄存器的具体设置。

  

时间: 2024-10-05 04:43:54

Tiny6410之NAND FLASH驱动的相关文章

【详解】如何编写Linux下Nand Flash驱动

From: http://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html 版本:v2.2 Crifan Li 摘要 本文先解释了Nand Flash相关的一些名词,再从Flash硬件机制开始,介绍到Nand Flash的常见的物理特性,且深入介绍了Nand Flash的一些高级功能,然后开始介绍Linux下面和Nand Flash相关的软件架构MTD的相关知识,最后介绍了

linux下Pl353 NAND Flash驱动分析

linux的NAND Flash驱动位于drivers/mtd/nand子目录下: nand_base.c-->定义通用的nand flash基本操作函数,如读写page,可自己重写这些函数 nand_bbt.c-->与坏块管理有关的函数和结构体 nand_ids.c-->nand_flash_ids[](芯片ID)和nand_manuf_ids[](厂商ID) nand_ecc.c-->软件ECC代码,若系统支持硬件ECC,则不用理会这个文件 pl353_nand.c-->

NAND FLASH 驱动分析

NAND FLASH是一个存储芯片 那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A" 问1. 原理图上NAND FLASH和S3C2440之间只有数据线, 怎么传输地址? 答1.在DATA0-DATA7上既传输数据,又传输地址 当ALE为高电平时传输的是地址, 问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令 怎么传入命令? 答2.在DATA0-DATA7上既传输数据,又传输地址,也传输命令 当ALE为高电平时传输的是地址, 当CLE为

Linux 下 Nand Flash 驱动说明

注册 driver_register 通过 module_init(s3c2410_nand_init);注册 Nand Flash 驱动. 在 s3c2410_nand_init ()中通过 driver_register()注册 s3c2410_nand_driver 驱动程序,如下所示: static struct device_driver s3c2410_nand_driver = { .name          = "s3c2410-nand", .bus        

Linux 下 Nand Flash 驱动主要数据结构说明

s3c2410 专有数据结构 s3c2410_nand_set struct s3c2410_nand_set { int                    nr_chips;     /* 芯片的数目 */ int                    nr_partitions; /* 分区的数目 */ char                   *name;          /* 集合名称   */ int                   nr_map;       /* 可选

嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序

NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输的是数据. 将数据发给nand Flash后,在发送第二次数据之前还要判断芯片是否处于空闲状态.一般是通过引脚RnB来判断,一般是高电平代表就绪,低电平代表正忙. 操作Nand Flash的一般步骤是: 1. 发命令 选中芯片 CLE设置为高电平 在DATA0-DATA7上输出命令值 发出一个写脉冲

nand Flash原理

6.1.3) Block 块 一个 Nand Flash (的 chip,芯片) 由很多个块(Block)组成,块的大小一般是 128KB, 256KB, 512KB,此处是 128KB.其他的小于 128KB 的,比如 64KB,一般都是下面将要介绍到的small block的Nand Flash. 块 Block,是Nand Flash的擦除操作的基本/最小单位. 6.1.4) Page 页 每个块里面又包含了很多页(page) .每个页的大小,对于现在常见的Nand Flash多数是2KB

Smart210学习记录------nor flash驱动

nor flash驱动与nand flash驱动的差别不大,只是设置不同的结构体而已,, nor flash驱动代码: #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/device.h> #include

块设备驱动之NOR FLASH驱动

转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/25240947 一.硬件原理 从原理图中我们能看到NOR FLASH有地址线,有数据线,能向内存一样读,不能向内存一样写(要发出某些命令).这也使得NOR的数据非常可靠,所以一般用来存储bootloader.当然现在手机上都只有nand flash了,节约成本嘛.下节我会带大家去分析nand flash驱动,并进行总结. 二.驱动程序 /* * 参考 drivers\mtd\m