0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

U-boot如何添加board

CHANBAEK 来源:人人极客社区 作者: 努力哥 2023-01-19 16:14 次阅读

U-boot代码层次

uboot需要支持众多的硬件,并且具有良好的可扩展性、可移植性和可维护性,因此必须要有一个设计良好的代码架构。代码架构的设计总是与软硬件架构密不可分的,在硬件层面嵌入式系统的核心一般包括以下层次:

(1)目标板:它包含了系统运行所需的所有组件,如SOC芯片DDR、flash/emmc存储器、各种外设以及时钟源、电源管理芯片等

(2)SOC:它包含了cpu、总线控制器、集成在片内的rom、sramdma控制器、硬件加速器、异构核,以及片内时钟、电源控制模块等

(3)处理器架构:它一般指处理器体系结构的大版本,不同的体系结构之间可能存在不同的指令集、异常模型以及内存模型等。例如对于arm系列架构,armv8和armv7就属于不同的处理器架构

(4)cpu型号:它是指处理器的具体型号,如cortex-a53或cortex-a72等

一般cpu型号和处理器架构数量相对较少,如对于arm架构来说一般就是arm官方发布的这些型号。而soc型号就要多一些,它主要是各芯片公司基于特定cpu架构以及其它ip模块,设计的专用或通用芯片,如高通海思设计的手机芯片。最后就是以soc芯片为核心设计的目标板了,在目标板上基本上集成了一款产品所需的所有组件,如一款手机的电路板。它们之间的简单关系如下图:

Dingtalk_20221206154648.jpg

Uboot的代码设计也遵循以上层次,arch目录包含了处理器架构相关代码,arch/cpu目录包含了特定cpu代码,而board目录则包含了特定目标板的代码。因此当我们新增加一款目标板时,主要的工作就可以集中在board相关的代码,只要不是太新的cpu型号,arch和cpu相关代码在uboot官方版本中都已经被支持。因此可以直接复用这部分实现,我们唯一要做的就是选择正确的配置选项。

如何添加board

添加board的基本步骤

当我们开始一个全新的项目时,总是希望能先让系统能运行起来,然后再在此基础上为其添加更多的feature,这个只包含能让系统运行所需模块的系统,叫做最小系统。cpu能正常运行包含以下几个条件:

(1)具有合适的电源和时钟

(2)程序代码被加载到合适的位置,cpu能够正常获取指令

(3)具有cpu用于数据操作的可读写内存

(4)cpu被release reset 当然对于需要支持中断的系统,则还需要包含中断控制器,而对于像操作系统这种需要通过定时器驱动进程切换的系统,则显然还需要timer定时器。为了达到以上目的,我们添加board的基本步骤大概如下: (1)在board目录下为新board添加一个目录,用于存放board特定的代码

(2)为新目录添加Kconfig配置选项和Makefile编译选项,将其添加到编译系统中

(3)在Kconfig中为该board定义一个配置项,并为该配置项添加其所支持的特性,如cpu架构、cpu型号等

(4)为新board增加一个配置相关的头文件和编译所需的defconfig文件,用于该board相关的选项配置

(5)在board目录下添加适当的文件,并实现必要的接口

test board添加示例

添加target配置选项

  1. 在arch/arm/Kconfig的board select菜单下新增如下的TARGET_TESTBOARD配置选项:
config TARGET_TESTBOARD
        bool "Qemu test board"
        select ARM64
        select DM
        select DM_SERIAL
        select PL01X_SERIAL
        select SUPPORT_SPL
        select SPL if SUPPORT_SPL
        select SPL_FRAMEWORK_BOARD_INIT_F if SPL
        select SPL_SERIAL_SUPPORT
        select PL011_SERIAL if SPL
        select SPL_LIBGENERIC_SUPPORT if SPL
        select SPL_LIBCOMMON_SUPPORT if SPL

它将在后面的configs/testboard_defconfig中通过CONFIG_ TARGET_TESTBOARD =y选择

  1. 在arch/arm/Kconfig文件中添加以下内容,以包含board的Kconfig文件
source "board/mars/test/Kconfig"

添加config头文件

在include/configs目录下添加config头文件testboard.h,并添加以下内容:

#ifndef __CONFIG_H
#define __CONFIG_H
#include 

#define CONFIG_SYS_SDRAM_BASE           0x40000000

/* The DTB generated by QEMU is placed at start of RAM, stay away from there */
#define CONFIG_SYS_INIT_SP_ADDR         (CONFIG_SYS_SDRAM_BASE + SZ_2M)
#define CONFIG_SYS_LOAD_ADDR            (CONFIG_SYS_SDRAM_BASE + SZ_2M)
#define CONFIG_SYS_MALLOC_LEN           SZ_16M

