1,主机环境:VMare下CentOS 5.5 ,1G内存。
2,集成开发环境:Elipse IDE
3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。
4,开发板:mini2440,2M nor flash,128M nand flash。
5,u-boot版本:u-boot-2009.08
6,参考文章:
http://blogold.chinaunix.net/u3/101649/showart.php?id=2105215
http://blog.chinaunix.net/space.php?uid=23787856&do=blog&id=115382
http://blogimg.chinaunix.net/blog/upfile2/100811115954.pdf
通常,在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动。u-boot中默认是从Nor Flash启动,再从上一节测试运行的结果的中看,还发现几个问题:第一,我开发板的Nor Flash是2M的,而这里显示的是512kB;第二,出现Warning - bad CRC, using default environment的警告信息。不是u-boot默认是从Nor Flash启动的吗?为什么会有这些错误信息呢?这是因为我们还没有添加对我们自己的Nor Flash的支持,u-boot默认的是其他型号的Nor Flash,而我们的Nor Flash的型号是SST39VF1601。另外怎样将命令行提示符前面的SMDK2410变成我自己定义的呢?下面我们一一来解决这些问题。
2.1,修改u-boot源码,使其完全支持Nor Flash。
【1】添加对我们mini2440开发板上2M的Nor Flash(型号为SST39VF1601)的支持
在虽然 S3C2440 和S3C2410 对于Nor Flash 的链接都是一样的,但是SBC2410 使用的AMD 的Nor Flash 芯片,而mini2440 使用的SST 的Nor Flash。这两款芯片在写入时所使用的块大小、时序和指令代码有差别,所以必须根据芯片的数据手册进行修改。主要的差别请看数据手册的对比:
SST39VF1601:
Am29LV160:
在u-boot中对Nor Flash的操作分别有初始化、擦除和写入,所以我们主要修改与硬件密切相关的三个函数flash_init、flash_erase、write_hword。
用gedit打开board/samsung/mini2440/flash.c,定位到31行附近,修改如下:
#define FLASH_BANK_SIZE PHYS_FLASH_SIZE
//#define MAIN_SECT_SIZE 0x10000 /* 64 KB */
#define MAIN_SECT_SIZE 0x1000 //定义为4k,刚好是一个扇区的大小
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
NorFlash硬件连接
有原理图可知,一般NorFlash放在Bank0.所以CONFIG_SYS_BASE=0,但是开启mmu后baseaddr=地址0映射到的新地址。0x555<<1的原因是LADDR1与A0连接。也就是0x555表示片内第0x555个word(16bit)。
#define CMD_UNLOCK_BYPASS 0x00000020
#if defined(CONFIG_SST_VF1601)
#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000005555 << 1)))
#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AAA << 1)))
#else
#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1)))
#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1)))
#endif
#define BIT_ERASE_DONE 0x00000080
在flash_init 函数中修改或添加后代码如下:
ulong flash_init (void)
{
int i, j;
ulong size = 0;
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
ulong flashbase = 0;
... ...
#elif defined(CONFIG_AMD_LV800)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV800B & FLASH_TYPEMASK);
#elif defined(CONFIG_SST_39VF1601)
(SST_MANUFACT & FLASH_VENDMASK) |
(SST_ID_xF1601 & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
#endif
... ...
for (j = 0; j < flash_info[i].sector_count; j++) {
#ifndef CONFIG_SST_VF1601
if (j <= 3) {
/* 1st one is 16 KB */
... ...
#else
flash_info[i].start[j] =
flashbase + (j) * MAIN_SECT_SIZE;
#endif
}
size += flash_info[i].size;
}
... ...
return size;
}
在flash_print_info 函数中修改或添加后代码如下:
void flash_print_info (flash_info_t * info)
{
int i;
switch (info->flash_id & FLASH_VENDMASK) {
case (AMD_MANUFACT & FLASH_VENDMASK):
printf ("AMD: ");
break;
case (SST_MANUFACT & FLASH_VENDMASK):
printf ("SST: ");
break;
default:
printf ("Unknown Vendor ");
break;
}
switch (info->flash_id & FLASH_TYPEMASK) {
case (AMD_ID_LV400B & FLASH_TYPEMASK):
printf ("1x Amd29LV400BB (4Mbit)\n");
break;
case (AMD_ID_LV800B & FLASH_TYPEMASK):
printf ("1x Amd29LV800BB (8Mbit)\n");
break;
case (SST_ID_xF1601 & FLASH_TYPEMASK):
printf ("1x SST39VF1610 (16Mbit)\n");
break;
default:
printf ("Unknown Chip Type\n");
goto Done;
break;
}
... ...
Done:;
}
在flash_erase函数中修改或添加后代码如下:
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
ushort result;
int iflag, cflag, prot, sect;
int rc = ERR_OK;
int chip;
.... ....
if ((s_first < 0) || (s_first > s_last)) {
return ERR_INVAL;
}
if ((s_first < 0) || (s_first > s_last)) {
return ERR_INVAL;
}
#ifdef CONFIG_SST_VF1601
if ((info->flash_id & FLASH_VENDMASK) !=
(SST_MANUFACT & FLASH_VENDMASK)) {
return ERR_UNKNOWN_FLASH_VENDOR;
}
#else
if ((info->flash_id & FLASH_VENDMASK) !=
(AMD_MANUFACT & FLASH_VENDMASK)) {
return ERR_UNKNOWN_FLASH_VENDOR;
}
#endif
prot = 0;
... ...
if (info->protect[sect] == 0) { /* not protected */
vu_short *addr = (vu_short *) (info->start[sect]);
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
*addr = CMD_ERASE_CONFIRM;
/* wait until flash is ready */
#if 0
chip = 0;
do {
... ...
printf ("ok.\n");
} else { /* it was protected */
printf ("protected!\n");
}
}
#endif
while(1){
unsigned short i;
i = *((volatile unsigned short *)addr) & 0x40;
if(i != (*((volatile unsigned short *)addr) & 0x40))
continue;
if((*((volatile unsigned short *)addr)) & 0x80)
break;
}
printf ("ok.\n");
} else { /* it was protected */
printf ("protected!\n");
}
}
在write_hword函数中修改或添加后代码如下:
tatic int write_hword (flash_info_t * info, ulong dest, ushort data)
{
vu_short *addr = (vu_short *) dest;
ushort result;
int rc = ERR_OK;
int cflag, iflag;
int chip;
... ...
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
//MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
MEM_FLASH_ADDR1 = CMD_PROGRAM;
//*addr = CMD_PROGRAM;
*addr = data;
/* arm simple, non interrupt dependent timer */
reset_timer_masked ();
/* wait until flash is ready */
#if 0
chip = 0;
do {
result = *addr;
... ...
} while (!chip);
*addr = CMD_READ_ARRAY;
if (chip == ERR || *addr != data)
rc = ERR_PROG_ERROR;
#endif
while(1){
unsigned short i = *(volatile unsigned short *)addr & 0x40;
if(i != (*(volatile unsigned short *)addr & 0x40)) //D6 == D6
continue;
if((*(volatile unsigned short *)addr & 0x80) == (data & 0x80)){
rc = ERR_OK;
break; //D7 == D7
}
}
if (iflag)
enable_interrupts ();
if (cflag)
icache_enable ();
return rc;
}
修改完后,保存。
【2】修改lowlevel_init.S 文件
为了匹配mini2440 的存储器配置(总线上连接的Nor Flash 和SDRAM),需要修改lowlevel_init.S文件。这个所连接的Nor Flash位数有关。至于SDRAM的参数,可以从芯片手册查到。据说有人将其64MB的内存升到了128MB,其参数就是在这里修改的,有需要可以看MINI2440: Auto probe for SDRAM size 。以下的64MB 内存的参数修改:
打开/board/samsung/mini2440/lowlevel_init.S,定位到123行,修改如下:
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
//#define Trp 0x0 /* 2clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#if defined(CONFIG_S3C2440)
#define Trp 0x2 /* 4clk */
#define REFCNT 1012
#else
#define Trp 0x0 /* 2clk */
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
#endif
/**************************************/
在这个 lowlevel_init.S 有一个小bug,使得无法使用OpenJTAG 下载到内存中直接运行,修正如下:
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
ldr r0, =SMRDATA
//ldr r1, _TEXT_BASE
ldr r1, =lowlevel_init
sub r0, r0, r1
adr r3, lowlevel_init /* r3 <- current position of code */
add r0, r0, r3
ldr r1, =BWSCON /* Bus Width Status Controller */
add r2, r0, #13*4
修改完后,保存。
【3】修改开发板终端中命令行提示符
用gedit打开include/configs/mini2440.h头文件,定位到116行,其中的 "SMDK2410 # " 就是开发板在终端中显示的提示符,现在将其改为 "[u-boot@MINI2440]# " ,如下所示
/*
* Miscellaneous configurable options
*/
#define CONFIG_SYS_LONGHELP /* undef to save memory */
#define CONFIG_SYS_PROMPT "[u-boot@MINI2440]# " /* Monitor Command Prompt */
【4】修改Nor Flash参数的部分定义
然后定位到157行附近,注释掉下面两个类型的Nor Flash设置,因为不是我们所使用的型号,然后加入新的定义,如下所示
/*-----------------------------------------------------------------------
* FLASH and environment organization
*/
#if 0 //注释掉下面两个类型的Nor Flash设置,因为不是我们所使用的型号
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#endif
#define CONFIG_SST_39VF1601 1 //添加mini2440开发板Nor Flash设置
... ...
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */
#define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */
#endif
#ifdef CONFIG_SST_VF1601
#define PHYS_FLASH_SIZE 0x00200000 /* 2MB */
#define CONFIG_SYS_MAX_FLASH_SECT (32) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET) /* addr of environment */
#endif
宏 CFG_ENV_ADDR定义了存放uboot变量的地址,换算一下为1MB-64KB=960KB地方,而实际uboot编译出来的大小仅为120KB 左右,由此可以得出,即使从新烧录了新编译的uboot到Nor flash内,也不会影响先前设定使用的uboot变量。
修改完后,保存。
【5】u-boot编译时间
u-boot的编译时间在/Makefile的384行附近:
$(VERSION_FILE):
@( printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' "$(U_BOOT_VERSION)" \
'$(shell $(TOPDIR)/tools/setlocalversion $(TOPDIR))' ) > [email protected]
@cmp -s $@ [email protected] && rm -f [email protected] || mv -f [email protected] $@
$(TIMESTAMP_FILE):
@date +'#define U_BOOT_DATE "%b %d %C%y"' > $@
@date +'#define U_BOOT_TIME "%T"' >> $@
而显示在终端或者LCD上的版本+编译时间的宏在/lib_arm/board.c的74行附近被引用,
打开/lib_arm/board.c的74行,定位到74行,修改如下:
#ifndef CONFIG_IDENT_STRING
#define CONFIG_IDENT_STRING ""
#endif
/*const char version_string[] = \
U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"CONFIG_IDENT_STRING; */
const char version_string[] = U_BOOT_VERSION;
这样可以屏蔽掉编译时间的显示。
2.2,重新编译,运行测试
[root@localhost u-boot-2009.08]# make clean
Generating include/autoconf.mk
[root@localhost u-boot-2009.08]# make
... ...
arm-linux-objcopy -O srec u-boot u-boot.srec
arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
[root@localhost u-boot-2009.08]#
编译的过程中,出现一个问题,这里把自己改过的地方说明一下,错误处在第四步的修改:
【4】修改Nor Flash参数的部分定义
#define CONFIG_SST_39VF1601 1 //添加mini2440开发板Nor Flash设置
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */
#define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */
#endif
#ifdef CONFIG_SST_VF1601(这里改为CONFIG_SST_39VF1601)
#define PHYS_FLASH_SIZE 0x00200000 /* 2MB */
#define CONFIG_SYS_MAX_FLASH_SECT (32) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET) /* addr of environment */
#endif
这个CONFIG_ENV_OFFSET在我编译的时候是提示未定义的,这里你可以直接改成常量0x070000,仿照上面的
宏 CFG_ENV_ADDR定义了存放uboot变量的地址,换算一下为1MB-64KB=960KB地方,而实际uboot编译出来的大小仅为120KB 左右,由此可以得出,即使从新烧录了新编译的uboot到Nor flash内,也不会影响先前设定使用的uboot变量。
修改完后,保存。
编译完成后,将根目录u-boot-2009.08下的u-boot.bin文件复制到/tftpboot目录下。在与开发板相连的终端中执行如下命令:
##### FriendlyARM BIOS 2.0 for 2440 #####
[x] format NAND FLASH for Linux
[v] Download vivi
[k] Download linux kernel
[y] Download root_yaffs image
[a] Absolute User Application
[n] Download Nboot for WinCE
[l] Download WinCE boot-logo
[w] Download WinCE NK.bin
[d] Download & Run
[z] Download zImage into RAM
[g] Boot linux from RAM
[f] Format the nand flash
[b] Boot the system
[s] Set the boot parameters
[u] Backup NAND Flash to HOST through USB(upload)
[r] Restore NAND Flash from HOST through USB
[q] Goto shell of vivi
Enter your selection: d
Clear the free memory
USB host is connected. Waiting a download.
Now, Downloading [ADDRESS:31000000h,TOTAL:99674]
RECEIVED FILE SIZE: 99674 (97KB/S, 1S)
Downloaded file at 0x30000000, size = 99664 bytes
U-Boot 2009.08 ( 5鏈?05 2011 - 22:39:33)
DRAM: 64 MB
Flash: 2 MB
In: serial
Out: serial
Err: serial
[u-boot@MINI2440]#
从运行结果看,Nor Flash的大小可以正确检测到了,命令行前面的名字也由原来的SMDK2410改成自己定义的[u-boot@MINI2440]# 了,但是有会出现bad CRC的警告信息,其实这并不是什么问题,只是还没有将环境变量设置到Nor Flash中,我们执行一下u-boot的:saveenv命令就可以了。如下所示:
[u-boot@MINI2440]# saveenv
Saving Environment to Flash...
Un-Protected 16 sectors
Erasing Flash...Erasing sector 64 ... ok.
Erasing sector 65 ... ok.
Erasing sector 66 ... ok.
Erasing sector 67 ... ok.
Erasing sector 68 ... ok.
Erasing sector 69 ... ok.
Erasing sector 70 ... ok.
Erasing sector 71 ... ok.
Erasing sector 72 ... ok.
Erasing sector 73 ... ok.
Erasing sector 74 ... ok.
Erasing sector 75 ... ok.
Erasing sector 76 ... ok.
Erasing sector 77 ... ok.
Erasing sector 78 ... ok.
Erasing sector 79 ... ok.
Erased 16 sectors
Writing to Flash... done
Protected 16 sectors
[u-boot@MINI2440]#
因为DRAM运行的是现在的u-boot,其下载命令还未实现,需要给开发板重新上电,再重新下载u-boot.bin到DRAM中运行
Enter your selection: d
Clear the free memory
USB host is connected. Waiting a download.
Now, Downloading [ADDRESS:31000000h,TOTAL:99682]
RECEIVED FILE SIZE: 99682 (97KB/S, 1S)
Downloaded file at 0x30000000, size = 99672 bytes
U-Boot 2009.08 ( 5鏈?05 2011 - 22:50:40)
DRAM: 64 MB
Flash: 2 MB
In: serial
Out: serial
Err: serial
[u-boot@MINI2440]#
可以观察到不会出现警告信息了,这时候u-boot已经对我们开发板上的Nor Flash完全支持了。
接下来将进入u-boot的第三阶段,为u-boot-2009.08增加nand flash支持。
有时间还是深入看一下falsh.c的代码吧!待续。。。。。