訂閱
糾錯
加入自媒體

Linux設備驅動統一模型解析

2021-04-13 09:48
一口Linux
關注

soc節(jié)點指定了<0x0 0xe0000000 0x00100000>;此屬性值指定對于1024KB范圍的地址空間,在物理0x0處尋址的子節(jié)點映射到物理0xe0000000的父地址。通過這種映射,串行設備節(jié)點可以通過0xe0004600地址的加載或存儲、0x4600(在注冊表中指定)的偏移量以及范圍中指定的0xe0000000映射尋址。

dma-ranges屬性名稱dma-ranges值類型<empty>或編碼為任意數量的(子總線地址、父總線地址、長度)三聯體描述dma-range屬性用于描述存儲器映射總線的直接存儲器訪問(dma)結構,其設備樹父級可以從總線的dma操作訪問。它提供了一種定義總線物理地址空間與總線父級物理地址空間之間映射或轉換的方法。dma-range屬性的值的格式是任意數量的(子總線地址、母線地址、長度)。指定的每個三聯體描述連續(xù)DMA地址范圍。1. 子總線地址是子總線地址空間內的物理地址。表示地址的單元格數取決于總線,可以通過該節(jié)點(dma-range屬性出現的節(jié)點)的#address-cells地址單元格確定。2. 父總線地址是父總線地址空間中的物理地址。表示父地址的單元格數取決于總線,可以通過定義父地址空間的節(jié)點的#address-cells屬性確定。3. 長度指定子地址空間中范圍的大小。表示大小的單元格數量可以根據該節(jié)點(dma-range屬性出現的節(jié)點)的#size-cells確定。Name(已棄用)屬性名稱name值類型<string>描述name屬性用于記錄節(jié)點名字,name屬性已經被棄用 ,不推薦使用 name屬性,一些老的設備樹文件可能會使用此屬性。device_type屬性名稱device_type值類型<string>描述由于DTS沒有FCode,因此不建議使用該屬性。只能用于在cpu節(jié)點和memory節(jié)點中,以便與IEEE 1275衍生設備兼容。1.3.4. 基本設備節(jié)點類型

所有設備樹文件均要包含一個根文件,并且所有設備樹文件均應在根節(jié)點下存在以下節(jié)點:

1個/cpus節(jié)點至少一個/memory節(jié)點

使用說明:R = 必需,O = 可選,OR = 可選但推薦,SD = 參見定義,所有其他的標準屬性均可接受,但可選

1.3.4.1. Root node

devicetree有一個單獨的根節(jié)點,所有其他設備節(jié)點都是它的后代。根節(jié)點的完整路徑為/。

屬性名稱使用說明類型定義#address-cellsR<u32>root子節(jié)點的reg property地址格式。#size-cellsR<u32>root子節(jié)點的reg property大小格式。modelR<string>指定唯一標識。系統板型號。推薦格式為“制造商,型號”compatibleR<stringlist>指定平臺體系結構列表。該平臺兼容。這一建議可供操作系統在選擇平臺特定代碼時使用。1.3.4.2. /aliases節(jié)點

設備樹文件可能具有一個別名節(jié)點(/aliases),該節(jié)點定義一個或多個別名屬性。別名節(jié)點應位于設備樹的根節(jié)點,并且具有節(jié)點名稱/別名。/aliases節(jié)點的每個屬性都定義了一個別名。屬性名稱指定別名。屬性值指定設備樹中節(jié)點的完整路徑。例如,屬性serial0 = "/simple-bus@fe000000/serial@llc500"定義了別名serial0。別名的命名規(guī)則如下:

字符描述0-9數字a-z小寫字母-破折號1.3.4.3. /memory節(jié)點

所有設備樹都需要內存設備節(jié)點,并描述系統的物理內存布局。如果系統具有多個范圍的內存,則可以創(chuàng)建多個內存節(jié)點,或者可以在單個內存節(jié)點的reg屬性中指定范圍。

/memory節(jié)點的屬性要求如下:

