Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304930
  • 博文数量: 99
  • 博客积分: 225
  • 博客等级: 二等列兵
  • 技术积分: 644
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-03 10:22
个人简介

遇顺境,处之淡然;遇逆境,处之泰然

文章分类
文章存档

2014年(12)

2013年(78)

2012年(9)

分类: LINUX

2012-03-10 19:55:24

u-boot-2010.06mini2440上的移植(三)---增加nand flash功能

移植环境

1,主机环境:VMware7.1.4 + Ubuntu10.04

2,编译环境:arm-linux-gcc v4.3.2

3,开发板:mini24402M nor flash256M nand flashDM9000网卡。

4u-boot版本:u-boot-2010.06

注:修改或添加的地方都用红色表示

移植步骤

(一)目前u-boot中还没有对2440Nand Flash的支持,也就是说要想u-bootNand Flash上启动得自己去实现了。首先,在include/configs/mini2440.h头文件中定义Nand要用到的宏和寄存器,如下:

$ gedit include/configs/mini2440.h

#define CONFIG_CMD_NAND

//在文件末尾加入以下Nand Flash相关定义

//#define   CONFIG_ENV_IS_IN_FLASH    1  /*屏蔽Nor Flash saveenv相关宏定义*/

//#define CONFIG_ENV_SIZE             0x10000   /* Total Size of Environment Sector */

 

#define   CONFIG_ENV_IS_IN_NAND  1

#define   CONFIG_ENV_OFFSET        0x60000

#define   CONFIG_ENV_SIZE          0x20000

#define   CONFIG_CMD_SAVEENV

 

/*

 * Nand flash register and envionment variables

 */

#define CONFIG_S3C2440_NAND_BOOT  1

#define NAND_CTL_BASE  0x4E000000  //Nand Flash配置寄存器基地址,查2440手册可得知

#define bINT_CTL(Nb)   __REG(INT_CTL_BASE+(Nb))

#define UBOOT_RAM_BASE  0x33f80000

#define STACK_BASE  0x33F00000     //定义堆栈的地址

#define STACK_SIZE  0x8000         //堆栈的长度大小

 

/* NAND flash settings */

#if defined(CONFIG_CMD_NAND)

#define CONFIG_NAND_S3C2410

#define CONFIG_SYS_NAND_BASE            0x4E000000 //Nand配置寄存器基地址

#define CONFIG_SYS_MAX_NAND_DEVICE      1

#define NAND_MAX_CHIPS                       1

#define CONFIG_MTD_NAND_VERIFY_WRITE    1

//#define NAND_SAMSUNG_LP_OPTIONS       1  //注意:我们这里是64MNand Flash,所以不用,如果是128M的大块Nand Flash,则需加上

#endif

(二)其次,修改cpu/arm920t/start.S这个文件,使u-bootNand Flash启动,在上一节中提过,u-boot默认是从Nor Flash启动的。修改部分如下:

$ gedit arch/arm/cpu/arm920t/start.S

/*注意:在上一篇Nor Flash启动中,我们为了把u-bootsupervivi下载到内存中运行而屏蔽掉这段有关CPU初始化的代码。而现在我们要把u-boot下载到Nand Flash中,从Nand Flash启动,所以现在要恢复这段代码。*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl      cpu_init_crit

#endif

#if 0                                    //屏蔽掉u-boot中的从Nor Flash启动部分

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate:                               /* relocate U-Boot to RAM          */

adr   r0, _start          /* r0 <- current position of code   */

ldr    r1, _TEXT_BASE                 /* test if we run from flash or RAM */

cmp r0, r1                           /* don't reloc during debug         */

beq  stack_setup

ldr    r2, _armboot_start

ldr    r3, _bss_start

sub   r2, r3, r2           /* r2 <- size of armboot            */

add  r2, r0, r2           /* r2 <- source end address         */

copy_loop:

ldmia        r0!, {r3-r10}               /* copy from source address [r0]    */

stmia        r1!, {r3-r10}               /* copy to   target address [r1]    */

cmp r0, r2                           /* until source end addreee [r2]    */

ble    copy_loop

#endif        /* CONFIG_SKIP_RELOCATE_UBOOT */

#endif

/***************** CHECK_CODE_POSITION ******************************************/

adr   r0, _start          /* r0 <- current position of code   */

ldr    r1, _TEXT_BASE                 /* test if we run from flash or RAM */

cmp     r0, r1                  /* don't reloc during debug         */

beq     stack_setup

/***************** CHECK_CODE_POSITION ******************************************/

