【问题记录】如何打包两个dtb文件

前言

在项目开发过程中,可能会遇到多个项目使用同一个源码仓库,并且代码是高度复用的,如果在不同的项目中只是代码存在一些差异,会有很好的解决方式去区分,但可能在不同的项目中设备树存在差异性,这个时候会相对来说比较难处理,本文目的就是以RK平台上的芯片为示例来实现将两个项目的dtb文件和内核文件一起打包,并根据不同的设备参数传递不同的设备树给内核进行解析。


一、熟悉打包流程

1. 查看编译内核信息,找到dtb信息

boot.img的生成分两步 [1] 将 e6000.dtb、logo.bmp、logo_kernel.bmp 三个文件打包成 resource.img 文件; [2] 将 Image、resource.img打包成 boot.img;

2. 搜索关键字,找到打包脚本的代码

3. 找到打包的命令

resource.img 打包命令 文件路径:srcipts/mkimg boot.img 打包命令整理后的打包命令

c 复制代码
1. resource.img 打包命令
    scripts/resource_tool ${DTB_PATH} ${LOGO} ${LOGO_KERNEL} >/dev/null
    --->
   ./scripts/resource_tool arch/arm64/boot/dts/rockchip/e6000.dtb logo.bmp logo_kernel.bmp
2. boot.img 打包命令
    ${srctree}/scripts/mkbootimg  ${KERNEL_IMAGE_ARG} ${RAMDISK_ARG} --second resource.img
 -o boot.img && 

    --->./scripts/mkbootimg --kernel ./arch/arm64/boot/Image --second resource.img  -o boot.img

4. 手动打包测试

c 复制代码
1.  打包 resource.img
    ./scripts/resource_tool arch/arm64/boot/dts/rockchip/e6000.dtb logo.bmp logo_kernel.bmp
2. 打包 boot.img 打包
    ./scripts/mkbootimg --kernel ./arch/arm64/boot/Image --second resource.img -o boot.img

5. resource_tool 打包工具

打包工具还有其它的参数选项,如果想看更详细的打包过程,可以加入 --print --verbose

二、修改编译脚本和打包工具

目的:将XEPU和EPU项目的dtb文件打包进新的内核升级包。 前提:XEPU和EPU中设备树的源文件(.dts)都是存在的。

1. 修改顶层编译脚本

c 复制代码
diff --git a/common/build.sh b/common/build.sh
index 7bc43f3..058e26b 100755
--- a/common/build.sh
+++ b/common/build.sh
@@ -122,7 +122,7 @@ function build_kernel(){
        echo "TARGET_KERNEL_CONFIG =$RK_KERNEL_DEFCONFIG"
        echo "TARGET_KERNEL_DTS    =$RK_KERNEL_DTS"
        echo "=========================================="
-       cd $TOP_DIR/kernel && make ARCH=$RK_ARCH $RK_KERNEL_DEFCONFIG && make ARCH=$RK_ARCH $RK_KERNEL_DTS.img -j$RK_JOBS && cd -
+       cd $TOP_DIR/kernel && make ARCH=$RK_ARCH rockchip/xepu.dtb && make ARCH=$RK_ARCH $RK_KERNEL_DEFCONFIG && make ARCH=$RK_ARCH $RK_KERNEL_DTS.img -j$RK_JOBS && cd -
        if [ $? -eq 0 ]; then
                echo "====Build kernel ok!===="
        else

可以通过make ARCH=xxx rockchip/xxxx.dtb自行测试单独编译dts文件

2. 修改脚本mkimg

c 复制代码
diff --git a/scripts/mkimg b/scripts/mkimg
index 402c4d4fb508..99710fc4aa88 100755
--- a/scripts/mkimg
+++ b/scripts/mkimg
@@ -4,6 +4,8 @@
 
 set -e
 
+XEPU_DTB=xepu.dtb
+
 usage() {
        cat >&2 << USAGE
 usage: $0 [-h] --dtb DTB
@@ -61,6 +63,7 @@ if [ "${ARCH}" == "arm" ]; then
        ZIMAGE=zImage
 else
        DTB_PATH=${objtree}/arch/arm64/boot/dts/rockchip/${DTB}
+       XEPU_DTB_PATH=${objtree}/arch/arm64/boot/dts/rockchip/${XEPU_DTB}
        KERNEL_IMAGE_ARG="--kernel ${objtree}/arch/arm64/boot/Image"
        KERNEL_ZIMAGE_ARG="--kernel ${objtree}/arch/arm64/boot/Image.lz4"
        ZIMAGE=Image.lz4
@@ -122,8 +125,9 @@ if [ "${srctree}" != "${objtree}" ]; then
                cp -a ${LOGO_KERNEL_PATH} ${objtree}/;
        fi
 fi
-scripts/resource_tool ${DTB_PATH} ${LOGO} ${LOGO_KERNEL} >/dev/null
-echo "  Image:  resource.img (with ${DTB} ${LOGO} ${LOGO_KERNEL}) is ready"
+
+scripts/resource_tool ${DTB_PATH} ${XEPU_DTB_PATH} ${LOGO} ${LOGO_KERNEL} >/dev/null
+echo "  Image:  resource.img (with ${DTB} ${XEPU_DTB} ${LOGO} ${LOGO_KERNEL}) is ready"
 
 if [ -f "${BOOT_IMG}" -a -x ${srctree}/scripts/repack-bootimg ]; then
        repack_boot_img;

这个脚本会调用打包工具并将打包的文件传递进去。

3. 修改打包工具源码

c 复制代码
diff --git a/scripts/resource_tool.c b/scripts/resource_tool.c
index c28d4068874a..b337184f4add 100644
--- a/scripts/resource_tool.c
+++ b/scripts/resource_tool.c
@@ -577,7 +577,8 @@ static bool g_debug =
   } while (0)
 
 /* sync with ./board/rockchip/rk30xx/rkloader.c #define FDT_PATH */
-#define FDT_PATH "rk-kernel.dtb"
+#define FDT_PATH_EPU "rk-kernel-epu.dtb"
+#define FDT_PATH_XEPU "rk-kernel-xepu.dtb"
 #define DTD_SUBFIX ".dtb"
 
 #define DEFAULT_IMAGE_PATH "resource.img"
@@ -1512,9 +1513,12 @@ static bool write_index_tbl(const int file_num, const char **files)
                if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) {
                        if (!foundFdt) {
                                /* use default path. */
-                               LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH);
-                               path = FDT_PATH;
+                               LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH_EPU);
+                               path = FDT_PATH_EPU;
                                foundFdt = true;
