1c5648129SYanteng Si.. SPDX-License-Identifier: GPL-2.0
2c5648129SYanteng Si.. include:: ../disclaimer-zh_CN.rst
3c5648129SYanteng Si
4e13ce769SMauro Carvalho Chehab:Original: Documentation/devicetree/usage-model.rst
5c5648129SYanteng Si
6c5648129SYanteng Si:翻译:
7c5648129SYanteng Si
8c5648129SYanteng Si 司延腾 Yanteng Si <siyanteng@loongson.cn>
9c5648129SYanteng Si
10c5648129SYanteng Si:校译:
11c5648129SYanteng Si
12c5648129SYanteng Si
13c5648129SYanteng Si===================
14c5648129SYanteng SiLinux 和 Devicetree
15c5648129SYanteng Si===================
16c5648129SYanteng Si
17c5648129SYanteng SiLinux对设备树数据的使用模型
18c5648129SYanteng Si
19c5648129SYanteng Si:作者: Grant Likely <grant.likely@secretlab.ca>
20c5648129SYanteng Si
21c5648129SYanteng Si这篇文章描述了Linux如何使用设备树。关于设备树数据格式的概述可以在
22c5648129SYanteng Sidevicetree.org\ [1]_ 的设备树使用页面上找到。
23c5648129SYanteng Si
24c5648129SYanteng Si.. [1] https://www.devicetree.org/specifications/
25c5648129SYanteng Si
26c5648129SYanteng Si"Open Firmware Device Tree",或简称为Devicetree(DT),是一种用于描述硬
27c5648129SYanteng Si件的数据结构和语言。更确切地说,它是一种操作系统可读的硬件描述,这样操作系统就不
28c5648129SYanteng Si需要对机器的细节进行硬编码。
29c5648129SYanteng Si
30c5648129SYanteng Si从结构上看,DT是一棵树,或者说是带有命名节点的无环图,节点可以有任意数量的命名
31c5648129SYanteng Si属性来封装任意的数据。还存在一种机制,可以在自然的树状结构之外创建从一个节点到
32c5648129SYanteng Si另一个节点的任意链接。
33c5648129SYanteng Si
34c5648129SYanteng Si从概念上讲,一套通用的使用惯例,称为 "bindings"(后文译为绑定),被定义为数据
35c5648129SYanteng Si应该如何出现在树中,以描述典型的硬件特性,包括数据总线、中断线、GPIO连接和外围
36c5648129SYanteng Si设备。
37c5648129SYanteng Si
38c5648129SYanteng Si尽可能使用现有的绑定来描述硬件,以最大限度地利用现有的支持代码,但由于属性和节
39c5648129SYanteng Si点名称是简单的文本字符串,通过定义新的节点和属性来扩展现有的绑定或创建新的绑定
40c5648129SYanteng Si很容易。然而,要警惕的是,在创建一个新的绑定之前,最好先对已经存在的东西做一些
41c5648129SYanteng Si功课。目前有两种不同的、不兼容的i2c总线的绑定,这是因为在创建新的绑定时没有事先
42c5648129SYanteng Si调查i2c设备在现有系统中是如何被枚举的。
43c5648129SYanteng Si
44c5648129SYanteng Si1. 历史
45c5648129SYanteng Si-------
46c5648129SYanteng SiDT最初是由Open Firmware创建的,作为将数据从Open Firmware传递给客户程序
47c5648129SYanteng Si(如传递给操作系统)的通信方法的一部分。操作系统使用设备树在运行时探测硬件的拓
48c5648129SYanteng Si扑结构,从而在没有硬编码信息的情况下支持大多数可用的硬件(假设所有设备的驱动程
49c5648129SYanteng Si序都可用)。
50c5648129SYanteng Si
51c5648129SYanteng Si由于Open Firmware通常在PowerPC和SPARC平台上使用,长期以来,对这些架构的
52c5648129SYanteng SiLinux支持一直使用设备树。
53c5648129SYanteng Si
54c5648129SYanteng Si2005年,当PowerPC Linux开始大规模清理并合并32位和64位支持时,决定在所有
55c5648129SYanteng SiPowerpc平台上要求DT支持,无论它们是否使用Open Firmware。为了做到这一点,
56c5648129SYanteng Si我们创建了一个叫做扁平化设备树(FDT)的DT表示法,它可以作为一个二进制的blob
57c5648129SYanteng Si传递给内核,而不需要真正的Open Firmware实现。U-Boot、kexec和其他引导程序
58c5648129SYanteng Si被修改,以支持传递设备树二进制(dtb)和在引导时修改dtb。DT也被添加到PowerPC
59c5648129SYanteng Si引导包装器(arch/powerpc/boot/\*)中,这样dtb就可以被包裹在内核镜像中,以
60c5648129SYanteng Si支持引导现有的非DT察觉的固件。
61c5648129SYanteng Si
62c5648129SYanteng Si一段时间后,FDT基础架构被普及到了所有的架构中。在写这篇文章的时候,6个主线架
63c5648129SYanteng Si构(arm、microblaze、mips、powerpc、sparc和x86)和1个非主线架构(ios)
64c5648129SYanteng Si有某种程度的DT支持。
65c5648129SYanteng Si
66c5648129SYanteng Si1. 数据模型
67c5648129SYanteng Si-----------
68c5648129SYanteng Si如果你还没有读过设备树用法\ [1]_页,那么现在就去读吧。没关系,我等着....
69c5648129SYanteng Si
70c5648129SYanteng Si2.1 高层次视角
71c5648129SYanteng Si--------------
72c5648129SYanteng Si最重要的是要明白,DT只是一个描述硬件的数据结构。它没有什么神奇之处,也不会神
73c5648129SYanteng Si奇地让所有的硬件配置问题消失。它所做的是提供一种语言,将硬件配置与Linux内核
74c5648129SYanteng Si(或任何其他操作系统)中的板卡和设备驱动支持解耦。使用它可以使板卡和设备支持
75c5648129SYanteng Si变成数据驱动;根据传递到内核的数据做出设置决定,而不是根据每台机器的硬编码选
76c5648129SYanteng Si择。
77c5648129SYanteng Si
78c5648129SYanteng Si理想情况下,数据驱动的平台设置应该导致更少的代码重复,并使其更容易用一个内核
79c5648129SYanteng Si镜像支持各种硬件。
80c5648129SYanteng Si
81c5648129SYanteng SiLinux使用DT数据有三个主要目的:
82c5648129SYanteng Si
83c5648129SYanteng Si1) 平台识别。
84c5648129SYanteng Si2) 运行时配置,以及
85c5648129SYanteng Si3) 设备数量。
86c5648129SYanteng Si
87c5648129SYanteng Si2.2 平台识别
88c5648129SYanteng Si------------
89c5648129SYanteng Si首先,内核将使用DT中的数据来识别特定的机器。在一个理想的世界里,具体的平台对
90c5648129SYanteng Si内核来说并不重要,因为所有的平台细节都会被设备树以一致和可靠的方式完美描述。
91c5648129SYanteng Si但是,硬件并不完美,所以内核必须在早期启动时识别机器,以便有机会运行特定于机
92c5648129SYanteng Si器的修复程序。
93c5648129SYanteng Si
94c5648129SYanteng Si在大多数情况下,机器的身份是不相关的,而内核将根据机器的核心CPU或SoC来选择
95c5648129SYanteng Si设置代码。例如,在ARM上,arch/arm/kernel/setup.c中的setup_arch()将调
96c5648129SYanteng Siarch/arm/kernel/devtree.c中的setup_machine_fdt(),它通过
97c5648129SYanteng Simachine_desc表搜索并选择与设备树数据最匹配的machine_desc。它通过查看根
98c5648129SYanteng Si设备树节点中的'compatible'属性,并将其与struct machine_desc中的
99c5648129SYanteng Sidt_compat列表(如果你好奇,该列表定义在arch/arm/include/asm/mach/arch.h
100c5648129SYanteng Si中)进行比较,从而确定最佳匹配。
101c5648129SYanteng Si
102c5648129SYanteng Si“compatible” 属性包含一个排序的字符串列表,以机器的确切名称开始,后面是
103c5648129SYanteng Si一个可选的与之兼容的板子列表,从最兼容到最不兼容排序。例如,TI BeagleBoard
104c5648129SYanteng Si和它的后继者BeagleBoard xM板的根兼容属性可能看起来分别为::
105c5648129SYanteng Si
106c5648129SYanteng Si	compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3";
107c5648129SYanteng Si	compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
108c5648129SYanteng Si
109c5648129SYanteng Si其中 "ti,map3-beagleboard-xm "指定了确切的型号,它还声称它与OMAP 3450 SoC
110c5648129SYanteng Si以及一般的OMP3系列SoC兼容。你会注意到,该列表从最具体的(确切的板子)到最
111c5648129SYanteng Si不具体的(SoC系列)进行排序。
112c5648129SYanteng Si
113c5648129SYanteng Si聪明的读者可能会指出,Beagle xM也可以声称与原Beagle板兼容。然而,我们应
114c5648129SYanteng Si该当心在板级上这样做,因为通常情况下,即使在同一产品系列中,每块板都有很高
115c5648129SYanteng Si的变化,而且当一块板声称与另一块板兼容时,很难确定到底是什么意思。对于高层
116c5648129SYanteng Si来说,最好是谨慎行事,不要声称一块板子与另一块板子兼容。值得注意的例外是,
117c5648129SYanteng Si当一块板子是另一块板子的载体时,例如CPU模块连接到一个载体板上。
118c5648129SYanteng Si
119c5648129SYanteng Si关于兼容值还有一个注意事项。在兼容属性中使用的任何字符串都必须有文件说明它
120c5648129SYanteng Si表示什么。在Documentation/devicetree/bindings中添加兼容字符串的文档。
121c5648129SYanteng Si
122c5648129SYanteng Si同样在ARM上,对于每个machine_desc,内核会查看是否有任何dt_compat列表条
12389c30dd2SHuilong Deng目出现在兼容属性中。如果有,那么该machine_desc就是驱动该机器的候选者。在搜索
124c5648129SYanteng Si了整个machine_descs表之后,setup_machine_fdt()根据每个machine_desc
125c5648129SYanteng Si在兼容属性中匹配的条目,返回 “最兼容” 的machine_desc。如果没有找到匹配
126c5648129SYanteng Si的machine_desc,那么它将返回NULL。
127c5648129SYanteng Si
128c5648129SYanteng Si这个方案背后的原因是观察到,在大多数情况下,如果它们都使用相同的SoC或相同
12989c30dd2SHuilong Deng系列的SoC,一个machine_desc可以支持大量的电路板。然而,不可避免地会有一些例
130c5648129SYanteng Si外情况,即特定的板子需要特殊的设置代码,这在一般情况下是没有用的。特殊情况
131c5648129SYanteng Si可以通过在通用设置代码中明确检查有问题的板子来处理,但如果超过几个情况下,
132c5648129SYanteng Si这样做很快就会变得很难看和/或无法维护。
133c5648129SYanteng Si
13489c30dd2SHuilong Deng相反,兼容列表允许通用machine_desc通过在dt_compat列表中指定“不太兼容”的值
135c5648129SYanteng Si来提供对广泛的通用板的支持。在上面的例子中,通用板支持可以声称与“ti,ompa3”
136c5648129SYanteng Si或“ti,ompa3450”兼容。如果在最初的beagleboard上发现了一个bug,需要在
137c5648129SYanteng Si早期启动时使用特殊的变通代码,那么可以添加一个新的machine_desc,实现变通,
138c5648129SYanteng Si并且只在“ti,omap3-beagleboard”上匹配。
139c5648129SYanteng Si
14089c30dd2SHuilong DengPowerPC使用了一个稍微不同的方案,它从每个machine_desc中调用.probe()钩子,
141c5648129SYanteng Si并使用第一个返回TRUE的钩子。然而,这种方法没有考虑到兼容列表的优先级,对于
142c5648129SYanteng Si新的架构支持可能应该避免。
143c5648129SYanteng Si
144c5648129SYanteng Si2.3 运行时配置
145c5648129SYanteng Si--------------
146c5648129SYanteng Si在大多数情况下,DT是将数据从固件传递给内核的唯一方法,所以也被用来传递运行
147c5648129SYanteng Si时和配置数据,如内核参数字符串和initrd镜像的位置。
148c5648129SYanteng Si
149c5648129SYanteng Si这些数据大部分都包含在/chosen节点中,当启动Linux时,它看起来就像这样::
150c5648129SYanteng Si
151c5648129SYanteng Si	chosen {
152c5648129SYanteng Si		bootargs = "console=ttyS0,115200 loglevel=8";
153c5648129SYanteng Si		initrd-start = <0xc8000000>;
154c5648129SYanteng Si		initrd-end = <0xc8200000>;
155c5648129SYanteng Si	};
156c5648129SYanteng Si
157c5648129SYanteng Sibootargs属性包含内核参数,initrd-\*属性定义initrd blob的地址和大小。注
158c5648129SYanteng Si意initrd-end是initrd映像后的第一个地址,所以这与结构体资源的通常语义不一
159c5648129SYanteng Si致。选择的节点也可以选择包含任意数量的额外属性,用于平台特定的配置数据。
160c5648129SYanteng Si
161c5648129SYanteng Si在早期启动过程中,架构设置代码通过不同的辅助回调函数多次调用
162c5648129SYanteng Siof_scan_flat_dt()来解析设备树数据,然后进行分页设置。of_scan_flat_dt()
163c5648129SYanteng Si代码扫描设备树,并使用辅助函数来提取早期启动期间所需的信息。通常情况下,
164c5648129SYanteng Siearly_init_dt_scan_chosen()辅助函数用于解析所选节点,包括内核参数,
165c5648129SYanteng Siearly_init_dt_scan_root()用于初始化DT地址空间模型,early_init_dt_scan_memory()
166c5648129SYanteng Si用于确定可用RAM的大小和位置。
167c5648129SYanteng Si
168c5648129SYanteng Si在ARM上,函数setup_machine_fdt()负责在选择支持板子的正确machine_desc
169c5648129SYanteng Si后,对设备树进行早期扫描。
170c5648129SYanteng Si
171c5648129SYanteng Si2.4 设备数量
172c5648129SYanteng Si------------
173c5648129SYanteng Si在电路板被识别后,在早期配置数据被解析后,内核初始化可以以正常方式进行。在
174c5648129SYanteng Si这个过程中的某个时刻,unflatten_device_tree()被调用以将数据转换成更有
175c5648129SYanteng Si效的运行时表示。这也是调用机器特定设置钩子的时候,比如ARM上的machine_desc
176c5648129SYanteng Si.init_early()、.init_irq()和.init_machine()钩子。本节的其余部分使用
177c5648129SYanteng Si了ARM实现的例子,但所有架构在使用DT时都会做几乎相同的事情。
178c5648129SYanteng Si
179c5648129SYanteng Si从名称上可以猜到,.init_early()用于在启动过程早期需要执行的任何机器特定设
180c5648129SYanteng Si置,而.init_irq()则用于设置中断处理。使用DT并不会实质性地改变这两个函数的
181c5648129SYanteng Si行为。如果提供了DT,那么.init_early()和.init_irq()都能调用任何一个DT查
182c5648129SYanteng Si询函数(of_* in include/linux/of*.h),以获得关于平台的额外数据。
183c5648129SYanteng Si
184c5648129SYanteng SiDT上下文中最有趣的钩子是.init_machine(),它主要负责将平台的数据填充到
185c5648129SYanteng SiLinux设备模型中。历史上,这在嵌入式平台上是通过在板卡support .c文件中定
186c5648129SYanteng Si义一组静态时钟结构、platform_devices和其他数据,并在.init_machine()中
187c5648129SYanteng Si大量注册来实现的。当使用DT时,就不用为每个平台的静态设备进行硬编码,可以通过
188c5648129SYanteng Si解析DT获得设备列表,并动态分配设备结构体。
189c5648129SYanteng Si
190c5648129SYanteng Si最简单的情况是,.init_machine()只负责注册一个platform_devices。
191c5648129SYanteng Siplatform_device是Linux使用的一个概念,用于不能被硬件检测到的内存或I/O映
192c5648129SYanteng Si射的设备,以及“复合”或 “虚拟”设备(后面会详细介绍)。虽然DT没有“平台设备”的
193c5648129SYanteng Si术语,但平台设备大致对应于树根的设备节点和简单内存映射总线节点的子节点。
194c5648129SYanteng Si
195c5648129SYanteng Si现在是举例说明的好时机。下面是NVIDIA Tegra板的设备树的一部分::
196c5648129SYanteng Si
197c5648129SYanteng Si  /{
198c5648129SYanteng Si	compatible = "nvidia,harmony", "nvidia,tegra20";
199c5648129SYanteng Si	#address-cells = <1>;
200c5648129SYanteng Si	#size-cells = <1>;
201c5648129SYanteng Si	interrupt-parent = <&intc>;
202c5648129SYanteng Si
203c5648129SYanteng Si	chosen { };
204c5648129SYanteng Si	aliases { };
205c5648129SYanteng Si
206c5648129SYanteng Si	memory {
207c5648129SYanteng Si		device_type = "memory";
208c5648129SYanteng Si		reg = <0x00000000 0x40000000>;
209c5648129SYanteng Si	};
210c5648129SYanteng Si
211c5648129SYanteng Si	soc {
212c5648129SYanteng Si		compatible = "nvidia,tegra20-soc", "simple-bus";
213c5648129SYanteng Si		#address-cells = <1>;
214c5648129SYanteng Si		#size-cells = <1>;
215c5648129SYanteng Si		ranges;
216c5648129SYanteng Si
217c5648129SYanteng Si		intc: interrupt-controller@50041000 {
218c5648129SYanteng Si			compatible = "nvidia,tegra20-gic";
219c5648129SYanteng Si			interrupt-controller;
220c5648129SYanteng Si			#interrupt-cells = <1>;
221c5648129SYanteng Si			reg = <0x50041000 0x1000>, < 0x50040100 0x0100 >;
222c5648129SYanteng Si		};
223c5648129SYanteng Si
224c5648129SYanteng Si		serial@70006300 {
225c5648129SYanteng Si			compatible = "nvidia,tegra20-uart";
226c5648129SYanteng Si			reg = <0x70006300 0x100>;
227c5648129SYanteng Si			interrupts = <122>;
228c5648129SYanteng Si		};
229c5648129SYanteng Si
230c5648129SYanteng Si		i2s1: i2s@70002800 {
231c5648129SYanteng Si			compatible = "nvidia,tegra20-i2s";
232c5648129SYanteng Si			reg = <0x70002800 0x100>;
233c5648129SYanteng Si			interrupts = <77>;
234c5648129SYanteng Si			codec = <&wm8903>;
235c5648129SYanteng Si		};
236c5648129SYanteng Si
237c5648129SYanteng Si		i2c@7000c000 {
238c5648129SYanteng Si			compatible = "nvidia,tegra20-i2c";
239c5648129SYanteng Si			#address-cells = <1>;
240c5648129SYanteng Si			#size-cells = <0>;
241c5648129SYanteng Si			reg = <0x7000c000 0x100>;
242c5648129SYanteng Si			interrupts = <70>;
243c5648129SYanteng Si
244c5648129SYanteng Si			wm8903: codec@1a {
245c5648129SYanteng Si				compatible = "wlf,wm8903";
246c5648129SYanteng Si				reg = <0x1a>;
247c5648129SYanteng Si				interrupts = <347>;
248c5648129SYanteng Si			};
249c5648129SYanteng Si		};
250c5648129SYanteng Si	};
251c5648129SYanteng Si
252c5648129SYanteng Si	sound {
253c5648129SYanteng Si		compatible = "nvidia,harmony-sound";
254c5648129SYanteng Si		i2s-controller = <&i2s1>;
255c5648129SYanteng Si		i2s-codec = <&wm8903>;
256c5648129SYanteng Si	};
257c5648129SYanteng Si  };
258c5648129SYanteng Si
259c5648129SYanteng Si在.init_machine()时,Tegra板支持代码将需要查看这个DT,并决定为哪些节点
260c5648129SYanteng Si创建platform_devices。然而,看一下这个树,并不能立即看出每个节点代表什么
261c5648129SYanteng Si类型的设备,甚至不能看出一个节点是否代表一个设备。/chosen、/aliases和
262c5648129SYanteng Si/memory节点是信息节点,并不描述设备(尽管可以说内存可以被认为是一个设备)。
263c5648129SYanteng Si/soc节点的子节点是内存映射的设备,但是codec@1a是一个i2c设备,而sound节
264c5648129SYanteng Si点代表的不是一个设备,而是其他设备是如何连接在一起以创建音频子系统的。我知
265c5648129SYanteng Si道每个设备是什么,因为我熟悉电路板的设计,但是内核怎么知道每个节点该怎么做?
266c5648129SYanteng Si
267c5648129SYanteng Si诀窍在于,内核从树的根部开始,寻找具有“兼容”属性的节点。首先,一般认为任何
268c5648129SYanteng Si具有“兼容”属性的节点都代表某种设备;其次,可以认为树根的任何节点要么直接连
269c5648129SYanteng Si接到处理器总线上,要么是无法用其他方式描述的杂项系统设备。对于这些节点中的
270c5648129SYanteng Si每一个,Linux都会分配和注册一个platform_device,它又可能被绑定到一个
271c5648129SYanteng Siplatform_driver。
272c5648129SYanteng Si
273c5648129SYanteng Si为什么为这些节点使用platform_device是一个安全的假设?嗯,就Linux对设备
274c5648129SYanteng Si的建模方式而言,几乎所有的总线类型都假定其设备是总线控制器的孩子。例如,每
275c5648129SYanteng Si个i2c_client是i2c_master的一个子节点。每个spi_device都是SPI总线的一
276c5648129SYanteng Si个子节点。类似的还有USB、PCI、MDIO等。同样的层次结构也出现在DT中,I2C设
277c5648129SYanteng Si备节点只作为I2C总线节点的子节点出现。同理,SPI、MDIO、USB等等。唯一不需
278c5648129SYanteng Si要特定类型的父设备的设备是platform_devices(和amba_devices,但后面会
279c5648129SYanteng Si详细介绍),它们将愉快地运行在Linux/sys/devices树的底部。因此,如果一个
280c5648129SYanteng SiDT节点位于树的根部,那么它真的可能最好注册为platform_device。
281c5648129SYanteng Si
282c5648129SYanteng SiLinux板支持代码调用of_platform_populate(NULL, NULL, NULL, NULL)来
283c5648129SYanteng Si启动树根的设备发现。参数都是NULL,因为当从树的根部开始时,不需要提供一个起
284c5648129SYanteng Si始节点(第一个NULL),一个父结构设备(最后一个NULL),而且我们没有使用匹配
285c5648129SYanteng Si表(尚未)。对于只需要注册设备的板子,除了of_platform_populate()的调用,
286c5648129SYanteng Si.init_machine()可以完全为空。
287c5648129SYanteng Si
288c5648129SYanteng Si在Tegra的例子中,这说明了/soc和/sound节点,但是SoC节点的子节点呢?它们
289c5648129SYanteng Si不应该也被注册为平台设备吗?对于Linux DT支持,一般的行为是子设备在驱动
290c5648129SYanteng Si.probe()时被父设备驱动注册。因此,一个i2c总线设备驱动程序将为每个子节点
291c5648129SYanteng Si注册一个i2c_client,一个SPI总线驱动程序将注册其spi_device子节点,其他
292c5648129SYanteng Si总线类型也是如此。根据该模型,可以编写一个与SoC节点绑定的驱动程序,并简单
293c5648129SYanteng Si地为其每个子节点注册platform_device。板卡支持代码将分配和注册一个SoC设
294c5648129SYanteng Si备,一个(理论上的)SoC设备驱动程序可以绑定到SoC设备,并在其.probe()钩
295c5648129SYanteng Si中为/soc/interruptcontroller/soc/serial/soc/i2s/soc/i2c296c5648129SYanteng Si册platform_devices。很简单,对吗?
297c5648129SYanteng Si
298c5648129SYanteng Si实际上,事实证明,将一些platform_device的子设备注册为更多的platform_device
299c5648129SYanteng Si是一种常见的模式,设备树支持代码反映了这一点,并使上述例子更简单。
300c5648129SYanteng Siof_platform_populate()的第二个参数是一个of_device_id表,任何与该表
301c5648129SYanteng Si中的条目相匹配的节点也将获得其子节点的注册。在Tegra的例子中,代码可以是
302c5648129SYanteng Si这样的::
303c5648129SYanteng Si
304c5648129SYanteng Si  static void __init harmony_init_machine(void)
305c5648129SYanteng Si  {
306c5648129SYanteng Si	/* ... */
307c5648129SYanteng Si	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
308c5648129SYanteng Si  }
309c5648129SYanteng Si
310c5648129SYanteng Si“simple-bus”在Devicetree规范中被定义为一个属性,意味着一个简单的内存映射
311c5648129SYanteng Si的总线,所以of_platform_populate()代码可以被写成只是假设简单总线兼容的节
312c5648129SYanteng Si点将总是被遍历。然而,我们把它作为一个参数传入,以便电路板支持代码可以随时覆
313c5648129SYanteng Si盖默认行为。
314c5648129SYanteng Si
315c5648129SYanteng Si[需要添加关于添加i2c/spi/etc子设备的讨论] 。
316c5648129SYanteng Si
317c5648129SYanteng Si附录A:AMBA设备
318c5648129SYanteng Si---------------
319c5648129SYanteng Si
320c5648129SYanteng SiARM Primecell是连接到ARM AMBA总线的某种设备,它包括对硬件检测和电源管理
321c5648129SYanteng Si的一些支持。在Linux中,amba_device和amba_bus_type结构体被用来表示
322c5648129SYanteng SiPrimecell设备。然而,棘手的一点是,AMBA总线上的所有设备并非都是Primecell,
323c5648129SYanteng Si而且对于Linux来说,典型的情况是amba_device和platform_device实例都是同
324c5648129SYanteng Si一总线段的同义词。
325c5648129SYanteng Si
326c5648129SYanteng Si当使用DT时,这给of_platform_populate()带来了问题,因为它必须决定是否将
327c5648129SYanteng Si每个节点注册为platform_device或amba_device。不幸的是,这使设备创建模型
328*b0b4a63fSBaruch Siach变得有点复杂,但解决方案原来并不是太具有侵略性。如果一个节点与“arm,primecell”
329c5648129SYanteng Si兼容,那么of_platform_populate()将把它注册为amba_device而不是
330c5648129SYanteng Siplatform_device。
331