拿到Cubieboard已经1周多了,平时上班比较忙,只能晚上玩一会,年关将近,周末都要加班呀....
拿到一个板,若只刷别人给的Image学不到太多东西,于是自己一点一点来
首先是Uboot 移植,所谓移植,其实别人都做好了,我只不过是做了一个启动卡
系统环境:电脑二台,台式机XP;笔记本RHEL5,平时就用这个,懒得整ubuntu
代码工具:XP上: Source Insight 3.5
RHEL5上: Vim,编译工具链arm-2009q3,这个应该有更高版本;串口工具minicom,我的版本是2.1
资源: 支持Cubieboard的U-boot下载网址:https://github.com/linux-sunxi/u-boot-sunxi ,我直接从网页按zip格式下载到XP下
制作方法参考网站:https://github.com/linux-sunxi/u-boot-sunxi/wiki
硬件: 串口线,淘宝Cubieboard自带USB串口线,RHEL5下不用装驱动就能使用,XP下可以用驱动精灵自动安装
microSD卡一枚,2G,读卡器一只,华强北出品,居然比淘宝贵...
开工:
首先观察Cubiebord预装的U-Boot,设置好minicom(具体方法请自己百度),连接串口(使用淘宝配的线),连线顺序如下图:
黑色 ---- GND
绿色 ---- RX
白色 ---- TX
将串口USB端插入笔记本,打开终端输入命令“minicom”,启动minicom之后,再将电源线插入笔记本USB,启动过程中按键盘任意键,进入U-boot,可以看到:
HELLO! BOOT0 is starting!
boot0 version : 1.5.1
dram size =1024
Succeed in opening nand flash.
Succeed in reading Boot1 file head.
The size of Boot1 is 0x0003c000.
The file stored in 0X00000000 of block 2 is perfect.
Check is correct.
Ready to disable icache.
Succeed in loading Boot1. //第1阶段bootloader
Jump to Boot1.
[ 0.133] boot1 version : 1.4.0
[ 0.133] pmu type = 3
[ 0.135] bat vol = 0
[ 0.161] axi:ahb:apb=3:2:2
[ 0.161] set dcdc2=1400, clock=1008 successed
[ 0.163] key
[ 0.175] no key found
[ 0.175] flash init start
[ 0.227] flash init finish
[ 0.228] fs init ok
[ 0.229] fattype FAT16
[ 0.229] fs mount ok
[ 0.236] script finish
[ 0.238] power finish
[ 0.245] BootMain start
[ 0.245] 0
[ 0.264] key value = 0
[ 0.264] recovery key high 6, low 4
[ 0.265] unable to find fastboot_key key_max value
[ 0.274] test for multi os boot with display
[ 0.275] show pic finish
[ 0.278] load kernel start
[ 0.302] load kernel successed
[ 0.302] start address = 0x4a00000
U-Boot 2011.09-rc1 (Nov 26 2012 - 14:01:52) Allwinner Technology //第2阶段bootloader
CPU: SUNXI Family
Board: A10-EVB
DRAM: 512 MiB
NAND: 3776 MiB
In: serial
Out: serial
Err: serial
--------fastboot partitions--------
-total partitions:11-
-name- -start- -size-
bootloader : 1000000 1000000
env : 2000000 1000000
boot : 3000000 2000000
system : 5000000 14000000
data : 19000000 20000000
misc : 39000000 1000000
recovery : 3a000000 2000000
cache : 3c000000 8000000
private : 44000000 1000000
sysrecovery : 45000000 14000000
UDISK : 59000000 93000000
-----------------------------------
Hit any key to stop autoboot: 0
sunxi#
输入命令 version,可以看到:
sunxi#version
U-Boot 2011.09-rc1 (Nov 26 2012 - 14:01:52) Allwinner Technology
arm-none-linux-gnueabi-gcc (Sourcery G++ Lite 2010.09-50) 4.5.1
GNU ld (Sourcery G++ Lite 2010.09-50) 2.20.51.20100809
sunxi#
使用的编译器是arm-none-linux-gnueabi-gcc,版本4.5.1,但是俺的是4.3.2版本,为此我费了了老大劲,换成4.4.1时才编译成功
有了上面的基本情况,开始编译制作,在XP下解压下载的u-boot-sunxi-sunxi.zip,删除board文件夹下除了allwinner文件的其他文件,board/allwinner文件夹内只需要保留common和Cubieboard两个文件夹,其他不需要;删除arch文件夹内除了arm文件的其他文件,arch/arm/cpu文件夹下只保留armv7和u-boot.lds,arch/arm/cpu/armv7内文件和sunxi文件夹保留,其他文件夹删除。这样做可以在Source Insight关联时减少关联项目,便于查阅,若还想更进一步,将include目录下与A10无关的头文件一并删除,关联时更加清晰。使用Source Insight 3.5建立一个工程,添加文件时选择u-boot解压文件夹,选择“add tree”,将全部文件加入工程,再选Project->Rebuilt Project...,如此一来,XP下的代码查阅工程就建立啦。
linux下解压U-boot到自己工作目录,不需要删除操作。
安装arm-2009q3.tar.bz2,在arm-2009q3.tar.bz2目录下输入命令:tar -jxvf arm-2009q3.tar.bz2 -C /usr/local/arm/
将编译器设置为默认arm编译器: vim /etc/profile
在末尾增加一行: export=$PATH:/usr/local/arm/arm-2009q3/bin
保存退出之后执行:source /etc/profile
或者重启,或者logoout一下,使设置生效。以上设置适合RHEL5,其他linux系统请百度解决。
编译U-boot: make cubieboard CROSS_COMPILE=arm-none-linux-gnueabi-
等待.........
生成三个.bin文件,分别是u-boot.bin和spl目录下的sunxi-spl.bin、u-boot-spl.bin
第1阶段bootloader:sunxi-spl.bin
第2阶段bootloader:u-boot.bin
u-boot-spl.bin我没试过,应该也是第一阶段的bootloader
SD卡准备(我机器上是/dev/sdb),linux下操作:
前面1M给bootloader使用(为什么?要仔细查查资料,目前我还不明白,望高人指点),先清零:
dd if=/dev/zero of=/dev/sdb bs=1M count=1
后面剩余的可以不管,也可分区,具体做法请百度
将u-boot写入,只写入第1阶段bootloader,在u-boot目录操作:
dd if=spl/sunxi-spl.bin of=/dev/sdb bs=1024 seek=8
取下SD卡,插到板子上,上电,minicom有输出如下:
U-Boot SPL 2012.10 (Jan 23 2013 - 21:18:42)
DRAM: 1024MB
SUNXI SD/MMC : 0
U-Boot SPL 2012.10 (Jan 23 2013 - 21:18:42)
然后就死掉了,那是因为没有写入第2阶段,即u-boot.bin。
从这一段输出,可以获得一些有用的信息,从打印信息入手,以便获取u-boot第一阶段代码运行轨迹。比较有特征的是“SUNXI SD/MMC”,在XP工程中搜索“SUNXI SD”(有斜杠就搜索不到,不知道为啥),可以定位到文件到..\drivers\mmc\sunxi_mmc.C的函数int sunxi_mmc_init(int sdc_no);
同样搜索“sunxi_mmc_init”.....最后得出调用关系如下,注意代码片段红色部分:
文件..\u-boot-sunxi-sunxi\arch\arm\cpu\armv7\ start.S, 调用函数 board_init_f :
......
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f //..\u-boot-sunxi-sunxi\arch\arm\lib\board.c
......
..\u-boot-sunxi-sunxi\arch\arm\lib\board.c文件的board_init_f对全局变量gd进行设置
void board_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp;
#ifdef CONFIG_PRAM
ulong reg;
#endif bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); /* Pointer is writable since we allocated a register for it */
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/*
给gd分配一段空间,位置位于((CONFIG_SYS_INIT_SP_ADDR) & ~0x07),这一段内存位于片上32K的SDRAM内
结合CONFIG_SYS_INIT_SP_ADDR的定义../include/configs/sunxi-common.h:
#define CONFIG_SYS_INIT_RAM_ADDR 0x0 /*A10内部RAM起始地址*/
#define CONFIG_SYS_INIT_RAM_SIZE 0x8000 /*A10内部RAM,32K */
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
GENERATED_GBL_DATA_SIZE在编译时自动生成在文件../generated/generic-asm-offses.h内,值为128
最后计算的结果还是与CONFIG_SYS_INIT_SP_ADDR相等,为啥要& ~0x07,末尾按8字节对齐?
此时,gd位于片内的32K空间上
*/
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); memset((void *)gd, 0, sizeof(gd_t)); gd->mon_len = _bss_end_ofs;
#ifdef CONFIG_OF_EMBED //没定义
/* Get a pointer to the FDT */
gd->fdt_blob = _binary_dt_dtb_start;
#elif defined CONFIG_OF_SEPARATE //没定义
/* FDT is at end of image */
gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
#endif
/* Allow the early environment to override the fdt address */
gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob );
for ( init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
/*
init_sequence是一个函数表,for循环执行初始化,初始化定时器,串口,控制台等等
其中,gd->ram_size在列表最后一个函数中获得SDRAM的size,cubieboard是1G,确定内存有效的方法就是给等于2的次幂的地址写入一个数据,在读出比较
写入读出一致确认内存有效,只需要32次循环就可以检测4G空间,感兴趣的可以自行阅读代码内容,如果不看该列表内容,根本不知道原来这里面设置了gd->ram_size
因为下面条件汇编均不成立,没有设置gd->ram_size,最后又在使用这个值,莫名其妙
*/
}#ifdef CONFIG_OF_CONTROL //没定义
/*For now, put this check after the console is ready */
if (fdtdec_prepare_fdt()) {
panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
"doc/README.fdt-control");
}
#endif debug("monitor len: %08lX\n", gd->mon_len);
/*
* Ram is setup, size stored in gd !!
*/
debug("ramsize: %08lX\n", gd->ram_size);
#if defined(CONFIG_SYS_MEM_TOP_HIDE) //没定义
/*
* Subtract specified amount of memory to hide so that it won't
* get "touched" at all by U-Boot. By fixing up gd->ram_size
* the Linux kernel should now get passed the now "corrected"
* memory size and won't touch it either. This should work
* for arch/ppc and arch/powerpc. Only Linux board ports in
* arch/powerpc with bootwrapper support, that recalculate the
* memory size from the SDRAM controller setup will have to
* get fixed.
*/
gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif
addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; ////gd->ram_size就是上面设置的,addr=0x400000000 + 1G 即内存的最后一个地址0x80000000
#ifdef CONFIG_LOGBUFFER //没定义
#ifndef CONFIG_ALT_LB_ADDR
/* reserve kernel log buffer */
addr -= (LOGBUFF_RESERVE);
debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
addr);
#endif
#endif#ifdef CONFIG_PRAM //没定义
/*
* reserve protected RAM
*/
reg = getenv_ulong("pram", 10, CONFIG_PRAM);
addr -= (reg << 10); /* size is in kB */
debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
#endif /* CONFIG_PRAM */
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) //没定义
/* reserve TLB table */
addr -= (4096 * 4); /* round down to next 64 kB limit */
addr &= ~(0x10000 - 1); gd->tlb_addr = addr;
debug("TLB table at: %08lx\n", addr);
#endif
/* round down to next 4 kB limit */
addr &= ~(4096 - 1); //4K空间给U-boot
debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
#ifdef CONFIG_LCD //没定义
#ifdef CONFIG_FB_ADDR
gd->fb_base = CONFIG_FB_ADDR;
#else
/* reserve memory for LCD display (always full pages) */
addr = lcd_setmem(addr);
gd->fb_base = addr;
#endif /* CONFIG_FB_ADDR */
#endif /* CONFIG_LCD */
/*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/
addr -= gd->mon_len; //分配内存
addr &= ~(4096 - 1); //按4K对齐,gd->mon_len不到4K则分配4K
debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);#ifndef CONFIG_SPL_BUILD
/*
* reserve memory for malloc() arena
*/
addr_sp = addr - TOTAL_MALLOC_LEN; //设置sp的首地址,可见压栈地址向下递减,此时addr停留在距离sp长度为TOTAL_MALLOC_LEN的地方
//TOTAL_MALLOC_LEN咋一看,应该是malloc的内存管理区域,是不是呢?往下看看
debug("Reserving %dk for malloc() at: %08lx\n",TOTAL_MALLOC_LEN >> 10, addr_sp);
/*
* (permanently) allocate a Board Info struct
* and a permanent copy of the "global" data
*/
addr_sp -= sizeof (bd_t); //分配一段内存给全局变量gd的成员bd,sp指着往下移动
bd = (bd_t *) addr_sp;
gd->bd = bd;
debug("Reserving %zu Bytes for Board Info at: %08lx\n",sizeof (bd_t), addr_sp);
#ifdef CONFIG_MACH_TYPE
gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif
addr_sp -= sizeof (gd_t); //分配一段内存给全局变量gd(即id),sp指着继续往下移动
id = (gd_t *) addr_sp;
debug("Reserving %zu Bytes for Global Data at: %08lx\n",sizeof (gd_t), addr_sp);
/* setup stackpointer for exeptions */
gd->irq_sp = addr_sp;
#ifdef CONFIG_USE_IRQ
addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
#endif
/* leave 3 words for abort-stack */
addr_sp -= 12; /* 8-byte alignment for ABI compliance */
addr_sp &= ~0x07;
#else
addr_sp += 128; /* leave 32 words for abort-stack */
gd->irq_sp = addr_sp;
#endif
debug("New Stack Pointer is: %08lx\n", addr_sp);
/*
执行到这里,内存基本分配已经出来了,从0x80000000往下,依次是:
1、4K空间给U-boot ,干啥用的?
2、gd->mon_len,按4K往上对齐,干啥用的?
3、TOTAL_MALLOC_LEN,malloc内存池----堆空间
4、gd的成员bd的空间
5、gd的空间
6、异常使用的栈
7、栈-----SP开始的地方
*/
#ifdef CONFIG_POST //没定义
post_bootmode_init();
post_run(NULL, POST_ROM | post_bootmode_get(0));
#endif gd->bd->bi_baudrate = gd->baudrate;
/* Ram ist board specific, so move it to board code ... */
dram_init_banksize(); //将ram的大小记录在gd内
display_dram_config(); /* and display it */ gd->relocaddr = addr; //显示内存大小,即minicom看到的打印内存大小那一行
gd->start_addr_sp = addr_sp; //将栈首地址记录在gd内
gd->reloc_off = addr - _TEXT_BASE; //记录U-boot代码段的偏移量,使用addr,由于拷贝时地址增加,因此代码紧邻malloc堆空间
debug("relocation Offset is: %08lx\n", gd->reloc_off);
memcpy(id, (void *)gd, sizeof(gd_t)); //将gd拷贝到id,即gd从片上32K空间转移到了外部SDRAM空间内了(id就在上面分配,地址是0x8xxxxxxx),为代码在内存上运行做准备
relocate_code(addr_sp, id, addr);
/*
重载relocate_code在start.S内部,是汇编代码,将参数传递过去,之后拷贝代码到addr开始的地方,
将堆栈设置为addr_sp,为C语言代码运行准备栈,调用以后将不会再返回,进入内存运行。
按照ARM编译时C函数传递规则,从第一个参数往后依次是r0,r1,r2.....
可知:r0 <------ addr_sp
r1 <------ id(即gd)
r2 <------ addr
*/
/* NOTREACHED - relocate_code() does not return */
}
再回到start.S,看看 重载relocate_code部分 :
/*------------------------------------------------------------------------------*/
#ifndef CONFIG_SPL_BUILD
/*
* void relocate_code (addr_sp, gd, addr_moni) //就是接上面而来的
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
ENTRY(relocate_code)
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6 //r6现在指向SDRAM空间,r0指向的_start肯定不在外部SDRAM内(应该是在内部32K空间内),所以第1次这个比较是不相等的
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */ //将r6复制给r1,此时r1的值就是传递过来的addr,即是即将拷贝U-boot的起始地址
ldr r3, _image_copy_end_ofs //需要拷贝的长度,这个需要看看lds文件的设置
add r2, r0, r3 /* r2 <- source end address */ //拷贝结束时的地址在若内
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */ //从r0开始,即_start,拷贝一次4字节,r0自动+4
stmia r1!, {r9-r10} /* copy to target address [r1] */ //拷贝到r1开始的地方,即addr开始的地方,一次4字节,r1自动+4
cmp r0, r2 /* until source end address [r2] */ //检查是否到达最后一个地址,到了就结束拷贝
blo copy_loop
....................
//接下一堆汇编,我承认没看懂
...................
直到下面,拷贝处理完成,跳到RAM中运行
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
jump_2_ram:
/*
* If I-cache is enabled invalidate it
*/
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
#endif
/*
* Move vector table
*/
#if !defined(CONFIG_TEGRA20) //没定义
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
add r0, r0, r9
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif /* !Tegra20 */
ldr r0, _board_init_r_ofs //准备运行board_init_r函数
adr r1, _start
add lr, r0, r1 //计算通过偏移量计算出board_init_r的位置
add lr, lr, r9 //这句是啥意思?是不是什么格式的偏移量?不懂
/* setup parameters for board_init_r */ //看看函数原型void board_init_r(gd_t *id, ulong dest_addr),传递规则第一个参数r0,第二个参数r1.....
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr //调用RAM中的代码,从board_init_r开始,不在返回
接下来就是C代码了,依次调用往下,最后到搜索的地方,其实当初我是反过来从下面一个个往上找这个关系的
还用一堆问题,数据时怎么从SD卡读到内存的?????第一次读了多少?(只有start.o?),超过32k的内容是怎么拷贝进来的?
是不是上面那段我看不懂的汇编干的??诸多问题.....有待进一步研究
..\u-boot-sunxi-sunxi\arch\arm\lib\board.c文件的board_init_r调用mmc_initialize
void board_init_r(gd_t *id, ulong dest_addr)
{
.....
#ifdef CONFIG_GENERIC_MMC
puts("MMC: "); //这就是看到的打印信息的前一部分
mmc_initialize(gd->bd); //..\u-boot-sunxi-sunxi\drivers\mmc\mmc.c
#endif
.....
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) { //可见,若进入u-boot的命令模式,就在这个主循环工作,可以研究一下
main_loop();
}
/* NOTREACHED - no way out of command loop except booting */
.....
}
..\u-boot-sunxi-sunxi\drivers\mmc\mmc.c文件的mmc_initialize调用board_mmc_init
int mmc_initialize(bd_t *bis)
{
INIT_LIST_HEAD (&mmc_devices);
cur_dev_num = 0;
if (board_mmc_init(bis) < 0) //..\u-boot-sunxi-sunxi\board\allwinner\common\board.c
cpu_mmc_init(bis);
print_mmc_devices(',');
return 0;
}
..\u-boot-sunxi-sunxi\board\allwinner\common\board.c文件的board_mmc_init调用sunxi_mmc_init
#ifdef CONFIG_GENERIC_MMC
int board_mmc_init(bd_t *bis) {
sunxi_mmc_init(CONFIG_MMC_SUNXI_SLOT); //..\u-boot-sunxi-sunxi\drivers\mmc\sunxi_mmc.c
return 0;
}
#endif
..\u-boot-sunxi-sunxi\drivers\mmc\sunxi_mmc.c文件的sunxi_mmc_init调用就是我们搜索的“SUNXI SD”
int sunxi_mmc_init(int sdc_no)
{
struct mmc *mmc;
memset(&mmc_dev[sdc_no], 0, sizeof(struct mmc));
memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host));
mmc = &mmc_dev[sdc_no];
sprintf(mmc->name, "SUNXI SD/MMC");
mmc->priv = &mmc_host[sdc_no];
mmc->send_cmd = mmc_send_cmd;
mmc->set_ios = mmc_set_ios;
mmc->init = mmc_core_init;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->host_caps = MMC_MODE_4BIT;
mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
mmc->f_min = 400000;
mmc->f_max = 52000000;
mmc_host[sdc_no].pdes = (struct sunxi_mmc_des*)0x50000000;
mmc_resource_init(sdc_no);
mmc_clk_io_on(sdc_no);
mmc_register(mmc);
return 0;
}
将u-boot写入,写入第2阶段bootloader,在u-boot目录操作:
dd if=u-boot.bin of=/dev/sdb bs=1024 seek=32
取下SD卡插到板子上,上电,minicom有输出如下:
U-Boot SPL 2012.10 (Jan 24 2013 - 21:42:50)
DRAM: 1024MB
SUNXI SD/MMC: 0
U-Boot 2012.10 (Jan 24 2013 - 21:42:50) Allwinner Technology
CPU: SUNXI Family
Board: Cubieboard
I2C: ready
DRAM: 1 GiB
MMC: SUNXI SD/MMC : 0
*** Warning - bad CRC, using default environment //没做参数文件,使用默认参数
In: serial
Out: serial
Err: serial
start main_loop...Hit any key to stop autoboot: 0
sun4i#
输入ersion命令:
sun4i#version
U-Boot 2012.10 (Jan 24 2013 - 21:42:50) Allwinner Technology
arm-none-linux-gnueabi-gcc (Sourcery G++ Lite 2009q3-67) 4.4.1
GNU ld (Sourcery G++ Lite 2009q3-67) 2.19.51.20090709
sun4i#
可以看到我使用的编译器是4.4.1版本的,低于原来板子自带u-boot编译器的版本
至此,U-boot的启动SD卡基本制作完成,接下来需要往里面增加新的功能,使其符合我的需求
1、练习,LED闪速.......这就是个毛病,拿到板子没看见LED在自己控制下闪烁就像程序没有运行一样....病的不轻
2、练习,增加一个测试命令
3、实战,增加Nand支持,实现读写,刷新,估计有现成模块可以使用,不会很难
4、增加网络支持,目前代码没有RTL8201CP的驱动,有rtl8139,rtl8169的驱动,可以参考,增加tftp功能,ping功能
5、将u-boot通过网络下载到内存,在写入nand,去掉SD卡,从nand启动,至此,u-boot移植可告一段落
以上每一步,若有所得,再来分享