您尚未登录。

楼主 #1 2021-02-22 18:45:56

winminwu
会员
注册时间: 2020-05-06
已发帖子: 21
积分: 21

v3s-uboot移植分析过程总结

1、获取源码。git clone https://github.com/Lichee-Pi/u-boot.git -b v3s-spi-experimental。
ps:下载慢的解决办法:将uboot源码导入到码云官网(https://gitee.com/),再git该官网下相应的链接地址。

2、编译得到u-boot-sunxi-with-spl.bin。
(1)make ARCH=arm CROSS_COMPILE=(/usr/local/arm/arm-2009q3(根据自身环境路径))/bin/arm-none-linux-gnueabi- (空格)LicheePi_Zero_480x272LCD_defconfig
(2)make ARCH=arm CROSS_COMPILE=(/usr/local/arm/arm-2009q3(根据自身环境路径))/bin/arm-none-linux-gnueabi- 2>&1 | tee build.log

3、启动设备
(1)SD卡启动。参考:https://blog.csdn.net/qq_40860568/article/details/96474001
(2)nor flash启动。
1)以上用的源码v3s-spi-experimental设备树已加入spi0以及make menuconfig中也选择了Device Drivers ‣ SPI Flash Support,不过需要根据自身情况选择相应的spi flash厂商,本人用的是XT25Q128,选择Winbond SPI flash support,其他选项默认就好。
2)因为用的spi flash是XT25Q128,所以还需要参考其作相应改动:https://whycan.com/t_4159.html。
3)需要安装sunxi-fel工具烧写进spi flash。

git clone -b spi-rebase https://github.com/Icenowy/sunxi-tools.git
进入工具目录执行make && sudo make install

ps:如果出现:fel_lib.c:26:20: fatal error: libusb.h: No such file or directory,那需要安装libusb:sudo apt-get install libusb-1.0-0-dev
4)使芯片进入FEL模式。

在spi flash的cs引脚处焊条引线;
上电或复位时,将引线接地便可进入FEL模式;
进入FLE模式后再断开引线和地的连接。

5)烧录命令:sunxi-fel -p spiflash-write 0 u-boot-sunxi-with-spl.bin

4、启动信息分析
(1)个人初体验。
以本人以前学习朱老师的课程中的uboot分析可知:soc(s5pV210)是自身固定了一段代码,该代码会读取uboot的前16k(BL1)去执行,而在这16k的代码会做的工作:将完整的uboot.bin复制到内存中,然后再长跳转到完整的uboot.bin去执行。
然而刚开始看到v3s的uboot启动信息就非常困惑。首先一眼看去,看到打印信息有一部分是重复的:

CPU: Allwinner V3s (SUN8I 1681)
Model: Lichee Pi Zero
DRAM: 64 MiB
MMC: SUNXI SD/MMC: 0
SF: Detected xt25q128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
Setting up a 480x272 lcd console (overscan 0x0)
dotclock: 10000kHz = 10000kHz: (1 3MHz 20) / 6
In: serial@01c28000
Out: serial@01c28000
Err: serial@01c28000

还以为是重定位造成的(在没长跳转之前执行了一遍,在跳转后又执行了这些代码一遍),当时就以为这是v3s的uboot和之前s5pV210的不一样吧。于是就追进源码去看,居然发现有两个board_init_f();其是通过CONFIG_SPL_BUILD宏定义条件编译的,刚开始以为整个uboot源码就只会编译和执行其中的一段代码,但是对照打印信息怎么都不对劲,因为最开头的打印信息:

U-Boot SPL 2017.01-rc2-00073-gdd6e874-dirty (Feb 17 2021 - 16:57:21)
DRAM: 64 MiB
Trying to boot from sunxi SPI

也打印了出来,在源码中这些打印的信息是在定义了CONFIG_SPL_BUILD宏才执行的啊,而如果定义了这个宏,那CPU: Allwinner V3s (SUN8I 1681)这些信息就不会被打印啊,再加上CPU: Allwinner V3s (SUN8I 1681)这些信息还出现了重复打印,这到底是怎么个重定位法跳来跳去执行的...
(2)几经折腾以及大胆猜测得到以下结论。
1)首先把那些重复打印信息先解决(这个是在最后才能发现的,现在因为知道了直接拿到第一点说明)。print_pre_console_buffer()【\common\console.c】就是因为该语句才导致出现信息的重复打印的(真能折腾死)。
2)上面说的board_init_f()函数出现了两个,其实两个都执行了,都在同一个uboot源码中,两个相同的函数居然能编译过,真神奇。其实它是被编译成两个不同的bin的了。
3)个人的分析过程(其中大多是猜的,错的指出即可)
/附录1/
RGB灯的汇编测试程序:
ldr r5, =0X1
ldr r6, =0X01C208D8
str r5, [r6]
ldr r5, =0X0
ldr r6, =0X01C208E8
str r5, [r6]
b delay_later
delay:
ldr r7, = 19999999
ldr r8, = 0
delay_loop:
sub r7,r7,#1
cmp r7,r8
bne delay_loop
mov pc,lr
delay_later:
bl delay
ldr r5, =0X1
ldr r6, =0X01C208E8
str r5, [r6]

