Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2261723
  • 博文数量: 218
  • 博客积分: 5767
  • 博客等级: 大校
  • 技术积分: 5883
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-01 14:44
文章存档

2012年(53)

2011年(131)

2009年(1)

2008年(33)

分类: LINUX

2011-09-24 15:09:01

 

1u-boot版本1.1.6gcc version 4.3.2

 

2)在Makefile中的smdk2410_config后加入

st2410_config :       unconfig

        @$(MKCONFIG) $(@:_config=) arm arm920t st2410 NULL s3c24x0我把我的板子起名叫st2410,可以依自己的喜好修改,注意@前用tab键空格。

各项的意思如下:

arm:        CPU的架构(ARCH)

arm920t:    CPU的类型(CPU),其对应于cpu/arm920t子目录。

st2410:    开发板的型号(BOARD),对应于board/st2410目录。

NULL:       开发者/或经销商(vender)

s3c24x0:    片上系统(SOC)

 

3)建立board/st2410目录,拷贝board/smdk2410下的文件到board/st2410目录,将smdk2410.c更名为st2410.c

cp -ar board/smdk2410/ board/st2410

mv board/st2410/smdk2410.c board/st2410/st2410.c

 

4)board/st2410/Makefile中,如下修改(因为前面将smdk2410.c文件改名为st2410.c)

COBJS:= smdk2410.o flash.o

改为:

COBJS:= st2410.o flash.o

 

5cp include/configs/smdk2410.h include/configs/st2410.h

并将st2410.h中的

#define CFG_PROMPT              "SMDK2410 # "

修改为

#define CFG_PROMPT              "ST2410 # "

6)测试编译能否成功:

make st2410_config

make all ARCH=arm

生成u-boot.binOK

 

 

支持Nandflash启动方式

1         修改cpu/arm920t/start.S文件

1)将以下代码

#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 */

修改为:

/***************** 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 *********************************/

#ifdef CONFIG_S3C2410

#define BWSCON 0x48000000

#endif

       ldr   r0, =BWSCON

       ldr   r0, [r0]

       ands r0, r0, #6             /*OM[1:0] != 0, NOR FLash boot*/

       bne  relocate             /*NOR FLash boot*/

/*    adr   r0, ResetEntry              ;OM[1:0] == 0, NAND FLash boot

       cmp r0, #0                          ;if use Multi-ice,

       bne  copy_proc_beg              ;don't read nand flash for boot*/

 

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

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

 

#define LENGTH_UBOOT 0x60000

#define NAND_CTL_BASE 0x4E000000

 

#ifdef      CONFIG_S3C2410

 

/* Offset */

#define oNFCONF 0x00

#define oNFCMD 0x04

