u-boot-2011.06移植

Posted on 2011-12-01 10:21  lesson1  阅读(1744)  评论(0)    收藏  举报

资料为网上摘抄

板子是国嵌的 GQ2440

    u-boot-2011.06虽然支持一些常见的开发板,但如果u-boot-2011.06不支持我们手上的开发板,那就要找到与我们的开发板最接近的u-boot-2011.06所支持的开发板,在这个开发板的基础上进行移植。u-boot-2011.06所支持的smdk2410开发板是最接近我的开发板的,所以我就在该此基础上进行修改、移植。

 

在移植之前,我们还需要安装、配置eldk,用于编译u-boot。下面我们就先介绍一下eldk的安装与配置:

1.下载eldk

        在ftp://ftp.denx.de/pub/eldk/选择任一版本的eldk并下载,我选择的是eldk4.2版本的arm-2008-11-24.iso文件。把该文件下载到/home/zhaocj/download/目录下。

2.在root权限下安装eldk

        创建挂载点:

mkdir   /mnt/dvdrom

        挂载光驱:

mount  –o loop /home/zhaocj/download/arm-2008-11-24.iso/mnt/dvdrom

        安装eldk:

cd   /mnt/dvdrom

./install –d /opt/eldk4.2/

       这样eldk就安装到了/opt/eldk4.2目录下。

3.设置环境变量

cd  ~

gedit   .bashrc

        在最后添加如下内容:

export  CROSS_COMPILE=arm-linux-

export  PATH=/opt/eldk4.2/bin: /opt/eldk4.2/usr/bin:$PATH

        保存并退出,然后执行:

source  .bashrc

        重启电脑就完成了eldk的安装。

 

       下面就介绍u-boot-2011.06的移植,在这里我把我的开发板命名为gq2440:

1.下载u-boot

        在ftp://ftp.denx.de/pub/u-boot/下载目前最新的u-boot版本(即u-boot-2011.06.tar.bz2)到我的用户主目录下。

2.解压u-boot

cd  ~

        把u-boot-2011.06解压到当前目录下

tar  –xvjf u-boot-2011.06.tar.bz2

cd  u-boot-2011.06

3.在u-boot中添加我的开发板信息

emacs  boards.cfg

       打开boards.cfg文件,在第70行(smdk2410 arm arm920t – samsung s3c24x0)的下面添加一行,内容如下:

gq2440 arm arm920t – samsung s3c24x0

       保存并退出。

4.通过复制的方式添加我的开发板头文件

cp include/configs/smdk2410.h include/configs/gq2440.h

5.通过复制的方式添加我的开发板文件夹

cp –r board/samsung/smdk2410 board/samsung/gq2440

       更改文件名

mv board/samsung/gq2440/smdk2410.c board/samsung/gq2440/gq2440.c

       修改Makefile文件

emacs board/samsung/gq2440/Makefile

       打开Makefile文件,在第28行中,把COBJS :=smdk2410.o改为:

COBJS:=gq2440.o

       保存并退出。

6.编译

make   distclean

make   gq2440_config

make

      

        如果上述过程没有出错的话,会在u-boot的目录下出现新的u-boot.bin文件。

2 NorFlash启动移植方法

.修改宏定义

打开include/configs/gq2440.h文件

第38行“#define CONFIG_S3C2410        ”改为:

38:#define CONFIG_S3C2440         

目的是告之系统本开发板使用的是S3C2440处理器。

 

第131行“#define CONFIG_SYS_PROMPT     "SMDK2410 # "”改为:

131:#define CONFIG_SYS_PROMPT      "gq2440# "

目的是使命令行提示符显示为“gq2440# ”。

 

第185行“#define CONFIG_FLASH_CFI_LEGACY”改为:

185:#define CONFIG_SYS_CFI_FLASH_CONFIG_REGS    {0xFFFF}

因为在u-boot-2011.06中,使用的是CFI的NorFlash接口,所以不需要定义CONFIG_FLASH_CFI_LEGACY,而是要定义CONFIG_SYS_CFI_FLASH_CONFIG_REGS。

 

