4.3.27. boardinfo 调试指南

4.3.27.1. 概述

boardinfo 驱动为上层软件提供了获取板级信息的接口。本文档将详细介绍 boardinfo 驱动的功能,并提供 sysfs 和 userspace API 两种访问方式。

4.3.27.2. 功能描述

boardinfo 驱动具备以下主要功能:

  • 读取关键硬件信息,包括芯片型号、名称、版本号、启动方式、SOC ID 及 DDR 信息等。

  • 配置下次启动时使用的 BAK slot,以便在系统启动时切换到指定的备份状态。

通过以上功能,boardinfo 驱动能够为系统提供实时和准确的板级信息,确保系统运行的稳定性和可靠性。

接口名称统一命名与 userspace API 返回值跟踪表(X5为例)

接口名称 接口功能 接口权限 userspace API 结果类型 返回值
soc_gen 查看芯片型号 RO 字符串 X5
soc_name 查看芯片名称,包括子型号 RO 字符串 X5M
X5H
UKNOWN
hw_name 查看硬件板子名称 RO 字符串 x5-fpga
x5-soc
x5-svb
x5-evb
board_version 查看硬件板子版本号 RO 字符串 v1
v2
v3
hw_info 查看硬件板子全名称
(由<hw_name>-<board_version>-<ddr_vendor>-<ddr_size>-<ddr_freq>组成)
RO 字符串 x5-evb-v2-cxmt-2048MB-4266
...
bootdevice_name 查看启动方式 RO 字符串 emmc
sd
nand
soc_uid 查看 SOC 的 ID 号 RO 字符串 soc唯一id
ddr_vendor 查看 DDR 厂商 RO 字符串 DDR厂商
ddr_type 查看 DDR类型,如LPDDR4或LPDDR4X RO 字符串 LPDDR4
LPDDR4X
ddr_freq 查看 DDR最高速率,单位Mbps RO 字符串 3200 Mbps
3733 Mbps
4266 Mbps
ddr_size 查看 DDR容量,单位MB RO 字符串 1024MB
2048MB
4096MB
8192MB
board_id 查看硬件板子 ID RO 字符串 当前board_id,以十六进制形式打印
sec_chip 查看是否是secure芯片 RO 字符串 未烧key的芯片: nosec_chip
烧地瓜key的芯片: sec_chip1
烧客户自己public key hash的芯片: sec_chip2
sec_boot 查看是否开启AVB和dm-verity校验 RO 字符串 enable
disable
bak_slot 读:当前启动的 BAK slot;
写:设置下次启动的 BAK slot
R/W 字符串 0
1

如何烧客户自己的public key hash,请参考X5 Customer root rsa key hash烧录及使用

4.3.27.3. 驱动代码

socinfo 驱动代码位于 kernel/drivers/soc/hobot/socinfo/socinfo.c,主要功能如下:

  • 读取 DTS 配置文件中配置的板级信息,并保存到对应变量中。

	if (read_from_property(pdev, "soc_gen", &soc_gen) ||
		read_from_property(pdev, "soc_name", &soc_name) ||
		read_from_property(pdev, "hw_name", &hw_name) ||
		read_from_property(pdev, "board_version", &board_version) ||
		read_from_property(pdev, "hw_info", &hw_info) ||
		read_from_property(pdev, "bootdevice_name", &bootdevice_name) ||
		read_from_property(pdev, "soc_uid", &soc_uid) ||
		read_from_property(pdev, "board_id", &board_id) ||
		read_from_property(pdev, "sec_chip", &sec_chip) ||
		read_from_property(pdev, "sec_boot", &sec_boot)) {
		return -1;
	}
  • 实现 sysfs 接口,提供上层软件获取板级信息的接口。

static struct class_attribute soc_gen_attribute =
	__ATTR(soc_gen, 0444, soc_gen_show, NULL);

static struct class_attribute soc_name_attribute =
	__ATTR(soc_name, 0444, soc_name_show, NULL);

static struct class_attribute hw_name_attribute =
	__ATTR(hw_name, 0444, hw_name_show, NULL);

static struct class_attribute board_version_attribute =
	__ATTR(board_version, 0444, board_version_show, NULL);

static struct class_attribute hw_info_attribute =
	__ATTR(hw_info, 0444, hw_info_show, NULL);