#define oNFSTAT 0x10

 

       @ reset NAND

       mov r1, #NAND_CTL_BASE

       ldr   r2, =0xf830   @ initial value

       str    r2, [r1, #oNFCONF] /* 设置NFCONF寄存器 */

 

       /* 设置NFCONT,初始化ECC/解码器,禁止NAND Flash片选 */

       ldr   r2, [r1, #oNFCONF]

       bic   r2, r2, #0x800      @ enable chip

       str    r2, [r1, #oNFCONF]

       mov r2, #0xff        @ RESET command

       strb  r2, [r1, #oNFCMD] /* 复位命令,第一次使用NAND Flash前复位 */

      

      

       mov r3, #0     @ wait

nand1:

       add  r3, r3, #0x1

       cmp r3, #0xa

       blt   nand1

 

nand2:

       ldr   r2, [r1, #oNFSTAT]     @ wait ready

       tst    r2, #0x1

       beq  nand2

      

       ldr   r2, [r1, #oNFCONF]

       orr   r2, r2, #0x800      @ disable chip

       str    r2, [r1, #oNFCONF]

      

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

/* 为调用C函数nand_read_ll准备堆栈 */

       ldr   sp, DW_STACK_START      @ setup stack pointer

       mov fp, #0     @ no previous frame, so fp=0

       /* 下面先设置r0r2,然后调用nand_read_ll函数将U-Boot读入RAM */

       @ copy U-Boot to RAM

       ldr   r0, =TEXT_BASE  /* 目的地址:U-BootRAM的开始地址 */

       mov r1, #0x0           /* 源地址:U-BootNAND Flash中的开始地址 */

       mov r2, #LENGTH_UBOOT  /* 复制的大小,必须比u-boot.bin文件大,并且必须是NAND Flash块大小的整数倍,这里设置为0x60000KB */

       bl    nand_read_ll   /* 跳转到nand_read_ll函数,开始复制U-BootRAM */

       tst    r0, #0x0  /* 检查返回值是否正确 */

       beq  ok_nand_read

 

bad_nand_read:

loop2:

       b     loop2      @ infinite loop

 

 

ok_nand_read:

       @ verify

       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

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

 

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

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 */

       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 ***********************************************/

2)在_start_armboot: .word start_armboot之后加入::

#define STACK_BASE 0x33f00000

#define STACK_SIZE 0x10000

       .align      2

DW_STACK_START:    .word      STACK_BASE+STACK_SIZE-4

 

2board/st2410加入NAND Flash读函数,建立nand_read.c

在上面添加的代码中有一个跳转:bl nand_read_ll ,它跳入是新增的 C 语言文件(board/st2410/nand_read.c)中的函数,这个文件原本是用 vivi 的代码,好来经过了 openmoko 的修改,并支持不同的 Nand Flash 芯片,我又多加了几个个芯片 ID以支持所有 2410 Nand Flash。代码如下:

/*

 * 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

 * Date  : $Date: 2004/02/04 10:37:37 $

 *

 * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.

 * Author: Harald Welte

 */

 

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

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

};

 

#if 0

#if defined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)

/* configuration for 2410 with 512byte sized flash */

#define NAND_PAGE_SIZE              512

#define BAD_BLOCK_OFFSET  5

#define NAND_BLOCK_MASK         (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE           0x4000

#else

/* configuration for 2440 with 2048byte sized flash */

#define NAND_5_ADDR_CYCLE

#define NAND_PAGE_SIZE              2048

#define BAD_BLOCK_OFFSET  NAND_PAGE_SIZE

#define    NAND_BLOCK_MASK              (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE           (NAND_PAGE_SIZE * 64)

#endif

 

/* compile time failure in case of an invalid configuration */

#if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)

#error "S3C2410 does not support nand page size != 512"

#endif

#endif

 

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)

       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;

}

 

       NAND Flash根据page大小可分为2种: 512B/page2048B/page的。但2410nandflash控制器仅支持512 B/page的,这里使用上面的函数处理,在2440的移植中再做更改。这两种NAND Flash的读操作是不同的。因此就需要U-Boot识别到NAND Flash的类型,然后采用相应的读操作,也就是说nand_read_ll函数要能自动适应两种NAND Flash。参考S3C2440的数据手册可以知道:根据NFCONF寄存器的Bit3AdvFlash (Read only))和Bit2 PageSize (Read only))可以判断NAND Flash的类型。Bit2Bit3NAND Flashblock类型的关系如下表所示:

2.4 NFCONFBit3Bit2NAND Flash的关系

       由于的NAND Flash只有512B/page2048 B/page这两种,因此根据NFCONF寄存器的Bit3即可区分这两种NAND Flash了。

       完整代码见board/samsung/mini2440/nand_read.c中的nand_read_ll函数,这里给出伪代码:

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

//根据NFCONF寄存器的Bit3来区分2NAND Flash

       if( NFCONF & 0x8 )        /* Bit1,表示是2KB/pageNAND Flash */

       {

              ////////////////////////////////////

              读取2K block NAND Flash

              ////////////////////////////////////

       }

      else                      /* Bit0,表示是512B/pageNAND Flash */

       {

              /////////////////////////////////////

              读取512B block NAND Flash

              /////////////////////////////////////

       }

    return 0;

}

3 修改board/st2410/Makefile

OBJS := st2410.o flash.o nand_read.o

 

4 include/configs/st2410.h中添加

/*

 * Nandflash Boot

 */

#define NAND_MAX_CHIPS 1

 

nand_read.c文件中有用到。

5 重新编译u-boot

make all ARCH=arm

 

6 通过jtagu-boot烧写到flash中就可以从NAND flash启动了

我的u-boot启动信息:

U-Boot 1.1.6 (Aug  8 2011 - 14:04:28)

DRAM:  64 MB

Flash: 512 kB

*** Warning - bad CRC, using default environment

In:    serial

Out:   serial

Err:   serial

