资讯详情

u-boot-1.2.0移植到s3c2440(一)主要是对NAND和NOR的支持

1.因为源中没有smdk2440配置,参考smdk2410,添加smdk2440

a.cp /board/smdk2410 /board/smdk2440 -rf

b.cp include/configs/ smdk2410.h include/configs/ smdk2440.h

c观察2410的编译。

makesmdk2410_config // 配置2410开发板信息

那思考,smdk2410_config设置在哪里?

(1)使用命令:grep “smdk2410_config” * -nR

(2)搜索结果:Makefile:1922:smdk2410_config :unconfig

(3)vim Makefile

在1924行看到以下信息:

smdk2410_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920tsmdk2410 NULL s3c24x0

(4)模仿(注意它们之间的空白行TAB或空格,否则编译报错)

smdk2440_config: unconfig

@$(MKCONFIG)$(@:_config=) arm arm920t smdk2440 NULL s3c24x0

现在,命令可以用来编译

makesmdk2440_config

make

下载使用命令:

进入前烧写u-boot中,按“q进入命令行,

1.usb 130000000

2.使用DNW下载

3.nand erase 0 20000

4.nand write 30000000 0 20000

5.拨开关到NAND启动

没有打印信息。编译不成功。开始修改代码

2.因为串口没有打印任何信息,读取代码,发现问题

(1)、阅读start.S添加其中的代码CONFIG_S3C2410替换成CONFIG_S3C2440,还得同时smdk2440.h中添加#defined(CONFIG_S3C2440) 1

如果你想更好地支持程序,你可以这样做:

#if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2410)

(2)对于这些初始作基本没有问题。

(3)、在lowlevel_init.S的SDRAM需要修改的设置

编译程序,烧写到开发板,串口工具上看不到任何信息。

现在只有重新检查程序。

推荐检查方法:

使用arm-linux-objdump -D u-boot> u-boot.dis

查看u-boot.dis文件,

可知_start = _armboot_start = TEXT_BASE = 0x33f80000

start_armboot= 0x33f80b4c

_bss_start= 0x33f961f8

_bss_end = 0x33f9a91c

可以根据这些信息了解程序的内存分布

由于目前程序连串信息无法输出,请找到相应的函数并查看。

start_armboot

init_sequence

board_init

可以看看到程序在这里设置时钟,用于串口。但在此之前,需要使用时钟。因此,将时钟设置放在这里start.S中,代替start.S分频系数 设置处board_init()中:

clk_power->LOCKTIME= 0xFFFFFF;

clk_power->MPLLCON = ((M_MDIV<< 12) (M_PDIV << 4) M_SDIV);

注释,现在重新编译烧写,在开发板下打印乱码。

虽然是乱码,但终于打印出来了,下面应该修改串口的设置。

3.修改串口信息的设置,使正常输出

一次检查init_sequence中的函数。serial_init与串口有关。

serial_init (cpu/arm920t/s3c24x/serial.c)

serial_setbrg

reg= get_PCLK() / (16 * gd->baudrate) - 1;// 设置波特率

get_PCLK

get_HCLK

&nbp;                       get_FCLK

                                                get_PLLCLK

检查其中的代码,发现不管是MPLL还是UPLL,最后的返回值都是:

           return((CONFIG_SYS_CLK_FREQ * m) / (p << s));

这个设置对于JZ_2440来说肯定是不对的。

修改:    

if (pllreg == MPLL)

{

           r = clk_power->MPLLCON;

           m = ((r & 0xFF000) >> 12) +8; // MPLLCON[19:12]

    p =((r & 0x003F0) >> 4) + 2;    //MPLLCON[9:4]

    s = r& 0x3;                                            //MPLLCON[1:0]

   return ((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));

}

    else if (pllreg == UPLL)

    {

           r = clk_power->UPLLCON;

           m = ((r & 0xFF000) >> 12) +8; // MPLLCON[19:12]

    p =((r & 0x003F0) >> 4) + 2;    //MPLLCON[9:4]

    s = r& 0x3;                                            //MPLLCON[1:0]

   return ((CONFIG_SYS_CLK_FREQ * m) / (p << s));

         }

这个代码一点也不简洁,但是现在先实现功能,到最后再来修改。

现在重新编译,打印如下结果:

U-Boot 1.2.0 (Aug  5 2013 - 15:13:39)

 

DRAM:  64 MB

Flash:512 kB

***Warning - bad CRC, using default environment

 

In:    serial

Out:   serial

Err:   serial

SMDK2410 #

