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

      

    海阔凭鱼跃,天高任鸟飞。
  • 相关阅读:
    Oracle数据库的非归档模式迁移到归档模式
    对Dataguard的三种模式的理解
    RMAN中建立Catalog 用数据库的例子
    Oracle中实现dblink的作法
    expdp 简单例子
    Oracle单节点_Grid_Infrastructure_DB_安装过程图解(三/三)
    Oracle单节点_Grid_Infrastructure_DB_安装过程图解(一/三)
    Oracle单节点_Grid_Infrastructure_DB_安装过程图解(二/三)
    Oracle 安装过程中 File not found "WFMLRSVCApp.ear" 的原因
    基于Django的在线考试系统
  • 原文地址:https://www.cnblogs.com/chenshikun/p/5988081.html
Copyright © 2020-2023  润新知