Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7650435
  • 博文数量: 961
  • 博客积分: 15795
  • 博客等级: 上将
  • 技术积分: 16612
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-07 14:23
文章分类

全部博文(961)

文章存档

2016年(1)

2015年(61)

2014年(41)

2013年(51)

2012年(235)

2011年(391)

2010年(181)

分类: 嵌入式

2010-08-09 17:12:27

嵌入式学习入门 http://blog.chinaunix.net/u3/117680/showart.php?id=2300212  

增nand flsah读写驱动

当u-boot的start.S运行到“_start_armboot: .word start_armboot”时,就会调用lib_arm/board.c中的start_armboot函数,至此u-boot正式进入第二阶段。此时注意:以前较早的u-boot版本进入第二阶段后,对Nand Flash的支持有新旧两套代码,新代码在drivers/nand目录下,旧代码在drivers/nand_legacy目录下,CFG_NAND_LEGACY宏决定了使用哪套代码,如果定义了该宏就使用旧代码,否则使用新代码。但是现在的u-boot-2009.08版本对Nand的初始化、读写实现是基于最近的Linux内核的MTD架构,删除了以前传统的执行方法,使移植没有以前那样复杂了,实现Nand的操作和基本命令都直接在drivers/mtd/nand目录下(在doc/README.nand中讲得很清楚)。下面我们结合代码来分析一下u-boot在第二阶段的执行流程:

1.lib_arm/board.c文件中的start_armboot函数调用了drivers/mtd/nand/nand.c文件中的nand_init函数,如下:
  #if defined(CONFIG_CMD_NAND) //可以看到CONFIG_CMD_NAND宏决定了Nand的初始化
      puts ("NAND: ");
      nand_init();
  #endif

2.nand_init调用了同文件下的nand_init_chip函数;
3.nand_init_chip函数调用drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用drivers/mtd/nand/nand_base.c函数中的nand_scan函数;
4.nand_scan函数调用了同文件下的nand_scan_ident函数等。


因为2440和2410对nand控制器的操作有很大的不同,所以s3c2410_nand.c下对nand操作的函数就是我们做移植需要实现的部分了,他与具体的Nand Flash硬件密切相关。为了区别与2410,这里我们就重新建立一个s3c2440_nand.c文件,在这里面来实现对nand的操作,代码如下:

#gedit drivers/mtd/nand/s3c2440_nand.c   //新建s3c2440_nand.c文件

#include

#if 0
#define DEBUGN    printf
#else
#define DEBUGN(x, args ...) {}
#endif

#include
#include
#include

 

#define __REGb(x)    (*(volatile unsigned char *)(x))
#define __REGi(x)    (*(volatile unsigned int *)(x))

 

#define NF_BASE  0x4e000000             //Nand配置寄存器基地址
#define NFCONF   __REGi(NF_BASE + 0x0)  //偏移后还是得到配置寄存器基地址
#define NFCONT   __REGi(NF_BASE + 0x4)  //偏移后得到Nand控制寄存器基地址
#define NFCMD    __REGb(NF_BASE + 0x8)  //偏移后得到Nand指令寄存器基地址
#define NFADDR   __REGb(NF_BASE + 0xc)  //偏移后得到Nand地址寄存器基地址
#define NFDATA   __REGb(NF_BASE + 0x10) //偏移后得到Nand数据寄存器基地址
#define NFMECCD0 __REGi(NF_BASE + 0x14) //偏移后得到Nand主数据区域ECC0寄存器基地址
#define NFMECCD1 __REGi(NF_BASE + 0x18) //偏移后得到Nand主数据区域ECC1寄存器基地址
#define NFSECCD  __REGi(NF_BASE + 0x1C) //偏移后得到Nand空闲区域ECC寄存器基地址
#define NFSTAT   __REGb(NF_BASE + 0x20) //偏移后得到Nand状态寄存器基地址
#define NFSTAT0  __REGi(NF_BASE + 0x24) //偏移后得到Nand ECC0状态寄存器基地址
#define NFSTAT1  __REGi(NF_BASE + 0x28) //偏移后得到Nand ECC1状态寄存器基地址
#define NFMECC0  __REGi(NF_BASE + 0x2C) //偏移后得到Nand主数据区域ECC0状态寄存器基地址
#define NFMECC1  __REGi(NF_BASE + 0x30) //偏移后得到Nand主数据区域ECC1状态寄存器基地址
#define NFSECC   __REGi(NF_BASE + 0x34) //偏移后得到Nand空闲区域ECC状态寄存器基地址
#define NFSBLK   __REGi(NF_BASE + 0x38) //偏移后得到Nand块开始地址
#define NFEBLK   __REGi(NF_BASE + 0x3c)
//偏移后得到Nand块结束地址

 

