Chinaunix首页 | 论坛 | 博客
  • 博客访问: 646621
  • 博文数量: 329
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 693
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-05 23:37
个人简介

Do not panic!

文章存档

2021年(1)

2018年(3)

2017年(7)

2016年(98)

2015年(220)

我的朋友

分类: 嵌入式

2015-01-18 00:21:12

  上两次移植的U-Boot2009.08虽然可以从NandFlash启动,但是,在U-Boot还是没有办法进行操作,主要是没有NandFlash的驱动,我的NandFlash的型号是三星公司的K9F1G08U,大小是128MB,页的大小是2KB,也就是大页NandFlash的读写,在以前的版本中,U-boot对NAND Flash支持新旧两套代码,而这以版本中,已经不在支持旧的代码,新代码移植于Linux内核2.6,它更加的智能,可以自动识别更多的NandFlash型号。NandFlash的驱动代码在drivers/mtd/nand/目录下,由于,这个版本的U-Boot还没有支持S3C2440,所以我们需要自己写驱动,不过,我们可以根据2410进行改写,只需要加上对S3C2440的支持。
   在进行移植前,我们必须要理解,在对NandFlash就行,驱动的时,各个函数的调用过程是怎么样的,它的入口函数是哪一个?
  首先,要让U-Boot支持NAND Flash,要在配置文件include/consigs/mini2440.h中,定义CFG_CMD_NAND;我们知道,在U-Boot第一阶段完成后,就会跳转到C函数,void start_armboot (void){},运行,这个函数在lib_arm/borad.c中进行定义的。在这个函数中我们可以看到,下面的一句代码,
  这句代码说明只有定义了CONFIG_CMD_NAND后,才会调用nand_init()函数,对Nand Flash进行相应的初始化,识别的过程。

void start_armboot (void)
{
  ..........
#if defined(CONFIG_CMD_NAND)
    puts ("NAND ");
    nand_init();        /* go init the NAND */
#endif

....................
   /* main_loop() can return to retry autoboot, if so just run it again. */
    for (;;) {
        main_loop ();
    }

1).CONFIG_CMD_NAND后,就会调用nand_init()初始化函数。该函数位于drivers/mtd/nand/nand.c中,

void nand_init(void)
{
    int i;
    unsigned int size = 0;
    for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
        nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
        size += nand_info[i].size / 1024;
        if (nand_curr_device == -1)
            nand_curr_device = i;
    }
    printf("NAND: %u MiB\n", size / 1024);

2) 在nand_init()函数中调用同一个文件中的nand_init_chip()函数。

static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
             ulong base_addr)
{

.........
    int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
    if (board_nand_init(nand) == 0) {
        if (nand_scan(mtd, maxchips) == 0) {
........

3)而在nand_init_chip()函数中调用,我们自己写的board_nand_init()函数,该函数在我们要改写的文件s3c2410_nand.c中,

4)然后,调用drivers/mtd/nand/nand_base.c文件中2900行附近的nand_scan()函数。

5)在nand_scan()函数调用,同一个文件中2628行附近的nand_scan_ident()函数

,nand_scan_ident()函数调用nand_get_flash_type()函数,得到NandFlash芯片的厂家ID,和芯片ID,

6)最后调用函数同一个文件中2684行附近的nand_scan_tail(),函数,进行,芯片中各个函数,操作的初始化。NandFlash的初始化,驱动也就完成了。

我们所要做的工作就是写其中的一个函数board_nand_init(),函数。在改写这个函数之前,我们应该,先配置好,各个变量。


那么我们就应该先在include/configs/mini2440.h文件中,添加下面的定义。

/*
 * Command line configuration.
 */

#include <config_cmd_default.h>

#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_NAND //添加的定义

我们还需要在该文件中定义一些设置的参数。include/configs/mini2440.h

/*-----------------------------------------------------------------------
  Nand FLash Setting
------------------------------------------------------------------------*/

#if defined (CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2410   //为了使s3c2410_nand.c文件编译进去,必须要定义。
//#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_NAND_BASE 0x4e000000   //NandFlash中的各个寄存器的地址,基址
#define CONFIG_SYS_MAX_NAND_DEVICE 1    //NandFlash设备的数目为1
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
//#define NAND_SAMSUNG_LP_OPTIONS 1
#define NAND_MAX_CHIPS 1  //每个NandFlash设备,由1个NandFlash芯片组成。
#define CONFIG_SYS_64BIT_VSPRINTF
#endif

