当前位置:首页 > 技术 > 正文内容

U-Boot设备树操作指南:查询与配置FDT节点

访客 技术 2026年8月12日 2

在嵌入式系统开发中,设备树(Device Tree,简称DT或FDT - Flattened Device Tree)是描述硬件配置的关键。U-Boot引导加载程序提供了强大的FDT工具,允许开发者在启动阶段查看和修改设备树节点。本文将详细介绍如何在U-Boot控制台中使用fdt命令进行设备树的查询与配置。

FDT命令概览

当系统在U-Boot控制台停下时,输入fdt命令,即可获取其使用帮助信息。

sunxi#fdt
fdt - flattened device tree utility commands
Usage:
fdt addr [-c] <addr> [<length>] - 设置当前操作的FDT地址 [并指定长度]
fdt move <fdt> <newaddr> <length> - 复制FDT到新地址并使其激活
fdt resize - 调整FDT大小至下一个4K对齐地址
fdt print <path> [<prop>] - 从指定路径递归打印节点及属性
fdt list <path> [<prop>] - 打印指定路径下的一级节点或属性
fdt get value <var> <path> <prop> - 获取属性值并存入变量
fdt get name <var> <path> <index> - 获取指定索引节点的名称并存入变量
fdt get addr <var> <path> <prop> - 获取属性起始地址并存入变量
fdt get size <var> <path> [<prop>] - 获取属性大小或节点数量并存入变量
fdt set <path> <prop> [<val>] - 设置指定路径节点的属性值
fdt mknode <path> <node> - 在指定路径下创建新节点
fdt rm <path> [<prop>] - 删除节点或属性
fdt header - 显示FDT头部信息
fdt bootcpu <id> - 设置启动CPU ID
fdt memory <addr> <size> - 添加/更新内存节点
fdt rsvmem print - 显示当前内存保留区域
fdt rsvmem add <addr> <size> - 添加内存保留区域
fdt rsvmem delete <index> - 删除内存保留区域
fdt chosen [<start> <end>] - 添加/更新/chosen分支
<start>/<end> - initrd起始/结束地址
注意: 省略路径前的'/'来解引用别名, 例如 'fdt print ethernet0'.

在这些命令中,fdt listfdt set是日常调试中最常用的两个命令。fdt list用于查看设备树节点的配置信息,而fdt set则用于修改这些配置。

1. 设备树节点查询

在修改设备树配置之前,首先需要确定目标字段在设备树中的完整路径。如果路径不明确,可以按照以下步骤逐步查询。

1.1 从根节点开始探索

首先可以从设备树的根节点/开始查询,查看其直接子节点及属性。

sunxi#fdt list /
/ {
    model = "{LICHEE_CHIP}";
    compatible = "arm,{LICHEE_CHIP}", "arm,{LICHEE_CHIP}";
    interrupt-parent = <0x00000001>;
    #address-cells = <0x00000002>;
    #size-cells = <0x00000002>;
    ......................
    cpuscfg {
    };
    ion {
    };
    dram {
    };
    memory@40000000 {
    };
    interrupt-controller@1c81000 {
    };
    sunxi-chipid@1c14200 {
    };
    timer {
    };
    pmu {
    };
    dvfs_table {
    };
    dramfreq {
    };
    gpu@0x01c40000 {
    };
    wlan {
    };
    bt {
    };
    btlpm {
    };
};

如果找到了目标配置,例如无线局域网(WLAN)的配置位于/wlan节点,可以直接使用fdt list命令查看其详细信息。

sunxi#fdt list /wlan
wlan {
    compatible = "allwinner,sunxi-wlan";
    clocks = <0x00000096>;
    wlan_power = "vcc-wifi";
    wlan_io_regulator = "vcc-wifi-io";
    wlan_busnum = <0x00000001>;
    status = "okay";
    device_type = "wlan";
    wlan_regon = <0x00000077 0x0000000b 0x00000002 0x00000001 0xffffffff 0xffffffff 0x00000000>;
    wlan_hostwake = <0x00000077 0x0000000b 0x00000003 0x00000006 0xffffffff 0xffffffff 0x00000000>;
};

1.2 深入特定子节点:以 soc 节点为例

如果在根目录下未能找到所需配置,它可能位于更深层的节点中,例如/soc

sunxi#fdt list /soc
soc@01c00000 {
    compatible = "simple-bus";
    #address-cells = <0x00000002>;
    #size-cells = <0x00000002>;
    ranges;
    device_type = "soc";
    ......................
    hdmi@01ee0000 {
    };
    tr@01000000 {
    };
    pwm@01c21400 {
    };
    nand0@01c03000 {
    };
    thermal_sensor {
    };
    cpu_budget_cool {
    };
    .......................
};

例如,要查看nand0设备的配置,可以使用完整的路径:

sunxi#fdt list /soc/nand0
nand0@01c03000 {
    compatible = "allwinner,sun50i-nand";
    device_type = "nand0";
    reg = <0x00000000 0x01c03000 0x00000000 0x00001000>;
    interrupts = <0x00000000 0x00000046 0x00000004>;
    clocks = <0x00000004 0x0000007e>;
    pinctrl-names = "default", "sleep";
    pinctrl-1 = <0x00000081>;
    nand0_regulator1 = "vcc-nand";
    nand0_regulator2 = "none";
    nand0_cache_level = <0x55aaaa55>;
    nand0_flush_cache_num = <0x55aaaa55>;
    nand0_capacity_level = <0x55aaaa55>;
    nand0_id_number_ctl = <0x55aaaa55>;
    nand0_print_level = <0x55aaaa55>;
    nand0_p0 = <0x55aaaa55>;
    nand0_p1 = <0x55aaaa55>;
    nand0_p2 = <0x55aaaa55>;
    nand0_p3 = <0x55aaaa55>;
    status = "disabled";
    nand0_support_2ch = <0x00000000>;
    pinctrl-0 = <0x000000a9 0x000000aa>;
};

1.3 利用设备树别名简化路径

设备树中的/aliases节点定义了设备完整路径的短名称(别名),这可以极大地简化查询操作。我们可以先查看所有定义的别名:

sunxi#fdt list /aliases
aliases {
    serial0 = "/soc@01c00000/uart@01c28000";
    ..............
    mmc0 = "/soc@01c00000/sdmmc@01c0f000";
    mmc2 = "/soc@01c00000/sdmmc@01C11000";
    nand0 = "/soc@01c00000/nand0@01c03000";
    disp = "/soc@01c00000/disp@01000000";
    lcd0 = "/soc@01c00000/lcd0@01c0c000";
    hdmi = "/soc@01c00000/hdmi@01ee0000";
    pwm = "/soc@01c00000/pwm@01c21400";
    boot_disp = "/soc@01c00000/boot_disp";
};
sunxi#

有了别名,就可以直接使用别名来查询节点,例如查询nand0

sunxi#fdt list nand0
nand0@01c03000 {
    compatible = "allwinner,sun50i-nand";
    device_type = "nand0";
    reg = <0x00000000 0x01c03000 0x00000000 0x00001000>;
    ..................
    pinctrl-names = "default", "sleep";
    pinctrl-1 = <0x00000081>;
};

请注意,在所有的fdt命令中,别名都可以作为path参数使用,例如fdt list <alias>fdt set <alias> <prop> <val>

2. 设备树节点修改

fdt set命令用于修改设备树中的属性值。它支持整数、字符串以及它们的数组形式。

2.1 修改整数属性

修改整数属性的命令格式为:fdt set <path> <prop> <value>。请注意,整数值通常需要用尖括号< >包围。

示例: 修改/wlan节点下的wlan_busnum属性。

sunxi#fdt list /wlan
wlan {
    compatible = "allwinner,sunxi-wlan";
    clocks = <0x00000096>;
    wlan_power = "vcc-wifi";
    wlan_io_regulator = "vcc-wifi-io";
    wlan_busnum = <0x00000001>;  // 当前值为1
    status = "disable";
    device_type = "wlan";
};
sunxi#fdt set /wlan wlan_busnum <0x2>
sunxi#fdt list /wlan
wlan {
    compatible = "allwinner,sunxi-wlan";
    clocks = <0x00000096>;
    wlan_power = "vcc-wifi";
    wlan_io_regulator = "vcc-wifi-io";
    wlan_busnum = <0x00000002>; // 修改后值为2
    status = "disable";
    device_type = "wlan";
};

如果需要设置整数数组,只需用空格分隔各个数值,例如:fdt set <path> <prop> <0x1 0x2 0x3>

2.2 修改字符串属性

修改字符串属性的命令格式为:fdt set <path> <prop> "string_value"。字符串值需要用双引号"包围。

示例: 修改/wlan节点下的status属性。

sunxi#fdt list /wlan
wlan {
    compatible = "allwinner,sunxi-wlan";
    clocks = <0x00000096>;
    wlan_power = "vcc-wifi";
    wlan_io_regulator = "vcc-wifi-io";
    wlan_busnum = <0x00000001>;
    status = "okay"; // 当前状态为 "okay"
    device_type = "wlan";
};
sunxi#fdt set /wlan status "disable"
sunxi#fdt list /wlan
wlan {
    compatible = "allwinner,sunxi-wlan";
    clocks = <0x00000096>;
    wlan_power = "vcc-wifi";
    wlan_io_regulator = "vcc-wifi-io";
    wlan_busnum = <0x00000001>;
    status = "disable"; // 修改后状态为 "disable"
    device_type = "wlan";
};
sunxi#

与整数数组类似,字符串数组也通过空格分隔实现,例如:fdt set <path> <prop> "string1" "string2"

3. GPIO与PIN配置的特殊处理

GPIO(通用输入输出)和PIN(引脚)的配置在设备树中通常以特定的数字编码或数组形式表示。理解这些编码对于正确配置至关重要。

3.1 GPIO端口数字编码

在许多Allwinner芯片平台中,GPIO端口被映射为数字编号,如下所示:

#define PA 0
#define PB 1
#define PC 2
#define PD 3
#define PE 4
#define PF 5
#define PG 6
#define PH 7
#define PI 8
#define PJ 9
#define PK 10
#define PL 11
#define PM 12
#define PN 13
#define PO 14
#define PP 15
#define default 0xffffffff // 表示使用默认值

这意味着PH7代表7号端口的第7个引脚(假设从0开始计数)。

3.2 PIN控制(Pinctrl)配置

Pinctrl节点用于管理GPIO引脚的复用功能、上下拉电阻、驱动能力和输出电平。通常存在cpuxcpus两个Pinctrl控制器节点,路径如下:

  • Cpux: /soc/pinctrl@01c20800
  • Cpus: /soc/pinctrl@01f02c00

PIN配置属性字段说明:

属性字段 含义
allwinner,function 对应引脚组的功能,如"lcd0"
allwinner,pins 关联的物理引脚名称列表,如"PD12", "PD13"
allwinner,pname 对应allwinner,pins中每个引脚的逻辑名称
allwinner,muxsel 引脚的复用功能选择,数字编码
allwinner,pull 内部电阻状态(上拉/下拉/无),数字编码
allwinner,drive 驱动能力设置,数字编码
allwinner,data 输出电平状态,数字编码

其中0xffffffff表示使用默认配置。

查看PIN配置示例: 查看cpux控制器下lcd0引脚组的配置。

sunxi#fdt list /soc/pinctrl@01c20800/lcd0
lcd0@0 {
    linux,phandle = <0x000000ab>;
    phandle = <0x000000ab>;
    allwinner,pins = "PD12", "PD13", "PD14", "PD15", "PD16", "PD17", "PD18", "PD19", "PD20", "PD21";
    allwinner,function = "lcd0";
    allwinner,pname = "lcdd0", "lcdd1", "lcdd2", "lcdd3", "lcdd4", "lcdd5", "lcdd6", "lcdd7", "lcdd8", "lcdd9";
    allwinner,muxsel = <0x00000003>;
    allwinner,pull = <0x00000000>;
    allwinner,drive = <0xffffffff>; // 当前驱动能力为默认值
    allwinner,data = <0xffffffff>;
};
sunxi#

修改PIN配置示例:lcd0引脚组的驱动能力设置为0x1

sunxi#fdt set /soc/pinctrl@01c20800/lcd0 allwinner,drive <0x1>
sunxi#fdt list /soc/pinctrl@01c20800/lcd0
lcd0@0 {
    linux,phandle = <0x000000ab>;
    phandle = <0x000000ab>;
    allwinner,pins = "PD12", "PD13", "PD14", "PD15", "PD16", "PD17", "PD18", "PD19", "PD20", "PD21";
    allwinner,function = "lcd0";
    allwinner,pname = "lcdd0", "lcdd1", "lcdd2", "lcdd3", "lcdd4", "lcdd5", "lcdd6", "lcdd7", "lcdd8", "lcdd9";
    allwinner,muxsel = <0x00000003>;
    allwinner,pull = <0x00000000>;
    allwinner,drive = <0x00000001>; // 驱动能力已修改为1
    allwinner,data = <0xffffffff>;
};

说明:allwinner,drive的修改会影响allwinner,pins中列出的所有相关引脚。同样,修改allwinner,muxselallwinner,pullallwinner,data也会对整个引脚组产生类似的影响。

3.3 GPIO通用配置

在某些设备树节点中,GPIO配置可能以一个整数数组的形式直接定义。以USB控制器中的usb_id_gpio属性为例:

sunxi#fdt list /soc/usbc0
usbc0@0 {
    test = <0x00000002 0x00000003 0x12345678>;
    device_type = "usbc0";
    compatible = "allwinner,sun50i-otg-manager";
    ........
    usb_serial_unique = <0x00000000>;
    usb_serial_number = "20080411";
    rndis_wceis = <0x00000001>;
    status = "okay";
    usb_id_gpio = <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0xffffffff 0xffffffff>;
};

usb_id_gpio = <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0xffffffff 0xffffffff>这个数组的解释如下:

属性数值 含义
0x00000030 设备树内部节点信息
0x00000007 GPIO端口号(PH)
0x00000009 端口内引脚序号(PH9)
0x00000000 功能分配(输入)
0x00000001 内部电阻状态(上拉)
0xffffffff 驱动能力(默认值)
0xffffffff 输出电平(默认值)

修改GPIO配置示例: 假设我们要修改usb_id_gpio的驱动能力和输出电平。

sunxi#fdt set /soc/usbc0 usb_id_gpio <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0x2 0x1>
sunxi#fdt list /soc/usbc0
usbc0@0 {
    test = <0x00000002 0x00000003 0x12345678>;
    device_type = "usbc0";
    compatible = "allwinner,sun50i-otg-manager";
    ........
    usb_serial_unique = <0x00000000>;
    usb_serial_number = "20080411";
    rndis_wceis = <0x00000001>;
    status = "okay";
    usb_id_gpio = <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0x00000002 0x00000001>; // 驱动能力和输出电平已修改
};
sunxi#

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。