擊左上方藍色“一口Linux”,選擇“設為星標”
第一時間看干貨文章 ?【干貨】嵌入式驅動工程師學習路線 ?【干貨】Linux嵌入式知識點-思維導圖-免費獲取 ?【就業】一個可以寫到簡歷的基于Linux物聯網綜合項目 ?【就業】簡歷模版
從 DTS 到 Driver Probe,徹底吃透 Linux 板級硬件描述機制, 先看一個框架圖

在 ARM、RISC-V、PowerPC 以及大量國產化 SoC 平臺中,Device Tree(設備樹)已經成為 Linux BSP、驅動適配和板級 bring-up 的核心基礎設施。很多系統研發工程師日常會改 DTS、排查 probe 失敗、修 GPIO 和中斷,但如果只停留在“會改節點”的層面,遇到 deferred probe、overlay、phandle 依賴、時鐘樹和多層 dtsi 繼承時就很容易陷入低效排查。
我們從 DTS 源文件 → DTB 裝載 → 內核 early boot → OF framework → platform driver probe → 運行時調試 全鏈路展開。
第一章:為什么 Linux 需要 Device Tree
早期 ARM Linux 大量依賴 mach-xxx/board-xxx.c ,把 UART 基地址、GPIO 復用、I2C 從設備、PHY 地址、SPI Flash 等板級信息直接寫死在內核源碼里。這樣做的最大問題是:每換一塊板子,都要改一次 kernel source 并重新編譯,導致 BSP 長期碎片化。Device Tree 的核心價值,就是把板級硬件差異從內核代碼中剝離,遷移到外部描述文件,讓 kernel image 與具體板型解耦。
舊模式:Board 差異 -> board-xxx.c -> 重新編譯 kernel新模式:Board 差異 -> DTS/DTB -> 同一 kernel image
實際 BSP 很少只用一個 dts,而是 SoC 層、模組層、板級層多層繼承:SoC .dtsi 提供控制器節點,board .dts 負責打開狀態和掛具體外設。這樣 UART、I2C、PCIe、GMAC 等公共資源在 SoC 層統一維護,板級只覆蓋差異部分,顯著提升可維護性
soc.dtsi|+-- module.dtsi|+-- board.dts
第二章:設備樹的數據結構本質設備樹本質是樹狀 node + property 結構。每個 node 對應一個硬件對象,例如 UART 控制器、I2C 總線、GPIO 控制器、以太網 MAC、PCIe Root Complex。節點名通常采用 name@addr 形式,其中地址與寄存器基址相關。
uart0: serial@ff1a0000 {compatible = "rockchip,rk3568-uart";reg = ;status = "okay";};
流程圖:
根節點 /|+-- soc|+-- uart+-- i2c+-- spi
驅動 probe 時幾乎所有初始化參數都來自 property: reg 提供寄存器地址, interrupts 提供 IRQ, clocks 提供時鐘輸入, gpios 提供控制線, phy-handle 建立 MAC 與 PHY 關聯。本質上,DTS 就是驅動初始化的靜態配置數據庫。
Property|+-- reg -> ioremap+-- interrupts -> request_irq+-- clocks -> clk_get+-- gpios -> gpiod_get
BootROM 先啟動 Bootloader,U-Boot 再加載 kernel image 和 dtb 文件,隨后通過 booti/bootm 把 dtb 地址傳遞給內核。ARM64 平臺通常通過 x0 寄存器傳遞 FDT 地址,kernel 在 early boot 階段解析。
ROM|vU-Boot|+--> load Image|+--> load xxx.dtb|vbooti|vKernel start
DTB 在啟動階段仍是 Flattened Device Tree(二進制扁平結構),內核通過 early_init_dt_scan 掃描內存、chosen、bootargs、reserved-memory 等關鍵節點,隨后構建 OF(Open Firmware)節點對象樹,為后續 platform device 創建提供基礎。
DTB blob|vearly_init_dt_scan|vunflatten_device_tree|vstruct device_node tree
很多人以為 DTS 節點存在,驅動就會自動 probe,實際上中間還隔著完整 OF 創建設備鏈路。內核通過 of_platform_populate 遍歷總線節點,把符合條件的 node 轉成 platform_device 。只有設備對象創建成功,才會進入 driver match。
DT node|vof_platform_populate|vplatform_device
驅動中的 of_match_table 定義兼容字符串列表,platform bus 在 platform_match 中調用 of_match_device 完成匹配。一旦 compatible 對上,內核就會進入 probe。
staticconststruct of_device_id xxx_of_match = {{ .compatible = "vendor,dev" },{}};
compatible string|vof_match_device|vdriver probe
設備樹強大的地方,不是單節點描述,而是節點間引用關系。 phandle 允許一個節點引用另一個節點,例如 MAC 引用 PHY、LCD 引用背光、設備引用 regulator。它本質上是樹節點之間的靜態依賴圖。
ethernet node|+--> phy-handle ---> phy node|+--> clocks -------> clk node
驅動里常見問題不是 compatible 不匹配,而是依賴資源讀取失敗。例如:
interrupt-parent 決定 IRQ 域
clocks 決定輸入時鐘源
reset-gpios 控制硬件復位
pinctrl 決定 IO 復用
任何一個 property 缺失,都可能導致 probe defer。
probe|+-- parse irq+-- parse clock+-- parse gpio+-- parse pinctrl|vresource ready ?
Overlay 的本質是在運行時向現有 OF 樹打補丁,新增 node 或修改 property,非常適合 FPGA、可插拔模組、攝像頭擴展板等場景。它不是重新加載內核,而是動態修改設備樹對象并觸發設備創建。
base dtb|+-- overlay.dtbo|vmergeto live tree
overlay 最常見問題包括:target path 錯誤、phandle 沖突、fragment 覆蓋錯誤、資源重復申請。尤其 GPIO 和 regulator 節點,若 base tree 已被占用,overlay 插入后很容易導致 probe fail 或資源 busy。
overlay load|vmerge fragment|+-- success -> create device+-- fail -> rollback
核心排查順序:
檢查 dtb 是否真正被加載
確認 /proc/device-tree 節點存在
核對 compatible
檢查 status 是否 okay
查看 dmesg 是否 deferred probe
檢查 clocks / irq / gpio 依賴
節點不存在?-> dtb 未生效節點存在但未 probe?-> compatible / statusprobe defer?-> clock gpio irq dependency
成熟 BSP 團隊不會只靠“改 DTS 試試看”,而是建立標準化排查路徑:
fdtdump 校驗 dtb
dtc -I dtb -O dts 反編譯核對
dmesg | grep OF
/sys/firmware/devicetree/base
debugfs 查看 pinctrl / clk
ftrace 跟蹤 probe defer
最終目標不是會寫節點,而是建立 從 DTS 到驅動資源鏈路的完整心智模型 。這樣無論是ARM、飛騰、瑞芯微、NXP 還是 Marvell 平臺 BSP,效率都會明顯提升。
最后設備設備樹的
總流程圖:
DTS -> DTC -> DTB-> U-Boot load-> Kernel early scan-> OF tree-> platform_device-> compatible match-> probe-> parse irq/clk/gpio-> driver ready
end
一口Linux
關注,回復【1024】海量Linux資料贈送
精彩文章合集
文章推薦