static struct class_attribute bootdevice_name_attribute =
	__ATTR(bootdevice_name, 0444, bootdevice_name_show, NULL);

static struct class_attribute soc_uid_attribute =
	__ATTR(soc_uid, 0444, soc_uid_show, NULL);

static struct class_attribute ddr_vender_attribute =
	__ATTR(ddr_vendor, 0444, ddr_vender_show, NULL);

static struct class_attribute ddr_type_attribute =
	__ATTR(ddr_type, 0444, ddr_type_show, NULL);

static struct class_attribute ddr_freq_attribute =
	__ATTR(ddr_freq, 0444, ddr_freq_show, NULL);

static struct class_attribute ddr_size_attribute =
	__ATTR(ddr_size, 0444, ddr_size_show, NULL);

static struct class_attribute board_id_attribute =
	__ATTR(board_id, 0444, board_id_show, NULL);

static struct class_attribute sec_chip_attribute =
	__ATTR(sec_chip, 0444, sec_chip_show, NULL);

	static struct class_attribute sec_boot_attribute =
	__ATTR(sec_boot, 0444, sec_boot_show, NULL);

static struct class_attribute bak_slot_attribute =
	__ATTR(bak_slot, 0644, bak_slot_show, bak_slot_store);

“soc_gen” 和 “soc_name” 需要在 Kernel DTS 文件中配置,路径是kernel/arch/arm64/boot/dts/hobot/x5.dtsi,节点名为 “socinfo”。

当前在 kernel dts  "hw_name"  "board_version" 的占位符长度为16字节,"hw_info" 的占位符长度为32字节,如果对应的字段超出了占位符的长度,将会导致 socinfo 此驱动初始化失败。

kernel_dts.png

“board_id”、”hw_name”、”board_version” 等信息需要在 Uboot DTS 文件中配置,路径是uboot/arch/arm/dts/x5.dtsi,节点名为 “board_type”。
DTS 中的 board_type_array 字段对应 “board_id”,board_id 相关修改请参考修改 Board ID 的宏定义
hardward_array 字段对应 “hw_name”,board_version 字段对应 “board_version”。

uboot_dts1.png

4.3.27.4. 功能使用

sysfs 接口

sysfs 接口路径位于 /sys/class/socinfo/,目前支持以下信息的获取:

例如要查看板级接口信息,可在命令行执行以下命令:

#查看芯片型号
root@buildroot:~# cat /sys/class/socinfo/soc_gen
x5

#查看芯片名称
root@buildroot:~# cat /sys/class/socinfo/soc_name
X5M

#查看硬件板子名称
root@buildroot:~# cat /sys/class/socinfo/hw_name
X5_EVB_LP4

#查看硬件板子版本号
root@buildroot:~# cat /sys/class/socinfo/board_version
1_B

#查看硬件板子全名称
root@buildroot:~# cat /sys/class/socinfo/hw_info
X5_EVB_LP4_1_B_cxmt_4096MB_4266

#查看启动方式
root@buildroot:~# cat /sys/class/socinfo/bootdevice_name
emmc

#查看SOC的ID号
root@buildroot:~# cat /sys/class/socinfo/soc_uid
0x308064960e31499301f0822400000000

#查看DDR厂商
root@buildroot:~# cat /sys/class/socinfo/ddr_vendor
cxmt

#查看DDR类型
root@buildroot:~# cat /sys/class/socinfo/ddr_type
LPDDR4

#查看DDR最高速率
root@buildroot:~# cat /sys/class/socinfo/ddr_freq
4266 Mbps

#查看DDR容量
root@buildroot:~# cat /sys/class/socinfo/ddr_size
4096MB

#查看硬件板子 ID
root@buildroot:~# cat /sys/class/socinfo/board_id
0x0202

#查看芯片secure类型
root@buildroot:~# cat /sys/class/socinfo/sec_chip
sec_chip1

#查看是否开启secure boot
root@buildroot:~# cat /sys/class/socinfo/sec_boot
enable

#查看当前启动的 BAK slot
root@buildroot:~# cat /sys/class/socinfo/bak_slot
0
#设置下次启动的 BAK slot
root@buildroot:~# echo 1 > /sys/class/socinfo/bak_slot
root@buildroot:~# reboot
root@buildroot:~# cat /sys/class/socinfo/bak_slot
1

