免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Device Tree

Contents

[hide]

[edit] Introduction

Linux and the Device Tree (Documentation/devicetree/usage-model)The Linux usage model for device tree data

Author: Grant Likely <grant.likely@secretlab.ca>

This article describes how Linux uses the device tree. An overview ofthe device tree data format can be found at the Device Tree Usage page on devicetree.org.

	All the cool architectures are using device tree.	I want to use device tree too!

The "Open Firmware Device Tree", or simply Device Tree (DT), is a datastructure and language for describing hardware. More specifically, itis a description of hardware that is readable by an operating systemso that the operating system doesn't need to hard code details of themachine.

Structurally, the DT is a tree, or acyclic graph with named nodes, andnodes may have an arbitrary number of named properties encapsulatingarbitrary data. A mechanism also exists to create arbitrarylinks from one node to another outside of the natural tree structure.

Conceptually, a common set of usage conventions, called 'bindings',is defined for how data should appear in the tree to describe typicalhardware characteristics including data busses, interrupt lines, GPIOconnections, and peripheral devices.

As much as possible, hardware is described using existing bindings tomaximize use of existing support code, but since property and nodenames are simply text strings, it is easy to extend existing bindingsor create new ones by defining new nodes and properties.

[edit] History

The DT was originally created by Open Firmware as part of thecommunication method for passing data from Open Firmware to a clientprogram (like to an operating system). An operating system used theDevice Tree to discover the topology of the hardware at runtime, andthereby support a majority of available hardware without hard codedinformation (assuming drivers were available for all devices).

Since Open Firmware is commonly used on PowerPC and SPARC platforms,the Linux support for those architectures has for a long time used theDevice Tree.

In 2005, when PowerPC Linux began a major cleanup and to merge 32-bitand 64-bit support, the decision was made to require DT support on allpowerpc platforms, regardless of whether or not they used OpenFirmware. To do this, a DT representation called the Flattened DeviceTree (FDT) was created which could be passed to the kernel as a binaryblob without requiring a real Open Firmware implementation. U-Boot,kexec, and other bootloaders were modified to support both passing aDevice Tree Binary (dtb) and to modify a dtb at boot time.

Some time later, FDT infrastructure was generalized to be usable byall architectures. At the time of this writing, 6 mainlinedarchitectures (arm, microblaze, mips, powerpc, sparc, and x86) and 1out of mainline (nios) have some level of DT support.

[edit] Data Model

If you haven't already read theDevice Tree Usage page, then go read it now. It's okay, I'll wait....

[edit] High Level View

The most important thing to understand is that the DT is simply a datastructure that describes the hardware. There is nothing magical aboutit, and it doesn't magically make all hardware configuration problemsgo away. What it does do is provide a language for decoupling thehardware configuration from the board and device driver support in theLinux kernel (or any other operating system for that matter). Usingit allows board and device support to become data driven; to makesetup decisions based on data passed into the kernel instead of onper-machine hard coded selections.

Ideally, data driven platform setup should result in less codeduplication and make it easier to support a wide range of hardwarewith a single kernel image.

Linux uses DT data for three major purposes:

  1. platform identification,
  2. runtime configuration, and
  3. device population.

[edit] Platform Identification

First and foremost, the kernel will use data in the DT to identify thespecific machine. In a perfect world, the specific platform shouldn'tmatter to the kernel because all platform details would be describedperfectly by the device tree in a consistent and reliable manner.Hardware is not perfect though, and so the kernel must identify themachine during early boot so that it has the opportunity to runmachine-specific fixups.

In the majority of cases, the machine identity is irrelevant, and thekernel will instead select setup code based on the machine's coreCPU or SoC. On ARM for example, setup_arch() inarch/arm/kernel/setup.c will call setup_machine_fdt() inarch/arm/kernel/devicetree.c which searches through the machine_desctable and selects the machine_desc which best matches the device treedata. It determines the best match by looking at the 'compatible'property in the root device tree node, and comparing it with thedt_compat list in struct machine_desc.