第191行“#define CONFIG_SYS_MAX_FLASH_SECT (19)”改为:

191:#define CONFIG_SYS_MAX_FLASH_SECT   (35)

因为本开发板使用的NorFlash是EN29LV160AB,它有35个扇区。

 

第212行“#define CONFIG_NAND_S3C2410”改为:

212:#define CONFIG_NAND_S3C2440

 

第213行“#define CONFIG_SYS_S3C2410_NAND_HWECC”改为:

213:#define CONFIG_SYS_S3C2440_NAND_HWECC

 

2.修改系统时钟频率

打开arch/arm/cpu/arm920t/start.s文件

第164行“# if defined(CONFIG_S3C2410)”改为:

164:# if defined(CONFIG_S3C2440)

 

第165行“ldr       r1, =0x3ff”改为:

165:ldr r1, =0x7fff

目的是屏蔽所有子中断。

 

第173行“mov     r1, #3”改为:

173:mov      r1, #5

目的是使FCLK:HCLK:PCLK= 1:4:8。

 

打开board/samsung/gq2440/gq2440.c文件

第42行至第44行的内容改为:

42:#define M_MDIV   92

43:#define M_PDIV    1

44:#define M_SDIV    1

本开发板的输入晶振频率为12MHz,通过上面的修改,则MPLL频率为400MHz。

 

第54行至第56行的内容改为:

54:#define U_M_MDIV     56

55:#define U_M_PDIV      2

56:#define U_M_SDIV      2

通过上面的修改,则UPLL频率为48MHz。

 

3.修改内存SDRAM时序

打开board/samsung/gq2440/lowlevel_init.s文件

第54行至第126行的内容改为:

54:#define B1_BWSCON          (DW16)

55:#define B2_BWSCON          (DW16)

56:#define B3_BWSCON          (DW16)

57:#define B4_BWSCON          (DW32)

58:#define B5_BWSCON          (DW16)

59:#define B6_BWSCON          (DW32)

60:#define B7_BWSCON          (DW32)

61:

62:

63:#define B0_Tacs                   0x3

64:#define B0_Tcos                   0x3

65:#define B0_Tacc                   0x7

66:#define B0_Tcoh                  0x3

67:#define B0_Tah                    0x3

68:#define B0_Tacp                  0x1

69:#define B0_PMC                  0x0

70:

71:

72:#define B1_Tacs                   0x1

73:#define B1_Tcos                   0x1

74:#define B1_Tacc                   0x6

75:#define B1_Tcoh                  0x1

76:#define B1_Tah                    0x1

77:#define B1_Tacp                  0x0

78:#define B1_PMC                  0x0

79:

80:#define B2_Tacs                   0x1

81:#define B2_Tcos                   0x1

82:#define B2_Tacc                   0x6

83:#define B2_Tcoh                  0x1

84:#define B2_Tah                    0x1

85:#define B2_Tacp                  0x0

86:#define B2_PMC                  0x0

87:

88:#define B3_Tacs                   0x1

89:#define B3_Tcos                   0x1

90:#define B3_Tacc                   0x6

91:#define B3_Tcoh                  0x1

92:#define B3_Tah                    0x1

93:#define B3_Tacp                  0x0

94:#define B3_PMC                  0x0

95:

96:#define B4_Tacs                   0x1

97:#define B4_Tcos                   0x1

98:#define B4_Tacc                   0x6

99:#define B4_Tcoh                  0x1

100:#define B4_Tah                  0x1

101:#define B4_Tacp                 0x0

102:#define B4_PMC                0x0

103:

104:#define B5_Tacs                 0x1

105:#define B5_Tcos                 0x1

106:#define B5_Tacc                 0x6

107:#define B5_Tcoh                0x1

108:#define B5_Tah                  0x1

109:#define B5_Tacp                 0x0

110:#define B5_PMC                0x0

111:

112:#define B6_MT                  0x3

113:#define B6_Trcd                 0x1

114:#define B6_SCAN                     0x1

115:

116:#define B7_MT                  0x3

117:#define B7_Trcd                 0x1

118:#define B7_SCAN                     0x1

119:

120:

