[U-Boot] Merging device trees at runtime for module-based systems

Stephen Warren swarren at wwwdotorg.org
Thu Nov 1 00:13:25 CET 2012


On 10/31/2012 05:00 PM, Daniel Mack wrote:
> cc devicetree-discuss. Here's a reference to the full thread:
> 
>   http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/145221/
> 
> On 26.10.2012 20:39, Stephen Warren wrote:
>> On 10/24/2012 03:47 AM, Daniel Mack wrote:
>>> Hi,
>>>
>>> a project I'm involved in uses a module/baseboard combo, and components
>>> on either board are described in DT. I'm currently using separate dts
>>> files which build upon each other with include statements, which works
>>> fine for development.
>>>
>>> In production though, we will certainly have running changes (and hence
>>> different versions) over the lifetime of the product for both the
>>> baseboard and the module, and the hardware has support for identifying
>>> the versions of both sides at runtime.
>>>
>>> So let's say we have n versions of the baseboard and m versions of the
>>> module, we would much like to only prepare n + m files, instead of n * m
>>> by pre-compiling every possible combination (some of which may actually
>>> never occur 'in the wild').
>>>
>>> So my question is: is it possible to do that kind of assembly of a
>>> number of files at runtime in U-Boot? I guess all it takes is merging a
>>> number of trees together, right? I browsed through the APIs but couldn't
>>> yet find an clear approach to that kind of problem. If not, what would
>>> it take to add that functionality? I can probably help with the
>>> implementation if someone tells me what would be the right way.
>>
>> Yes, solving this would be very useful; it's a wide-spread problem.
>>
>> Some thoughts though:
>>
>> Simply overlaying two DTBs on top of each-other (in the same fashion
>> that dtc's /include/ statement would do at compile-time) might not be
>> fully general enough, although perhaps it would be sufficient for your
>> immediate needs.
>>
>> For example, lets say that a GPIO is routed from a device on the main
>> board to a device on a daughter board, or even from one daughter board
>> into the main board and back out to a different daughter board. Now,
>> consider that the different board(s) that are the source of the GPIO
>> might use completely different SoCs or versions of the SoC, which might
>> require using a different GPIO specifier to represent the signal. That
>> means you need to change the .dtb file for the "client" of the GPIO
>> depending on the HW or .dtb that provides the GPIO. That's certainly not
>> a simple matter of merging multiple .dtb blobs together.
> 
> Hmm. After implementing a very simple overlay approach, I can now see
> your point :) Yes in fact, that's a real problem.
> 
>> The same issue could easily apply to I2C or SPI buses, chip selects, etc.
>>
>> One solution would be to explicitly represent a connector or
>> connection-point in DT, such that the connector can implement the naming
>> of all signals that pass through it, and provide a translation point for
>> hooking the two DT fragments together. This seems within the spirit of DT.
> 
> Yes, but you still can't handle references that way.
> 
> Let me try and conclude this for others. Say the "module" tree "A" looks
> something like this:
> 
> 	/ {
> 		multi-regulator {
> 			vcc1v8: regulator at 0 {
> 				/* ... */
> 			};
> 		};
> 	};
> 
> ... and the baseboard ("B"), that makes use of (and hence depends on)
> the module, has something like this:
> 
> 	/ {
> 		consumer {
> 			main-supply = <&vcc1v8>;
> 		};
> 	};
> 
> Now, let's say in a subsequent version of the module, we change whatever
> provides that supply for 1.8 volts, but the consumer on the baseboard
> shouldn't care much of course, thanks to all the abstraction layers that
> we have now in the kernel.
> 
> However, the problem here is that I can't just compile trees A and B
> individually into .dtbs that get merged later, because dtc will bail on
> the unresolved reference of &vcc1v8 of course. And cases like this are
> the whole reason why I started to think about modularization of trees in
> the first place.
> 
> So the simple overlay method doesn't help here at all, even though I can
> share the code if anyone's interested.

Yes, you've understood me exactly.

The connector-base approach I was thinking about might look (very very)
roughly as follows:

main board:

	/ {
		multi-regulator {
			vcc1v8: regulator at 0 {
				/* ... */
			};
		};
		connector {
			compatible = "vendor,board-socket-a";
			vcc1v8-supply = <&vcc1v8>;
		};
	};

child board:

	/ {
		connector {
			compatible = "vendor,board-plug-a";
			vcc1v8: regulator {
			};
		};
		consumer {
			main-supply = <&vcc1v8>;
		};
	};

... plus some logic so that the "driver"s for the two connector nodes
get linked together, such that the code forwards "requests" for the
regulator that the plug receives on to the node for the socket, which
then lists the actual provider.

Obviously, the above DT is an extremely rough sketch, and we need to
think about:

a) Exactly how the plug/socket get linked together.

b) Can we make a generic driver for the plug/socket, so we don't have to
write a driver for each board's connector design. The driver would have
to forward all kinds of regulator, GPIO, interrupt, ... requests it
receives at one node, on to the node that's listed in the other
connector node. Kinda like "ranges" but for arbitrary resources, not
just memory maps, in a way.


More information about the U-Boot mailing list