/***************** CHECK_BOOT_FLASH ******************************************/

ldr    r1, =( (4<<28)|(3<<4)|(3<<2) )                   /* address of Internal SRAM  0x4000003C*/

mov r0, #0                 /* r0 = 0 */

str    r0, [r1]

mov r1, #0x3c           /* address of men  0x0000003C*/

ldr    r0, [r1]

cmp r0, #0

bne  relocate

/* recovery  */

ldr    r0, =(0xdeadbeef)

ldr    r1, =( (4<<28)|(3<<4)|(3<<2) )

str    r0, [r1]

/***************** CHECK_BOOT_FLASH ******************************************/

/***************** NAND_BOOT *************************************************/

//下面添加2440u-bootNand Flash启动

#ifdef CONFIG_S3C2440_NAND_BOOT

#define  oNFCONF  0x00

#define  oNFCONT  0x04

#define  oNFCMD   0x08

#define  oNFSTAT   0x20

#define  LENGTH_UBOOT  0x60000

    mov r1, #NAND_CTL_BASE   //复位Nand Flash

    ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

    str r2, [r1, #oNFCONF]   //设置配置寄存器的初始值,参考s3c2440手册

    ldr r2, [r1, #oNFCONF]

    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )

    str r2, [r1, #oNFCONT]   //设置控制寄存器

    ldr r2, [r1, #oNFCONT]

    ldr r2, =(0x6)           //RnB Clear

    str r2, [r1, #oNFSTAT]

ldr r2, [r1, #oNFSTAT]

    mov r2, #0xff            //复位command

    strb r2, [r1, #oNFCMD]

    mov r3, #0               //等待

nand1:

    add r3, r3, #0x1

    cmp r3, #0xa

    blt nand1

nand2:

    ldr r2, [r1, #oNFSTAT]   //等待就绪

    tst r2, #0x4

    beq nand2

    ldr r2, [r1, #oNFCONT]

    orr r2, r2, #0x2         //取消片选

    str r2, [r1, #oNFCONT]

    //get read to call C functions (for nand_read())

    ldr sp, DW_STACK_START   //C代码准备堆栈,DW_STACK_START定义在下面

    mov fp, #0             

    //copy U-Boot to RAM

    ldr r0, =TEXT_BASE//传递给C代码的第一个参数:u-bootRAM中的起始地址

    mov r1, #0x0      //传递给C代码的第二个参数:Nand Flash的起始地址

    mov r2, # LENGTH_UBOOT //传递给C代码的第三个参数:u-boot的长度大小(128k)

    bl nand_read_ll   //此处调用C代码中读Nand的函数,现在还没有要自己编写实现

    tst r0, #0x0

    beq ok_nand_read

bad_nand_read:

    loop2: b loop2    //infinite loop

ok_nand_read: //检查搬移后的数据,如果前4k完全相同,表示搬移成功

    mov r0, #0

    ldr r1, =TEXT_BASE

    mov r2, #0x400           //4 bytes * 1024 = 4K-bytes

go_next:

    ldr r3, [r0], #4

    ldr r4, [r1], #4

    teq r3, r4

    bne notmatch

    subs r2, r2, #4

    beq stack_setup

    bne go_next

notmatch:

    loop3: b loop3           //infinite loop

#endif                      //CONFIG_S3C2440_NAND_BOOT

/***************** NAND_BOOT *************************************************/

/***************** NOR_BOOT *************************************************/

relocate:                               /* relocate U-Boot to RAM          */

      /*********** CHECK_FOR_MAGIC_NUMBER***************/

ldr    r1, =(0xdeadbeef)

cmp r0, r1

bne  loop3

      /*********** CHECK_FOR_MAGIC_NUMBER***************/

adr   r0, _start          /* r0 <- current position of code   */

ldr    r1, _TEXT_BASE                 /* test if we run from flash or RAM */

ldr    r2, _armboot_start

ldr    r3, _bss_start

sub   r2, r3, r2           /* r2 <- size of armboot            */

add  r2, r0, r2           /* r2 <- source end address         */

copy_loop:

ldmia        r0!, {r3-r10}               /* copy from source address [r0]    */

stmia        r1!, {r3-r10}               /* copy to   target address [r1]    */

cmp r0, r2                           /* until source end addreee [r2]    */

ble    copy_loop

/***************** NOR_BOOT *************************************************/

 

/* Set up the stack                                                     */

stack_setup:

ldr    r0, _TEXT_BASE                 /* upper 128 KiB: relocated uboot   */

sub   r0, r0, #CONFIG_SYS_MALLOC_LEN        /* malloc area              */

sub   r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */

#ifdef CONFIG_USE_IRQ

sub   r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub   sp, r0, #12                 /* leave 3 words for abort-stack    */

bic    sp, sp, #7          /* 8-byte alignment for ABI compliance */

 

clear_bss:

ldr    r0, _bss_start           /* find start of bss segment        */

ldr    r1, _bss_end             /* stop here                        */

mov r2, #0x00000000               /* clear                            */

 

clbss_l:str r2, [r0]               /* clear loop...                    */

add  r0, r0, #4

cmp r0, r1

ble    clbss_l

 

ldr    pc, _start_armboot

 

#if defined(CONFIG_S3C2440)  //区别与其他开发板

//根据mini2440原理图可知LED分别由S3C2440PB5678口来控制,以下是PB端口寄存

//器基地址(2440DataSheet得知)

#define GPBCON 0x56000010

#define GPBDAT 0x56000014

#define GPBUP  0x56000018    

//以下对寄存器的操作参照S3C2440DataSheet进行操作

    ldr r0, =GPBUP

    ldr r1, =0x7FF    //即:二进制11111111111,关闭PB口上拉

    str r1, [r0]

    ldr r0, =GPBCON  //配置PB5678为输出口,对应PBCON寄存器的第10-17

    ldr r1, =0x154FD  //即:二进制010101010011111101

    str r1, [r0]

 

    ldr r0, =GPBDAT

    ldr r1, =0x1C0    //即:二进制111000000PB5设为低电平,678为高电平

    str r1, [r0]

#endif

 

//此段代码使u-boot启动后,点亮开发板上的LED1LED2LED3LED4不亮

 

_start_armboot:       .word start_armboot //在这一句的下面加上DW_STACK_START的定义

.align  2

DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

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

$ gedit board/jason/mini2440/nand_read.c //新建一个nand_read.c文件,记得保存

#include

#include

 

#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

 

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

#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 NFSTAT_BUSY 1

#define nand_select() (NFCONF &= ~0x800)

#define nand_deselect() (NFCONF |= 0x800)

#define nand_clear_RnB() do {} while (0)

#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)

#define NFCONF   __REGi(NF_BASE + 0x0)

#define NFCONT   __REGi(NF_BASE + 0x4)

#define NFCMD    __REGb(NF_BASE + 0x8)

#define NFADDR   __REGb(NF_BASE + 0xc)

#define NFDATA   __REGb(NF_BASE + 0x10)

#define NFDATA16 __REGw(NF_BASE + 0x10)

#define NFSTAT   __REGb(NF_BASE + 0x20)

#define NFSTAT_BUSY 1

#define nand_select()    (NFCONT &= ~(1 << 1))

#define nand_deselect()  (NFCONT |= (1 << 1))

#define nand_clear_RnB() (NFSTAT |= (1 << 2))

#endif

 

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();

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

              for (i = 0; i < nand->page_size; i++) {

              *buf = (NFDATA & 0xff);

              buf++;

                }

 

#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)

 

       for (i = 0; i < (nand->page_size>>1); i++) {

              *ptr16 = NFDATA16;

              ptr16++;

       }

#endif

       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;

}

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

COBJS    := mini2440.o flash.o nand_read.o

(五)在上一节中我们说过,通常在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动,但不管是从Nor启动或者从Nand启动,进入第二阶段以后,两者的执行流程是相同的。

现在的u-boot-2010-06版本对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函数等。

我们在u-boot提供的关于S3C2410nand_flash驱动文件的基础上添加相关代码以支持S3C2440.

 

$ gedit drivers/mtd/nand/s3c2410_nand.c

#include

#include

#include

#include

#define   NF_BASE             0x4e000000

 

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

#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 S3C2410_NFCONT_EN          (1<<0)

#define S3C2410_NFCONT_INITECC     (1<<4)

#define S3C2410_NFCONT_nFCE        (1<<1)

#define S3C2410_NFCONT_MAINECCLOCK (1<<5)

#define S3C2410_NFCONF_TACLS(x)    ((x)<<12)

#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<8)

#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<4)

 

#define S3C2410_ADDR_NALE 0x08

#define S3C2410_ADDR_NCLE 0x0c

#endif

 

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 s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)

{

//     struct nand_chip *chip = mtd->priv;

       struct s3c2410_nand *nand = s3c2410_get_base_nand();

 

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

 

       if (ctrl & NAND_CTRL_CHANGE) {

    //  ulong IO_ADDR_W = (ulong) nand;

              IO_ADDR_W = (ulong)nand;

 

              if (!(ctrl & NAND_CLE))

                     IO_ADDR_W |= S3C2410_ADDR_NCLE;

              if (!(ctrl & NAND_ALE))

                     IO_ADDR_W |= S3C2410_ADDR_NALE;

 

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

 

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

              if (ctrl & NAND_NCE)

                     writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,

                            &nand->NFCONF);

              else

                     writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,

                            &nand->NFCONF);

       }

#endif

#if defined(CONFIG_S3C2440)

              if (ctrl & NAND_NCE)

                     writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE,

                            &nand->NFCONT);

              else

                     writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE,

                            &nand->NFCONT);

       }

#endif

 

       if (cmd != NAND_CMD_NONE)

       // writeb(cmd, chip->IO_ADDR_W);

              writeb(cmd, (void *)IO_ADDR_W);

}

static int s3c2410_dev_ready(struct mtd_info *mtd)

{

       struct s3c2410_nand *nand = s3c2410_get_base_nand();

       debugX(1, "dev_ready/n");

       return readl(&nand->NFSTAT) & 0x01;

}

 

#ifdef CONFIG_S3C2410_NAND_HWECC

void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)

{

       struct s3c2410_nand *nand = s3c2410_get_base_nand();

       debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)/n", mtd, mode);

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

       writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);