121:#define REFEN                  0x1

122:#define TREFMD               0x0

123:#define Trp                 0x1

124:#define Trc                 0x1

125:#define Tchr                0x2

126:#define REFCNT                1268

 

4.修改NandFlash相关内容。

尽管本次移植没有涉及到NandFlash,但为了能够编译成功,必须修改下面有关NandFlash的内容。

 

进入u-boot-2011.06目录,执行下列命令:

cp drivers/mtd/nand/s3c2410_nand.c drivers/mtd/nand/s3c2440_nand.c

打开drivers/mtd/nand/s3c2440_nand.c文件,把该文件内的所有有关“2410”的地方一律改为“2440”。

再打开drivers/mtd/nand/Makefile文件

第48行“COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o”改为

48:COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

 

编译u-boot,把编译生成的新的u-boot.bin烧写到NorFlash中。开发板上电启动后,则在超级终端(或类似的软件)中显示的结果为:

 

U-Boot 2011.06 (Jul 30 2011 - 23:40:44)

 

DRAM: 64 MiB

Flash: 2 MiB

NAND: raise: Signal # 8 caught

raise: Signal # 8 caught

raise: Signal # 8 caught

raise: Signal # 8 caught

raise: Signal # 8 caught

raise: Signal # 8 caught

No NAND device found!!!

0 MiB

*** Warning - bad CRC, using defaultenvironment

 

In:   serial

Out:  serial

Err:  serial

Net:  CS8900-0

gq2440 #

 

从上述显示的内容可以看出本开发板的一些基本的信息,如DRAM为64M,NorFlash为2M,由于我没有设置NandFlash,因此系统没有检测到NandFlash,命令提示符也已经修改为“gq2440 # ”。

 

在提示符下输入flinfo,则会把NorFlash的更详细的信息显示出来:

 

Bank # 1: CFI conformant flash (16 x16)  Size: 2 MB in 35 Sectors

  AMDStandard command set, Manufacturer ID: 0x1C,Device ID: 0x2249

 Erase timeout: 16384 ms, write timeout: 1 ms

 

 Sector Start Addresses:

 00000000   RO   00004000  RO   00006000   RO  00008000   RO   00010000  RO

 

 00020000   RO   00030000  RO   00040000   RO  00050000   RO   00060000  RO

 

 00070000   RO   00080000        00090000        000A0000        000B0000

 

  000C0000        000D0000        000E0000        000F0000        00100000

 

 00110000        00120000        00130000        00140000        00150000

 

 00160000        00170000        00180000        00190000        001A0000

 

 001B0000        001C0000        001D0000        001E0000        001F0000

 3 支持NandFlash读写

我们把drivers/mtd/nand/s3c2410_nand.c文件复制为s3c2440_nand.c文件,并把该文件内的所有有关“2410”的地方一律改为“2440”。这么修改仅仅是能够让系统编译成功,并没有真正实现NandFlash的读写。在这里,我们就来介绍如何让u-boot支持NandFlash的读写。

 

由于s3c2410与s3c2440的NandFlash控制器不一样,因此s3c2440_nand.c文件并不能直接应用,需要进行适当的修改,而主要修改的内容就是s3c2440的相关寄存器。

 

首先重新定义要用到的寄存器,把原文中第27行至第37行之间的宏定义去掉,改为下面的形式:

#define S3C2440_NFCONT_SECCL       (1<<6)

#define S3C2440_NFCONT_MECCL       (1<<5)

#define S3C2440_NFCONT_INITECC     (1<<4)

#define S3C2440_NFCONT_nCE         (1<<1)

#define S3C2440_NFCONT_MODE        (1<<0)

#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

 

然后就是修改s3c2440_hwcontrol函数和board_nand_init函数,其他函数不变。

 

board_nand_init函数主要是用于对NandFlash的初始化,对它修改的内容是对寄存器NFCONF和寄存器NFCONT的修改,如下所示为修改后的board_nand_init函数,其中红色标注的地方为修改的地方:

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

 

      

#ifdefined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)

       tacls = CONFIG_S3C24XX_TACLS;

       twrph0 = CONFIG_S3C24XX_TWRPH0;

       twrph1 = CONFIG_S3C24XX_TWRPH1;