注意:如果芯片名称 soc_nameUKNOWN,则属于是早期出厂芯片,未在eFUSE中烧写对应bit,需要根据芯片丝印区分芯片类型。

hw_info 由 <hw_name>-<board_version>-<ddr_vendor>-<ddr_size>-<ddr_freq> 组成:

  • hw_name: X5_EVB_LP4

  • board_version: 1_B

  • ddr_vendor: cxmt

  • ddr_size: 4096MB

  • ddr_freq: 4266

userspace API 接口

源码路径:hbre/hbutils/boardinfo

头文件: boardinfo.h

链接库: libboardinfo.so.1

接口定义

hb_get_boardinfo

【函数声明】

int32_t hb_get_boardinfo(char *key, void *dst, uint32_t len);

【参数描述】

  • [OUT] key: 要获取的板级信息

  • [OUT] dst: 接收结果的缓存空间

  • [IN] len: 缓存空间最大长度

【返回值】

  • HB_BINFO_SUCCESS:成功

  • HB_BINFO_INVALID_PARAM: 非法参数,如空指针

  • HB_BINFO_SHORT_BUF: 缓存空间过小

  • HB_BINFO_PLAT_NOT_SUPPORT: 本平台不支持的板级信息

【功能描述】

获取板级信息 key,结果将存入 dst,并返回错误代码。

动态库接口返回的错误类型

动态库错误值定义如下:

enum hb_binfo_retval {
	HB_BINFO_SUCCESS,
	HB_BINFO_INVALID_PARAM,
	HB_BINFO_SHORT_BUF,
	HB_BINFO_PLAT_NOT_SUPPORT,
};

示例代码

调用 userspace API 接口时,需先链接动态库,示例代码如下:

#include <stdio.h>
#include <stdint.h>
#include "boardinfo.h"

int main(void) {
	int32_t ret;
	char buf[1024];

	ret = hb_get_boardinfo("soc_gen", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("soc_gen:%s\n", buf);
	}

	ret = hb_get_boardinfo("soc_name", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("soc_name:%s\n", buf);
	}

	ret = hb_get_boardinfo("hw_name", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("hw_name:%s\n", buf);
	}

	ret = hb_get_boardinfo("board_version", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("board_version:%s\n", buf);
	}

	ret = hb_get_boardinfo("hw_info", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("hw_info:%s\n", buf);
	}

	ret = hb_get_boardinfo("bootdevice_name", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("bootdevice_name:%s\n", buf);
	}

	ret = hb_get_boardinfo("soc_uid", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("soc_uid:%s\n", buf);
	}

	ret = hb_get_boardinfo("ddr_type", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("ddr_type:%s\n", buf);
	}

	ret = hb_get_boardinfo("ddr_size", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("ddr_size:%s\n", buf);
	}

	ret = hb_get_boardinfo("ddr_vendor", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("ddr_vendor:%s\n", buf);
	}

	ret = hb_get_boardinfo("ddr_freq", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("ddr_freq:%s\n", buf);
	}

	ret = hb_get_boardinfo("board_id", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("board_id:%s\n", buf);
	}

	ret = hb_get_boardinfo("sec_chip", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("sec_chip:%s\n", buf);
	}

	ret = hb_get_boardinfo("sec_boot", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("sec_boot:%s\n", buf);
	}

	ret = hb_get_boardinfo("board_id", buf, 2);
	if (ret == 0) {
		printf("hb_get_boardinfo test HB_BINFO_SHORT_BUF failed\n");
	} else {
		printf("hb_get_boardinfo test HB_BINFO_SHORT_BUF pass\n");
	}

	ret = hb_get_boardinfo("bak_slot", buf, 1024);
	if (ret) {
		printf("hb_get_boardinfo failed, ret:%d\n", ret);
	} else {
		printf("bak_slot:%s\n", buf);
	}

	ret = hb_get_boardinfo(NULL, buf, 1024);
	if (ret == 0) {
		printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM failed\n");
	} else {
		printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM pass\n");
	}

	ret = hb_get_boardinfo("xx", buf, 1024);
	if (ret == 0) {
		printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM failed\n");
	} else {
		printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM pass\n");
	}

	return 0;
}

4.3.27.5. 常见问题

  • 使用 userspace API 接口时,如果传入的 key 值不存在,则返回 HB_BINFO_INVALID_PARAM 错误,此时 dst 指针不会被修改,需要检查返回值是否为 0。