精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linu設備樹及其語法介紹

CHANBAEK ? 來源:嵌入式攻城獅 ? 作者:安迪西 ? 2023-04-14 11:38 ? 次閱讀

1. 什么是設備樹

設備樹的本質也是操作寄存器,只不過寄存器的相關信息放在了設備樹中,配置寄存器時需要使用OF函數從設備樹中讀取寄存器數據后再進行配置

Linux 3.x之前是沒有設備樹的,Linux通過內核源碼中arch/arm/mach-xxx和arch/arm/plat-xxx文件夾里的板級描述文件來描述ARM架構中的板級信息。 隨著ARM硬件種類增多,與板子相關的設備文件也越來越多,導致內核越來越大,而實際上這些硬件板級信息與內核并無相關關系

2011年,Linus發現該問題后,引入了PowerPC等架構已經采用的設備樹機制,將板級信息從內核中分離開來,用一個專屬的文件格式(.dts文件)來描述。 設備樹的作用就是描述硬件平臺的硬件資源,它可被bootloader傳遞到內核,內核可以從設備樹中獲取硬件信息。 設備樹描述硬件資源時有兩個特點:

  • 以樹狀結構描述硬件資源
  • 可以像頭文件那樣,一個設備樹文件可以引用另一個設備樹文件,實現代碼重用

圖片

DTS、DTSI、DTB、DTC文件的區別及定義:

圖片

DTC工具源碼在Linux內核的scripts/dtc/Makefile文件中:

hostprogs-y:= dtc 
always:= $(hostprogs-y) 

dtc-objs:= dtc.o flattree.o fstree.o data.o livetree.o treesource.o srcpos.o checks.o util.o 
dtc-objs+= dtc-lexer.lex.o dtc-parser.tab.o 
......

由上可見DTC工具依賴于dtc.c, flattree.c, fstree.c等文件,最終編譯并鏈接出DTC這個主機文件。 若要編譯DTS文件,只需要進入到Linux源碼根目錄下,然后執行如下命令:

make all   #編譯Linux源碼中的所有東西,包括zImage、.ko驅動模塊以及設備樹
make dtbs  #只是編譯設備樹

基于ARM架構的SOC有很多,一種SOC又可制作出多款板子,每個板子都有對應的DTS文件,那么如何確定編譯哪一個DTS文件呢? 以I.MX6ULL芯片的板子為例,打開arch/arm/boot/dts/Makefile,有如下內容:

dtb-$(CONFIG_SOC_IMX6UL) += \\ 
    imx6ul-14x14-ddr3-arm2.dtb \\ 
    imx6ul-14x14-ddr3-arm2-emmc.dtb \\ 
    ...... 
dtb-$(CONFIG_SOC_IMX6ULL) += \\ 
    imx6ull-14x14-ddr3-arm2.dtb \\ 
    imx6ull-14x14-ddr3-arm2-adc.dtb \\ 
    ......

選中I.MX6ULL后(即CONFIG_SOC_IMX6ULL=y),所有使用該SOC的板子對應的.dts文件都會被編譯為.dtb。 若新做一個板子,只需要新建一個對應的.dts文件,再將對應的.dtb文件名添加到 dtb-$(CONFIG_SOC_IMX6ULL)下,這樣在編譯設備樹時就會將對應的.dts編譯為二進制的.dtb文件

2. 設備樹語法介紹

2.1 設備樹代碼分析

關于i. MX6ULL已有的設備樹文件,大致有以下幾種

imx6ull-14x14-evk-emmc.dts文件:在/arch/arm/boot/dts/文件夾中,描述了emmc板子的usdhc信息。 該文件通過頭文件的形式包含了另一個設備樹文件

#include "imx6ull-14x14-evk.dts"

&usdhc2 {
    pinctrl-names = "default", "state_100mhz", "state_200mhz";
    pinctrl-0 = <&pinctrl_usdhc2_8bit>;
    pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
    pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
    bus-width = <8>;
    non-removable;
    status = "okay";
};

imx6ull-14x14-evk.dts文件:在/arch/arm/boot/dts/文件夾中,包含了根節點、子節點及其他追加內容

#include 
#include "imx6ull.dtsi"