(1)在“bl board_init_f”【\arch\arm\lib\crt0.S】紧后
加了LED闪烁测试:发现LED闪烁了两次。
猜测:
uboot有两个bin文件,一个是定义了CONFIG_SPL_BUILD宏的SPL的bin文件,
另一个则是没有定义的完整uboot的bin文件;SPL的bin文件是将/common/spl/spl.c
编译进去的,而完整uboot的bin文件则是没有将其编译进去,故两者调用的
board_init_f和board_init_r是不一样的。

(2)在“ldr lr, =board_init_r”【\arch\arm\lib\crt0.S】前
加了LED慢闪;在“ldr pc, =board_init_r”【\arch\arm\lib\crt0.S】前
加了LED快闪:发现LED先是慢闪一下,后再快闪一下。

猜测:
在SPL的bin文件运行时是通过短跳转到board_init_r,
而在完整uboot的bin文件运行时是通过长跳转到board_init_r。

(3)在“b relocate_code”【\arch\arm\lib\crt0.S】前
加了LED闪烁测试:发现只闪烁了一次。

猜测:
只有在完整uboot的bin文件中才会调用relocate_code进行代码重定位,
从中可推断SPL的bin文件运行只是初始化了DDR和判断从哪里启动等,并没
有实现重定位。

总结:
u-boot-sunxi-with-spl.bin文件中的最前面代码是sunxi-spl.bin【\spl】,
其主要作用是初始化了DDR和判断从哪里启动等,最后便跳转到u-boot.bin中运行,
期间是通过CONFIG_SPL_BUILD等宏来区分board_init_f、board_init_r等函数,
代码重定位是在u-boot.bin中实现。
/附录1/

/附录2-sunxi-spl.bin/
(1)_start【\arch\arm\lib\vectors.S】
reset:

reset【\arch\arm\cpu\armv7\start.S】

lowlevel_init:

lowlevel_init【\arch\arm\cpu\armv7\lowlevel_init.S】

设置栈
s_init();

s_init()【\arch\arm\mach-sunxi\board.c】

clock_init();
timer_init();
gpio_init();
i2c_init_board();
eth_init_board();
_main:

_main

(2)_main【\arch\arm\lib\crt0.S】
设置栈
board_init_f_alloc_reserve();
board_init_f_init_reserve();
board_init_f();

board_init_f()【\arch\arm\mach-sunxi\board.c】

spl_init();
preloader_console_init();

preloader_console_init()【\common\spl\spl.c】

serial_init();

/U-Boot SPL 2017.01-rc2-00057-g32ab180-dirty/

sunxi_board_init();

sunxi_board_init()【\board\sunxi\board.c】

printf("DRAM:");
ramsize = sunxi_dram_init();
printf(" %d MiB\n", (int)(ramsize >> 20));

(3)board_init_r【\common\spl\spl.c】
board_boot_order(spl_boot_list);
boot_from_devices(&spl_image, spl_boot_list,ARRAY_SIZE(spl_boot_list));
spl_board_prepare_for_boot();
jump_to_image_no_args(&spl_image);
/附录2-sunxi-spl.bin/

/附录3-u-boot.bin/
(1)board_init_f()【\common\board_f.c】
initf_malloc();
initf_dm();
mark_bootstage();
timer_init();
init_baud_rate();

init_baud_rate()【\common\board_f.c】

CONFIG_BAUDRATE【\include\configs\sunxi-common.h】
serial_init();
console_init_f();
display_options(); /U-Boot 2017.01-rc2-00057-g32ab180-dirty/
display_text_info(); /show debugging info if required/
print_cpuinfo(); /CPU: Allwinner V3s (SUN8I 1681)/
show_board_info(); /Model: Lichee Pi Zero/
INIT_FUNC_WATCHDOG_INIT
INIT_FUNC_WATCHDOG_RESET
init_func_i2c();
init_func_spi();
announce_dram_init();
dram_init(); /DRAM: 64 MiB/
INIT_FUNC_WATCHDOG_RESET
setup_dest_addr();

setup_dest_addr【\common\board_f.c】