可见修改成功。但是查看上面的打印信息,很明显“Flash:512kb”的信息不符合实际,因为我们的NOR Flash是有2MB的。于是下面就要来更改NOR。

 

4.      支持NOR Flash

根据上面的错误信息,使用命令“grep "Flash:" * -nR”,其中一条如下:

lib_arm/board.c:183:    puts ("Flash: ");

         找到函数display_flash_config(),查看它在哪儿被调用。

根据打印信息可以看到应该是在start_armboot中被调用的,因为它紧接在“DRAM” 的打印信息之后,而“DRAM:  64MB”在display_dram_config()函数中被打印。一定要看源代码,不然就云里雾里了。

在函数display_flash_config(size);其中的size是flash_init ()的返回值,所以追本溯源,到flash_init ()函数里查看。

drivers /cfi_flash.c

         flash_init

                   size += flash_info[i].size =flash_get_size (bank_base[i], i);

                   flash_get_size()      

                           flash_detect_cfi()

在这些函数中,可以看到有很多的打印信息,但是为什么没有被打印出来呢?是不是有某些变量开关呢?仔细预读源代码。找出原因。一路追究下去原来是要定义DEBUG变量

         #define DEBUG        // 就添加在cfi_flash.c中吧

编译运行,还是打印。重新检查代码,发现在cfi_flash.c的开头还定义了一个变量总开关CFG_FLASH_CFI_DRIVER,所以将这个变量在smdk2440.h中声明:       #defineCFG_FLASH_CFI_DRIVER

