 Okay, welcome to the session about device stream and how to get your device tree bindings accepted in less than 10 iterations. My name is Krzysztof Kozłowski. If you don't know how to pronounce my name, it can be just Krzysztof, works perfectly fine. So I work for RINARO in Qualcomm landing team. I upstream few, some support for Qualcomm SOCs. I'm also co-maintainer of the device tree bindings in the Linux kernel and I take care about a few other things as well in the kernel, few other subsystems there. And this is about RINARO services. Okay, what the topic would be about. So I will say a few words about the generic rules, about the bindings in the Linux kernel. I will show how to use the DT schema. Also, I will explain a bit what is this DT schema. The main part of the topic would be dos and dons. So what, as a reviewer, I kind of expect from the bindings. The presentation finishes with something which I call reusable patterns. I will not be going through this. I keep them on this presentation so you can use them in your upstreaming process and also other references so we can use the slides in your work. If there are questions, we can leave them till the end but actually you could also interrupt me and if you see something interesting, just ask a question during the talk. So short disclaimer that device tree bindings are used in several projects. However, I maintain the Linux kernel. Therefore, the entire talk is focused on the Linux kernel device tree bindings. The guidelines here are mostly based on the experience and also the guidelines sometimes change and during the review on the mailing list, some things might be different than I tell you here. Sorry, I mean, the maintenance decision over rule, whatever I wrote here. Okay, what are the bindings and device tree schema? Device tree sources, so the DTS. I hope that everyone in this audience know it. So the DTS describes the hardware so the kernel can use it. It's mostly for the cases when the hardware is non-discoverable. And now the device tree bindings describes, say, what are the rules, how this DTS should be created. So similarly as the DTS, the bindings also focus on the hardware. So we don't describe the Linux drivers. We don't describe anything for the operating system. We rather document the hardware which can be used by different implementations. Although, of course, we focus on the Linux kernel. So in the past, we're using the text to describe the bindings. But device tree schema or DTS schema is the new format. We use YAML there. And it has certain benefits. So because it's a language, so we can first of all, validate the bindings against the something which we call meta schema. So certain rules, how the bindings should be written. But what is more important, we can validate the DTS. So you can check whether DTS has some style or some important features and therefore it conforms to the bindings, whether the DTS actually presents what binding is telling to do. The rule is that for the Linux kernel device tree bindings, all of the new bindings should be in DTS schema. We don't accept anything in the text. The old bindings which are in the text, you could still extend adding their compatibles, it's okay. However, adding new properties to text bindings, usually it's not accepted with some exceptions. How could it look? I hope the text is a bit visible. So on the left, there's a DTS, there's a SPI bus with one device, it's ADC. It has a compatible, it has a unit address reg and it has one regulator called VRF. On the right side, there is a piece of the device binding in DTS schema without some parts of the boilerplate. So there are some few things which are here removed for the obvious reason. It starts with the title description and again we say what is the hardware. So the hardware is some ADC with its name, it's a channel. Then we list the properties. What properties do we expect? We expect the compatible, very specific one. We expect the reg with maximum one item and there can be also the supply which is the regulator, VRF regulator. We list which properties are required under the list of required and we finish the binding with the keyword called additional properties false. This means that no other properties can appear. I will also mention this additional properties false later in my talk. What are the generic rules for the bindings? We already have it documented. It's everything. So I'm basically repeating the Linux kernel doc. First of all, they focused on the hardware. So they should be independent of the implementation and hopefully some other operating systems or other projects are using the bindings, not only Linux kernel. Therefore, for the same reason, we try to avoid the Linux system. So we avoid the Linux subsystem naming in the bindings. We don't describe the drivers or Linux specific subsystem. We also try to avoid describing the operating system policy. So we don't tell the operating system in the bindings what the system should do. It's not the hardware description anymore. And of course, the bindings are for the same as DTS, are for non-discoverable hardware. If your hardware can discover itself, for example, present some kind of ID, version ID and then you can discover what type of block it has or can say what type of features, capabilities it has. Maybe you don't need the bindings for these pieces at all. The less work for me actually. I mean, I would have much less things to review. When you contribute to the kernel and send your bindings for your new device as a patches, there are a few also things which we all expect them to have. So we want them to be dual licensed, mainly because we want them to be used by other projects as well, so GPL and DSD. The file name should follow certain pattern, the same as compatible. So we want the vendor comma and the name of the block. And if your bindings come with also with the headers, so these are usually located in include DT bindings, ta-ta-ta, these are also part of the bindings. The same rules, dual license, naming, similar as compatible. And please don't mix the bindings with the driver code because they are describing a bit different piece of that is grabbing the hardware. So we expect the bindings patches to be really separate patch in the patch set, the best before the usage comes. Quite important property is the compatible. So what are the rules for the bindings regarding the compatible? Most important should be specific, which means that we don't accept the wildcards. And of course on the mailing list, pretty often we saw discussions that some bindings in the kernel already had a wildcard, therefore my device also had a wildcard. No, it's not, doesn't work like this just because we accepted something in the past. Sorry, I mean that guy was lucky, you are not. So the wildcards are not allowed because you want the compatibles to be very precise. We can accept some family names, I mean like a device family name. There are such exceptions. So usually it's for the SOC IP blocks when one device, I mean, actually all devices have similar programming model. So the example here shown is this Qualcomm MDSS DSI controller. So this is the controller for the DSI in the graphics. So all of the devices have similar interface so we accept a compatible which matches the entire family which you still have to prepend with the specific compatible. So with the compatible matching the actual device. Therefore there are two compatibles, one for SM8550 and then the generic one. What else? If you have devices which can be on multiple buses, so there are such devices for SQC or SPI, then the compatible should not include this type of the bus. I mean, in case of the Linux kernel bindings on which bus your device resides, this depends on the note, on the device not parent to the device. So it should not be part of the compatible. The compatible just describes that the device and device is just, in my example, four. Very nice device thing. Linux has two specific compatibles. So I think these are not used in other projects that come from the Linux. And this is the Cisco and simple MFD. You can use them and see them pretty a lot in the Linux kernel, mostly around the SOC world. So every SOC will have at least Cisco. The main rule here is that we want them to be prepended with a device-specific compatible. So Cisco and nor neither, Cisco and simple MFD cannot be used alone. What are their meanings? Simple MFD means very simple multifunctional device. But the true meaning is that this device doesn't provide anything for its children. All children does not depend on any of the features of the parent. This means that you cannot have in such a device which is simple MFD. You cannot have any reset lines. You cannot have any clocks, anything. Because otherwise this is not simple MFD. This is purely for very, very simple devices which you don't want to write a driver for it. And probably you should not overuse it to write your drivers with simple MFD. Just create your own device and call off-platform populates to populate the children. Now the Cisco. Cisco represents some kind of non-very generic type of register range which contains several pieces and it's not actually responsible for one device. So they don't represent one specific device. Pretty often this is called system controller and this might have several bits for different pieces. There is also a tendency to simplify design of all the bindings, all the DTSs that instead of writing a phi node or instead of writing a reset controller, some kind of SOC developer or DTS upstreamer will push it as a Cisco. And then the reset client, so another device which needs to reset something will use the Cisco and be handled to reset something. So please don't. The Cisco is not an excuse for laziness. Please describe such dependencies precisely. So if you need a reset, create a reset provider and use it from the reset consumer. This also has important pieces because the reset and clocks and other will guarantee you proper ordering, will guarantee your probe deferral and everything, device links, everything. Okay, let's go further. So the other generic rules about the bindings, so properties. We tried the properties to be, to representing also the hardware characteristics. So the good example is let's say if there is some regulator, it has voltage. So minimum voltage should be represented in units of the microvolts. Rather anti-pattern would be to represented in register values. Pretty often we accept it for devices, I mean for properties specific to devices, but in general if you have a property which actually maps to a physical phenomena, then use the common units and we have such units which I will also mention a bit further. So in this case, microvolts. Okay, so these were the bindings. Now, device tree schema. First of all, I will not say exactly what is the device tree schema. I'm just simplifying. It's a set of let's say rules and entire out of tree, out of the kernel application we've written in Python with a lot of YAML. For you the important part is that we use their specific language which is YAML and how to use it. So install the package from the Python and then when you write your bindings please test them before sending. So there are here three comments which allow you to check the bindings. Either you can test the binding themselves or you can test entire family of bindings in the example of Qualcomm bindings or some piece of direction of the Linux kernel. And this is how you can test your binding. More interesting part is how to test your DTS. So we expect actually that all the new SOC platforms which are being introduced to the Linux kernel are coming with towards zero or close to zero of the device tree schema validation warnings. This means that the DTS for this new platform at least for new sub architecture comes without warnings when validating against the device tree schema. How to check it? So of course this depends you are testing DTS so this depends on the cross compiling. You can test all of the DTS as with the DPS check but this will take a lot of time. Therefore you can narrow the check for the specific bindings in the example with trivial devices.yml or you can even test on your DTB target. So then you run a bit different syntax. It's a make check DTBS which checks one specific target. So in this case, Qualcomm SM845 HDK board. You can even intersect these two so check one board with one specific binding. No questions so far, okay. Oh, there is a question. Can you get a mic here? Here on the left, my left. So, yeah? Okay, I use an external DTB when I'm compiling my kernel so can you check an external DTB? Yes, I think there's a DT validate that's coming from the DT schema so if you install the package or install the DT schema then you should have a response proper comment. I never tried it. I work only on the upstream therefore please upstream your DTBS but it should also work. So it was not heard. And the question was whether can you test validate some DTB which is out of three? The answer is yes, I hope. That's the point. All right, let's go. So there are also a few dos and don'ts about the device three schema. So the bindings written in device three schema. So these are rules I hope people will follow and this will save me a lot of time when you send the patches because I'll be less grumpy and less reviewing less job to review when reviewing the patches. So what to do, what to don't do. So first of all, please always look for a standard property. We have already several defined properties in the DT schema repo. We have some common properties lying in the Linux kernel. You can check the other bindings, how they do it. So look for the common parts. We don't want to duplicate the properties. However, pretty often you will need property for your device and your property. So let's say custom property and then the rules come. You need a vendor prefix. You need the type, type is expressed with the dollar ref. Unless you use a standard unit, I will say about it in a second and you should provide a description. So the code at the bottom shows this example. So this is a Qualcomm property. It has a ref, it's unsigned integer 32. And there's a description saying what is this property about. Now you don't need this type, this ref, for certain things. First of all, if you use a property with a well-known suffix. So we have a list of the suffixes like microvolt or even microamp 1000 hertz percent. Then you don't need to provide the type because the DT schema expects already the type. So then you can skip it. The example is entry latency US, so microseconds. Several other properties are also defined by the DT schema. They are not exactly like units but such example is the supply. Supply means here the regulator supply. So also there is nothing, no need to provide the time for the supply. And there is a set of common properties which are well known like interrupts, reg, what else? I don't know, resets, clocks, all of them already have defined time that these are, for example, p-handles, or actually p-handle array. However, you still might need to provide some constraints. So for the case for the interrupts, we need to say that how many interrupts we expect one interrupt in the example here. Pretty common property are the arrays. So usually these are expressed like with the reg, clocks, DMAs, reset lines, interrupts, power domains, all of them. And there's a corresponding property called softening, softening names, so clock, clock names. Reset names. The main rule is here that the list, both lists should be strictly ordered and we expect specific order and the names are actually a helper. Now, this of course is not 100% true because from time to time Linux drivers depend on the names, therefore the names is not exactly the helper, but having the names should not allow you to kind of have a relaxed ordering of the array. So again, the items in the array are strictly ordered. We expect them to be ordered. There are of course exceptions. If you have the names, don't make them redundant. So if the, this is interrupt, it's enough to say that's TX interrupt, not TX IRQ, it's obviously IRQ. And how does it look? There is a way to describe it with the example below. So there's a clocks, keyword items, which says it is an array, and this array expects two items and they are defined by descriptions. So they'll be 24 megahertz clock and there's a bus clock. Then also we need to describe the names if we use the names, and as well we expect two items and these two items are const, so they are fixed, we expect ref and bus. This is strictly defined array. So no order can change, no other entries can appear here. Arrays can also have different flavor. So first of all, obvious cases you can skip description like here is the example of the items for the resets are not written because what would be the point of saying that this is the reset for the first and this is the reset for the second. So we just say the constraints, max items. If minimum items equals to max items, just say max items, it's enough. Although also there are exceptions if you define it in all of if then blocks or in kind of conditional block. For really obvious cases like the reg, you just say that how many items you expect like a max items one. If you would have here more of the IO address space ranges, then this would not be enough and we would expect to enumerate, say what is the first, what is the second, what is the third because they are strictly specific order. But if you have just one, just say that it's max items one, want to say more. I said at the beginning some time ago about the SysCon providers. So the SysCon block which is a system controller. Now about the consumer, so the other side. So this is also pretty often appears in many, many cases this is a SysCon p-handler. The rule here that if you have a property called SysCon it's too generic, it's not specific enough. So it would be not good. You need a vendor prefix, you need some type of descriptive name. So this in the example shows the sysreg, system registers shortcut and you need some type of description like this is p-handled to the system register region. It can be also described a bit better or more applicable to other cases if you have an offset. So then you can use p-handle array for such SysCon and say that you have an array of actually one item and this item has two. So there are two descriptions here. The first is the actual p-handle, a second is offset. Several drivers already use such pattern. The bindings finish with this keyword called additional properties or unavelated properties false. So this keywords determines how other properties will be evaluated. So these are all the properties which are not explicitly mentioned in the binding. These other properties can come from divestory schema itself or from other reference schemas, anything which comes from how we write the bindings. So for almost 99% of your cases you will use either additional properties or unavelated properties and set it to the false. If your binding does not reference other schema in the top level, so there is no top level dollar ref, then most likely you want to use additional properties false, almost actually 100% want to use additional properties false. And the example here is exactly that case. So there's a list of properties, there's some of them are required and additional properties false, which means that nothing else is allowed, only these properties are expected. Now, you might have a bit different case. So you might have a top level reference and this example here shows the panel binding which is using the, or referencing the panel comma datiam schema. So this other binding comes with its own properties. However, you might not like all the properties, you might just choose that, yeah, I write the binding for the panel but all this common panel bindings are not good for me. Therefore, you can list which properties you want. I want the backlight, I want reset GPIOs and I assign them to true, which means that I just want them to evaluate. I don't define the type, I don't define the description, why? Because this other reference schema, this panel common already tells me the type, already tells me the description, what is this? I just have to mention it. And then of course, I also finished the binding with additional properties false. This means that no other properties, which you list here are allowed, including no other properties mentioned in the panel common. This makes sense for certain cases. Although, if you reference other schema, you rather would like to have such case. So you would like to use unevaluated properties. There are two examples here. So typical is the regulator. So this is actually patterned property but it doesn't matter, there is the LDO, actually that can be up to four LDOs. And they reference regulator.yaml and finish with unevaluated properties false. The example below is the same panel example as before, just with unevaluated properties false. This means that you reference the other schema and you accept all of the properties coming from this other schema, from the regulator.yaml or panel common.yaml. You can add more properties and nothing else. So nothing which was not evaluated is not accepted. Nothing else is allowed here. So if you reference other schema, most likely you would like to have this style. So you finish your binding with unevaluated properties false. Finally, the binding finishes with the example. So we want some one or two relevant examples which will validate the binding itself. This is used during this make DT binding check and we use it for the purpose of testing the binding whether the binding is correct. It also serves as a purpose example for anyone who will be writing DTS based on the binding. There is really no point to have 10 examples if they differ by just compatible or free properties because this is pretty often obvious stuff. And unlike for the yaml, we prefer here for space indentation, although two space indentation for such DTS example is also okay. What about the example more? So we don't want there to have status. So status, okay, status disabled. It's not relevant for this example. It's pretty common mistake when you copy an example from DTS. And there is usually no need to provide some unnecessary pieces of other example. So if you, for example, if you have a binding for a clock provider, there is no point to give example of consumer of a clock because it's pretty obvious. We have thousands of consumers. Just provide the example for the same for your device or the provider. The final rule, it's which applies for all the DTS. So we prefer the know the names to be generic and therefore the proper node name for this, for example, for ADC is ADC, not AD7190. That would be pretty it. I have here available patterns. And as I mentioned, I will not be going through them. I leave them only if anyone would like to have some cheat sheet when working with your device rebindings. So I will quickly go through it up to the thank you and the questions. Any questions? Yeah. Could you go back to the beginning slide, please? I think it was. Which one? Right, right at the beginning. I would like to speak up. The microphone's fairly quiet. Honest. Can you go back to the beginning? Beginning slide. Yeah. Sorry, it's where you say that one there. So this is true for Linux. The do not describe software policies is something that Linux does because it has a user space. So other users of device tree, for example, Uboot allows that or needs that because there's configuration goes there because it has to put it there. It can't put it anywhere else. And Zephyr is actually the same. And perhaps that's the reason why Zephyr hasn't been upstreaming bindings, but it's certainly something that is now allowed in the DT schema, as I understand it. And so I just wanted to make that comment. So far, I think there was no case that actually someone was trying to upstream Uboot bindings which have the policy saying how Uboot should behave. So we didn't have exactly, I think, that case to say whether it's not or yes or no. So the policy here that we don't describe operating system policies is for the Linux. For the case of the Uboot or other projects, this would be probably discussed. And therefore I made a disclaimer that the further Linux open source community might overrule this talk, but it's a valid point. There's a question there, Far. I have seen people mixing the Cisco and simple MFD compatible strings recently quite a bit. This is apparently not allowed, right? Is there a reason behind that? Together. Together, yes. No, it is allowed, yeah, it's okay, it's fine. So the only thing which you need to have is to have a specific compatible. What Rob Herring was saying on the mailing list that actually he believes that this is contradictory. So if something is Cisco, it actually cannot be a simple MFD. And he's complaining about this on mailing list. However, he accepts this. So it's a rule by practice. So it's okay. So this is okay to use. We are not supposed to create some sort of wrapper drivers which would do the sub-node scanning. This is okay. If you follow the rule that simple MFD cannot have any other resources for the children. So the children cannot depend on resources. Ah, okay. So because this is the rule of the simple MFD. So the only resource coming from the parent is the IO address space. So the register, special register region space. Good job, thanks. So we actually ran into an issue in TI. Maybe we're using the J720 controller. I didn't get that. Is this better? Yeah, so we did run into an issue at TI with the device trees. So we ended up using like TI J720 system controller along with the Cisco. Then we realized that the register accesses can overlap and it depends on the driver how the request is going to happen. So what we are trying to do is to get away from Cisco entirely with simple bus. So if I got correctly, one conclusion was to get away from the Cisco. And yeah, it's a nice shortcut. The same as simple MFD, but if you start using such compatibility in your source design, then actually you limit yourself and then you might have troubles further in your upstreaming process. So, okay, any other questions? Oh yeah, there is. It's a bit loud at this time. I noticed that sometimes warnings appear when you update your DTC or whatever because it discovers new things that it doesn't like. And then you get a lot of warnings that for files that were previously valid and now not. Is that something that's continuing or have we reached the end of that? So if I got the question, you mean how to reduce the amount of warnings when you do the validation or can you refresh? So go back three years, I run DTC, it gives me no warnings on a particular DT. I do it now, it produces 50 warnings because DTC is checking a lot more stuff. I mean, I'm just wondering, will that continue? Because it's annoying because you've got perfectly valid DTs that now produce warnings six months later. So the answer is probably that there will be still warnings going, but it's up to you to fix them. So one of the answers, how I became the device she bindings maintainer is just I was converting a lot of things, a lot of things and fixing DTS on the way. So it's community effort. And the point is that, yeah, we have a lot of warning. So with all of the automation tools and someone has to fix them. And the DTC, so the DT compiler warnings are also should be fixed. I don't think that they are a requirement for the system ready, but it would be actually nice to have the platforms without them. There's a question further. This is more of a kind of a conceptual question, but say for example, check patch has this parameter fixed in place, which can just attempt to fix the errors for you. Is there any chance that the DT tooling will have something similar ish and that it will attempt to fix the errors for you in the bind, in the DT source? DT not, but chat GPT can. Yeah. Maybe. So if we describe entire DTS in the binding, so because there are some values, let's say that you miss introps or you miss some GPIOs, but what is the value for the GPIO or the introps? You can actually write it in the bind. You can create so complex binding that it describes every value and you can generate DTS out of the binding. But of course, yeah. I don't think that's the point. I mean, fixed basic errors like no, this called like ADS 74, something, something instead of ADC, that kind of errors I think could be fixed already, right? Based on the bindings. Yeah, probably start simple things. Yeah, there could be. And what could be probably improved also the errors coming from the DT schema. So when it finds some mistakes in your bindings and produces a very interesting error, which is quite sometimes challenged to decipher, so. Yes, thanks. Yeah, one more question here. It's quite overriding. It's healthy exercise. Why choose a license? Or dual license? Why choose dual license for DT-by-DQ? The question is why do we have dual license for the bindings? Because you want them to be used in other projects, which might have different licenses. So not everything runs on GPL. There are some BSD things as well. Sucks. I guess that's it. Ah, no, no, no, no, one more. I was wondering in the example you had for the DT schema check, it didn't have the checker flag, but the bot seems to ask for dash M. Is that important to have? This DT checker flag dash M? No, so this, when the rope runs is bot, which scans all your patches, it runs with this DT checker flag, which also checks whether actually your binding does not, whether it references the example in the example, the binding which you want to put there. So basically it tests whether the example matches the binding because if you test one binding and you put the irrelevant example, then your check, local check would be fine and you would not notice that the example doesn't match. But when you submit, I mean skip this flag and it will be also perfectly fine. And if something is wrong, then the rope will correct it. I mean the bot will correct it. Back to a question that was asked earlier, the first one. There's a comment on the chat about how to validate an external DTS. So I never tried it, how to... It's available. How to, there's a comment, how to do it. Yes, yes, explaining. Good, so that's for how to validate them. With DTS, we pass a path to a DTB wherever it is. Great, cool. And then back to the decent file. Anything more? Then I guess that's it. So thank you very much for coming.