標籤:
原文網址:http://blog.csdn.net/dongwuming/article/details/12784213
簡介
主要功能是不在代碼中寫入程式碼裝置資訊,而是用專門的檔案來描述。整個系統的裝置節點會形成一個樹,裝置節點裡可以設定屬性。官網在http://www.devicetree.org 。入門指南請參考http://www.devicetree.org/Device_Tree_Usage 。Linux上一些狀況請參考"kernel/Document/devicetree/",其中"bindings"子目錄描述各種裝置的devicetree的描述方法,各廠商的各類裝置的描述方法都可能不同。
MSM8974 上DeviceTree簡介
裝置描述源檔案放在"kernel/arch/arm/boot/dts/"下尾碼是".dts"或".dtsi",一般".dtsi"是被其它檔案包含的,只用dtc編譯".dts"檔案。Build時會用"dtc"命令把需要的裝置描述檔案編譯成".dtb"檔案,並放到到bootimage的某個地方。對裝置描述的解析處理實現主要在"kernel/drivers/of/"目錄中,需要配置"CONFIG_OF"。啟動過程中,bootloader(預設是bootable/bootloader/lk)會根據機器硬體資訊選擇合適的devicetree裝入記憶體,把地址等相關資訊傳給kernel。kernel中,會根據傳入的資訊建立裝置。
版本聲明和包含其它檔案
一般".dts"檔案會先進行版本申明,如下面的第一行。".dts"或".dtsi"檔案也可能包含其它".dtsi"檔案,如下面的3/4行。
/dts-v1/;/include/ "msm8974-v2.2.dtsi"/include/ "msm8974-mtp.dtsi"
關於取地址符號的使用
如經常碰到類似下面的寫法。沒找到相關文檔說明(看源碼來理解也很費勁)。作用應該是對之前定義過的裝置(例子中是"soc")進行補充描述。
&soc {[email protected] {compatible = "qcom,android-usb";reg = <0xfe8050c8 0xc8>;qcom,android-usb-swfi-latency = <1>;};......};哪些檔案被編入二進位映像
有兩種方式使用DT。第一種可包含多個dtb,編入dt.img,放入boot.img。第二種只包含一個dtb,直接追加到kernelimage後面,放入boot.img。
dtc編譯在kernel/AndroidKernel.mk中定義。先用定義"DTS_NAMES"變數,它的每個entry(記為"DTS_NAME"變數,下面的$$arch)中可能有arch和rev兩部分,和.config中相關配置有關,用下面方法找出。
while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/;$$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/;$$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/} print $$arch;
得到上述"DTS_NAMES"變數,用"$(DTS_NAME)*.dts"方式去"kernel/arch/arm/boot/dts/"下匹配。見下面的定義,其中"cat"命令就是產生帶DT的kernelimage。
define append-dtbmkdir -p $(KERNEL_OUT)/arch/arm/boot;$(foreach DTS_NAME, $(DTS_NAMES), $(foreach d, $(DTS_FILES), $(DTC) -p 1024 -O dtb -o $(call DTB_FILE,$(d)) $(d); cat $(KERNEL_ZIMG) $(call DTB_FILE,$(d)) > $(call ZIMG_FILE,$(d));))endef
如,msm8974的MR2的ES1版中,"DTS_NAMES"變數的值為"msm8974 msmsamarium",會編入的檔案有。
msm8974pro-ab-cdp.dts msm8974pro-ac-mtp.dts msm8974-v1-mtp.dts msm8974-v2.0-1-fluid.dts msm8974-v2.2-fluid.dts msmsamarium-sim.dtsmsm8974pro-ab-fluid.dts msm8974-v1-cdp.dts msm8974-v1-rumi.dts msm8974-v2.0-1-liquid.dts msm8974-v2.2-liquid.dtsmsm8974pro-ab-liquid.dts msm8974-v1-fluid.dts msm8974-v1-sim.dts msm8974-v2.0-1-mtp.dts msm8974-v2.2-mtp.dtsmsm8974pro-ab-mtp.dts msm8974-v1-liquid.dts msm8974-v2.0-1-cdp.dts msm8974-v2.2-cdp.dts msmsamarium-rumi.dts
第二種方式沒看到後續如何放入boot.img。對於第一種方式,會用"device/qcom/common/generate_extra_images.mk"中定義的下面規則編出"dt.img",
$(INSTALLED_DTIMAGE_TARGET): $(DTBTOOL) $(INSTALLED_KERNEL_TARGET)$(build-dtimage-target)
在"build/core/Makefile"中用下面語句使它被編入boot.img。
ifeq ($(strip $(BOARD_KERNEL_SEPARATED_DT)),true) INTERNAL_BOOTIMAGE_ARGS += --dt $(INSTALLED_DTIMAGE_TARGET) BOOTIMAGE_EXTRA_DEPS := $(INSTALLED_DTIMAGE_TARGET)endif
lk中的處理
8974目前實際用的應該是方式1。在下面boot_linux_from_mmc()中,調用dev_tree_get_entry_info(),裡面會根據硬體(chipset和platform的id,系統實際跑時的資訊在系統boot的更早階段由N側設定並傳來,而DT中的資訊由根節點的"qcom,msm-id"屬性定義)來選擇合適的DT,後面會把該DT裝入記憶體,把地址等資訊傳給kernel(據說是通過CPU寄存器)。
qcom,msm-id = <126 8 0x20002>, <185 8 0x20002>, <186 8 0x20002>;
kmain() |bootstrap2() |arch_init() |platform_init() |target_init() |apps_init()//call init() of APPs defined using APP_START macro |aboot_init() |boot_linux_from_mmc() |//for device tree approach 1 |dev_tree_get_entry_info() |__dev_tree_get_entry_info() |memmove((void *)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size); |//for device tree approach 2 |dev_tree_appended() |boot_linux() |update_device_tree() |entry(0, machtype, (unsigned*)tags_phys);//pass control to kernel
kernel中的處理
在下面的setup_machine_fdt()中,會通過用各機器描述(machine description)的"dt_compat"屬性和傳入DT的根節點的"compatible"屬性進行匹配來選擇適當的machine description。會在下面board_dt_populate()處理中,會根據devicetree資訊建立裝置。
start_kernel() |setup_arch() |setup_machine_fdt()//select machine description according to DT infocustomize_machine()//called because it is an arch_initcall |msm8974_init() |board_dt_populate() |of_platform_bus_create() |of_platform_device_create_pdata() |of_device_alloc() |dev->dev.of_node = of_node_get(np);//pointer to data of struct device_node, that is device node in DT |of_platform_bus_create()//call it recursively to walk through the DT
上面of_device_alloc()時會在dev->dev.of_node中儲存對DT中裝置節點的引用。在驅動中,一般會增加下面用於裝置和驅動匹配的".of_match_table"資訊。
static struct of_device_id msm_otg_dt_match[] = {{.compatible = "qcom,hsusb-otg",},{}};static struct platform_driver msm_otg_driver = {.remove = __devexit_p(msm_otg_remove),.driver = {.......of_match_table = msm_otg_dt_match,},};
在kernel/drivers/base/platform.c的platform_match()中會調用下面處理來進行裝置和驅動的匹配。of_driver_match_device()中,一般會根據"compatible"屬性來匹配(如果設了name或type,則先根據name/type匹配)。
if (of_driver_match_device(dev, drv))return 1;
下面是裝置節點操作(一般是讀取)的一些API。
of_property_read_string()of_find_property()of_get_next_child()of_get_parent()
【轉】android MSM8974 上DeviceTree簡介----不錯