天天看點

第八章 裝置樹詳解-8.3核心對裝置樹的處理

    看了韋老師的裝置樹視訊,講的很好!也在網上找到了根據老師講課内容整理出來的博文,關于.dts轉換成.dtb檔案的内容可以參考這篇博文:https://blog.csdn.net/huanting_123/article/details/90142745

    單闆上電之後uboot引導核心啟動的流程,也參考該作者的另一篇博文:https://blog.csdn.net/huanting_123/article/details/89931329,中間涉及彙編和好多看了頭暈的代碼,自己寫起來有些吃力,等後面深入學習了再來分析。

 後面會陸續講到核心對裝置樹的處理,也可以參考上面的這位作者的博文,這裡自己寫一下自己的了解。隻能是自己的一些淺顯了解,深入代碼内部的了解暫時還做不到。

8.3.2.對裝置樹中平台資訊的處理(選擇machine_desc)

    可參考:

    核心中有很多machine_desc結構體描述單闆資訊,其中有個字元串變量為dt_compat,它可以為單個字元串也可以為多個字元串,字元串内容為該machine_desc可以支援的單闆資訊。.dts中的根節點的compatiple中申明了該裝置樹可以運作的單闆類型,可以是單個字元串或多個字元串,依次與dt_compat對比,排在前面的compatiple屬性優先比對。看下6ull的dts和machine_desc。

//.dts:
/ {
	model = "Freescale i.MX6 ULL 14x14 EVK Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
}
********************************************************
//arch/arm/mach-imx6ul.c

static const char * const imx6ul_dt_compat[] __initconst = {
    "fsl,imx6ul",
    "fsl,imx6ull",
    NULL,
};
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 UltraLite (Device Tree)")
    .map_io = imx6ul_map_io,
    .init_irq = imx6ul_init_irq,
    .init_machine = imx6ul_init_machine,
    .init_late = imx6ul_init_late,
    .dt_compat = imx6ul_dt_compat,
MACHINE_END
           

函數調用過程:

第八章 裝置樹詳解-8.3核心對裝置樹的處理

8.3.3.對裝置樹中運作時配置資訊的提取

    可參考:https://blog.csdn.net/huanting_123/article/details/89978923

    主要是講核心如何提取幾個特殊節點和屬性:

a. /chosen節點中bootargs屬性的值, 存入全局變量: boot_command_line

b. 确定根節點的這2個屬性的值: #address-cells, #size-cells,存入全局變量: dt_root_addr_cells, dt_root_size_cells

c. 解析/memory中的reg屬性, 提取出"base, size", 最終調用memblock_add(base, size); 

第八章 裝置樹詳解-8.3核心對裝置樹的處理

8.3.4.dtb轉換為device_node(unflatten)

    核心先計算出整個樹的大小并為其配置設定記憶體空間,然後将裝置樹中的每個node轉化為device_node,再為每個device_node填入device_properties。

unflatten_device_tree(); //解壓裝置樹
    __unflatten_device_tree(initial_boot_params, NULL, &of_root,
        early_init_dt_alloc_memory_arch, false); //執行解壓

            /* First pass, scan for size 計算裝置樹的大小*/
            size = unflatten_dt_nodes(blob, NULL, dad, NULL);

            /* Allocate memory for the expanded device tree 為裝置樹配置設定記憶體*/
            mem = dt_alloc(size + 4, __alignof__(struct device_node));

            /* Second pass, do actual unflattening */
            unflatten_dt_nodes(blob, mem, dad, mynodes); //解壓裝置樹節點
                fdt_next_node(); //周遊裝置樹找節點
                populate_node(); //填充裝置樹節點

                |-->fdt_get_name(); //擷取name屬性
                |-->np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node)); //為node配置設定記憶體
                |-->of_node_init(np); //初始化節點
                |-->np->full_name = fn = ((char *)np) + sizeof(*np);
                 //将device_node的full_name指向結構體結尾處,即将一個節點的unit name放置在一個struct device_node的結尾處。
                |-->populate_properties(); //填充屬性

                    ||-->fdt_next_property_offset(); //
                    ||-->pp = unflatten_dt_alloc(mem, sizeof(struct property),
__alignof__(struct property)); //為property配置設定記憶體
                    ||-->pp->name = (char *)pname;
                    ||-->pp->length = sz;
                    ||-->pp->value = (__be32 *)val;
           

    關于韋老師的那個node和特性的圖是很好的,但是太長了,不貼出來了。

