`
wodamazi
  • 浏览: 1416506 次
文章分类
社区版块
存档分类
最新评论

UBOOT-2010-03在S3C2440上的移植<四>------------支持NANDFLASH

 
阅读更多

五、修改 Nand flash 相关代码,使 U-BOOT 支持 Nand flash

上文连接:

UBOOT-2010-03在S3C2440上的移植<三>------------自动识别启动模式Nand Or Nor

5.1)start.S中Nand Boot需要nand_read_ll函数, 在board/samsung/eilian240下新建文件nand_read.c
文件内容如下:

/*
* nand_read.c: Simple NAND read functions for booting from NAND
*
* This is used by cpu/arm920/start.S assembler code,
* and the board-specific linker script must make sure this
* file is linked within the first 4kB of NAND flash.
*
* Taken from GPLv2 licensed vivi bootloader,
* Copyright (C) 2002 MIZI Research, Inc.
*
* Author: Hwang, Chideok <hwang@mizi.com>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
*/

#include <common.h>
#include <linux/mtd/nand.h>


#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGw(x) (*(volatile unsigned short *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE + 0x0)/**0x4e000000**NAND配置寄存器**/
#define NFCONT __REGi(NF_BASE + 0x4)/**0x4e000004**NAND控制寄存器**/
#define NFCMD __REGb(NF_BASE + 0x8)/*0x4e000008**NAND命令寄存器Bit7-0存放芯片内设命令值*/
#define NFADDR __REGb(NF_BASE + 0xc)/**0x4e00000C**NAND地址寄存器Bit7-0存放**/
#define NFDATA __REGb(NF_BASE + 0x10)/**0x4e000010**NAND数据寄存器8位IO**/
#define NFDATA16 __REGw(NF_BASE + 0x10)/**0x4e000010**NAND数据寄存器16位IO**/
#define NFSTAT __REGb(NF_BASE + 0x20)/**0x4e000020**NAND状态寄存器**/
#define NFSTAT_BUSY 1
#define nand_select() (NFCONT &= ~(1 << 1)) /***芯片片选**/
#define nand_deselect() (NFCONT |= (1 << 1))/**取消芯片片选**/
#define nand_clear_RnB() (NFSTAT |= (1 << 2)) /**NFSTAT状态寄存器的Bit2 写1
/**************上面这些都是一些S3C2440NANDFLASH寄存器的定义怎么定义数据手册很详细的*******/
/****我再一次的打开了S3C2440数据手册***/
static inline void nand_wait(void)
{
int i;

while (!(NFSTAT & NFSTAT_BUSY))
for (i=0; i<10; i++);
}

struct boot_nand_t {
int page_size;
int block_size;
int bad_block_offset;
// unsigned long size;
};


static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
{
unsigned char data;
unsigned long page_num;

nand_clear_RnB();
if (nand->page_size == 512) {
NFCMD = NAND_CMD_READOOB; /* 0x50 */
NFADDR = nand->bad_block_offset & 0xf;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = i >> 11; /* addr / 2048 */
NFCMD = NAND_CMD_READ0;
NFADDR = nand->bad_block_offset & 0xff;
NFADDR = (nand->bad_block_offset >> 8) & 0xff;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
} else {
return -1;
}
nand_wait();
data = (NFDATA & 0xff);
if (data != 0xff)
return 1;

return 0;
}

static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
{
unsigned short *ptr16 = (unsigned short *)buf;
unsigned int i, page_num;

nand_clear_RnB();

NFCMD = NAND_CMD_READ0;

if (nand->page_size == 512) {
/* Write Address */
NFADDR = addr & 0xff;
NFADDR = (addr >> 9) & 0xff;
NFADDR = (addr >> 17) & 0xff;
NFADDR = (addr >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = addr >> 11; /* addr / 2048 */
/* Write Address */
NFADDR = 0;
NFADDR = 0;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
} else {
return -1;
}
nand_wait();

for (i = 0; i < (nand->page_size>>1); i++) {
*ptr16 = NFDATA16;
ptr16++;
}

return nand->page_size;
}

static unsigned short nand_read_id()
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA;
res = (res << 8) | NFDATA;
return res;
}

extern unsigned int dynpart_size[];

/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
unsigned short nand_id;
struct boot_nand_t nand;

/* chip Enable */
nand_select();
nand_clear_RnB();

for (i = 0; i < 10; i++) ;
nand_id = nand_read_id();
if (0) { /* dirty little hack to detect if nand id is misread */
unsigned short * nid = (unsigned short *)0x31fffff0;
*nid = nand_id;
}

if (nand_id == 0xec76 || /* Samsung K91208 */
nand_id == 0xad76 ) { /*Hynix HY27US08121A*/
nand.page_size = 512;
nand.block_size = 16 * 1024;
nand.bad_block_offset = 5;
// nand.size = 0x4000000;
} else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */
nand_id == 0xecda || /* Samsung K9F2G08U0B */
nand_id == 0xecd3 ) { /* Samsung K9K8G08 */
nand.page_size = 2048;
nand.block_size = 128 * 1024;
nand.bad_block_offset = nand.page_size;
// nand.size = 0x8000000;
} else {
return -1; // hang
}
if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
return -1; /* invalid alignment */

for (i=start_addr; i < (start_addr + size);) {
#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
if (i & (nand.block_size-1)== 0) {
if (is_bad_block(&nand, i) ||
is_bad_block(&nand, i + nand.page_size)) {
/* Bad block */
i += nand.block_size;
size += nand.block_size;
continue;
}
}
#endif
j = nand_read_page_ll(&nand, buf, i);
i += j;
buf += j;
}

/* chip Disable */
nand_deselect();

return 0;
}

/**********************接下来我想对这些代码进行分析这才是我本次移植的目的*******************/

六、了解NANDFLASH的一些硬件特性

6.1.1)nand flash layout


6.1.2)Nand Flash的物理存储单元的阵列组织结构以本开发板上的K9F2G08X0A为例:

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,最新的Nand Flash的是4KB、8KB等,这类的页大小大于 2KB的Nand Flash,被称作 big block的 Nand Flash,对应的发读写命令地址,一共 5个周期(cycle),而老的 Nand Flash,页大小是 256B,512B,这类的 Nand Flash被称作 small block,地址周期只有 4个。 页 Page,是读写操作的基本单位。 不过,也有例外的是,有些 Nand Flash支持 subpage(1/2 页或 1/4页)子页的读写操作,不过一般很少见。

6.1.5) oob / Redundant Area / Spare Area
每一个页,对应还有一块区域,叫做空闲区域(spare area)/冗余区域(redundant area),而Linux 系统中,一般叫做 OOB(Out Of Band),这个区域,是最初基于Nand Flash的硬件特性:数据在读写时候相对容易错误,所以为了保证数据的正确性,必须要有对应的检测和纠错机制,此机制被叫做 EDC(Error Detection Code)/所以设计了多余的区域,用于放置数据的校验值。Oob 的读写操作,一般是随着页的操作一起完成的,即读写页的时候,对应地就读写了 oob。
关于 oob具体用途,总结起来有:
标记是否是坏快
存储ECC数据
存储一些和文件系统相关的数据。如 jffs2 就会用到这些空间存储一些特定信息,而yaffs2 文件系统,会在 oob中,存放很多和自己文件系统相关的信息

6.1.6)NANDFLASH常用命令设置


从上图可以看到,如果要实现读一个页的数据,就要发送 Read的命令,而且是分两个周期(Cycle),即分两次发送对应的命令,第一次是 0x00h,第二次是 0x30h,而两次命令中间,需要发送对应的你所要读取的页的地址。
对应地,其他常见的一些操作,比如写一个页的数据(Page Program),就是先发送 0x80h,然后发生要写入的地址,再发送0x10h。

6.1.7)PIN DESCRIPTION



对上表进行中文翻译。。。。。。。。


Notes:#代表低电平有效

6.1.8)理解NANDFLASH的操作时序图以Read Operation为例


Notes:此图来自三星的型号 K9F2G08的 Nand Flash的数据手册(datasheet)。
我们来一起看看,我在上图的特意标注的①边上的红色竖线。 红色竖线所处的时刻,是在发送读操作的第一个周期的命令 0x00之前的那一刻。 让我们看看,在那一刻,其所穿过好几行都对应什么值,以及进一步理解,为何要那个值。
1)红色竖线穿过的第一行,是 CLE。前面介绍命令所存使能(CLE)的那个引脚将CLE 置 1,就说明你将要通过 I/O 复用端口发送进入Nand Flash的,是命令,而不是地址或者其他类型的数据。只有这样将 CLE 置 1,使其有效,才能去通知了内部硬件逻辑,你接下来将收到的是命令,内部硬件逻辑,才会将受到的命令,放到命令寄存器中,才能实现后面正确的操作,否则,不去将 CLE 置 1 使其有效,硬件会无所适从,不知道你传入的到底是数据还是命令了。
2)而第二行,是 CE#,那一刻的值是 0。这个道理很简单,你既然要向Nand Flash发命令,那么先要选中它,所以,要保证 CE#为低电平,使其有效,也就是片选有效。
3)第三行是 WE#,意思是写使能。因为接下来是往 Nand Flash里面写命令,所以,要使
得 WE#有效,所以设为低电平。
4)第四行,是 ALE 是低电平,而 ALE 是高电平有效,此时意思就是使其无效。而对应地,前面介绍的,使 CLE 有效,因为将要数据的是命令(此时是发送图示所示的读命令第二周期的 0x30) ,而不是地址。如果在其他某些场合,比如接下来的要输入地址的时候,就要使其有效,而使 CLE 无效了。
5)第五行,RE#,此时是高电平,无效。可以看到,知道后面低 6 阶段,才变成低电平,才有效,因为那时候,要发生读取命令,去读取数据。
6)第六行,就是我们重点要介绍的,复用的输入输出 I/O 端口了,此刻,还没有输入数据,接下来,在不同的阶段,会输入或输出不同的数据/地址。
7)第七行,R/B#,高电平,表示 R(Ready)/就绪,因为到了后面的第 5阶段,硬件内部,在第四阶段,接受了外界的读取命令后,把该页的数据一点点送到页寄存器中,这段时间,属于系统在忙着干活,属于忙的阶段,所以,R/B#才变成低,表示 Busy忙的状态的。 其他的时序的就类似的理解。

8)以上资料摘字网络 经整理成为自己的东西。。。(I'm sorry I forgot to is the great god of the blog )

七、好了经过上面这么一分析再回到第五步 那些代码是否能看懂了<至少我明白了很多>

/***********************************************到此结束*******************************************/

该文档下载链接:点击下载该文档

下接:

UBOOT-2011-03在S3C2440上的移植<四>------------支持NANDFLASH<续>








分享到:
评论

相关推荐

    uboot nand驱动_completely1no_s3c2440_NAND_nandflash驱动程序_

    这是 s3c2440开发板 的 nandflash程序 可供学习和移植

    S3C2440移植uboot之支持NANDFLASH

    上一节我们移植了uboot,S3C2440移植uboot之支持NORFLASH。这节我们继续移植,支持NANDFLASH。 文章目录编译报错拷贝s3c2410_nand.c,修改宏定义支持SC32440修改NFCONF,NFCONT,支持S3C2440修改s3c2440_hwcontrol...

    jz2440-uboot-0825

    uboot移植详细的文档,支持tftp、USB、nand flash nor flash

    u-boot-2012.10移植全记录(基于s3c2440)

    文档详细记录了基于s3c2440的uboot2012.10的移植记录,移植了从Nor Flash启动,从Nand Flash启动,Nand读写,DM9000EP网卡驱动,usbslave以及烧录yaffs2文件系统等功能。

    6410uboot移植借鉴

    手把手教你uboot移植,基于...由于Uboot2011.06对S3C6410有了很好的支持,所以采用Uboot2011.06版本。 一、 移植环境 主 机:VMWare-ubuntu 开发板:ok6410—512M nandflash,Kernel:2.6.30.4 u-boot:u-boot-2011.06

    U-Boot从NAND Flash启动的实现

    分析了U-Boot启动流程的两个阶段及实现从NAND Flash启动的原理和思路,并根据NAND Flash的物理结构和存储特点,增加U-Boot对NAND Flash的操作支持,从而完成把存储在NAND Flash上的U-Boot代码复制到SDRAM中执行,...

    uboott移植实验手册及技术文档

    实验三 移植U-Boot-1.3.1 实验 【实验目的】 了解 U-Boot-1.3.1 的代码结构,掌握其移植方法。 【实验环境】 1、Ubuntu 7.0.4发行版 2、u-boot-1.3.1 3、FS2410平台 ...#if defined(CONFIG_S3C2440) ...

    郭天祥ARM9视频教程(第13和20讲均可观看).docx

    4. uboot在TX2440A上移植 5. uboot常用命令讲解 uboot使用专题 第六部分 嵌入式系统移植之linux内核 第十五讲 Linux内核分析和配置 1. 内核源码目录结构分析 2. Makefile,Kconfig文件分析 3. Linux启动过程分析 4. ...

    基于2440的bootloader程序

    在2440下的bootloader,仿照uboot,实现了nandflash(大页)登录,移植dm9000网卡,实现tftp下载内核,并引导内核启动。

    嵌入式Linux开发实用教程内的s3c64xx.c

    嵌入式Linux开发实用教程是基于ok6410编写的一本移植uboot,移植nandflash,移植内核等的教程,内容十分详细,遇到的编译不过的点都会一一给出方法,美中不足的就是作者所提供的网盘地址有些已经失效,导致部分需要...

    嵌入式Linux应用开发完全手册.pdf

    《嵌入式Linux应用开发完全手册》以S3C2410、S3C2440开发板为例,从分析硬件上电执行的第一条指令开始,到构造出一个类似PDA、基于Linux的桌面GUI系统,带领读者学习、掌握从最底层到最高层的软件编写方法。...

Global site tag (gtag.js) - Google Analytics