2018年6月17日 星期日

Linux Kernel(15.3)- The Linux usage model for device tree data


這篇基本上就是"Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data的筆記

DT(Device Tree,或稱Open Firmware Device Tree)是一個資料結構(data structure)用於讓OS讀取硬體周邊訊息動態執行,因此OS就不用hard code硬體驅動。

所謂的"bindings"就是一組通用的DTS設定,用來描述其硬體,包含了data busses, interrupt lines, GPIO connections, and peripheral devices等等。

盡可能使用現有的binding來描述硬體,以最大限度地利用現有的代碼,但由於property和node名稱只是字串,因此通過定義新property和node可以輕鬆擴展現有binding。 不要沒做功課就自己建立新的binding,i2c busses就因為沒有先確認是否已經有人定義了相關的binding,就建立了新的binding,導致現在有兩套不相容的binding發生。

DT所做的只是提供一種language將硬體設定從device driver分離開來,如此可以透過傳入不同的DT給OS,以適應不同的硬體設定裝置. 進而減少一些重複的code。

DT在Linux底下有三個主要目的
1) platform identification,
2) runtime configuration, and
3) device population.


platform identification

首先kernel會先使用DT來辨識特定的機器,並且執行相關的初始化,比如ARM會在setup_arch()呼叫setup_machine_fdt()尋找適合的DT(比對DT root底下的"compatible" property。
    compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
上面的例子定義了"ti,omap3-beagleboard-xm",也宣稱相容"OMAP 3450 SOC"與"OMAP3"系列的SoC,你會注意到這樣的宣稱會從最具體的board到SoC的家族,關於compatible的值必須進行記錄說明其含義。

runtime configuration

一般來說,DT是firmware傳遞資料給kernel的唯一方法,PowerPC呼叫of_scan_flat_dt(early_init_dt_scan_root, NULL)執行early init,ARM則是呼叫mdesc = setup_machine_fdt(__atags_pointer)

device population

在early configuration之後,kernel會用 unflatten_device_tree()將DT轉成device node tree,讓之後的init_early(), init_irq() and init_machine()等等使用,init_early()用於任何需要在啟動過程中儘早執行的設置,init_irq()用於設置中斷處理,而init_machine()負責建立Linux platform device,這裡主要呼叫of_platform_populate()建構platform device。之後的driver也是透過of_platform_populate()建構platform device。
i2c_add_driver( ) @ i2c.h  
  |-> i2c_register_driver() @i2c-core.c /* 將device_driver中的bus_type設成i2c_bus_type */  
    |--> driver_register() @driver.c  
      |--> bus_add_driver() @bus.c /* 建立sysfs file node 與 attr */  
        |--> driver_attach() @dd.c  
          |--> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) @bus.c  
            |--> __driver_attach @dd.c  
              |--> driver_match_device(drv, dev) @base.h  
                |--> i2c_device_match() @i2c-core.c  
                  /***********************************************  
                   如果是device tree, 會透過 of_driver_match_device()去做匹配的動作
                   如果不是device tree就改用 i2c_match_id()去完成匹配的動作
                  ***************************************************/ 
                  /* Attempt an OF style match */
                  if (of_driver_match_device(dev, drv))
                    return 1;

                  /* Then ACPI style match */
                  if (acpi_driver_match_device(dev, drv))
                    return 1;
                  
                  driver = to_i2c_driver(drv);
                  /* match on an id table if there is one */
                  if (driver->id_table)
                    return i2c_match_id(driver->id_table, client) != NULL;
              |--> driver_probe_device() @dd.c  
                /*如果匹配成功, 接下來就要準備 call driver 中的 probe function*/
                |--> really_probe() @dd.c  
                  |--> i2c_device_probe() @i2c-core.c  
                    |--> rt5627_i2c_probe() @rt5627.c  
from http://janbarry0914.blogspot.com/2014/08/device-tree-i2c-device-driver-match.html



熱門文章