Chinaunix首页 | 论坛 | 博客
  • 博客访问: 32352
  • 博文数量: 12
  • 博客积分: 445
  • 博客等级: 下士
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-06 16:49
文章分类

全部博文(12)

文章存档

2012年(12)

我的朋友

分类: 嵌入式

2012-10-07 01:23:53

5、在u-boot中添加对NandFlash的支持

    
    在上一节中我们说过,通常在嵌入式bootloader中,有两种方式来引导启动内核:从NorFlash启动和从NandFlash启动,但不管是从Nor启动或者从Nand启动,进入第二阶段以后,两者的执行流程是相同的。当u-boot的start.S运行到“_start_armboot: .word start_armboot”时,就会调用lib_arm/board.c中的start_armboot函数,至此u-boot正式进入第二阶段。

    下面我们结合代码来分析一下u-boot在第二阶段的执行流程:


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

  6. 2.nand_init调用了同文件下的nand_init_chip函数;

  7. 3.nand_init_chip函数调用drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用drivers/mtd/nand/nand_base.c函数中的nand_scan函数;

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

  1. #include

 #include
 #include
 #include

 #define NF_BASE 0x4e000000

 #define S3C2440_NFCONT_EN          (1<<0)
 #define S3C2440_NFCONT_INITECC     (1<<4)
 #define S3C2440_NFCONT_nFCE        (1<<1)
 #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)

 #define S3C2440_ADDR_NALE 0x08
 #define S3C2440_ADDR_NCLE 0x0c

 ulong IO_ADDR_W = NF_BASE; 

 #ifdef CONFIG_NAND_SPL

 /* in the early stage of NAND flash booting, printf() is not available  */
 #define printf(fmt, args...)

 static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
int i;
struct nand_chip *this = mtd->priv;

for (i = 0; i < len; i++)
buf[i] = readb(this->IO_ADDR_R);
 }
 #endif

 static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned  int ctrl)
 {
struct s3c2440_nand *nand = s3c2440_get_base_nand();

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

if (ctrl & NAND_CTRL_CHANGE) {
IO_ADDR_W = (ulong)nand;
if (!(ctrl & NAND_CLE))
IO_ADDR_W |= S3C2440_ADDR_NCLE;
if (!(ctrl & NAND_ALE))
IO_ADDR_W |= S3C2440_ADDR_NALE;

if (ctrl & NAND_NCE)
writel(readl(&nand->NFCONT) & ~S3C2440_NFCONT_n  FCE, &nand->NFCONT);
else
writel(readl(&nand->NFCONT) | S3C2440_NFCONT_nF  CE, &nand->NFCONT);
}

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

 static int s3c2440_dev_ready(struct mtd_info *mtd)
 {
struct s3c2440_nand *nand = s3c2440_get_base_nand();
debugX(1, "dev_ready\n");
return readl(&nand->NFSTAT) & 0x01;
 }

 #ifdef CONFIG_S3C2440_NAND_HWECC
 void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
 {
struct s3c2440_nand *nand = s3c2440_get_base_nand();
debugX(1, "s3c2440_nand_enable_hwecc(%p, %d)\n", mtd, mode);

writel(readl(&nand->NFCONT) | S3C2440_NFCONT_INITECC, &nand->NF      CONT);
 } 

 static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_ch  ar *dat, u_char *ecc_code)
 {
struct s3c2440_nand *nand = s3c2440_get_base_nand();
ecc_code[0] = readb(&nand->NFMECCD0);
ecc_code[1] = readb(&nand->NFMECCD0 + 1);
ecc_code[2] = readb(&nand->NFMECCD0 + 2);
ecc_code[3] = readb(&nand->NFMECCD0 + 3);
debugX(1, "s3c2440_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%  02x 0x%02x\n", mtd , ecc_code[0], ecc_code[1], ecc_code[2], ecc_code[3  ]  );

return 0;
 }

 static int s3c2440_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] &&
   read_ecc[3] == calc_ecc[3])