ST2410 #

 

可以看出:和第一次make的结果一样,u-boot命令依然不能用,也就是说不能用saveenv保存设置,因为我们现在只是完成了u-bootNAND FLASH的启动工作,添加了nand_read.c函数,而不能实现写操作,

norflash启动时u-boot支持Nand Flash的读写操作

U-BOOT 1.1.5以后的版本对NAND FLASH的支持有新旧两套代码,心代码在drivers/mtd/nand目录下面,就代码在drivers/mtd/nand_legacy目录下面。文档 doc/README.nand对这两套代码有所说明:使用旧代码需要定义更多的宏,而新代码移植自Linux内核2.6.12,它更加智能,可以自动识别更多型号的NAND Flash。目前之所以还保留旧的代码,是因为两个目标板NETTANETTA_ISDN使用JFFS文件系统,它们还依赖于旧代码。当相关功能移植到新代码之后,旧的代码将从U-Boot中去除。这里我们移植用新的代码来支持nand flash.如果让UBOOT支持 nand flash首先在include/configs/st2410.h里添加CONFIG_CMD_NAND宏,这些宏在incldue /config_cmd_all.h定义。然后选择哪套代码需要在include/configs/st2410.h定义 CONFIG_NAND_LEGACY宏,不定义则用新的代码。我们使用新的代码来支持nand flash

现在开始移植:

要让U-Boot支持NAND Flash,首先在配置文件include/configs/st2410.h的宏CONFIG_COMMANDS中增加CFG_CMD_NAND,如下:

 

#define CONFIG_COMMANDS \

                        (CONFIG_CMD_DFL  | \

                        CFG_CMD_CACHE    | \

                        CFG_CMD_NAND     | \

                        /*CFG_CMD_EEPROM |*/ \

                        /*CFG_CMD_I2C    |*/ \

                        /*CFG_CMD_USB    |*/ \

                        CFG_CMD_REGINFO  | \

                        CFG_CMD_DATE     | \

                        CFG_CMD_ELF)

……

 

然后选择使用哪套代码:在配置文件中定义宏CFG_NAND_LEGACY则使用旧代码,否则使用新代码。

使用旧代码时,需要实现drivers/nand_legacy/nand_legacy.c中使用到的各种宏,比如:

#define NAND_WAIT_READY(nand)/* 等待Nand Flash的状态为“就绪”,代码依赖于具体的开发板 */

#define WRITE_NAND_COMMAND(d, adr)/* NAND Flash命令,代码依赖于具体的开发板 */

 

代码的移植没有现成的文档,在CONFIG_COMMANDS中增加CFG_CMD_NAND后,就编译代码,然后一个一个地解决出现的错误。编译结果中出现的错误和警告如下:

                 from nand.c:28:

/home/just/study/uboot/nand-u-boot-1.1.6/include/linux/mtd/nand.h:412: error: 'NAND_MAX_CHIPS' undeclared here (not in a function)

nand.c:35: error: 'CFG_MAX_NAND_DEVICE' undeclared here (not in a function)

nand.c:38: error: 'CFG_NAND_BASE' undeclared here (not in a function)

make[1]: *** [nand.o] 错误 1

make[1]: Leaving directory `/home/just/study/uboot/nand-u-boot-1.1.6/drivers/nand'

make: *** [drivers/nand/libnand.a] 错误 2

在配置文件include/configs/st210.h中增加如下3个宏就可以解决上述错误。在Flash的驱动程序中,设备是逻辑上的概念,表示一组相同结构、访问函数相同的Flash芯片。在本书所用开发板中,只有一个NAND Flash芯片,所以设备数为1,芯片数也为1

 

#define CFG_NAND_BASE 0x4e000000   /* nand flash控制器的基址,无实际意义,这在board_nand_init中重新指定 */

#define CFG_MAX_NAND_DEVICE 1/* NAND Flash“设备”的数目为1 */

#define NAND_MAX_CHIPS 1/* 每个NAND Flash“设备”由1NAND Flash“芯片”组成 */

 

修改配置文件后再次编译,现在只有一个错误了,“board_nand_init函数未定义”:

nand.c:50: undefined reference to `board_nand_init'

 