#define CONFIG_SYS_BOOTM_LEN            SZ_64M

#define CONFIG_SYS_HZ                       1000

#define CONFIG_PL01x_PORTS              {(void *)(0x9000000)}
#define CONFIG_PL011_CLOCK      1


#define CONFIG_SYS_UBOOT_START 0x40300000
#define BOOT_TARGET_DEVICES(func) \\
        func(VIRTIO, virtio, 0)

#define CONFIG_EXTRA_ENV_SETTINGS \\
        "fdt_addr=0x43000000\\0" \\
        "kernel_addr_r=0x40000000\\0" \\
        "bootargs=earlycon root=/dev/vda\\0" \\
        "bootcmd=smhload /home/lgj/work/linux/arch/arm64/boot/Image ${kernel_addr_r};" \\
        "smhload /home/lgj/work/linux/arch/arm64/boot/dts/qemu/test-board-smc.dtb ${fdt_addr};" \\
        "booti ${kernel_addr_r} - ${fdt_addr}\\0"

#define CONFIG_SYS_CBSIZE 512
#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
#define CONFIG_SYS_MAX_FLASH_BANKS_DETECT       2
#define CONFIG_SYS_MAX_FLASH_SECT       256 /* Sector: 256K, Bank: 64M */
#define CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS

#define CONFIG_SPL_MAX_SIZE 0x25000
#define CONFIG_SPL_STACK (CONFIG_SYS_SDRAM_BASE + SZ_1M)
#define CONFIG_SPL_BSS_START_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_1M)

#define CONFIG_SPL_BSS_MAX_SIZE 0x1000
#endif

添加dtb文件

使用qemu模拟器启动uboot时,模拟器会提供一个默认的dtb文件,但是我们也可以使用自己自定义的dtb文件,以下是自定义dtb文件的方法:

  1. 在arch/arm/dts/目录下添加dts文件test-board-minimal.dts,并在目录的Makefile中添加以下编译选项
dtb-$(CONFIG_TARGET_TESTBOARD) += test-board-minimal.dtb
  1. 在配置文件configs/testboard_defconfig中指定该dtb为默认dtb文件,并使能uboot的设备树支持
CONFIG_DEFAULT_DEVICE_TREE="test-board-minimal"
CONFIG_OF_CONTROL=y
CONFIG_OF_SEPARATE=y

添加board文件

  1. 在board目录下创建mars/test目录
  2. 在board/mars/test目录下创建Kconfig文件,并添加如下内容
if TARGET_TESTBOARD
config SYS_VENDOR
        default "mars"

config SYS_BOARD
        default "test"

config SYS_CONFIG_NAME
        default "testboard"
endif

其中:

SYS_VENDOR:用于指定该board的vendor名,它与SYS_BOARD一起确定会被编译的board代码路径。即board/< SYS_VENDOR >/common和board/< SYS_VENDOR >/< SYS_BOARD >的路径下的Makefile会被执行,在我们的例子中该目录为board/mars/common/和board/mars/test/SYS_BOARD:用于指定在board/< SYS_VENDOR >下需要编译的board路径,如当前配置下该目录为board/mars/test/

SYS_CONFIG_NAME用于指定include/configs目录下的头文件名,如当前配置该文件即为include/configs/testboard.h

  1. 在board/mars/test目录下创建MAINTAINERS文件,并添加如下内容
QEMU QEMU TEST BOARD
M:      xxx@yyy.com
S:      Maintained
F:      board/mars/test
F:      include/configs/testboard.h
F:      configs/testboard.h
  1. 在board/mars/test目录下创建Makefile文件,并添加如下内容
obj-y   += testboard.o
  1. 创建board/mars/test目录下创建testboard.c文件,并添加如下内容
include 
#include 
#include 
#include 
#include 

#ifdef CONFIG_ARM64
#include 
static struct mm_region testboard_mem_map[] = {
        {
                /* Flash */
                .virt = 0x00000000UL,
                .phys = 0x00000000UL,
                .size = 0x08000000UL,
                .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
                         PTE_BLOCK_INNER_SHARE
        }, {
                /* Lowmem peripherals */
                .virt = 0x08000000UL,
                .phys = 0x08000000UL,
                .size = 0x38000000,
                .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
                         PTE_BLOCK_NON_SHARE |
                         PTE_BLOCK_PXN | PTE_BLOCK_UXN
        }, {
                /* RAM */
                .virt = 0x40000000UL,
                .phys = 0x40000000UL,
                .size = 255UL * SZ_1G,
                .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
                         PTE_BLOCK_INNER_SHARE
        }, {
                /* Highmem PCI-E ECAM memory area */
                .virt = 0x4010000000ULL,
                .phys = 0x4010000000ULL,
                .size = 0x10000000,
                .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
                         PTE_BLOCK_NON_SHARE |
                         PTE_BLOCK_PXN | PTE_BLOCK_UXN
        }, {
                /* Highmem PCI-E MMIO memory area */
                .virt = 0x8000000000ULL,
                .phys = 0x8000000000ULL,
                .size = 0x8000000000ULL,
                .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
                         PTE_BLOCK_NON_SHARE |
                         PTE_BLOCK_PXN | PTE_BLOCK_UXN
        }, {
                /* List terminator */
                0,
        }
};