屬性名稱使用說明類型定義device_typeRO<string>regR<prop-encoded-array>由任意數量的地址和大小對組成,它們指定內存范圍的物理地址和大小initial-mapped-areaO<prop-encoded-array>指定”初始映射區(qū)域”的地址和大小,是一個由三元組組成的屬性編碼數組(有效地址、物理地址、大。。有效和物理地址均應為64位(值),大小應為32位(值)

在xxx.dts中

memory {
      reg =  <0x40000000 0x10000000>;   起始地址0x40000000 長度0x10000000(32MB)
};
1.3.4.4. /chosen 節(jié)點

/chosen 節(jié)點不代表系統中的實際設備,而是描述了在運行時由系統固件選擇或指定的參數。它應該是根節(jié)點的子節(jié)點。

屬性名稱使用說明類型定義bootargsO<string>指定程序的啟動參數。如果不需要引導參數,則該值可能為空字符串stdout-pathO<string>指定到表示用于引導控制臺輸出的設備的節(jié)點的完整路徑。如果包含’:’,則它將終止路徑。該值可以是別名。stdin-pathO<string>指定到表示用于引導控制臺輸入的設備的節(jié)點的完整路徑。如果包含’:’,則它將終止路徑。該值可以是別名。

示例:

chosen {
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};
1.3.4.5. /cpus節(jié)點屬性

所有設備樹均需要/cpus/cpu節(jié)點。它并不代表系統中的真實設備,而是作為代表系統cpu的子cpu節(jié)點的容器。

屬性名稱使用說明類型定義device_typeR<string>值應為“cpu”regR<prop-encoded-array>它為CPU節(jié)點表示的CPU/線程定義了唯一的CPU/線程ID。如果CPU支持多線程,則reg是一個數組,每個線程具有一個元素。clock-frequencyR<prop-encoded-array>以Hz為單位指定CPU的當前時鐘速度,格式可以是,或timebase-frequencyR<prop-encoded-array>指定更新時基的當前頻率statusSD<string>此屬性應存在于對稱多進程(SMP)CPU的節(jié)點中 配置。”okay”:CPU正在運行;”disable”:CPU處于靜止狀態(tài)。1.3.5. 中斷映射

在設備樹中,存在邏輯中斷樹,該邏輯中斷樹表示平臺硬件中斷的層次結構和路由。在設備樹中,使用interrupt-parent屬性表示中斷源與中斷控制器的物理連線。代表產生中斷的設備節(jié)點包含一個中斷父屬性,該屬性具有一個虛擬值,指向給設備的中斷所路由到的設備(通常是中斷控制器)。

如果產生中斷的設備不具有中斷父屬性,則假定其中斷父節(jié)點為其設備父節(jié)點。每個中斷產生設備都包含一個中斷屬性,該屬性的值描述該設備的一個或多個中斷源。每個源都用稱為中斷描述符表示。中斷描述符的格式和含義是特定于中斷域的,即,取決于中斷域根節(jié)點上節(jié)點的屬性。中斷域的根使用#interrupt-cells屬性定義對中斷描述符進行編碼所需的值數量。

中斷域是解釋中斷描述符的上下文。中斷域的根可以是中斷控制器(interrupt controller)或中斷連接器(interrupt nexus):

中斷控制器是物理設備,需要一個驅動程序來處理通過它路由的中斷。它還可能級聯到另一個中斷域。中斷控制器由設備樹中該節(jié)點上的interrupt-controller指定。中斷連接器定義了一個中斷域和另一個中斷域之間的轉換。翻譯基于特定領域和總線的信息。使用interrupt-map屬性在域之間進行轉換。例如,PCI控制器設備節(jié)點可以是一個中斷連接器,定義從PCI中斷命名空間(INTA、INTB等)到具有中斷請求(IRQ)編號的中斷控制器的轉換。

1.3.5.1. Interrupts屬性名稱interrupts值類型<prop-encoded-array>編碼為任意數量的中斷描述符描述設備節(jié)點的中斷屬性定義設備生成的中斷。interrupts屬性的值由任意數量的中斷描述符組成。中斷描述符的格式由中斷域根定義。

示例:

interrupts = <GIC_SPI INT_DMA IRQ_TYPE_LEVEL_HIGH>;

1.3.5.2. interrupt-parent屬性名稱interrupt-parent值類型<phandle>描述由于中斷樹中節(jié)點的層次結構可能與device tree不匹配,因此interrupt-parent屬性可用于明確中斷父級的定義。該值是中斷父級的phandle。如果設備缺少此屬性,則假定其中斷父級為其設備樹父級。

示例:

interrupt-parent = <&gpe>;

1.3.5.3. interrupts-extended屬性名稱interrupts-extended值類型<phandle>描述擴展的中斷屬性列出了設備產生的中斷。當設備連接到多個中斷控制器時,應該使用interrupts-extended代替interrupts,因為它會在每一個中斷描述符編碼一個父代phandle

示例:

interrupts-extended = <&pic 0xA 8>, <&gic 0xda>;

1.3.5.4. #interrupt-cells屬性名稱#interrupt-cells值類型<u32>描述#interrupt-cells屬性定義對中斷域的中斷描述符進行編碼所需的單元數量1.3.5.5. interrupt-controller屬性名稱interrupt-controller值類型<empty>描述中斷控制器屬性的存在將節(jié)點定義為中斷控制器節(jié)點。1.4.Device Tree binary格式

Devicetree Blob (DTB)格式是Devicetree數據的平面二進制編碼。它用來在軟件程序之間交換設備數據。例如,在引導操作系統時,固件將向操作系統內核傳遞一個DTB。

DTB格式將devicetree數據編碼為一個單一的、線性的、無指針的數據結構。它由一個小標題組成,接下來是三個大小可變的部分:內存保留塊、結構塊和字符串塊這些應該按照這個順序出現在扁平的devicetree中。

因此。當按地址加載到內存中時,設備樹結構作為一個整體。將類似于圖中的圖表。

1.4.1. dt_header

設備樹的頭部是由以下C結構體定義的。所有字段都是32位整數,以big-endian格式存儲。

struct fdt_header {
此字段應包含值0xd00dfeed(big-endian)
uint32_t magic;     magic word FDT_MAGIC
此字段應包含設備數據結構的總大。ㄗ止(jié))。該大小應包含結構的所有部分:報頭、內存預留塊、結構塊和字符串塊,以及塊之間或最終塊之后的自由空間間隙。
uint32_t totalsize;    total size of DT block
此字段應包含結構塊從標題開始的字節(jié)偏移
uint32_t off_dt_struct;    offset to structure
此字段應包含從標題開始的字符串塊的字節(jié)偏移量
uint32_t off_dt_strings;   offset to strings
此字段應包含從標題開始的內存保留塊的字節(jié)偏移量
uint32_t off_mem_rsvmap;   offset to memory reserve map
此字段應包含設備數據結構的版本
uint32_t version;    format version
此字段應包含設備所用版本向后兼容的最低版本數據結構
uint32_t last_comp_version;   last compatible version
 version 2 fields below
此字段應包含系統引導CPU的物理ID。它應與設備樹中CPU節(jié)點的reg屬性中給定的物理ID相同
uint32_t boot_cpuid_phys;   Which physical CPU id we're booting on
 version 3 fields below
此字段應包含字符串塊部分的字節(jié)長度
uint32_t size_dt_strings;   size of the strings block
 version 17 fields below
此字段應包含結構塊部分的字節(jié)長度
uint32_t size_dt_struct;   size of the structure block
};
1.4.2. memory reservation block