调用board_nand_init函数的过程为:NAND Flash的初始化入口函数是nand_init,它在lib_arm/board.cstart_armboot函数中被调用;nand_init函数在drivers/nand/nand.c中实现,它调用相同文件中的nand_init_chip函数;nand_init_chip函数首先调用 board_nand_init函数来初始化NAND Flash设备,最后才是统一的识别过程。

board_nand_init函数的名称就可以知道它是平台/开发板相关的函数,需要自己编写。本书在cpu/arm920t/s3c24x0 目录下新建一个文件nand_flash.c,在里面针对S3C2410S3C2440实现了统一的board_nand_init函数。

在编写board_nand_init函数的之前,需要针对S3C2410S3C2440 NAND Flash控制器的不同定义一些数据结构和函数:

(1)       include/s3c24x0.h文件中增加S3C2440_NAND数据结构。S3C2410_NAND数据结构文件中已经有定义。

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

 

typedef struct {

        S3C24X0_REG32 NFCONF;

        S3C24X0_REG32 NFCONT;

        S3C24X0_REG32 NFCMD;

        S3C24X0_REG32 NFADDR;

        S3C24X0_REG32 NFDATA;

        S3C24X0_REG32 NFMECCD0;

        S3C24X0_REG32 NFMECCD1;

        S3C24X0_REG32 NFSECCD;

        S3C24X0_REG32 NFSTAT;

        S3C24X0_REG32 NFESTAT0;

        S3C24X0_REG32 NFESTAT1;

        S3C24X0_REG32 NFMECC0;

        S3C24X0_REG32 NFMECC1;

        S3C24X0_REG32 NFSECC;

        S3C24X0_REG32 NFSBLK;

        S3C24X0_REG32 NFEBLK;

} /*__attribute__((__packed__))*/ S3C2440_NAND;

2)在include/s3c2410.h文件中仿照S3C2410_GetBase_NAND函数定义S3C2440_GetBase_NAND函数。

 

/* for s3c2440 */

static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)

{

  return (S3C2440_NAND * const)S3C2410_NAND_BASE;

}

 

 

既然新的NAND Flash代码是从Linux内核2.6.12中移植来的,那么cpu/arm920t/s3c24x0/nand_flash.c文件也可以仿照内核中,对S3C2410S3C2440NAND Flash进行初始化的drivers/mtd/nand/s3c2410.c文件来编写。为了方便阅读,先把 cpu/arm920t/s3c24x0/nand_flash.c文件的代码全部列出来,再讲解:

/*

 * s3c2410/s3c2440NAND Flash控制器接口,  修改自Linux内核2.6.13文件drivers/mtd/nand/s3c2410.c

*/

 

#include

#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)

#include

#include

 

DECLARE_GLOBAL_DATA_PTR;

 

#define S3C2410_NFSTAT_READY (1<<0)

#define S3C2410_NFCONF_nFCE (1<<11)

#define S3C2440_NFSTAT_READY (1<<0)

#define S3C2440_NFCONT_nFCE (1<<1)

 

 /* S3C2410NAND Flash的片选函数 */

static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)

{

 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

  if (chip == -1) {

  s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;/* 禁止片选信号 */

 } else {

 s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;/* 使能片选信号 */

   }

}

 

 /* S3C2410:命令和控制函数

* 注意,这个函数仅仅根据各种命令来修改“写地址”IO_ADDR_W 的值(这称为tglx方法)

* 这种方法使得平台/开发板相关的代码很简单。

 * 真正发出命令是在上一层NAND Flash的统一的驱动中实现,

* 它首先调用这个函数修改“写地址”,然后才分别发出控制、地址、数据序列。

*/

static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)

{

 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

 struct nand_chip *chip = mtd->priv;

 switch (cmd) {

  case NAND_CTL_SETNCE:

  case NAND_CTL_CLRNCE:

  printf("%s: called for NCE/n", __FUNCTION__);

  break;

 

  case NAND_CTL_SETCLE:

    chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;

    break;

 

  case NAND_CTL_SETALE:

    chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;

    break;

 

   /* NAND_CTL_CLRCLE: */

  default:

    chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;

    break;

    }

 }

 

 /* S3C2410:查询NAND Flash状态

*

* 返回值:0 , 1 就绪

 */

static int s3c2410_nand_devready(struct mtd_info *mtd)

{

 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

 return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);

 

}

 

 /* S3C2440NAND Flash的片选函数 */

 

 static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)

