移植环境
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
通常,在嵌入式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];
... ...
Nor Flash硬件连接
有原理图可知,一般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 Typen");
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 内存的参数修改: