.. SPDX-License-Identifier: GPL-2.0 .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/devicetree/usage-model.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: =================== Linux å’Œ Devicetree =================== Linuxå¯¹è®¾å¤‡æ ‘æ•°æ®çš„使用模型 :作者: Grant Likely <grant.likely@secretlab.ca> è¿™ç¯‡æ–‡ç« æ述了Linuxå¦‚ä½•ä½¿ç”¨è®¾å¤‡æ ‘ã€‚å…³äºŽè®¾å¤‡æ ‘æ•°æ®æ ¼å¼çš„概述å¯ä»¥åœ¨ devicetree.org\ [1]_ çš„è®¾å¤‡æ ‘ä½¿ç”¨é¡µé¢ä¸Šæ‰¾åˆ°ã€‚ .. [1] https://www.devicetree.org/specifications/ "Open Firmware Device Tree",或简称为Devicetree(DT),是一ç§ç”¨äºŽæ述硬 件的数æ®ç»“æž„å’Œè¯è¨€ã€‚更确切地说,它是一ç§æ“作系统å¯è¯»çš„硬件æè¿°ï¼Œè¿™æ ·æ“ä½œç³»ç»Ÿå°±ä¸ éœ€è¦å¯¹æœºå™¨çš„细节进行硬编ç 。 从结构上看,DTæ˜¯ä¸€æ£µæ ‘ï¼Œæˆ–è€…è¯´æ˜¯å¸¦æœ‰å‘½åèŠ‚ç‚¹çš„æ— çŽ¯å›¾ï¼ŒèŠ‚ç‚¹å¯ä»¥æœ‰ä»»æ„æ•°é‡çš„命å 属性æ¥å°è£…ä»»æ„çš„æ•°æ®ã€‚还å˜åœ¨ä¸€ç§æœºåˆ¶ï¼Œå¯ä»¥åœ¨è‡ªç„¶çš„æ ‘çŠ¶ç»“æž„ä¹‹å¤–åˆ›å»ºä»Žä¸€ä¸ªèŠ‚ç‚¹åˆ° å¦ä¸€ä¸ªèŠ‚点的任æ„链接。 从概念上讲,一套通用的使用惯例,称为 "bindings"(åŽæ–‡è¯‘ä¸ºç»‘å®šï¼‰ï¼Œè¢«å®šä¹‰ä¸ºæ•°æ® åº”è¯¥å¦‚ä½•å‡ºçŽ°åœ¨æ ‘ä¸ï¼Œä»¥æ述典型的硬件特性,包括数æ®æ€»çº¿ã€ä¸æ–线ã€GPIO连接和外围 设备。 å°½å¯èƒ½ä½¿ç”¨çŽ°æœ‰çš„绑定æ¥æ述硬件,以最大é™åº¦åœ°åˆ©ç”¨çŽ°æœ‰çš„支æŒä»£ç ,但由于属性和节 点å称是简å•çš„文本å—符串,通过定义新的节点和属性æ¥æ‰©å±•çŽ°æœ‰çš„绑定或创建新的绑定 很容易。然而,è¦è¦æƒ•çš„是,在创建一个新的绑定之å‰ï¼Œæœ€å¥½å…ˆå¯¹å·²ç»å˜åœ¨çš„东西åšä¸€äº› 功课。目å‰æœ‰ä¸¤ç§ä¸åŒçš„ã€ä¸å…¼å®¹çš„i2cæ€»çº¿çš„ç»‘å®šï¼Œè¿™æ˜¯å› ä¸ºåœ¨åˆ›å»ºæ–°çš„ç»‘å®šæ—¶æ²¡æœ‰äº‹å…ˆ 调查i2c设备在现有系统ä¸æ˜¯å¦‚何被枚举的。 1. åŽ†å² ------- DT最åˆæ˜¯ç”±Open Firmware创建的,作为将数æ®ä»ŽOpen Firmwareä¼ é€’ç»™å®¢æˆ·ç¨‹åº ï¼ˆå¦‚ä¼ é€’ç»™æ“作系统)的通信方法的一部分。æ“ä½œç³»ç»Ÿä½¿ç”¨è®¾å¤‡æ ‘åœ¨è¿è¡Œæ—¶æŽ¢æµ‹ç¡¬ä»¶çš„æ‹“ 扑结构,从而在没有硬编ç ä¿¡æ¯çš„情况下支æŒå¤§å¤šæ•°å¯ç”¨çš„硬件(å‡è®¾æ‰€æœ‰è®¾å¤‡çš„驱动程 åºéƒ½å¯ç”¨ï¼‰ã€‚ 由于Open Firmware通常在PowerPCå’ŒSPARCå¹³å°ä¸Šä½¿ç”¨ï¼Œé•¿æœŸä»¥æ¥ï¼Œå¯¹è¿™äº›æž¶æž„çš„ Linux支æŒä¸€ç›´ä½¿ç”¨è®¾å¤‡æ ‘。 2005年,当PowerPC Linux开始大规模清ç†å¹¶åˆå¹¶32ä½å’Œ64ä½æ”¯æŒæ—¶ï¼Œå†³å®šåœ¨æ‰€æœ‰ Powerpcå¹³å°ä¸Šè¦æ±‚DT支æŒï¼Œæ— 论它们是å¦ä½¿ç”¨Open Firmware。为了åšåˆ°è¿™ä¸€ç‚¹ï¼Œ 我们创建了一个å«åšæ‰å¹³åŒ–è®¾å¤‡æ ‘ï¼ˆFDT)的DT表示法,它å¯ä»¥ä½œä¸ºä¸€ä¸ªäºŒè¿›åˆ¶çš„blob ä¼ é€’ç»™å†…æ ¸ï¼Œè€Œä¸éœ€è¦çœŸæ£çš„Open Firmware实现。U-Bootã€kexecå’Œå…¶ä»–å¼•å¯¼ç¨‹åº è¢«ä¿®æ”¹ï¼Œä»¥æ”¯æŒä¼ é€’è®¾å¤‡æ ‘äºŒè¿›åˆ¶ï¼ˆdtb)和在引导时修改dtb。DTä¹Ÿè¢«æ·»åŠ åˆ°PowerPC 引导包装器(arch/powerpc/boot/\*)ä¸ï¼Œè¿™æ ·dtbå°±å¯ä»¥è¢«åŒ…è£¹åœ¨å†…æ ¸é•œåƒä¸ï¼Œä»¥ 支æŒå¼•å¯¼çŽ°æœ‰çš„éžDT察觉的固件。 一段时间åŽï¼ŒFDT基础架构被普åŠåˆ°äº†æ‰€æœ‰çš„架构ä¸ã€‚åœ¨å†™è¿™ç¯‡æ–‡ç« çš„æ—¶å€™ï¼Œ6个主线架 构(armã€microblazeã€mipsã€powerpcã€sparcå’Œx86)和1个éžä¸»çº¿æž¶æž„(ios) 有æŸç§ç¨‹åº¦çš„DT支æŒã€‚ 1. æ•°æ®æ¨¡åž‹ ----------- å¦‚æžœä½ è¿˜æ²¡æœ‰è¯»è¿‡è®¾å¤‡æ ‘ç”¨æ³•\ [1]_页,那么现在就去读å§ã€‚没关系,我ç‰ç€.... 2.1 高层次视角 -------------- 最é‡è¦çš„是è¦æ˜Žç™½ï¼ŒDTåªæ˜¯ä¸€ä¸ªæ述硬件的数æ®ç»“构。它没有什么神奇之处,也ä¸ä¼šç¥ž 奇地让所有的硬件é…置问题消失。它所åšçš„是æ供一ç§è¯è¨€ï¼Œå°†ç¡¬ä»¶é…置与Linuxå†…æ ¸ (或任何其他æ“作系统)ä¸çš„æ¿å¡å’Œè®¾å¤‡é©±åŠ¨æ”¯æŒè§£è€¦ã€‚使用它å¯ä»¥ä½¿æ¿å¡å’Œè®¾å¤‡æ”¯æŒ å˜æˆæ•°æ®é©±åŠ¨ï¼›æ ¹æ®ä¼ é€’åˆ°å†…æ ¸çš„æ•°æ®åšå‡ºè®¾ç½®å†³å®šï¼Œè€Œä¸æ˜¯æ ¹æ®æ¯å°æœºå™¨çš„硬编ç 选 择。 ç†æƒ³æƒ…况下,数æ®é©±åŠ¨çš„å¹³å°è®¾ç½®åº”该导致更少的代ç é‡å¤ï¼Œå¹¶ä½¿å…¶æ›´å®¹æ˜“ç”¨ä¸€ä¸ªå†…æ ¸ é•œåƒæ”¯æŒå„ç§ç¡¬ä»¶ã€‚ Linux使用DTæ•°æ®æœ‰ä¸‰ä¸ªä¸»è¦ç›®çš„: 1) å¹³å°è¯†åˆ«ã€‚ 2) è¿è¡Œæ—¶é…ç½®ï¼Œä»¥åŠ 3) 设备数é‡ã€‚ 2.2 å¹³å°è¯†åˆ« ------------ é¦–å…ˆï¼Œå†…æ ¸å°†ä½¿ç”¨DTä¸çš„æ•°æ®æ¥è¯†åˆ«ç‰¹å®šçš„机器。在一个ç†æƒ³çš„世界里,具体的平å°å¯¹ å†…æ ¸æ¥è¯´å¹¶ä¸é‡è¦ï¼Œå› 为所有的平å°ç»†èŠ‚éƒ½ä¼šè¢«è®¾å¤‡æ ‘ä»¥ä¸€è‡´å’Œå¯é çš„æ–¹å¼å®Œç¾Žæ述。 但是,硬件并ä¸å®Œç¾Žï¼Œæ‰€ä»¥å†…æ ¸å¿…é¡»åœ¨æ—©æœŸå¯åŠ¨æ—¶è¯†åˆ«æœºå™¨ï¼Œä»¥ä¾¿æœ‰æœºä¼šè¿è¡Œç‰¹å®šäºŽæœº 器的修å¤ç¨‹åºã€‚ 在大多数情况下,机器的身份是ä¸ç›¸å…³çš„ï¼Œè€Œå†…æ ¸å°†æ ¹æ®æœºå™¨çš„æ ¸å¿ƒCPU或SoCæ¥é€‰æ‹© 设置代ç 。例如,在ARM上,arch/arm/kernel/setup.cä¸çš„setup_arch()将调 用arch/arm/kernel/devtree.cä¸çš„setup_machine_fdt(),它通过 machine_desc表æœç´¢å¹¶é€‰æ‹©ä¸Žè®¾å¤‡æ ‘æ•°æ®æœ€åŒ¹é…çš„machine_descã€‚å®ƒé€šè¿‡æŸ¥çœ‹æ ¹ è®¾å¤‡æ ‘èŠ‚ç‚¹ä¸çš„'compatible'属性,并将其与struct machine_descä¸çš„ dt_compatåˆ—è¡¨ï¼ˆå¦‚æžœä½ å¥½å¥‡ï¼Œè¯¥åˆ—è¡¨å®šä¹‰åœ¨arch/arm/include/asm/mach/arch.h ä¸ï¼‰è¿›è¡Œæ¯”较,从而确定最佳匹é…。 “compatible†属性包å«ä¸€ä¸ªæŽ’åºçš„å—符串列表,以机器的确切å称开始,åŽé¢æ˜¯ 一个å¯é€‰çš„与之兼容的æ¿å列表,从最兼容到最ä¸å…¼å®¹æŽ’åºã€‚例如,TI BeagleBoard 和它的åŽç»§è€…BeagleBoard xMæ¿çš„æ ¹å…¼å®¹å±žæ€§å¯èƒ½çœ‹èµ·æ¥åˆ†åˆ«ä¸º:: compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3"; compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3"; å…¶ä¸ "ti,map3-beagleboard-xm "指定了确切的型å·ï¼Œå®ƒè¿˜å£°ç§°å®ƒä¸ŽOMAP 3450 SoC 以åŠä¸€èˆ¬çš„OMP3系列SoCå…¼å®¹ã€‚ä½ ä¼šæ³¨æ„到,该列表从最具体的(确切的æ¿å)到最 ä¸å…·ä½“的(SoC系列)进行排åºã€‚ èªæ˜Žçš„读者å¯èƒ½ä¼šæŒ‡å‡ºï¼ŒBeagle xM也å¯ä»¥å£°ç§°ä¸ŽåŽŸBeagleæ¿å…¼å®¹ã€‚然而,我们应 该当心在æ¿çº§ä¸Šè¿™æ ·åšï¼Œå› 为通常情况下,å³ä½¿åœ¨åŒä¸€äº§å“系列ä¸ï¼Œæ¯å—æ¿éƒ½æœ‰å¾ˆé«˜ çš„å˜åŒ–,而且当一å—æ¿å£°ç§°ä¸Žå¦ä¸€å—æ¿å…¼å®¹æ—¶ï¼Œå¾ˆéš¾ç¡®å®šåˆ°åº•æ˜¯ä»€ä¹ˆæ„æ€ã€‚对于高层 æ¥è¯´ï¼Œæœ€å¥½æ˜¯è°¨æ…Žè¡Œäº‹ï¼Œä¸è¦å£°ç§°ä¸€å—æ¿å与å¦ä¸€å—æ¿å兼容。值得注æ„的例外是, 当一å—æ¿å是å¦ä¸€å—æ¿å的载体时,例如CPU模å—连接到一个载体æ¿ä¸Šã€‚ 关于兼容值还有一个注æ„事项。在兼容属性ä¸ä½¿ç”¨çš„任何å—符串都必须有文件说明它 表示什么。在Documentation/devicetree/bindingsä¸æ·»åŠ 兼容å—符串的文档。 åŒæ ·åœ¨ARM上,对于æ¯ä¸ªmachine_descï¼Œå†…æ ¸ä¼šæŸ¥çœ‹æ˜¯å¦æœ‰ä»»ä½•dt_compatåˆ—è¡¨æ¡ ç›®å‡ºçŽ°åœ¨å…¼å®¹å±žæ€§ä¸ã€‚如果有,那么该machine_desc就是驱动该机器的候选者。在æœç´¢ 了整个machine_descs表之åŽï¼Œsetup_machine_fdt()æ ¹æ®æ¯ä¸ªmachine_desc 在兼容属性ä¸åŒ¹é…çš„æ¡ç›®ï¼Œè¿”回 “最兼容†的machine_descã€‚å¦‚æžœæ²¡æœ‰æ‰¾åˆ°åŒ¹é… çš„machine_desc,那么它将返回NULL。 这个方案背åŽçš„åŽŸå› æ˜¯è§‚å¯Ÿåˆ°ï¼Œåœ¨å¤§å¤šæ•°æƒ…å†µä¸‹ï¼Œå¦‚æžœå®ƒä»¬éƒ½ä½¿ç”¨ç›¸åŒçš„SoCæˆ–ç›¸åŒ ç³»åˆ—çš„SoC,一个machine_descå¯ä»¥æ”¯æŒå¤§é‡çš„电路æ¿ã€‚然而,ä¸å¯é¿å…地会有一些例 外情况,å³ç‰¹å®šçš„æ¿å需è¦ç‰¹æ®Šçš„设置代ç ,这在一般情况下是没有用的。特殊情况 å¯ä»¥é€šè¿‡åœ¨é€šç”¨è®¾ç½®ä»£ç ä¸æ˜Žç¡®æ£€æŸ¥æœ‰é—®é¢˜çš„æ¿åæ¥å¤„ç†ï¼Œä½†å¦‚æžœè¶…è¿‡å‡ ä¸ªæƒ…å†µä¸‹ï¼Œ è¿™æ ·åšå¾ˆå¿«å°±ä¼šå˜å¾—很难看和/æˆ–æ— æ³•ç»´æŠ¤ã€‚ 相å,兼容列表å…许通用machine_desc通过在dt_compat列表ä¸æŒ‡å®šâ€œä¸å¤ªå…¼å®¹â€çš„值 æ¥æ供对广泛的通用æ¿çš„支æŒã€‚在上é¢çš„例åä¸ï¼Œé€šç”¨æ¿æ”¯æŒå¯ä»¥å£°ç§°ä¸Žâ€œti,ompa3†或“ti,ompa3450â€å…¼å®¹ã€‚如果在最åˆçš„beagleboard上å‘现了一个bug,需è¦åœ¨ 早期å¯åŠ¨æ—¶ä½¿ç”¨ç‰¹æ®Šçš„å˜é€šä»£ç ,那么å¯ä»¥æ·»åŠ 一个新的machine_desc,实现å˜é€šï¼Œ 并且åªåœ¨â€œti,omap3-beagleboardâ€ä¸ŠåŒ¹é…。 PowerPC使用了一个ç¨å¾®ä¸åŒçš„方案,它从æ¯ä¸ªmachine_descä¸è°ƒç”¨.probe()é’©å, 并使用第一个返回TRUEçš„é’©å。然而,这ç§æ–¹æ³•æ²¡æœ‰è€ƒè™‘到兼容列表的优先级,对于 新的架构支æŒå¯èƒ½åº”该é¿å…。 2.3 è¿è¡Œæ—¶é…ç½® -------------- 在大多数情况下,DT是将数æ®ä»Žå›ºä»¶ä¼ é€’ç»™å†…æ ¸çš„å”¯ä¸€æ–¹æ³•ï¼Œæ‰€ä»¥ä¹Ÿè¢«ç”¨æ¥ä¼ 递è¿è¡Œ 时和é…置数æ®ï¼Œå¦‚å†…æ ¸å‚æ•°å—符串和initrdé•œåƒçš„ä½ç½®ã€‚ 这些数æ®å¤§éƒ¨åˆ†éƒ½åŒ…å«åœ¨/chosen节点ä¸ï¼Œå½“å¯åŠ¨Linux时,它看起æ¥å°±åƒè¿™æ ·:: chosen { bootargs = "console=ttyS0,115200 loglevel=8"; initrd-start = <0xc8000000>; initrd-end = <0xc8200000>; }; bootargs属性包å«å†…æ ¸å‚数,initrd-\*属性定义initrd blob的地å€å’Œå¤§å°ã€‚注 æ„initrd-end是initrdæ˜ åƒåŽçš„第一个地å€ï¼Œæ‰€ä»¥è¿™ä¸Žç»“构体资æºçš„通常è¯ä¹‰ä¸ä¸€ 致。选择的节点也å¯ä»¥é€‰æ‹©åŒ…å«ä»»æ„æ•°é‡çš„é¢å¤–属性,用于平å°ç‰¹å®šçš„é…置数æ®ã€‚ 在早期å¯åŠ¨è¿‡ç¨‹ä¸ï¼Œæž¶æž„设置代ç 通过ä¸åŒçš„辅助回调函数多次调用 of_scan_flat_dt()æ¥è§£æžè®¾å¤‡æ ‘æ•°æ®ï¼Œç„¶åŽè¿›è¡Œåˆ†é¡µè®¾ç½®ã€‚of_scan_flat_dt() 代ç 扫æè®¾å¤‡æ ‘ï¼Œå¹¶ä½¿ç”¨è¾…åŠ©å‡½æ•°æ¥æå–早期å¯åŠ¨æœŸé—´æ‰€éœ€çš„ä¿¡æ¯ã€‚通常情况下, early_init_dt_scan_chosen()辅助函数用于解æžæ‰€é€‰èŠ‚ç‚¹ï¼ŒåŒ…æ‹¬å†…æ ¸å‚数, early_init_dt_scan_root()用于åˆå§‹åŒ–DT地å€ç©ºé—´æ¨¡åž‹ï¼Œearly_init_dt_scan_memory() 用于确定å¯ç”¨RAM的大å°å’Œä½ç½®ã€‚ 在ARM上,函数setup_machine_fdt()负责在选择支æŒæ¿åçš„æ£ç¡®machine_desc åŽï¼Œå¯¹è®¾å¤‡æ ‘进行早期扫æ。 2.4 è®¾å¤‡æ•°é‡ ------------ 在电路æ¿è¢«è¯†åˆ«åŽï¼Œåœ¨æ—©æœŸé…置数æ®è¢«è§£æžåŽï¼Œå†…æ ¸åˆå§‹åŒ–å¯ä»¥ä»¥æ£å¸¸æ–¹å¼è¿›è¡Œã€‚在 这个过程ä¸çš„æŸä¸ªæ—¶åˆ»ï¼Œunflatten_device_tree()被调用以将数æ®è½¬æ¢æˆæ›´æœ‰ 效的è¿è¡Œæ—¶è¡¨ç¤ºã€‚这也是调用机器特定设置钩å的时候,比如ARM上的machine_desc .init_early()ã€.init_irq()å’Œ.init_machine()é’©å。本节的其余部分使用 了ARM实现的例å,但所有架构在使用DT时都会åšå‡ 乎相åŒçš„事情。 从å称上å¯ä»¥çŒœåˆ°ï¼Œ.init_early()用于在å¯åŠ¨è¿‡ç¨‹æ—©æœŸéœ€è¦æ‰§è¡Œçš„任何机器特定设 置,而.init_irq()则用于设置ä¸æ–处ç†ã€‚使用DT并ä¸ä¼šå®žè´¨æ€§åœ°æ”¹å˜è¿™ä¸¤ä¸ªå‡½æ•°çš„ 行为。如果æ供了DT,那么.init_early()å’Œ.init_irq()都能调用任何一个DT查 询函数(of_* in include/linux/of*.h),以获得关于平å°çš„é¢å¤–æ•°æ®ã€‚ DT上下文ä¸æœ€æœ‰è¶£çš„é’©å是.init_machine(),它主è¦è´Ÿè´£å°†å¹³å°çš„æ•°æ®å¡«å……到 Linux设备模型ä¸ã€‚历å²ä¸Šï¼Œè¿™åœ¨åµŒå…¥å¼å¹³å°ä¸Šæ˜¯é€šè¿‡åœ¨æ¿å¡support .c文件ä¸å®š 义一组é™æ€æ—¶é’Ÿç»“æž„ã€platform_devices和其他数æ®ï¼Œå¹¶åœ¨.init_machine()ä¸ å¤§é‡æ³¨å†Œæ¥å®žçŽ°çš„。当使用DT时,就ä¸ç”¨ä¸ºæ¯ä¸ªå¹³å°çš„é™æ€è®¾å¤‡è¿›è¡Œç¡¬ç¼–ç ,å¯ä»¥é€šè¿‡ 解æžDT获得设备列表,并动æ€åˆ†é…设备结构体。 最简å•çš„情况是,.init_machine()åªè´Ÿè´£æ³¨å†Œä¸€ä¸ªplatform_devices。 platform_device是Linux使用的一个概念,用于ä¸èƒ½è¢«ç¡¬ä»¶æ£€æµ‹åˆ°çš„内å˜æˆ–I/Oæ˜ å°„çš„è®¾å¤‡ï¼Œä»¥åŠâ€œå¤åˆâ€æˆ– “虚拟â€è®¾å¤‡ï¼ˆåŽé¢ä¼šè¯¦ç»†ä»‹ç»ï¼‰ã€‚虽然DT没有“平å°è®¾å¤‡â€çš„ 术è¯ï¼Œä½†å¹³å°è®¾å¤‡å¤§è‡´å¯¹åº”äºŽæ ‘æ ¹çš„è®¾å¤‡èŠ‚ç‚¹å’Œç®€å•å†…å˜æ˜ 射总线节点的å节点。 现在是举例说明的好时机。下é¢æ˜¯NVIDIA Tegraæ¿çš„è®¾å¤‡æ ‘çš„ä¸€éƒ¨åˆ†:: /{ compatible = "nvidia,harmony", "nvidia,tegra20"; #address-cells = <1>; #size-cells = <1>; interrupt-parent = <&intc>; chosen { }; aliases { }; memory { device_type = "memory"; reg = <0x00000000 0x40000000>; }; soc { compatible = "nvidia,tegra20-soc", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges; intc: interrupt-controller@50041000 { compatible = "nvidia,tegra20-gic"; interrupt-controller; #interrupt-cells = <1>; reg = <0x50041000 0x1000>, < 0x50040100 0x0100 >; }; serial@70006300 { compatible = "nvidia,tegra20-uart"; reg = <0x70006300 0x100>; interrupts = <122>; }; i2s1: i2s@70002800 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x100>; interrupts = <77>; codec = <&wm8903>; }; i2c@7000c000 { compatible = "nvidia,tegra20-i2c"; #address-cells = <1>; #size-cells = <0>; reg = <0x7000c000 0x100>; interrupts = <70>; wm8903: codec@1a { compatible = "wlf,wm8903"; reg = <0x1a>; interrupts = <347>; }; }; }; sound { compatible = "nvidia,harmony-sound"; i2s-controller = <&i2s1>; i2s-codec = <&wm8903>; }; }; 在.init_machine()时,Tegraæ¿æ”¯æŒä»£ç 将需è¦æŸ¥çœ‹è¿™ä¸ªDT,并决定为哪些节点 创建platform_devicesã€‚ç„¶è€Œï¼Œçœ‹ä¸€ä¸‹è¿™ä¸ªæ ‘ï¼Œå¹¶ä¸èƒ½ç«‹å³çœ‹å‡ºæ¯ä¸ªèŠ‚点代表什么 类型的设备,甚至ä¸èƒ½çœ‹å‡ºä¸€ä¸ªèŠ‚点是å¦ä»£è¡¨ä¸€ä¸ªè®¾å¤‡ã€‚/chosenã€/aliaseså’Œ /memory节点是信æ¯èŠ‚点,并ä¸æ述设备(尽管å¯ä»¥è¯´å†…å˜å¯ä»¥è¢«è®¤ä¸ºæ˜¯ä¸€ä¸ªè®¾å¤‡ï¼‰ã€‚ /soc节点的å节点是内å˜æ˜ 射的设备,但是codec@1a是一个i2c设备,而sound节 点代表的ä¸æ˜¯ä¸€ä¸ªè®¾å¤‡ï¼Œè€Œæ˜¯å…¶ä»–设备是如何连接在一起以创建音频å系统的。我知 é“æ¯ä¸ªè®¾å¤‡æ˜¯ä»€ä¹ˆï¼Œå› 为我熟悉电路æ¿çš„è®¾è®¡ï¼Œä½†æ˜¯å†…æ ¸æ€Žä¹ˆçŸ¥é“æ¯ä¸ªèŠ‚点该怎么åšï¼Ÿ 诀çªåœ¨äºŽï¼Œå†…æ ¸ä»Žæ ‘çš„æ ¹éƒ¨å¼€å§‹ï¼Œå¯»æ‰¾å…·æœ‰â€œå…¼å®¹â€å±žæ€§çš„节点。首先,一般认为任何 具有“兼容â€å±žæ€§çš„节点都代表æŸç§è®¾å¤‡ï¼›å…¶æ¬¡ï¼Œå¯ä»¥è®¤ä¸ºæ ‘æ ¹çš„ä»»ä½•èŠ‚ç‚¹è¦ä¹ˆç›´æŽ¥è¿ž 接到处ç†å™¨æ€»çº¿ä¸Šï¼Œè¦ä¹ˆæ˜¯æ— 法用其他方å¼æè¿°çš„æ‚项系统设备。对于这些节点ä¸çš„ æ¯ä¸€ä¸ªï¼ŒLinux都会分é…和注册一个platform_device,它åˆå¯èƒ½è¢«ç»‘定到一个 platform_driver。 为什么为这些节点使用platform_device是一个安全的å‡è®¾ï¼Ÿå—¯ï¼Œå°±Linux对设备 的建模方å¼è€Œè¨€ï¼Œå‡ 乎所有的总线类型都å‡å®šå…¶è®¾å¤‡æ˜¯æ€»çº¿æŽ§åˆ¶å™¨çš„å©åã€‚ä¾‹å¦‚ï¼Œæ¯ ä¸ªi2c_client是i2c_master的一个å节点。æ¯ä¸ªspi_device都是SPI总线的一 个å节点。类似的还有USBã€PCIã€MDIOç‰ã€‚åŒæ ·çš„层次结构也出现在DTä¸ï¼ŒI2C设 备节点åªä½œä¸ºI2C总线节点的å节点出现。åŒç†ï¼ŒSPIã€MDIOã€USBç‰ç‰ã€‚唯一ä¸éœ€ è¦ç‰¹å®šç±»åž‹çš„父设备的设备是platform_devices(和amba_devices,但åŽé¢ä¼š 详细介ç»ï¼‰ï¼Œå®ƒä»¬å°†æ„‰å¿«åœ°è¿è¡Œåœ¨Linux/sys/devicesæ ‘çš„åº•éƒ¨ã€‚å› æ¤ï¼Œå¦‚果一个 DT节点ä½äºŽæ ‘çš„æ ¹éƒ¨ï¼Œé‚£ä¹ˆå®ƒçœŸçš„å¯èƒ½æœ€å¥½æ³¨å†Œä¸ºplatform_device。 Linuxæ¿æ”¯æŒä»£ç 调用of_platform_populate(NULL, NULL, NULL, NULL)æ¥ å¯åŠ¨æ ‘æ ¹çš„è®¾å¤‡å‘现。å‚数都是NULLï¼Œå› ä¸ºå½“ä»Žæ ‘çš„æ ¹éƒ¨å¼€å§‹æ—¶ï¼Œä¸éœ€è¦æ供一个起 始节点(第一个NULL),一个父结构设备(最åŽä¸€ä¸ªNULLï¼‰ï¼Œè€Œä¸”æˆ‘ä»¬æ²¡æœ‰ä½¿ç”¨åŒ¹é… è¡¨ï¼ˆå°šæœªï¼‰ã€‚å¯¹äºŽåªéœ€è¦æ³¨å†Œè®¾å¤‡çš„æ¿å,除了of_platform_populate()的调用, .init_machine()å¯ä»¥å®Œå…¨ä¸ºç©ºã€‚ 在Tegra的例åä¸ï¼Œè¿™è¯´æ˜Žäº†/socå’Œ/sound节点,但是SoC节点的å节点呢?它们 ä¸åº”该也被注册为平å°è®¾å¤‡å—?对于Linux DT支æŒï¼Œä¸€èˆ¬çš„行为是å设备在驱动 .probe()æ—¶è¢«çˆ¶è®¾å¤‡é©±åŠ¨æ³¨å†Œã€‚å› æ¤ï¼Œä¸€ä¸ªi2c总线设备驱动程åºå°†ä¸ºæ¯ä¸ªå节点 注册一个i2c_client,一个SPI总线驱动程åºå°†æ³¨å†Œå…¶spi_deviceå节点,其他 总线类型也是如æ¤ã€‚æ ¹æ®è¯¥æ¨¡åž‹ï¼Œå¯ä»¥ç¼–写一个与SoC节点绑定的驱动程åºï¼Œå¹¶ç®€å• 地为其æ¯ä¸ªå节点注册platform_device。æ¿å¡æ”¯æŒä»£ç 将分é…和注册一个SoC设 备,一个(ç†è®ºä¸Šçš„)SoC设备驱动程åºå¯ä»¥ç»‘定到SoC设备,并在其.probe()é’© ä¸ä¸º/soc/interruptcontrollerã€/soc/serialã€/soc/i2så’Œ/soc/i2c注 册platform_devices。很简å•ï¼Œå¯¹å—? 实际上,事实è¯æ˜Žï¼Œå°†ä¸€äº›platform_deviceçš„å设备注册为更多的platform_device 是一ç§å¸¸è§çš„模å¼ï¼Œè®¾å¤‡æ ‘支æŒä»£ç åæ˜ äº†è¿™ä¸€ç‚¹ï¼Œå¹¶ä½¿ä¸Šè¿°ä¾‹å更简å•ã€‚ of_platform_populate()的第二个å‚数是一个of_device_id表,任何与该表 ä¸çš„æ¡ç›®ç›¸åŒ¹é…的节点也将获得其å节点的注册。在Tegra的例åä¸ï¼Œä»£ç å¯ä»¥æ˜¯ è¿™æ ·çš„:: static void __init harmony_init_machine(void) { /* ... */ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } “simple-busâ€åœ¨Devicetree规范ä¸è¢«å®šä¹‰ä¸ºä¸€ä¸ªå±žæ€§ï¼Œæ„味ç€ä¸€ä¸ªç®€å•çš„内å˜æ˜ å°„ 的总线,所以of_platform_populate()代ç å¯ä»¥è¢«å†™æˆåªæ˜¯å‡è®¾ç®€å•æ€»çº¿å…¼å®¹çš„节 点将总是被é历。然而,我们把它作为一个å‚æ•°ä¼ å…¥ï¼Œä»¥ä¾¿ç”µè·¯æ¿æ”¯æŒä»£ç å¯ä»¥éšæ—¶è¦† 盖默认行为。 [需è¦æ·»åŠ å…³äºŽæ·»åŠ i2c/spi/etcå设备的讨论] 。 附录A:AMBA设备 --------------- ARM Primecell是连接到ARM AMBA总线的æŸç§è®¾å¤‡ï¼Œå®ƒåŒ…括对硬件检测和电æºç®¡ç† 的一些支æŒã€‚在Linuxä¸ï¼Œamba_deviceå’Œamba_bus_type结构体被用æ¥è¡¨ç¤º Primecell设备。然而,棘手的一点是,AMBA总线上的所有设备并éžéƒ½æ˜¯Primecell, 而且对于Linuxæ¥è¯´ï¼Œå…¸åž‹çš„情况是amba_deviceå’Œplatform_deviceå®žä¾‹éƒ½æ˜¯åŒ ä¸€æ€»çº¿æ®µçš„åŒä¹‰è¯ã€‚ 当使用DT时,这给of_platform_populate()带æ¥äº†é—®é¢˜ï¼Œå› 为它必须决定是å¦å°† æ¯ä¸ªèŠ‚点注册为platform_device或amba_device。ä¸å¹¸çš„是,这使设备创建模型 å˜å¾—有点å¤æ‚,但解决方案原æ¥å¹¶ä¸æ˜¯å¤ªå…·æœ‰ä¾µç•¥æ€§ã€‚如果一个节点与“arm,amba-primecell†兼容,那么of_platform_populate()将把它注册为amba_device而ä¸æ˜¯ platform_device。