{

 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

 if (chip == -1) {

 s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;/* 禁止片选信号 */

 } else {

 s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;/* 使能片选信号 */

   }

 }

 /* S3C2440:命令和控制函数,与s3c2410_nand_hwcontrol函数类似 */

 

 static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)

 {

 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

 struct nand_chip *chip = mtd->priv;

 

 switch (cmd) {

 

 case NAND_CTL_SETNCE:

 case NAND_CTL_CLRNCE:

   printf("%s: called for NCE/n", __FUNCTION__);

   break;

 

 case NAND_CTL_SETCLE:

   chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;

   break;

 

 case NAND_CTL_SETALE:

   chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;

   break;

 

 /* NAND_CTL_CLRALE: */

 default:

   chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;

   break;

     }

 }

 

 /* S3C2440:查询NAND Flash状态

* 返回值:0 , 1 就绪

 */

static int s3c2440_nand_devready(struct mtd_info *mtd)

{

 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

 

 return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);

}

 

 /*

 * Nand flash硬件初始化:

* 设置NAND Flash的时序, 使能NAND Flash控制器

 */

 static void s3c24x0_nand_inithw(void)

{

 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

 

 #define TACLS 0

 #define TWRPH0 4

 #define TWRPH1 2

 

 if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)

   {

     /* 使能NAND Flash控制器,初始化ECC,使能片选信号,设置时序 */

  s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

   }

 else

   {

     /* 设置时序 */

   s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

     /* 初始化ECC,使能NAND Flash控制器,使能片选信号 */

   s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);

    }

 }

 

/*

 * drivers/nand/nand.c调用, 初始化NAND Flash硬件,初始化访问接口函数

 */

 void board_nand_init(struct nand_chip *chip)

 {

 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

 s3c24x0_nand_inithw();/* Nand flash硬件初始化 */

 

 if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410) {

 chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;

 chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;

 chip->hwcontrol = s3c2410_nand_hwcontrol;

 chip->dev_ready = s3c2410_nand_devready;

 chip->select_chip = s3c2410_nand_select_chip;

 chip->options = 0;/* 设置位宽等,位宽为8 */

 } else {

 chip->IO_ADDR_R = (void *)&s3c2440nand->NFDATA;

 chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;

 chip->hwcontrol = s3c2440_nand_hwcontrol;

 chip->dev_ready = s3c2440_nand_devready;

 chip->select_chip = s3c2440_nand_select_chip;

 chip->options = 0;/* 设置位宽等,位宽为8 */

   }

 

 chip->eccmode = NAND_ECC_SOFT;/* ECC较验方式:软件ECC */

 

 }

 

 

#endif

 

文件中分别针对S3C2410S3C2440实现了NAND Flash最底层访问函数,并进行了一些硬件的设置(比如时序、使能NAND Flash控制器等)。新的代码对NAND Flash的封装做得很好,只要向上提供底层初始化函数board_nand_init来设置好平台/开发板相关的初始化、提供底层接口即可。

最后,只要将新建的nand_flash.c文件编入U-Boot中就可以擦除、读写NAND Flash了。如下修改cpu/arm920t/s3c24x0/Makefile文件即可:

 

COBJS = i2c.o interrupts.o serial.o speed.o /

usb_ohci.o

改为:

COBJS = i2c.o interrupts.o serial.o speed.o /

usb_ohci.o nand_flash.o

 

加入 NAND 闪存芯片型号

/include/linux/mtd/nand_ids.h 中对如下结构体赋值进行修改:

static struct nand_flash_dev nand_flash_ids[] = {

..........................................

{"Samsung K9F1208U0M",    NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},

..........................................

}

这样对于该款 NAND 闪存芯片的操作才能正确执行。由于我移植的开发板上是K9F1208U0Mnand_ids.h 中有{"Samsung unknown 64Mb",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},在这里可省出这一步。

 

现在,可以再编译,此时又出现下面错误

 

arm-linux-ld: failed to merge target specific data of file /opt/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t/libgcc.a(_clz.o)

/opt/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t/libgcc.a(_dvmd_lnx.o): In function `__aeabi_ldiv0':

(.text+0x8): undefined reference to `raise'

make: *** [u-boot] 错误 1

由于我用的toolchain版本是4.3.2,目前这个版本比较新,而我移植的uboot可是好几年前的版本了,所以它的“tricks”对该toolchain无能为力(或许新版的uboot能摆平)。