+                       } else {
+                               LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH_XEPU);
+                               path = FDT_PATH_XEPU;
                        }
                }
                snprintf(entry.path, sizeof(entry.path), "%s", path);

注意,每次内核编译时,打包工具都会编译,也可以自行手动编译:gcc -o resource_tool resource_tool.c 另外,FDT_PATH_EPU、FDT_PATH_XEPU这个定义很重要,在boot下根据此值来进行区分不同的dtb文件 至此修改完成后,在工程的顶层目录直接编译,就可以了,如下:

三、将不同的dtb文件传递给内核

dtb文件是在启动内核之前将dtb文件传递给内核进行解析的,在EPU和XEPU中如何能将对应的dtb文件传递给相应的设备,这就需要一个标识,可以选择HWID来进行区分EPU和XEPU。

1. 获取HWID

因为HWID是存放在EEPROM内的,所以需要在uboot下编写EEPROM的读操作,由于代码较多,获取HWID代码如下

c 复制代码
int e2prom_get_hwid(ushort *e2prom_hwid)
{
	uchar *src = NULL; uchar *tmp = NULL;
	int ix = 0;
	uint magic = 0;
	int success = 0;
	int err;
	struct udevice *dev_id;

	err = i2c_get_chip_for_busnum(I2C_BUS_STD1, AT24C02_I2C_ADDR, 1, &dev_id);
	if (err) {
		printf("%s(%d): Cannot find PMIC I2C chip\n", __func__, __LINE__);
		return err;
	}

	/* malloc space */
	if(NULL == (src = malloc(E2PROM_SIZE)))
		goto error_out;
	memset (src, 0, E2PROM_SIZE);

	/* Read date from e2prom */
	e2prom_read(src, dev_id, 0, E2PROM_SIZE);
	/* Check magic number and version */
	magic = *(uint *)src;
	if ((magic & E2P_MAGIC_VAL_MASK) != E2P_MAGIC_VALID) {
		printf("Bad magic number!");
		goto error_out;
	}	
	tmp = src + sizeof(uint);
	do {
		e2pdt edata;
		ushort sval = 0;
		memset((char *)&edata, 0, sizeof(e2pdt));
		memcpy((char *)&edata, tmp, 2*sizeof(uchar));
		memcpy(edata.buf, tmp+sizeof(uchar)*2, edata.elength);			
		if(edata.etype == E2P_HWID)
		{
			memcpy((char *)&sval, edata.buf, edata.elength);
			*e2prom_hwid = (ushort)(sval);
			success = 1;
			break;
		}
		/* Find next */
		tmp = tmp + sizeof(uchar)*2 + edata.elength;
	} while ((++ix) < (sizeof(e2p_keyword)/sizeof(e2pdnt)));

	if(success)
	{
		if(src)
			free(src);
		return 0;
	}
error_out:
	printf("Get pid form e2prom error, please check e2prom!\n");
	if(src)
		free(src);
	return -1;
}

2. 区分dtb文件

