I don’t have an answer, but some information might be useful to you…
It is important to understand that a device tree is essentially an argument passed to a driver, and that it isn’t directly part of any kernel. Long ago the kernel was going to end up with different patches and drivers for various minor changes of a driver among different hardware, even for the same manufacturer. Instead of doing this, Linus Torvalds decided to make variations as a unified driver with arguments passed instead of thousands of different drivers. A given device tree fragment is applied only to a particular driver. If the fragment does not work with that driver, then the driver ignores it.
Although there is a device tree build available in the kernel source it isn’t really part of the kernel. It just happens though that a fragment is only useful if a given driver is configured. The kernel Kconfig
mechanism is used to not only select kernel features to build, but also (when building the dtbs
target) to include different fragments which might apply to given configurations. If your kernel build configuration is wrong, or not an exact match to the existing hardware, then the device tree will also be wrong when built this way. It is simply a convenience to make the Kconfig
also define a set of fragments to include.
If we go back to the device tree itself, and ignore the kernel build method of obtaining a tree, consider that each fragment is actually independent of another. You can easily reverse compile a binary tree that was a file, edit the source, and then recompile it. You don’t need to use the kernel source. For any Ubuntu system, including Jetsons, you can install the compiler with “sudo apt-get install device-tree-compiler
”, which produces the dtc
application.
Some examples; binary name will arbitrarily be called “sample.dtb
”:
# Decompile/reverse compile a .dtb:
dtc -I dtb -O dts sample.dts sample.dtb
# Edit the plain text, sample.dts, then recompile it as a new name:
dtc -I dts -O dtb sample_modified.dtb sample.dts
# On a Jetson, extract the running system's current tree (note on this follows):
dtc -I fs -O dts extracted.dts /proc/device-tree
Regarding the last option, converting a tree from the running system, keep in mind that the bootloader can read a device tree, edit it, and then pass it on to the Linux kernel as it loads. It is not a guarantee that the bootloader does not modify the tree prior to passing it to the kernel. Chances are though that you’ll get what you want.
If you were to build a kernel the configuration is critical. The exact same source with minor differences in configuration is not the same kernel. On a Jetson developer’s kit the default shipping configuration is via the target “tegra_defconfig
”, if and only if you’ve also set the CONFIG_LOCALVERSION
. A copy of the actual .config
file used in kernel config can be found by copying “/proc/config.gz
” to your kernel source, running gunzip
on it, moving it to file name .config
, and then editing CONFIG_LOCALVERSION
. On a default Jetson this is what you would edit:
CONFIG_LOCALVERSION="-tegra"
Note that the base kernel source version has the CONFIG_LOCALVERSION
appended to it, which is what provides the output of the command “uname -r
”. This, in turn, is where the kernel finds its modules:
/lib/modules/$(uname -r)/kernel
If any of this is not matched, then your kernel build is not the same kernel as the running system. Normally it does not matter if you use the tegra_defconfig
target (plus CONFIG_LOCALVERSION
setting) versus the /proc/config.gz
(plus CONFIG_LOCALVERSION
), you’d get the same set of features, which implies the same device tree fragments.
If your edit is for hardware which you’ve added separately, and if that hardware is not configured in the default configuration, then your device tree fragment will be missing. If you have a different carrier board, and that board has the same hardware, but arranged differently, then the tree would change, but the kernel config would remain constant.
Also beware that simply configuring a kernel is not sufficient. One must also propagate that configuration throughout the source before doing something which depends on that configuration. If you were to build the kernel Image
target, then this does propagate the configuration (such that any other build target will get a correct configuration). On the other hand, if you were to build just modules
or just the dtbs
targets, you will have a failure case because the configuration was not propagated. You could instead run “make modules_depend
” to propagate the configuration. I usually advise building the Image
target at least once as a sanity check since it will detect certain errors that the other build targets might miss.
Incidentally, if you’ve propagated the configuration, and want to log a dtbs
target build (a huge log) for reference, then you could do something like this (this is the simplest case):
make dtbs 2>&1 | tee log_dtbs.txt
You could then search for the .dtsi
files and .dts
files related to your edits and know exactly what went into them and where they were used.
Someone from NVIDIA could probably answer questions about which specific .dts
and .dtsi
files are used with a given driver or stage of boot. Sometimes it is about what the bootloader uses instead of being about what the kernel uses.