return 0;

printf("s3c2440_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;
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_  power();
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();

debugX(1, "board_nand_init()\n");

writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON  );
twrph0 = 4;
twrph1 = 2;
tacls = 0;

cfg = 0;
cfg |= S3C2440_NFCONF_TACLS(tacls - 1);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
writel(cfg, &nand_reg->NFCONF);

cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4  )|(0<<1)|(1<<0);
writel(cfg, &nand_reg->NFCONT);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;

nand->select_chip = NULL;

/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
 #ifdef CONFIG_NAND_SPL
nand->read_buf = nand_read_buf;
 #endif

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

nand->dev_ready = s3c2440_dev_ready;

 #ifdef CONFIG_S3C2440_NAND_HWECC
  nand->ecc.hwctl = s3c2440_nand_enable_hwecc;
nand->ecc.calculate = s3c2440_nand_calculate_ecc;
nand->ecc.correct = s3c2440_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
 #else
nand->ecc.mode = NAND_ECC_SOFT;
 #endif

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

debugX(1, "end of nand_init\n");

return 0;
 }

    其次修改include/asm-arm/arch-s3c24x0/目录下的s3c24x0.h文件,增加s3c2440_nand结构体,代码如下:

  1. /* NAND FLASH (see S3C2410 manual chapter 6) */
  2. struct s3c2410_nand {
  3.     u32    NFCONF;
  4.     u32    NFCMD;
  5.     u32    NFADDR;
  6.     u32    NFDATA;
  7.     u32    NFSTAT;
  8.     u32    NFECC;
  9. };

  10. struct s3c2440_nand {
  11.     u32    NFCONF;
  12.     u32    NFCONT;
  13.     u32    NFCMD;
  14.     u32    NFADDR;
  15.     u32    NFDATA;
  16.     u32    NFMECCD0;
  17.     u32    NFMECCD1;
  18.     u32    NFSECCD;
  19.     u32    NFSTAT;
  20.     u32    NFESTAT0;
  21.     u32    NFESTAT1;
  22.     u32    NFMECC0;
  23.     u32    NFMECC1;
  24.     u32    NFSECC;
  25.     u32    NFSBLK;
  26.     u32    NFEBLK;
  27. };

    然后修改include/asm-arm/arch-s3c24x0/目录下的s3c2410.h文件,增加s3c2440_get_base_nand函数,代码如下:

  1. static inline struct s3c2410_nand *s3c2410_get_base_nand(void)
  2. {
  3.     return (struct s3c2410_nand *)S3C2410_NAND_BASE;
  4. }

  5. static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
  6. {
  7.     return (struct s3c2440_nand *)S3C2410_NAND_BASE;
  8. }
   
    然后在开发板配置文件include/configs/smdk2440.h文件中定义支持NandFlash操作的相关宏,代码如下:

  1. #ifndef __CONFIG_H
  2. #define __CONFIG_H
  3. .
  4. .
  5. .
  6.  #define CONFIG_CMD_CACHE
  7.  #define CONFIG_CMD_DATE
  8.  #define CONFIG_CMD_ELF
  9.  #define CONFIG_CMD_NAND 
  .
  .
  .

  在smdk2440.h文件最后面增加一下代码:
     #if defined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_NAND_BASE 0x4E000000 
#define CONFIG_SYS_MAX_NAND_DEVICE 1  
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
    #endif
#endif /* __CONFIG_H */


     最后,修改drivers/mtd/nand/目录下的Makefile文件,添加s3c2440_nand.c的编译选项,代码如下:

  1. COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o

  2. COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
 
    重新编译u-boot,下载到NorFlash中,运行结果如下图:
    
    从上图可以看出u-boot已经可以识别出开发板上的NandFlash了,可以通过 # nand info命令来查看NandFlash的信息,结果如下:

    虽然u-boot下奶已经可以识别出NandFlash,但是还不支持从NandFlash启动,需要进一步的修改u-boot源码来达到这一目的。
阅读(1002) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~