完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
需要知道的一点是,在arm64架构下,linux已经弃用mach_xx等文件夹来描述板级信息供linux内核启动时去匹配根节点下的compatible属性来找到对应设备树。
取而代之是单纯的接收bootloader传递过来的单一设备树文件dtb所在的内存地址。所以当多个dtb文件存在镜像中或者内存中时,如何找到需要的dtb的这个任务,就落在了bootloader肩上。 0 - uboot代码准备 本文中主要涉及到了两个版本的uboot
分别可以通过以下方式获取。 1 - 友善之臂版uboot如何获取要加载的设备树 友善之臂用的版本是2014.10版的uboot 首先,引用源自 common/cmd_bootrk.c @ rk_load_image_from_storage() /* loader fdt from resource if content.load_addr == NULL */ #ifdef CONFIG_OF_LIBFDT if (!content.load_addr) { #ifdef CONFIG_OF_FROM_RESOURCE puts("load fdt from resouce.n"); content = rkimage_load_fdt(get_disk_partition(RESOURCE_NAME)); #endif } 跟踪看到,board/rockchip/common/rkloader/rkimage.c @ rkimage_load_fdt() resource_content rkimage_load_fdt(const disk_partition_t* ptn) { resource_content content; snprintf(content.path, sizeof(content.path), "%s", get_fdt_name()); content.load_addr = 0; #ifndef CONFIG_RESOURCE_PARTITION return content; #else if (!ptn) return content; if (!strcmp((char*)ptn->name, BOOT_NAME) || !strcmp((char*)ptn->name, RECOVERY_NAME)) { //load from bootimg's second data area. unsigned long blksz = ptn->blksz; int offset = 0; rk_boot_img_hdr *hdr = NULL; #ifdef CONFIG_RK_NVME_BOOT_EN hdr = memalign(SZ_4K, blksz << 2); #else hdr = memalign(ARCH_DMA_MINALIGN, blksz << 2); #endif if (StorageReadLba(ptn->start, (void *) hdr, 1 << 2) != 0) { return content; } if (!memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) && hdr->second_size) { //compute second data area's offset. offset = ptn->start + (hdr->page_size / blksz); offset += ALIGN(hdr->kernel_size, hdr->page_size) / blksz; offset += ALIGN(hdr->ramdisk_size, hdr->page_size) / blksz; if (get_content(offset, &content)) load_content(&content); } return content; } //load from spec partition. if (get_content(ptn->start, &content)) load_content(&content); return content; #endif } 对于上面两个红框处,我们分别讨论 1.1 - get_fdt_name 获取设备树dtb文件名 其代码本质是调用 getenv 从环境变量中取得 "dtb_name"变量上的字符串 static const char* get_fdt_name(void) { char *name = getenv("dtb_name"); if (name) return name; if (!gBootInfo.fdt_name[0]) { return FDT_PATH; } return gBootInfo.fdt_name; } 而这个“dtb_name“变量中包含的字符串就是我们需要的dtb文件名。它是在 board/rockchip/rk33xx/rk33xx.c @ rk33xx.c文件中被写入的 /* * Board revision list: * 0b00 - NanoPC-T4 * 0b01 - NanoPi M4 * * Extended by ADC_IN4 * Group A: * 0x04 - NanoPi NEO4 * 0x06 - SOC-RK3399 * * Group B: * 0x21 - NanoPi M4 Ver2.0 */ static int pcb_rev = -1; static void bd_hwrev_init(void) { gpio_direction_input(GPIO_BANK4 | GPIO_D0); gpio_direction_input(GPIO_BANK4 | GPIO_D1); pcb_rev = gpio_get_value(GPIO_BANK4 | GPIO_D0); pcb_rev |= (gpio_get_value(GPIO_BANK4 | GPIO_D1) << 1); if (pcb_rev == 0x3) { /* Revision group A: 0x04 ~ 0x13 */ pcb_rev = 0x4 + get_adc_index(4); } else if (pcb_rev == 0x1) { int idx = get_adc_index(4); /* Revision group B: 0x21 ~ 0x2f */ if (idx > 0) { pcb_rev = 0x20 + idx; } } } /* To override __weak symbols */ u32 get_board_rev(void) { return pcb_rev; } static void set_dtb_name(void) { char info[64] = {0, }; snprintf(info, ARRAY_SIZE(info), "rk3399-nanopi4-rev%02x.dtb", get_board_rev()); setenv("dtb_name", info); } 我们因此知道了,友善之臂的nanopi系列板子,是通过板上 GPIO4_D1、GPIO4_D0 的输入电平,以及 ADC_IN4 脚的输入电压来判断载入什么dtb的 1.2 - get_content() 获取所需dtb的地址 rkimage_load_fdt() 函数中,将 “dev_name” 中的设备树名写入到content.path变量中。在 common/resource.c @ get_content() 函数中 bool get_content(int base_offset, resource_content* content) { bool ret = false; index_tbl_entry entry; debug("get_content: base_offset = 0x%xn", base_offset); if (!base_offset) { base_offset = get_base_offset(); } if (!base_offset) { FBTERR("base offset is NULL!n"); goto end; } if (!get_entry(base_offset, content->path, &entry)) goto end; content->content_offset = entry.content_offset + base_offset; content->content_size = entry.content_size; ret = true; end: return ret; } 将 content.path 传入 get_entry() 函数,其函数修改传入的 entry 参数变量。get_entry() 函数也在common/resource.c static bool get_entry(int base_offset, const char* file_path, index_tbl_entry* entry) { 。。。 ret = get_entry_ram(header, table, header.tbl_entry_num * header.tbl_entry_size * BLOCK_SIZE, file_path, entry); end: if (table) { free(table); } return ret; } |
|
|
|
可知,其调用 get_entry_ram 函数,将指定dtb文件地址解析并传送到 entry 中。在 common/resource.c @ get_entry_ram()函数中
。。。 for (i = 0; i < header.tbl_entry_num; i++) { //TODO: support tbl_entry_size memcpy(entry, table + i * header.tbl_entry_size * BLOCK_SIZE, sizeof(*entry)); if (memcmp(entry->tag, INDEX_TBL_ENTR_TAG, sizeof(entry->tag))) { FBTERR("Something wrong with index entry:%d!n", i); goto end; } FBTDBG("Lookup entry(%d):ntpath:%sntoffset:%dtsize:%dn", i, entry->path, entry->content_offset, entry->content_size); if (!strncmp(entry->path, file_path, sizeof(entry->path))) break; } 。。。 从resource镜像的头部中寻找对应的设备树名,一条一条比对,当比对当前在entry->path中的设备树名与需要的设备树名比对相同时退出。
< >2 - 瑞芯微github上stable-4.4版uboot如何获取设备树 stable-4.4版本的uboot(2017.09)使用类似现在linux的架构目录。uboot类似kernel也有了自己的设备树,方便自身加载初始化。因此这里分两个部分讨论,一个是uboot自己的设备树 uboot-dtb ,一个是linux需要的设备树 kernel-dtb。 2.1 - uboot-dtb 在 uboot/configs 目录下存放各种defconfig,其中包含有一项配置,例如firefly的firefly-rk3399 直接指定了使用什么默认设备树 在 ubootarcharmdtsrk3399-firefly.dts 中我们可以看到 /* * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd. * * SPDX-License-Identifier: GPL-2.0+ */ /dts-v1/; #include #include #include "rk3399.dtsi" #include "rk3399-sdram-ddr3-1600.dtsi" #include "rk3399-u-boot.dtsi" / { model = "Firefly-RK3399 Board"; compatible = "firefly,firefly-rk3399", "rockchip,rk3399"; 依据这个来进行uboot中设备树的匹配,但是注意,这个是uboot自用的设备树,并不是要传递给kernel的 2.2 - kernel-dtb 在 archarmmach-rockchipresource_img.c @ rockchip_read_dtb_file()函数中,我们可以看到 。。。 int rockchip_read_dtb_file(void *fdt_addr) { struct resource_file *file; char *def_dtb = DTB_FILE; int ret; /* search order: "rk-kernel.dtb" -> distro -> hwid */ file = get_file_info(NULL, def_dtb); if (!file) { #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB ret = rockchip_read_distro_dtb(fdt_addr); if (ret > 0) return ret; /* found & load done */ #endif #ifdef CONFIG_ROCKCHIP_HWID_DTB file = rockchip_read_hwid_dtb(); #endif if (!file) return -ENODEV; } 。。。 从resource.img中获取kernel-dtb有三个阶段(图中的红、绿、蓝三框)。 < >2.2.1 - get_file_info() 直接在 resource.img 中查找 rk-kernel.dtb 首先是去resource.img中寻找有没有叫“rk-kernel.dtb”的这个设备树文件(宏定义DTB_FILE),在 archarmmach-rockchipresource_img.c 中: static struct resource_file *get_file_info(struct resource_img_hdr *hdr, const char *name) { struct resource_file *file; struct list_head *node; if (list_empty(&entrys_head)) { if (init_resource_list(hdr)) return NULL; } list_for_each(node, &entrys_head) { file = list_entry(node, struct resource_file, link); if (!strcmp(file->name, name)) return file; } return NULL; } 2.2.2 - EARLY_DISTRO中寻找指定dtb 如果 2.2.1 搜索失败了,没有rk-kernel.dtb,且定义了 CONFIG_ROCKCHIP_EARLY_DISTRO_DTB 则调用 rockchip_read_distro_dtb(fdt_addr)函数去寻找,在archarmmach-rockchipresource_img.c 中: #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB static int rockchip_read_distro_dtb(void *fdt_addr) { const char *cmd = "part list ${devtype} ${devnum} -bootable devplist"; char *devnum, *devtype, *devplist; char devnum_part[12]; char fdt_hex_str[19]; char *fs_argv[5]; int size; int ret; if (!rockchip_get_bootdev() || !fdt_addr) return -ENODEV; ret = run_command_list(cmd, -1, 0); if (ret) return ret; 。。。 在 archarmmach-rockchipKconfig中我们可以看到,如果定义了 ROCKCHIP_EARLY_DISTRO_DTB,则我们还可以自己定义在镜像文件中dtb的名称 2.2.3 - HWID判断使用dtb 如果2.2.1失败了,没有rk-kernel.dtb,且定义了CONFIG_ROCKCHIP_HWID_DTB 则调用rockchip_read_hwid_dtb()函数,读取硬件引脚来判断使用什么dtb,在archarmmach-rockchipresource_img.c 中: /* Get according to hardware id(GPIO/ADC) */ static struct resource_file *rockchip_read_hwid_dtb(void) { struct resource_file *file; struct list_head *node; /* Find dtb file according to hardware id(GPIO/ADC) */ list_for_each(node, &entrys_head) { file = list_entry(node, struct resource_file, link); if (!strstr(file->name, ".dtb")) continue; if (strstr(file->name, KEY_WORDS_ADC_CTRL) && strstr(file->name, KEY_WORDS_ADC_CH) && !rockchip_read_dtb_by_adc(file->name)) { return file; } else if (strstr(file->name, KEY_WORDS_GPIO) && !rockchip_read_dtb_by_gpio(file->name)) { return file; } } return NULL; } |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1924 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2406 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5193 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 13:16 , Processed in 0.555535 second(s), Total 44, Slave 37 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号