#endif

 

#if defined(CONFIG_S3C2440)

       writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT);

#endif

}

 

static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,

                                  u_char *ecc_code)

{

       struct s3c2410_nand *nand = s3c2410_get_base_nand();

       ecc_code[0] = readb(&nand->NFECC);

       ecc_code[1] = readb(&nand->NFECC + 1);

       ecc_code[2] = readb(&nand->NFECC + 2);

       debugX(1, "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;

       struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();

       struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();

 

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

 

       writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);

 

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

       /* initialize hardware */

       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);

       writel(cfg, &nand_reg->NFCONF);

 

       /* initialize nand_chip data structure */

       nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;

#endif

#if defined(CONFIG_S3C2440)

       twrph0 = 4;

       twrph1 = 2;

       tacls = 0;

 

       cfg = 0;

       cfg |= S3C2410_NFCONF_TACLS(tacls - 1);

       cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);

       cfg |= S3C2410_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;

#endif

 

       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 = 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_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_S3C2410_NAND_BBT

       nand->options = NAND_USE_FLASH_BBT;

#else

       nand->options = 0;

#endif

 

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

 

       return 0;

}

 

(六) 修改s3c24x0.h,增加Nand flash寄存器定义

$ gedit arch/arm/include/asm/arch-s3c24x0/s3c24x0.h

 

