Linux設備驅動統(tǒng)一模型解析
1. 設備樹概念
1.1.設備樹感性認識
設備樹(Device Tree),將這個詞分開就是“設備”和“樹”,描述設備樹的文件叫做DTS(Device Tree Source),這個DTS 文件采用樹形結構描述板級設備,比如CPU 數(shù)量、 內(nèi)存基地址、IIC 接口上接了哪些設備、SPI 接口上接了哪些設備等等。設備樹是樹形數(shù)據(jù)結構,具有描述系統(tǒng)中設備的節(jié)點。每個節(jié)點都有描述所代表設備特征的鍵值對。每個節(jié)點只有一個父節(jié)點,而根節(jié)點則沒有父節(jié)點。
1.2.DTS、DTB、DTC
DTS:設備樹源碼文件;DTB:將DTS編譯后得到的二進制文件;DTC:DTS的編譯工具,其源碼在內(nèi)核的scriptsdtc目錄下;谕瑯觓rm架構的CPU有很多,同一個CPU會制作很多配置不一的板子,如何正確的編譯所選的板子的DTS文件呢?在內(nèi)核的arch/arm/boot/dts/Makefile中:
dtb-$(CONFIG_ARCH_XXX) += xxx.dtb
dtb-$(CONFIG_ARCH_XXX) += xxx-sip.dtb
dtb-$(CONFIG_ARCH_XXX) += xxx.dtb
dtb-$(CONFIG_ARCH_XXX) += xxx.dtb
例如xxxx的開發(fā)板,只要設置CONFIG_ARCH_xxx=y(tǒng),所有用到這顆SOC的DTS都會編譯成DTB。如果后續(xù)還用到了這顆SOC設計的開發(fā)板,只要新建一個DTS文件,并將對應名稱的DTB文件名加到dtb-$(CONFIG_ARCH_xxx)中,在編譯設備樹時就會將DTS編譯為二進制的DTB文件。
1.3.Device Tree語法
以下語法分析均以xxx.dts為例。
1.3.1. dtsi頭文件
設備樹的頭文件擴展名為 .dtsi。以xxx.dts為例,其包含以下頭文件。
#include "skeleton.dtsi"
#include xxx.h"
#include "xxx-clocks.dtsi"
#include "xxx-pinctrl.dtsi"
#include "xxx-camera.dtsi"
需要注意的是.dts文件不但可以引用.dtsi文件,還可以引用.h文件和其他的.dts文件。Q1:每一個.dtsi和.dts都有自己的根節(jié)點,但是一個設備樹文件只允許有一個根節(jié)點,DTC如何處理?將根節(jié)點合并,保留最后一級的根節(jié)點。包含的頭文件內(nèi)容會被展開,展開的位置在/memory和/cpus之間。(存疑,只用xxx.dts編譯過)Q2:如果包含過程中有重復的compatible,DTC怎么處理?編譯時不會報錯,會生成兩個compatible屬性一樣的節(jié)點。
1.3.2. 設備節(jié)點
設備樹中的每一個節(jié)點都按照以下格式命名:
node-name@unit-address
node-name表示節(jié)點名稱,它的長度范圍應該是1~31個字符,可以由以下的字符組成:
字符說明0~9數(shù)字a-z小寫字母A-Z大寫字母,逗號(英文).句號(英文)_下劃線(英文)+加號-減號
表 2-1節(jié)點名稱的有效字符
節(jié)點名稱應以較低或大寫字符開頭,并應描述設備的一般類別。節(jié)點的單位地址特定于節(jié)點所在的總線類型。它由表2-1中字符集中的一個或多個ASCII字符組成。單位地址必須與節(jié)點的reg屬性中指定的第一個地址匹配。如果節(jié)點沒有reg屬性,則必須省略@unit-address,并且單獨使用節(jié)點名稱將節(jié)點與樹中相同級別的其他節(jié)點區(qū)分開來。對于reg格式和單位地址,特定總線的綁定可能會指定附加更具體的要求。根節(jié)點沒有節(jié)點名稱或單位地址。它由正斜杠(/)標識。
圖 2-1節(jié)點名稱示例
在圖2-1中,節(jié)點名稱為cpu的兩個節(jié)點通過uint-address 0和1區(qū)分;節(jié)點名稱為ethernet的兩個節(jié)點通過uint-address fe002000和fe003000區(qū)分。在設備樹中經(jīng)常會看到以下設備名稱:
watchdog: watchdog@04009800
冒號前的是節(jié)點標簽(label),冒號后是節(jié)點名稱。引入label的目的是方便訪問節(jié)點,可以直接通過&label來訪問這個節(jié)點。比如上述節(jié)點就可以使用&watchdog來訪問。
1.3.2.1. 通用名稱建議
節(jié)點的名稱應該有些通用,反映設備的功能,而不是其精確的編程模型。如適用,名稱應為以下選擇之一:
? adc ? accelerometer
? atm ? audio-codec
? audio-controller ? backlight:
? bluetooth ? bus
? cache-controller ? camera
? can ? charger
? clock: ? clock-controller
? compact-flash ? cpu
? cpus ? crypto
? disk ? display
? dma-controller ? dsp
? eeprom ? efuse:
? mdio ? memory
? memory-controller ? mmc
? mmc-slot ? mouse
? nand-controller ? nvram
? oscillator ? parallel
? pc-card ? pci
? pcie ? phy
? pinctrl ? pmic
? pmu ? port
? ports ? pwm
1.3.2.2. 路徑名稱
通過指定從根節(jié)點到所需節(jié)點的完整路徑(通過所有子節(jié)點),可以唯一識別devicetree中的節(jié)點。指定設備路徑的約定是:
/node-name-1/node-name-2/.../node-name-N
例如,在圖2-1中,到cpu#1的設備路徑為:
/cpus/cpu@1
/為根節(jié)點,在保證完整路徑明確的前提下,可以省略uint-address。
1.3.3. 屬性
設備樹中的每個節(jié)點都有描述節(jié)點特性的屬性。屬性由名稱和值組成。
1.3.3.1. 屬性名稱
屬性名稱的長度范圍應該是1~31個字符,可以由以下的字符組成:
字符說明0~9數(shù)字a-z小寫字母A-Z大寫字母,逗號(英文).句號(英文)_下劃線(英文)+加號?問號(英文)##號(hash)
非標準屬性名稱應指定唯一的字符串前綴,例如股票代號,用于標識定義該屬性的公司或組織的名稱。示例:
xxx,pin-function = <6>;
fsl,channel-fifo-len
linux,network-index
ibm,ppc-interrupt-server#s
1.3.3.2. 屬性值
屬性值是包含與屬性關聯(lián)的信息的零或多個字節(jié)的數(shù)組。
數(shù)值描述、值為空,用于描述bool信息。個人理解類似于flag參數(shù)、32位整數(shù),采用big-endian格式。示例:32位值0x11223344將在內(nèi)存中表示為:地址 11 地址 + 1 22 地址 + 2 33 地址 + 3 44、表示采用big-endian格式的64位整數(shù)。包括兩個值,其中第一個值包含整數(shù)的最有效位,第二個值包含最小有效位。例如:64位值0x1122334455667788將表示為兩個單元格:<0x11223344 0x55667788>。、格式特定于屬性,參見屬性定義。、字符串可打印且以空值()結尾。、一個值。phandle值是引用設備樹中另一個節(jié)點的方法。可被引用的任何節(jié)點都用唯一的定義了phandle屬性數(shù)值。該數(shù)字用于帶有phandle值類型的屬性值。、串聯(lián)在一起的值列表。
big-endian和little-endian(大小端):big-endian:是指低地址端存放高位字節(jié);little-endian:是指高地址端存放低位字節(jié);
1.3.3.3. 標準屬性Compatible(兼容)屬性名稱兼容值值類型<stringlist>描述兼容屬性值由定義設備特定編程模型的一個或多個字符串組成?蛻舳顺绦驊褂么俗址斜磉x擇設備驅動程序。該屬性值包含一個從最特定到最通用的null終止字符串的串聯(lián)列表。它們允許設備表達其與一系列類似設備的兼容性,可能允許單個設備驅動器與幾個設備匹配。推薦的格式是“制造商,型號”,其中制造商是描述制造商名稱的字符串(如股票代號)。
示例:
compatible =“fsl,mpc8641”,“ns16550”;
在此示例中,操作系統(tǒng)將首先嘗試查找支持fsl,mpc8641-uartmpc8641的設備驅動程序。如果找不到驅動程序,然后,它將嘗試定位受支持的更通用的ns16550設備類型驅動程序 。
一般驅動程序文件都會有個OF匹配表,此匹配表保存著一些compatible值,如果設備節(jié)點的 compatible屬性值和OF匹配表中的任何一個值相等,那么就表示設備可以使用這驅動。比如在文件drvier/misc/memctrl.c中:
static struct of_device_id_xxx_memctrl_of_match[] = {
{ .compatible = "xxxx,memctrl", },
{},
};
對應的,在arch/arm/boot/dts/xxx.dts中有:
memctrl: memctrl {
compatible = "xxxx,memctrl";
reg = <0x0121B000 0x1044>;
clocks = <&sdram_bandw_clk>, <&mem_axi_clk>;
clock-names = "sdram_bandwidth_clk", "mem_axi_clk";
interrupts = <GIC_SPI INT_SDRAM IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <1>;
};
Model(型號)屬性名稱模型值值類型
描述指定設備的制造商型號。推薦的格式為:“制造商,型號”,其中制造商是描述制造商名稱的字符串(如股票代號)。
示例:
model =“fsl,MPC8349EMITX”;
Phandle(pointer handle)屬性名稱pointer handle值值類型
描述phandle屬性指定設備樹中唯一節(jié)點的數(shù)字標識符。phandle屬性值被需要引用與該屬性關聯(lián)的節(jié)點的其他節(jié)點使用。
示例:
pic@10000000 {
phandle = <1>;
interrupt-controller;
};
定義了1的phandle值。另一個設備節(jié)點可以引用phandle值為1的pic節(jié)點:
another-device-node {
interrupt-parent = <1>;
};
Status屬性名稱狀態(tài)值值類型<string>描述狀態(tài)屬性指示設備的操作狀態(tài),其有效值如下:"okay":指示設備可運行。"disabled":表明設備目前尚未運行,但未來可能會運行(例如,未插入或關閉某物)。"fail":表示設備無法運行,在設備中檢測到嚴重錯誤,如果不進行維修就不太可能運行"fail-sss":表示設備無法運行,在設備中檢測到嚴重錯誤,如果不進行維修就不太可能運行,sss部分特定于設備,并指示檢測到的錯誤情況。#address-cells and #size-cells屬性名稱#address-cells,#size-cells值類型<u32>描述#address-cells和#size-cells屬性可用于設備樹層次結構中包含子節(jié)點并描述如何解決子設備節(jié)點的任何設備節(jié)點。#address-cells屬性定義用于編碼子節(jié)點的reg屬性中地址字段的個單元格的數(shù)量。#size-cells屬性定義用于編碼子節(jié)點的reg屬性中大小字段的個單元格的數(shù)量。#address-cells = <1>;
#size-cells = <0>;
表示reg屬性中有一個u32表示address,沒有表示reg大小的數(shù)據(jù),所以:reg = <0x0>; 即reg的起始地址為0x0,不描述其大小
#address-cells = <1>;
#size-cells = <1>;
表示reg屬性中有一個u32表示address,有一個u32表示size,所以:reg = <0x00000000 0x00040000>; 即reg的起始地址為0x00000000,大小是0x00040000
Reg屬性名稱reg值類型<prop-encoded-array> 編碼為任意數(shù)量(地址、長度)對描述reg屬性描述設備資源在其父總線定義的地址空間內(nèi)的地址。這通常意味著內(nèi)存映射IO寄存器塊的偏移和長度,但在某些總線類型上可能有不同的含義。根節(jié)點定義的地址空間中的地址為cpu真實地址。該值是一個,由任意數(shù)量的地址和長度對組成,<地址長度>。指定地址和長度所需的單元格的數(shù)量是總線特定的,由設備節(jié)點父級中的#address-cells和#size-cells屬性指定。如果父節(jié)點為#size-cells單元格指定值0,則應忽略reg值中的長度字段。
示例:假設系統(tǒng)芯片中的設備包含兩個寄存器塊,SOC中偏移0x3000的32字節(jié)塊和偏移0xFE00的256字節(jié)塊。reg屬性的編碼如下(假設#address-cells和#size-cells值為1):
reg=<0x3000 0x20 0xFE00 0x100>;
virtual-reg屬性名稱virtual-reg值類型<u32>描述virtual-reg屬性指定一個有效地址,該地址映射到設備節(jié)點的reg屬性中指定的第一個物理地址。此屬性使引導程序能夠為客戶端程序提供已設置的虛擬到物理映射。Ranges屬性名稱range值類型<empty>或編碼為任意數(shù)量的(子總線地址、父總線地址、長度)三聯(lián)體描述range屬性提供了一種在總線地址空間(子地址空間)和總線節(jié)點父地址空間(父地址空間)之間定義映射或轉換的方法。range屬性值的格式是任意數(shù)量的三聯(lián)體(子總線地址、父總線地址、長度):1.子總線地址是子總線地址空間內(nèi)的物理地址。表示地址的單元格數(shù)取決于總線,可以通過此節(jié)點(出現(xiàn)range屬性的節(jié)點)的#address-cells確定。2. 父總線地址是父總線地址空間中的物理地址。表示父地址的單元格數(shù)取決于總線,可以通過定義父地址空間的節(jié)點的#address-cells屬性確定。3. 長度指定子地址空間中范圍的大小。表示大小的單元格數(shù)可以根據(jù)該節(jié)點(出現(xiàn)range屬性的節(jié)點)的#size-cells確定。如果屬性用值定義,則它指定父地址和子地址空間相同,并且不需要地址轉換。如果總線節(jié)點中不存在該屬性,則假設節(jié)點的子節(jié)點和父地址空間之間不存在映射。
示例:
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0xe0000000 0x00100000>;
serial {
device_type = "serial";
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
interrupts = <0xA 0x8>;
interrupt-parent = <&ipic>;
};
};
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個字
最新活動更多
-
10月31日立即下載>> 【限時免費下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月28日立即報名>>> 2024工程師系列—工業(yè)電子技術在線會議
-
12月19日立即報名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報名中>> OFweek2024中國智造CIO在線峰會
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍皮書》
推薦專題
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結構工程師 廣東省/深圳市