【ARM-Linux开发】内核3.x版本之后设备树机制
內(nèi)核3.x版本之后設備樹機制
Based??on??Linux??3.10.24??source??code?
參考/documentation/devicetree/Booting-without-of.txt文檔
目錄
內(nèi)核3.x版本之后設備樹機制 1
一、設備樹(Device??Tree)基本概念及作用 3
二、設備樹的組成和使用 4
①DTS和DTSI 4
②DTC 4
③DTB 5
④Bootloader 5
三、設備樹中dts、dtsi文件的基本語法 5
㈠chosen?node 8
㈡aliases?node 8
㈢memory?node 9
㈣ 其他節(jié)點 10
四、DTB相關結構 13
㈠Header 14
㈢字符串塊 16
㈣ memory?reserve?map 16
五、解析DTB的函數(shù)及相關數(shù)據(jù)結構 17
㈠machine_desc結構 17
㈡設備節(jié)點結構體 18
㈢屬性結構體 19
㈣ uboot下的相關結構體 19
六、DTB加載及解析過程 21
七、OF的API接口 32
一、設備樹(Device??Tree)基本概念及作用
在內(nèi)核源碼中,存在大量對板級細節(jié)信息描述的代碼。這些代碼充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目錄,對內(nèi)核而言這些platform設備、resource、i2c_board_info、spi_board_info以及各種硬件的platform_data絕大多數(shù)純屬垃圾冗余代碼。為了解決這一問題,ARM內(nèi)核版本3.x之后引入了原先在Power?PC等其他體系架構已經(jīng)使用的Flattened?Device?Tree。
“A?data?structure?by?which?bootloaders?pass?hardware?layout?to?Linux?in?a?device-independent?manner,?simplifying?hardware?probing.”開源文檔中對設備樹的描述是,一種描述硬件資源的數(shù)據(jù)結構,它通過bootloader將硬件資源傳給內(nèi)核,使得內(nèi)核和硬件資源描述相對獨立。
Device?Tree可以描述的信息包括CPU的數(shù)量和類別、內(nèi)存基地址和大小、總線和橋、外設連接、中斷控制器和中斷使用情況、GPIO控制器和GPIO使用情況、Clock控制器和Clock使用情況。
另外,設備樹對于可熱插拔的熱備不進行具體描述,它只描述用于控制該熱插拔設備的控制器。
設備樹的主要優(yōu)勢:對于同一SOC的不同主板,只需更換設備樹文件.dtb即可實現(xiàn)不同主板的無差異支持,而無需更換內(nèi)核文件。
注:要使得3.x之后的內(nèi)核支持使用設備樹,除了內(nèi)核編譯時需要打開相對應的選項外,bootloader也需要支持將設備樹的數(shù)據(jù)結構傳給內(nèi)核。
二、設備樹的組成和使用
設備樹包含DTC(device?tree?compiler),DTS(device?tree?source和DTB(device?tree?blob)。其對應關系如圖1-1所示:
圖1-1?DTS、DTC、DTB之間的關系
①DTS和DTSI
.dts文件是一種ASCII文本對Device?Tree的描述,放置在內(nèi)核的/arch/arm/boot/dts目錄。一般而言,一個.dts文件對應一個ARM的machine。
由于一個SOC可能有多個不同的電路板,而每個電路板擁有一個?.dts。這些dts勢必會存在許多共同部分,為了減少代碼的冗余,設備樹將這些共同部分提煉保存在.dtsi文件中,供不同的dts共同使用。.dtsi的使用方法,類似于C語言的頭文件,在dts文件中需要進行include?.dtsi文件。當然,dtsi本身也支持include?另一個dtsi文件。
②DTC
DTC為編譯工具,它可以將.dts文件編譯成.dtb文件。DTC的源碼位于內(nèi)核的scripts/dtc目錄,內(nèi)核選中CONFIG_OF,編譯內(nèi)核的時候,主機可執(zhí)行程序DTC就會被編譯出來。?即scripts/dtc/Makefile中
hostprogs-y :=?dtc
always :=?$(hostprogs-y)?
在內(nèi)核的arch/arm/boot/dts/Makefile中,若選中某種SOC,則與其對應相關的所有dtb文件都將編譯出來。在linux下,make?dtbs可單獨編譯dtb。以下截取了TEGRA平臺的一部分。
ifeq?($(CONFIG_OF),y)
dtb-$(CONFIG_ARCH_TEGRA)?+=?tegra20-harmony.dtb?\
tegra30-beaver.dtb?\
tegra114-dalmore.dtb?\
tegra124-ardbeg.dtb?
③DTB
DTC編譯.dts生成的二進制文件(.dtb),bootloader在引導內(nèi)核時,會預先讀取.dtb到內(nèi)存,進而由內(nèi)核解析。
④Bootloader
Bootloader需要將設備樹在內(nèi)存中的地址傳給內(nèi)核。在ARM中通過bootm或bootz命令來進行傳遞。bootm?[kernel_addr]?[initrd_address]?[dtb_address],其中kernel_addr為內(nèi)核鏡像的地址,initrd為initrd的地址,dtb_address為dtb所在的地址。若initrd_address為空,則用“-”來代替。
三、設備樹中dts、dtsi文件的基本語法
DTS的基本語法范例,如圖3-1?所示。
它包括一系列節(jié)點,以及描述節(jié)點的屬性。
“/”為root節(jié)點。在一個.dts文件中,有且僅有一個root節(jié)點;在root節(jié)點下有“node1”,“node2”子節(jié)點,稱root為“node1”和“node2”的parent節(jié)點,除了root節(jié)點外,每個節(jié)點有且僅有一個parent;其中子節(jié)點node1下還存在子節(jié)點“child-nodel1”和“child-node2”。
注:如果看過內(nèi)核/arch/arm/boot/dts目錄的讀者看到這可能有一個疑問。在每個.dsti和.dts中都會存在一個“/”根節(jié)點,那么如果在一個設備樹文件中include一個.dtsi文件,那么豈不是存在多個“/”根節(jié)點了么。其實不然,編譯器DTC在對.dts進行編譯生成dtb時,會對node進行合并操作,最終生成的dtb只有一個root?node。Dtc會進行合并操作這一點從屬性上也可以得到驗證。這個稍后做講解。
在節(jié)點的{}里面是描述該節(jié)點的屬性(property),即設備的特性。它的值是多樣化的:
1.它可以是字符串string,如①;也可能是字符串數(shù)組string-list,如②
2.它也可以是32?bit?unsigned?integers,如cell⑧,用<>表示
3.它也可以是binary?data,如③,用[]表示
4.它也可能是空,如⑦
圖3-1??DTS的基本語法范例
在/arch/arm/boot/dts/目錄中有一個文件skeleton.dtsi,該文件為各ARM?vendor共用的一些硬件定義信息。以下為skeleton.dtsi的全部內(nèi)容。
/?{
#address-cells?=?<1>;
#size-cells?=?<1>;
chosen?{?};
aliases?{?};
memory?{?device_type?=?"memory";?reg?=?<0?0>;?};
};
如上,屬性#?address-cells的值為1,它代表以“/”根節(jié)點為parent的子節(jié)點中,reg屬性中存在一個address值;#size-cells的值為1,它代表以“\”?根節(jié)點為parent的子節(jié)點中,reg屬性中存在一個size值。即父節(jié)點的#?address-cells和#size-cells決定了子節(jié)點的address和size的長度;Reg的組織形式為reg?=?
下面列舉例子,對一些典型節(jié)點進行具體描述。
㈠chosen?node
chosen?{
bootargs?=?"tegraid=40.0.0.00.00?vmalloc=256M?video=tegrafb?console=ttyS0,115200n8?earlyprintk";
};
chosen?node?主要用來描述由系統(tǒng)指定的runtime?parameter,它并沒有描述任何硬件設備節(jié)點信息。原先通過tag?list傳遞的一些linux?kernel運行的參數(shù),可以通過chosen節(jié)點來傳遞。如command?line可以通過bootargs這個property來傳遞。如果存在chosen?node,它的parent節(jié)點必須為“/”根節(jié)點。
㈡aliases?node
aliases?{
i2c6?=?&pca9546_i2c0;
i2c7?=?&pca9546_i2c1;
i2c8?=?&pca9546_i2c2;
i2c9?=?&pca9546_i2c3;
};
aliases?node用來定義別名,類似C++中引用。上面是一個在.dtsi中的典型應用,當使用i2c6時,也即使用pca9546_i2c0,使得引用節(jié)點變得簡單方便。例:當.dts??include?該.dtsi時,將i2c6的status屬性賦值為okay,則表明該主板上的pca9546_i2c0處于enable狀態(tài);反之,status賦值為disabled,則表明該主板上的pca9546_i2c0處于disenable狀態(tài)。如下是引用的具體例子:
&i2c6?{
status?=?"okay";
};
㈢memory?node
memory?{
device_type?=?"memory";
reg?=?<0x00000000?0x20000000>;?/*?512?MB?*/
};
對于memory?node,device_type必須為memory,由之前的描述可以知道該memory?node是以0x00000000為起始地址,以0x20000000為結束地址的512MB的空間。
一般而言,在.dts中不對memory進行描述,而是通過bootargs中類似521M@0x00000000的方式傳遞給內(nèi)核。
㈣ 其他節(jié)點
由于其他設備節(jié)點依據(jù)屬性進行描述,具有類似的形式。接下來的部分主要分析各種屬性的含義及作用,并結合相關的例子進行闡述。
㈠?Reg屬性
在device?node?中,reg是描述memory-mapped?IO?register的offset和length。子節(jié)點的reg屬性address和length長度取決于父節(jié)點對應的#address-cells和#size-cells的值。例:
在上述的aips節(jié)點中,存在子節(jié)點spda。spda中的中reg為<0x70000000?0x40000?>,其0x700000000為address,0x40000為size。這一點在圖3-1下有作介紹。
這里補充的一點是:
設備節(jié)點的名稱格式node-name@unit-address,節(jié)點名稱用node-name唯一標識,為一個ASCII字符串。其中@unit-address為可選項,可以不作描述。unit-address的具體格式和設備掛載在哪個bus上相關。如:cpu的unit-address從0開始編址,以此加1;本例中,aips為0x70000000。
㈡?compatible屬性
在①中,compatible屬性為string?list,用來將設備匹配對應的driver驅(qū)動,優(yōu)先級為從左向右。本例中spba的驅(qū)動優(yōu)先考慮“fsl,aips-bus”驅(qū)動;若沒有“fsl,aips-bus”驅(qū)動,則用字符串“simple-bus”來繼續(xù)尋找合適的驅(qū)動。即compatible實現(xiàn)了原先內(nèi)核版本3.x之前,platform_device中.name的功能,至于具體的實現(xiàn)方法,本文后面會做講解。
注:對于“/”root節(jié)點,它也存在compatible屬性,用來匹配machine?type。具體說明將在后面給出。
㈢?interrupts屬性
設備節(jié)點通過interrupt-parent來指定它所依附的中斷控制器,當節(jié)點沒有指定interrupt-parent時,則從parent節(jié)點中繼承。上面例子中,root節(jié)點的interrupt-parent?=?<&mic>。這里使用了引用,即mic引用了②中的inrerrupt-controller?@40008000;root節(jié)點的子節(jié)點并沒有指定interrupt-controller,如ahb、fab,它們均使用從根節(jié)點繼承過來的mic,即位于0x40008000的中斷控制器。
若子節(jié)點使用到中斷(中斷號、觸發(fā)方法等等),則需用interrupt屬性來指定,該屬性的數(shù)值長度受中斷控制器中#inrerrupt-controller值③控制,即interrupt屬性<>中數(shù)值的個數(shù)為#inrerrupt-controller的值;本例中#inrerrupt-controller=<2>,因而④中interrupts的值為<0x3d?0>形式,具體每個數(shù)值的含義由驅(qū)動實現(xiàn)決定。
㈣?ranges屬性
ranges屬性為地址轉(zhuǎn)換表,這在pcie中使用較為常見,它表明了該設備在到parent節(jié)點中所對用的地址映射關系。ranges格式長度受當前節(jié)點#address-cell、parent節(jié)點#address-cells、當前節(jié)點#size-cell所控制。順序為ranges=<前節(jié)點#address-cell,?parent節(jié)點#address-cells?,?當前節(jié)點#size-cell。在本例中,當前節(jié)點#address-cell=<1>,對應于⑤中的第一個0x20000000;parent節(jié)點#address-cells=<1>,對應于⑤中的第二個0x20000000;當前節(jié)點#size-cell=<1>,對應于⑤中的0x30000000。即ahb0節(jié)點所占空間從0x20000000地址開始,對應于父節(jié)點的0x20000000地址開始的0x30000000地址空間大小。
注:對于相同名稱的節(jié)點,dtc會根據(jù)定義的先后順序進行合并,其相同屬性,取后定義的那個。
四、DTB相關結構
本節(jié)講下.dts編譯生成的dtb文件,其布局結構。
DTB由三部分組成:頭(Header)、結構塊(device-tree?structure)、字符串塊(string?block)。下面將詳細介紹這三部分的內(nèi)容。
㈠Header
在\kernel\include\linux\of_fdt.h文件中有相關定義
設備樹結構塊是一個線性化的結構體,是設備樹的主體,以節(jié)點的形式保存了主板上的設備信息。
在結構塊中,以宏OF_DT_BEGIN_NODE標志一個節(jié)點的開始,以宏OF_DT_END_NODE標識一個節(jié)點的結束,整個結構塊以宏OF_DT_END?(0x00000009)結束。在\kernel\include\linux\of_fdt.h中有相關定義,我們把這些宏稱之為token。
(1)FDT_BEGIN_NODE?(0x00000001)。該token描述了一個node的開始位置,緊挨著該token的就是node?name(包括unit?address)
(2)FDT_END_NODE?(0x00000002)。該token描述了一個node的結束位置。
(3)FDT_PROP?(0x00000003)。該token描述了一個property的開始位置,該token之后是兩個u32的數(shù)據(jù),分別是length和name?offset。length表示該property?value?data的size。name?offset表示該屬性字符串在device?tree?strings?block的偏移值。length和name?offset之后就是長度為length具體的屬性值數(shù)據(jù)。
(4)FDT_NOP?(0x00000004)。
(5)FDT_END?(0x00000009)。該token標識了一個DTB的結束位置。
一個節(jié)點的結構如下:
(1)節(jié)點開始標志:一般為OF_DT_BEGIN_NODE(0x00000001)。
(2)節(jié)點路徑或者節(jié)點的單元名(version<3以節(jié)點路徑表示,version>=0x10以節(jié)點單元名表示)
(3)填充字段(對齊到四字節(jié))
(4)節(jié)點屬性。每個屬性以宏OF_DT_PROP(0x00000003)開始,后面依次為屬性值的字節(jié)長度(4字節(jié))、屬性名稱在字符串塊中的偏移量(4字節(jié))、屬性值和填充(對齊到四字節(jié))。
(5)如果存在子節(jié)點,則定義子節(jié)點。
(6)節(jié)點結束標志OF_DT_END_NODE(0x00000002)。
㈢字符串塊
通過節(jié)點的定義知道節(jié)點都有若干屬性,而不同的節(jié)點的屬性又有大量相同的屬性名稱,因此將這些屬性名稱提取出一張表,當節(jié)點需要應用某個屬性名稱時,直接在屬性名字段保存該屬性名稱在字符串塊中的偏移量。
㈣?memory?reserve?map
這個區(qū)域包括了若干的reserve?memory描述符。每個reserve?memory描述符是由address和size組成。其中address和size都是用U64來描述。
有些系統(tǒng),我們也許會保留一些memory有特殊用途(例如DTB或者initrd?image),或者在有些DSP+ARM的SOC?platform上,有些memory被保留用于ARM和DSP進行信息交互。這些保留內(nèi)存不會進入內(nèi)存管理系統(tǒng)。
五、解析DTB的函數(shù)及相關數(shù)據(jù)結構
㈠machine_desc結構
內(nèi)核將機器信息記錄為machine_desc結構體(該定義在/arch/arm/include/asm/mach/arch.h),并保存在_arch_info_begin到_arch_info_end之間(_arch_info_begin,_arch_info_end為虛擬地址,是編譯內(nèi)核時指定的,此時mmu還未進行初始化。它其實通過匯編完成地址偏移操作)
machine_desc結構體用宏MACHINE_START進行定義,一般在/arch/arm/子目錄,與板級相關的文件中進行成員函數(shù)及變量的賦值。由linker將machine_desc聚集在.arch.info.init節(jié)區(qū)形成列表。
bootloader引導內(nèi)核時,ARM寄存器r2會將.dtb的首地址傳給內(nèi)核,內(nèi)核根據(jù)該地址,解析.dtb中根節(jié)點的compatible屬性,將該屬性與內(nèi)核中預先定義machine_desc結構體的dt_compat成員做匹配,得到最匹配的一個machine_desc。
在代碼中,內(nèi)核通過在start_kernel->setup_arch中調(diào)用setup_machine_fdt來實現(xiàn)上述功能,該函數(shù)的具體實現(xiàn)可參見/arch/arm/kernel/devtree.c。?
㈡設備節(jié)點結構體
1.
記錄節(jié)點信息的結構體。.dtb經(jīng)過解析之后將以device_node列表的形式存儲節(jié)點信息。
㈢屬性結構體
device_node結構體中的成員結構體,用于描述節(jié)點屬性信息。
㈣?uboot下的相關結構體
首先我們看下uboot用于記錄os、initrd、fdt信息的數(shù)據(jù)結構bootm_headers,其定義在/include/image.h中,這邊截取了其中與dtb相關的一小部分。
fit_hdr_fdt指向DTB設備樹鏡像的頭。
lmb為uboot下的一種內(nèi)存管理機制,全稱為logical?memory?blocks。用于管理鏡像的內(nèi)存。lmb所記錄的內(nèi)存信息最終會傳遞給kernel。這里對lmb不做展開描述。在/include/lmb.h和/lib/lmb.c中有對lmb的接口和定義的具體描述。有興趣的讀者可以看下,所包含的代碼量不多。
六、DTB加載及解析過程
先從uboot里的do_bootm出發(fā),根據(jù)之前描述,DTB在內(nèi)存中的地址通過bootm命令進行傳遞。在bootm中,它會根據(jù)所傳進來的DTB地址,對DTB所在內(nèi)存做一系列操作,為內(nèi)核解析DTB提供保證。上圖為對應的函數(shù)調(diào)用關系圖。
在do_bootm中,主要調(diào)用函數(shù)為do_bootm_states,第四個參數(shù)為bootm所要處理的階段和狀態(tài)。?
在do_bootm_states中,bootm_start會對lmb進行初始化操作,lmb所管理的物理內(nèi)存塊有三種方式獲取。起始地址,優(yōu)先級從上往下:
1.?環(huán)境變量“bootm_low”
2.?宏CONFIG_SYS_SDRAM_BASE(在tegra124中為0x80000000)
3.?gd->bd->bi_dram[0].start
大小:
1.?環(huán)境變量“bootm_size”
2.?gd->bd->bi_dram[0].size
經(jīng)過初始化之后,這塊內(nèi)存就歸lmb所管轄。接著,調(diào)用bootm_find_os進行kernel鏡像的相關操作,這里不具體闡述。
還記得之前講過bootm的三個參數(shù)么,第一個參數(shù)內(nèi)核地址已經(jīng)被bootm_find_os處理,而接下來的兩個參數(shù)會在bootm_find_other中執(zhí)行操作。
首先,bootm_find_other根據(jù)第二個參數(shù)找到ramdisk的地址,得到ramdisk的鏡像;然后根據(jù)第三個參數(shù)得到DTB鏡像,同檢查kernel和ramdisk鏡像一樣,檢查DTB鏡像也會進行一系列的校驗工作,如果校驗錯誤,將無法正常啟動內(nèi)核。另外,uboot在確認DTB鏡像無誤之后,會將該地址保存在環(huán)境變量“fdtaddr”中。
接著,uboot會把DTB鏡像reload一次,使得DTB鏡像所在的物理內(nèi)存歸lmb所管理:①boot_fdt_add_mem_rsv_regions會將原先的內(nèi)存DTB鏡像所在的內(nèi)存置為reserve,保證該段內(nèi)存不會被其他非法使用,保證接下來的reload數(shù)據(jù)是正確的;②boot_relocate_fdt會在bootmap區(qū)域中申請一塊未被使用的內(nèi)存,接著將DTB鏡像內(nèi)容復制到這塊區(qū)域(即歸lmb所管理的區(qū)域)
注:若環(huán)境變量中,指定“fdt_high”參數(shù),則會根據(jù)該值,調(diào)用lmb_alloc_base函數(shù)來分配DTB鏡像reload的地址空間。若分配失敗,則會停止bootm操作。因而,不建議設置fdt_high參數(shù)。
接下來,do_bootm會根據(jù)內(nèi)核的類型調(diào)用對應的啟動函數(shù)。與linux對應的是do_bootm_linux。
①?boot_prep_linux
為啟動后的kernel準備參數(shù)
②?boot_jump_linux
以上是boot_jump_linux的片段代碼,可以看出:若使用DTB,則原先用來存儲ATAG的寄存器R2,將會用來存儲.dtb鏡像地址。
boot_jump_linux最后將調(diào)用kernel_entry,將.dtb鏡像地址傳給內(nèi)核。
下面我們來看下內(nèi)核的處理部分:
在arch/arm/kernel/head.S中,有這樣一段:
_vet_atags定義在/arch/arm/kernel/head-common.S中,它主要對DTB鏡像做了一個簡單的校驗。
真正解析處理dbt的開始部分,是setup_arch->setup_machine_fdt。這部分的處理在第五部分的machine_mdesc中有提及。
如圖,是setup_machine_fdt中的解析過程。
解析chosen節(jié)點將對boot_command_line進行初始化。
解析根節(jié)點的{size,address}將對dt_root_size_cells,dt_root_addr_cells進行初始化。為之后解析memory等其他節(jié)點提供依據(jù)。
解析memory節(jié)點,將會把節(jié)點中描述的內(nèi)存,加入memory的bank。為之后的內(nèi)存初始化提供條件。
解析設備樹在函數(shù)unflatten_device_tree中完成,它將.dtb解析成device_node結構(第五部分有其定義),并構成單項鏈表,以供OF的API接口使用。
下面主要結合代碼分析:/drivers/of/fdt.c
總的歸納為:
①?kernel入口處獲取到uboot傳過來的.dtb鏡像的基地址
②?通過early_init_dt_scan()函數(shù)來獲取kernel初始化時需要的bootargs和cmd_line等系統(tǒng)引導參數(shù)。
③?調(diào)用unflatten_device_tree函數(shù)來解析dtb文件,構建一個由device_node結構連接而成的單向鏈表,并使用全局變量of_allnodes保存這個鏈表的頭指針。
④?內(nèi)核調(diào)用OF的API接口,獲取of_allnodes鏈表信息來初始化內(nèi)核其他子系統(tǒng)、設備等。
七、OF的API接口
OF的接口函數(shù)在/drivers/of/目錄下,有of_i2c.c、of_mdio.c、of_mtd.c、Adress.c等等
這里將列出幾個常用的API接口。
1.?用來查找在dtb中的根節(jié)點
unsigned?long?__init?of_get_flat_dt_root(void)
2.?根據(jù)deice_node結構的full_name參數(shù),在全局鏈表of_allnodes中,查找合適的device_node
struct?device_node?*of_find_node_by_path(const?char?*path)
例如:
struct?device_node?*cpus;
cpus=of_find_node_by_path("/cpus");
3.?若from=NULL,則在全局鏈表of_allnodes中根據(jù)name查找合適的device_node
struct?device_node?*of_find_node_by_name(struct?device_node?*from,const?char?*name)
例如:
struct?device_node?*np;
np?=?of_find_node_by_name(NULL,"firewire");
4.?根據(jù)設備類型查找相應的device_node
struct?device_node?*of_find_node_by_type(struct?device_node?*from,const?char?*type)
例如:
struct?device_node?*tsi_pci;
tsi_pci=?of_find_node_by_type(NULL,"pci");
5.?根據(jù)compatible字符串查找device_node
struct?device_node?*of_find_compatible_node(struct?device_node?*from,const?char?*type,?const?char?*compatible)
6.?根據(jù)節(jié)點屬性的name查找device_node
struct?device_node?*of_find_node_with_property(struct?device_node?*from,const?char?*prop_name)
7.?根據(jù)phandle查找device_node
struct?device_node?*of_find_node_by_phandle(phandle?handle)
8.?根據(jù)alias的name獲得設備id號
int?of_alias_get_id(struct?device_node?*np,?const?char?*stem)
9.?device?node計數(shù)增加/減少
struct?device_node?*of_node_get(struct?device_node?*node)
void?of_node_put(struct?device_node?*node)
10.?根據(jù)property結構的name參數(shù),在指定的device?node中查找合適的property
struct?property?*of_find_property(const?struct?device_node?*np,const?char?*name,int?*lenp)
11.?根據(jù)property結構的name參數(shù),返回該屬性的屬性值
const?void?*of_get_property(const?struct?device_node?*np,?const?char?*name,int?*lenp)
12.?根據(jù)compat參數(shù)與device?node的compatible匹配,返回匹配度
int?of_device_is_compatible(const?struct?device_node?*device,const?char?*compat)
13.?獲得父節(jié)點的device?node
struct?device_node?*of_get_parent(const?struct?device_node?*node)
14.?將matches數(shù)組中of_device_id結構的name和type與device?node的compatible和type匹配,返回匹配度最高的of_device_id結構
const?struct?of_device_id?*of_match_node(const?struct?of_device_id?*matches,const?struct?device_node?*node)
15.?根據(jù)屬性名propname,讀出屬性值中的第index個u32數(shù)值給out_value
int?of_property_read_u32_index(const?struct?device_node?*np,const?char?*propname,u32?index,?u32?*out_value)
16.?根據(jù)屬性名propname,讀出該屬性的數(shù)組中sz個屬性值給out_values
int?of_property_read_u8_array(const?struct?device_node?*np,const?char?*propname,?u8?*out_values,?size_t?sz)
int?of_property_read_u16_array(const?struct?device_node?*np,const?char?*propname,?u16?*out_values,?size_t?sz)
int?of_property_read_u32_array(const?struct?device_node?*np,const?char?*propname,?u32?*out_values,size_t?sz)
17.?根據(jù)屬性名propname,讀出該屬性的u64屬性值
int?of_property_read_u64(const?struct?device_node?*np,?const?char?*propname,u64?*out_value)
18.?根據(jù)屬性名propname,讀出該屬性的字符串屬性值
int?of_property_read_string(struct?device_node?*np,?const?char?*propname,const?char?**out_string)
19.?根據(jù)屬性名propname,讀出該字符串屬性值數(shù)組中的第index個字符串
int?of_property_read_string_index(struct?device_node?*np,?const?char?*propname,int?index,?const?char?**output)
20.?讀取屬性名propname中,字符串屬性值的個數(shù)
int?of_property_count_strings(struct?device_node?*np,?const?char?*propname)
21.?讀取該設備的第index個irq號
unsigned?int?irq_of_parse_and_map(struct?device_node?*dev,?int?index)
22.?讀取該設備的第index個irq號,并填充一個irq資源結構體
int?of_irq_to_resource(struct?device_node?*dev,?int?index,?struct?resource?*r)
23.?獲取該設備的irq個數(shù)
int?of_irq_count(struct?device_node?*dev)
24.?獲取設備寄存器地址,并填充寄存器資源結構體
int?of_address_to_resource(struct?device_node?*dev,?int?index,struct?resource?*r)
const?__be32?*of_get_address(struct?device_node?*dev,?int?index,?u64?*size,unsigned?int?*flags)
25.?獲取經(jīng)過映射的寄存器虛擬地址
void?__iomem?*of_iomap(struct?device_node?*np,?int?index)
24.?根據(jù)device_node查找返回該設備對應的platform_device結構
struct?platform_device?*of_find_device_by_node(struct?device_node?*np)
25.?根據(jù)device?node,bus?id以及父節(jié)點創(chuàng)建該設備的platform_device結構
struct?platform_device?*of_device_alloc(struct?device_node?*np,const?char?*bus_id,struct?device?*parent)
static?struct?platform_device?*of_platform_device_create_pdata(struct?device_node?*np,const?char?*bus_id,
void?*platform_data,struct?device?*parent)
26.?遍歷of_allnodes中的節(jié)點掛接到of_platform_bus_type總線上,由于此時of_platform_bus_type總線上還沒有驅(qū)動,所以此時不進行匹配
int?of_platform_bus_probe(struct?device_node?*root,const?struct?of_device_id?*matches,struct?device?*parent)
轉(zhuǎn)載于:https://www.cnblogs.com/huty/p/8517543.html
總結
以上是生活随笔為你收集整理的【ARM-Linux开发】内核3.x版本之后设备树机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言重难点:内存对齐和位段
- 下一篇: C++设计模式-Adapter适配器模式