现在就能打印信息了。(注意,DEBUG应该声明在“#include<common.h>”语句之前,也就是cfi_flash.c文件最开头)

分析打印的结果:

                  ……

              Flash:  0 kB

              ……

修改smdk2440,去掉CONFIG_AMD_LV400

              #defineCONFIG_AMD_LV800                   1

         重新编译:

              Flash:  2 MB

         如果先打印信息太多,可以将刚才定义的DEBUG变量删去。

 

NOR  Flash

A0-A19:地址输入

Q0-Q14:数据的输入/输出

Q15/A-1:Q15(Word mode)/LSB addr(Byte mode)

CE#:片选信号

WE#:写信号

BYTE#:Word/Byte选择

Reset#:硬件复位引脚/段保护解

OE#:输出信号

RY/BY#:准备好/忙

WP/ACC#:写保护/加速引脚

注意:如果没有使用WP/ACC#引脚,那就将这个引脚连接到VCC或是悬空,WP/ACC#内部有个上拉电阻,当没有链接引脚WP/ACC#的时候处于Vih。

 

5.      添加对NAND Flash的支持

在lib_arm/board.c中找到puts ("NAND:  ");

可见要想支持NAND的先定义变量CFG_CMD_NAND,所以在smdk2440.h中将CFG_CMD_NAND的注释去掉。

编译不通过,因为NAND根本就没有被初始化。

         在board.c中和nand相关的函数就是nand_init()。

         nand_init()

                   nand_chip_init()

board_nand_init();            // 这是nand初始化的函数,但是在u-boot-1.2.0中没

// 有实现,所以编译会在这儿出错

                   nand_scan()     // 这个函数就是识别出我们开发板里的nand的。

         要想NAND能用起来,就先得把初始化的工作完成。

        

// 这个函数在源中是没有的,自己实现,参照u-boot-2012-04-01

int board_nand_init(struct nand_chip *nand)

{

         u_int8_ttacls, twrph0, twrph1;

         S3C2440_NAND* const s3c_nand = S3C2440_GetBase_NAND();

 

         puts("board_nand_init()\n");

         /*initialize hardware */

         tacls= 0;

         twrph0= 1;

         twrph1= 0;

        

         //+1 my901001106@163.com        2013-8-414:07:48   初始化

         s3c_nand->NFCONF=(tacls<<12) | (twrph0<<8) | (twrph1<<4);

 

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

         s3c_nand->NFCONT= (1<<4)|(0<<1)|(1<<0);  // 这儿的片选一定选中,不然死得很惨

        

         /*initialize nand_chip data structure */

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

         nand->IO_ADDR_W= (void *)&s3c_nand->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

 

         nand->eccmode       = NAND_ECC_SOFT;

 

         /*hwcontrol always must be implemented */

         nand->hwcontrol= s3c2440_hwcontrol;         // 自定义,用于片选,ALE、CLE的

 

         nand->dev_ready= s3c2440_dev_ready;        // 自定义,

 

#ifdef CONFIG_S3C2440_NAND_BBT

         nand->options= NAND_USE_FLASH_BBT;

#else

         nand->options= 0;

#endif

 

         return0;

}

        

// 这个函数写得有点臭了,可以阅读代码再重新修改

static void s3c2440_hwcontrol(structmtd_info *mtd, unsigned int dat)

{

         S3C2440_NAND* const s3c_nand = S3C2440_GetBase_NAND();

         structnand_chip *this = mtd->priv;

 

         switch(dat) {

         caseNAND_CTL_SETCLE:

                   this->IO_ADDR_W= (void *)&s3c_nand->NFCMD;

                   break;

                  

         caseNAND_CTL_CLRCLE:

                   this->IO_ADDR_W= (void *)&s3c_nand->NFDATA;

                   break;

                  

         caseNAND_CTL_SETALE:

                   this->IO_ADDR_W= (void *)&s3c_nand->NFADDR;

                   break;

                  

         caseNAND_CTL_CLRALE:

                   this->IO_ADDR_W= (void *)&s3c_nand->NFDATA;

                   break;

                  

         caseNAND_CTL_SETNCE:

                   s3c_nand->NFCONF&= ~(1<<1);

                   break;

         caseNAND_CTL_CLRNCE:

                   s3c_nand->NFCONF|= (1<<1);                 

                   break;

         default:

                   puts("error!\n");

                   break;

         }

}

 

static int s3c2440_dev_ready(structmtd_info *mtd)

{

         S3C2440_NAND* const s3c_nand = S3C2440_GetBase_NAND();

         //puts("dev_ready\n");

         return(s3c_nand->NFSTAT & 0x01);

}

韦东山的JZ_2440:

         nand_flash_ids[37]=      {"NAND 256MiB 3,3V8-bit",           0xDA, 0, 256, 0,NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}

 

6.      让u-boot在NAND Flash中也能启动

在start.S中有这样一段代码:

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

adr   r0,_start          /* r0 <- currentposition of code   */

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

cmp    r0, r1          // 比较链接地址和代码的起始位置是否相等

beq    stack_setup

 

ldr    r2,_armboot_start // 0x33f80000

ldr    r3,_bss_start           // 0x33f961f8

sub   r2,r3, r2           /* r2 <- size ofarmboot            */

add  r2,r0, r2           /* r2 <- source endaddress         */

 

copy_loop:

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

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

cmp r0, r2                           /* until source endaddreee [r2]    */

         ble    copy_loop

很明显,这段代码只能支持在NOR Flash的启动。现在,我们就得注释掉这段代码,重新写这段重定位的代码。用下面这段代码代替

// 重定位

adr r0, _start            //_start的实际运行地址

ldr r1, _TEXT_BASE // 0x33f80000 

cmp r0, r1

beq  clear_bss

ldr r2, _armboot_start            

ldr    r3,_bss_start           // 0x33fa11fc

sub   r2,r3, r2           /* r2 <- size ofarmboot */

         bl copyCodeToSDRAM

在这儿我们调用了C函数copyCodeToSDRAM,所以,在这段代码之前还得重新设置栈。即把上面这段代码紧跟在stack_setup之后即可。

下面就是跳转到copyCodeToSDRAM函数的实现。

因为我们的开发板有两个启动模式,一种是NOR,另一种是NAND,那怎么区分?

记住NOR Flash有一个重要的特性,它能像内存一样的执行,但是不能像内存一样的读写。所以我们可以尝试在0地址写入一个数,然后再读出来,如果值没有发生改变,那就是NOR启动方式,若发生改变就是NAND启动方式。注意:先要保存这个0地址的值然后再写入,假如是NAND方式的话,我们还要用这个保存的值恢复0地址。不然程序就会跑飞了。

ntisBootFromNOR(void)

{

volatile unsigned int *p = (volatile unsignedint *)0x0;

unsigned int tmp;

 

tmp = *p;

*p = 0x12345678;

if(*p == 0x12345678)

{

           *p = tmp;

           return 0;

}

return 1;

         另外还要实现NAND的读函数。看过东山哥视频的都知道怎么写。

         就是有点要注意。其中的NFDATA、NFCMD等是8位的。定义的时候不要写顺手了写成:

#define NFCMD                (*(volatile unsigned long*)0x4E000008)

#define NFADDR              (*(volatile unsigned long*)0x4E00000C)

这样你会死得很惨,怎么调试都觉得程序没有错误,可是就是读不出来数据。所以还是把那个long改成char吧!

 

 

编译中遇到的错误:

1.      error: unterminated #if

缺少一个#endif结尾,它们成对出现

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

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

这个问题由于我是用的是gcc 4.3.x,版本太高了。换成gcc3.4.5编译OK

         

标签: 电阻bss79ce6327

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台