€•ËÎŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ*/translations/zh_CN/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ*/translations/zh_TW/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ*/translations/it_IT/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ*/translations/ja_JP/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ*/translations/ko_KR/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ*/translations/pt_BR/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ*/translations/sp_SP/devicetree/usage-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…””}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³ŒD/var/lib/git/docbuild/linux/Documentation/devicetree/usage-model.rst”h´KubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒLinux and the Devicetree”h]”hŒLinux and the Devicetree”…””}”(hhÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÊh²hh³hÇh´KubhŒ paragraph”“”)”}”(hŒ*The Linux usage model for device tree data”h]”hŒ*The Linux usage model for device tree data”…””}”(hhßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhŒ field_list”“”)”}”(hhh]”hŒfield”“”)”}”(hhh]”(hŒ field_name”“”)”}”(hŒAuthor”h]”hŒAuthor”…””}”(hhùh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h÷hhôh³hÇh´KubhŒ field_body”“”)”}”(hŒ)Grant Likely ”h]”hÞ)”}”(hŒ(Grant Likely ”h]”(hŒGrant Likely <”…””}”(hj h²hh³Nh´NubhŒ reference”“”)”}”(hŒgrant.likely@secretlab.ca”h]”hŒgrant.likely@secretlab.ca”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œ mailto:grant.likely@secretlab.ca”uh1jhj ubhŒ>”…””}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhôubeh}”(h]”h ]”h"]”h$]”h&]”uh1hòh³hÇh´K hhïh²hubah}”(h]”h ]”h"]”h$]”h&]”uh1híhhÊh²hh³hÇh´K ubhÞ)”}”(hŒ¦This article describes how Linux uses the device tree. An overview of the device tree data format can be found on the device tree usage page at devicetree.org\ [1]_.”h]”(hŒ¡This article describes how Linux uses the device tree. An overview of the device tree data format can be found on the device tree usage page at devicetree.org ”…””}”(hjCh²hh³Nh´NubhŒfootnote_reference”“”)”}”(hŒ[1]_”h]”hŒ1”…””}”(hjMh²hh³Nh´Nubah}”(h]”Œid1”ah ]”h"]”h$]”h&]”Œrefid”Œid2”Œdocname”Œdevicetree/usage-model”uh1jKhjCŒresolved”KubhŒ.”…””}”(hjCh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K hhÊh²hubhŒfootnote”“”)”}”(hŒ+https://www.devicetree.org/specifications/ ”h]”(hŒlabel”“”)”}”(hŒ1”h]”hŒ1”…””}”(hjsh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jqhjmubhÞ)”}”(hŒ*https://www.devicetree.org/specifications/”h]”j)”}”(hjƒh]”hŒ*https://www.devicetree.org/specifications/”…””}”(hj…h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”jƒuh1jhjubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Khjmubeh}”(h]”j]ah ]”h"]”Œ1”ah$]”h&]”(jWŒid3”ej^j_uh1jkh³hÇh´KhhÊh²hj`KubhÞ)”}”(hX The "Open Firmware Device Tree", or simply Devicetree (DT), is a data structure and language for describing hardware. More specifically, it is a description of hardware that is readable by an operating system so that the operating system doesn't need to hard code details of the machine.”h]”hX&The “Open Firmware Device Treeâ€, or simply Devicetree (DT), is a data structure and language for describing hardware. More specifically, it is a description of hardware that is readable by an operating system so that the operating system doesn’t need to hard code details of the machine.”…””}”(hj¡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hXStructurally, the DT is a tree, or acyclic graph with named nodes, and nodes may have an arbitrary number of named properties encapsulating arbitrary data. A mechanism also exists to create arbitrary links from one node to another outside of the natural tree structure.”h]”hXStructurally, the DT is a tree, or acyclic graph with named nodes, and nodes may have an arbitrary number of named properties encapsulating arbitrary data. A mechanism also exists to create arbitrary links from one node to another outside of the natural tree structure.”…””}”(hj¯h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hŒôConceptually, a common set of usage conventions, called 'bindings', is defined for how data should appear in the tree to describe typical hardware characteristics including data busses, interrupt lines, GPIO connections, and peripheral devices.”h]”hŒøConceptually, a common set of usage conventions, called ‘bindings’, is defined for how data should appear in the tree to describe typical hardware characteristics including data busses, interrupt lines, GPIO connections, and peripheral devices.”…””}”(hj½h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hXNAs much as possible, hardware is described using existing bindings to maximize use of existing support code, but since property and node names are simply text strings, it is easy to extend existing bindings or create new ones by defining new nodes and properties. Be wary, however, of creating a new binding without first doing some homework about what already exists. There are currently two different, incompatible, bindings for i2c busses that came about because the new binding was created without first investigating how i2c devices were already being enumerated in existing systems.”h]”hXNAs much as possible, hardware is described using existing bindings to maximize use of existing support code, but since property and node names are simply text strings, it is easy to extend existing bindings or create new ones by defining new nodes and properties. Be wary, however, of creating a new binding without first doing some homework about what already exists. There are currently two different, incompatible, bindings for i2c busses that came about because the new binding was created without first investigating how i2c devices were already being enumerated in existing systems.”…””}”(hjËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K!hhÊh²hubhÉ)”}”(hhh]”(hÎ)”}”(hŒ 1. History”h]”hŒ 1. History”…””}”(hjÜh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÙh²hh³hÇh´K,ubhÞ)”}”(hX‘The DT was originally created by Open Firmware as part of the communication method for passing data from Open Firmware to a client program (like to an operating system). An operating system used the Device Tree to discover the topology of the hardware at runtime, and thereby supported a majority of available hardware without hard coded information (assuming drivers were available for all devices).”h]”hX‘The DT was originally created by Open Firmware as part of the communication method for passing data from Open Firmware to a client program (like to an operating system). An operating system used the Device Tree to discover the topology of the hardware at runtime, and thereby supported a majority of available hardware without hard coded information (assuming drivers were available for all devices).”…””}”(hjêh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K-hjÙh²hubhÞ)”}”(hŒ˜Since Open Firmware is commonly used on PowerPC and SPARC platforms, the Linux support for those architectures has for a long time used the Device Tree.”h]”hŒ˜Since Open Firmware is commonly used on PowerPC and SPARC platforms, the Linux support for those architectures has for a long time used the Device Tree.”…””}”(hjøh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K4hjÙh²hubhÞ)”}”(hXÒIn 2005, when PowerPC Linux began a major cleanup and to merge 32-bit and 64-bit support, the decision was made to require DT support on all powerpc platforms, regardless of whether or not they used Open Firmware. To do this, a DT representation called the Flattened Device Tree (FDT) was created which could be passed to the kernel as a binary blob without requiring a real Open Firmware implementation. U-Boot, kexec, and other bootloaders were modified to support both passing a Device Tree Binary (dtb) and to modify a dtb at boot time. DT was also added to the PowerPC boot wrapper (``arch/powerpc/boot/*``) so that a dtb could be wrapped up with the kernel image to support booting existing non-DT aware firmware.”h]”(hXOIn 2005, when PowerPC Linux began a major cleanup and to merge 32-bit and 64-bit support, the decision was made to require DT support on all powerpc platforms, regardless of whether or not they used Open Firmware. To do this, a DT representation called the Flattened Device Tree (FDT) was created which could be passed to the kernel as a binary blob without requiring a real Open Firmware implementation. U-Boot, kexec, and other bootloaders were modified to support both passing a Device Tree Binary (dtb) and to modify a dtb at boot time. DT was also added to the PowerPC boot wrapper (”…””}”(hjh²hh³Nh´NubhŒliteral”“”)”}”(hŒ``arch/powerpc/boot/*``”h]”hŒarch/powerpc/boot/*”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒl) so that a dtb could be wrapped up with the kernel image to support booting existing non-DT aware firmware.”…””}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K8hjÙh²hubhÞ)”}”(hŒûSome time later, FDT infrastructure was generalized to be usable by all architectures. At the time of this writing, 6 mainlined architectures (arm, microblaze, mips, powerpc, sparc, and x86) and 1 out of mainline (nios) have some level of DT support.”h]”hŒûSome time later, FDT infrastructure was generalized to be usable by all architectures. At the time of this writing, 6 mainlined architectures (arm, microblaze, mips, powerpc, sparc, and x86) and 1 out of mainline (nios) have some level of DT support.”…””}”(hj(h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KDhjÙh²hubeh}”(h]”Œhistory”ah ]”h"]”Œ 1. history”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K,ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ 2. Data Model”h]”hŒ 2. Data Model”…””}”(hjAh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj>h²hh³hÇh´KJubhÞ)”}”(hŒlIf you haven't already read the Device Tree Usage\ [1]_ page, then go read it now. It's okay, I'll wait....”h]”(hŒ5If you haven’t already read the Device Tree Usage ”…””}”(hjOh²hh³Nh´NubjL)”}”(hŒ[1]_”h]”hŒ1”…””}”(hjWh²hh³Nh´Nubah}”(h]”j ah ]”h"]”h$]”h&]”j\j]j^j_uh1jKhjOj`KubhŒ9 page, then go read it now. It’s okay, I’ll wait....”…””}”(hjOh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KKhj>h²hubeh}”(h]”Œ data-model”ah ]”h"]”Œ 2. data model”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KJubhÉ)”}”(hhh]”(hÎ)”}”(hŒ2.1 High Level View”h]”hŒ2.1 High Level View”…””}”(hjzh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjwh²hh³hÇh´KOubhÞ)”}”(hXJThe most important thing to understand is that the DT is simply a data structure that describes the hardware. There is nothing magical about it, and it doesn't magically make all hardware configuration problems go away. What it does do is provide a language for decoupling the hardware configuration from the board and device driver support in the Linux kernel (or any other operating system for that matter). Using it allows board and device support to become data driven; to make setup decisions based on data passed into the kernel instead of on per-machine hard coded selections.”h]”hXLThe most important thing to understand is that the DT is simply a data structure that describes the hardware. There is nothing magical about it, and it doesn’t magically make all hardware configuration problems go away. What it does do is provide a language for decoupling the hardware configuration from the board and device driver support in the Linux kernel (or any other operating system for that matter). Using it allows board and device support to become data driven; to make setup decisions based on data passed into the kernel instead of on per-machine hard coded selections.”…””}”(hjˆh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KPhjwh²hubhÞ)”}”(hŒIdeally, data driven platform setup should result in less code duplication and make it easier to support a wide range of hardware with a single kernel image.”h]”hŒIdeally, data driven platform setup should result in less code duplication and make it easier to support a wide range of hardware with a single kernel image.”…””}”(hj–h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KZhjwh²hubhÞ)”}”(hŒ,Linux uses DT data for three major purposes:”h]”hŒ,Linux uses DT data for three major purposes:”…””}”(hj¤h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K^hjwh²hubhŒenumerated_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒplatform identification,”h]”hÞ)”}”(hj»h]”hŒplatform identification,”…””}”(hj½h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K`hj¹ubah}”(h]”h ]”h"]”h$]”h&]”uh1j·hj´h²hh³hÇh´Nubj¸)”}”(hŒruntime configuration, and”h]”hÞ)”}”(hjÒh]”hŒruntime configuration, and”…””}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KahjÐubah}”(h]”h ]”h"]”h$]”h&]”uh1j·hj´h²hh³hÇh´Nubj¸)”}”(hŒdevice population. ”h]”hÞ)”}”(hŒdevice population.”h]”hŒdevice population.”…””}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kbhjçubah}”(h]”h ]”h"]”h$]”h&]”uh1j·hj´h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ)”uh1j²hjwh²hh³hÇh´K`ubeh}”(h]”Œhigh-level-view”ah ]”h"]”Œ2.1 high level view”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KOubhÉ)”}”(hhh]”(hÎ)”}”(hŒ2.2 Platform Identification”h]”hŒ2.2 Platform Identification”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjh²hh³hÇh´KeubhÞ)”}”(hX±First and foremost, the kernel will use data in the DT to identify the specific machine. In a perfect world, the specific platform shouldn't matter to the kernel because all platform details would be described perfectly by the device tree in a consistent and reliable manner. Hardware is not perfect though, and so the kernel must identify the machine during early boot so that it has the opportunity to run machine-specific fixups.”h]”hX³First and foremost, the kernel will use data in the DT to identify the specific machine. In a perfect world, the specific platform shouldn’t matter to the kernel because all platform details would be described perfectly by the device tree in a consistent and reliable manner. Hardware is not perfect though, and so the kernel must identify the machine during early boot so that it has the opportunity to run machine-specific fixups.”…””}”(hj#h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kfhjh²hubhÞ)”}”(hXmIn the majority of cases, the machine identity is irrelevant, and the kernel will instead select setup code based on the machine's core CPU or SoC. On ARM for example, setup_arch() in arch/arm/kernel/setup.c will call setup_machine_fdt() in arch/arm/kernel/devtree.c which searches through the machine_desc table and selects the machine_desc which best matches the device tree data. It determines the best match by looking at the 'compatible' property in the root device tree node, and comparing it with the dt_compat list in struct machine_desc (which is defined in arch/arm/include/asm/mach/arch.h if you're curious).”h]”hXuIn the majority of cases, the machine identity is irrelevant, and the kernel will instead select setup code based on the machine’s core CPU or SoC. On ARM for example, setup_arch() in arch/arm/kernel/setup.c will call setup_machine_fdt() in arch/arm/kernel/devtree.c which searches through the machine_desc table and selects the machine_desc which best matches the device tree data. It determines the best match by looking at the ‘compatible’ property in the root device tree node, and comparing it with the dt_compat list in struct machine_desc (which is defined in arch/arm/include/asm/mach/arch.h if you’re curious).”…””}”(hj1h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Knhjh²hubhÞ)”}”(hX[The 'compatible' property contains a sorted list of strings starting with the exact name of the machine, followed by an optional list of boards it is compatible with sorted from most compatible to least. For example, the root compatible properties for the TI BeagleBoard and its successor, the BeagleBoard xM board might look like, respectively::”h]”hX^The ‘compatible’ property contains a sorted list of strings starting with the exact name of the machine, followed by an optional list of boards it is compatible with sorted from most compatible to least. For example, the root compatible properties for the TI BeagleBoard and its successor, the BeagleBoard xM board might look like, respectively:”…””}”(hj?h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kyhjh²hubhŒ literal_block”“”)”}”(hŒ‚compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3"; compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";”h]”hŒ‚compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3"; compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";”…””}”hjOsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jMh³hÇh´Khjh²hubhÞ)”}”(hXWhere "ti,omap3-beagleboard-xm" specifies the exact model, it also claims that it is compatible with the OMAP 3450 SoC, and the omap3 family of SoCs in general. You'll notice that the list is sorted from most specific (exact board) to least specific (SoC family).”h]”hXWhere “ti,omap3-beagleboard-xm†specifies the exact model, it also claims that it is compatible with the OMAP 3450 SoC, and the omap3 family of SoCs in general. You’ll notice that the list is sorted from most specific (exact board) to least specific (SoC family).”…””}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K‚hjh²hubhÞ)”}”(hXwAstute readers might point out that the Beagle xM could also claim compatibility with the original Beagle board. However, one should be cautioned about doing so at the board level since there is typically a high level of change from one board to another, even within the same product line, and it is hard to nail down exactly what is meant when one board claims to be compatible with another. For the top level, it is better to err on the side of caution and not claim one board is compatible with another. The notable exception would be when one board is a carrier for another, such as a CPU module attached to a carrier board.”h]”hXwAstute readers might point out that the Beagle xM could also claim compatibility with the original Beagle board. However, one should be cautioned about doing so at the board level since there is typically a high level of change from one board to another, even within the same product line, and it is hard to nail down exactly what is meant when one board claims to be compatible with another. For the top level, it is better to err on the side of caution and not claim one board is compatible with another. The notable exception would be when one board is a carrier for another, such as a CPU module attached to a carrier board.”…””}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K‡hjh²hubhÞ)”}”(hŒÉOne more note on compatible values. Any string used in a compatible property must be documented as to what it indicates. Add documentation for compatible strings in Documentation/devicetree/bindings.”h]”hŒÉOne more note on compatible values. Any string used in a compatible property must be documented as to what it indicates. Add documentation for compatible strings in Documentation/devicetree/bindings.”…””}”(hjyh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K’hjh²hubhÞ)”}”(hXÓAgain on ARM, for each machine_desc, the kernel looks to see if any of the dt_compat list entries appear in the compatible property. If one does, then that machine_desc is a candidate for driving the machine. After searching the entire table of machine_descs, setup_machine_fdt() returns the 'most compatible' machine_desc based on which entry in the compatible property each machine_desc matches against. If no matching machine_desc is found, then it returns NULL.”h]”hX×Again on ARM, for each machine_desc, the kernel looks to see if any of the dt_compat list entries appear in the compatible property. If one does, then that machine_desc is a candidate for driving the machine. After searching the entire table of machine_descs, setup_machine_fdt() returns the ‘most compatible’ machine_desc based on which entry in the compatible property each machine_desc matches against. If no matching machine_desc is found, then it returns NULL.”…””}”(hj‡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K–hjh²hubhÞ)”}”(hX'The reasoning behind this scheme is the observation that in the majority of cases, a single machine_desc can support a large number of boards if they all use the same SoC, or same family of SoCs. However, invariably there will be some exceptions where a specific board will require special setup code that is not useful in the generic case. Special cases could be handled by explicitly checking for the troublesome board(s) in generic setup code, but doing so very quickly becomes ugly and/or unmaintainable if it is more than just a couple of cases.”h]”hX'The reasoning behind this scheme is the observation that in the majority of cases, a single machine_desc can support a large number of boards if they all use the same SoC, or same family of SoCs. However, invariably there will be some exceptions where a specific board will require special setup code that is not useful in the generic case. Special cases could be handled by explicitly checking for the troublesome board(s) in generic setup code, but doing so very quickly becomes ugly and/or unmaintainable if it is more than just a couple of cases.”…””}”(hj•h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kžhjh²hubhÞ)”}”(hXôInstead, the compatible list allows a generic machine_desc to provide support for a wide common set of boards by specifying "less compatible" values in the dt_compat list. In the example above, generic board support can claim compatibility with "ti,omap3" or "ti,omap3450". If a bug was discovered on the original beagleboard that required special workaround code during early boot, then a new machine_desc could be added which implements the workarounds and only matches on "ti,omap3-beagleboard".”h]”hXInstead, the compatible list allows a generic machine_desc to provide support for a wide common set of boards by specifying “less compatible†values in the dt_compat list. In the example above, generic board support can claim compatibility with “ti,omap3†or “ti,omap3450â€. If a bug was discovered on the original beagleboard that required special workaround code during early boot, then a new machine_desc could be added which implements the workarounds and only matches on “ti,omap3-beagleboardâ€.”…””}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K¨hjh²hubhÞ)”}”(hXPowerPC uses a slightly different scheme where it calls the .probe() hook from each machine_desc, and the first one returning TRUE is used. However, this approach does not take into account the priority of the compatible list, and probably should be avoided for new architecture support.”h]”hXPowerPC uses a slightly different scheme where it calls the .probe() hook from each machine_desc, and the first one returning TRUE is used. However, this approach does not take into account the priority of the compatible list, and probably should be avoided for new architecture support.”…””}”(hj±h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K±hjh²hubeh}”(h]”Œplatform-identification”ah ]”h"]”Œ2.2 platform identification”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KeubhÉ)”}”(hhh]”(hÎ)”}”(hŒ2.3 Runtime configuration”h]”hŒ2.3 Runtime configuration”…””}”(hjÊh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÇh²hh³hÇh´K¸ubhÞ)”}”(hŒáIn most cases, a DT will be the sole method of communicating data from firmware to the kernel, so also gets used to pass in runtime and configuration data like the kernel parameters string and the location of an initrd image.”h]”hŒáIn most cases, a DT will be the sole method of communicating data from firmware to the kernel, so also gets used to pass in runtime and configuration data like the kernel parameters string and the location of an initrd image.”…””}”(hjØh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K¹hjÇh²hubhÞ)”}”(hŒmMost of this data is contained in the /chosen node, and when booting Linux it will look something like this::”h]”hŒlMost of this data is contained in the /chosen node, and when booting Linux it will look something like this:”…””}”(hjæh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K¾hjÇh²hubjN)”}”(hŒ‰chosen { bootargs = "console=ttyS0,115200 loglevel=8"; initrd-start = <0xc8000000>; initrd-end = <0xc8200000>; };”h]”hŒ‰chosen { bootargs = "console=ttyS0,115200 loglevel=8"; initrd-start = <0xc8000000>; initrd-end = <0xc8200000>; };”…””}”hjôsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jMh³hÇh´KÁhjÇh²hubhÞ)”}”(hXƒThe bootargs property contains the kernel arguments, and the initrd-* properties define the address and size of an initrd blob. Note that initrd-end is the first address after the initrd image, so this doesn't match the usual semantic of struct resource. The chosen node may also optionally contain an arbitrary number of additional properties for platform-specific configuration data.”h]”hX…The bootargs property contains the kernel arguments, and the initrd-* properties define the address and size of an initrd blob. Note that initrd-end is the first address after the initrd image, so this doesn’t match the usual semantic of struct resource. The chosen node may also optionally contain an arbitrary number of additional properties for platform-specific configuration data.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KÇhjÇh²hubhÞ)”}”(hX/During early boot, the architecture setup code calls of_scan_flat_dt() several times with different helper callbacks to parse device tree data before paging is set up. The of_scan_flat_dt() code scans through the device tree and uses the helpers to extract information required during early boot. Typically the early_init_dt_scan_chosen() helper is used to parse the chosen node including kernel parameters, early_init_dt_scan_root() to initialize the DT address space model, and early_init_dt_scan_memory() to determine the size and location of usable RAM.”h]”hX/During early boot, the architecture setup code calls of_scan_flat_dt() several times with different helper callbacks to parse device tree data before paging is set up. The of_scan_flat_dt() code scans through the device tree and uses the helpers to extract information required during early boot. Typically the early_init_dt_scan_chosen() helper is used to parse the chosen node including kernel parameters, early_init_dt_scan_root() to initialize the DT address space model, and early_init_dt_scan_memory() to determine the size and location of usable RAM.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KÎhjÇh²hubhÞ)”}”(hŒŸOn ARM, the function setup_machine_fdt() is responsible for early scanning of the device tree after selecting the correct machine_desc that supports the board.”h]”hŒŸOn ARM, the function setup_machine_fdt() is responsible for early scanning of the device tree after selecting the correct machine_desc that supports the board.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KØhjÇh²hubeh}”(h]”Œruntime-configuration”ah ]”h"]”Œ2.3 runtime configuration”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K¸ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ2.4 Device population”h]”hŒ2.4 Device population”…””}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj4h²hh³hÇh´KÝubhÞ)”}”(hXAAfter the board has been identified, and after the early configuration data has been parsed, then kernel initialization can proceed in the normal way. At some point in this process, unflatten_device_tree() is called to convert the data into a more efficient runtime representation. This is also when machine-specific setup hooks will get called, like the machine_desc .init_early(), .init_irq() and .init_machine() hooks on ARM. The remainder of this section uses examples from the ARM implementation, but all architectures will do pretty much the same thing when using a DT.”h]”hXAAfter the board has been identified, and after the early configuration data has been parsed, then kernel initialization can proceed in the normal way. At some point in this process, unflatten_device_tree() is called to convert the data into a more efficient runtime representation. This is also when machine-specific setup hooks will get called, like the machine_desc .init_early(), .init_irq() and .init_machine() hooks on ARM. The remainder of this section uses examples from the ARM implementation, but all architectures will do pretty much the same thing when using a DT.”…””}”(hjEh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KÞhj4h²hubhÞ)”}”(hXÇAs can be guessed by the names, .init_early() is used for any machine- specific setup that needs to be executed early in the boot process, and .init_irq() is used to set up interrupt handling. Using a DT doesn't materially change the behaviour of either of these functions. If a DT is provided, then both .init_early() and .init_irq() are able to call any of the DT query functions (of_* in include/linux/of*.h) to get additional data about the platform.”h]”hXÉAs can be guessed by the names, .init_early() is used for any machine- specific setup that needs to be executed early in the boot process, and .init_irq() is used to set up interrupt handling. Using a DT doesn’t materially change the behaviour of either of these functions. If a DT is provided, then both .init_early() and .init_irq() are able to call any of the DT query functions (of_* in include/linux/of*.h) to get additional data about the platform.”…””}”(hjSh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kèhj4h²hubhÞ)”}”(hX1The most interesting hook in the DT context is .init_machine() which is primarily responsible for populating the Linux device model with data about the platform. Historically this has been implemented on embedded platforms by defining a set of static clock structures, platform_devices, and other data in the board support .c file, and registering it en-masse in .init_machine(). When DT is used, then instead of hard coding static devices for each platform, the list of devices can be obtained by parsing the DT, and allocating device structures dynamically.”h]”hX1The most interesting hook in the DT context is .init_machine() which is primarily responsible for populating the Linux device model with data about the platform. Historically this has been implemented on embedded platforms by defining a set of static clock structures, platform_devices, and other data in the board support .c file, and registering it en-masse in .init_machine(). When DT is used, then instead of hard coding static devices for each platform, the list of devices can be obtained by parsing the DT, and allocating device structures dynamically.”…””}”(hjah²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kðhj4h²hubhÞ)”}”(hXØThe simplest case is when .init_machine() is only responsible for registering a block of platform_devices. A platform_device is a concept used by Linux for memory or I/O mapped devices which cannot be detected by hardware, and for 'composite' or 'virtual' devices (more on those later). While there is no 'platform device' terminology for the DT, platform devices roughly correspond to device nodes at the root of the tree and children of simple memory mapped bus nodes.”h]”hXäThe simplest case is when .init_machine() is only responsible for registering a block of platform_devices. A platform_device is a concept used by Linux for memory or I/O mapped devices which cannot be detected by hardware, and for ‘composite’ or ‘virtual’ devices (more on those later). While there is no ‘platform device’ terminology for the DT, platform devices roughly correspond to device nodes at the root of the tree and children of simple memory mapped bus nodes.”…””}”(hjoh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kúhj4h²hubhÞ)”}”(hŒmAbout now is a good time to lay out an example. Here is part of the device tree for the NVIDIA Tegra board::”h]”hŒlAbout now is a good time to lay out an example. Here is part of the device tree for the NVIDIA Tegra board:”…””}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Mhj4h²hubjN)”}”(hX4/{ 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>; }; };”h]”hX4/{ 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>; }; };”…””}”hj‹sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jMh³hÇh´Mhj4h²hubhÞ)”}”(hX At .init_machine() time, Tegra board support code will need to look at this DT and decide which nodes to create platform_devices for. However, looking at the tree, it is not immediately obvious what kind of device each node represents, or even if a node represents a device at all. The /chosen, /aliases, and /memory nodes are informational nodes that don't describe devices (although arguably memory could be considered a device). The children of the /soc node are memory mapped devices, but the codec@1a is an i2c device, and the sound node represents not a device, but rather how other devices are connected together to create the audio subsystem. I know what each device is because I'm familiar with the board design, but how does the kernel know what to do with each node?”h]”(hXõAt .init_machine() time, Tegra board support code will need to look at this DT and decide which nodes to create platform_devices for. However, looking at the tree, it is not immediately obvious what kind of device each node represents, or even if a node represents a device at all. The /chosen, /aliases, and /memory nodes are informational nodes that don’t describe devices (although arguably memory could be considered a device). The children of the /soc node are memory mapped devices, but the ”…””}”(hj™h²hh³Nh´Nubj)”}”(hŒcodec@1a”h]”hŒcodec@1a”…””}”(hj¡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œmailto:codec@1a”uh1jhj™ubhX is an i2c device, and the sound node represents not a device, but rather how other devices are connected together to create the audio subsystem. I know what each device is because I’m familiar with the board design, but how does the kernel know what to do with each node?”…””}”(hj™h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´MChj4h²hubhÞ)”}”(hXThe trick is that the kernel starts at the root of the tree and looks for nodes that have a 'compatible' property. First, it is generally assumed that any node with a 'compatible' property represents a device of some kind, and second, it can be assumed that any node at the root of the tree is either directly attached to the processor bus, or is a miscellaneous system device that cannot be described any other way. For each of these nodes, Linux allocates and registers a platform_device, which in turn may get bound to a platform_driver.”h]”hX%The trick is that the kernel starts at the root of the tree and looks for nodes that have a ‘compatible’ property. First, it is generally assumed that any node with a ‘compatible’ property represents a device of some kind, and second, it can be assumed that any node at the root of the tree is either directly attached to the processor bus, or is a miscellaneous system device that cannot be described any other way. For each of these nodes, Linux allocates and registers a platform_device, which in turn may get bound to a platform_driver.”…””}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´MPhj4h²hubhÞ)”}”(hX#Why is using a platform_device for these nodes a safe assumption? Well, for the way that Linux models devices, just about all bus_types assume that its devices are children of a bus controller. For example, each i2c_client is a child of an i2c_master. Each spi_device is a child of an SPI bus. Similarly for USB, PCI, MDIO, etc. The same hierarchy is also found in the DT, where I2C device nodes only ever appear as children of an I2C bus node. Ditto for SPI, MDIO, USB, etc. The only devices which do not require a specific type of parent device are platform_devices (and amba_devices, but more on that later), which will happily live at the base of the Linux /sys/devices tree. Therefore, if a DT node is at the root of the tree, then it really probably is best registered as a platform_device.”h]”hX#Why is using a platform_device for these nodes a safe assumption? Well, for the way that Linux models devices, just about all bus_types assume that its devices are children of a bus controller. For example, each i2c_client is a child of an i2c_master. Each spi_device is a child of an SPI bus. Similarly for USB, PCI, MDIO, etc. The same hierarchy is also found in the DT, where I2C device nodes only ever appear as children of an I2C bus node. Ditto for SPI, MDIO, USB, etc. The only devices which do not require a specific type of parent device are platform_devices (and amba_devices, but more on that later), which will happily live at the base of the Linux /sys/devices tree. Therefore, if a DT node is at the root of the tree, then it really probably is best registered as a platform_device.”…””}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´MYhj4h²hubhÞ)”}”(hXèLinux board support code calls of_platform_populate(NULL, NULL, NULL, NULL) to kick off discovery of devices at the root of the tree. The parameters are all NULL because when starting from the root of the tree, there is no need to provide a starting node (the first NULL), a parent struct device (the last NULL), and we're not using a match table (yet). For a board that only needs to register devices, .init_machine() can be completely empty except for the of_platform_populate() call.”h]”hXêLinux board support code calls of_platform_populate(NULL, NULL, NULL, NULL) to kick off discovery of devices at the root of the tree. The parameters are all NULL because when starting from the root of the tree, there is no need to provide a starting node (the first NULL), a parent struct device (the last NULL), and we’re not using a match table (yet). For a board that only needs to register devices, .init_machine() can be completely empty except for the of_platform_populate() call.”…””}”(hj×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Mfhj4h²hubhÞ)”}”(hXpIn the Tegra example, this accounts for the /soc and /sound nodes, but what about the children of the SoC node? Shouldn't they be registered as platform devices too? For Linux DT support, the generic behaviour is for child devices to be registered by the parent's device driver at driver .probe() time. So, an i2c bus device driver will register a i2c_client for each child node, an SPI bus driver will register its spi_device children, and similarly for other bus_types. According to that model, a driver could be written that binds to the SoC node and simply registers platform_devices for each of its children. The board support code would allocate and register an SoC device, a (theoretical) SoC device driver could bind to the SoC device, and register platform_devices for /soc/interrupt-controller, /soc/serial, /soc/i2s, and /soc/i2c in its .probe() hook. Easy, right?”h]”hXtIn the Tegra example, this accounts for the /soc and /sound nodes, but what about the children of the SoC node? Shouldn’t they be registered as platform devices too? For Linux DT support, the generic behaviour is for child devices to be registered by the parent’s device driver at driver .probe() time. So, an i2c bus device driver will register a i2c_client for each child node, an SPI bus driver will register its spi_device children, and similarly for other bus_types. According to that model, a driver could be written that binds to the SoC node and simply registers platform_devices for each of its children. The board support code would allocate and register an SoC device, a (theoretical) SoC device driver could bind to the SoC device, and register platform_devices for /soc/interrupt-controller, /soc/serial, /soc/i2s, and /soc/i2c in its .probe() hook. Easy, right?”…””}”(hjåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Mohj4h²hubhÞ)”}”(hX«Actually, it turns out that registering children of some platform_devices as more platform_devices is a common pattern, and the device tree support code reflects that and makes the above example simpler. The second argument to of_platform_populate() is an of_device_id table, and any node that matches an entry in that table will also get its child nodes registered. In the Tegra case, the code can look something like this::”h]”hXªActually, it turns out that registering children of some platform_devices as more platform_devices is a common pattern, and the device tree support code reflects that and makes the above example simpler. The second argument to of_platform_populate() is an of_device_id table, and any node that matches an entry in that table will also get its child nodes registered. In the Tegra case, the code can look something like this:”…””}”(hjóh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´M}hj4h²hubjN)”}”(hŒ‹static void __init harmony_init_machine(void) { /* ... */ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); }”h]”hŒ‹static void __init harmony_init_machine(void) { /* ... */ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); }”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jMh³hÇh´M…hj4h²hubhÞ)”}”(hXO"simple-bus" is defined in the Devicetree Specification as a property meaning a simple memory mapped bus, so the of_platform_populate() code could be written to just assume simple-bus compatible nodes will always be traversed. However, we pass it in as an argument so that board support code can always override the default behaviour.”h]”hXS“simple-bus†is defined in the Devicetree Specification as a property meaning a simple memory mapped bus, so the of_platform_populate() code could be written to just assume simple-bus compatible nodes will always be traversed. However, we pass it in as an argument so that board support code can always override the default behaviour.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´M‹hj4h²hubhÞ)”}”(hŒ<[Need to add discussion of adding i2c/spi/etc child devices]”h]”hŒ<[Need to add discussion of adding i2c/spi/etc child devices]”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´M‘hj4h²hubeh}”(h]”Œdevice-population”ah ]”h"]”Œ2.4 device population”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KÝubhÉ)”}”(hhh]”(hÎ)”}”(hŒAppendix A: AMBA devices”h]”hŒAppendix A: AMBA devices”…””}”(hj6h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj3h²hh³hÇh´M”ubhÞ)”}”(hX³ARM Primecells are a certain kind of device attached to the ARM AMBA bus which include some support for hardware detection and power management. In Linux, struct amba_device and the amba_bus_type is used to represent Primecell devices. However, the fiddly bit is that not all devices on an AMBA bus are Primecells, and for Linux it is typical for both amba_device and platform_device instances to be siblings of the same bus segment.”h]”hX³ARM Primecells are a certain kind of device attached to the ARM AMBA bus which include some support for hardware detection and power management. In Linux, struct amba_device and the amba_bus_type is used to represent Primecell devices. However, the fiddly bit is that not all devices on an AMBA bus are Primecells, and for Linux it is typical for both amba_device and platform_device instances to be siblings of the same bus segment.”…””}”(hjDh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´M–hj3h²hubhÞ)”}”(hX®When using the DT, this creates problems for of_platform_populate() because it must decide whether to register each node as either a platform_device or an amba_device. This unfortunately complicates the device creation model a little bit, but the solution turns out not to be too invasive. If a node is compatible with "arm,primecell", then of_platform_populate() will register it as an amba_device instead of a platform_device.”h]”hX²When using the DT, this creates problems for of_platform_populate() because it must decide whether to register each node as either a platform_device or an amba_device. This unfortunately complicates the device creation model a little bit, but the solution turns out not to be too invasive. If a node is compatible with “arm,primecellâ€, then of_platform_populate() will register it as an amba_device instead of a platform_device.”…””}”(hjRh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Mžhj3h²hubeh}”(h]”Œappendix-a-amba-devices”ah ]”h"]”Œappendix a: amba devices”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´M”ubeh}”(h]”Œlinux-and-the-devicetree”ah ]”h"]”Œlinux and the devicetree”ah$]”h&]”uh1hÈhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hÍNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j“Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œ1”]”(jMjWesŒrefids”}”Œnameids”}”(jmjjjj]j;j8jtjqjj jÄjÁj1j.j0j-jejbuŒ nametypes”}”(jm‰jˆj;‰jt‰j‰jĉj1‰j0‰je‰uh}”(jjhÊjWjMj]jmj8jÙjqj>j jWj jwjÁjj.jÇj-j4jbj3uŒ footnote_refs”}”jÓ]”(jMjWesŒ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”jmaŒ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”j¡Ks…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.