#define CONFIG_INITRD_TAG
#define CONFIG_CMDLINE_TAG

#define CONFIG_SYS_HUSH_PARSER
#define CONFIG_SYS_PROMPT_HUSH_PS2 ">"
#define CONFIG_CMDLINE_EDITING

#define CONFIG_AUTO_COMPLETE

因为,U-Boot本身含有,s3c2410_nand.c的函数,也就是支持这个型号的NandFlash,我们只需要在这个文件的基础上进行修改就可以了。这个文件也在/drivers/mtd/nand/s3c2410_nand.c。


#include <common.h>
#if 0
#define DEBUGN    printf
#else
#define DEBUGN(x, args ...) {}
#endif

#include <nand.h>
#include <s3c2410.h> //自己添加
#include <asm/io.h>

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

#define    NF_BASE        0x4e000000 //nandFlash寄存器的基地址

#if defined (CONFIG_S3C2410)
#define    NFCONF        __REGi(NF_BASE + 0x0)
#define    NFCMD        __REGb(NF_BASE + 0x4)
#define    NFADDR        __REGb(NF_BASE + 0x8)
#define    NFDATA        __REGb(NF_BASE + 0xc)
#define    NFSTAT        __REGb(NF_BASE + 0x10)
#define NFECC0        __REGb(NF_BASE + 0x14)
#define NFECC1        __REGb(NF_BASE + 0x15)
#define NFECC2        __REGb(NF_BASE + 0x16)

#define S3C2410_NFCONF_EN (1<<15)
#define S3C2410_NFCONF_512BYTE (1<<14)
#define S3C2410_NFCONF_4STEP (1<<13)
#define S3C2410_NFCONF_INITECC (1<<12)
#define S3C2410_NFCONF_nFCE (1<<11)
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)

#define S3C2410_ADDR_NALE 4
#define S3C2410_ADDR_NCLE 8
#endif

#if defined (CONFIG_S3C2440)
#define S3C2440_ADDR_NALE 0x08
#define S3C2440_ADDR_NCLE 0x0c

#define NFCONF __REGi(NF_BASE + 0x00) //用基地址加上后边的偏移地址得到该寄存器的地址
#define NFCONT __REGb(NF_BASE + 0x04)
#define NFCMD __REGb(NF_BASE + 0x08)
#define NFADDR __REGb(NF_BASE + 0x0c)
#define NFDATA __REGb(NF_BASE + 0x10)

#define NFMECCD0 __REGb(NF_BASE + 0x14)
#define NFMECCD1 __REGb(NF_BASE + 0x18)
#define NFSECCD __REGb(NF_BASE + 0x1c)

#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFSTAT0 __REGb(NF_BASE + 0x24)
#define NFSTAT1 __REGb(NF_BASE + 0x28)

#define NFMECC0 __REGb(NF_BASE + 0x2c)
#define NFMECC1 __REGb(NF_BASE + 0x30)
#define NFSECC __REGb(NF_BASE + 0x34)
#define NFEBLK __REGb(NF_BASE + 0x3c)
#define NFSBLK __REGb(NF_BASE + 0x38)

#define NFECC0 __REGb(NF_BASE + 0x2c)
#define NFECC1 __REGb(NF_BASE + 0x2d)
#define NFECC2 __REGb(NF_BASE + 0x2e)

#define S3C2440_NFCONT_nFCE     (1<<1)
#define S3C2440_NFCONT_EN         (1<<0)
#define S3C2440_NFCONT_INITECC     (1<<4)
#define S3C2440_NFCONT_MAINECCLOCK (1<<5)

#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)

#endif

ulong IO_ADDR_W = NF_BASE;

static void s3c2410_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_NCLE; //要写的是地址
        if (!(ctrl & NAND_ALE))
            IO_ADDR_W |= S3C2440_ADDR_NALE; //要写的是命令

        //chip->IO_ADDR_W = (void *)IO_ADDR_W;

#if defined (CONFIG_S3C2410)
        if (ctrl & NAND_NCE)
            NFCONF &= ~S3C2410_NFCONF_nFCE; 
        else
            NFCONF |= S3C2410_NFCONF_nFCE; 
    }
#endif