/ {
    model = "Freescale i.MX6 ULL 14x14 EVK Board";
    compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

    chosen {
        stdout-path = &uart1;
    };

    memory {
        reg = <0x80000000 0x20000000>;
    };

    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        linux,cma {
            compatible = "shared-dma-pool";
            reusable;
            size = <0x14000000>;
            linux,cma-default;
        };
    };

    backlight {
        compatible = "pwm-backlight";
        pwms = <&pwm1 0 5000000>;
        brightness-levels = <0 4 8 16 32 64 128 255>;
        default-brightness-level = <6>;
        status = "okay";
    };

    pxp_v4l2 {
        compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
        status = "okay";
    };

    regulators {
        compatible = "simple-bus";
        ......
    };
    ......
};

&cpu0 {
    arm-supply = <®_arm>;
    soc-supply = <®_soc>;
    dc-supply = <®_gpio_dvfs>;
};

&clks {
    assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
    assigned-clock-rates = <786432000>;
};
......
&wdog1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_wdog>;
    fsl,wdog_b;
};

imx6ull.dtsi文件:是設備樹的頭文件,其格式與設備樹基本相同

#include 
#include "imx6dl-pinfunc.h"
#include "imx6qdl.dtsi"

/ {
    aliases {
        i2c3 = &i2c4;
    };

    cpus {
        #address-cells = <1>;
        #size-cells = <0>;

        cpu0: cpu@0 {
            compatible = "arm,cortex-a9";
            device_type = "cpu";
            ......
        };

        cpu@1 {
            compatible = "arm,cortex-a9";
            device_type = "cpu";
            reg = <1>;
            next-level-cache = <&L2>;
        };
    };

    reserved-memory {
        ......
    };

    soc {
        ......
        ocram: sram@00905000 {
            compatible = "mmio-sram";
            reg = <0x00905000 0x1B000>;
            clocks = <&clks IMX6QDL_CLK_OCRAM>;
        };
        ......
    };
};
......
&vpu_fsl {
    iramsize = <0>;
};

2.2 DTS語法介紹

設備樹采用樹形結構來描述板子上的設備信息,每個設備都是一個節點,叫做設備節點,每個節點都通過一些屬性信息來描述節點信息,屬性就是鍵-值對

node-name@unit-address{
    屬性1 = ...
    屬性2 = ...
    子節點...
}

節點名稱:node-name用于指定節點名稱,應使用字母開頭,并能描述設備類別(根節點用斜杠表示)

單元地址:@unit-address用于指定單元地址,@為分隔符,后面是實際的單元地址,它的值與節點reg屬性的第一個地址一致,若沒有reg屬性值,則可以省略單元地址

節點屬性:節點的大括號{ }中包含的內容是節點屬性, 一個節點可以包含多個屬性信息,設備樹最主要的內容就是編寫節點的屬性。 屬性包括自定義屬性和標準屬性

  • model屬性:用于指定設備的制造商和型號,多個字符串使用“,”分隔開
  • compatible屬性:由一個或多個字符串組成,是用來查找節點的方法之一
  • status屬性:用于指示設備的操作狀態,通過status可以禁用或啟用設備
  • reg屬性:描述設備資源在其父總線定義的地址空間內的地址,通常用于表示一塊寄存器的起始地址和長度
  • #address-cells 和 #size-cells:這兩個屬性同時存在,前者決定了子節點reg屬性中地址信息所占用的字長,后者決定了長度信息所占的字長
  • ranges屬性:是一個地址映射/轉換表,由子地址、父地址和地址空間長度這三部分組成
    • child-bus-address:子總線地址空間的物理地址, 由父節點的#address-cells 確定此物理地址所占用的字長
    • parent-bus-address:父總線地址空間的物理地址,同樣由父節點的#address-cells 確定此物理地址所占用的字長
    • length:子地址空間的長度,由父節點的#size-cells 確定此地址長度所占用的字長
      特殊節點:aliases子節點、chosen子節點
//為其他節點起一個別名
aliases {
    i2c3 = &i2c4;
};
//該節點位于根節點下,它不代表實際硬件,主要用于給內核傳遞參數
//下面代碼表示系統標準輸出stdout使用串口uart1
chosen {
    stdout-path = &uart1;
};

