设备注册Linux加载DTS设备节点的过程(以高通8974平台为例)

工作之余抽点时间出来写写博文,希望对新接触的朋友有帮助。今天在这里和大家一起学习一下设备注册

            DTS是Device Tree Source的缩写,用来描述设备的件硬细节。在去过的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充满着大批的渣滓代码,当相少数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是渣滓,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种件硬的platform_data。为了去失落这些渣滓代码,Linux用采DTS种这新的数据结构来描述件硬设备。用采Device Tree后,很多件硬的细节可以直接透过它传递给Linux,而不再需要在kernel中停止大批的余冗编码。

           有关DTS的语法格式,网上有很多资料,这里我就不再赘述了。本文主要讲Linux是怎样加载DTS设备点节的程流。上面以高通QCT8974平台(Linux内核)为例停止解讲:

    (1)用使DTS注册平台线总的程过

           在讲注册程过之前,我们先看看DTS是怎样描述平台线总结构的,以i2c线总为例:

    / { model = "Qualcomm MSM 8974"; compatible = "qcom,msm8974"; interrupt-parent = <&intc>; aliases { spi0 = &spi_0; spi7 = &spi_7; sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ sdhc3 = &sdhc_3; /* SDC3 SDIO slot */ sdhc4 = &sdhc_4; /* SDC4 SDIO slot */ }; memory { secure_mem: secure_region { linux,contiguous-region; reg = <0 0x7800000="">; label = "secure_mem"; }; adsp_mem: adsp_region { linux,contiguous-region; reg = <0 0x2000000="">; label = "adsp_mem"; }; }; intc: interrupt-controller@F9000000 { compatible = "qcom,msm-qgic2"; interrupt-controller; #interrupt-cells = <3>; reg = <0xf9000000 0x1000="">, <0xf9002000 0x1000="">; }; msmgpio: gpio@fd510000 { compatible = "qcom,msm-gpio"; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0xfd510000 0x4000="">; ngpio = <146>; interrupts = <0 208="" 0="">; qcom,direct-connect-irqs = <8>; }; wcd9xxx_intc: wcd9xxx-irq { compatible = "qcom,wcd9xxx-irq"; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&msmgpio>; interrupts = <72 0="">; interrupt-names = "cdc-int"; }; timer { compatible = "arm,armv7-timer"; interrupts = <1 2="" 0="" 1="" 3="" 0="">; clock-frequency = <19200000>; }; i2c_0: i2c@f9967000 { /* BLSP#11 */ cell-index = <0>; compatible = "qcom,i2c-qup"; reg = <0xf9967000 0x1000="">; #address-cells = <1>; #size-cells = <0>; reg-names = "qup_phys_addr"; interrupts = <0 105="" 0="">; interrupt-names = "qup_err_intr"; qcom,i2c-bus-freq = <100000>; qcom,i2c-src-freq = <50000000>; }; i2c_2: i2c@f9924000 { cell-index = <2>; compatible = "qcom,i2c-qup"; reg = <0xf9924000 0x1000="">; #address-cells = <1>; #size-cells = <0>; reg-names = "qup_phys_addr"; interrupts = <0 96="" 0="">; interrupt-names = "qup_err_intr"; qcom,i2c-bus-freq = <100000>; qcom,i2c-src-freq = <50000000>; }; spi_0: spi@f9923000 { compatible = "qcom,spi-qup-v2"; reg = <0xf9923000 0x1000="">; interrupts = <0 95="" 0="">; spi-max-frequency = <19200000>; #address-cells = <1>; #size-cells = <0>; gpios = <&msmgpio 3 0>, /* CLK */ <&msmgpio 1 0>, /* MISO */ <&msmgpio 0 0>; /* MOSI */ cs-gpios = <&msmgpio 9 0>; }; };

    每日一道理
水仙亭亭玉立,兰花典雅幽香,牡丹雍容华贵,梨花洁白无暇……美丽的花朵总能得到世人的羡慕与赞叹,殊不知,它从一粒小小的种子到最后开花,要历经无数的艰辛与坎坷!我们的成长也是如此。只有做辛勤的“织梦者”,我们的梦想才会成真!

    从面上可知,系统平台上挂载了很多线总,如i2c、spi、uart等等,个一每线总分别被描述为一个点节。Linux在启动后,到C口入时,会行执以下作操,加载系统平台上的线总和设备:

    start_kernel() --> setup_arch() --> unflatten_device_tree() 

    unflatten_device_tree()的代码如下:

    void __init unflatten_device_tree(void) { __unflatten_device_tree(initial_boot_params, &allnodes, early_init_dt_alloc_memory_arch); /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ of_alias_scan(early_init_dt_alloc_memory_arch); }

     在行执完unflatten_device_tree()后,DTS点节信息被剖析出来,保存到allnodes表链中,allnodes会在前面被用到。

    随后,当系统启动到board文件时,会调用.init_machine,高通8974平台对应的是msm8974_init()。接着调用of_platform_populate(....)口接,加载平台线总和平台设备。至此,系统平台上的有所已配置的线总和设备将被注册到系统中。注意:不是dtsi文件中有所的点节都会被注册,在注册线总和设备时,会对dts点节的态状作一个断判,如果点节里头的status属性没有被定义,或者status属性被定义了并且值被设为“ok”或者“okay”,其他况情则不被注册到系统中。

    

    (2)用使DTS注册线总设备的程过

           面上讲了Linux怎样用使DTS注册平台线总和平台设备到系统中,那么其他设备,例如i2c、spi设备是怎样注册到系统中的呢?上面我们就以i2c设备为例,解讲Linux怎样注册i2c设备到系统中。

     以高通8974平台为例,在注册i2c线总时,会调用到qup_i2c_probe()口接,该口接用于请求线总资源和添加i2c适配器。在胜利添加i2c适配器后,会调用of_i2c_register_devices()口接。此口接会剖析i2c线总点节的子点节(挂载在该线总上的i2c设备点节),取获i2c设备的址地、中断号等件硬信息。然后调用request_module()加载设备对应的动驱文件,调用i2c_new_device(),生成i2c设备。此时设备和动驱都已加载,于是drvier里头的probe方法将被调用。前面程流就和之前一样了。

    

           简而言之,Linux用采DTS描述设备件硬信息后,省去了大批板文件渣滓信息。Linux在开机启动阶段,会剖析DTS文件,保存到全局表链allnodes中,在失落用.init_machine时,会跟据allnodes中的信息注册平台线总和设备。值得注意的是,加载程流并非按找从根树到叶树的方法递归注册,而是只注册根点节下的第一级子点节,第二级及后之的子点节暂不注册。Linux系统下的设备大多都是挂载在平台线总下的,因此在平台线总被注册后,会根据allnodes点节的树结构,去找寻该线总的子点节,有所的子点节将被作为设备注册到该线总上。

    

文章结束给大家分享下程序员的一些笑话语录: 问路
有一个驾驶热气球的人发现他迷路了。他降低了飞行的高度,并认出了地面 上的一个人。他继续下降高度并对着那个人大叫,“打扰一下,你能告诉我我 在哪吗?”
下面那个人说:“是的。你在热气球里啊,盘旋在 30 英尺的空中”。
热气球上的人说:“你一定是在 IT 部门做技术工作”。
“没错”,地面上的人说到,“你是怎么知道的?”
“呵呵”,热气球上的人说,“你告诉我的每件事在技术上都是对的,但对都没 有用”。
地面上的人说,“你一定是管理层的人”。
“没错”,热气球上的人说,“可是你是怎么知道的?”
“呵呵”,地面上的那人说到,“你不知道你在哪里,你也不知道你要去哪,你 总希望我能帮你。你现在和我们刚见面时还在原来那个地方,但现在却是我 错了”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值