在mini2440上,nor flash启动和nand flash启动可以满足不同的需要,这里进行移植,nor的启动移植比较简单,因为不需要进行代码的重定向,nand的启动相对复杂,这里先从nor开始,进入正题:
一.修改支持nor flash启动
第一步:修改mini2440.h
在第27行:
#define CONFIG_SYS_TEXT_BASE 0x30008000
这里将这个值改为0x0,因为从nor flash启动,直接在0地址执行就可以,不需要再拷贝到sdram中。修改为:
#define CONFIG_SYS_TEXT_BASE 0x0
之前我的帖子分析的start.s启动过程等等,都是对应的没有做代码重定向,没有从nand启动,因为那时候只在sdram里执行u-boot,在第37行:
//#define CONFIG_SKIP_LOWLEVEL_INIT
将其注释掉,这样程序执行:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
因为我们没有定义CONFIG_SKIP_LOWLEVEL_INIT,所以程序就会跳转到cpu_init_crit里面,在cpu_init_crit里面,程序进一步跳转到
mov ip, lr
bl lowlevel_init
mov lr,ip
进入lowlevel_init以后,就会执行这一段代码:
ldr r0, =SMRDATA
ldr r1,=CONFIG_SYS_TEXT_BASE
sub r0,r0, r1
因为TEXT_BASE现在被我们设置为了0,SMRDATA就会从相对0地址的地方开始,这样我们就可以从nor flash启动。
第二步:修改lowlevel_init.s
第113行:
#define REFCNT 1113
这个REFCNT其实是位宽和刷新频率的设置,这里需要做一个修改,改为如下:
#define REFCNT 0x4f4
第三步:编译测试
这里我编译没有问题,下载进去在执行erase的时候,无法擦除我的nor flash,这可能是我原来的u-boot对nor flash的第一个块进行了保护,即使protectoff all也没用,但是可以擦除别的块,所以这里我借助了j-link来下载我移植的u-boot到nor flash。具体的下载步骤不懂得可以上网查下,下载进去之后启动,输出如下信息:
U-Boot 2014.04 (Sep 02 2015 - 15:09:02)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: 2 MiB
NAND: 256 MiB
*** Warning - bad CRC, using defaultenvironment
In: serial
Out: serial
Err: serial
Net: dm9000
MINI2440 Deep_l_zh #
说明我们是可以从nor启动了,下面进入nand的移植,我们一般nor只是用来调试和学习,所以掌握从nand启动是很重要的。
二.nand flash启动移植
第一步:去除-pie选项
在arch/arm/config.mk中,第82行,修改如下:
# needed for relocation
#LDFLAGS_u-boot += -pie
这里是为了避免重定向后新的地址比较复杂,所以还是采用老的办法进行修改。
第二步:修改mini2440.h
重新将TEXT_BASE制定为0x33f80000
#define CONFIG_SYS_TEXT_BASE 0x33f80000
第三步:添加nand_read_b.c文件并修改makefile
在/board/mini2440/mini2440下,修改Makefile,将其编译进去,修改部分如下:
obj-y :=mini2440.o
obj-y += nand_read_b.o
obj-y +=lowlevel_init.o
接着再该目录下创建nand_read_b.c文件,该文件所有内容如下:
#define NFCONF(*((volatile unsigned long*)0x4E000000))
#define NFCONT(*((volatileunsigned long *)0x4E000004))
#define NFCMMD(*((volatileunsigned char *)0x4E000008))
#define NFADDR(*((volatileunsigned char *)0x4E00000C))
#define NFDATA(*((volatileunsigned char *)0x4E000010))
#define NFSTAT(*((volatileunsigned char *)0x4E000020))
static void nand_read_b(unsignedint addr,unsigned char *buf,unsigned int len);
static intisBootFromNorFlash(void)
{
volatileint *p = (volatile int *)0;
intval;
val= *p;
*p= 0x12345678;
if(*p == 0x12345678)
{
/*写成功, 是 nand 启动 */
*p= val;
return0;
}
else
{
/*NOR 不能像内存一样写 */
return1;
}
}
void nand_init_b(void)
{
#defineTACLS 3
#defineTWRPH0 3
#defineTWRPH1 2
/*设置时序 */
NFCONF= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/*使能 NAND Flash 控制器, 初始化 ECC, 禁止片选 */
NFCONT= (1<<4)|(1<<1)|(1<<0);
}
void copy_code_to_sdram(unsignedchar *src, unsigned char *dest, unsigned int len)
{
int i = 0;
/* 如果是 NOR 启动 */
if(isBootFromNorFlash())
{
while(i < len)
{
dest[i]= src[i];
i++;
}
}
else
{
nand_init_b();
nand_read_b((unsignedint)src, dest, len);
}
}
void clear_bss(void)
{
externint __bss_start, __bss_end;
int*p = &__bss_start;
for(; p < &__bss_end; p++)
*p= 0;
}
static void nand_select(void)
{
NFCONT &= ~(1<<1);
}
static void nand_deselect(void)
{
NFCONT |= (1<<1);
}
static void nand_cmd(unsignedchar cmd)
{
volatileint i;
NFCMMD= cmd;
for(i = 0; i < 10; i++);
}
static void nand_addr(unsignedint addr)
{
unsignedint col = addr % 2048;
unsignedint page = addr / 2048;
volatileint i;
NFADDR= col & 0xff;
for(i = 0; i < 10; i++);
NFADDR= (col >> 8) & 0xff;
for(i = 0; i < 10; i++);
NFADDR= page & 0xff;
for(i = 0; i < 10; i++);
NFADDR= (page >> 8) & 0xff;
for(i = 0; i < 10; i++);
NFADDR= (page >> 16) & 0xff;
for(i = 0; i < 10; i++);
}
static void nand_wait_ready(void)
{
while (!(NFSTAT & 1));
}
static unsigned charnand_data(void)
{
return NFDATA;
}
static void nand_read_b(unsignedint addr, unsigned char *buf, unsigned int len)
{
int col = addr % 2048;
int i = 0;
/* 1. 选中 */
nand_select();
while (i < len)
{
/*2. 发出读命令 00h */
nand_cmd(0x00);
/*3. 发出地址(分 5 步发出) */
nand_addr(addr);
/*4. 发出读命令 30h */
nand_cmd(0x30);
/*5. 判断状态 */
nand_wait_ready();
/*6. 读数据 */
for(; (col < 2048) && (i < len); col++)
{
buf[i]= nand_data();
i++;
addr++;
}
col= 0;
}
/* 7. 取消选中 */
nand_deselect();
}
第四步:修改crt0.S
在arch/arm/lib/crt0.S文件中,修改如下:
ENTRY(_main)
/*
* Set up initial C runtime environment andcall board_init_f(0).
*/
#ifdefined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp,=(CONFIG_SPL_STACK)
#else
ldr sp,=(CONFIG_SYS_INIT_SP_ADDR)
#endif
bic sp,sp, #7 /* 8-byte alignment for ABIcompliance */
sub sp,sp, #GD_SIZE /* allocate one GD aboveSP */
bic sp,sp, #7 /* 8-byte alignment for ABIcompliance */
mov r9,sp /* GD is above SP */
#if 1
__TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
mov r0, #0
ldr r1, __TEXT_BASE
ldr r2, __TEXT_BASE
ldr r3, =__bss_end
sub r2, r3, r2
bl copy_code_to_sdram
bl clear_bss
ldr pc, =call_board_init_f
call_board_init_f:
mov r0, #0
bl board_init_f
ldr sp, [r9, #GD_START_ADDR_SP] /* sp =gd->start_addr_sp */
bic sp, sp, #7 /* 8-byte alignment forABI compliance */
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
subr9, r9, #GD_SIZE /* new GD is below bd*/
ldr r1, __TEXT_BASE
bl board_init_r
#else
mov r0,#0
bl board_init_f
#if !defined(CONFIG_SPL_BUILD)
/*
* Set up intermediate environment (new sp andgd) and call
* relocate_code(addr_moni). Trick here is thatwe'll return
* 'here' but relocated.
*/
ldr sp,[r9, #GD_START_ADDR_SP] /* sp =gd->start_addr_sp */
bic sp,sp, #7 /* 8-byte alignment for ABIcompliance */
ldr r9,[r9, #GD_BD] /* r9 = gd->bd*/
sub r9,r9, #GD_SIZE /* new GD isbelow bd */
adr lr,here
ldr r0,[r9, #GD_RELOC_OFF] /* r0 =gd->reloc_off */
add lr,lr, r0
ldr r0,[r9, #GD_RELOCADDR] /* r0 =gd->relocaddr */
b relocate_code
here:
/* Set up final(full) environment */
bl c_runtime_cpu_setup /* we still call old routine here */
ldr r0,=__bss_start /* this is auto-relocated!*/
ldr r1,=__bss_end /* this isauto-relocated! */
mov r2,#0x00000000 /* prepare zero toclear BSS */
clbss_l:cmp r0, r1 /*while not at end of BSS */
strlo r2,[r0] /* clear 32-bit BSS word */
addlo r0,r0, #4 /* move to next */
blo clbss_l
bl coloured_LED_init
bl red_led_on
/* call board_init_r(gd_t *id, ulongdest_addr) */
mov r0, r9 /* gd_t */
ldr r1,[r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
ldr pc,=board_init_r /* this isauto-relocated! */
/* we should not return here. */
#endif
#endif
ENDPROC(_main)
第五步:修改board_init_f函数
在arch/arm/lib/board.c中,第265行,修改为:
unsigned intboard_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
注释掉372的addr,添加新的addr:
//addr -= gd->mon_len;
//addr &= ~(4096 - 1);
addr=CONFIG_SYS_TEXT_BASE;
在结尾461行添加:
memcpy(id, (void *)gd, sizeof(gd_t));
return (unsignedint)id;
}
第六步:修改common.h
在/include下,common.h第298行,修改为:
unsigned int board_init_f(ulong);
第七步:修改链接脚本u-boot.lds
在arch/arm/cpu/下,u-boot.lds,第20行:
*(.__image_copy_start)
CPUDIR/start.o (.text*)
board/mini2440/mini2440/lowlevel_init.o(.text*)
board/mini2440/mini2440/nand_read_b.o(.text*)
*(.text*)
同时需要修改/board/mini2440/mini2440下的Makefile,修改如下:
obj-y :=mini2440.o
extra-y :=nand_read_b.o
extra-y +=lowlevel_init.o
第八步:修改顶层/arch/arm/config.mk
注释掉checkarmreloc这部分,否则编译会出错
在第105行:
#ALL-y += checkarmreloc
第九步:编译测试
从nor启动,然后下载到nand之后,关闭电源,s2开关打到nand处启动,出现如下信息:
U-Boot 2014.04 (Sep 02 2015 - 18:54:01)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: *** failed ***
### ERROR ### Please RESET the board ###
因为这时候从nand启动,检测不到nor flash的信息,但是使用友善的u-boot从nand启动是可以读到nor的信息的,并且可以使用nor的命令对其进行操作,看来这个地址空间还有很多文章,这里能够从nand启动进行内核引导的是我们的目的。所以,屏蔽这个错误,这个错误在我们移植nor flash读写的时候就探讨过了,这里进去arch/arm/lib/board.c,第577行:
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
} else {
puts(failed);
// hang();
}
把这个hang()函数注释掉。
再次编译下载。
U-Boot 2014.04 (Sep 02 2015 - 19:06:04)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: *** failed ***
NAND: 256 MiB
*** Warning - bad CRC, using defaultenvironment
In: serial
Out: serial
Err: serial
Net: dm9000
MINI2440 Deep_l_zh #
可以看到成功了,不得不说,移植过程参照网上大神移植到tq2440的帖子,但是期间遇到了很多小问题,这里没有一一写下来,对自己还是收获不少,如有不正确,还请指出,大家共同进步!