您尚未登录。

楼主 #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