#if defined(CONFIG_S3C2440)

struct s3c2410_nand {

  u32 NFCONF;

  u32 NFCONT;

  u32 NFCMD;

  u32 NFADDR;

  u32 NFDATA;

  u32 NFMECCD0;

  u32 NFMECCD1;

  u32 NFSECCD;

  u32 NFSTAT;

  u32 NFESTAT0;

  u32 NFESTAT1;

  u32 NFMECC0;

  u32 NFMECC1;

  u32 NFSECC;

  u32 NFSBLK;

  u32 NFEBLK;

};

#endif

#if defined(CONFIG_S3C2410)&& !defined (CONFIG_S3C2440)

/* NAND FLASH (see S3C2410 manual chapter 6) */

struct s3c2410_nand {

         u32  NFCONF;

         u32  NFCMD;

         u32  NFADDR;

         u32  NFDATA;

         u32  NFSTAT;

         u32  NFECC;

};

#endif

(七)还有一个重要的地方要修改,在cpu/arm920t/u-boot.lds中,这个u-boot启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的。如下:

$ gedit arch/arm/cpu/arm920t/u-boot.lds

.text :

{

     arch/arm/cpu/arm920t/start.o    (.text)

         board/jason/mini2440/lowlevel_init.o (.text)

         board/jason/mini2440/nand_read.o (.text)

     *(.text)

}

(八)编译成功后生成u-boot.bin文件。下载时先将mini2440开发板调到Nor启动档,利用supervivia命令将u-boot.bin下载到开发板的Nand Flash中,再把开发板调到Nand启动档,打开电源就从Nand Flash启动了,启动结果如下:

可以看到环境变量保存成功,将开发板重启后不会再有bad CRCnand flash 移植成功。

 

 

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