/*

  • Now that we have DRAM mapped and working, we can

  • relocate the code and continue running from DRAM.
    *

  • Reserve memory at end of RAM for (top down in that order):

  • - area that won't get touched by U-Boot and Linux (optional)

  • - kernel log buffer

  • - protected RAM

  • - LCD framebuffer

  • - monitor code

  • - board info struct
    */
    gd->ram_size = board_reserve_ram_top(gd->ram_size);
    gd->ram_top = CONFIG_SYS_SDRAM_BASE;
    gd->ram_top += get_effective_memsize();
    gd->ram_top = board_get_usable_ram_top(gd->mon_len);
    gd->relocaddr = gd->ram_top; /gd->relocaddr = 0X43E00000/
    reserve_round_4k();
    gd->relocaddr &= ~(4096 - 1); /gd->relocaddr = 0X43E00000/
    reserve_mmu();
    /gd->relocaddr = 0X43DF0000/
    reserve_uboot();
    /gd->relocaddr = 0X43D60000/
    reserve_malloc();
    reserve_board();
    setup_machine(); / board id for Linux() /
    >CONFIG_MACH_TYPE【\include\configs\sun4i.h】
    #define CONFIG_MACH_TYPE (4104|((CONFIG_MACH_TYPE_COMPAT_REV) << 28))
    reserve_global_data();
    reserve_fdt();
    reserve_arch()
    reserve_stacks();
    setup_dram_config();
    show_dram_config();
    INIT_FUNC_WATCHDOG_RESET
    setup_reloc(); /重定位准备/
    gd->relocaddr = 0X43D60000;
    gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
    /gd->reloc_off = 0XF60000/

(2)board_init_r【\common\board_r.c】
initr_reloc();
initr_caches();
initr_reloc_global_data();
initr_malloc();
initr_dm(); /dm表示driver model?/
initr_bootstage();
board_init(); /Setup chipselects/
stdio_init_tables();
initr_serial();
INIT_FUNC_WATCHDOG_RESET
#ifndef CONFIG_SYS_NO_FLASH
initr_flash();
#endif
INIT_FUNC_WATCHDOG_RESET
initr_mmc(); /MMC: SUNXI SD/MMC: 0/
initr_env();

initr_env()【\common\board_r.c】

env_relocate();

env_relocate()【\common\env_common.c】

env_relocate_spec();

env_relocate_spec()【\common\env_sf.c 2】

/Invalid bus 0 (err=-19)/
/***Warning-spi_flash_probe()..failed ...*/

spi_flash_probe();

spi_flash_probe()【\driver\mtd\spi\sf-uclass.c】

spi_flash_probe_bus_cs();

原因:\arch\arm\dts\sun8i-v3s-licheepi-zero.dts处没配置好spi0

INIT_FUNC_WATCHDOG_RESET
stdio_add_devices();

stdio_add_devices【\common\stdio.c】

drv_video_init();

drv_video_init【\drivers\video\cfb_console.c】

cfg_video_init();

cfg_video_init【\drivers\video\cfb_console.c】

video_hw_init();

video_hw_init【\drivers\video\Sunxi_display.c】

//配置信息
/*
CONFIG_VIDEO_LCD_MODE=
"x:480,y:272,depth:18,pclk_khz:10000,
le:42,ri:8,up:11,lo:4,hs:1,vs:1,
sync:3,vmode:0"
*/
char *lcd_mode = CONFIG_VIDEO_LCD_MODE;

/Setting up a 480x272 lcd console (overscan 0x0)/

sunxi_mode_set();
/dotclock: 10000kHz = 10000kHz: (1 3MHz 20) / 6/

video_console_address = video_logo();

video_logo()【\drivers\video\cfb_console.c】

/logo图片的更换可参考:http://zero.lichee.pro/%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91/uboot_logo.html/

//logo的宽
VIDEO_LOGO_WIDTH
//logo的高
VIDEO_LOGO_HEIGHT
//logo的x坐标
video_logo_xpos
//logo的y坐标
video_logo_ypos
//分辨率-列
VIDEO_VISIBLE_COLS
//分辨率-行
VIDEO_VISIBLE_ROWS

initr_jumptable();
console_init_r(); /CONFIG_SYS_CONSOLE_IS_IN_ENV is not set/

console_init_r【\common\console.c 2】

stdio_print_current_devices();

stdio_print_current_devices()【\common\console.c】

/*
In: serial@01c28000
Out: serial@01c28000
Err: serial@01c28000
*/
print_pre_console_buffer();

print_pre_console_buffer()【\common\console.c】

/*
经过实践验证,如下信息:
CPU: Allwinner V3s (SUN8I 1681)
Model: Lichee Pi Zero
...
重复打印便是出现在此函数中
*/

INIT_FUNC_WATCHDOG_RESET
interrupt_init();
initr_enable_interrupts();
initr_ethaddr();
INIT_FUNC_WATCHDOG_RESET
initr_net();
/附录3-u-boot.bin/

后面本人将会将tftp加载内核以及设备树到内存,并通过NFS文件系统的方式启动内核的思路总结发表

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn


东莞哇酷科技有限公司开发