#else

       tacls = 2;

       twrph0 = 3;

       twrph1 = 1;

#endif

 

       cfg = S3C2440_NFCONF_TACLS(tacls - 1);

       cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);

       cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);

       writel(cfg,&nand_reg->nfconf);

      

       cfg = S3C2440_NFCONT_SECCL;

       cfg |= S3C2440_NFCONT_MECCL;

       cfg |= S3C2440_NFCONT_MODE;

       writel(cfg,&nand_reg->nfcont);

 

      

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

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

 

       nand->select_chip = NULL;

 

      

      

#ifdefCONFIG_NAND_SPL

       nand->read_buf = nand_read_buf;

#endif

 

      

       nand->cmd_ctrl = s3c2440_hwcontrol;

 

       nand->dev_ready = s3c2440_dev_ready;

 

#ifdefCONFIG_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 ofnand_init\n");

 

       return 0;

}

 

最后修改s3c2440_hwcontrol函数,该函数是用于对NandFlash的写命令和写地址操作:

static void s3c2440_hwcontrol(structmtd_info *mtd, int cmd, unsigned int ctrl)

{

       struct nand_chip *chip =mtd->priv;

       struct s3c2440_nand *nand = s3c2440_get_base_nand();

      

       debugX(1,"hwcontrol(): 0xx 0xx\n", cmd, ctrl);

 

       if (ctrl &NAND_CTRL_CHANGE) {

              ulong 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(cmd ==NAND_CMD_NONE)

                     IO_ADDR_W = &nand->nfdata;

 

              chip->IO_ADDR_W= (void *)IO_ADDR_W;

 

              if (ctrl &NAND_NCE)

                     writel(readl(&nand->nfconf)& ~S3C2440_NFCONT_nCE,

                            &nand->nfconf);

              else

                     writel(readl(&nand->nfconf)| S3C2440_NFCONT_nCE,

                            &nand->nfconf);

       }

 

       if (cmd !=NAND_CMD_NONE)

              writeb(cmd, chip->IO_ADDR_W);

}

在这个函数中,除了修改寄存器的值以及设置写命令和写地址的IO端口外,我们还增加了if(cmd == NAND_CMD_NONE)判断语句。如果不加这个判断语句,向NandFlash内写数据是写不进去的,尽管系统不会提示任何错误,并显示“OK”,但其实数据是没有被写入的,因此一定要加上这条语句。这是因为在写完命令和地址后,一定还要把IO端口的地址重新设置为寄存器NFDATA。

 

需要说明的是,由于系统没有定义CONFIG_S3C2410_NAND_HWECC,因此我们暂时先不对s3c2440_nand_enable_hwecc函数、s3c2440_nand_calculate_ecc函数和s3c2440_nand_correct_data函数进行修改。

 

我们把编译好的u-boot.bin文件烧写到norflash中,利用NandFlash的相关命令进行验证:

U-Boot2011.06 (Aug 10 2011 - 23:16:25)

 

DRAM:  64 MiB

Flash: 2MiB

NAND:  256 MiB

***Warning - bad CRC, using default environment

 

In:    serial

Out:   serial

Err:   serial

Net:   CS8900-0

gq2440# nand info

 

Device 0:nand0, sector size 128 KiB

gq2440# nand device 0

gq2440# nand erase 0x100000 0x300000

 

NANDerase: device 0 offset 0x100000, size 0x300000

Erasingat 0x3e0000 -- 100% complete.

OK

gq2440# nand write 0 0x100000 0x300000

 

NANDwrite: device 0 offset 0x100000, size 0x300000

 3145728 bytes written: OK

gq2440# nand read 0x30004000 0x100000 0x300000

 

NANDread: device 0 offset 0x100000, size 0x300000

 3145728 bytes read: OK

gq2440# md.b 0

00000000:13 00 00 ea 14 f0 9f e5 14 f0 9fe5 14 f0 9f e5   ................

00000010:14 f0 9f e5 14 f0 9fe5 14 f0 9f e5 14 f0 9fe5    ................