The 'compatible' property contains a sorted list of strings startingwith the exact name of the machine, followed by an optional list ofboards it is compatible with sorted from most compatible to least. Forexample, the root compatible properties for the TI BeagleBoard and itssuccessor, the BeagleBoard xM board might look like:

	compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3";	compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";

Where "ti,omap3-beagleboard-xm" specifies the exact model, it alsoclaims that it compatible with the OMAP 3450 SoC, and the omap3 familyof SoCs in general. You'll notice that the list is sorted from mostspecific (exact board) to least specific (SoC family).

Astute readers might point out that the Beagle xM could also claimcompatibility with the original Beagle board. However, one should becautioned about doing so at the board level since there is typically ahigh level of change from one board to another, even within the sameproduct line, and it is hard to nail down exactly what is meant when oneboard claims to be compatible with another. For the top level, it isbetter to err on the side of caution and not claim one board iscompatible with another. The notable exception would be when oneboard is a carrier for another, such as a CPU module attached to acarrier board.

One more note on compatible values. Any string used in a compatibleproperty must be documented as to what it indicates. Adddocumentation for compatible strings in Documentation/devicetree/bindings.

Again on ARM, for each machine_desc, the kernel looks to see ifany of the dt_compat list entries appear in the compatible property.If one does, then that machine_desc is a candidate for driving themachine. After searching the entire table of machine_descs,setup_machine_fdt() returns the 'most compatible' machine_desc basedon which entry in the compatible property each machine_desc matchesagainst. If no matching machine_desc is found, then it returns NULL.

The reasoning behind this scheme is the observation that in the majorityof cases, a single machine_desc can support a large number of boardsif they all use the same SoC, or same family of SoCs. However,invariably there will be some exceptions where a specific board willrequire special setup code that is not useful in the generic case.Special cases could be handled by explicitly checking for thetroublesome board(s) in generic setup code, but doing so very quicklybecomes ugly and/or unmaintainable if it is more than just a couple ofcases.

Instead, the compatible list allows a generic machine_desc to providesupport for a wide common set of boards by specifying "lesscompatible" value 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 beagleboardthat required special workaround code during early boot, then a newmachine_desc could be added which implements the workarounds and onlymatches on "ti,omap3-beagleboard".

PowerPC 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 thecompatible list, and probably should be avoided for new architecturesupport.

[edit] Runtime configuration

In most cases, a DT will be the sole method of communicating data fromfirmware to the kernel, so also gets used to pass in runtime andconfiguration data like the kernel parameters string and the locationof an initrd image.

Most of this data is contained in the /chosen node, and when bootingLinux it will look something like this:

	chosen {		bootargs = "console=ttyS0,115200 loglevel=8";		initrd-start = <0xc8000000>;		initrd-end = <0xc8200000>;	};

The bootargs property contains the kernel arguments, and the initrd-*properties define the address and size of an initrd blob. Thechosen node may also optionally contain an arbitrary number ofadditional properties for platform-specific configuration data.

During early boot, the architecture setup code calls of_scan_flat_dt()several times with different helper callbacks to parse device treedata before paging is setup. The of_scan_flat_dt() code scans throughthe device tree and uses the helpers to extract information requiredduring early boot. Typically the early_init_dt_scan_chosen() helperis 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 andlocation of usable RAM.

On ARM, the function setup_machine_fdt() is responsible for earlyscanning of the device tree after selecting the correct machine_descthat supports the board.

[edit] Device population

After the board has been identified, and after the early configuration datahas been parsed, then kernel initialization can proceed in the normalway. At some point in this process, unflatten_device_tree() is calledto convert the data into a more efficient runtime representation.This is also when machine-specific setup hooks will get called, likethe machine_desc .init_early(), .init_irq() and .init_machine() hookson ARM. The remainder of this section uses examples from the ARMimplementation, but all architectures will do pretty much the samething when using a DT.

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 DTdoesn't materially change the behaviour of either of these functions.If a DT is provided, then both .init_early() and .init_irq() are ableto call any of the DT query functions (of_* in include/linux/of*.h) toget additional data about the platform.