#if defined (CONFIG_S3C2440)
        if(ctrl & NAND_NCE)
            NFCONT &= ~S3C2440_NFCONT_nFCE;
//使能Nand Flash,
        else
        NFCONT |= S3C2440_NFCONT_nFCE;
//禁止Nand Flash
    }
#endif
    if (cmd != NAND_CMD_NONE)
        writeb(cmd, (void *)IO_ADDR_W);
}

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

#ifdef CONFIG_S3C2410_NAND_HWECC
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
    DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
    #if defined (CONFIG_S3C2410)
        NFCONF |= S3C2410_NFCONF_INITECC;
    #endif
    #if defined (CONFIG_S3C2440)
        writel(readl(&nand->NFCONT) | S3C2440_NFCONT_INITECC, &nand->NFCONT);
    #endif
}

static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
                 u_char *ecc_code)
{
    ecc_code[0] = NFECC0;
    ecc_code[1] = NFECC1;
    ecc_code[2] = NFECC2;
    DEBUGN("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
        mtd , ecc_code[0], ecc_code[1], ecc_code[2]);

    return 0;
}

static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
                 u_char *read_ecc, u_char *calc_ecc)
{
    if (read_ecc[0] == calc_ecc[0] &&
     read_ecc[1] == calc_ecc[1] &&
     read_ecc[2] == calc_ecc[2])
        return 0;

    printf("s3c2410_nand_correct_data: not implemented\n");
    return -1;
}
#endif

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();
    S3C2440_NAND * const nand_reg = S3C2440_GetBase_NAND();
    DEBUGN("board_nand_init()\n");

    clk_power->CLKCON |= (1 << 4);
    
    /* initialize hardware */
#if defined (CONFIG_S3C2410)
    twrph0 = 3; twrph1 = 0; tacls = 0;

    cfg = S3C2410_NFCONF_EN;
    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

    NFCONF = cfg;

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

#if defined (CONFIG_S3C2440) //在这里进行,NandFlash NFCONF 和NFCONT寄存器的初始化
    twrph0 = 4;twrph1 = 2;tacls = 0;
    cfg = 0;
    cfg |= S3C2440_NFCONF_TACLS(tacls);
    cfg |= S3C2440_NFCONF_TWRPH0(twrph0);
    cfg |= S3C2440_NFCONF_TWRPH1(twrph1);
    
    NFCONF = cfg;
    NFCONT= (0<<13) | (0<<12) | (0<<10) | (0<<9) | (0<<8) | (<<6) | (0<<5) | (1<<4) |(0<<1) |(1<<0);
    /* initialize nand_chip data structure 
这个地址就是NFDATA寄存器的地址* */
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
    
#endif
    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */

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

    nand->dev_ready = s3c2410_dev_ready;

#ifdef CONFIG_S3C2410_NAND_HWECC
    nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
    nand->ecc.calculate = s3c2410_nand_calculate_ecc;
    nand->ecc.correct = s3c2410_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW3_512;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif

#ifdef CONFIG_S3C2410_NAND_BBT
    nand->options = NAND_USE_FLASH_BBT;
#else
    nand->options = 0;
#endif

    DEBUGN("end of nand_init\n");

    return 0;
}

然后我们可以查看该目录下的Makefile文件。

include $(TOPDIR)/config.mk

LIB    := $(obj)libnand.a

ifdef CONFIG_CMD_NAND   // 如果定义了CONFIG_CMD_NAND,下面的六个文件都会被
COBJS-y += nand.o     //编译进去,而下面的必须在定义了相应的配置常量以后才能
COBJS-y += nand_base.o  //编译进去
COBJS-y += nand_bbt.o
COBJS-y += nand_ecc.o
COBJS-y += nand_ids.o
COBJS-y += nand_util.o

COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o
COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o
COBJS-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
COBJS-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
COBJS-$(CONFIG_NAND_NDFC) += ndfc.o
COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o

//而只有定义了CONFIG_NAND_S3C2410后,s3c2410_nand.c文件才能被编译进去,这里可以从新定义一个s3c2440_nand.c的文件,改一下MakeFile文件中的这个位置。重新进行编译

OBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o    
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o   

COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o
endif

到此,U-Boot中的NandFlash驱动已经移植完成,可以进行相应的擦出,和写入操作了。下面是一个运行的截图。

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