8.3.5.device_node轉換為platform_device

一路轉化過來就是:dts -> dtb -> device_node -> platform_device

兩個問題:

  1. 哪些device_node可以轉換為platform_device?

并非所有的device_node都會轉換為platform_device,隻有以下的device_node會轉換:

a.1 根節點不會轉化成platform_device;

a.2 根節點的子節點(父節點)必須含有compatible屬性才可以轉化成platform_device;

a.3 孫節點可以轉化為platform_device的前提是自身必須含有compatible屬性而且父節點必須含有特殊的compatible屬性,如"simple-bus","simple-mfd","isa","arm,amba-bus"。

舉例:

/ {
      mytest {
            /*父節點中的"simple-bus"屬性會導緻其子節點也會建構出平台裝置的裝置端*/
          compatile = "mytest", "simple-bus";
          [email protected] {
                compatile = "mytest_0";
          };
      };
      
      i2c {
          compatile = "samsung,i2c";
          at24c02 {
                compatile = "at24c02";                      
          };
      };
};
           

(1)節點 /mytest 會被轉換為 platform_device。由于它相容 "simple-bus", 它的子節點 /mytest/[email protected] 也會被轉換為platform_device. 也就是說一個節點的 compatible 屬性中隻要有 "simple-bus",其子節也會轉換為 platform_device,若沒有是不會轉換的。

(2)/i2c 節點一般表示i2c控制器,它會被轉換為platform_device,在核心中有對應的 platform_driver; 其子節點 /i2c/at24c02 節點不會被轉換為 platform_device,它被如何處理完全由父節點的 platform_driver 決定, 一般是被建立為一個i2c_client。

b. 怎麼轉換?

    首先看一個結構體platform_device,找到一篇很好的博文:https://www.cnblogs.com/downey-blog/p/10486568.html,引用:

“在老版本的核心中,platform_device部分是靜态定義的,其實最主要的部分就是resources部分,這一部分描述了目前驅動需要的硬體資源,一般是IO,中斷等資源。

    在裝置樹中,這一類資源通常通過reg屬性來描述,中斷則通過interrupts來描述,是以,裝置樹中的reg和interrupts資源将會被轉換成platform_device内的struct resources資源。

那麼,裝置樹中其他屬性是怎麼轉換的呢?答案是:不需要轉換,在platform_device中有一個成員struct device dev,這個dev中又有一個指針成員struct device_node *of_node,linux的做法就是将這個of_node指針直接指向由裝置樹轉換而來的device_node結構。

例如,有這麼一個struct platform_device* of_test.我們可以直接通過of_test->dev.of_node來通路裝置樹中的資訊.”

第八章 裝置樹詳解-8.3核心對裝置樹的處理

 原來是這麼個調用關系!

8.3.6.platform_device跟platform_driver的比對

    發現寫的很不錯的博文記錄下:https://blog.csdn.net/richard_liujh/article/details/45825333

第八章 裝置樹詳解-8.3核心對裝置樹的處理

小結:uboot把裝置樹編譯成的.dtb檔案的位址傳遞給核心,核心提取.dtb根節點的compatible屬性來比對machine_desc,解析.dtb的chosen節點、memory節點、#address-cells和#size-cells屬性,為其配置設定記憶體。再去周遊整個.dtb檔案的節點,将其轉換成device_nodes,填充到各個device_nodes的properties,最終建構出device-tree。再根據compatible屬性的轉化原則将某些device_nodes轉化成platform_devices,不能轉化成device_nodes的節點核心提供專門的處理函數。platform_devices被挂載到不同的裝置總線上,等待platform_drivers的注冊。到這裡裝置樹到核心的轉化過程已經清楚了,回歸到leddrv.c中。

繼續閱讀