修改方法

cpu/arm920t/config.mk 改为

PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8 \

    -msoft-float

 

PLATFORM_CPPFLAGS +=

# ====================================================================

#

# Supply options according to compiler version

#

# ====================================================================

PLATFORM_CPPFLAGS +=$(call cc-option,)

PLATFORM_RELFLAGS +=$(call cc-option,$(call cc-option,))

 

uboot的根目录Makefile文件中把PLATFORM_LIBS 修该为如下值

PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc -lc -L/opt/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/usr/lib

然后重新

make distclean 

make  st2410_config

make all ARCH=arm

应就能通过了

 

我遇到问题就是在移植uboo1.1.6 中加入 CFG_CMD_NAND 就报那个错误 不过友善提供的可以通过

通过对比 修改了上面两个地方  就不在提示那个错误了

U-Boot 1.1.6 (Aug  9 2011 - 11:26:02)

DRAM:  64 MB

Flash: 512 kB

NAND:  64 MiB

*** Warning - bad CRC, using default environment

In:    serial

Out:   serial

Err:   serial

ST2410 #

查看nand flash的信息:

ST2410 # nand info

Device 0: NAND 64MiB 3,3V 8-bit, sector size 16 KiB

擦出 nand

ST2410 # nand erase 0x02200000 0x04000000

 

NAND erase: device 0 whole chip

Erasing at 0x2200000 --   0

Erasing at 0x22a0000 --   1

Erasing at 0x2344000 --   2mplete.

Erasing at 0x23e8000 --   3mplete.

Erasing at 0x248c000 --   4mplete.

Erasing at 0x2530000 --   5

 

NAND 64MiB 3,3V 8-bit: MTD Erase failure: -22

 

NAND 64MiB 3,3V 8-bit: MTD get bad block failed: -22

ERROR

现在的代码支持的非常好,能自动检测出坏快。不错!

 

*** Warning - bad CRC, using default environment

 

输入saveenvreset保存不了变量。。。。

可能是没把新的环境变量保存到nandflash,原来uboot默认把环境变量保存到norflash中,这个也是在事后修改程序后才发觉的。修改st2410.h如下:

#define CFG_ENV_IS_IN_FLASH     1          /*enviroment is in the norflash*/这里为修改的。

改为:

//#define CFG_ENV_IS_IN_FLASH     1          /*enviroment is in the norflash*/

#define CFG_ENV_IS_IN_NAND  1

#define CFG_ENV_OFFSET      0x40000

 

修改完再生成u-boot.bin再烧入板中,在dnw下观察信息,竟然第一次的warning都没有,有点不可思议。

 

U-BOOT Nand命令支持

http://blogold.chinaunix.net/u1/47239/showart.php?id=376731

u-boot1.1.6 nand_legacy驱动提供了u-bootnand相关命令的一个轻量级的实现,但好象可扩展性不足。本文主要分析u-boot 1.16/drivers/nand文件夹下的源程序。

.关键数据结构

1.struct mtd_info

该结构在include\linux\mtd\Mtd.h中定义,字段比较多,有很多还是函数指针,它是MTD设备操作的通用接口,这个结构中有一个比较重要的成员 void *privpriv被声明成void指针,在下文的分析中会知道priv实际上指向了nand_chip结构。

2.struct nand_chip

   该结构在include\linux\mtd\Nand.h中定义,从名字上看就知道u-boot用它来描述Nand Flash芯片的结构,比如它定义了页地址的偏移,页地址的位掩码等。struct nand_chip不用我们手动的初始化,而是由另外一个结构,struct nand_flash_dev在程序中动态的初始化。

3.struct nand_flash_dev

 

    该结构的定义有两处地方分别是

include/linux/mtd/nand_legacy.h nand_legacy模块使用

include/linux/mtd/nand.h       u-boot通用nand架构使用

 

特别是在移植的时候要小心把两者混淆。我们先来看看改结构的定义

 

struct nand_flash_dev {

       char *name;          

       int id;

       unsigned long pagesize;

       unsigned long chipsize;

       unsigned long erasesize;

       unsigned long options;

};

 

name : Nand Flash名称

id : u-boot内部id编号???

chipsize : MB为单位的芯片大小,比如64M