內存保留塊向客戶端程序提供物理內存中被保留的區(qū)域的列表,這些內存不用于一般的內存分配,目的是保護重要的數據結構不被客戶端程序覆蓋。這個區(qū)域包括了若干的reserve memory描述符。每個reserve memory描述符是由address和size組成。其中address和size都是用U64來描述:

struct fdt_reserve_entry {
uint64_t address;
uint64_t size;
};
1.4.3. Structure block

結構塊描述了設備樹本身的結構和內容。它由若干的分片組成,每個分片開始位置都是保存了令牌(token),以此來描述該分片的屬性和內容。

FDT_BEGIN_NODE (0x00000001):該token描述了一個node的開始位置,緊挨著該token的就是node name(包括unit address)FDT_END_NODE (0x00000002):該token描述了一個node的結束位置FDT_PROP (0x00000003):該token描述了一個property的開始位置,該token之后是兩個u32的數據。它們之后就是長度為len的具體的屬性值數據。struct {
uint32_t len; 表示該property value data的size。
uint32_t nameoff; 表示該屬性字符串在device tree strings block的偏移值

FDT_NOP (0x00000004):被解析設備樹的程序忽略,可用于覆蓋其他屬性,以刪除它FDT_END (0x00000009):標記結構塊的結束所以,一個DTB的結構塊可能如下:(optionally) any number of FDT_NOP tokens
FDT_BEGIN_NODE token:
--node’s name
--paddings
For each property of the node:
              --FDT_NOP(optionally)
              --FDT_PROP token
                  --property    
all child nodes in this format
(optionally) any number of FDT_NOP tokens
FDT_END_NODE token
1.4.4. Strings Block

定義了各個node中使用的屬性的字符串表。由于很多屬性會出現在多個node中,因此,所有的屬性字符串組成了一個string block。這樣可以壓縮DTB的size。

1.5.Linux解析設備樹

設備樹描述了設備的詳細信息,這些信息包括數字類型的、字符串類型的、數組類型的,我們在編寫驅動時需要去獲取這些信息。Linux內核提供一系列以of_開頭的函數來獲取設備樹信息,這些函數的原型都定義在include/linux/of.h中。設備以節(jié)點的形式掛在設備樹上,Linux內核使用device_node結構體來描述一個節(jié)點,其定義在include/linux/of.h中:

struct device_node {
const char *name;     device node name
const char *type;     對應device_type的屬性
phandle phandle;      對應該節(jié)點的phandle屬性
const char *full_name;  從“/”開始的,表示該node的full path
Struct  property *properties;      該節(jié)點的屬性列表
如果需要刪除某些屬性,kernel并非真的刪除,而是掛入到deadprops的列表
struct  property *deadprops;  removed properties
parent、child以及sibling將所有的device node連接起來
Struct  device_node *parent;  
Struct  device_node *child;
Struct  device_node *sibling;
通過該指針可以獲取相同類型的下一個node
Struct  device_node *next;  next device of same type
通過該指針可以獲取node global list下一個node
struct  device_node *allnext;  next in list of all nodes
struct  kobject kobj;
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
1.5.1. 查找節(jié)點的 OF函數1.5.1.1. of_find_node_by_name

功能 :Find a node by its "name" property函數

struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)

參數 :

@from:開始查找的節(jié)點,如果為NULL表示從根節(jié)點開始查找整個設備樹。
@name::要查找的節(jié)點名字。

返回值: 找到的節(jié)點,如果為NULL表示查找失敗。

1.5.1.2. of_find_node_by_path

功能 :Find a node matching a full OF path函數 :

struct device_node *of_find_node_by_path(const char *path)

參數 :@path: 完整的匹配路徑返回值 :找到的節(jié)點,如果為NULL表示查找失敗。

1.5.1.3. of_find_node_by_type

功能 Find a node by its "device_type" property函數

struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)

