summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2011-10-24 18:04:27 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-10-24 18:04:27 -0400
commitaf1bdb79ca64ceadc7b44b11929b384eff66ce59 (patch)
treec4bb4c94acaf44a113edc60dc0661d4282f0f100
parent552a79413a691a09abf1b3707561858422afc53c (diff)
parent1021eb4c454312e65365a4700a1f2b33a0654aa4 (diff)
Merge branch 'devicetree/arm-linaro-3.1' of git://git.secretlab.ca/git/linux-2.6 into linaro-3.1linux-linaro-3.1-2011.10-2
-rw-r--r--Documentation/devicetree/bindings/arm/freescale.txt7
-rw-r--r--Documentation/devicetree/bindings/arm/genesi.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/primecell.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/samsung.txt9
-rw-r--r--Documentation/devicetree/bindings/gpio/pl061-gpio.txt10
-rw-r--r--Documentation/devicetree/bindings/spi/spi_pl022.txt12
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt40
-rw-r--r--Documentation/devicetree/usage-model403
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/arm/boot/dts/exynos4-smdkv310.dts11
-rw-r--r--arch/arm/boot/dts/genesi-efikamx.dts22
-rw-r--r--arch/arm/boot/dts/genesi-efikasb.dts22
-rw-r--r--arch/arm/boot/dts/isee-igep-v2.dts7
-rw-r--r--arch/arm/boot/dts/isee-igep-v3.dts7
-rw-r--r--arch/arm/boot/dts/mx51-babbage.dts22
-rw-r--r--arch/arm/boot/dts/mx53-loco.dts22
-rw-r--r--arch/arm/boot/dts/omap3-beagle.dts7
-rw-r--r--arch/arm/boot/dts/omap3-overo.dts7
-rw-r--r--arch/arm/boot/dts/omap4-panda.dts11
-rw-r--r--arch/arm/boot/dts/vexpress.dts10
-rw-r--r--arch/arm/mach-exynos4/Makefile.boot2
-rw-r--r--arch/arm/mach-exynos4/mach-smdkv310.c6
-rw-r--r--arch/arm/mach-mx5/Makefile.boot5
-rw-r--r--arch/arm/mach-mx5/board-mx51_babbage.c6
-rw-r--r--arch/arm/mach-mx5/board-mx51_efikamx.c6
-rw-r--r--arch/arm/mach-mx5/board-mx51_efikasb.c6
-rw-r--r--arch/arm/mach-mx5/board-mx53_loco.c5
-rw-r--r--arch/arm/mach-omap2/Makefile.boot6
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c12
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c6
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c6
-rw-r--r--arch/arm/mach-omap2/board-overo.c6
-rw-r--r--arch/arm/mach-versatile/Makefile.boot2
-rw-r--r--arch/arm/mach-vexpress/Makefile.boot2
-rw-r--r--arch/arm/mach-vexpress/v2m.c6
-rw-r--r--drivers/of/base.c150
-rw-r--r--drivers/of/fdt.c6
-rw-r--r--drivers/of/irq.c14
-rw-r--r--drivers/of/pdt.c8
-rw-r--r--drivers/of/platform.c7
-rw-r--r--drivers/tty/serial/altera_jtaguart.c5
-rw-r--r--drivers/tty/serial/altera_uart.c4
-rw-r--r--drivers/tty/serial/imx.c11
-rw-r--r--drivers/tty/serial/uartlite.c4
-rw-r--r--include/linux/of.h41
-rw-r--r--include/linux/of_platform.h7
46 files changed, 956 insertions, 26 deletions
diff --git a/Documentation/devicetree/bindings/arm/freescale.txt b/Documentation/devicetree/bindings/arm/freescale.txt
new file mode 100644
index 00000000000..8c52102b225
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/freescale.txt
@@ -0,0 +1,7 @@
+mx51 "Babbage" evalutation board
+Required root node properties:
+ - compatible = "fsl,mx51-babbage", "fsl,mx51";
+
+mx53 "Loco" evaluation board
+Required root node properties:
+ - compatible = "fsl,mx53-loco", "fsl,mx53";
diff --git a/Documentation/devicetree/bindings/arm/genesi.txt b/Documentation/devicetree/bindings/arm/genesi.txt
new file mode 100644
index 00000000000..b353489acd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/genesi.txt
@@ -0,0 +1,8 @@
+Genesi EfikaMX based on Freescale mx51
+Required root node properties:
+ - compatible = "genesi,efikamx", "fsl,mx51";
+
+Genesi EfikaMX Smartbook based on Freescale mx51
+Required root node properties:
+ - compatible = "genesi,efikasb", "fsl,mx51";
+
diff --git a/Documentation/devicetree/bindings/arm/primecell.txt b/Documentation/devicetree/bindings/arm/primecell.txt
index 1d5d7a870ec..951ca46789d 100644
--- a/Documentation/devicetree/bindings/arm/primecell.txt
+++ b/Documentation/devicetree/bindings/arm/primecell.txt
@@ -6,7 +6,9 @@ driver matching.
Required properties:
-- compatible : should be a specific value for peripheral and "arm,primecell"
+- compatible : should be a specific name for the peripheral and
+ "arm,primecell". The specific name will match the ARM
+ engineering name for the logic block in the form: "arm,pl???"
Optional properties:
diff --git a/Documentation/devicetree/bindings/arm/samsung.txt b/Documentation/devicetree/bindings/arm/samsung.txt
new file mode 100644
index 00000000000..594cb97e3d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung.txt
@@ -0,0 +1,9 @@
+Samsung Exynos4 S5PV310 SoC based SMDKV310 eval board
+
+ SMDKV310 eval board is based on S5PV310 SoC which belongs to
+ Samsung's Exynos4 family of application processors.
+
+Required root node properties:
+ - compatible = "samsung,smdkv310","samsung,s5pv310"
+ (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board.
+ (b) "samsung,s5pv310" - for boards based on S5PV310 SoC.
diff --git a/Documentation/devicetree/bindings/gpio/pl061-gpio.txt b/Documentation/devicetree/bindings/gpio/pl061-gpio.txt
new file mode 100644
index 00000000000..a2c416bcbcc
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/pl061-gpio.txt
@@ -0,0 +1,10 @@
+ARM PL061 GPIO controller
+
+Required properties:
+- compatible : "arm,pl061", "arm,primecell"
+- #gpio-cells : Should be two. The first cell is the pin number and the
+ second cell is used to specify optional parameters:
+ - bit 0 specifies polarity (0 for normal, 1 for inverted)
+- gpio-controller : Marks the device node as a GPIO controller.
+- interrupts : Interrupt mapping for GPIO IRQ.
+
diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt
new file mode 100644
index 00000000000..306ec3ff3c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt
@@ -0,0 +1,12 @@
+ARM PL022 SPI controller
+
+Required properties:
+- compatible : "arm,pl022", "arm,primecell"
+- reg : Offset and length of the register set for the device
+- interrupts : Should contain SPI controller interrupt
+
+Optional properties:
+- cs-gpios : should specify GPIOs used for chipselects.
+ The gpios will be referred to as reg = <index> in the SPI child nodes.
+ If unspecified, a single SPI device without a chip select can be used.
+
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
new file mode 100644
index 00000000000..e8552782b44
--- /dev/null
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -0,0 +1,40 @@
+Device tree binding vendor prefix registry. Keep list in alphabetical order.
+
+This isn't an exhaustive list, but you should add new prefixes to it before
+using them to avoid name-space collisions.
+
+adi Analog Devices, Inc.
+amcc Applied Micro Circuits Corporation (APM, formally AMCC)
+apm Applied Micro Circuits Corporation (APM)
+arm ARM Ltd.
+atmel Atmel Corporation
+chrp Common Hardware Reference Platform
+dallas Maxim Integrated Products (formerly Dallas Semiconductor)
+denx Denx Software Engineering
+epson Seiko Epson Corp.
+est ESTeem Wireless Modems
+fsl Freescale Semiconductor
+GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+hp Hewlett Packard
+ibm International Business Machines (IBM)
+idt Integrated Device Technologies, Inc.
+intercontrol Inter Control Group
+linux Linux-specific binding
+marvell Marvell Technology Group Ltd.
+maxim Maxim Integrated Products
+mosaixtech Mosaix Technologies, Inc.
+national National Semiconductor
+nintendo Nintendo
+nvidia NVIDIA
+nxp NXP Semiconductors
+powervr Imagination Technologies
+qcom Qualcomm, Inc.
+ramtron Ramtron International
+samsung Samsung Semiconductor
+schindler Schindler
+simtek
+sirf SiRF Technology, Inc.
+stericsson ST-Ericsson
+ti Texas Instruments
+xlnx Xilinx
diff --git a/Documentation/devicetree/usage-model b/Documentation/devicetree/usage-model
new file mode 100644
index 00000000000..45e03b8dd04
--- /dev/null
+++ b/Documentation/devicetree/usage-model
@@ -0,0 +1,403 @@
+Linux and the Device Tree
+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 of
+the device tree data format can be found at the <a
+href="http://devicetree.org/Device_Tree_Usage">Device Tree Usage</a>
+page on <a href="http://devicetree.org">devicetree.org</a>.
+
+
+ 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 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.
+
+Structurally, 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.
+
+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.
+
+As 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.
+
+<h2>History</h2>
+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 support a majority of available hardware without hard coded
+information (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 the
+Device Tree.
+
+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.
+
+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.
+
+<h2>Data Model</h2>
+If you haven't already read the
+href="http://devicetree.org/Device_Tree_Usage">Device Tree Usage</a>
+page, then go read it now. It's okay, I'll wait....
+
+<h3>High Level View</h3>
+The 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.
+
+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.
+
+Linux uses DT data for three major purposes:
+1) platform identification,
+2) runtime configuration, and
+3) device population.
+
+<h4>Platform Identification</h4>
+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.
+
+In 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/devicetree.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.
+
+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:
+
+ 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 also
+claims that it 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).
+
+Astute 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.
+
+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.
+
+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.
+
+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.
+
+Instead, the compatible list allows a generic machine_desc to provide
+support for a wide common set of boards by specifying "less
+compatible" 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 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".
+
+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 the
+compatible list, and probably should be avoided for new architecture
+support.
+
+<h4>Runtime configuration</h4>
+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.
+
+Most of this data is contained in the /chosen node, and when booting
+Linux it will look something like this:
+
+ chosen {
+ bootargs = "console=ttyS0,115200 loglevel=8";
+ initrd-start = &lt;0xc8000000&gt;;
+ initrd-end = &lt;0xc8200000&gt;;
+ };
+
+The bootargs property contains the kernel arguments, and the initrd-*
+properties define the address and size of an initrd blob. The
+chosen node may also optionally contain an arbitrary number of
+additional 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 tree
+data before paging is setup. 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.
+
+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.
+
+<h4>Device population</h4>
+After 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.
+
+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.
+
+The 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.
+
+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.
+
+About now is a good time to lay out an example. Here is part of the
+device 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 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?
+
+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.
+
+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.
+
+Linux board support code calls of_platform_populate(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.
+
+In 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, an SoC device driver would 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? Although
+it is a lot of mucking about for just registering platform devices.
+
+It turns out that registering children of certain platform_devices as
+more platform_devices is a common pattern, and the device tree support
+code reflects that. 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:
+
+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 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.
+
+<h2>Appendix A: AMBA devices</h2>
+
+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.
+
+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,amba-primecell", then
+of_platform_populate() will register it as an amba_device instead of a
+platform_device.
diff --git a/MAINTAINERS b/MAINTAINERS
index 6185d051358..73369be4c24 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4728,10 +4728,12 @@ F: drivers/i2c/busses/i2c-ocores.c
OPEN FIRMWARE AND FLATTENED DEVICE TREE
M: Grant Likely <grant.likely@secretlab.ca>
+M: Rob Herring <rob.herring@calxeda.com>
L: devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
W: http://fdt.secretlab.ca
T: git git://git.secretlab.ca/git/linux-2.6.git
S: Maintained
+F: Documentation/devicetree
F: drivers/of
F: include/linux/of*.h
K: of_get_property
diff --git a/arch/arm/boot/dts/exynos4-smdkv310.dts b/arch/arm/boot/dts/exynos4-smdkv310.dts
new file mode 100644
index 00000000000..dd6c80a7ffc
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4-smdkv310.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Samsung Exynos4 SMDKV310 eval board";
+ compatible = "samsung,smdkv310", "samsung,s5pv310";
+
+ memory {
+ reg = <0x40000000 0x08000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/genesi-efikamx.dts b/arch/arm/boot/dts/genesi-efikamx.dts
new file mode 100644
index 00000000000..e81ffcc8443
--- /dev/null
+++ b/arch/arm/boot/dts/genesi-efikamx.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Genesi EfikaMX nettop";
+ compatible = "genesi,efikamx", "fsl,mx51";
+
+ memory {
+ reg = <0x90000000 0x20000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/genesi-efikasb.dts b/arch/arm/boot/dts/genesi-efikasb.dts
new file mode 100644
index 00000000000..9fda6ae314e
--- /dev/null
+++ b/arch/arm/boot/dts/genesi-efikasb.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Genesi Efika Smartbook";
+ compatible = "genesi,efikasb", "fsl,mx51";
+
+ memory {
+ reg = <0x90000000 0x20000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/isee-igep-v2.dts b/arch/arm/boot/dts/isee-igep-v2.dts
new file mode 100644
index 00000000000..72caabb85b7
--- /dev/null
+++ b/arch/arm/boot/dts/isee-igep-v2.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "ISSE IGEPv2 Board";
+ compatible = "ISEE,igep-v2";
+};
diff --git a/arch/arm/boot/dts/isee-igep-v3.dts b/arch/arm/boot/dts/isee-igep-v3.dts
new file mode 100644
index 00000000000..f40886fef69
--- /dev/null
+++ b/arch/arm/boot/dts/isee-igep-v3.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "ISSE IGEPv3 Module";
+ compatible = "ISEE,igep-v3";
+};
diff --git a/arch/arm/boot/dts/mx51-babbage.dts b/arch/arm/boot/dts/mx51-babbage.dts
new file mode 100644
index 00000000000..e5e9c8913d0
--- /dev/null
+++ b/arch/arm/boot/dts/mx51-babbage.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Freescale i.MX51 Babbage";
+ compatible = "fsl,mx51-babbage", "fsl,mx51";
+
+ memory {
+ reg = <0x90000000 0x20000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/mx53-loco.dts b/arch/arm/boot/dts/mx53-loco.dts
new file mode 100644
index 00000000000..8426c620614
--- /dev/null
+++ b/arch/arm/boot/dts/mx53-loco.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Freescale i.MX53 LOCO";
+ compatible = "fsl,mx53-loco", "fsl,mx53";
+
+ memory {
+ reg = <0x70000000 0x40000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
new file mode 100644
index 00000000000..44394660006
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "TI OMAP3 BeagleBoard";
+ compatible = "ti,omap3-beagle";
+};
diff --git a/arch/arm/boot/dts/omap3-overo.dts b/arch/arm/boot/dts/omap3-overo.dts
new file mode 100644
index 00000000000..c61f0112bf3
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-overo.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Gumstix Overo";
+ compatible = "gumstix,omap3-overo";
+};
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
new file mode 100644
index 00000000000..58909e9b664
--- /dev/null
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/memreserve/ 0x9D000000 0x03000000; /* Frame buffer */
+/memreserve/ 0xB0000000 0x10000000; /* Top 256MB is unaccessable */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "TI OMAP4 PandaBoard";
+ compatible = "ti,omap4-panda", "ti,omap4430";
+};
diff --git a/arch/arm/boot/dts/vexpress.dts b/arch/arm/boot/dts/vexpress.dts
new file mode 100644
index 00000000000..5f3bc1d1f1c
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress.dts
@@ -0,0 +1,10 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "ARM Versatile Express";
+ compatible = "arm,vexpress";
+ memory {
+ reg = <0x60000000 0x40000000>;
+ };
+};
diff --git a/arch/arm/mach-exynos4/Makefile.boot b/arch/arm/mach-exynos4/Makefile.boot
index d65956ffb43..fcee6b5384a 100644
--- a/arch/arm/mach-exynos4/Makefile.boot
+++ b/arch/arm/mach-exynos4/Makefile.boot
@@ -1,2 +1,4 @@
zreladdr-y := 0x40008000
params_phys-y := 0x40000100
+
+dtb-$(CONFIG_MACH_SMDKV310) += exynos4-smdkv310.dtb
diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c
index d90fcddbee1..1d7bf2138dd 100644
--- a/arch/arm/mach-exynos4/mach-smdkv310.c
+++ b/arch/arm/mach-exynos4/mach-smdkv310.c
@@ -252,6 +252,11 @@ static void __init smdkv310_machine_init(void)
platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices));
}
+static char const *smdkv310_dt_compat[] __initdata = {
+ "samsung,smdkv310",
+ NULL
+};
+
MACHINE_START(SMDKV310, "SMDKV310")
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
/* Maintainer: Changhwan Youn <chaos.youn@samsung.com> */
@@ -260,4 +265,5 @@ MACHINE_START(SMDKV310, "SMDKV310")
.map_io = smdkv310_map_io,
.init_machine = smdkv310_machine_init,
.timer = &exynos4_timer,
+ .dt_compat = smdkv310_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot
index e928be1b675..4111462e242 100644
--- a/arch/arm/mach-mx5/Makefile.boot
+++ b/arch/arm/mach-mx5/Makefile.boot
@@ -7,3 +7,8 @@ initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000
zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000
params_phys-$(CONFIG_ARCH_MX53) := 0x70000100
initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000
+
+dtb-$(CONFIG_MACH_MX51_BABBAGE) += mx51-babbage.dtb
+dtb-$(CONFIG_MACH_MX51_EFIKAMX) += genesi-efikamx.dtb
+dtb-$(CONFIG_MACH_MX51_EFIKASB) += genesi-efikasb.dtb
+dtb-$(CONFIG_MACH_MX53_LOCO) += mx53-loco.dtb
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c
index 468926a48fe..8c65ede42b7 100644
--- a/arch/arm/mach-mx5/board-mx51_babbage.c
+++ b/arch/arm/mach-mx5/board-mx51_babbage.c
@@ -414,6 +414,11 @@ static struct sys_timer mx51_babbage_timer = {
.init = mx51_babbage_timer_init,
};
+static const char *mx51_babbage_dt_match[] __initdata = {
+ "fsl,mx51-babbage",
+ NULL
+};
+
MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
/* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */
.atag_offset = 0x100,
@@ -422,4 +427,5 @@ MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
.init_irq = mx51_init_irq,
.timer = &mx51_babbage_timer,
.init_machine = mx51_babbage_init,
+ .dt_compat = mx51_babbage_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c
index c36880da03f..b183efc7396 100644
--- a/arch/arm/mach-mx5/board-mx51_efikamx.c
+++ b/arch/arm/mach-mx5/board-mx51_efikamx.c
@@ -278,6 +278,11 @@ static struct sys_timer mx51_efikamx_timer = {
.init = mx51_efikamx_timer_init,
};
+static const char *mx51_efikamx_dt_match[] __initdata = {
+ "genesi,efikamx",
+ NULL
+};
+
MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
/* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */
.atag_offset = 0x100,
@@ -286,4 +291,5 @@ MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
.init_irq = mx51_init_irq,
.timer = &mx51_efikamx_timer,
.init_machine = mx51_efikamx_init,
+ .dt_compat = mx51_efikamx_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-mx5/board-mx51_efikasb.c
index ba5436a9fb1..dfdc011cc72 100644
--- a/arch/arm/mach-mx5/board-mx51_efikasb.c
+++ b/arch/arm/mach-mx5/board-mx51_efikasb.c
@@ -265,6 +265,11 @@ static struct sys_timer mx51_efikasb_timer = {
.init = mx51_efikasb_timer_init,
};
+static const char *mx51_efikasb_dt_match[] __initdata = {
+ "genesi,efikasb",
+ NULL
+};
+
MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook")
.atag_offset = 0x100,
.map_io = mx51_map_io,
@@ -272,4 +277,5 @@ MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook")
.init_irq = mx51_init_irq,
.init_machine = efikasb_board_init,
.timer = &mx51_efikasb_timer,
+ .dt_compat = mx51_efikasb_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c
index 4e1d51d252d..13cddd703be 100644
--- a/arch/arm/mach-mx5/board-mx53_loco.c
+++ b/arch/arm/mach-mx5/board-mx53_loco.c
@@ -284,10 +284,15 @@ static struct sys_timer mx53_loco_timer = {
.init = mx53_loco_timer_init,
};
+static const char *mx53_loco_dt_match[] __initdata = {
+ "fsl,mx53-loco",
+ NULL
+};
MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board")
.map_io = mx53_map_io,
.init_early = imx53_init_early,
.init_irq = mx53_init_irq,
.timer = &mx53_loco_timer,
.init_machine = mx53_loco_board_init,
+ .dt_compat = mx53_loco_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot
index 565aff7f37a..422c1700ccf 100644
--- a/arch/arm/mach-omap2/Makefile.boot
+++ b/arch/arm/mach-omap2/Makefile.boot
@@ -1,3 +1,9 @@
zreladdr-y := 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x80800000
+
+dtb-$(CONFIG_MACH_OMAP3_BEAGLE) += omap3-beagle.dtb
+dtb-$(CONFIG_MACH_OMAP4_PANDA) += omap4-panda.dtb
+dtb-$(CONFIG_MACH_OVERO) += omap3-overo.dtb
+dtb-$(CONFIG_MACH_IGEP0020) += isee-igep-v2.dtb
+dtb-$(CONFIG_MACH_IGEP0030) += isee-igep-v3.dtb
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 7040352b16b..cfa2870df34 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -671,6 +671,11 @@ static void __init igep_init(void)
}
}
+static const char *igep2_dt_compat[] = {
+ "ISEE,igep-v2",
+ NULL
+};
+
MACHINE_START(IGEP0020, "IGEP v2 board")
.atag_offset = 0x100,
.reserve = omap_reserve,
@@ -679,8 +684,14 @@ MACHINE_START(IGEP0020, "IGEP v2 board")
.init_irq = omap3_init_irq,
.init_machine = igep_init,
.timer = &omap3_timer,
+ .dt_compat = igep2_dt_compat,
MACHINE_END
+static const char *igep3_dt_compat[] = {
+ "ISEE,igep-v3",
+ NULL
+};
+
MACHINE_START(IGEP0030, "IGEP OMAP3 module")
.atag_offset = 0x100,
.reserve = omap_reserve,
@@ -689,4 +700,5 @@ MACHINE_START(IGEP0030, "IGEP OMAP3 module")
.init_irq = omap3_init_irq,
.init_machine = igep_init,
.timer = &omap3_timer,
+ .dt_compat = &igep3_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 1fde8a0474b..d73ec628f83 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -555,6 +555,11 @@ static void __init omap3_beagle_init(void)
beagle_opp_init();
}
+static const char *omap3_beagle_dt_match[] = {
+ "ti,omap3-beagle",
+ NULL
+};
+
MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
/* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
.atag_offset = 0x100,
@@ -564,4 +569,5 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
.init_irq = omap3_beagle_init_irq,
.init_machine = omap3_beagle_init,
.timer = &omap3_secure_timer,
+ .dt_compat = omap3_beagle_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 683bede73d5..124cf21a221 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -581,6 +581,11 @@ static void __init omap4_panda_map_io(void)
omap44xx_map_common_io();
}
+static const char *omap4_panda_match[] = {
+ "ti,omap4-panda",
+ NULL,
+};
+
MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
/* Maintainer: David Anders - Texas Instruments Inc */
.atag_offset = 0x100,
@@ -590,4 +595,5 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
.init_irq = gic_init_irq,
.init_machine = omap4_panda_init,
.timer = &omap4_timer,
+ .dt_compat = omap4_panda_match,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index e592fb134c4..0fccc7b0d38 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -560,6 +560,11 @@ static void __init overo_init(void)
"OVERO_GPIO_USBH_CPEN\n");
}
+static const char *omap3_overo_dt_match[] = {
+ "gumstix,omap3-overo",
+ NULL
+};
+
MACHINE_START(OVERO, "Gumstix Overo")
.atag_offset = 0x100,
.reserve = omap_reserve,
@@ -568,4 +573,5 @@ MACHINE_START(OVERO, "Gumstix Overo")
.init_irq = omap3_init_irq,
.init_machine = overo_init,
.timer = &omap3_timer,
+ .dt_compat = omap3_overo_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot
index c7e75acfe6c..c08ab6da090 100644
--- a/arch/arm/mach-versatile/Makefile.boot
+++ b/arch/arm/mach-versatile/Makefile.boot
@@ -2,3 +2,5 @@
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
+dtb-$(CONFIG_MACH_VERSATILE_DT) += versatile-pb.dtb
+dtb-$(CONFIG_MACH_VERSATILE_DT) += versatile-ab.dtb
diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot
index 07c2d9c457e..9920a1053e2 100644
--- a/arch/arm/mach-vexpress/Makefile.boot
+++ b/arch/arm/mach-vexpress/Makefile.boot
@@ -1,3 +1,5 @@
zreladdr-y := 0x60008000
params_phys-y := 0x60000100
initrd_phys-y := 0x60800000
+
+dtb-$(CONFIG_ARCH_VEXPRESS_CA9X4) += vexpress.dtb
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 1fafc324460..f9c47defaa8 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -442,6 +442,11 @@ static void __init v2m_init(void)
ct_desc->init_tile();
}
+static const char *vexpress_dt_match[] __initdata = {
+ "arm,vexpress",
+ NULL,
+};
+
MACHINE_START(VEXPRESS, "ARM-Versatile Express")
.atag_offset = 0x100,
.map_io = v2m_map_io,
@@ -449,4 +454,5 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
.init_irq = v2m_init_irq,
.timer = &v2m_timer,
.init_machine = v2m_init,
+ .dt_compat = vexpress_dt_match,
MACHINE_END
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 3ff22e32b60..b970562e011 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -17,14 +17,39 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+static LIST_HEAD(aliases_lookup);
+
struct device_node *allnodes;
struct device_node *of_chosen;
+struct device_node *of_aliases;
+
+static DEFINE_MUTEX(of_aliases_mutex);
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
@@ -632,6 +657,35 @@ int of_property_read_u32_array(const struct device_node *np,
EXPORT_SYMBOL_GPL(of_property_read_u32_array);
/**
+ * of_property_read_u64 - Find and read a 64 bit integer from a property
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ *
+ * Search for a property in a device node and read a 64-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64(const struct device_node *np, const char *propname,
+ u64 *out_value)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if (sizeof(*out_value) > prop->length)
+ return -EOVERFLOW;
+ *out_value = of_read_number(prop->value, 2);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u64);
+
+/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
@@ -988,3 +1042,99 @@ out_unlock:
}
#endif /* defined(CONFIG_OF_DYNAMIC) */
+static void of_alias_add(struct alias_prop *ap, struct device_node *np,
+ int id, const char *stem, int stem_len)
+{
+ ap->np = np;
+ ap->id = id;
+ strncpy(ap->stem, stem, stem_len);
+ ap->stem[stem_len] = 0;
+ list_add_tail(&ap->link, &aliases_lookup);
+ pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
+ ap->alias, ap->stem, ap->id, np ? np->full_name : NULL);
+}
+
+/**
+ * of_alias_scan - Scan all properties of 'aliases' node
+ *
+ * The function scans all the properties of 'aliases' node and populate
+ * the the global lookup table with the properties. It returns the
+ * number of alias_prop found, or error code in error case.
+ *
+ * @dt_alloc: An allocator that provides a virtual address to memory
+ * for the resulting tree
+ */
+void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
+{
+ struct property *pp;
+
+ of_chosen = of_find_node_by_path("/chosen");
+ if (of_chosen == NULL)
+ of_chosen = of_find_node_by_path("/chosen@0");
+ of_aliases = of_find_node_by_path("/aliases");
+ if (!of_aliases)
+ return;
+
+ for_each_property(pp, of_aliases->properties) {
+ const char *start = pp->name;
+ const char *end = start + strlen(start);
+ struct device_node *np;
+ struct alias_prop *ap;
+ int id, len;
+
+ /* Skip those we do not want to proceed */
+ if (!strcmp(pp->name, "name") ||
+ !strcmp(pp->name, "phandle") ||
+ !strcmp(pp->name, "linux,phandle"))
+ continue;
+
+ np = of_find_node_by_path(pp->value);
+ if (!np)
+ continue;
+
+ /* walk the alias backwards to extract the id and work out
+ * the 'stem' string */
+ while (isdigit(*(end-1)) && end > start)
+ end--;
+ len = end - start;
+
+ if (kstrtoint(end, 10, &id) < 0)
+ continue;
+
+ /* Allocate an alias_prop with enough space for the stem */
+ ap = dt_alloc(sizeof(*ap) + len + 1, 4);
+ if (!ap)
+ continue;
+ ap->alias = start;
+ of_alias_add(ap, np, id, start, len);
+ }
+}
+
+/**
+ * of_alias_get_id - Get alias id for the given device_node
+ * @np: Pointer to the given device_node
+ * @stem: Alias stem of the given device_node
+ *
+ * The function travels the lookup table to get alias id for the given
+ * device_node and alias stem. It returns the alias id if find it.
+ */
+int of_alias_get_id(struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = -ENODEV;
+
+ mutex_lock(&of_aliases_mutex);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (strcmp(app->stem, stem) != 0)
+ continue;
+
+ if (np == app->np) {
+ id = app->id;
+ break;
+ }
+ }
+ mutex_unlock(&of_aliases_mutex);
+
+ return id;
+}
+EXPORT_SYMBOL_GPL(of_alias_get_id);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 65200af29c5..aeec35bc378 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -707,10 +707,8 @@ void __init unflatten_device_tree(void)
__unflatten_device_tree(initial_boot_params, &allnodes,
early_init_dt_alloc_memory_arch);
- /* Get pointer to OF "/chosen" node for use everywhere */
- of_chosen = of_find_node_by_path("/chosen");
- if (of_chosen == NULL)
- of_chosen = of_find_node_by_path("/chosen@0");
+ /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */
+ of_alias_scan(early_init_dt_alloc_memory_arch);
}
#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 9f689f1da0f..6a5b5e777dd 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -58,27 +58,27 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
*/
struct device_node *of_irq_find_parent(struct device_node *child)
{
- struct device_node *p;
+ struct device_node *p, *c = child;
const __be32 *parp;
- if (!of_node_get(child))
+ if (!of_node_get(c))
return NULL;
do {
- parp = of_get_property(child, "interrupt-parent", NULL);
+ parp = of_get_property(c, "interrupt-parent", NULL);
if (parp == NULL)
- p = of_get_parent(child);
+ p = of_get_parent(c);
else {
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
p = of_node_get(of_irq_dflt_pic);
else
p = of_find_node_by_phandle(be32_to_cpup(parp));
}
- of_node_put(child);
- child = p;
+ of_node_put(c);
+ c = p;
} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
- return p;
+ return (p == child) ? NULL : p;
}
/**
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
index 4d87b5dc928..bc5b3990f6e 100644
--- a/drivers/of/pdt.c
+++ b/drivers/of/pdt.c
@@ -229,6 +229,11 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
return ret;
}
+static void *kernel_tree_alloc(u64 size, u64 align)
+{
+ return prom_early_alloc(size);
+}
+
void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
{
struct device_node **nextp;
@@ -245,4 +250,7 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
nextp = &allnodes->allnext;
allnodes->child = of_pdt_build_tree(allnodes,
of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
+
+ /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */
+ of_alias_scan(kernel_tree_alloc);
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index ed5a6d3c26a..b22f8873a41 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -345,6 +345,7 @@ static int of_platform_bus_create(struct device_node *bus,
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
+ int id = -1;
int rc = 0;
/* Make sure it has a compatible property */
@@ -357,6 +358,7 @@ static int of_platform_bus_create(struct device_node *bus,
auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata->name;
+ id = auxdata->id;
platform_data = auxdata->platform_data;
}
@@ -366,6 +368,11 @@ static int of_platform_bus_create(struct device_node *bus,
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
+
+ /* override the id if auxdata gives an id */
+ if (id != -1)
+ dev->id = id;
+
if (!dev || !of_match_node(matches, bus))
return 0;
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 60e049b041a..af46c56080d 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/console.h>
+#include <linux/of.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
@@ -472,8 +473,6 @@ static struct of_device_id altera_jtaguart_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
-#else
-#define altera_jtaguart_match NULL
#endif /* CONFIG_OF */
static struct platform_driver altera_jtaguart_platform_driver = {
@@ -482,7 +481,7 @@ static struct platform_driver altera_jtaguart_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = altera_jtaguart_match,
+ .of_match_table = of_match_ptr(altera_jtaguart_match),
},
};
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 50bc5a5ac65..0abd31d2361 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -616,8 +616,6 @@ static struct of_device_id altera_uart_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, altera_uart_match);
-#else
-#define altera_uart_match NULL
#endif /* CONFIG_OF */
static struct platform_driver altera_uart_platform_driver = {
@@ -626,7 +624,7 @@ static struct platform_driver altera_uart_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = altera_uart_match,
+ .of_match_table = of_match_ptr(altera_uart_match),
},
};
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 7e91b3d368c..99898773706 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1286,17 +1286,20 @@ static int serial_imx_resume(struct platform_device *dev)
static int serial_imx_probe_dt(struct imx_port *sport,
struct platform_device *pdev)
{
- static int portnum = 0;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(imx_uart_dt_ids, &pdev->dev);
+ int ret;
if (!np)
return -ENODEV;
- sport->port.line = portnum++;
- if (sport->port.line >= UART_NR)
- return -EINVAL;
+ ret = of_alias_get_id(np, "serial");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+ return -ENODEV;
+ }
+ sport->port.line = ret;
if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
sport->have_rtscts = 1;
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 8af1ed83a4c..0aed022d21b 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -568,8 +568,6 @@ static struct of_device_id ulite_of_match[] __devinitdata = {
{}
};
MODULE_DEVICE_TABLE(of, ulite_of_match);
-#else /* CONFIG_OF */
-#define ulite_of_match NULL
#endif /* CONFIG_OF */
static int __devinit ulite_probe(struct platform_device *pdev)
@@ -609,7 +607,7 @@ static struct platform_driver ulite_platform_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "uartlite",
- .of_match_table = ulite_of_match,
+ .of_match_table = of_match_ptr(ulite_of_match),
},
};
diff --git a/include/linux/of.h b/include/linux/of.h
index 9180dc5cb00..92c40a14224 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -68,6 +68,7 @@ struct device_node {
/* Pointer for first entry in chain of all nodes. */
extern struct device_node *allnodes;
extern struct device_node *of_chosen;
+extern struct device_node *of_aliases;
extern rwlock_t devtree_lock;
static inline bool of_have_populated_dt(void)
@@ -199,6 +200,8 @@ extern int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values,
size_t sz);
+extern int of_property_read_u64(const struct device_node *np,
+ const char *propname, u64 *out_value);
extern int of_property_read_string(struct device_node *np,
const char *propname,
@@ -209,6 +212,9 @@ extern int of_device_is_available(const struct device_node *device);
extern const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp);
+#define for_each_property(pp, properties) \
+ for (pp = properties; pp != NULL; pp = pp->next)
+
extern int of_n_addr_cells(struct device_node *np);
extern int of_n_size_cells(struct device_node *np);
extern const struct of_device_id *of_match_node(
@@ -221,6 +227,9 @@ extern int of_parse_phandles_with_args(struct device_node *np,
const char *list_name, const char *cells_name, int index,
struct device_node **out_node, const void **out_args);
+extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
+extern int of_alias_get_id(struct device_node *np, const char *stem);
+
extern int of_machine_is_compatible(const char *compat);
extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -235,6 +244,7 @@ extern void of_attach_node(struct device_node *);
extern void of_detach_node(struct device_node *);
#endif
+#define of_match_ptr(_ptr) (_ptr)
#else /* CONFIG_OF */
static inline bool of_have_populated_dt(void)
@@ -242,6 +252,22 @@ static inline bool of_have_populated_dt(void)
return false;
}
+#define for_each_child_of_node(parent, child) \
+ while (0)
+
+static inline int of_device_is_compatible(const struct device_node *device,
+ const char *name)
+{
+ return 0;
+}
+
+static inline struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp)
+{
+ return NULL;
+}
+
static inline int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values, size_t sz)
@@ -263,6 +289,21 @@ static inline const void *of_get_property(const struct device_node *node,
return NULL;
}
+static inline int of_property_read_u64(const struct device_node *np,
+ const char *propname, u64 *out_value)
+{
+ return -ENOSYS;
+}
+
+static inline struct device_node *of_parse_phandle(struct device_node *np,
+ const char *phandle_name,
+ int index)
+{
+ return NULL;
+}
+
+#define of_match_ptr(_ptr) NULL
+#define of_match_node(_matches, _node) NULL
#endif /* CONFIG_OF */
static inline int of_property_read_u32(const struct device_node *np,
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 5a6f458a4bb..0c53ecbd937 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -45,13 +45,18 @@ struct of_dev_auxdata {
char *compatible;
resource_size_t phys_addr;
char *name;
+ int id;
void *platform_data;
};
/* Macro to simplify populating a lookup table */
#define OF_DEV_AUXDATA(_compat,_phys,_name,_pdata) \
{ .compatible = _compat, .phys_addr = _phys, .name = _name, \
- .platform_data = _pdata }
+ .id = -1, .platform_data = _pdata }
+
+#define OF_DEV_AUXDATA_ID(_compat,_phys,_name,_id,_pdata) \
+ { .compatible = _compat, .phys_addr = _phys, .name = _name, \
+ .id = _id, .platform_data = _pdata }
/**
* of_platform_driver - Legacy of-aware driver for platform devices.