#define S3C2440_NFCONT_nCE  (1<<1)
#define S3C2440_ADDR_NALE   0x0c
#define S3C2440_ADDR_NCLE   0x08

 

ulong IO_ADDR_W = NF_BASE;

 

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
    struct nand_chip *chip = mtd->priv;

    DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

    if (ctrl & NAND_CTRL_CHANGE) {
        IO_ADDR_W = NF_BASE;

        if (!(ctrl & NAND_CLE))                //要写的是地址
            IO_ADDR_W |= S3C2440_ADDR_NALE;
        if (!(ctrl & NAND_ALE))                //要写的是命令
            IO_ADDR_W |= S3C2440_ADDR_NCLE;

        if (ctrl & NAND_NCE)
            NFCONT &= ~S3C2440_NFCONT_nCE;    //使能nand flash
        else
            NFCONT |= S3C2440_NFCONT_nCE;     //禁止nand flash
    }

    if (cmd != NAND_CMD_NONE)
        writeb(cmd,(void *)IO_ADDR_W);
}

 

static int s3c2440_dev_ready(struct mtd_info *mtd)
{
    DEBUGN("dev_ready\n");
    return (NFSTAT & 0x01);
}

 

int board_nand_init(struct nand_chip *nand)
{
    u_int32_t cfg;
    u_int8_t tacls, twrph0, twrph1;
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

 

    DEBUGN("board_nand_init()\n");

 

    clk_power->CLKCON |= (1 << 4);

 

    twrph0 = 4; twrph1 = 2; tacls = 0;

 

    cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);
    NFCONF = cfg;

 

    cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);
    NFCONT = cfg;

 

    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;

 

    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */

    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c2440_hwcontrol;

 

    nand->dev_ready = s3c2440_dev_ready;

 

    return 0;
}

 

其次,在开发板配置文件include/configs/my2440.h文件中定义支持Nand操作的相关宏,如下:

#gedit include/configs/my2440.h

/* Command line configuration. */
#define CONFIG_CMD_NAND
#define CONFIG_CMDLINE_EDITING

#ifdef CONFIG_CMDLINE_EDITING
#undef CONFIG_AUTO_COMPLETE
#else
#define CONFIG_AUTO_COMPLETE
#endif

 

/* NAND flash settings */
#if defined(CONFIG_CMD_NAND)
#define CONFIG_SYS_NAND_BASE            0x4E000000 //Nand配置寄存器基地址
#define CONFIG_SYS_MAX_NAND_DEVICE      1
#define CONFIG_MTD_NAND_VERIFY_WRITE    1
//#define NAND_SAMSUNG_LP_OPTIONS       1 
//注意:我们这里是64M的Nand Flash,所以不用,如果是128M的大块Nand Flash,则需加上
#endif

 

然后,在drivers/mtd/nand/Makefile文件中添加s3c2440_nand.c的编译项,如下:

# gedit drivers/mtd/nand/Makefile

COBJS-y += s3c2440_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

再次,在board/samsung/my2440/目录下新建一个nand_read.c文件,在该文件中来实现上面汇编中要调用的nand_read_ll函数,代码如下:

文件: nand_read(256M).rar
大小: 1KB
下载: 下载

文件: nand_read(64M).rar
大小: 0KB
下载: 下载

然后,在board/samsung/my2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,如下:

COBJS    := my2440.o flash.o nand_read.o

 

最后,重新编译u-boot并使用

 
阅读(2392) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~