00000020:e0 01 00 00 40 02 00 00 a0 0200 00 00 03 00 00    ....@...........

00000030:60 03 00 00 c0 03 00 00 20 04 0000 ef be ad de    `....... .......

gq2440# md.b 0x30004000

30004000:13 00 00 ea 14 f0 9f e5 14 f0 9fe5 14 f0 9f e5   ................

30004010:14 f0 9f e5 14 f0 9fe5 14 f0 9f e5 14 f0 9fe5    ................

30004020:e0 01 00 00 40 02 00 00 a0 0200 00 00 03 00 00    ....@...........

30004030:60 03 00 00 c0 03 00 00 20 04 0000 ef be ad de    `....... .......

上电以后NAND显示为256MiB,说明系统能够正确识别出NandFlash。然后我们把SDRAM中的数据写入到NandFlash中,再读取NandFlash中的这段数据,通过与原SDRAM的数据做比较,可以看出这两段数据的内容是一致的,因此我们能够断定移植的u-boot可以对NandFlash进行正确的读和写操作。

 

另外,如果你想更详细地了解开发板上NandFlash的情况,可以把drivers/mtd/nand/nand_base.c文件中第2676行中的MTDDEBUG改为printf,再把该行的MTD_DEBUG_LEVEL0,去掉,则在上电后,会显示如下内容:

U-Boot2011.06 (Aug 10 2011 - 23:55:48)

 

DRAM:  64 MiB

Flash: 2MiB

NAND:  NAND device: ManufacturerID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)

256 MiB

***Warning - bad CRC, using default environment

 

In:    serial

Out:   serial

Err:   serial

Net:   CS8900-0

4 解决raise: Signal # 8 caught

其实把这个bug去掉也很简单,就是把time.c(在arch/arm/arm920t/s3c24x0目录下)这个文件中的四个全局变量用gd这个数据结构中的4个相关成员代替就可以了,具体的就是:

timer_load_val用gd->timer_rate_hz替代;

timer_clk用gd->tbl替代;

timestamp用gd->timer_reset_value替代;

lastdec用gd->lastinc替代。

 

下面我们就列出time.c这个文件具体需要修改的地方:

 

去掉第38行和第39行关于timer_load_val和timer_clk这两个变量的声明,并加上下面代码:

38:DECLARE_GLOBAL_DATA_PTR;

 

去掉第49行和第50行关于timestamp和lastdec这两个变量的声明;

 

去掉第60行至第68行语句(if (timer_load_val == 0)的判断内容),改为:

60:gd->timer_rate_hz = get_PCLK() /(2*16*100);

61:gd->tbl = get_PCLK() / (2 * 16);

 

剩下需要修改的内容就是具体的变量替换,其中每条语句前面的行号为源文件的行号:

70:gd->lastinc = gd->timer_rate_hz;

71:writel(gd->timer_rate_hz,&timers->tcntb4);

78:gd->timer_reset_value = 0;

99:gd->timer_reset_value = t;

108:tmo *= (gd->timer_rate_hz * 100);

118:gd->lastinc = READ_TIMER();

119:gd->timer_reset_value = 0;

126:return tmr / (gd->tbl / CONFIG_SYS_HZ);

137:tmo *= (gd->timer_rate_hz * 100);

140:tmo = usec * (gd->timer_rate_hz * 100);

