[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
|
|
Subscribe / Log in / New account

Platform devices and device trees

By Jonathan Corbet
June 21, 2011
The first part of this pair of articles described the kernel's mechanism for dealing with non-discoverable devices: platform devices. The platform device scheme has a long history and is heavily used, but it has some disadvantages, the biggest of which is the need to instantiate these devices in code. There are alternatives coming into play, though; this article will describe how platform devices interact with the device tree mechanism.

The current platform device mechanism is relatively easy to use for a developer trying to bring up Linux on a new system. It's just a matter of creating the descriptions for the devices present on that system and registering all of the devices at boot time. Unfortunately, this approach leads to the proliferation of "board files," each of which describes a single type of computer. Kernels are typically built around a single board file and cannot boot on any other type of system. Board files sort of worked when there were relatively small numbers of embedded system types to deal with. Now Linux-based embedded systems are everywhere, architectures which have typically depended on board files (ARM, in particular) are finding their way into more types of systems, and the whole scheme looks poised to collapse under its own weight.

The hoped-for solution to this problem goes by the term "device trees"; in essence, a device tree is a textual description of a specific system's hardware configuration. The device tree is passed to the kernel at boot time; the kernel then reads through it to learn about what kind of system it is actually running on. With luck, device trees will abstract the differences between systems into boot-time data and allow generic kernels to run on a much wider variety of hardware.

This article is a good introduction to the device tree format and how it can be used to describe real-world systems; it is recommended reading for anybody interested in the subject.

It is possible for platform devices to work on a device-tree-enabled system with no extra work at all, especially once Grant Likely's improvements are merged. If the device tree includes a platform device (where such devices, in the device tree context, are those which are direct children of the root or are attached to a "simple bus"), that device will be instantiated and matched against a driver. The memory-mapped I/O and interrupt resources will be marshalled from the device tree description and made available to the device's probe() function in the usual way. The driver need not know that the device was instantiated out of a device tree rather than from a hard-coded platform device definition.

Life is not always quite that simple, though. Device names appearing in the device tree (in the "compatible" property) tend to take a standardized form which does not necessarily match the name given to the driver in the Linux kernel; among other things, device trees really are meant to work with more than one operating system. So it may be desirable to attach specific names to a platform device for use with device trees. The kernel provides an of_device_id structure which can be used for this purpose:

    static const struct of_device_id my_of_ids[] = {
	{ .compatible = "long,funky-device-tree-name" },
	{ }
    };

When the platform driver is declared, it stores a pointer to this table in the driver substructure:

    static struct platform_driver my_driver = {
	/* ... */
	.driver	= {
		.name = "my-driver",
		.of_match_table = my_of_ids
 	}
    };

The driver can also declare the ID table as a device table to enable autoloading of the module as the device tree is instantiated:

    MODULE_DEVICE_TABLE(of, my_of_ids);

The one other thing capable of complicating the situation is platform data. Needless to say, the device tree code is unaware of the specific structure used by a given driver for its platform data, so it will be unable to provide that information in that form. On the other hand, the device tree mechanism is equipped to allow the passing of just about any information that the driver may need to know. Making use of that information will require the driver to become a bit more aware of the device tree subsystem, though.

Drivers expecting platform data should check the dev.platform_data pointer in the usual way. If there is a non-null value there, the driver has been instantiated in the traditional way and device tree does not enter into the picture; the platform data should be used in the usual way. If, however, the driver has been instantiated from the device tree code, the platform_data pointer will be null, indicating that the information must be acquired from the device tree directly.

In this case, the driver will find a device_node pointer in the platform devices dev.of_node field. The various device tree access functions (of_get_property(), primarily) can then be used to extract the needed information from the device tree. After that, it's business as usual.

In summary: making platform drivers work with device trees is a relatively straightforward task. It is mostly a matter of getting the right names in place so that the binding between a device tree node and the driver can be made, with a bit of additional work required in cases where platform data is in use. The nice result is that the static platform_device declarations can go away, along with the board files that contain them. That should, eventually, allow the removal of a bunch of boilerplate code from the kernel while simultaneously making the kernel more flexible.

Index entries for this article
KernelDevice tree
KernelPlatform data


to post comments

Platform devices and device trees

Posted Jun 23, 2011 3:54 UTC (Thu) by neilbrown (subscriber, #359) [Link] (1 responses)

> struct of_device_id

I thought "it is a bit odd starting an identifier with a preposition" .... but then the answer floated up from long distant memories: "Open Firmware" - it isn't a preposition at all, it is an abbreviation!

Platform devices and device trees

Posted Jun 23, 2011 22:26 UTC (Thu) by glikely (subscriber, #39601) [Link]

And it's a horrid abbreviation to use for that exact reason. "ofw_" would have been better. I've been toying with doing a mass rename to "dt_*", but doing a mass rename is another level of pain I don't really want to deal with.

Platform devices and device trees

Posted Jun 23, 2011 13:10 UTC (Thu) by etienne (guest, #25256) [Link] (12 responses)

I understand that "device trees" is the way everybody is going, but I just want to say few things:
- there does not seem to be any "device trees" checker, so that errors are found at execution time and not compilation/link time.
- the kernel, at the time it is analysing the "device trees", is still looking for its serial port or permanent storage, so it cannot display or store any kind of error/warning message.
- in an area where kernels are often seriously patched (embedded), a construct may be valid for a stock kernel but not parse-able by a modified kernel.

One way to solve the problem may be to parse-check and insert a section of the ELF file to represent the device tree, but I am not sure if it is more interesting to tell the linker that "this device is not present, that device is at address 0x333444, ..." so that the linker can remove parts of code and optimise others.
You still can have a single pre-linked kernel in this case, it just has some relocation to sort out (and relocation to NULL could be handled specially by the linker) - but still a single kernel.

Another way to handle the problem would be to have a device tree checker in "Das U-boot", but I am not sure we want to complexify the boot code because it is difficult to handle errors at this point (run a text editor?).
There isn't any program run (like LILO or GRUB config manager) when the boot configuration is changed so no device tree check there.

Moreover, boards with system-on-chip processor have a constant part due to the system-on-chip used, and it would probably be better to keep the system-on-chip description (big but limited number) separate of the one of the board (unlimited).
Then, we could even dream of the system on chip provider giving a complete and valid description of their product as open source...

Just my £0.02...

Platform devices and device trees

Posted Jun 23, 2011 15:14 UTC (Thu) by krisis (guest, #70792) [Link] (9 responses)

I'm not entirely familiar with device trees, so don't take anything I say as gospel, but I believe there is a binary format for device trees that is compiled from the traditional device tree, that the kernel can also take.

Platform devices and device trees

Posted Jun 23, 2011 19:33 UTC (Thu) by glikely (subscriber, #39601) [Link] (8 responses)

The kernel only accepts the tokenized (dtb) from produced by the device tree compiler. The textual source form (dts) is designed to be editable by mere mortals.

Platform devices and device trees

Posted Jun 23, 2011 22:07 UTC (Thu) by krisis (guest, #70792) [Link] (7 responses)

Continuing the subject of me not knowing enough about device trees, Now that there is a knowledgeable person present, I might as well ask :)

I work on an embedded platform with a DM9000 ethernet controller. This particular controller can either get its MAC address from an attached EEPROM or it can be set via the platform_data mechanism. As a cost saving measure, there is no EEPROM attached to the controller on this board, so in order to get a MAC address, we pull the die ID from the CPU during boot and use that to initialize the MAC address in the device struct before we pass it to the driver core.

Is there a mechanism to enable these sort of hacks with device trees and if so, how?

Platform devices and device trees

Posted Jun 23, 2011 22:11 UTC (Thu) by glikely (subscriber, #39601) [Link] (5 responses)

In the device tree node for the MAC, add a "local-mac-address" property containing the desired MAC address. The DM9000 driver can be easily modified to obtain this value at .probe time by calling of_get_mac_address().

Platform devices and device trees

Posted Jun 23, 2011 22:28 UTC (Thu) by krisis (guest, #70792) [Link] (4 responses)

Wouldn't that just set the MAC address to a fixed value for all of my boards?

The hack is that I'm getting a unique MAC address for each of the boards by using the unique-per-cpu die ID, which I pull during board setup.

(The code for this hack is in arch/arm/mach-omap2/board-devkit8000.c if anyone wants to have a look. It's the omap_dm9000_init function)

Platform devices and device trees

Posted Jun 23, 2011 22:37 UTC (Thu) by glikely (subscriber, #39601) [Link] (3 responses)

Wouldn't that just set the MAC address to a fixed value for all of my boards? The hack is that I'm getting a unique MAC address for each of the boards by using the unique-per-cpu die ID, which I pull during board setup.

The model pretty much assumes that the DT data is complete and accurate by the time it is passed to the kernel. If you need to do machine-specific hacks, there is little recourse but but to have machine specific setup code. DT doesn't change the situation in that regard. If really necessary, there is a way to attach supplemental platform_data to devices registered from the DT, but it is discouraged.

However, the DT can be dynamically modified to squirt in the mac address either by the boot loader (U-Boot) or when the .dtb is installed on the board. You don't need to have a separate .dts for each board with a different MAC address.

(The code for this hack is in arch/arm/mach-omap2/board-devkit8000.c if anyone wants to have a look. It's the omap_dm9000_init function)
Nice. I have a devkit8000, but I could never get a modern kernel to boot on the thing.

Platform devices and device trees

Posted Jun 24, 2011 0:28 UTC (Fri) by dlang (guest, #313) [Link] (2 responses)

this is a common enough issue that it may be worth defining a 'magic' MAC address (all 0's??) and if you see that going through a list of steps to create a MAC address (ending with generate something random). Ideally each step on this list could fail cleanly so all such checks could be gathered into one 'I have no real MAC address, generate one' routine.

Platform devices and device trees

Posted Jun 24, 2011 18:47 UTC (Fri) by broonie (subscriber, #7078) [Link] (1 responses)

It's extremely common and the kernel is already doing stuff to handle the case where it can't get a MAC address at all. The issue here is not that there's no MAC address, it's that the MAC is being shipped in a non-standard location (eg, a bootloader variable) and we need a way to hand that value to the chip. Once the kernel has the data there's not much problem.

Platform devices and device trees

Posted Jun 24, 2011 22:17 UTC (Fri) by dlang (guest, #313) [Link]

in reading the post, it sounded to me like he had special code in the driver so that if there was no eeprom with the MAC address, he would generate it from the cpuid.

yes, it would be nice for the code to look in the device tree to see if there is a MAC address provided.

but if there isn't, he shouldn't have special case code in that one driver to calculate the MAC, he should call the general case code to handle the case where there is no MAC (and come to think of it, that general case code should probably be what is taught to look in the device tree for the MAC)

Platform devices and device trees

Posted Jun 24, 2011 11:13 UTC (Fri) by etienne (guest, #25256) [Link]

I have to admit that my comment was not knowledgeable enough, my device tree memory from the PPC world is already old, and I am currently bothered by this ARM demo board refusing to boot (i.e. display the first line) of a Linux kernel compiled from the kernel.org tree.
Last time it happened in the PPC world was when the device tree file was not correctly loaded in memory or loaded to the wrong RAM address/from the wrong FLASH address or corrupted.
I have read here on LVN about a patch to insert the device tree in the kernel file, so that would sort out this kind of problem.
I am still puzzled by the fact that the ARM processor I am using is completely defined, all its device address are fixed - up to the point that I have a CPU choice in the kernel menuconfig (CONFIG_ARCH_TI816X=y), yet the future would be a kernel file with variable device addresses to be resolved at run time from another file. (resolving at link time would be fine)
Now I shut up, my current problem is obviously not device tree - I have to look again at u-boot config.

Platform devices and device trees

Posted Jun 23, 2011 20:04 UTC (Thu) by klossner (subscriber, #30046) [Link]

The device tree source code is compiled by the dtc tool to the compact binary form expected by the of_xxx() routines. The tool finds and publicizes errors, albeit sometimes with cryptic messages.

My current work is with products that use u-boot as the bootloader. u-boot takes the binary device tree, adds decorations to reflect the hardware (e.g., describing the amount of installed system RAM), then passes it to the Linux kernel.

It's true that a single system-on-chip processor has a constant part. But it may be one of a large family of such chips. It can be easier to describe the individual components of the SOC in the device tree (e.g., there are PCI Express ports at addresses X and Y and an Ethernet port at Z) than to prepare a code module for each chip.

Platform devices and device trees

Posted Jun 23, 2011 20:53 UTC (Thu) by glikely (subscriber, #39601) [Link]

- there does not seem to be any "device trees" checker, so that errors are found at execution time and not compilation/link time.

The device tree compiler (dtc) does some semantic checking. It is limited, but adding more semantic checking is definitely welcome and encouraged.

- the kernel, at the time it is analysing the "device trees", is still looking for its serial port or permanent storage, so it cannot display or store any kind of error/warning message.

At least on ARM, if you're debugging, the low level debug code can select an output device at kernel build time and get output even in the startup assembly code. Well before even looking at the DT data.

- in an area where kernels are often seriously patched (embedded), a construct may be valid for a stock kernel but not parse-able by a modified kernel.

Not sure what the argument is here. Yes, out of tree code is often filled with unconventional hacks that don't survive by the time they hit mainline. However, once DT bindings are mainlined, we try *really hard* not to break them. On of the requirements for merging DT parsing code is that it must also document any new bindings in the Documentation directory.

Moreover, boards with system-on-chip processor have a constant part due to the system-on-chip used, and it would probably be better to keep the system-on-chip description (big but limited number) separate of the one of the board (unlimited).

The device tree compiler has an include mechanism so that multiple board .dts files can include a single SoC .dts description. The SoC description is indeed static, and any number of boards can be build off of it. I did consider a scheme of passing multiple dtbs to the kernel, one for configuration, one for board layout, one for SoC layout, etc, but figuring out how to get the kernel to manage the separated blobs was worse overall. Instead, it is handled in the dts source form and merged into a single dtb by dtc.

Platform devices and device trees

Posted Jun 24, 2011 18:58 UTC (Fri) by giraffedata (guest, #1954) [Link]

Device names appearing in the device tree (in the "compatible" property)

I believe those are names of device types, not of devices.

It's important not to confuse the object with the class.


Copyright © 2011, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds