前言
针对uboot已经加载完设备树的情况下,在uboot阶段对设备的内容进行动态的修改。
一、设备树
主要是针对gpio这个属性中的RK_PA6进行修改
//这个电主要是供usb 的 vbus电,其中gpio是使能脚,这里修改的就是使能脚
vcc5v0_host: vcc5v0-host-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_host";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc5v0_usb>;
pinctrl-names = "default";
pinctrl-0 = <&vcc5v0_host_en>;
};
二、代码及log
2.1 代码
int usb_otg_vbus_dtb_overlay(int switch_usb_port)
{
const char *vbus_node_path = "/vcc5v0-host-regulator"; //设备树vbus节点路径
const void *fdt_blob = gd->fdt_blob; //设备树的handle,用作get_prop
void *fdt = (void *)gd->fdt_blob; //设备树的handle,用作set_prop
int vbus_node_offset; //vbus的节点 offset
const char *prop_name = "gpio"; //需要在vbus节点获取的属性
int prop_len; //gpio这个属性值的数量
const u32 *prop; //获取gpio这个属性值数组
fdt32_t tmp_prop[3] = {0, 0, 0}; //存储获取到的属性值
vbus_node_offset = fdt_path_offset(fdt_blob, vbus_node_path);
if (vbus_node_offset < 0) {
printf("path:%s not exist \n", vbus_node_path);
}
prop = fdt_getprop(fdt_blob, vbus_node_offset, prop_name, &prop_len);
if (prop_len < 0) {
printf("%s, Failed to get property length\n", __func__);
} else {
for (int i = 0; i < prop_len / sizeof(u32); i++) {
//大小端转换,不然数值看不出来(对不上RK_PA6这些数值)
fdt32_t tmp = cpu_to_fdt32(prop[i]);
printf("%s %u:%u \n", __func__, prop[i], tmp);
tmp_prop[i] = tmp;
}
}
//这里根据switch_usb_port类型使用gpio0中不同的pin脚
if (switch_usb_port == USE_USB2_PORT) {
tmp_prop[1] = RK_PA7;
} else if (switch_usb_port == USE_USB1_PORT) {
tmp_prop[1] = RK_PA6;
}
//修改设备树内容
//这里需要先转一遍,再写入,不然会大小端会出错的(导致整个设备树乱掉)
for (int i = 0; i < prop_len / sizeof(u32); i++) {
tmp_prop[i] = fdt32_to_cpu(tmp_prop[i]);
}
const void *new_prop = tmp_prop;
int ret = fdt_setprop_inplace(fdt, vbus_node_offset, prop_name, new_prop, prop_len);
if (ret < 0) {
printf("%s libfdt fdt_setprop(): %s\n", __func__, fdt_strerror(ret));
}
//这部分查看修改效果
prop = fdt_getprop(fdt_blob, vbus_node_offset, prop_name, &prop_len);
if (prop_len < 0) {
printf("--%s, Failed to get property length\n", __func__);
} else {
for (int i = 0; i < prop_len / sizeof(u32); i++) {
fdt32_t tmp = cpu_to_fdt32(prop[i]);
printf("--%s %u:%u \n", __func__, prop[i], tmp);
}
}
return 0;
}
注意事项:
1.关于大小端转换,读取出来的设备树内容需要使用cpu_to_fdt32来转换一下才可以正常读出。写入的数据也需要使用fdt32_to_cpu进行转换一下才可以正常写入,否则设备树会乱掉,然后出现各种错误。
2.不建议新增属性值,新增属性值会增大设备树的大小,导致出现未知错误。
3.建议使用带inplace尾缀的api进行操作。
2.2 log确认
在代码后面有一属性复读的操作,可得到如下log
2.3 效果确认
使用万用表进行电压的确认。
修改前,该usb口做host vbus电压是正常供应5V
修改后,该usb口做host vbus电压是为0,因为使能脚被改变了,所以vbus没有被使能供电。