zoukankan      html  css  js  c++  java
  • android MSM8974 上DeviceTree简介

    简介

    主要功能是不在代码中硬编码设备信息,而是用专门的文件来描述。整个系统的设备节点会形成一个树,设备节点里可以设置属性。官网在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 {
    	android_usb@fe8050c8 {
    		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-dtb
    mkdir -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.dts
    msm8974pro-ab-fluid.dts   msm8974-v1-cdp.dts     msm8974-v1-rumi.dts     msm8974-v2.0-1-liquid.dts  msm8974-v2.2-liquid.dts
    msm8974pro-ab-liquid.dts  msm8974-v1-fluid.dts   msm8974-v1-sim.dts      msm8974-v2.0-1-mtp.dts     msm8974-v2.2-mtp.dts
    msm8974pro-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 info
    
    customize_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()
  • 相关阅读:
    Read-Copy Update Implementation For Non-Cache-Coherent Systems
    10 华电内部文档搜索系统 search04
    10 华电内部文档搜索系统 search05
    lucene4
    10 华电内部文档搜索系统 search01
    01 lucene基础 北风网项目培训 Lucene实践课程 索引
    01 lucene基础 北风网项目培训 Lucene实践课程 系统架构
    01 lucene基础 北风网项目培训 Lucene实践课程 Lucene概述
    第五章 大数据平台与技术 第13讲 NoSQL数据库
    第五章 大数据平台与技术 第12讲 大数据处理平台Spark
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298229.html
Copyright © 2011-2022 走看看