struct mm_region *mem_map = testboard_mem_map;
#endif

int board_init(void)
{
        return 0;
}

int dram_init(void)
{
        if (fdtdec_setup_mem_size_base() != 0)
                return -EINVAL;

        return 0;
}

int dram_init_banksize(void)
{
        fdtdec_setup_memory_banksize();

        return 0;
}

void *board_fdt_blob_setup(void)
{
        /* QEMU loads a generated DTB for us at the start of RAM. */
        return (void *)CONFIG_SYS_SDRAM_BASE;
}

void enable_caches(void)
{
         icache_enable();
         dcache_enable();
}

#ifdef CONFIG_SPL
u32 spl_boot_device(void)
{
        return BOOT_DEVICE_SEMIHOSTING;
}
#endif

创建defconfig配置文件

在configs目录下为testboard创建配置文件testboard_defconfig,并添加如下内容

CONFIG_ARM=y
CONFIG_TARGET_TESTBOARD=y
CONFIG_POSITION_INDEPENDENT=y
CONFIG_NR_DRAM_BANKS=1
CONFIG_ENV_SIZE=0x40000
CONFIG_ENV_SECT_SIZE=0x40000
CONFIG_DEFAULT_DEVICE_TREE="test-board-minimal"
CONFIG_ENV_ADDR=0x4000000

CONFIG_OF_CONTROL=y
CONFIG_OF_SEPARATE=y

CONFIG_DM_SERIAL=y
CONFIG_DM_ETH=y
CONFIG_SYSRESET=y
CONFIG_SEMIHOSTING=y

# add boot stage info to fdt
CONFIG_OF_FDT=y

CONFIG_SPL_SYS_MALLOC_F_LEN=0x1000
CONFIG_SPL_TEXT_BASE=0x40000000
CONFIG_CONS_INDEX=0
CONFIG_SYS_TEXT_BASE=0x40300000
# CONFIG_DISPLAY_CPUINFO is not set

spl支持semihost启动

  1. 将arch/arm/lib/semihosting.c中smh_load_file导出,即去掉下面定义中的static
static int smh_load_file(const char * const name, ulong load_addr,  ulong *end_addr)
{
        …
}
  1. 将arch/arm/lib/semihosting.c中的do_smhload文件修改为只有uboot编译,即将其修改为:
#ifndef CONFIG_SPL_BUILD
static int do_smhload(struct cmd_tbl *cmdtp, int flag, int argc,
                      char *const argv[]) {
}
#endif
  1. 在arch/arm/include/asm/spl.h的BOOT DEVICE枚举中添加对semihosting的支持
enum {
        …
        BOOT_DEVICE_SEMIHOSTING,
        BOOT_DEVICE_NONE
};
  1. 在common/spl/目录下添加文件spl_semihosting.c,并添加以下内容:
#include 
#include 
extern int smh_load_file(const char * const name, ulong load_addr,
                         ulong *end_addr);

static int spl_sh_load_image(struct spl_image_info *spl_image,
                              struct spl_boot_device *bootdev)
{
        int rc;
        ulong uboot_load_addr = 0x40300000, uboot_end_addr;

        rc = smh_load_file("u-boot.bin", uboot_load_addr,
                         &uboot_end_addr);
        if (rc < 0) {
                if (CONFIG_IS_ENABLED(SHOW_ERRORS) &&
                    CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT))
                        printf(SPL_TPL_PROMPT "load file u-boot.bin failed (err=%d)\\n",
                               rc);
                else
                        puts(SPL_TPL_PROMPT "load file u-boot.bin failed\\n");
 