160:if (gd->lastinc >= now) {

162:gd->timer_reset_value += gd->lastinc -now;

165:gd->timer_reset_value += gd->lastinc + gd->timer_rate_hz- now;

167:gd->lastinc = now;

169:return gd->timer_reset_value;

181:tbclk = gd->timer_rate_hz * 100;

 

通过上述的修改,我们再上电启动后,就不会再有raise: Signal # 8 caught了。

5 硬件ECC

,我们很好地完成了u-boot对NandFlash的读写,但这个读写进行的是软件ECC,即用软件编程的方法实现ECC。我们知道S3C2440的NandFlash控制器是支持硬件ECC的,因此在这里我们就来讲解如何实现硬件ECC。

 

NandFlash的每一页分为main区和spare区,S3C2440的NandFlash控制器支持这两个区的硬件ECC,但为了兼容u-boot-2011.06,我们只实现main区的硬件ECC。

 

为了实现硬件ECC,首先需要在include/configs/gq2440.h文件内定义宏CONFIG_S3C2440_NAND_HWECC,这样在drivers/mtd/nand/s3c2440_nand.c文件内就定义了硬件ECC所需要的三个函数:s3c2440_nand_enable_hwecc函数、s3c2440_nand_calculate_ecc函数和s3c2440_nand_correct_data函数,而且在board_nand_init函数内,又把这三个函数分别赋给了相对应的结构体的三个成员,这样在进行NandFlash读写时,就会调用这三个函数,从而实现了硬件ECC。s3c2440_nand_enable_hwecc函数负责使能硬件ECC,s3c2440_nand_calculate_ecc函数负责计算ECC(当然这种计算是由硬件来完成的),s3c2440_nand_correct_data函数负责进行ECC的校验(同样地,这种校验也是由硬件自动完成的)。

 

为了理解u-boot是如何进行硬件ECC的,我们先来简要地分析一下相关的函数。NandFlash是以页为最小单位进行读写操作的,支持硬件ECC的读操作最终是由nand_read_page_hwecc函数(在drivers/mtd/nand目录下)来完成的,支持硬件ECC的写操作最终是由nand_write_page_hwecc函数(在drivers/mtd/nand目录下)来完成的。nand_read_page_hwecc函数的流程为先读取main区数据,同时通过调用s3c2440_nand_calculate_ecc函数来得到硬件ECC;再读取spare区数据;然后提取出储存在spare区内的main区ECC;最后通过调用s3c2440_nand_correct_data函数来对刚刚读取的main区数据进行校验。nand_write_page_hwecc函数的流程比较简单,它先写入main区数据,同时通过调用s3c2440_nand_calculate_ecc函数来得到硬件ECC;然后就是把硬件ECC写入到spare区内。

 

无论是nand_write_page_hwecc函数,还是nand_write_page_hwecc函数,内部都有一个这样的for循环体:

for(i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {

……  ……

}

其中三个主要变量的定义为:

eccsize= chip->ecc.size;

eccbytes= chip->ecc.bytes;

eccsteps= chip->ecc.steps;

下面我们就来介绍一下这个循环的作用:不同的CPU的NandFlash控制器一次所能完成的硬件ECC的字节数是不一样的,例如有些CPU一次只能完成512字节的硬件ECC,但如果开发板上的NandFlash每页有2048个字节,那该怎么办呢?这时就要用到一个循环体,通过循环多次来得到一页的硬件ECC。例如上面这种情况,就要循环4次(2048÷512=4),才能得到这个页内数据完整的硬件ECC。另外每一次硬件ECC,不同的CPU所生成的ECC字节数也是不同的,有的是3个字节,有的是4个字节。

那么,上面那三个变量的含义就分别为:

ecc.size:每一次硬件ECC所检验的字节个数

ecc.bytes:每一次硬件ECC所生成的字节个数

ecc.steps:每一页需要进行硬件ECC的次数

对于S3C2440来说,一次硬件ECC可以检验2048个字节,并且生成4个字节的ECC,因此ecc.size应该为2048,ecc.bytes应该为4。而ecc.steps是通过计算得到的,即系统上电后能够获知NandFlash的每页的大小,用这个值除以ecc.size就等于ecc.steps。所以对于这三个参数,只需事先定义好前两个参数即可。而这两个参数是在drivers/mtd/nand/s3c2440_nand.c文件中的board_nand_init函数内被定义赋值的,即:

nand->ecc.size = 2048;

nand->ecc.bytes = 4;

 

u-boot-2011.06对S3C2440的NandFlash控制器的寄存器定义得不完整,而且有错误,因此我们还需要对此进行修改。删除arch/arm/include/asm/arch-s3c24x0/s3c24x0.h文件内的第167行至第178行内容,添加进下面的内容:

struct s3c2440_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;

};

 

最后,我们对s3c2440_nand_enable_hwecc函数、s3c2440_nand_calculate_ecc函数和s3c2440_nand_correct_data函数进行修改。

 

void s3c2440_nand_enable_hwecc(structmtd_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& ~S3C2440_NFCONT_MECCL,&nand->nfcont);

}

