 Hello, good morning. I guess it's time to get started. So before I get started with the talk, how many people have already written some device refragments? Yeah, quite a few, maybe like a third of the room. Okay. Not successfully. Okay. So in this talk at the title suggests, I'm going to try to go from the basics and introduce what is the device tree, what's the main idea, and help you understand the syntax of the device tree and hopefully a little bit the spirit of the device tree. As a disclaimer, I'm by far not a device tree guru. All the talk is based on what I've learned in the field doing some ARM development. So obviously it's all ARM stuff. It should have been in the subtitle probably, but it's all ARM related. I don't know how the device tree is used on other architectures, but at the moment I guess most of the code is probably going to be interested in ARM specific things. So it's really, I'm really not a device tree guru. I will try not to make too many inaccuracies, but there might be some. I will just try to share how I see the device tree today. Just a few words. I'm Thomas. I work for Free Elections. We do training and development, and the reason why I gained some device tree experience over the last year and a half is because we've been involved in mainlining the support for the Armada 370 and Armada XP SOCs for Marvel. So those SOCs are used mainly in NAS devices, and we've pushed the support for those SOCs into the mainline channel, and it was all based on device tree from day zero. So we've done a lot of device related work around that, and I also happened to work on Build Boot as a side project. So today I first want to start with the user perspective. So not the channel developer, but the user. The device tree is changing in terms of how you boot the channel. So it's going to be a fairly short section. Then goes through the basic device tree syntax. See a simple example of a device tree. Then the overall organization. So after looking at the very simple fragment, overall what's the organization of the different nodes and sub nodes that we have in the device tree. And then we'll go through different examples of device tree and we'll talk about different bindings. I mentioned like clocks and pin control and introps and things like that. Just to give you a feeling of how the device tree is being used today, and then end up with some general consideration about device tree bindings design. So before the device tree, when you wanted to use a channel on ARM, the channel was completely containing the entire description of the hardware in terms of C-based structures, describing all the platform devices, the I-square C devices, the SPI devices. So the channel was, I would say, self-sufficient. You had a single binary. You image the image, whatever image type you're using. Your bootloader puts that into memory. It starts it. And before starting it, it gives it a few information. The machine number in register R1 and an ATACS set of information. So it's kind of a data structure that the bootloader builds with information such as the memory location and size, the channel command line and a bunch of other things. And passes that to the channel, which finds it at some location passed in R2. Passes that. But most of the, if not all of the hardware description was inside the channel itself. So it's pretty much what you had, a new image, just the ATACS information passed by the bootloader, and that's it. So what the device tree changes is that the description of the hardware moves into a separate binary blob that's a new file, an additional file, next to your channel image. So in addition to your U-image or Z-image, you have one of those files that ends with a DTB extension, which is the binary-compiled version of the device tree, describing the hardware platform. And the bootloader will actually load two things into memory. On one side, the channel image, as it used to do, and also the binary blob. And will pass the address of this binary blob to the channel, which will parse it to find out what's the hardware available on this particular platform. So it replaces the machine-type idea. It no longer exists, and the channel really bases all its hardware discovery strategy on the device tree. So that's the change on the user perspective. So yeah, basically instead of ATACS that were limited to describing a very limited set of information, we now have a much more complicated data structure with a lot more information, and that is being passed to the channel. So that's nice, but it requires a device tree capability at the bootloader level. As you've noticed here below, I've mentioned how to boot a device tree capable channel from the bootloader bus from U-boot and Burrbox. So the bootloader needs to be aware of that, needs to be aware of this change in the protocol between the bootloader and the channel. And it happens that not all bootloaders that are available today on platforms, on existing platforms do support that. So yes, U-boot and Burrbox in their mainline version do support that, but as most of you probably know, many of the platforms around have some crazy vendor bootloaders that have been written years ago, and they are not going to change really soon. For some vendors, it's in the process of being done. For others, it's already done, but you don't necessarily have a device tree capable bootloader. So to solve this problem, the channel developers have added a compatibility mode, which is called the appended DTB. And the idea is that to make the bootloader believe that there is still only one single channel image filed to load into memory. But in fact, this channel image is actually the channel image itself to which you append the DTB, which is the binary version of the device tree. And the way you do that is just with CAD or whatever tool you like to do this. And then you give your bootloader this thing. It doesn't know it has a device tree. But since you've built the channel with this configuration option, config arm appended DTB, the channel will look after the channel image, find that there is a DTB, and use that as the hardware description. And from that point on, it's exactly similar as if you had a device tree capable bootloader. There is also an additional option, attack DTB compact, which tells the channel, read the attacks information that are passed by the bootloader. So normally if your bootloader is DT capable, no longer attacks. But since your bootloader is in that case not DT capable, it's still passing some attacks, including the channel command line and the memory location and size. And the channel is capable of reading out those information and patching the device tree so that from the channel point of view it's just as if the bootloader was device tree capable. So that's the idea from the user's perspective. That's the change. Now what's exactly is the device tree. So to help me introduce the device tree, I just copy pasted a bunch of fragments from the standard for embedded poor architecture platform requirements, which is actually the, I guess the formal documents that describes what is the device tree, the syntax and its meaning. I found it quite hard to read originally. I guess it takes a little bit of experience with the device tree to actually understand what this document is saying. But when you read it again and again and again, it's hard to make sense after a while. So what this document specifies is the concept called the device tree, which describes the system hardware. A boot program, as I was saying, loads that into the memory and passes that to the client, which in our case is Linux, and this client is going to use that to know what's the hardware available. So device tree is a tree data structure as the name suggests with nodes that describe different elements in your system. It's actually being used to describe the hardware that cannot be dynamically detected. So we are typically not going to describe USB devices or PCI devices in the device tree, because you have mechanisms to enumerate them dynamically. But we're going to describe all those platform devices, I2C, SPI, that are not dynamically discoverable. The basic syntax is actually I would say quite simple, but maybe it's just because I became used to it. So it's a tree of nodes. Each node has a name, which is here and a unit address, which is typically used to uniquely identify different nodes having the same name, and it's normally used for the memory address at which this device is mapped for memory map devices. And then each node can have a number of properties and can have a number of subnodes. And so the device tree syntax does not impose any specific name for the properties, any specific value, it's just a very simple language, and you can use whatever property name you want, whatever node name you want, how many subnodes you want, and so on. So the language is actually pretty simple. Each property can have different types of values, there are integer values, there are Boolean properties, there are string properties, there are also properties that point to another node, that's what we call a p-handle in the device tree language. So actually a device can reference another device, and we're going to see a practical example of that. You can have child nodes to describe things that you are managing. So one typical example is you have an I2C controller, and then this I2C controller allows you to access an I2C bus, and the devices that sit on that bus are going to be child nodes of the I2C controller node. I'm going to show such an example. Some nodes can have labels, and labels are the name that's used for p-handle. So it's a shortcut for pointing to a specific node. So basically the syntax of the device tree itself is, I would say, pretty simple. The complexity comes from giving it a meaning. How do you go from this source representation to binary? So on ARM, all the device tree source files at the moment are located in ARCH ARM boot DTS. So this directory is growing in size quite quickly. I made a graph that I could have included, but it's really growing like crazy, due to the number of platforms being converted. And we basically have two files with two different extensions in there. We have DTSI files where DTSI stands for includes and final DTS files. So the final DTS files are usually the one that describes board level information and that are the one combined into DTBs. And they generally include one or several DTSI that describe information from the SOC or that are shared between multiple boards. So the idea is that instead of duplicating information if you have one SOC used by 20 boards, all the SOC level information is stored in a DTSI which can be included in several DTS files. Then we have a tool, the device tree compiler or DTC that is located in Scripps DTC that is used to take DTS file and then resolve all the included files and turn that into a packed binary format that your boot loader and the channel can actually understand. And what it produces is the DTB or device tree blow. That is actually what gets manipulated again by your loader and your channel. And you don't necessarily usually have to worry about building the DTB yourself because in this very directory Archambu DTS there is a make file which tells for each platform, so for each ARM sub architecture, in that case here it's the Marvel platform I've been working on which lists all the DTBs that should be built. So generally you have a list sometimes quite huge list of all the boards that are part of this platform and so whenever you're going to build the channel for this platform it's going to build all the DTBs for all those boards and it will be your job to select the correct DTB and put that into your boot loader and start your system. So now a simple real example of one node of a device tree. So I've taken one from the IMX28 DTSI so it's SOC level information and some other things. So we have a label AUR0 and then the node name it's serial at some address and the address you need address here just for well clarity is the same as the address where the registers of this device are available into memory but it's actually doesn't it's not very important this part here you could have used 0, 1, 4, 24 or anything what's really important is what we have in this property the first property compatible is probably the most important one and the most complex one to understand so I'm going to talk several times about it over this presentation what the EPAPR says is that it defines the programming model for the device well what that means so basically it allows the operating system to identify which driver should be responsible for driving this device so there will be a direct match between a direct connection between the compatible string being chosen and the driver that is going to be bound to this very device. Then we have the reg property which gives the for memory mapped devices where it's available in memory we have the intrap number we can have potentially several of them here we have references to DMA channels and that's interesting because as you can see this property here has a list of two values and these values are P-handles so they are pointing to some other node which actually is going to be the DMA engine on this platform and in addition it's kind of passing an argument to this P-handle in some ways so it's saying yeah okay for DMA I'm going to use DMA engine 8 okay I don't know what that means exactly at the moment and DMA engine 9 and in fact it's going to be used by the DMA engine API to know which DMA channel this specific hardware block is going to use so it's going to be using 8 or 9 and to make lookup easier in the driver it's also associating names to each entry in this list so it's saying Rx is this one and Tx is this one so I know it's not necessarily well explicit but that's the way it works and this allows the channel APIs to allow you in the driver to say something like I want to get the Rx DMA channel and it's going to find out yeah okay Rx is the first one in the list so it's going to be this one and I'm going to give you a reference to this DMA channel so it's a bit weird but that's the way it works here we have more or less the same thing but we have only one element and it's just saying okay the clock for this device is part of this other node and the argument I'm passing is 45 that's a way of identifying this clock and in this DTSI file we're saying this device is disabled when status is disabled for a platform device it tells the channel not to probe that device and the reason is that in DTSI files usually you describe all the internal SoC devices but not necessarily all of them are used on a specific board so in the DTSI file for a specific board you're going to say this device I'm going to enable it so that it gets probed but if some other like UART is not wired on your specific board you're probably going to leave it disabled because there's no point in probing a device that's not being used on the driver side for this thing the driver now needs to say which devices it is capable of supporting and again that's done using this compatible string mechanism so a bit like in the old world the platform devices at the name which was used to match with the name of the driver and when they matched the probe function of the platform driver was called here it's when the compatible string is matching with a list of IDs that's inside the driver that's the driver probe function that's going to be called so whenever you have a platform driver function with the old style we were using this driver name so it had to match between platform device and platform driver and now we have an OF match table which points here to a list of tuples that give a compatible string and some private data and so when the channel is going to go through the device tree find all the devices find which driver matches your probe function if it matches it will find yeah there is a match and it will also allow you to retrieve this private data so this specific driver for example supports two variants of this UART so it supports two compatible strings but it has two different private data so that the driver can adapt to the small differences between those two variations of the hardware block that makes sense and in the probe function which is here the driver can actually fetch that private data by using the OF match device function so basically it's going to redo the matching for the platform device against the table and give you a pointer to which entry has actually matched this device so you can retrieve the private data and then your driver can act differently depending on the data that's available so a single driver can handle as many compatible strings as you want and it allows the driver to hide small differences or larger differences between variations of the same or a similar hardware block that's the idea of course if those differences are too important then maybe you need two different drivers that's the usual thing it doesn't change anything here but the single driver can expose and handle multiple compatible strings and act a little bit differently depending on the compatible string that's being passed on the C code point of view there isn't much change compared to normal platform devices because all of the APIs that were used or most of the APIs that were used by platform drivers to retrieve resources, clocks in RQs memory maps regions or DMA channels or anything like that all those APIs have gained a device tree support so they are automatically click going to do the right thing so for example you were doing platform get RQ in your driver and in the old world it was going into your platform device then resources and finding the RQ resource now it's finding the interrupts property in the device tree and providing that to you transparently same thing for platform get resource for the memory resource, same thing for the clock same thing for the DMA channels and here you see we have those names Rx and Tx and they will automatically be mapped to the right entry in the list of DMA channels for that device but of course there are some additional properties that you may add in your device tree that describe more precisely how the device is connected in your system or give some more specific information so there is a device tree specific API which usually is prefixed by OF and one example in this driver is that it supports an additional property called UART as RTSCTS which allows you to tell whether this UART as RTSCTS connected or not so that's a board specific information that you can add in this node here but not in the DTSI file because that's SOC level so you would most likely add that in the DTS file which describes the board and the driver gets to know whether this property is set or not by calling OF get property and there is a lot of other things you can do with OF functions like go through child nodes and there is a whole bunch of API functions that you can use they are usually quite simple so as I was saying until now there is a mechanism that allows you to include device trees into other device trees so DTSI files are included files and DTS files are final device trees and as I was saying usually DTSI contain SOC level information and DTS files contain board level information but the inclusion is interesting and I think it's one of the probably the strongest point of the device tree in my opinion is that the inclusion works by actually overlaying the different trees on top of each other so a DTSI file can set a property and it can be overridden by a DTS file that is including that DTSI so I'm going to take an example here and that actually comes from the canal so the canal has an AM33XX DTSI file to describe this TI SOC so there's a bunch of nodes and I've taken again the UART example and then there is one DTS file for the big old bone in that case it's the white big old bone the original one and as you can see the hierarchy of the nodes is exactly the same and it will actually put the second tree overlaid on top of the first one so if there is a new property here which is the case for the pin control names and pin control 0 property it's going to add them and if a property is present on BOSS which is the case for status here of course the including one is going to override the included one so at the end the real DTB that the canal is going to see is that one so of course the DTB is compiled it's kind of the virtual textual representation of that DTB but it's going to have the union of those properties with those one taking precedence over those ones if they are BOSS present and this works on several levels so for example on the SOCs I've worked on we have a family of SOCs they have many things in common but some things different so instead of being just one DTSI and per SOC and then DTS files for the boards we have a tree of DTSI files where we have all the common things for all SOCs in this DTSI and then progressively you refine the description of the hardware all the way to the boards so this is maybe going to add this one is a 4 core variant it has 4 gigabit interfaces and 10 PCI express interfaces for example this one is only a dual core with maybe 2 or 3 internet interfaces the device tree is describing progressively all those details all the way to the board which is going to describe how things are wired and the additional elements on the board so that's I believe it's really the strong point describing the hardware progressively with properties overlaying properties from the included device tree file now there is the concept of the binding basically the binding is how to make sense out of the properties as I was saying the device tree is just a language you can write whatever property you want like foobar equal blah blah and it's just going to compile fine there is absolutely no at the moment no tool, no mechanism to check whether the property you're using actually makes sense and exists so you can write whatever you want in the device tree but of course to make it useful you have to make sense out of a set of properties names, property values compatible strings and so on and that's what we call bindings so a binding is essentially a specification that says if you want to describe I don't know such or such even at interface you have to use this compatible string add this property with this value and these are the possible values add this other property with these other values and so on and so on so it's actually a binding is actually a specification it's not code it has to be implemented in one or several drivers that may follow the same binding so it has an implementation but the binding is really a specification so as the EPAPR says the bindings are our specific types and classes of devices are represented in the device tree and the compatible string is the key to identify which binding applies to a given node in the device tree that's how it works and a binding should be designed to allow the description of all the necessary hardware details that a driver will need to actually make use of that device and connect it with the other devices around if needed so the core part of the device tree bindings is actually documentation as I was saying and they are documented in documentation device tree bindings and there's a bunch of growing set of files in there it's a bit messy organization in there but it's you can find your way, Grap is your friend and basically whenever you add a new driver that introduces a binding in the canal you are required to write such a documentation usually it's pretty simple because for most devices it's quite simple for some other cases it gets really really crazy because the bindings are very complicated so you have the entire range all between nowadays all the new device tree bindings must be reviewed by the device tree maintainers so there is a dedicated mailing list so if you're interested in device tree discussions and very very lengthy discussion on how to best represent some hardware in the DT and you like to read hundreds of emails just subscribe to that mailing list there's the team of maintainers that are supposed to review the bindings and act them when they are appropriate or give feedback this process is not working really really well at the moment because there are so much development going on on ARM that the device tree maintainers are completely overflowed by bindings to review and it's too slow so there are ongoing discussion on how to make that process go better there were discussions yesterday in the ARM canal minis summit and I think they are going to relax a little bit the rules here and give a bit more freedom to people so that development can go on but up to now the idea was that binding is something that I'm going to mention that later that is design once and should stay forever which is a very very hard and strict rule and very difficult to work with so apparently they are going to relax that a little bit but usually when you design a binding it should be a little bit future proof and allow to exist for a while so here is an example of device tree binding documentation I took the one of the example I used before so basically what it says is well for what type of device it is then what are the required or optional properties so here it says you need to have a compatible property, you need to have a right property you have to have an interrupt property a dma property and so on for example it forgets clocks because clocks is a property that basically you can use in whatever device you want but it should probably mention it so the documentation is not completely accurate here and then usually gives an example and any other information that can be useful so that's what we have and that's what device tree binding maintainers typically review, that's what's important then if the implementation is somewhat broken we can fix it later but the binding is normally an interface that is not supposed to change so we have to be a little bit careful on how it's designed now that we've looked at one single node let's try to have another look at the device tree in its entirety at the root of the device tree which is supposed to describe the entire hardware platform we have a bunch of nodes that are either managerial or optional but that are described in the EPAPR specification and then you can add more nodes and actually the more nodes that you're going to add are the most important ones so amongst the ones specified in the specification are the CPUs, memory, chosen analysis node and there are a bunch of others but those ones are the most common ones so the CPU nodes is going to have sub nodes describing each CPU in the system like whether you have a Cortex AA8 line or some other thing and sometimes some additional properties of each CPU the memory node is mainly used to define where the memory is located the physical memory and what its size is the chosen node is according to the specification a place where parameters chosen or defined by the system firmware at boot time can be stored at the moment it's mainly used to pass the channel command line so if the boot loader is device tree capable it's going to take your device tree blob and it's going to patch it or I would say update it by inserting your channel command line into the DTB and the channel will find it at this place then we have analysis node which contains shortcuts to send in nodes that are needed for some specific bindings I don't want to really dive into the details here and then the most important sections are going to be the description of the buses in the SOC and onboard devices so I've taken the example of the IMX28 platform again and as you can see we have the root of the tree here then we have those common nodes specified by the EPAPR specification and then we have subnodes other subnodes here describing various buses on this platform so depending on how your SOC is organized and how the interconnects are connected together which device sits on which bus you can have as many nodes as you want subnodes if those buses are like subbuses on some other platforms it's much simpler than that you just have one single top level node like called SOC and you have all the platform devices in there it all depends it's left to the the freedom is left to the the person like designing the description of this particular platform so here it matches the hardware so without going into the details it has like two I would say like more or less slow bus and one high speed bus the high speed bus HB is here and has like the memory and some Ethernet and that kind of things and then the APBH and APBX are other buses that are like slower speed devices so that's just the way the SOC is organized but they model that into the device tree as we can see here and so within those nodes there are going to be all the devices that you see over here so in AHB we're going to have for example the Ethernet devices and then in APBH we're going to have I don't know the interrupt controller for example and then the SSP0 SSP1 and so on and so on so it's really as I try to ensure that you could see the direct connection between the schematics the block diagram and the device tree representation here and then at the board level in the DTS file basically since it's overlaid we have the same organization so we can add more information about which you want to enable which SSP device we want to enable and so on and so on and we can also add more nodes that describe board level information such as sound complex or LEDs or backlight information and that kind of things so that's the overall organization and of course depending on the SOC family you're using the hierarchy of buses is going to be different so the exact hierarchy is going to be slightly different but the idea is always usually the same one thing that's important here is the top level compatible string so just like you have compatible strings in nodes identifying devices you have one at the top of the device tree that's actually going to identify the platform and here as you can see we have two compatible strings and you can actually give as many compatible strings as you want and they should be given from the most precise first to the least precise last so that the matching is done by trying to match first finding the driver or the canal elements responsible for driving this element of the device tree that is the most specific possible so here we're having one compatible string that identifies the board it's the evaluation board for the IMX28 so that's IMX28 EVK and then this platform is also compatible with IMX28 because it does this SOC and this top level compatible property is the one that is going to be used to find which sub architecture you're actually running so in the past we had these machine start machine end sections that were identifying each board nowadays we have DT machine start structures that basically have more or less the same thing but what they have in addition is a DT compact field which points to a list of compatible string that this platform is supporting so with the advent of multi-platform canals you can have within the same canal image the support for OMAP SOC for Marvell SOCs for free scale SOCs and of course it's going to have to decide which platform is being booted at the moment and the way it does that is it looks at this top level compatible string it finds which machine description structure as this compatible string and if there is a match then it's going to use all the other hooks that are inside this structure to like start the timer the interrupt controller and register all the devices then it's exactly as it was before but that's the way the connection is made this compatible string can also be used within C code to test if the machine is the one you're interested in to do like some some quirks and different changes that may be needed for example it was used a lot in the transition from no device tree to device tree because not all drivers had device tree bindings because they were in discussion so a lot of C code was being kept around and if the machine being booted was that one then you would continue to register manually using C some platform devices that could not yet be described in the device tree progressively being less and less used on most platforms as we have more and more bindings but it's still one possibility so here we're for example matching that the machine is compatible with IMx28 EVK which is going to be true because that platform is actually the one we're looking at. Does that make sense? This matching so that's the way, yeah, matching with the sub architecture code is being made with the device tree inside the bus, so inside of each of those elements we're going to have a compatible string that defines with what this bus is compatible what entity in the canal is going to handle that bus if it's an I2C bus then most likely the compatible string is going to identify an I2C controller driver if it's an SPI bus then most likely the compatible string is going to refer to an SPI controller driver that has a special value, simple bus that's used to say that's just a memory mapped bus and the driver, the canals would actually go through the sub nodes of this bus and register each of them as platform devices so many of the SOCs are using just a simple bus because they don't need any special bus handling but some other SOCs for example including the Marvel one, they have a bus that has some crazy configuration possibilities and so we have a special compatible property and a special bus driver that goes through the sub nodes and does some fancy things with them so it's possible to have some specific bus driver but most of the platform do simple bus basically goes through the sub nodes, register platform devices easy inside this bus you're also going to have other properties and the address cells and size cells they are going to say in the reg property how many 32 bits values because a cell is a 32 bit value are going to be needed to encode addresses and size for the IO memory region so if I take an example here this APB bus is a simple bus so there's no special driver in the canal except something that will register platform devices and it needs one cell to encode addresses and one cell to encode size and that's why we have only two cells here because we have one cell for the address and one cell for the size so there's a relation between how many values you put in reg and those two informations there can also be a range property here which describes address translations between the child bus and the parent bus so if they are not in the same address space you can describe all the addresses here should be transformed according to some range so some transformation you can say for example from address X to Y in the child bus it's in fact address A to B in the parent bus so for most buses you don't care about that because it's not necessarily useful but some buses have funky things that require those translations some of the SOCs use that to make the addresses here a little bit simpler for example if all your devices are their register in a specific area of memory instead of encoding this base address over and over again in each device you can just put a translation here that says okay everything that's at A000 are actually my devices so whenever an address 0 is used in my child bus I can translate that into address A000 in the parent bus so in the child nodes instead of writing this you could just write OX to 2000 and that would be translated into OX A00 to 1000 so that's what we can do with ranges when the property is empty like it is there it just means it's there's an identity mapping between the child bus and the parent bus they're in the same address space so there's no translation going on and the reg property in the bus is completely useless it's just here as information of how large is the address space covered by this bus it's not used at all and there are other platforms where it's not available it's not used because it's just an information thing here is another example with an I2C bus so typically this is the bus of the SOC and one of the nodes that could be here could be an I2C controller so what you see here is actually here inside this node that's the roots of our SOC bus so one of the devices on our SOC bus and it's an I2C controller so since it's a controller it's a device like any other so it has a compatible string it has some registers to control it it has some intros, maybe DMA channels maybe other clocks and other informations but this device being a controller it drives a bus and so you need to describe the devices with a really innumerable bus and so since it's a bus we're going to add again address cells, size cells and in the I2C world the binding that has been chosen is that the reg property of I2C devices is used to give the slave address of the device on the I2C bus and that's the only information needed so you don't need a size you just need one address so address cells is 1 size cells is 0 being one specific device on the I2C bus the reg property is used to give the child the I2C slave address so depending on where you are reg means either the memory location of the device or it might mean the I2C slave address or it might mean the chip select used on SPI or it might mean completely something else so the meaning of a given property can only be interpreted relatively to where it's located in the device tree and which binding applies to this specific node generally they try to keep things that make sense I believe that makes sense because reg is where the thing is so it makes sense to use that but it can be a little bit confusing at times to have the same property name being used to actually give a different type of value and so for each of those child nodes we again have a compatible string that can identify the driver and then a bunch of other information that are needed for this the description of this specific piece of hardware so here we have like pointers to regulators that are needed by this device here we have another property that probably gives a page size of some I2C eProm or Flash or whatever that are going to be used by the corresponding driver so this is part so for this we have one binding for this we have one binding so each device has its associated device tree binding which is the specification giving the meaning of those properties intrup handling is interesting we have a number of properties related to intrup handling one of them is intrup controller it's just a boolean property if it's there it means that the current node is an intrup controller it can receive intrips intrips cells there is a property that indicates the number of cells that are needed in the intrips field to encode an intrup number sometimes it's just one, just an intrup number sometimes it's more complicated and I'm going to show an example and we also have a property called intrup parent which is a PNVOL so it's a pointer which tells for this specific device what is the intrup controller that is receiving the intrips generated by this device in addition to saying which intrup number is being fired you also need to say which intrup controller is receiving this because on some platforms you may have multiple intrup controllers often there is a top level intrup parent definition for the main intrup controller so that you don't have to repeat that over and over again in all the device nodes so if you have one main intrup controller you give intrup parent at the top and it will consider that all devices are using that so if you explicitly override that with an intrup parent property in the device node so to make that more realistic, let's see an example again, imx28 so the intrup controller is just one device like any other so it's described in the whoops, in the apbh bus as a device, compatible string it has some registers, but it also does two additional properties which says I'm an intrup controller I'll describe intrup so I will be late but I guess it's launched so I can probably extend a little bit it's very wise from the program committee to always put me before lunch breaks because I always have too many slides so this is saying we need one cell to encode intrup numbers and here as we can see we have one intrup number so it's matching the fact that we need only one cell and the reason why the channel is going to understand that those intrips are going to this intrup controller is because we have this top level intrup parent so this top level intrup parent property could have been here as well and then duplicated in all the other devices but just to make it shorter it was moved at the top of the device tree because the logic of this binding is that whenever you don't find an intrup parent property you just go in the parent bus and if it's not there in the parent bus and if it's not there in the parent bus until you find what is the intrup parent for this bus let's look at a more complicated example that's a Tegra 20 platform just picked a random one so it has an I2C controller which triggers an intrup to the main intrup controller it has a GPIO block which triggers intrup to this intrup controller and it has on some specific board so that's the blue part is the SOC and the gray part is the board on the board you have a radio codec which sits on the I2C bus so it's controlled there and it also has a GPIO interrupt a GPIO line that's used for signaling an intrup so it goes to the GPIO controller here and the code to do that is actually interesting and we're going to have a look at that so at the SOC level what do we have? We have the intrup controller the I2C controller and the GPIO controller is just a normal device like any other it's marked as intrup controller but that's what you can see here the number of cells is different it's a geek so it has a different way of expressing intrups I'm not going into the details but instead of recording only one information it needs three informations and that's something we can see here so the I2C controller intrups goes to the main intrup controller because the intrup parent here is pointing to this node using the P&L and therefore if it wants to describe an intrup it should have three cells which it has here and as you can see some of the values are not just numbers because nowadays most of the device tree inclusion is resolved using the C preprocessor so we can use defines to replace magic values it's something fairly recent like maybe two or three channel releases ago, something like that instead like magic numbers all over the place now we have this possibility of using macros which is quite nice we have another device here the GPIO block and it's triggering a number of intrups to the main intrup controller and if we look now at the board level what the board level is going to do is for the I2C controller it's just going to enable it and it's going to describe which devices are on this I2C bus so what we have on this I2C bus is an audio codec which is here we have a compatible string, the I2C slave address and what's important in the discussion here is the interrupt parent and intrup property so this the intrup that is triggered by this audio codec is not going to the main intrup controller so we are overriding the intrup parent property saying the intrup of this device is going to this other intrup controller which is actually the GPIO bank and this is possible because the GPIO bank is saying hey I'm an intrup controller actually and if you want to describe an intrup that's pointing to me you need two cells in the intrups property that's what we have here intrup cells and that's exactly what it is doing it's giving like one cell here and another cell so it's basically giving which GPIO is used and whether it's like level triggered that kind of additional information so that's the way you can read things in the device tree so I know it's quite weird at the beginning understanding that okay this needs two cells because this intrup is going to this intrup controller and this intrup controller is saying that to express an intrup that's pointing to me we need two cells but that's the way things are organized I have too many examples but so another example is clocks so here is a very partial view of the clock tree on some Marvel SOCs so we have core clocks we have CPU clocks and we have gaitable clocks for the various devices and therefore if you want to end all that in the channel you have drivers for all those different clocks some of them can be changed some of them can be gated or can change their rates whatever and therefore at the SOC level what we did is we created drivers for all of those clocks so we have one driver for the core clocks here and we have one driver for the CPU clocks and then we have one driver for the gaitable clocks so it's actually pointing to a bunch of registers that allow us to read the current rate maybe turn off the clock or do manipulation of the clocks and then we need to allow devices to reference those clocks and so here are a bunch of examples of devices that reference their clock for example a CPU can reference a clock so there is a proper binding for clocks consumer that's valid for all devices you should use a clocks equal property and give one or several clocks that this device requires so this our each CPU is using clock and here we have a P&L and then an argument and we're finding the same logic as before this is pointing to CPU CLK CPU CLK is here and it's saying clock sales equal one so whenever you want to specify a clock that's managed by the driver you shouldn't just point to this node but you should give an additional information and this information is zero and the binding defines what this zero or one or two means and in our binding it means which clock you're actually interested in so maybe I don't remember CPU clock zero is going to be that one core clock two is going to be that one gaitable clock 23 is going to be that one so that's a way of encoding information in the device tree of course that's just a choice of the binding some other people do it differently but that's one of the possibility of representing clocks we have another example here the timer is actually using can use two different clocks either a fixed reference clock or a clock provided by the SOC and we're using just like DMAs channels we have this mechanism clock names which gives a name to the first entry and another name to the second entry so that in the driver code you can say I want to get the nbclk clock or I want to get the fixed clock and the driver doesn't know exactly which clock is that it just knows that it has like two clocks that and it knows their names but it doesn't know exactly to which clock it's going to end up pointing to here we have another device it's the USB controller and it's pointing to a gaitable clocks and because this gaitable clock driver also has clock cells equal one when you make a clock specifier you need to pass an initial information and here we also have the description of the clock tree because those gaitable clock and CPU clock as you can see they also by themselves are a clock reference to a core clock so that describing progressively the clock tree so there is really and that's why I try to include block diagram of the hardware next to the device tree description is that there's really a one to one mapping between the two things the final example that I have is the pin control binding so the pin control subsystem allows to manage pin maxing so whenever a device needs some pins to be configured in some way it needs to interact with the pin control subsystem and just like clocks have a common binding that's used in all devices on the consumer side the pin control subsystem has a consumer binding that can be used by all devices and this binding to make it short basically consists in two properties a pin control dash and a number so typically just zero except you have some more complex case and this is going to give a list of pin control configuration that you need for this device to operate properly and then it has a pin control names property which is a bit like clock names and dma names is going to give names to each of the states because the pin control 0 pin control 1, pin control 2 allows you to give different states of the device for example when it's active or when it's idle or in suspend you may want to max the pins in a different way to save power so you can give different names to these different states but in the general case if you don't have too crazy power management going on and you can just have one pin control 0 property that gives a list of pin configuration and name that default and without doing any change in your driver whenever your device is going to be probed it's part of the platform driver logic it's going to notice oh there is a default pin control configuration in there and it's going to ask the pin control subsystem please configure whatever pins that are described in this configuration in the proper state and that's being done automatically so that's the consumer side binding and of course there is provider side binding and the provider side binding just like the clock provider bindings are specific to each pin control driver so that can be some confusing at times that's our pin control and some drivers which actually control the configuration of pins describe which configurations are available and some drivers have decided to give just register and basically value so these informations are identifying one pin and in which state it should be configured so it can have black magic values some other drivers have decided to make things a little bit more explicit by listing the name of the pins the function they should be mixed in but what's important is that in both cases there is a name given to this configuration and that's the name you find here using the P-endals and so what this is going to do when this device is going to be probed since that's the default state it's going to ask the pin control subsystem to use this configuration so the pin control driver is going to look at that one and this pins in this configuration so again that's really closely tied to the hardware and describing all the different mixing possibilities and allowing board files to say ok on this specific board the way the MMC is wired is that way or the way I don't know the UR is wired is that way so the final notes I have are more general information about the GT so it's what that it's really a hardware description language so it should describe the hardware layout and how it works but it's not there to describe the hardware the configuration of the system so for example a very simple example I have is you can describe in the device tree whether a device supports DMA or not because that's a property of the hardware my device is DMA capable or it is not but you cannot describe or you should not in the describe whether you want to use DMA or not but it's not the property of the hardware it's just how you want the system to be configured but it's not a representation of what the hardware is and this is sometimes causing some issues because in the old world we had these platform devices with platform data and people are just creating the device tree binding by each member of the platform data field is going to be a property in the device tree this is more or less true for some of the properties that are actually describing the hardware but for some of the other properties it's not necessarily correct to turn it into a device tree property because it's not describing hardware but just a choice on the usage of the hardware and that's normally not part of the device tree the big question being where do you encode this information and there isn't much of a generic answer to that question and funnily that's one of the issues that people are facing when moving to device tree so it's really a pair a case by case discussion on how to solve that particular problem to express a specific configuration but normally device tree is not here for exposing these configuration decisions DT Bindings as an ABI I guess most of the crowd is reading LWN or if you don't you should so the device tree idea is that it's OS independent so normally other operating systems should be able to use the device tree as a representation of the hardware which also explains why configuration choices should not be part of the device tree and the original idea is that hardware manufacturers could like write a device tree flash it into a device and then let the user install whatever operating system it wants and have it like discover what hardware is available that's the theory then there is real life going on if you want this to actually work you create a new binding one of those specifications and you start shipping products that use this binding then you have to keep them around forever and keep the compatibility forever or otherwise some other product will no longer work with a more recent kernel version and this is hard to achieve because the hardware, the way of describing the hardware is quite complicated the hardware platform is very large the number of those platforms is enormous and going on at a crazy crazy rate and there is not enough manpower to review all those bindings and take good decisions in a timely fashion but until now the position of the device tree I would say gurus was that it should be a stable API and that maybe someday the device tree files would be taken out of the kernel and really have the two things separated but at the arm in the summits yesterday there was discussion around that because the device tree bindings stability is really hard to achieve and it's slowing down the development quite significantly because you have to make the perfect choice from the first time and that's not really the way I believe Linux has been developed over time usually like make a simple solution to solve the problem that you have right now and then later on when you have a better understanding of the problem like how your hardware is working or you're seeing the new SOC line or the new devices then you have a better view of what's going on then you can improve the solution to cover more cases and more cases and progressively iterate and make things better but with device tree bindings if you want stability then you have to be right on the first time and that's really hard and kind of breaking the idea that well let's solve the problem we have right now and make it better later so it's been hard I mean I've been involved in some device tree bindings discussions where you have to plan everything in advance like how things are going to end up and how things are going to work even though you don't really understand the hardware really well yet so that's complicated and so the discussions I'm not sure exactly what the conclusion was and what is being presented today at the Canals Summit but my feeling is that we've reached points where even the DT gurus are starting to realize that it may not be so easy to make it a stable ABI and that at least for some time we may have to relax the rules a little bit and let some non-stable bindings flow in and let people get better understanding of how it works and progressively get the most important bindings in place so probably the rules will change a little bit and it's no longer going to be a completely strict Canal ABI so if it's not strict then it's not Canal ABI at all so I'm not sure what the final conclusion is going to be hopefully LWN is going to make a write up about that after the Canals Summit but that's an area that's still in movement so some guidelines two things I have in mind when writing bindings deciding on the compatible string is important it's really important to use a precise string rather than a vague one so what I'm mentioning is that a number of people are doing okay my device is being used like in the variant T3020 and T3030 of my I don't know SOC line for example so I'm going to call the compatible string FU T3XX because it covers 320 and 330 but then T340 comes out and in fact they changed the way the hardware block works and it's no longer compatible the programming model of the device is not the same the registers have changed the intros have changed, some things have changed and it's no longer compatible so now you have a compatible string T3XX that no longer makes any sense because it it doesn't reflect what T340 is capable of so what you should instead do is use T320 and potentially use for T320 and T330 if they are exactly compatible and there's the same IP block and they have supposedly no difference then you can just use the same compatible string that's precise on the device tree of Boss of Zeus platforms and then when T340 comes out then you have maybe another driver or in the same driver you have another compatible string and some specific handling that allows you to handle the differences so that's one thing and the other I believe recommendation I would have is to not encode too much hardware details in the device tree some people had the vision that the device tree should allow you to adapt the channel to a new SoC without making any changes in the channel code which I believe is completely crazy because there's no way of knowing how the next SoC is going to be different from the previous ones so instead I believe that but it's something that it's more or less a philosophical problem but I believe that it's probably best to have most of the hardware differences being handled in even by the driver and then have different compatible strings to identify different variants of the same IP block of the almost similar IP block between variants of your SoC family and the reason is that if you have too much hardware details in the device tree to try to make the driver more generic usually the genericity is in the wrong direction so when you actually have the next hardware oh oops I didn't plan it properly and it doesn't work out properly and the other reason is that it makes the binding more complex and since normally binding are supposed to be stable the more properties you add into it the harder it is to keep something stable so keep the binding simple is I believe one of the way of making sure that you won't have to break them too many times some future directions more GT bindings for various subsystems such as DRM or audio for examples are still lacking device tree bindings because they are a pretty complex subsystem they make various devices interact between each other so that's still ongoing a tool to validate device trees again bindings as I was saying the device tree compiler only makes syntax checks like if you have property equal and then code and then a string and then make sure it's syntaxically correct but if you make a typo in the name of your property it's not going to notice if you make any other typo if you use age of a binding it's not going to notice so there's no type checking there's no nothing in some way it's a little bit strange because we had C in the past that was doing type checking and compile time checks and everything all nicely now we have a language that doesn't do that anymore but okay that's the way it is and so there are some tools that are being discussed to actually instead of writing like a document for the binding something that would be usable for documents but also programs and that would describe okay a binding expect this and that property with these values and so on and then a tool would allow to make validations on the device tree against the bindings and make sure you're not using a property that doesn't exist or a value that isn't possible and that kind of additional checks so that's being discussed and another thing that has been discussed for a long time is supposedly the device tree has other representations of something outside but it's probably going to cause a huge number of compatibility issues like I don't know how do you synchronize the release schedules of these two entities and if you use old device tree with a new kernel or the opposite what's going to happen and so on it's all part of the stable ABI discussion and yeah I think things are moving in this area and people are realizing it may not be as simple as they thought it would be originally some references the slides of course will be available on the website but the most important references is the EPAPR document but again as I said it's pretty hard to get started with that document there is the device tree.org wiki that hasn't been updated in years probably so it's not so useful and then you have the device tree documentation and the bindings in the kernel sources and the device tree mailing list that's probably the best starting points to continue looking to that I know I'm horribly late if there are questions before lunch I'll be happy to take some of them yes sir you can, I think with DTC I've never used that myself but you can disassemble a device tree that you can take the binary representation and get more or less the textual representation I think some of the information are lost in the process like maybe the labels of the nodes are lost because they're not useful at run time but you can disassemble a device tree maybe you can okay so yeah so yeah you can do that if you have a macro on your DTC yeah of course if you have a macro it's lost another question maybe the device tree the magic number of the stars yeah the device tree has a magic number at the start and when it's you're using the appended DTB mechanism it's looking at this magic number and same thing if you're using a DT capable bootloader it's looking at this magic which I don't remember what it is to find out whether it's 8 tags or a device tree blob I don't know the question is is there any way of authenticating the device tree blob like making sure it isn't being corrupted I don't know I have no idea whether there's a CRC or anything like that in a device tree blob maybe someone else can comment on that but I don't know flexibility of having a single one client for a long period of time has there been any discussion of well you have some inherent versioning capabilities because you can change the compatible string and handling the old compatible string and understand it as it was before and then understand a new compatible string and understand the binding that corresponds to this new compatible string then you have some kind of versioning capabilities in here because you have two compatible strings that identifies two different bindings the issue is that at least I believe the compatible string normally tells which hardware you have but normally for a given piece of hardware you should have one compatible string regardless of whether the binding is evolving but that's not something that has been really discussed I believe and beyond that there's no versioning mechanism in place I think there was some discussion that Leonardo connected about having some properties with a version of the binding but it didn't went further and just random thoughts like that so at the moment the answer of the device tree people about that if the binding changes well first don't do it but if it really needs to change then the way to change it is you change the compatible string and in your driver you keep the code to handle both the old one and the new one which obviously means a lot of crap code in all the drivers everywhere but that's something they don't seem to really care about last question I guess that's a good question I have no idea whether there's the proc is there a proc entry with the FDT or something and swap on the audience yes it's a binary format that you get in in the front I'm being told it's a text version not sure how it's working exactly but maybe it's just I don't see how it can be disassembled true let me make one comment so the CE workgroup of Mellonix foundation is intensely interested in fixing some of the problems particularly the lack of documentation and so hopefully we'll be able to announce some stuff shortly about some more resources to help the advisory authors okay so on that I'm gonna thank you and wish you a good lunch late certainly but thank you for your attention