3. 設備樹OF函數

內核提供了一系列函數用于從設備節點獲取節點中定義的屬性,這些函數以of_開頭,稱為OF函數。 在編寫設備樹版的驅動時,在進行硬件配置方面,就是要用這些OF函數,將寄存器地址等信息從設備樹文件中獲取出來,然后進行配置

圖片

3.1 查找節點的OF函數

設備都是以節點的形式掛到設備樹上的,因此要獲取這個設備的其他屬性信息,必須先獲取到這個設備的節點。 內核使用device_node結構體來描述一個節點,此結構體定義在文件include/linux/of.h中,定義如下:

struct device_node {
    const char *name; /* 節點名字 */
    const char *type; /* 設備類型 */
    phandle phandle;
    const char *full_name; /* 節點全名 */
    struct fwnode_handle fwnode;

    struct property *properties; /* 屬性 */
    struct property *deadprops; /* removed 屬性 */
    struct device_node *parent; /* 父節點 */
    struct device_node *child; /* 子節點 */
    struct device_node *sibling;
    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
};

of_find_node_by_name:通過節點名字查找指定的節點

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
//from:開始查找的節點,NULL表示從根節點開始查找整個設備樹
//name:要查找的節點名字
//返回值:找到的節點,NULL表示查找失敗

of_find_node_by_type:通過device_type屬性查找指定的節點

struct device_node *of_find_node_by_type(struct device_node *from, const char *type)
//from:開始查找的節點,NULL表示從根節點開始查找整個設備樹
//type:要查找的節點對應的type字符串,即device_type屬性值
//返回值:找到的節點,NULL表示查找失敗

of_find_compatible_node:根據device_type和compatible這兩個屬性查找指定的節點

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)
//from:開始查找的節點,NULL表示從根節點開始查找整個設備樹
//type:要查找的節點對應的device_type屬性值,為NULL時表示忽略掉該屬性
//compatible:要查找的節點所對應的compatible屬性列表
//返回值:找到的節點,NULL表示查找失敗

of_find_matching_node_and_match:通過of_device_id匹配表來查找指定的節點

struct device_node *of_find_matching_node_and_match(struct device_node *from,
                                          const struct of_device_id *matches,
                                           const struct of_device_id **match)
//from:開始查找的節點,NULL表示從根節點開始查找整個設備樹
//matches:of_device_id匹配表,也就是在此匹配表里面查找節點
//match:找到的匹配的of_device_id
//返回值:找到的節點,NULL表示查找失敗

of_find_node_by_path:通過路徑來查找指定的節點

inline struct device_node *of_find_node_by_path(const char *path)
//path:帶有全路徑的節點名
//返回值:找到的節點,NULL表示查找失敗

3.2 查找父/子節點的OF函數

of_get_parent:用于查找父節點

struct device_node *of_get_parent(const struct device_node *node)
//node:要查找的父節點的節點
//返回值:找到的父節點

of_get_next_child:用迭代的方式查找子節點

struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)
//node:父節點
//prev:前一個子節點,即從哪一個子節點開始迭代的查找下一個子節點,若為NULL,表示從第一個子節點開始
//返回值: 找到的下一個子節點

3.3 提取屬性值的OF函數

節點的屬性信息里面保存了驅動所需要的內容,因此對于屬性值的提取非常重要,內核中使用結構體property表示屬性,定義在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;
};

of_find_property:查找指定的屬性

property *of_find_property(const struct device_node *np, const char *name, int *lenp)
//np:設備節點
//name:屬性名字
//lenp:屬性值的字節數
//返回值:找到的屬性

of_property_count_elems_of_size:獲取屬性中元素的數量

int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)
//np:設備節點
//proname:需要統計元素數量的屬性名字
//elem_size:元素長度
//返回值:得到的屬性元素數量

of_property_read_u32_index:從屬性中獲取指定標號的u32類型數據值

int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)
//np:設備節點
//proname:要讀取的屬性名字
//index:要讀取的值標號
//out_value:讀取到的值
//返回值:0 讀取成功,負值,讀取失敗,-EINVAL 表示屬性不存在, 
//       -ENODATA 表示沒有要讀取的數據,-EOVERFLOW 表示屬性值列表大小