The most interesting hook in the DT context is .init_machine() whichis primarily responsible for populating the Linux device model withdata about the platform. Historically this has been implemented onembedded platforms by defining a set of static clock structures,platform_devices, and other data in the board support .c file, andregistering it en-masse in .init_machine(). When DT is used, theninstead of hard coding static devices for each platform, the list ofdevices can be obtained by parsing the DT, and allocating devicestructures dynamically.

The simplest case is when .init_machine() is only responsible forregistering a block of platform_devices. A platform_device is a conceptused by Linux for memory or I/O mapped devices which cannot be detectedby hardware, and for 'composite' or 'virtual' devices (more on thoselater). While there is no 'platform device' terminology for the DT,platform devices roughly correspond to device nodes at the root of thetree and children of simple memory mapped bus nodes.

About now is a good time to lay out an example. Here is part of thedevice tree for the NVIDIA Tegra board.

/{	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>;		};		i2s-1: i2s@70002800 {			compatible = "nvidia,tegra20-i2s";			reg = <0x70002800 0x100>;			interrupts = <77>;			codec = <&wm8903>;		};		i2c@7000c000 {			compatible = "nvidia,tegra20-i2c";			#address-cells = <1>;			#size-cells = <1>;			reg = <0x7000c000 0x100>;			interrupts = <70>;			wm8903: codec@1a {				compatible = "wlf,wm8903";				reg = <0x1a>;				interrupts = <347>;			};		};	};	sound {		compatible = "nvidia,harmony-sound";		i2s-controller = <&i2s-1>;		i2s-codec = <&wm8903>;	};};

At .machine_init() time, Tegra board support code will need to look atthis DT and decide which nodes to create platform_devices for.However, looking at the tree, it is not immediately obvious what kindof device each node represents, or even if a node represents a deviceat all. The /chosen, /aliases, and /memory nodes are informationalnodes that don't describe devices (although arguably memory could beconsidered a device). The children of the /soc node are memory mappeddevices, but the codec@1a is an i2c device, and the sound noderepresents not a device, but rather how other devices are connectedtogether to create the audio subsystem. I know what each device isbecause I'm familiar with the board design, but how does the kernelknow what to do with each node?

The trick is that the kernel starts at the root of the tree and looksfor nodes that have a 'compatible' property. First, it is generallyassumed that any node with a 'compatible' property represents a deviceof some kind, and second, it can be assumed that any node at the rootof the tree is either directly attached to the processor bus, or is amiscellaneous system device that cannot be described any other way.For each of these nodes, Linux allocates and registers aplatform_device, which in turn may get bound to a platform_driver.

Why is using a platform_device for these nodes a safe assumption?Well, for the way that Linux models devices, just about all bus_typesassume that its devices are children of a bus controller. Forexample, each i2c_client is a child of an i2c_master. Each spi_deviceis a child of an SPI bus. Similarly for USB, PCI, MDIO, etc. Thesame hierarchy is also found in the DT, where I2C device nodes onlyever 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 parentdevice are platform_devices (and amba_devices, but more on thatlater), which will happily live at the base of the Linux /sys/devicestree. Therefore, if a DT node is at the root of the tree, then itreally probably is best registered as a platform_device.

Linux board support code calls of_platform_populate(NULL, NULL, NULL)to kick off discovery of devices at the root of the tree. Theparameters are all NULL because when starting from the root of thetree, there is no need to provide a starting node (the first NULL), aparent struct device (the last NULL), and we're not using a matchtable (yet). For a board that only needs to register devices,.init_machine() can be completely empty except for theof_platform_populate() call.

In the Tegra example, this accounts for the /soc and /sound nodes, butwhat about the children of the SoC node? Shouldn't they be registeredas platform devices too? For Linux DT support, the generic behaviouris for child devices to be registered by the parent's device driver atdriver .probe() time. So, an i2c bus device driver will register ai2c_client for each child node, an SPI bus driver will registerits spi_device children, and similarly for other bus_types.According to that model, a driver could be written that binds to theSoC node and simply registers platform_devices for each of itschildren. The board support code would allocate and register an SoCdevice, an SoC device driver would bind to the SoC device, andregister platform_devices for /soc/interrupt-controller, /soc/serial,/soc/i2s, and /soc/i2c in its .probe() hook. Easy, right? Althoughit is a lot of mucking about for just registering platform devices.

It turns out that registering children of certain platform_devices asmore platform_devices is a common pattern, and the device tree supportcode reflects that. The second argument to of_platform_populate() isan of_device_id table, and any node that matches an entry in thattable will also get its child nodes registered. In the tegra case,the code can look something like this:

static struct of_device_id harmony_bus_ids[] __initdata = {	{ .compatible = "simple-bus", },	{}};static void __init harmony_init_machine(void){	/* ... */	of_platform_populate(NULL, harmony_bus_ids, NULL);}

"simple-bus" is defined in the ePAPR 1.0 specification as a propertymeaning a simple memory mapped bus, so the of_platform_populate() codecould be written to just assume simple-bus compatible nodes willalways be traversed. However, we pass it in as an argument so thatboard support code can always override the default behaviour.

[edit] Appendix A: AMBA devices

ARM Primecells are a certain kind of device attached to the ARM AMBAbus which include some support for hardware detection and powermanagement. In Linux, struct amba_device and the amba_bus_type isused to represent Primecell devices. However, the fiddly bit is thatnot all devices on an AMBA bus are Primecells, and for Linux it istypical for both amba_device and platform_device instances to besiblings of the same bus segment.

When using the DT, this creates problems for of_platform_populate()because it must decide whether to register each node as either aplatform_device or an amba_device. This unfortunately complicates thedevice creation model a little bit, but the solution turns out not tobe too invasive. If a node is compatible with "arm,amba-primecell", thenof_platform_populate() will register it as an amba_device instead of aplatform_device.

[edit] OMAP specifics bindings

For the moment (kernel 3.2), OMAP devices are still relying on the omap_device / omap_hwmod mechanismto populate the IRQ, DMA and address space. A TI specific binding was thus added for that purpose.

ti,hwmods = "hwmod1", "hwmod2";

[edit] Common Pitfalls of DT

  • All data is encoded in big endian format
  • Helpers available to convert data from big endian format to whatever format a given cpu supports

For example be32_to_cpu() converts data from big endian 32 bit format to the format supported by cpu

  • Typo’s in dts files can be very expensive

No checking done at compile time by the DTC compiler

  • Editing a .dtsi file does not recompile the .dts file which includes it. Manually remove the .dtb file (Maybe there is a better alternative I don’t know of)

[edit] OMAP DT migration series

A couple of device tree series for OMAP were already posted and can be used as a reference / example for driver owner.

OMAP: Add initial support for DT on OMAP3 & OMAP4

  • git://gitorious.org/omap-pm/linux.git for_3.2/3_omap_devicetree

OMAP3+: Add DT support for early devices and i2c / twl6030

  • git://gitorious.org/omap-pm/linux.git for_3.2/4_omap_dt_i2c_twl

In this series, the GPIO driver can be used to see how to move some platform_data information to device tree properties.

Device tree support for regulators

  • git://gitorious.org/omap-pm/linux.git 5+_omap_dt_i2c_twl_reg

[edit] Drivers / Features migration status

Feature / Driver
Owner
3.2
3.3
3.4
3.5
3.6
3.7
3.8
Missing Feature
Dependency / Remarks
board-genericBenoitDone
OMAP3 DTS (Beagle + xM)BenoitDone
OMAP4 DTS (SDP, Panda)BenoitDone
OMAP5 DTS (SDP)Benoit Done
mpu, l3, ivaBenoitDone
Add irq-names bindingBenoit Done
Add reg-names bindingBenoit Done
Move irq, reg from hwmod to DTSBenoit target
Add dma bindings Jon target
Regulator binding Rajendra Done
Serial Rajendra Done
I2C Benoit Done
TWL4030/6030 Benoit Done
TWL6040 Peter Done
TWL: SMPS / LDORajendra Done
TWL: RTC BenoitDone
GPIO Benoit Done
MMC Rajendra Done GPIO, SMPS
USB HOST HS Felipe target GPIO runtime PM
McSPI Benoit Done GPIO
Pin MuxTony target Dependency with pin control subsystem from Linus Walleij (STE / Linaro)
Clock BindingMike target Dependency with common clock framework
DSS Tomi & Archit GPIO, SMPS Dependency on Generic Panel Framework
Control ModuleTBD target
Timer Jon target Accepted
PRM Tero targetPRM and CM driver are keys to store the PRCM related data stored in hwmod so far.
CM Tero target
SDMA Jon target
Watchdog Jon target
SmartReflex Keerthy target
EMIF Aneesh Done
GPMC Afzal target
DMIC Peter Target Accepted
AESS Liam target
McBSP Peter target Queued
McPDM Peter target Accepted
Slimbus TBD TBC
Mailbox Omar
IOMMU Ohad
Spinlock Benoit target Posted, need Ohad Acked-By:. Some improvement were also considered during the review - namely adding the baseid property.
Bandgap Keerthy
Counter 32k Jon target
Keyboard Kishore target
Accelerometer Kishore target
TouchScreen Kishore target
Other Sensors Kishore target
ISS TBD TBC
FDIF TBD TBC
IPU TBD
HSI Shubrajyothi
C2C TBD
USB OTG HS TBD

[edit] Booting with DT blob

Using an updated/dt-enabled u-boot

  • get the latest u-boot sources from git://git.denx.de/u-boot.git
  • The basic DT support for OMAP is available in mainline since 3.2-rc1
  • use omap2plus_defconfig as it has DT support enabled by default
  • Build the dtb file using 'make ARCH=arm <dtb-file-name>'
  • Supported <dtb-file-name> for now are omap4-panda.dtb, omap4-sdp.dtb and omap3-beagle.dtb
  • load the kernel to a <kerneladdress> and dtb file to a <dtbaddress> in RAM over NFS or from a MMC card.
  • Use the following u-boot command to specify the dtb file location to the kernel at boot
 set fdt_high 0xffffffff ; fdt addr <dtbaddress>; fdt resize; bootm <kernaddress> - <dtbaddress>'


Using legacy u-boot and DT-APPEND support in kernel

Grant did a patch to build and append automatically the blob to the zImage before creating the uImage. The latest patch based upon kernel 3.4-rc5 is available here File:Append-dtb.tar.gz. The orignal patch can be found on the git tree below.

 git://gitorious.org/omap-pm/linux.git dt_test/build_uimage_append

Thanks to that, you can create the proper uImage after enabling CONFIG_ARM_APPENDED_DTB in Boot Options config.The syntax is that one:

 make uImage-dtb.<board-dts>

The following board DTS are available for the moment:

 make uImage-dtb.omap4-sdp make uImage-dtb.omap4-panda make uImage-dtb.omap3-beagle

A legacy u-boot without DT support can then load this uImage like before. The kernel will detect the presence of the DTB blob and pass the physical address automatically.

[edit] Links

The devicetree.org wiki web maintained by Grant:http://devicetree.org/Main_Page

The most interesting page:http://devicetree.org/Device_Tree_Usage

The official spec:http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf

ARM Device Tree Status Report presentation done by Grant During ELC 2010:http://elinux.org/images/b/b6/ARM_Device_Tree_Status_Report.pdf

ELCE: Grant Likely on device treeshttp://lwn.net/Articles/414016/

Retrieved from "
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服