该函数的任务就是初始化ECC(即复位ECC),并解锁main区ECC。

 

static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, constu_char *dat,

                                  u_char *ecc_code)

{

       struct  s3c2440_nand *nand = s3c2440_get_base_nand();

       u32  mecc0;

 

       writel(readl(&nand->nfcont)| S3C2440_NFCONT_MECCL,&nand->nfcont);

 

       mecc0= readl(&nand->nfmecc0);

       ecc_code[0]= mecc0 & 0xff;

       ecc_code[1] = (mecc0 >> 8) &0xff;

       ecc_code[2] = (mecc0 >> 16) &0xff;

       ecc_code[3] =(mecc0 >> 24) & 0xff;

      

       debugX(1,"s3c2440_nand_calculate_hwecc(%p,):0xx 0xx 0xx 0xx\n",

         mtd , ecc_code[0], ecc_code[1], ecc_code[2], ecc_code[3]);

 

       return 0;

}

该函数首先锁定main区ECC,然后读取寄存器NFMECC0,该寄存器存放着由硬件生成的main区ECC,最后把4个1字节的ECC存放到ecc_code数组内。

 

 

static int s3c2440_nand_correct_data(struct mtd_info *mtd, u_char*dat,

                                 u_char *read_ecc, u_char *calc_ecc)

{

       struct  s3c2440_nand *nand = s3c2440_get_base_nand();

       u32  meccdata0, meccdata1, estat0, err_byte_addr;

       int  ret = -1;

       u8  repaired;

 

       meccdata0= (read_ecc[1] << 16) | read_ecc[0];

       meccdata1= (read_ecc[3] << 16) | read_ecc[2];

       writel(meccdata0,&nand->nfmeccd0);

       writel(meccdata1,&nand->nfmeccd1);

 

      

       estat0= readl(&nand->nfestat0);  

 

       switch(estat0 & 0x3) {

       case  0:

              ret= 0;

              break;

 

       case  1:

             

              err_byte_addr= (estat0 >> 7) & 0x7ff;

              repaired= dat[err_byte_addr] ^ (1 << ((estat0 >> 4) & 0x7));

 

              printf("S3C NAND: 1 bit error detected at byte%ld. "

                     "Correcting from 0xx to0xx...OK\n",

                     err_byte_addr, dat[err_byte_addr],repaired);

 

              dat[err_byte_addr]= repaired;

 

              ret= 1;

              break;

 

       case  2:

       case  3:

              printf("S3C NAND: ECC uncorrectable errordetected. "

                     "Not correctable.\n");

              ret= -1;

              break;

       }

 

       return   ret;

}

该函数首先把read_ecc数组内的ECC存入寄存器NFMECCD0和寄存器NFMECCD1中,这样系统就会自动校验数据,并把状态放入寄存器NFESTAT0中,然后读取该寄存器的后4位,当为0时表示校验正确;当为1时表示发生了1位错误(该类错误可以校正),我们把它校正过来;当为2和3时表示发生其他类型的错误,这类错误是无法校正的。

 

通过以上内容的修改,我们就实现了NandFlash的硬件ECC。

 

ECC足以保证所读数据的正确性,并在有些情况下还可以修正错误,但它不能保证所写数据的正确性。为了保证所写数据的正确性,u-boot还可以通过在include/configs/gq2440.h文件内定义宏CONFIG_MTD_NAND_VERIFY_WRITE来实现把所写的数据再读取一遍,然后与被写入的数据之间进行比较来判断所写数据的正确性,这一过程是在drivers/mtd/nand/nand_base.c文件的nand_write_page函数内调用实现的。

6 DM9000移植

 实现了UBOOT中关于DM9000的部分,当然都是拿来主意,对于网卡我是相当陌生的。