of_property_read_u8_array:讀取屬性中u8類型的數組數據(類似的還有u16、u32 和 u64)

int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz)
//np:設備節點
//proname:要讀取的屬性名字
//out_value:讀取到的數組值
//sz:要讀取的數組元素數量
//返回值:0 讀取成功,負值,讀取失敗,-EINVAL 表示屬性不存在, 
//       -ENODATA 表示沒有要讀取的數據,-EOVERFLOW 表示屬性值列表太

of_property_read_u8:讀取只有一個整形值的屬性(類似的還有u16、u32和u64)

int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value)
//np:設備節點
//proname:要讀取的屬性名字
//out_value:讀取到的數組值
//返回值:0 讀取成功,負值,讀取失敗,-EINVAL 表示屬性不存在, 
//       -ENODATA 表示沒有要讀取的數據,-EOVERFLOW 表示屬性值列表太小

of_property_read_string:讀取屬性中字符串值

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)
//np:設備節點
//proname:要讀取的屬性名字
//out_string:讀取到的字符串值
//返回值:0,讀取成功,負值,讀取失敗

of_n_addr_cells:獲取#address-cells 屬性值

int of_n_addr_cells(struct device_node *np)
//np:設備節點
//返回值:獲取到的#address-cells屬性值

of_n_size_cells:獲取#size-cells 屬性值

int of_n_size_cells(struct device_node *np)
//np:設備節點
//返回值:獲取到的#size-cells屬性值

3.4 其他常用OF函數

of_device_is_compatible:查看節點的compatible屬性是否有包含compat指定的字符串,也就是檢查設備節點的兼容性

int of_device_is_compatible(const struct device_node *device, const char *compat)
//device:設備節點
//compat:要查看的字符串
//返回值: 0,節點的 compatible 屬性中不包含 compat 指定的字符串; 
//        正數,節點的 compatible 屬性中包含 compat 指定的字符串

of_get_address:獲取地址相關屬性

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)
//dev:設備節點
//index:要讀取的地址標號
//size:地址長度
//flags:參數,比如IORESOURCE_IO、IORESOURCE_MEM等
//返回值:讀取到的地址數據首地址,表示讀取失敗

of_translate_address:將設備樹讀取到的地址轉換為物理地址

u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
//dev:設備節點
//in_addr:要轉換的地址
//返回值:得到的物理地址,為OF_BAD_ADDR表示轉換失敗

of_address_to_resource:將reg屬性值,轉換為resource結構體類型

int of_address_to_resource(struct device_node *dev, int index, struct resource *r)
//dev:設備節點
//index:地址資源標號
//r:得到的 resource 類型的資源值
//返回值: 0,成功;負值,失敗

of_iomap:用于直接內存映射

void __iomem *of_iomap(struct device_node *np, int index)
//np:設備節點
//index:reg屬性中要完成內存映射的段,如果reg屬性只有一段的話index就設置為0
//返回值:經過內存映射后的虛擬內存首地址,NULL表示內存映射失敗
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    134

    文章

    9054

    瀏覽量

    366834
  • 寄存器
    +關注

    關注

    31

    文章

    5322

    瀏覽量

    120022
  • 源碼
    +關注

    關注

    8

    文章

    633

    瀏覽量

    29143
  • Linu
    +關注

    關注

    0

    文章

    26

    瀏覽量

    19809
  • 設備樹
    +關注

    關注

    0

    文章

    38

    瀏覽量

    3110