參數

@from:開始查找的節(jié)點,如果為NULL表示從根節(jié)點開始查找整個設備樹
@type: 要查找的節(jié)點類型

返回值 找到的節(jié)點,如果為NULL表示查找失敗。

1.5.1.4. of_find_compatible_node

功能 通過device_type和compatible查找指定節(jié)點函數

struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible)

參數

@from:開始查找的節(jié)點,如果為NULL表示從根節(jié)點開始查找整個設備樹
@type: 要查找的節(jié)點device_type屬性
@compatible:節(jié)點的compatible屬性列表

返回值 找到的節(jié)點,如果為NULL表示查找失敗。

1.5.1.5. of_find_node_with_property

功能 通過屬性名查找指定節(jié)點函數

struct device_node *of_find_node_with_property(struct device_node *from,const char *prop_name)

參數

@from:開始查找的節(jié)點,如果為NULL表示從根節(jié)點開始查找整個設備樹
@type: 要查找的節(jié)點屬性名稱

返回值 找到的節(jié)點,如果為NULL表示查找失敗。

1.5.2. 查找父 /子節(jié)點的 OF函數1.5.2.1. of_get_parent

功能 函數用于獲取指定節(jié)點的父節(jié)點(如果有父節(jié)點的話 )函數

struct device_node *of_get_parent(const struct device_node *node)

參數

@node:要查找父節(jié)點的節(jié)點

返回值 找到的父節(jié)點

1.5.2.2. of_get_next_available_child

功能 獲取子節(jié)點,并跳過status = "disabled"的節(jié)點函數

struct device_node *of_get_next_available_child(const struct device_node *node,struct device_node *prev)

參數

@node: 父節(jié)點
@prev:當前父節(jié)點的上一個子節(jié)點, 如果為空,則獲取第一個子節(jié)點

返回值 找到的子節(jié)點

1.5.3. 提取屬性值的 OF函數

Linux內核使用struct property來保存節(jié)點的屬性,其定義在/include/linux/of.h中:

struct property {
char  *name;      屬性的名稱
int  length;      屬性的長度
void  *value;     屬性的值
struct property *next;   下一個屬性
unsigned long _flags;    
unsigned int unique_id;
struct bin_attribute attr;
};
1.5.3.1. of_find_property

功能 尋找指定的屬性函數

struct property *of_find_property(const struct device_node *np,
     const char *name,
     int *lenp)

參數

@np: 設備節(jié)點
@name:屬性名稱
@lenp:屬性的字節(jié)數

返回值 找到的屬性

1.5.3.2. 讀取屬性中u8、u16、u32和u64類型的數組數據

當設置sz為1時,就是讀取一個數據,Linux內核也是這么封裝的。

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)
int of_property_read_u64(const struct device_node *np, const char *propname,
       u64 *out_value)
1.5.3.3. of_property_read_string

功能 找到并讀取屬性字符串函數

int of_property_read_string(struct device_node *np, const char *propname,const char **out_string)

參數

@np: 設備節(jié)點
@propname:屬性名稱
@out_string:讀取的字符串

返回值

0:讀取成功
-EINVAL:屬性不存在
-ENODATA:屬性沒有這個值
-EILSEQ:字符串不是以空字符’’結尾

<上一頁  1  2  3  下一頁>  
聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權或其他問題,請聯系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

    掃碼關注公眾號
    OFweek人工智能網
    獲取更多精彩內容
    文章糾錯
    x
    *文字標題:
    *糾錯內容:
    聯系郵箱:
    *驗 證 碼:

    粵公網安備 44030502002758號