c 复制代码
index f31bef24e2..5c2e2a654d 100755
--- 
+#define EPU_HWID            0x145
+#define XEPU_HWID           0x4d4
+#define XEPU_DTB_FILE          "rk-kernel-xepu.dtb"
+#define EPU_DTB_FILE           "rk-kernel-epu.dtb"
+
+char *dtb_file = NULL;
+
 int rk_board_init(void)
 {
        struct udevice *pinctrl, *regulator;
        int ret;
+       ushort hwid;
+ 
+       /* different products's dtb file are distinguished according to HWID */
+       e2prom_get_hwid(&hwid);
+       if(hwid == XEPU_HWID)
+               dtb_file = XEPU_DTB_FILE;
+       else if(hwid == EPU_HWID)
+               dtb_file = EPU_DTB_FILE;
+       else
+               dtb_file = EPU_DTB_FILE;
+
+       printf("%s[%d]: hwid=0x%x, dtb_file:%s\n", __func__,__LINE__, hwid, dtb_file);

可以看到 XEPU_DTB_FILE 、 EPU_DTB_FILE 与打包工具中的FDT_PATH_XEPU、FDT_PATH_EPU是对应的,因为最后在检索时就是根据此值来进行区分。 另外,定义了全局指针变量dtb_file是为了传递获取到的具体设备的索引值。在何处会用到呢,必定是在对设备树进行检索时。需要修改代码,将获取到的实际索引值传递进去。

c 复制代码
--- a/arch/arm/mach-rockchip/resource_img.c
+++ b/arch/arm/mach-rockchip/resource_img.c
@@ -27,7 +27,9 @@ DECLARE_GLOBAL_DATA_PTR;
 #define ENTRY_TAG_SIZE                 4
 #define MAX_FILE_NAME_LEN              220
 #define MAX_HASH_LEN                   32
-#define DTB_FILE                       "rk-kernel.dtb"
+//#define DTB_FILE                     "rk-kernel.dtb"
+
+extern char *dtb_file;
 
 /*
  *         resource image structure
@@ -284,7 +286,7 @@ static int read_dtb_from_android_v2(int rsce_base, int dtb_offset, int dtb_size)
         * we don't need to verify DTB hash from resource.img file entry.
         */
 #ifndef CONFIG_ROCKCHIP_DTB_VERIFY
-       if (replace_resource_entry(DTB_FILE, rsce_base, dtb_offset, dtb_size))
+       if (replace_resource_entry(dtb_file, rsce_base, dtb_offset, dtb_size))
                printf("Failed to load dtb from v2 dtb position\n");
        else
 #endif
@@ -344,7 +346,7 @@ static int resource_create_list(struct blk_desc *dev_desc, int rsce_base)
                        goto err;
                } else {
                        free(hdr);
-                       return replace_resource_entry(DTB_FILE, rsce_base,
+                       return replace_resource_entry(dtb_file, rsce_base,
                                                      0, fdt_totalsize(hdr));
                }
        }
@@ -868,9 +870,9 @@ int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size)
        file = rockchip_read_hwid_dtb();
        /* If dtbs matched hardware id(GPIO/ADC) not found, try the default */
        if (!file)
-               file = get_file_info(DTB_FILE);
+               file = get_file_info(dtb_file);
 #else
-       file = get_file_info(DTB_FILE);
+       file = get_file_info(dtb_file);
 #endif
        if (!file)
                return -ENODEV;

这里需要将DTB_FILE用dtb_file中的值进行替换。 至此,整个修改就完成了,编译更新uboot的内核版本,通过修改EEPROM中HWID的值就可以实现加载不同的dtb文件了

相关推荐
小糖学代码6 小时前
LLM系列:1.python入门:3.布尔型对象
linux·开发语言·python
shizhan_cloud6 小时前
Shell 函数的知识与实践
linux·运维
Deng8723473486 小时前
代码语法检查工具
linux·服务器·windows
霍夫曼8 小时前
UTC时间与本地时间转换问题
java·linux·服务器·前端·javascript
月熊9 小时前
在root无法通过登录界面进去时,通过原本的普通用户qiujian如何把它修改为自己指定的用户名
linux·运维·服务器
大江东去浪淘尽千古风流人物10 小时前
【DSP】向量化操作的误差来源分析及其经典解决方案
linux·运维·人工智能·算法·vr·dsp开发·mr
赖small强10 小时前
【Linux驱动开发】NOR Flash 技术原理与 Linux 系统应用全解析
linux·驱动开发·nor flash·芯片内执行
IT运维爱好者12 小时前
【Linux】LVM理论介绍、实战操作
linux·磁盘扩容·lvm
LEEE@FPGA12 小时前
ZYNQ MPSOC linux hello world
linux·运维·服务器
郝学胜-神的一滴12 小时前
Linux定时器编程:深入理解setitimer函数
linux·服务器·开发语言·c++·程序人生