收藏 人收藏

    評論

    相關推薦

    Linux 設備詳解

    .dts的設備文件,在內核使用前需要轉換一次,主要是把繁復的語法形式及屬性值轉換成字節數據(特殊的數據結構),而非符號。.dts文件轉換后是.dtb的二進制文件。3、節點3.1、命名節點的命名以字母、數字
    發表于 11-02 13:46

    Linux 設備詳解

    .dts的設備文件,在內核使用前需要轉換一次,主要是把繁復的語法形式及屬性值轉換成字節數據(特殊的數據結構),而非符號。.dts文件轉換后是.dtb的二進制文件。3、節點3.1、命名節點的命名以字母、數字
    發表于 11-29 17:58

    語法在開發過程中的相關應用和具體使用場景

    【技術學院】開發者的進階之路:用語法來實現預編譯
    發表于 05-14 06:19

    什么是設備?由什么組成?設備怎么使用?

    什么是設備?由什么組成?設備怎么使用?
    發表于 03-04 07:04

    【米爾-TIAM62開發板-接替335x-試用評測】+(三)手把手創建Uboot設備與內核設備實戰

    這一數據結構進行了深入的研究和學習。設備是一種特殊的語法格式,用于描述嵌入式系統中的硬件信息。這種數據結構允許我們在不直接訪問硬件的情況下,通過軟件來識別和控制硬件設備。 首先,我了
    發表于 11-28 09:54

    如何修改內核設備

    本文檔介紹了內核設備的位置和包含關系 1.內核設備位置 文件 備注 dts longan/device/config/chips/t50
    發表于 12-14 13:42

    ARM Device Tree設備

    近期在學校如何寫linux的設備驅動,這片文章告訴我們為什么要引進設備Device Tree,以及舉例說明設備是怎樣寫的
    發表于 11-17 18:16 ?22次下載

    決策介紹

    關于決策介紹,是一些很基礎的介紹,不過是英文介紹
    發表于 09-18 14:55 ?0次下載

    ARM嵌入式Linux設備介紹及應用

      設備機制從Linux內核3.2版本左右開始采用,其不僅可以定義ARMSoC內部內存映射外設,還可以定義整個板卡,下面就以ToradexColibriVF61計算機模塊搭配ColibriEvaBoard為例來展示設備
    發表于 09-16 11:53 ?9次下載
    ARM嵌入式Linux<b class='flag-5'>設備</b><b class='flag-5'>樹</b><b class='flag-5'>介紹</b>及應用

    詳細解答Linux設備語法的原理構造

    Linux內核從3.x開始引入設備的概念,用于實現驅動代碼與設備信息相分離。在設備出現以前,所有關于
    發表于 05-15 10:53 ?1564次閱讀
    詳細解答Linux<b class='flag-5'>設備</b><b class='flag-5'>樹</b><b class='flag-5'>語法</b>的原理構造

    Petalinux工程中設備介紹

    設備是 Petalinux kernel 的關鍵組件,接下來以 2020.1 版本為例,為大家介紹一下在Xilinx Petalinux 工程中的設備
    的頭像 發表于 02-20 16:32 ?6819次閱讀
    Petalinux工程中<b class='flag-5'>設備</b><b class='flag-5'>樹</b>的<b class='flag-5'>介紹</b>

    基于關鍵詞的GCC抽象語法消除冗余算法

    GCC( GNU Compiler Collection)編譯器編譯¢語言源程序所生成的抽象語法文本中包含大量與源代碼無關的冗余信息,若直接進行解析,會嚴重影響分析效率,降低分析精確度,同時
    發表于 05-07 10:30 ?210次下載

    設備的傳遞及kernel 對設備的解析

    當 U-Boot 將設備加載到內存指定位置后,ARM 內核的 SoC 以通用寄存器 r2 來傳遞 dtb 在內存中的地址。kernel 獲取到該地址后對 dtb 文件做進一步的處理。 設備
    的頭像 發表于 07-29 11:19 ?2375次閱讀
    <b class='flag-5'>設備</b><b class='flag-5'>樹</b>的傳遞及kernel 對<b class='flag-5'>設備</b><b class='flag-5'>樹</b>的解析

    zynq開發中的設備

    在zynq開發中經常會修改設備,每次遇到這種情況都有點發愁,今天把設備相關的知識點總結一下,希望以后遇到設備
    的頭像 發表于 05-25 11:29 ?2113次閱讀
    zynq開發中的<b class='flag-5'>設備</b><b class='flag-5'>樹</b>

    如何修改內核設備

    如何修改內核設備
    的頭像 發表于 12-14 14:06 ?772次閱讀
    如何修改內核<b class='flag-5'>設備</b><b class='flag-5'>樹</b>