前言
在项目开发过程中,可能会遇到多个项目使用同一个源码仓库,并且代码是高度复用的,如果在不同的项目中只是代码存在一些差异,会有很好的解决方式去区分,但可能在不同的项目中设备树存在差异性,这个时候会相对来说比较难处理,本文目的就是以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文件了