首先,在include/configs/fl2440.h中去掉原先CS8900网卡的定义,再定义各种关于DM9000网卡的宏:  

  1. /*#define CONFIG_CS8900*/               /* we have a CS8900 on-board */  
  2. /*#define CONFIG_CS8900_BASE    0x19000300 */  
  3. /*#define CONFIG_CS8900_BUS16*/ /* the Linux driver does accesses as shorts */  
  4. #define CONFIG_DRIVER_DM9000 1   
  5. #define CONFIG_DM9000_BASE 0x20000300   
  6. #define DM9000_IO CONFIG_DM9000_BASE   
  7. #define DM9000_DATA (CONFIG_DM9000_BASE+4) /* the cmd pin is addr2*/   
  8. #define CONFIG_ETHADDR a8:00:3E:26:0A:5B   
  9. #define CONFIG_NETMASK 255.255.255.0   
  10. #define CONFIG_IPADDR 192.168.1.11   
  11. #define CONFIG_SERVERIP 192.168.1.234   
  12. #define CONFIG_NET_MULTI   
  13.   
  14. /* 
  15. #define CONFIG_NETMASK          255.255.255.0 
  16. #define CONFIG_IPADDR           10.0.0.110 
  17. #define CONFIG_SERVERIP         10.0.0.1 
  18. */  

   DM9000在FL2440的硬件连接原理图:

 

    图中可以看出DM9000连接到NGCS4,看下地址空间可以知道NGCS4的基址是0x20000000,所以网卡基址是0x20000300,后面这个300据他们说是DM9000内部寄存器是这样定义的,就现实来说我的网卡在这个基址上工作良好,所以应该是对的。

    CMD连接的是ADDR2,查DM9000手册上CMD为1时发送的是数据信息,所以,DM9000的数据地址是0x20000304,这个很容易理解。

    修改fl2440.c中的board_eth_init函数:

  1. #ifdef CONFIG_CMD_NET   
  2. int board_eth_init(bd_t *bis)  
  3. {  
  4.         return dm9000_initialize(bis);  
  5. }  
  6. #endif  

    修改drivers/net/dm9000x.c,将下面这段注释掉,至于原因,我也不清楚,不管。

 
  1. i = 0;  
  2. while (!(dm9000_phy_read(1) & 0x20)) {  /* autonegation complete bit */  
  3.         udelay(1000);  
  4.         i++;  
  5.         if (i == 10000) {  
  6.                 printf("could not establish link\n");  
  7.                 return 0;  
  8.         }  
  9. }  
  10.   
  11. /* see what we've got */  
  12. lnk = dm9000_phy_read(17) >> 12;  
  13. printf("operating at ");  
  14. switch (lnk) {  
  15. case 1:  
  16.         printf("10M half duplex ");  
  17.         break;  
  18. case 2:  
  19.         printf("10M full duplex ");  
  20.         break;  
  21. case 4:  
  22.         printf("100M half duplex ");  
  23.         break;  
  24. case 8:  
  25.         printf("100M full duplex ");  
  26.         break;  
  27. default:  
  28.         printf("unknown: %d ", lnk);  
  29.         break;  
  30. }  
  31. printf("mode\n");  

    注释这个函数中的内容,不然网卡会自动断开:

 

 

 
  1. static void dm9000_halt(struct eth_device *netdev)  
  2. {  
  3. #if 0   
  4.         DM9000_DBG("%s\n", __func__);  
  5.   
  6.         /* RESET devie */  
  7.         dm9000_phy_write(0, 0x8000);    /* PHY RESET */  
  8.         DM9000_iow(DM9000_GPR, 0x01);   /* Power-Down PHY */  
  9.         DM9000_iow(DM9000_IMR, 0x80);   /* Disable all interrupt */  
  10.         DM9000_iow(DM9000_RCR, 0x00);   /* Disable RX */  
  11. #endif   
  12. }  

    编译好后,网卡就起来了。

7  修改机器码

  u-boot-2011.06\board\samsung\gq2440\gq2440.c 

 /* arch number of SMDK2410-Board */
 gd->bd->bi_arch_number = 1999;

 /* adress of boot parameters */
 gd->bd->bi_boot_params = 0x30000100;

 完成!

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3