                return -1;
        }
 
        spl_image->load_addr = uboot_load_addr;
        spl_image->entry_point = uboot_load_addr;
        spl_image->os = IH_OS_U_BOOT;

        return 0;
}
SPL_LOAD_IMAGE_METHOD("SEMIHOSTING", 0, BOOT_DEVICE_SEMIHOSTING, spl_sh_load_image);
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • soc
    soc
    +关注

    关注

    38

    文章

    3750

    浏览量

    215733
  • u-boot
    +关注

    关注

    0

    文章

    116

    浏览量

    38045
  • 代码
    +关注

    关注

    30

    文章

    4557

    浏览量

    66826
  • board
    +关注

    关注

    0

    文章

    32

    浏览量

    19511
收藏 人收藏

    评论

    相关推荐

    S3C6410移植u-boot

    )include/config.mk步骤41、从U-boot根目录,进入nand_spl/board/samsung/cd nand_spl/board/samsung/2、新建目录smdk6410并将
    发表于 02-23 14:31

    基于开发板的U-Boot移植

    /boards.cfguboot2011.06/config.mkuboot2011.06/Makefile移植过程就是在新的U-Boot代码中增加与S5PV210开发板CPU级和Board级代码,使之能够在210开发板上面运行。1.
    发表于 01-14 14:31

    开发板上移植U-Boot

    /boards.cfguboot2011.06/config.mkuboot2011.06/Makefile移植过程就是在新的U-Boot代码中增加与S5PV210开发板CPU级和Board级代码,使之能够在210开发板上面运行。1.
    发表于 01-14 14:36

    关于U-boot的问题?

    U-Boot是不是下载好的文件然后在ubuntu里去编译?U-Boot的编译和移植的区别和关系是什么?U-Boot的移植=烧写?
    发表于 05-12 08:22

    U-Boot是如何引导系统的

    通过串口连接BeagleBone Black,参见http://elinux.org/Beagleboard:Terminal_Shells启动到U-Boot的时候,会看到Hit any key
    发表于 10-22 17:43

    【Z-turn Board试用体验】+ u-boot启动

    ,miniciom进入等待状态,等待u-boot启动时候的打印信息。这时按下开发板上的PS端的复位键K2,马上minicom中就接收到了u-boot的启动信息,分析这些信息能知道u-boot的启动流程
    发表于 07-12 17:24

    【OK210试用体验】u-boot篇 -- u-boot初体验

    2010.6版本开始。 u-boot-2010.03及以前版本:api存放u-boot提供的接口函数board根据不同开发板定制的代码common通用函数cpu对应不同的CPU,比如arm920t
    发表于 08-21 19:57

    【OK210试用体验】u-boot篇 -- u-boot初体验(续)

    相关文件夹的内容。我们需要知道u-boot提供给我们的开发板类型有哪些,可以在u-bootboard目录下查看。在board的Samsung文件夹下,并没有S5PV210这块开发板,
    发表于 08-22 01:44

    【OK210试用体验】u-boot篇 -- u-boot进一步定制

    是打印u-boot相关信息,display_banner定义和board_init_f在同一个代码文件里,这里可以添加自己的显示信息。 在arch/arm/cpu/armv7/s5pc1xx
    发表于 09-07 11:38

    【OK210试用体验】u-boot篇 -- u-boot命令tab补全功能

    【OK210试用体验】u-boot篇 -- u-boot命令tab补全功能 在Ubuntu环境下,可以试用“tab”键命令来实现命令补全功能,但是在u-boot中,默认是不支持补全功能的,这里来实现
    发表于 09-10 17:56

    【OK210试用体验】u-boot篇 -- 添加启动蜂鸣器鸣响功能

    【OK210试用体验】u-boot篇 -- 添加启动蜂鸣器鸣响功能 当我们在用SD卡启动OK210的时候,都会听到蜂鸣器的鸣响,这个对于提示正常启动还是蛮有意义的。对于自己移植u-boot
    发表于 09-15 00:54

    8168 emv nand u-boot问题,急救

    我使用的u-boot为ti-ezsdk_dm816x-evm_5_03_00_09/board-support/prebuilt-images 下编译好的u-boot   使用sd卡写nand
    发表于 06-21 09:24

    u-boot详解

    U-Boot主要目录结构 - board 目标板相关文件,主要包含SDRAM、FLASH驱动; - common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测; - cpu 与处理器相关
    发表于 07-04 04:56

    U-Boot的移植操作

    U-Boot的移植U-Boot的移植主要分为两个层面,一个是对CPU的移植,一个是针对Board的移植。U-Boot中已经有大量可直接下载到某些开发板上的程序,为了减小工作量,可选一个
    发表于 07-15 07:48

    如何在SDARM中调试u-boot

    请问我有已经移植好的u-boot-1.1.6,烧入mini2440的nor flash可以正常使用。现在我想使用这个移植好的u-boot在SDRAM中重新调试这个uboot.我对移植好的uboot
    发表于 09-25 05:45