erasesize : 擦除块的大小,比如0x400016K

options : 一些选项,比较重要的是Flash的数据位宽,如果你的Nand Flash16位宽的,则必须包含NAND_BUSWIDTH_16选项。我们必须根据所使用的Nand Flash来填充里面的字段。

 

4.关键数据结构在程序中的使用

struct nand_info_t nand_info[ CFG_MAX_NAND_DEVICE ];

drivers\nand\nand.c中定义。CFG_MAX_NAND_DEVICE是板子的Nand Flash芯片的数量必须在板子的配置文件中定义(比如 include\configs\smdk2410.h)。

 

static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];

drivers\nand\nand.c中定义。CFG_MAX_NAND_DEVICE的定义同上。

 

struct nand_flash_dev nand_flash_ids[] = { };

drivers\nand\nand_ids.c中定义。这里要注意一点,在include\linux\mtd\nand_ids.h里面也nand_flash_ids[]的定义,那是由nand legacy驱动模块使用的。两者不能混淆!!!。在nand_flash_ids的定义中我找到了适合我的Nand Flash的结构描述:

{"NAND 64MiB 3,3V 8-bit",        0x76, 512, 64, 0x4000, 0}

设备ID0x76,页大小为512Byte,总的容量为64M,擦除块为0x400016K),数据位宽8Bit。如果你的Nand Flash没有合适的描述,需要自己在该数组中添加相应的定义。

 

.Nand Flash初始化

1.nand_init drivers\nand\nand.c

nand_init函数在lib_xxx/Board.cstart_armboot中调用。是u-boot Nand的主函数。nand_init的主要功能是对CFG_MAX_NAND_DEVICENand设备进行初始化(调用nand_init_chip,累加Nand Flash的总大小。在nand_init结束时,可以配置是否执行board_nand_select_device,选择Nand芯片。

2.nand_init_chip drivers\nand\nand.c

static void nand_init_chip struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr )调用各个开发板提供的 board_nand_init 函数( board\\.c )让开发板获得初始化Nand Flash芯片的机会。调用 nand_scan

 

3.nand_scan drivers\nand\nand_base.c

int nand_scan( struct mtd_info *mtd, int maxchips )

这是u-boot初始化nand设备的核心函数。它主要完成以下工作

 

1)初始化nand_chip的函数指针,这些函数一般在 board\\.c中定义。

struct nand_chip *this = mtd->priv

....

if( this-> cmdfunc == NULL )

       this->cmdfunc = nand_command;

上面是初始化nand_chipcmdfunc指针的代码,如果在board_init_nand中开发板没有提供自己的nand_command函数,u-boot 将使用默认的nand_command函数(我觉得u-boot提供的这些默认的函数都不适合特定的硬件,所以很多都要自己重新写)。

 

2)使用上面注册的函数指针,读取Nand Flash的设备,并且在上文提到的nand_flash_ids[]中找是否有匹配项,若找到匹配的项,则初始化 nand_chip mtd_info,它们的初始化代码老长的一段,一般没什么问题。

 

. Nand Flash 操作

1. Read

函数调用层次:(如下图)。

common/env_nand.c里面读取Nand Flash中的环境变量为例

common/env_nand.c

ret = nand_read( &nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr );

nand_info[]就是我们在1.4讲到的nand_info_tmtd_info的别名)数组。此处的nand_read是个inline函数,下面是它的实现:

include/nand.h

static inline int nand_read(nand_info_t *info, ulong ofs, ulong *len, u_char *buf)

{

       return info->read(info, ofs, *len, (size_t*)len, buf);

}

 

可以看出nand_read实际上调用的是nand_inforead方法。nand_inforead方法是在2.3中讲到的nand_scan中初始化

drivers/nand/nand_base.c

int nand_scan(struct mtd_info *mtd, int machips)

{

      

       mtd->read = nand_read;

      

}

 

此处又一个nand_read!!!

 

drivers/nand/nand_base.c

static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)

{

       return nand_read_ecc( mtd, from, len, retlen, buf, NULL, NULL );

}

又一层包装!!!

 

drivers/nand/nand_base.c

static int nand_read_ecc()

{

      

}

终于到达最后一层了,nand_read_ecc通过调用nand_chip里面提供的函数对nand flash完成读的操作。具体可以看看代码,老长的一段。

 

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