Device Tree是一種描述硬件的數據結構,它起源於 OpenFirmware (OF)。在Linux 2.6中,ARM架構的板極硬件細節過多地被硬編碼在arch/arm/plat-xxx和arch/arm/mach-xxx,採用Device Tree後,許多硬件的細節可以直接透過它傳遞給Linux,而不再需要在kernel中進行大量的冗餘編碼。Device Tree由一系列被命名的結點(node)和屬性(property)組成,而結點本身可包含子結點。所謂屬性,其實就是成對出現的name和value。
如果要使用Device Tree,首先用戶要了解自己的硬件配置和系統運行參數,並把這些信息組織成Device Tree source file。
Device Tree將會被通過DTC(Device Tree Compiler)編譯成適合機器處理的DTB(device tree blob)文件。
Device Tree不是必須要描述系統中的所有硬件信息,可以動態探測到的設備是不需要描述的,但是無法動態識別的,需要在device tree中描述。例如,USB device不需要描述,usb host controller不能被探測,需要描述。
下面給出一個Device Tree的模版:
/
name = "device-tree"
model = "MyBoardName"
compatible = "MyBoardFamilyName"
#address-cells = <2>
#size-cells = <2>
linux,phandle = <0>
chosen {
name = "chosen"
bootargs = "root=/dev/sda2"
linux,phandle = <4>
}
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0:cpu@0x000 {
device_type = "cpu";
compatible = "arm,cortex-a7";
reg = <0x000>;
clock-latency = <40000>;
clocks = <&cru ARMCLK>;
resets = <&cru SRST_CORE0>;
};
memory {
device_type = "memory";
reg = <0x60000000 0x40000000>;
};
分析上面給出的例子,總結一下幾點:
1、device tree的基本單元是node。這些node被組織成樹狀結構,root node的node name是確定的,必須是“/”。除了root node,每個node都只有一個parent。一個device tree文件中只能有一個root node。
2、每個node中包含了若干的property/value來描述該node的一些特性。
2-1、每個node用節點名字(node name)標識,節點名字的格式是node-name@unit-address。
2-2、如果該node沒有reg屬性(後面會描述這個property),那麼該節點名字中必須不能包括@和unit-address。
2-3、對於cpu,其unit-address就是從0開始編址,以此加一。而具體的設備,其unit-address就是寄存器地址。
3、在一個樹狀結構的device tree中,要想唯一指定一個node必須使用full path。在上面的例子中,cpu node我們可以通過/cpus/cpu@0x000訪問。
4、屬性:
4-1、可能是空,也就是沒有值的定義。
4-2、屬性值是32bit unsigned integers可能是一個u32、u64的數值(值得一提的是cell這個術語,在Device Tree表示32bit的信息單位)。例如#address-cells = <1> 。如果一個device node中包含了有尋址需求(要定義reg property),那麼就必須要定義#address-cells和#size-cells這兩個屬性
4-3、屬性值是text string或者string list,可能是一個字符串。例如device_type = "cpu";
一個node被定義成如下:
[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
}
“[]”表示option,label方便在dts文件中引用,一個dts文件可以嵌套多個node,並且可以通過include xxx.dtsi來包含其他的node(如果包含,dti中的內容將把dtsi覆蓋)
其中的相關的規則如下:
1、aliases 節點定義了一些別名。(當要引用一個node的時候要指明相對於root node的full path,如果多次引用,每次都要寫這麼複雜的字符串多少是有些麻煩,因此可以在aliases 節點定義一些設備節點full path的縮寫。)
2、memory device node是所有設備樹文件的必備節點,它定義了系統物理內存的layout。reg定義了該memory的起始地址和長度。其device_type必須等於memory。
3、device_type屬性定義了該node的設備類型,例如cpu、serial等。
4、reg屬性定義了訪問該device node的地址信息,該屬性的值被解析成任意長度的(address,size)數組,具體用多長的數據來表示address和size是在其parent node中定義(#address-cells和#size-cells)。reg描述了memory-mapped IO register的offset和length。
5、model屬性指明瞭該設備屬於哪個設備生產商的哪一個model。
6、compatible屬性,該屬性的值是string list,定義了一系列的modle(每個string是一個model)。這些字符串列表被操作系統用來選擇用哪一個driver來驅動該設備。compatible的作用就是,在uboot中的代碼能通過compatible屬性match到dts相同的driver。uboot代碼內容如下:
static const struct udevice_id rockchip_gpio_ids[] = {
{ .compatible = "rockchip,gpio-bank" },
{ }
};
U_BOOT_DRIVER(gpio_rockchip) = {
.name = "gpio_rockchip",
.id = UCLASS_GPIO,
.of_match = rockchip_gpio_ids,
.ops = &gpio_rockchip_ops,
.priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
.probe = rockchip_gpio_probe,
};
Device Tree顯示的內容如下:
gpio0: gpio0@2007c000 {
compatible = "rockchip,gpio-bank";
reg = <0x2007c000 0x100>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO0>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
7、在dts文件中是用interrupt-parent這個屬性來標識,使interrupt source物理連接到interruptcontroller。因爲能夠產生中斷的device node沒有定義interrupt-parent的話,其interrupt-parent屬性就是跟隨parent node。因此,與其在所有的下游設備中定義interrupt-parent,不如統一在root node中定義了。
8、interrupts屬性有三個
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
第一個member表示該 interrupt 是 SPI 還是 PPI。
第二個member就是具體的中斷號了。查閱SoC的手冊就可以得到。(36 = number - 32)
第三個member指的是中斷的觸發方式,每個SoC是不同的,查閱SoC的手冊就可以知道了。
9、dmas = <&pdma 2>, <&pdma 3>;dma地址和dma通道選擇
---------------------
作者:Orangehaswing
來源:CSDN
原文:https://blog.csdn.net/gxlzyt123456/article/details/60141297
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!