精华内容
下载资源
问答
  • u-boot移植新手入门实践视频教程中使用的配套pdf文档。
  • 海思Hi3531芯片的uboot移植,含uboot移植、DDR3参数配置、uboot镜像下载和网络测试等4部分构成,内容包括SDK中的uboot源码解压到最终下载和测试全流程,实测可用。
  • uboot移植详细教程

    2015-08-29 10:16:47
    uboot移植详细教程,建议看完前面几个脚本分析文档,再接下来看uboot。
  • Linux 系统要启动就必须需要一个 bootloader 程序,也就说芯片上电以后先运行一段bootloader 程序。这段 bootloader 程序会先初始化 DDR 等外设,然后将 Linux 内核从 flash(NAND,NOR,FLASH,SD,MMC 等)拷贝到 DDR 中,...
  • imx287 linux+uboot移植

    2018-10-30 12:53:04
    本文件里包含uboot和linux的移植过程文档和具体源码,内容是参照周立功的官方源码修改的,所以分值不高,有需要自行下载,遇到问题可以跟我交流1002337604@qq.com
  • AM335x UBOOT移植记录

    2015-05-24 06:26:51
    一、移植过程 1、架构移植 2、SOC移植 3、板级移植 二、3种移植的区别 1、架构移植:Cortex-A8、MIPS、POWERPC 2、SOC移植 :同一系列,不同型号间的外设(如I2C)的区别 3、板级移植:EVM(删减模块,驱动)的...
  • 关于am335x平台的uboot移植文档,基于官方SDK开发,文档详细说明了移植修改代码应注意事项,以及需要修改的代码段,希望给正在使用am335x的朋友有所帮助,文档有本人在项目开发过程中实践整理
  • 自己移植了x210v3的开发板的uboot和Linux心得,这块开发板基于s5pv210芯片。和其他的210开发板差不多,如果你是210的板子,那么可以参考我写得教程,希望对你有所帮助。
  • uboot移植之网卡

    2021-01-06 05:40:18
    经过前面的几节内容,我们的uboot移植已经支持了nor flash启动和nand flash启动了,这一节的内容是让Uboot支持DM9000网卡,就可以使用tftp下载文件了,速度要比串口下载快很多 第一步先找到DM9000的文件–driver/...
  • 嵌入式uboot移植

    2016-12-14 10:09:03
    本论文是从知网上找的关于uboot移植,有s3c244,6410的以及基于龙芯平台的,一共十二篇。望对你有帮助。
  • uboot移植步骤

    2021-04-22 13:51:48
    Uboot移植具体步骤(本例子为Samsung origen板) 第一步:准备源码 网上下载现成的uboot开源代码:https://ftp.denx.de/pub/u-boot/ 在该网站中选择与板子兼容的uboot源文件(公司中一般咨询硬件工程师) 在Linux系统下...

    Uboot移植具体步骤(本例子为Samsung origen板)

    第一步:准备源码

    网上下载现成的uboot开源代码:https://ftp.denx.de/pub/u-boot/
    在该网站中选择与板子兼容的uboot源文件(公司中一般咨询硬件工程师)
    在Linux系统下解压
    tar xf 压缩包名

    第二步:修改源码

    1.抄板:将和你板子兼容的文件复制一份文件
    cd u-boot-2013.01/board/samsung/
    cp origen fs4412 -r
    2.直接执行make fs4412,如下错误:
    在这里插入图片描述
    说明在make的时候不认识fs4412这个文件夹,需要自行添加。执行以下命令:
    grep origen . -r 显示如下结果图:
    在这里插入图片描述
    通过该命令即可找到配置文件夹为/boards.cfg,然后进入该文件
    vim boards.cfg 在该文件夹中添加如下句段:
    fs4412 arm armv7 fs4412 samsung exynos
    3.准备就绪后执行make fs4412,出现以下错误:
    在这里插入图片描述
    为找到fs4412.h文件,原因在于我们复制了origen文件夹,但是在整个项目中有origen.h文件而却没有fs4412.h的头文件,所以我们需要将头文件也复制一份:
    find -name origen.h
    该命令可以找到文件的路径为./include/configs/origen.h
    cp /include/configs/origen.h /include/configs/fs4412.h
    再执行make fs4412,此时应该就可以编译成功生成二进制文件uboot.bin
    4.此时生成的二进制文件并不能完全运行,原因在于本次的例子板子为Samsung的芯片,要想我们烧写的uboot程序被芯片识别则需要三星的签名和加工编译的源码才能实现,该加工留着下一步说明,现在我们就算编译加工成功了任然无法正常运行该uboot。
    此时我们应该学会进行板子调试:调试的方法即检查uboot文件是否被执行,我们需要找到文件的起始文件,那么如何查看起始文件呢?
    4.1 uboot.lds为连接文件即文件执行的首选文件可以在该文件中看到
    vim uboot.lds
    在这里插入图片描述
    可以看到目标起始文件为arch/arm/cpu/armv8/start.o
    进入该文件夹cd arch/arm/cpu/armv8/
    找到文件的开始b reset
    在reset函数中加入一段代码,作用在于证明uboot被执行(该代码可以是亮灯)
    然后调试uboot源文件哪里需要修改删除或者添加代码即可
    5.就算uboot启动了我们还需要打开网卡驱动已经其他的一些常用的系统命令的编辑。
    从下载下来的文件中有一个common的文件夹,该文件夹中存放着一些系统文件,这些文件有些在配置里面被编译,有些没被编译,被编译出来的会生成一个.o文件,我们才看这个目录下的文件的时候发现网络cmd_net.c并没有被编译生成.o文件,所以默认的网络并不能启动,我们要做的就是修改配置将文件进行编译即可。
    方法:
    5.1进入驱动的文件目录:cd drivers
    5.2查找网卡的名字 find -name *9000*(网卡的名字在芯片设计图中可以得知,或者直接询问)
    在这里插入图片描述
    获得以下的文件,进入文件cd /net在net目录下我们编译的时候会有一个MakeFile文件来统一执行编译命令,所以我们可以通过查看该文件确认文件怎么执行
    找到文件中存在一个宏定义CONFIG_DRIVER_DM9000
    我们搜索到这个宏定义并没有定义出来,所以在默认编译的时候MakeFile文件不会将该模块编译出来,导致无法启动网卡。
    5.3 我们需要在fs4412.h的头文件中全局搜索CONFIG_DRIVER_DM9000将该宏定义未定义改为#define
    以上做完之后编译无法通过因为文件中的网卡管脚在你自己开发板的具体实现还未完成,需要自己编写一部分网卡管脚代码才能编译通过。(难点:具体怎么添加和添加什么代码需要结合自己的板子来开发)
    6.以上步骤完成uboot移植基本完成。
    追加知识点:
    如果需要人为的为系统增加命令那么需要在common文件夹下新建一个自己的命令.c文件文件书写格式可以参考该文件夹下的任何一个.c文件,最后如果想要该文件被编译,必须在该路径下的MakeFile中定义
    COBJS-y += 文件名.o该语句中的文件名表示你创建的.c文件,-y表示必须被编译

    总结:
    1.选中和自己板子适配的uboot启动文件,拷贝一个完全一样的文件夹
    2.观察主MakeFile下的文件编译方法,调整并编译拷贝的文件夹,可以编译通过生成一个二进制xx.bin文件。
    3.如果编译然后烧写到SD卡中该文件可以直接启动则为最理想的状态,如果不能启动,需要我们对uboot的启动进行修改,直到成功启动,看见uboot操作界面。(这一步参考上面的第四点)
    4.看见操作界面后某些功能无法启用,比如网络等,则需要我们根据自己手上的板子来针对性的编写程序,以完成一个完整的uboot移植。(这一步为该步骤中的重难点)

    第三步:编译并加工源码(这一步的具体内容仅适应Samsung的origen)

    编译: root@ubuntu:~/u-boot-2013.01# make fs4412 加工:
    1.将工具文件夹拷到u-boot-2013.01目录
    root@ubuntu:~/u-boot-2013.01#
    cp /mnt/hgfs/E/class/201201/code/day3/tool_bin/ . -r
    2. 进入工具文件夹执行mk_uboot.sh
    root@ubuntu:~/u-boot-2013.01# cd tool_bin
    root@ubuntu:~/u-boot-2013.01/tool_bin# ./mk_uboot.sh
    //放开注释cp
    …/u-boot.bin .

    第四步:烧写测试

    将生成好的img镜像文件通过SD卡烧写工具烧写进去即可。

    展开全文
  • 1. 选择合适的官方原版uboot 1.1 官方原版uboot的版本 (1)版本号。刚开始是1.3.4,后来变成2009.08 (2)新版和旧版的差别。uboot的架构很早就定下来了,然后里面普遍公用的东西(common目录下、drivers目录下、fs目录...

    注:以下内容来自朱老师物联网大讲堂课件

    1. 选择合适的官方原版uboot

    1.1 官方原版uboot的版本

    (1)版本号。刚开始是1.3.4,后来变成2009.08
    (2)新版和旧版的差别。uboot的架构很早就定下来了,然后里面普遍公用的东西(common目录下、drivers目录下、fs目录下等···)在各个版本之间几乎是完全一样的。差别最大的是board和cpu目录,这两个目录正是单板(开发板)相关的。越新的uboot版本支持越多的开发板(CPU),所以越新的uboot越庞大。
    (3)并不是越新的版本就越好。越新的uboot中会多出更多的开发板的支持代码,如果我们的开发板并不是很新,就没必要去用很新版本的uboot。因为多出来的代码自己也用不到而且还会成为累赘。
    为了方便学习我们这里也使用2013.10的版本

    1.2 官方原版uboot的来源

    uboot可以有3种获取途径:uboot官方、SoC官方如(三星)、具体开发板的官方(如:九鼎)。
    我们选择从官方下载(ftp://ftp.denx.de/pub/u-boot/)

    1.3 新版uboot配置体系的改变

    (1)在最新的uboot版本(准确的说是2013.10到2014.10中的某个版本)中,uboot的文件体系发生了一个很大的变化。这个变化就是uboot引入了linux kernel的配置体系(Kbuild、Kconfig、menuconfig),从而让我们可以在图形界面下,像配置内核一样配置uboot。
    (2)所以新版本的uboot配置时和我们之前的课程讲的就不同了。我们移植时不能选择这种配置方式更改之后的uboot版本。我们要选择更改之前的。
    (3)新版本的配置方式本质上和linux kernel一样的,所以在学完linux kernel移植后自己就能看懂,因此不用担心。

    使用2013.10对比最新的2020.10 文件结构区别如下(左边是2013.10文件,右边是2020.10文件)
    在这里插入图片描述
    使用2013.10对比最新的2020.10 文件夹结构区别如下(左边是2013.10文件夹,右边是2020.10文件夹)
    在这里插入图片描述
    可以发现有80%的文件夹结构是相同的,但外面的文件的差异就比较大了,这里我们先不深入探究。

    因为我们的S5PV210是比较早的产品,我们选择2013.10版本进行实验移植。

    注意:实践工作中一般是从SoC厂商的uboot出发移植的
    在工作中一般是不需要从uboot官方版本出发去做移植的,而是从SoC厂商提供的开发板配套的uboot去做移植的。

    文档后续我们提到的都是2013.10版的uboot

    2. 确定我们要移植的board模板

    2.1 文件夹结构分析、主要文件检视

    总的来说,文件夹结构和以前基本一样。不同的主要是lib,以前是lib_arm和lib_generic,现在是arch和lib。arch目录下放的是和cpu架构有关的东西。
    总的来说,2013.10版本的uboot在结构上和1.3.4版本的uboot还是有所不同的。

    2.2 参照物开发板的选择

    我们开发板使用的CPU是S5PV210,所以要找uboot中针对S5PV210或者S5PC110进行移植的作为参考。
    我们先在board里面找,但是并没有明显的发现,所以我们有一个想法就是将全部文件导入到SI,然后查找关键字S5PV210、S5PC110,主要看configs目录下和board目录下
    关键字S5PC110搜索结果如下:
    S5p_goni.h (u-boot-2013.10\include\configs)
    lowlevel_init.S (u-boot-2013.10\board\samsung\goni)
    关键字S5PV210没有搜索结果

    根据规律,我们应该参考include/configs/s5p_goni.h,对应的board在uboot/board/samsung/goni这个目录。
    结论:
    参照物开发板为:s5p_goni
    配置对应的cpu、board文件夹分别为:
    cpu: u-boot-2013.10\arch\arm\cpu\armv7
    board: u-boot-2013.10\board\samsung\goni

    2.3 删除无关文件和文件夹

    其实不删除也可以,但是删除更好。
    我们已经在board中选择了goni,所以其他的文件都可以删除了。
    通过S5PV210的数据手册可知我们的架构是ARMv7,所以arch->arm->cpu中除过ARMv7其他的架构都可以删除了,arm层除过arm也都可以删除了。
    在这里插入图片描述
    注意: 对于不确定能不能删的都先不要删除。

    3. 开发板的配置

    3.1 建立SI工程并预解析

    这个工程我们已经在上一步建立了,所以这一步就只需要Project->sync file 即可。
    验证方式就是我们搜索start.s我们发现只能看到一个start文件在armv7中。

    对照之前三星自带的uboot,我们发现:
    (1)2013.10版本的uboot的Makefile中使用了boards.cfg文件,因此在配置uboot时make xxx_config,这个xxx要到boards.cfg文件中查找。
    (2)其实就相当于把以前的版本的uboot中各种开发板的配置部分规则抽离出来写到了Makefile中,然后把配置信息部分写到了一个独立文件boards.cfg。

    以前的版本(三星的为例):

    smdkv210single_config :	unconfig
    	@$(MKCONFIG) $(@:_config=) arm s5pc11x smdkc110 samsung s5pc110
    	@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/smdkc110/config.mk
    
    MKCONFIG	:= $(SRCTREE)/mkconfig
    

    现在的版本(2013.10)

    %_config::	unconfig
    	@$(MKCONFIG) -A $(@:_config=)
    
    MKCONFIG	:= $(SRCTREE)/mkconfig
    

    总结:以前是直接在Makefile中进行传参的,这样导致程序会越来越大,所以后面的版本选择了将配置信息写到了一个独立文件boards.cfg,我们实际使用时直接根据去匹配调取。
    在这里插入图片描述

    3.2 make s5p_goni_config

    问题: 那么现在的配置信息是如何工作的呢?
    我们在主Makefile中发现了如下的程序

    
    MKCONFIG	:= $(SRCTREE)/mkconfig
    export MKCONFIG
    
    %_config::	unconfig
    	@$(MKCONFIG) -A $(@:_config=) //:_config=表示使用空格替换_config
    
    

    举例说明:
    第一步、当我们make s5p_goni_config 时,会执行如下的指令,也就是给mkconfig传参

    (SRCTREE)/mkconfig -A s5p_goni 
    

    在这里插入图片描述

    第二步、到了mkconfig脚本中了。在24到35行中使用awk正则表达式将boards.cfg中与刚才$1(s5p_goni)能够匹配上的那一行截取出来赋值给变量line,然后将line的内容以空格为间隔依次分开,分别赋值给$1、$2···$8。
    注意在解析完boards.cfg之后,$1到$8就有了新的值。
    $1 = Active
    $2 = arm
    $3 = armv7
    $4 = s5pc1xx
    $5 = samsung
    $6 = goni
    $7 = s5p_goni
    $8 = -
    第三步、对几个重要的变量进行传参
    arch="$2"=arm
    cpu=armv7
    soc="$4"=s5pc1xx
    vendor="$5"=samsung
    board="$6"=goni
    这样就将配置信息传给了mkconfig,方可进行后续的操作。

    4.主Makefile的修改

    4.1 符号链接

    这部分和我们之前的是一模一样的------>嵌入式之uboot的配置和编译过程学习笔记
    (1)include/asm -> arch/arm/include/asm
    (2)include/asm/arch -> include/asm/arch-s5pc1xx
    (3)include/asm/proc -> include/asm/proc-armv
    最后创建了include/config.h文件。

    4.2 Makefile中添加交叉编译工具链

    官方原版的uboot中CROSS_COMPLIE是没有定义的,需要自己去定义。如果没定义就直接去编译,就会用gcc编译。
    我们将我们之前定义的地址复制到主Makefile的对应位置就好了,注意这里的位置必须和你实际的是对应的。
    CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
    官方的uboot解压后没有烧录程序,所以我们将我们之前使用的sd_fusing复制到当前的目录
    这个时候就可以编译生成烧录文件了。

    5.Uboot2013.10的架构大体分析

    5.1 对start.S进行框架分析

    1.头文件包含
    2.代码开始,先reset进入SVC管理模式
    3.构建异常向量表
    4.读取链接地址
    5.关中断(IRQ、FIQ)
    6.进入cpu_init_cp15(刷新L1 cache的icache和dcache,关MMU)
    7.进入cpu_init_crit(执行lowlevel_init函数关看门狗、设置SRAM、设置中断、uart_asm_init、internal_ram_init)
    8.跳转到 _main(board_init_f、relocate_code、board_init_r)

    说明
    (1)cpu_init_crit函数成功初始化串口后,转入_main函数,函数在arch/arm/lib/crt0.S文件中。
    (2)在crt0.S中首先设置栈,将sp指向DDR中的栈地址;然后调用board_init_f函数进行板级初始化。函数在arch/arm/lib/board.c中。
    (3)以前三星提供的uboot板级初始化是在start_armboot中,我们目前移植的这个版本uboot中,把以前uboot的第二阶段start_armboot函数分成了2部分:board_init_r + board_init_f
    (4)board_init_f中肯定是做了板级初始化,board_init_r中进入了uboot的命令行。

    5.2 uboot2013.10版本中移植思路

    在uboot2013.10版本中思路:uboot的第二阶段就在crt0.S文件中,第二阶段的入口就是_main函数。第一阶段工作主要就是cpu_init_crit函数,所以我们要在cpu_init_crit函数中添加DDR初始化和uboot的重定位。
    那我们移植uboot启动第一阶段的流程为:

    1. 先在cpu_init_crit函数中添加DDR初始化
    2. 在start.S中bl _main之前添加uboot的重定位
    3. 长跳转到DDR开始第二阶段,将bl _main改成ldr pc, __main(__main: .word _main)长跳转

    6. Uboot启动第一阶段的实现

    6.1 程序进入lowlevel_init并打印出debug字符“OK”

    6.1.1 解决SD卡检验和不能通过

    实验现象:出现了两次SD checksum Error,uboot不能启动
    现象分析:出现两次就说明我们的SD卡的校验失败(正常应该是一次,也就是1st启动被破坏)
    解决思路:要不就是uboot.bin原材料的问题,要不就是sd_fusing 这个程序的问题
    解决办法:先对比uboot.bin的头信息,我们发现正常的uboot比出错的uboot多出了16个字节的头,对照我们的sd_fusing中的镜像制作程序,我们知道SD卡的镜像制作是跳过16个字节开始计算checksum的,但是出错的uboot显然在最开始并没有预留16字节的头,所以我们添加上即可。

    	.word 0x2000
    	.word 0x0
    	.word 0x0
    	.word 0x0
    

    在这里插入图片描述

    6.1.2 串口无输出

    发现问题

    实验现象:按下按键出现了一次SD checksum Error ,后续无任何输出
    现象分析:说明我们的SD卡第二次启动正常了,就是串口现在无输出
    解决思路:设置断点,确定故障区域,因为现在串口不工作,我们无法通过串口观察,所以我们可以设置一些硬件来观察,如led的点亮。
    为了方便观察我们先设置开发板置锁。
    如下为我们添加的位置

    //add power lock
    	ldr r0, =0xE010E81C
    	ldr r1, =0x301
    	str r1, [r0]
    
    
    #define GPJ0CON	0xE0200240
    #define GPJ0DAT	0xE0200244
    
    
    // 第一步:把所有引脚都设置为输出模式,代码不变
    	ldr r0, =0x11111111 		// 从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数
    	ldr r1, =GPJ0CON			// 是合法立即数还是非法立即数。一般写代码都用ldr伪指令
    	str r0, [r1]				// 寄存器间接寻址。功能是把r0中的数写入到r1中的数为地址的内存中去
    
    //熄灭第一个led
    	ldr r0, =((1<<3) | (0<<4) | (0<<5))	// 清清楚楚的看到哪个灭,哪个是亮
    	ldr r1, =GPJ0DAT
    	str r0, [r1]				// 把1写入到GPJ0DAT寄存器中,引脚即输出高电平,LED熄灭
    
    	
    /*
     * Setup vector:
     * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
     * Continue to use ROM code vector only in OMAP4 spl)
     */
    	
    #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
    	/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
    	mrc	p15, 0, r0, c1, c0, 0	@ Read CP15 SCTRL Register
    	bic	r0, #CR_V		@ V = 0
    	mcr	p15, 0, r0, c1, c0, 0	@ Write CP15 SCTRL Register
    
    	/* Set vector address in CP15 VBAR register */
    	ldr	r0, =_start
    	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR
    #endif
    
    
    	// 第2步:熄灭第二个led
    		ldr r0, =((1<<3) | (1<<4) | (0<<5))	// 清清楚楚的看到哪个灭,哪个是亮
    		ldr r1, =GPJ0DAT
    		str r0, [r1]				// 把1写入到GPJ0DAT寄存器中,引脚即输出高电平,LED熄灭
    
    	/* the mask ROM code should have PLL and others stable */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    	bl	cpu_init_cp15
    	bl	cpu_init_crit
    #endif
    
    	// 第3步:熄灭第三个led
    		ldr r0, =((1<<3) | (1<<4) | (1<<5)) // 清清楚楚的看到哪个灭,哪个是亮
    		ldr r1, =GPJ0DAT
    		str r0, [r1]				// 把1写入到GPJ0DAT寄存器中,引脚即输出高电平,LED熄灭
    
    	bl	_main
    
    

    编译运行
    实验现象:开发板可以置锁,第一个和第二个LED熄灭了,第三个并没有熄灭
    现象分析:说明问题出现在LED2之后LED3之前,也就是如下的代码:

    	/* the mask ROM code should have PLL and others stable */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    	bl	cpu_init_cp15
    	bl	cpu_init_crit
    #endif
    

    逐步继续缩小范围,最后发现在cpu_init_crit这个函数里,b lowlevel_init不能跳转成功

    解决问题

    现象分析

    • 三星S5PV210要求BL1大小为8KB,因此uboot第一阶段代码必须在整个uboot镜像的前8KB内,否则跳转不到。
    • 对比三星移植版本的uboot的u-boot.lds和官方版本uboot的连接脚本u-boot.lds(注意这两个版本的uboot的连接脚本的位置是不同的),就发现lowlevel_init.S的代码段没有被放在前面。

    解决方法:在u-boot.lds中start.o后面添加board/samsung/goni/lowlevel_init.o (.text*),这个就保证了lowlevel_init函数被连接到前面8kb中去。也就是人为控制其优先处理。

    编译报错,lowlevel_init重复定义了。
    在这里插入图片描述
    为什么会重复定义?
    因为lowlevel_init这个函数被连接时连接了2次。一次是board/samsung/goni这个目录下生成时连接了1次,第2次是连接脚本最终在连接生成u-boot时又连接了一次,所以重复定义了。
    解决思路,让board/samsung/goni中的只编译不连接,最后在链接脚本中链接。
    如何解决:在第一次链接的Makefile中,我们使用LOWL变量替换原来的SOBJS,然后在最后链接时不要添加LOWL就好了。

    include $(TOPDIR)/config.mk
    
    LIB	= $(obj)lib$(BOARD).o
    
    COBJS-y	:= goni.o onenand.o
    #SOBJS	:= lowlevel_init.o
    LOWL    := lowlevel_init.o cpu_init.o
    SRCS    := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
    OBJS	:= $(addprefix $(obj),$(COBJS-y))
    SOBJS	:= $(addprefix $(obj),$(SOBJS))
    
    $(LIB):	$(obj).depend $(LOWL) $(OBJS)
    	$(call cmd_link_o_target, $(SOBJS) $(OBJS))
    

    使用串口做节点
    其实串口在内部的iROM已经初始化过了,所以我们可以直接使用,毕竟SD checksum Error也是通过串口输出的。
    所以我们要确认出现问题的位置的话,后续我们就可以设置多个节点

    ldr	r1, =0x4F4F4F4F
    ldr r2, =0XE2900820       //设置为串口2 
    str	r1, [r2]		@'O'
    

    编译运行:可以观察到串口输出O,并且LED全熄灭,说明解决了跳转的问题,现在程序可以跳转到lowlevel_init中去执行了。

    6.2 初始化DDR

    三星版本的uboot:在lowlevel_init.S中调用mem_ctrl_asm_init实现的。
    uboot2013中:没有进行DDR的初始化
    移植的方法:如果有就直接更改(我们实际是没有可以使用的),所以我们的办法就是使用三星版本的uboot中DDR初始化函数在cpu/s5pc11x/s5pc110/cpu_init.S文件中,直接将这个文件移植过来即可。

    移植初始化DDR的具体步骤

    1. 通过SI找到三星的DDR初始化代码发现是mem_ctrl_asm_init函数,这个代码在cpu/s5pc11x/s5pc110/cpu_init.S文件中,所以我们直接将其移植到我们的u-boot-2013.10\board\samsung\goni中,也顺带加到我们的makefile中(还要更改链接脚本)
    2. 为了方便查看,避免不必要的错误,我们先将cpu_init.S中没有用的程序删除(对照三星官方的条件编译)
    3. 添加头文件s5pc110.h到include目录下,更新整个工程。
    4. 添加cpu_init.S中未定义的宏
    5. 对头文件s5pc110.h进行处理
      1)#include <asm/hardware.h>先注释掉这个头文件,如果后续程序报错我们再改,如果不注释掉我们担心会欺骗了编译器,导致后续的问题
      2)然后我们先注释掉s5pc110.h这个头文件中没有被定义的宏
      __REG(实验发现不移植这部分使用默认的也可以)
    6. 在lowlevel_init程序中调用mem_ctrl_asm_init函数,并且输出‘K’
    7. 编译运行发现串口输出了OK字符,说明我们的初始化程序已经可以正常工作了。

    注意:如果在修改文件过程中,需要对比文件或者文件夹可以使用Beyond Compare 4工具
    总结:在移植过程中我们要一直顺着程序的运行这条路,缺什么补什么,多什么删什么(也可不删),在头文件的调用过程中经常遇到互相调用,不确定的我们就先注释掉,后续若导致程序编译出错我们再去检查释放。因为整个程序是一张网,我们如果保留了没必要的头文件,那就可能要移植更多被他调用的文件。所以我们就先让一条线拉通,后续根据需要进行“织网”。

    6.3 添加重定位

    三星版本的重定位:设置栈(准备调用C函数)->确认是否需要重定位(我们以冷启动为例)->确认启动方式(mmcsd_boot)->movi_bl2_copy(movi.c)->after_copy->清bss->长跳转到_start_armboot
    uboot2013.10重定位:_main->board_init_f->relocate_code->board_init_r
    结论:虽然uboot2013.10也有重定位的代码,但是我们需要改动的地方比较多,所以我们就直接移植三星版本的重定位
    重定位思路
    (1)确定代码添加位置
    按照我们之前的一直思路,重定位部分代码应该在DDR初始化之后和uboot第二阶段来临前之间。
    uboot的第一阶段和第二阶段的划分并不是绝对的,唯一必须遵循的原则就是第一阶段不能大于8KB。所以uboot的第一阶段最少要完成DDR初始化和重定位,最多不能超过8KB。在满足这些条件时,第一阶段和第二阶段的接点可以随便挑。
    找到合适的地方来写重定位代码,重定位之后远跳转到第二阶段的入口。
    (2)增加调试代码,我们使用串口打印来调试
    (3)移植三星的重定位代码和文件到工程中
    主要包含start.S中的设置栈(准备调用C函数)->确认是否需要重定位(我们以冷启动为例)->确认启动方式(mmcsd_boot)部分,和movi_bl2_copy(movi.c),以及对应的头文件
    (4)添加编译文件,删除多余的部分,进行初步编译
    移植实践
    (1)我们添加在cpu_init_crit之后,_main之前
    (2)添加在重定位之前输出字符‘A’在_main函数中输出‘B’
    (3)添加start.S内容、movi.c movi.h 文件,注意更改对应的copy脚本,我们先将不使用的函数删除掉,因为它们的内部需要一些特定的宏,等我们使用时再添加。
    (4)
    编译1
    实验现象:编译很快fail,显示很多gpio.h:99: error: field ‘mp2_0’ has incomplete type
    解决办法:查询得知,这是不完整类型的问题,不完整类型是一种用于描述标识符而无法确认该描述符大小的类型,对照处理过的宏定义发现是将汇编的.word命令放在了头文件中,所以从.h中移出即可解决。
    编译2
    实验现象:编译fail,显示:movi.c:30: error: ‘CFG_ENV_SIZE’ undeclared (first use in this function)
    现象分析:在movi.c中未定义CFG_ENV_SIZE,因为这个宏定义有可能是宏定义嵌套的
    解决办法:找出未定义的CFG_ENV_SIZE,在s5p_goni.h中定义
    编译3
    实验现象
    警告:movi.c:36: note: expected ‘u32 *’ but argument is of type ‘int’
    错误:include/movi.h:234: error: expected specifier-qualifier-list before ‘member_t’

    现象分析:对于警告先不处理,先处理error,查询可知expected specifier-qualifier-list before表示有未被定义的变量。
    解决办法:我们屏蔽了movi.h中# error TCM_BASE or BL2_BASE is not defined这句,就没有报错了,因为这句在movi.h中显示很奇怪。
    编译4
    实验现象:出现u-boot contains relocations other than R_ARM_RELATIVE
    make: *** [checkarmreloc] Error 1
    解决办法:在Linux中查找关键字R_ARM_RELATIVE,指令:grep “R_ARM_RELATIVE” -nR *
    在这里插入图片描述
    我们在Makefile中找到了如下的代码,大体上看是用来检查重定位是否是按照R_ARM_RELATIVE,这里我们先屏蔽掉
    在这里插入图片描述
    编译5
    实验现象:编译通过,但是串口只是输出了OK
    现象分析:说明我们在重定位之前代码已经出问题了,也就是说是在lowlevel_init函数中
    解决办法:使用串口打印确认卡的位置,如果无用则删除。
    编译6
    实验现象:程序无法跳转到_main
    现象分析:可能的原因,重定位失败,地址无法跳转,程序未被编译
    解决过程
    1.将长跳转改为bl短跳转发现可以正常进入_main函数,证明了整个编译过程是没问题
    2.所以就是重定位部分出现了问题,那么我们就要确认重定位的几个关键因素链接地址、代码copy函数。
    最后发现是CFG_PHY_UBOOT_BASE (uboot在MEM中的起始地址)和CONFIG_SYS_TEXT_BASE(链接地址)地址不一致导致的
    修改之后我们可以看到有板子的硬件信息显示了
    在这里插入图片描述

    总结:因为DDR已经初始化,所以我们有大片的内存可以使用,这就是我们要重定位的原因,uboot重定位的过程为
    1)设定DDR中uboot的起始地址
    2)判断当前的运行地址和1中的地址是否一致
    3)一致则跳过重定位,不一致则调用movi_bl2_copy函数copy
    4)长跳转至DDR中继续运行

    7.Uboot启动第二阶段的实现

    7.1 Uboot2013.10函数框架梳理

    先梳理uboot2013.10第二阶段的函数框架,对我们后续的移植会帮助很大

    board_init_f
    	init_sequence
    		arch_cpu_init(重命名并设置CPU id)
    		mark_bootstage
    		board_early_init_f()
    		timer_init(设置Timer 4)
    		board_postclk_init()
    		get_clocks()
    		env_init(初始化环境变量)
    		init_baudrate(设置波特率)
    		serial_init(串口通信建立)
    		console_init_f(控制台阶段1初始化)
    		display_banner(显示uboot标语日期、时间、自定义)
    		print_cpuinfo(CPU名字和id以及时钟信息)
    		checkboard(board name)
    		init_func_i2c(初始化i2c功能)
    		dram_init(配置DDR的数量、大小、起始地址)
    	设置arch_number到全局变量
    	interrupt_init
    	设置baudrate到全局变量
    	dram_init_banksize
    	display_dram_config(显示DRAM的配置)
    	
    relocate_code(自带的重定位,我们未使用)
    
    board_init_r
    	enable_caches(开icache)
    	board_init(获取机器码和参数个数)
    	set_cpu_clk_info(函数为空)
    	serial_initialize(串口初始化)
    	logbuff_init_ptrs()
    	mem_malloc_init()
    	arch_early_init_r()
    	power_init_board(PMIC初始化)
    	输出flash信息
    	输出NAND信息
    	输出MMC信息
    	初始化环境变量
    	arm_pci_init()
    	stdio_init(devices list)
    	jumptable_init(跳转表)
    	console_init_r(控制台设置)
    	checkboard(输出board信息)
    	enable_interrupts(开中断)
    	board_late_init()
    	输出NET信息
    	进入命令行main_loop
    
    

    在梳理框架的过程中我们更改了一些简单的配置(如:banner 设置、board name、DRAM size),移除了onenand部分的代码,现在可以进入命令行了。
    在这里插入图片描述
    名词解释: MiB
    MiB,全称“mebibyte”,是数字信息中的一个字节单位, 前缀“mebi”等于2^20,1 mebibyte等于1,048,576字节。
    每1024Byte为1KB,每1024KB为1MB,每1024MB为1GB,每1024GB为1TB,而在国际单位制中TB、GB、MB、KB是“1000进制”的数,为此国际电工协会(IEC)拟定了"KiB"、“MiB”、“GiB"的二进制单位,专用来标示“1024进位”的数据大小。
    总的来说就是国际上为了更严格的区分1000进制和1024进制,所以使用了MB和MiB,我们平时使用一般不会严格区分。

    7.2 一步步完善uboot启动第二阶段的细节

    7.2.1 board_init_f中实现的函数

    init_sequence中
    print_cpuinfo

    print_cpuinfo函数用来打印CPU信息,我们现在打印的信息是错误的
    在这里插入图片描述

    实现目标1:CPU名称的实现(S5PV210)
    实现步骤:对比、分析、移植

    1)对比
    三星版本的print_cpuinfo通过条件编译,直接输出

    printf("\nCPU:  S5PV210@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
    

    uboot2013.10:通过调用函数获取cpu名称、id、以及时钟频率

    int print_cpuinfo(void)
    {
    	char buf[32];
    
    	printf("CPU:\t%s%X@%sMHz\n",
    			s5p_get_cpu_name(), s5p_cpu_id,
    			strmhz(buf, get_arm_clk()));
    
    	return 0;
    }
    

    2)分析:对比发现uboot2013.10中发现是使用unsigned int s5p_cpu_id = 0xC100的方式输出字符C,但我们的V是无法通过这种方式实现的,所以我们直接移植三星的。
    3)移植

    int print_cpuinfo(void)
    {
    	char buf[32];
    	printf("\nCPU:  S5PV210@%sMHz(OK)\n", strmhz(buf, get_arm_clk()));
    	return 0;
    }
    

    实现目标2:时钟频率的修改(@1000MHz(OK)),并且显示出重要的频率值
    关键函数

    1. 获取s5p_cpu_id的函数s5p_set_cpu_id
      这个函数的实现过程就是读取特定寄存器中的值来获取id,PC110/100还有我们的V210 都是用0xE0000000这个地址来存放,所以我们V210启动默认的是110
      在这里插入图片描述
    #define S5PC100_PRO_ID		0xE0000000
    
    static inline void s5p_set_cpu_id(void)
    {
    	s5p_cpu_id = readl(S5PC100_PRO_ID);
    	s5p_cpu_id = 0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12);
    }
    
    1. 生成对应type的宏定义函数,这个函数的作用就是起到条件运行的作用,如果读到的chip id和自己的id一致,则返回1
    //宏定义来生成对应type的函数,该函数根据s5p_cpu_id确认是哪个CPU
    #define IS_SAMSUNG_TYPE(type, id)			\
    static inline int cpu_is_##type(void)		\
    {						                	\
    	return s5p_cpu_id == id ? 1 : 0;		\
    }
    
    IS_SAMSUNG_TYPE(s5pc100, 0xc100)
    IS_SAMSUNG_TYPE(s5pc110, 0xc110)
    //如上的宏定义展开
    static inline int cpu_is_s5pc100(void) 
    { 
    	return s5p_cpu_id == 0xc100 ? 1 : 0; 
    };
    static inline int cpu_is_s5pc110(void) 
    { 
    	return s5p_cpu_id == 0xc110 ? 1 : 0; 
    };
    
    
    1. 使用宏定义函数SAMSUNG_BASE(device, base)来实现samsung_get_base_##device(void),这么做的好处是我们在使用特定模块的基地址时,直接调用这个函数就可以,函数内部会自动进行CPU的判断。
    #define SAMSUNG_BASE(device, base)				\
    static inline unsigned int samsung_get_base_##device(void)	\
    {								\
    	if (cpu_is_s5pc100())					\
    		return S5PC100_##base;				\
    	else if (cpu_is_s5pc110())				\
    		return S5PC110_##base;				\
    	else							\
    		return 0;					\
    }
    
    SAMSUNG_BASE(clock, CLOCK_BASE)
    SAMSUNG_BASE(mmc, MMC_BASE)
    SAMSUNG_BASE(timer, PWMTIMER_BASE)
    SAMSUNG_BASE(uart, UART_BASE)
    SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
    //我们宏定义展开SAMSUNG_BASE(clock, CLOCK_BASE)
    static inline unsigned int samsung_get_base_clock(void)	\
    {								\
    	if (cpu_is_s5pc100())					\
    		return S5PC100_CLOCK_BASE;				\
    	else if (cpu_is_s5pc110())				\
    		return S5PC110_CLOCK_BASE;				\
    	else							\
    		return 0;					\
    }
    
    
    1. 通过如上三个函数的分析,可知我们的clock执行的是s5pc110_get_arm_clk()
    unsigned long get_arm_clk(void)
    {
    	if (cpu_is_s5pc110())
    		return s5pc110_get_arm_clk();
    	else
    		return s5pc100_get_arm_clk();
    }
    
    /* s5pc110: return ARM clock frequency */
    static unsigned long s5pc110_get_arm_clk(void)
    {
    //通过samsung_get_base_clock得到clock的基地址
    //定义一个s5pc110_clock 结构体类型的指针clk指向clock的基地址
    //最后使其返回s5pc110_clock 结构的值
    	struct s5pc110_clock *clk =
    		(struct s5pc110_clock *)samsung_get_base_clock();
    	unsigned long div;
    	unsigned long dout_apll, armclk;
    	unsigned int apll_ratio;
    
    	div = readl(&clk->div0);
    
    	/* APLL_RATIO: [2:0] */
    	apll_ratio = div & 0x7;
    
    	dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
    	armclk = dout_apll;
    
    	return armclk;
    }
    
    //这个结构体的排布就是按照其在寄存器中的位置构成的,res是用来填充未定义/未使用的寄存器
    //这么做是为了在C语言调用时可直接通过指针进行访问我们在汇编阶段已经配置的寄存器。
    struct s5pc110_clock {
    	unsigned int	apll_lock;
    	unsigned char	res1[0x4];
    	unsigned int	mpll_lock;
    	unsigned char	res2[0x4];
    	unsigned int	epll_lock;
    	unsigned char	res3[0xc];
    	unsigned int	vpll_lock;
    	unsigned char	res4[0xdc];
    	unsigned int	apll_con;
    	unsigned char	res5[0x4];
    	unsigned int	mpll_con;
    	unsigned char	res6[0x4];
    	unsigned int	epll_con;
    	unsigned char	res7[0xc];
    	unsigned int	vpll_con;
    	unsigned char	res8[0xdc];
    	unsigned int	src0;
    	unsigned int	src1;
    	unsigned int	src2;
    	unsigned int	src3;
    	unsigned char	res9[0xf0];
    	unsigned int	div0;
    	unsigned int	div1;
    	unsigned int	div2;
    	unsigned int	div3;
    	unsigned int	div4;
    	unsigned char	res10[0x1ec];
    	unsigned int	gate_d00;
    	unsigned int	gate_d01;
    	unsigned int	gate_d02;
    	unsigned char	res11[0x54];
    	unsigned int	gate_sclk0;
    	unsigned int	gate_sclk1;
    };
    

    移植原理:根据我们对如上几个函数的分析,我们知道uboot2013.10的时钟系统是在汇编的lowlevel_init中进行了初始化,然后在clock中根据需要进行获取。所以我们直接移植汇编部分的代码。

    移植步骤
    1.我们先在lowlevel_init中调用系统的system_clock_init函数,发现输出是800MHz
    2.然后我们将三星的汇编时钟初始化移植到我们的lowlevel_init中,根据其条件进行删改
    编译报错:

    lowlevel_init.S:290: Error: constant expression expected -- `ldr r1,=(1<<31|APLL_MDIV<<16|APLL_PDIV<<8|APLL_SDIV)'
    lowlevel_init.S:293: Error: constant expression expected -- `ldr r1,=(1<<31|MPLL_MDIV<<16|MPLL_PDIV<<8|MPLL_SDIV)'
    

    原因:这几个变量有赋值,在移植过程中漏掉了。
    编译已经可以实现1000MHz的显示了。
    最后实现各个重要时钟频率
    这里的设置主要的问题是函数的调用,自带的是static类型的函数,我们要将其转化为外部可以调用的函数
    出现了频率值异常,我们最后发现是因为strmhz函数的问题
    经过调试我们已经可以正常输出一些重要的频率信息了。
    在这里插入图片描述

    7.2.2 board_init_r中实现的函数

    在这个函数中我们主要实现SD/MMC的初始化

    问题:系统默认是onenand启动,但我们实际是MMC/SD启动,现在就是我们的环境变量不能保存。
    这里有一个问题就是之前我们直接移除了onenand的代码,这样虽然可以使程序继续运行,但是导致的结果就是配置的过程还是onenand,所以我们这次直接更改配置文件
    解决方法:设定系统为MMC/SD启动,并进行必要的移植
    实现步骤
    1.解决onenand的配置问题,让系统不对onenand相关代码进行编译,使系统对MMC相关的代码进行编译
    2.找到出问题的代码位置
    3.移植MMC/SD初始化的代码到程序中
    实现过程
    第一步:我们更改添加了配置头文件s5p_goni.h

    //#define CONFIG_ENV_IS_IN_ONENAND	1
    #define CONFIG_ENV_IS_IN_MMC	1
    #define CONFIG_SYS_MMC_ENV_DEV		0
    

    在串口出现了error,并且只侦测到了一个devices
    在这里插入图片描述
    第二步:顺着MMC初始化代码查看为什么只出现了一个device
    操作控制寄存器的方式:通过结构体将寄存器进行分类打包,直接对结构体进行操作
    在这里插入图片描述

    mmc_initialize
    (drivers/mmc/mmc.c)
    	board_mmc_init //配置MASSMEMORY_EN和MMC的GPIO、得到MMC对应通道的地址、通道、总线宽度
    	(board/samsung/goni/goni.c)
    

    这里的board_mmc_init中的SD card部分依赖特定的宏,这里我们没有使用所以我们也只能看到一个device,解决的办法就是去掉条件
    这样我们就能显示两个devices了
    在这里插入图片描述
    第三步:找出error的代码位置

    mmc_initialize
    (drivers/mmc/mmc.c)
    	board_mmc_init //配置MASSMEMORY_EN和MMC的GPIO、得到MMC对应通道的地址、通道、总线宽度
    	(board/samsung/goni/goni.c)
    	do_preinit 
    	(drivers/mmc/mmc.c)
    		mmc_start_init
    		(drivers/mmc/mmc.c)
    			mmc_go_idle
    				mmc_send_cmd
    					mmc->send_cmd = sdhci_send_command;
    					(drivers/mmc/sdhci.c)
    						sdhci_transfer_data(error 信息出现的代码)
    

    第四步:错误原因分析
    sdhic.c中的所有函数构成了三星210CPU的SD/MMC控制器的驱动。这里面的函数是三星公司的工程师写的,内容就是用来控制210CPU的内部的SD/MMC控制器和外部的SD卡通信的。这就是所谓的驱动。
    sdhci_transfer_data函数出错,说明是SoC的SD/MMC控制器和外部SD卡(其实现在用的是SD0的iNand)的数据传输出了问题。(细节分析发现是控制器内部有一个中断状态错误标志被置位了。)
    第五步:解决方案分析
    两条思路:第一是去逐行的分析SD卡驱动实现(分析中要对SD卡通信协议和210这个SoC的SD控制器非常熟悉),然后发现错误所在,然后修改代码解决问题;第二个是投机取巧的方法,就是把原来三星移植版本的uboot中的SD/MMC驱动整个移植过来替换掉uboot2013.10中的MMC驱动。其实还有第三条折中思路,就是综合第一种和第二种,譬如参考三星移植版本的uboot中的驱动实现来修补uboot2013.10中的驱动实现。
    第六步:对比三星版本的和uboot2013.10的区别

    三星版本
    mmc.c drivers/mmc/mmc.c
    s3c_hsmmc.c drivers/mmc/s3c_hsmmc.c(配置MMC端并赋值)
    cpu.c cpu/s5pc11x/cpu.c(调用setup_hsmmc.c和s3c_hsmmc.c)
    setup_hsmmc.c cpu/s5pc11x/setup_hsmmc.c(设置时钟配置GPIO,可以理解为CPU控制器端的配置)
    
    uboot2013.10版本
    mmc.c drivers/mmc/mmc.c
    sdhci.c  drivers/mmc/sdhci.c(mmc和cpu控制器沟通)
    s5p_sdhci.c  drivers/mmc/s5p_sdhci.c(配置MMC端并赋值)
    goni.c board/samsung/goni/goni.c(配置CPU控制器端的GPIO)
    

    经过分析发现:SD卡驱动要工作要包含2部分内容,一部分是drivers/mmc目录下的是驱动,另外一部分是uboot自己提供的初始化代码(譬如GPIO初始化、时钟初始化)
    第七步:复制必要的文件并修改相应Makefile
    1)移植mmc目录下的文件,屏蔽掉之前的sdhci.c和s5p_sdhci.c,添加s3c_hsmmc.c到工程中
    2)移植cpu.c,因为我们的cpu.c只是一些简单的调用,我们直接将其内容复制到我们board_mmc_init的位置
    3)移植setup_hsmmc.c文件,这里我们要存放的位置就是我们实际使用的位置,这个函数的使用是在board_mmc_init中被调用的,也就是goni.c中,并且修改makefile.
    第八步:对整个程序进行梳理
    查看是否有遗漏或者未修改的地方
    我们就从mmc_initialize开始
    首先进行时钟配置和GPIO的设置(这部分是我们移植的),发现的问题是:
    get_MPLL_CLK时钟函数不能被找到,因为名称不同改为:get_pll_clk(MPLL)
    然后我们查看我们的devices下的文件是否有未定义的
    mmc.c文件中的SD_APP_OP_COND未定义,所以我们直接使用三星的mmc.h覆盖

    基本没有什么明显的问题了,我们下来开始尝试编译
    第九步:编译调试
    出错1:setup_hsmmc.c:2: fatal error: regs.h: No such file or directory
    我们注释掉regs.h 添加s5pc110.h
    出错2 :第二次出现MPLL未定义,我们添加头文件clk.h到项目中
    #include <asm/arch/clk.h>
    出错3 :mmc_write.c:29: error: ‘SD_CMD_ERASE_WR_BLK_START’ undeclared (first use in this function)
    因为我们已经不使用mmc_write,因为mmc_write.o和mmc.o公用一个宏,所以我们直接在Makefile中注释掉。
    再次尝试就可以编译通过了。
    第十步:效果测试
    在这里插入图片描述
    测试1 :我们可以更改bootdelay了,并且可以保存到MMC0 ,重启后bootdelay还是起作用的。
    测试2 :我们通过mmc的指令给iNand中写入88888888,并可以成功读取
    原始地址38000000的数据
    在这里插入图片描述
    写入新的值88888888
    在这里插入图片描述
    将新的值写入到mmc中
    在这里插入图片描述
    再次从mmc中读取38000000处的值
    在这里插入图片描述
    总结:在MMC的初始化这部分,我们首先做的就是将之前的onenand初始化注释掉,让系统编译MMC初始化代码。
    针对自带的mmc初始化,我们如果更改的话难度比较大,所以我们选择直接移植三星版本的mmc初始化,这一过程首先就是对比两者的差异,然后进行初步移植(包括文件的移植、头文件的移植、源代码的删减)。
    完成初步移植后,开始编译,根据编译结果,一步步解决,直到成功编译。

    7.2.3 环境变量的移植

    7.2.3.1 环境变量存储位置的确认

    我们在之前mmc初始化完成后更改过环境变量,发现使可以更改的,并且是保存在MMC(0)中,这个保存的位置我们可以在saveenv中查看。
    在uboot2013.10中函数的格式为do_env_XXX

    //执行do_env_save函数,输出我们要存储的位置,并调用saveenv函数
    static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
    		       char * const argv[])
    {
    	printf("Saving Environment to %s...\n", env_name_spec);
    
    	return saveenv() ? 1 : 0;
    }
    
    //首先遍历找到我们要存储的device,并赋值给mmc
    int saveenv(void)
    {
    	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
    	ssize_t	len;
    	char	*res;
    	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
    	u32	offset;
    	int	ret, copy = 0;
    //判断是否找到了device,并且进行mmc初始化
    	if (init_mmc_for_env(mmc))
    		return 1;
    //这部分应该是从hash表中导出环境变量
    	res = (char *)&env_new->data;
    	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
    	if (len < 0) {
    		error("Cannot export environment: errno = %d\n", errno);
    		ret = 1;
    		goto fini;
    	}
    //进行crc校验
    	env_new->crc = crc32(0, &env_new->data[0], ENV_SIZE);
    
    #ifdef CONFIG_ENV_OFFSET_REDUND
    	env_new->flags	= ++env_flags; /* increase the serial */
    
    	if (gd->env_valid == 1)
    		copy = 1;
    #endif
    //获取我们环境变量要存储的地址mmc_get_env_addr的两个输入型参数为device的结构体指针、环境变量的类型(是否为冗余环境变量),一个输出型参数&offset,表示要存放环境变量的位置
    	if (mmc_get_env_addr(mmc, copy, &offset)) {
    		ret = 1;
    		goto fini;
    	}
    //输出我们要写的MMC类型以及通道
    	printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "",
    	       CONFIG_SYS_MMC_ENV_DEV);
    //写环境变量到mmc大小为CONFIG_ENV_SIZE,
    	if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
    		puts("failed\n");
    		ret = 1;
    		goto fini;
    	}
    
    	puts("done\n");
    	ret = 0;
    
    #ifdef CONFIG_ENV_OFFSET_REDUND
    	gd->env_valid = gd->env_valid == 2 ? 1 : 2;
    #endif
    
    fini:
    	fini_mmc_for_env(mmc);
    	return ret;
    }
    //我们没有定义CONFIG_SYS_MMC_ENV_PART这个宏,所以这部分不执行
    static void fini_mmc_for_env(struct mmc *mmc)
    {
    #ifdef CONFIG_SYS_MMC_ENV_PART
    	if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num)
    		mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV,
    				mmc->part_num);
    #endif
    }
    
    static inline int write_env(struct mmc *mmc, unsigned long size,
    			    unsigned long offset, const void *buffer)
    {
    	uint blk_start, blk_cnt, n;
    //进行对齐,并计算起始扇区和总的扇区大小,所以我们的offset应该是以扇区为单位
    	blk_start	= ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
    	blk_cnt		= ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len;
    
    	n = mmc->block_dev.block_write(CONFIG_SYS_MMC_ENV_DEV, blk_start,
    					blk_cnt, (u_char *)buffer);
    
    	return (n == blk_cnt) ? 0 : -1;
    }
    
    

    下来我们就要考虑我们应该存放环境变量的起始扇区为多少了(原则是不能和BL1和BL2冲突)
    我们先查看我们的烧录文件sd_fusing.sh我们知道我们将BL1烧录到了扇区1开始的位置,将剩余uboot烧录到了49扇区开始的位置
    我们查看我们的DRAM重定位代码,也是将bl2从inand的第49个扇区复制到DRAM。
    根据这里面的MOVI_BL2_POS,我们可以计算出我们环境变量MOVI_ENV_BLKCNT的开始扇区=1+16 = 17,那么我们的offset就为17*512

    #define MOVI_BL2_POS		((eFUSE_SIZE / MOVI_BLKSIZE) + MOVI_BL1_BLKCNT + MOVI_ENV_BLKCNT)
    (((1 * 512) / 512) + ((8 * 1024) / 512) + (0x4000 / 512))
    

    copy_bl2宏进行展开

    #define MOVI_BL2_POS		((eFUSE_SIZE / MOVI_BLKSIZE) + MOVI_BL1_BLKCNT + MOVI_ENV_BLKCNT)
    
    #define eFUSE_SIZE		(1 * 512)	// 512 Byte eFuse, 512 Byte reserved
    #define MOVI_BLKSIZE		512
    #define MOVI_BL1_BLKCNT		(SS_SIZE / MOVI_BLKSIZE)
    #define SS_SIZE			(8 * 1024)
    #define MOVI_ENV_BLKCNT		(CFG_ENV_SIZE / MOVI_BLKSIZE)	/* 16KB */
    #define CFG_ENV_SIZE		0x4000	/* Total Size of Environment Sector */
    
    
    #define MOVI_BL2_BLKCNT		(PART_SIZE_BL / MOVI_BLKSIZE)	/* 512KB */
    #define PART_SIZE_BL		(512 * 1024)
    #define MOVI_BLKSIZE		512
    
    int main()
    {
    copy_bl2(0, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
    			CFG_PHY_UBOOT_BASE, 0);
    					
    copy_bl2(0, (((1 * 512) / 512) + ((8 * 1024) / 512) + (0x4000 / 512)), ((512 * 1024) / 512),
       CFG_PHY_UBOOT_BASE, 0);
    
    copy_bl2(0,49,1024,CFG_PHY_UBOOT_BASE,0)
    			
    }
    

    总结
    iNand分区表检查-env究竟应该放在哪
    (1)测试环境变量是否可以保存,通过开机set设置环境变量然后save,然后关机后重启来测试环境变量的保存是否成功。
    (2)我们的环境变量究竟保存到哪里去了?这个就要去分析代码中的分区表。
    (3)环境变量应该被放在哪里?虽然无法确定ENV一定要放在哪里,但是有一些地方肯定是不能放的,否则将来会出问题。原则是同一个SD卡扇区只能放一种东西,不能叠加,否则就会被覆盖掉。uboot烧录时使用的扇区数是:SD2的扇区1-16和49-x(x-49大于等于uboot的大小)
    (3)从uboot的烧录情况来看,SD2的扇区0空闲,扇区1-16被uboot的BL1占用,扇区17-48空闲,扇区49-x被uboot的BL2占用。再往后就是内核、rootfs等镜像的分区了。系统移植工程师可以根据kernel镜像大小、rootfs大小等来自由给SD分区。
    (4)从uboot的分区情况来看,ENV不能往扇区1-16或者49-x中来放置,其他地方都可以商量。ENV的大小是16K字节也就是32个扇区。

    环境变量相关代码浏览
    (1)目前情况是uboot在SD2中,而ENV在SD0中,所以现在ENV不管放在哪个扇区都能工作,不会有问题。但是我们还是得找到ENV分区所在并且改到不会和uboot冲突,因为将来部署系统时我们会将uboot和kernel、rootfs等都烧录到iNnand中去,那时候也要确保不会冲突。
    (2)static inline int write_env(struct mmc *mmc, unsigned long size,
    unsigned long offset, const void *buffer)
    类似于这种函数,在代码分析中,关键是弄明白各种参数的意义。mmc表示要写的mmc设备,size表示要写的大小,offset表示要写到SD卡的哪个扇区去,buffer是要写的内容。
    (3)CONFIG_ENV_OFFSET这个宏决定了我们的ENV在SD卡中相对SD卡扇区0的偏移量,也就是ENV写到SD卡的哪里去了。经过分析发现这个宏的值为0.所以我们的ENV
    被写到了0扇区开始的32个扇区中。
    (4)写到这里肯定不行,因为和uboot的BL1冲突了。解决方案是改变这个CONFIG_ENV_OFFSET的值,将ENV写到别的空闲扇区去。
    (5)#define MOVI_BL2_POS ((eFUSE_SIZE / MOVI_BLKSIZE) + MOVI_BL1_BLKCNT + MOVI_ENV_BLKCNT) 后面这三个其实分别是1+16+32=49
    其中的1就是扇区0(空闲的),16是就是扇区1-16(uboot的BL1),32就是扇区17-48(存放ENV的),49自然就是uboot的BL2开始扇区了。这种安排是三星移植的uboot版本中推荐的SD卡的分区方式,不一定是唯一的。
    (6)我们参考这个设计,即可实现环境变量不冲突。所以只要将ENV放到17扇区起始的地方即可。

    7.2.3.2 测试环境变量

    测试方法:
    第一步:先查看之前环境变量的存储位置(默认是0扇区)
    在这里插入图片描述
    第二步:擦除inand中之前的环境变量
    我们选择的是直接使用一段无用的代码去覆盖原本0扇区开始,共49扇区的内容
    mmc write 0 30000000 0# 49
    并且这个时候17扇区部分也是乱码
    在这里插入图片描述
    在这里插入图片描述
    第三步:reset后,设定一个环境变量作为标记
    reset后,因为inand中的环境变量已经不能CRC校验通过,所以使用了系统默认的环境变量。
    我们可以设置一个环境变量作为我们观察的标记,我们设置bootdelay = 6(默认是1)
    第四步:查看之前扇区0和17扇区的存储内容
    扇区0的内容
    在这里插入图片描述
    扇区17的内容
    在这里插入图片描述
    在这里插入图片描述
    这样我们就实现了环境变量的的重新分区。
    总结
    环境变量部分主要是要对环境变量在mmc中的排布清楚,直到不应该放什么地方,应该放什么地方。
    其次就是我们在uboot下对mmc命令的使用了
    mmc read 是用来读取mmc特定扇区特定大小的内容到规定的地址缓冲区
    mmc write 是将特定地址的内容写入到我们mmc的特定扇区
    md命令就是显示当下我们缓冲区的内容

    7.2.3.3 移植重要的环境变量

    因为默认的环境变量太过繁琐,我们可以练习将其设置为简洁一点的
    我们直接在头文件中修改相应的宏,目前我们只设置了两个最重要的CONFIG_BOOTARGS / CONFIG_BOOTCOMMAND 宏

    #define CONFIG_BOOTARGS	"console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3 " 
    #define CONFIG_BOOTCOMMAND	"movi read kernel 30008000; bootm 30008000"
    

    7.2.4 网卡移植

    现状: 我们的uboot命令行中ping和tftp命令不能使用
    **解决思路:**先添加网络相关的命令,然后进行网卡移植
    解决过程
    第一步: 通过查找我们发现我们的uboot是有网络相关的函数,只不过是依赖特定的宏,所以我们定义特定的宏即可。
    第二步: 我们的ping命令可以使用后,我们发现串口的NET输出:
    Net: Net Initialization Skipped
    No ethernet found.
    第三步: 查找报错信息出现的位置如下

    int eth_initialize(bd_t *bis)
    {
    	int num_devices = 0;
    	eth_devices = NULL;
    	eth_current = NULL;
    
    	bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
    #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
    	miiphy_init();
    #endif
    
    #ifdef CONFIG_PHYLIB
    	phy_init();
    #endif
    
    	eth_env_init(bis);
    
    	/*
    	 * If board-specific initialization exists, call it.
    	 * If not, call a CPU-specific one
    	 */
    	if (board_eth_init != __def_eth_init) {
    		if (board_eth_init(bis) < 0)
    			printf("Board Net Initialization Failed\n");
    	} else if (cpu_eth_init != __def_eth_init) {
    		if (cpu_eth_init(bis) < 0)
    			printf("CPU Net Initialization Failed\n");
    	} else
    		printf("Net Initialization Skipped\n");
    
    	if (!eth_devices) {
    		puts("No ethernet found.\n");
    		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
    	} else {
    		struct eth_device *dev = eth_devices;
    		char *ethprime = getenv("ethprime");
    	}
    }
    

    第四步: 暂时还不知道怎么改,所以梳理uboot2013的网卡初始化框架

    1.eth_initialize(gd->bd);(board.c中调用该函数)
    	2.eth_env_init(bis);(字面理解是网络的环境变量初始化)
    	3.(board_eth_init != __def_eth_init) 
    	如果3中board_eth_init有被定义则执行自己
    	4.board_eth_init(bis) 
    	如果3中未定义则再次进行5进行判断
    	5.(cpu_eth_init != __def_eth_init)
    	如果5中cpu_eth_init 有被定义,则执行自己cpu_eth_init
    	如果5中也没有定义cpu_eth_init,则输出“Net Initialization Skipped”
    	6.eth_devices判断是否为NULL
    	如果6的结果为NULL,则输出“No ethernet found”
    	如果6的结果不为NULL,则输出网络设备的相关信息
    

    第五步: 解决error :Net Initialization Skipped
    根据第四步我们的分析我们知道了我们的报错信息是因为我们未定义board_eth_init或cpu_eth_init ,因为现在我们已经在第二阶段了,所以我们选择定义板级的初始化我们先将之前我们三星版本的dm9000_pre_init移植到uboot2013的board_init中进行板级的初始化。
    下来我们就要考虑board_eth_init函数中放什么东西了,根据程序我们可知,我们只要保证board_eth_init的返回值大于0就可以解决Net Initialization Skipped这个问题。

    第六步: 解决error :No ethernet found
    我们在第四步已经知道了,这个问题的解决就是要让eth_devices不为空。
    我们直到我们使用的是DM9000 ,所以我们查找DM9000的设备初始化代码dm9000_initialize,然后在上一步的board_eth_init函数中进行调用即可。

    第七步: 实验测试
    我们可以使用ping命令和Ubuntu ping通,并且可以通过tftp下载镜像
    在这里插入图片描述

    8. 总结

    这部分我们主要做了如下的工作
    目标:在uboot官方选择了一个uboot版本进行移植
    思路:顺着程序运行的顺序,逐步通过代码的调试实现一个个功能
    过程

    1. 修改新版本的Makefile的配置文件(新版本将配置参数单独包装成了boards.cfg)
    2. Uboot2013.10的大体框架梳理
    3. 使用led和串口进行调试,实现了启动第一阶段初始化DDR、重定位等
    4. 根据串口打印的信息,我们实现第二阶段CPU信息显示、板载硬件的信息显示,并成功进入命令行
    5. SD/MMC的初始化移植
    6. 环境变量的移植
    7. 网卡的移植

    备注:uboot的移植还没有结束,我们只是实现了一些大体的功能。

    展开全文
  • FS4412系统移植uboot移植实验代码,包括uboot2013源码,三星加密文件,移植需要修改的代码,移植好的能用的代码
  • uboot移植与分析

    2018-04-01 10:50:19
    详细分析mini2440uboot启动过程 记录移植的详细步骤与思路 贴出移植修改的代码
  • iTOP4412 uboot移植教程

    2021-05-29 10:43:47
    好多刚开始学习uboot移植的同学总是觉得uboot好难,但是再难的问题如果把它一步步拆开,一个个解决,问题也就将迎刃而解。做uboot移植,我们首先就得了解uboot的编译流程,zhe

    好多刚开始学习uboot移植的同学总是觉得uboot好难,但是再难的问题如果把它一步步拆开,一个个解决,问题也就将迎刃而解。做uboot移植,我们首先就得了解uboot的编译流程,这里以在iTOP4412精英版2G内存的板子上移植u-boot-2013.01.tar.bz2为例子,uboot可以到https://ftp.denx.de/pub/u-boot/网站进行下载,执行: tar jxvf u-boot-2013.01.tar.bz2进行解压。

    解压完在u-boot-2013.01文件夹下有如下文件

    先看看README文件,看它是如何说明uboot的使用,在3863行可以看到关于编译uboot的说明

    首先是配置配置交叉编译器,然后执行make NAME_config,再执行make all。这里的NAME我们该怎么写呢?在3898行有说明,关于NAME的配置说明请参照boards.cfg文件。

    打开boards.cfg文件

    在第40行有Target    ARCH    CPU    Board name    Vendor    SOC    Options一个表头,即下面的内容是按照这个规则列出来的,Target就是对应我们上面的make NAME_config中的NAME,这个我们可以随便设置;ARCH是对应我们要移植目标板芯片的架构;CPU对应芯片核心型号;Board name对应板子的名称,这个可以自己随便设置,但是要对应到board/$(Vendor)/$(Board name)目录;Vendor是指芯片的供应商名称;SOC是对应芯片系列号;Options是额外配置项。iTOP4412的板子的芯片名称为exynos4412,根据芯片手册可知,它是属于三星公司提供的arm架构的armv7型号exynos系列芯片,即ARCH=arm,CPU=armv7,Vendor=samsung,SOC=exynos,其他几个是我们自己设定的,先看看board/$(Vendor)/目录下(即board/samsung/)有哪些文件

    其中common目录下放的是samsung板子的一些通用接口,dts目录就是放dts(Device Tree Source 设备树资源)文件,关于dts就不在这里展开讲述,其他文件名都可以在boards.cfg文件中找到定义。通过查看boards.cfg文件中的定义可知origen的板子跟iTOP4412比较相似,我们就先用这个配置来编译。即make origen_config后再执行make

    那么在执行这两个命令的时候,整个工程是如何进行编译的呢?我们先来看看顶级目录下的Makefile文件,u-boot-2013的顶层Makefile只有smdk6400_noUSB_config和smdk6400_config的具体配置,那么其他的配置该怎么执行呢?

    在第775行

    %_config::  unconfig

        @$(MKCONFIG) -A $(@:_config=)

    这个就是对应其他配置的规则,%_config的%是通配符,只要字串中带有后缀_config的都会引用到这里,也就是执行make origen_config时首先匹配到这里。理解Makefile的规则的都知道Makefile的最基本规则就是

    目标: 依赖

           对应目标的操作规则

    unconfig在770行有定义,就是删除之前的一些配置。接下来我们就看看@$(MKCONFIG) -A $(@:_config=)干了些啥。

    在131行定义了MKCONFIG变量,就是顶级目录下的mkconfig脚本

    @$(MKCONFIG) -A $(@:_config=)

    相当于执行

    mkconfig -A origen

    在看看mkconfig脚本可以看看mkconfig -A origen干了些啥

     

    这里第22行是我自己添加的log,看看@$(MKCONFIG) -A $(@:_config=)的时候传递了哪些参数,在23行到42行也可以看出该脚本只允许传递两个参数,第一个参数是:-A,第二个参数是我们的Target。参数条件必须落入第一个if分支,如果不能进去第一个分支就会报错。第一个if分支只要是通过我们传递的Target去boards.cfg文件中找出对应的列表,我们可以执行它上面的命令试试。

    这里执行make origen_config的打印也验证了我们上面的参数,执行egrep命令也找出了origen对应的列表,然后将这些列表参数进行变量赋值

    创建链接

    赋值变量并写进include/config.mk文件

    创建include/config.h文件,并往里面写一些宏定义和添加头文件包含

    至此,mkconfig -A origen已经完成,也就是我们的make origen_config完成了以上工作。再用git status命令查看执行以上命令,对整个工程做了哪些修改

    发现多了以上文件。

    接下来分析make命令

    首先在166行是判断include/config.mk是否存在,如果有就继续执行,如果没有则跳到722行,后面就报错退出了。也就是说在执行make之前,必须先执行make NAME_config进行配置。

    在188行是配置交叉编译器,关于iTOP4412交叉编译器的构建可以参考iTOP4412交叉编译器构建这篇博客。

    这段代码是分别去这些路径找链接脚本的,如果都找不到也会报错退出,至于链接脚本干啥用后面会接着讲。

    找到链接脚本之后,接着就是设置编译顺序,其中$(CPUDIR)/start.o必须放第一位,因为uboot就是从这个文件启动的。

    因为我们最终需要的是u-boot.bin文件,在444行找到了生成u-boot.bin目标的规则,依赖于u-boot,其中BOARD_SIZE_CHECK没有定义,也就是这行没有任何操作。

    可能有些人不明白,为什么执行make的时候会到u-boot.bin这里?其实再追溯到上面429行就知道了,当我们执行make,但是后面不加任何目标的时候,就会在Makefile文件中找到all这个目标来执行,而all又依赖于$(ALL-y) $(SUBDIR_EXAMPLES),在412行又找到ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map,也就是在执行make的时候其实会生成好几个文件,但是只有u-boot.bin是我们目前关心的。

    到这里我们已经成功地把u-boot.bin给编译出来了,但是它还不能启动。因为exynos4412芯片采用了Secure Boot技术,所以我们编译完u-boot.bin还需对u-boot.bin文件进行修改。修改步骤如下:

    1.找到讯为电子提供uboot的源码,将根目录下的sdfuse_q文件夹拷贝到u-boot-2013.01目录下

    2.修改Makefile,在u-boot.bin中添加规则

    3.将编译出来的u-boot.bin拷贝到讯为电子提供的CodeSign4SecureBoot_SCP目录下,这里包含着exynos4412芯片BL1阶段的可执行程序,其实是由三星提供的无源码可执行程序。

    4.合并文件

    cat E4412_N.bl1.SCP2G.bin bl2.bin all00_padding.bin u-boot.bin tzsw_SMDK4412_SCP_2GB.bin > u-boot-iTOP-4412.bin

     

    得到u-boot-iTOP-4412.bin文件

    5.用dd命令将u-boot-iTOP-4412.bin文件写进SD卡

    sudo dd if=u-boot-iTOP-4412.bin of=/dev/sdb seek=1

     

    这个时候将SD卡插到板子上,把拨码开关拨到SD卡启动位置就可以启动了,因为我们只是用origen的配置文件,在iTOP4412上未必能真的启动

    那么我们先修改代码点亮LED灯

    修改arch/arm/cpu/armv7/start.S文件添加点亮LED程序

    执行make重新编译,将合并的文件写进SD卡,重新启动板子,可以看到板子的LED亮了

    到此,关于iTOP4412精英版2G内存的板子上移植u-boot-2013.01已经结束,整个教程比较长,希望以后能简洁明了,如果不对的地方也请指出。

    展开全文
  • uboot 移植

    2018-01-09 21:36:41
    s3c2440 uboot移植手册,确实不错,平台是Mini2440,友善出品,
  • exynos4412_uboot移植与分析 ,exynos4412 uboot移植
  • mini2400 移植uboot的详细记录,从网上获取的原始uboot移植到mini2440的详细过程。
  • Uboot移植流程

    2020-01-14 09:56:18
    linux-Bootloader(Uboot)移植流程 前言 ...uboot启动的过程比较复杂,这里就只贴几张图片了,重点放在后面的uboot移植。。 补充:①Bootloader的两个阶段 ②内核传参:Bootloader启动完成后...

    linux-Bootloader(Uboot)移植流程

    前言

    最近在做ZigBee的温室大棚项目,将自己学习的过程和经验分享给大家。本文基于linux3.4.39内核版本,s5p6818开发板实现。

    1、uboot启动简介

    uboot启动的过程比较复杂,这里就只贴几张图片了,重点放在后面的uboot移植。。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    补充:①Bootloader的两个阶段
    在这里插入图片描述
    ②内核传参:Bootloader启动完成后在操作系统关闭前都将不会执行,所有会被操作系统覆盖,由操作系统管理所有内存资源,但是Bootloader启动OS时会将一些重要信息传递给OS,称为给内核传参。参数由多个结构体组成,起始地址为0x4000_ 0100(uboot中bi_ boot_
    _ params成员记录)。参数结构体如下(了解):
    在这里插入图片描述

    2、uboot移植步骤

    1)、将uboot源文件拷贝至虚拟机()我的是Ubuntu16),并解压出来。
    在这里插入图片描述
    2)、uboot根目录下执行make x6818_config
    在这里插入图片描述
    3)、修改include/configs/x6818.h配置文件
    在这里插入图片描述
    4)、make 生成u-boot.bin,包含剪切去掉ELF格式
    注意:make 前先make clean清理之前的编译结果。
    在这里插入图片描述
    5)、执行tools下的mk6818
    在这里插入图片描述在这里插入图片描述
    6)、下载到开发板
    开发板开机三秒倒计时时快速按下回车键,进入uboot界面。

    下载镜像烧写工具
    在这里插入图片描述
    修改镜像所在路径,相对脚本的相对路径:
    在这里插入图片描述
    在uboot界面下输入:fastboot,回车后,双击脚本sp_linux_image_down.bat。
    在这里插入图片描述
    在这里插入图片描述

    3、总结

    虽然uboot启动的过程很复杂,但uboot移植很简单,主要是对硬件的支持的配置,但这部分一般都是芯片厂商提供(即x6818_config等多个配置文件),我们需要那种配置直接使用即可。
    写的很粗糙,若有错误请指正。谢谢!
    fastboot工具下载链接:https://download.csdn.net/download/qq_41583666/12100653

    展开全文
  • imx6ull uboot移植

    2021-03-04 14:02:41
    uboot移植主要是根据原厂的uboot移植:芯片厂商通常会做一块自己的评估板并发布BSP,当我们需要定制自己的开发板时可以根据自己的需求(硬件上的不同),对原厂的uboot裁剪等等。 注:BSP 通常包含uboot、Linux内核...
  • 我们使用uboot的时候,大多数都是直接编译再移植了,很少改动里面的具体内容,特别是其中包含的命令等。
  • FS4412系统移植实验手册-uboot移植
  • TX2440A uboot移植

    2013-06-08 10:05:10
    TX2440A uboot移植 基于s3c2440开发板
  • 要动的是值,而uboot为了具有可移植性把值都宏定义在include/configs/xxx.h中了。因此我们只需要去这个配置头文件中更改配置值即可。 (2)更改内容是:#define DMC0_MEMCONFIG_0 0x20E01323改为: **#define ...
  • uboot移植新手入门实践

    千次阅读 2018-10-07 17:17:09
    uboot移植新手入门实践。以SoC产家提供的demo 板uboot源码作为移植基础,分析uboot启动过程中做了什么事;移植uboot到itop 4412开发板。
  • s5pv210 的uboot移植

    2018-03-03 17:27:16
    uboot官网对s5pv210的uboot进行移植,针对cortex-A8板子
  • (1)添加三星的mmc驱动 在三星中复制的文件 #mmc.c drivers/mmc/mmc.c #s3c_hsmmc.c ... #endif (6)修改s5p_goni.h (7)移植测试 mmc设备列表 读取扇区1的数据到0x30000000 查看0x300000的数据 写mmc数据和查看写的数据
  • Zynq系列--Uboot移植

    千次阅读 2019-11-03 11:18:53
    zynq-7000系列基于zynq-zed的uboot的编译 目的:编译uboot,下载,并实现ping功能 1.下载uboot: https://github.com/HongyunChen/u-boot-xlnx-xilinx-v2018.3 (内有我的配置好的文件以及设备树)本文选择的是18...
  • IMX6ULL Uboot 移植

    2021-08-01 19:44:16
    uboot移植主要是根据原厂的uboot移植:芯片厂商通常会做一块自己的评估板并发布BSP,我们使用的就是NXP官方的评估板的Uboot进行裁剪,修改得来我们自己板子的程序。 本次使用的是NXP 官方原版的 uboot-imx-rel_imx_...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,530
精华内容 5,812
关键字:

uboot移植