I have no experience with cameras, but am hoping to clear up some concepts related to the topic which might speed things up for you. This means possibly answering about ideas instead of concrete examples, and not a direct answer, and often not even directly related to your question (I’m trying to be thorough, and really need a summary of what current questions are for any hope of a useful answer…this is a long thread).
Regarding the kernel and modules, understand that some features are invasive and were never designed to work as a loadable module. An example is virtual memory for user space programs…swapping out for cases of insufficient RAM. One cannot simply add or remove that feature since it affects just about everything, and so this has no option to be built as a module. Building as a module does have extra requirements, and so typically something like a driver for a specific device can be built as a module, but not always.
When a module or kernel driver does load which is for some optional hardware (such as a camera sensor), then the driver needs to find the device before it can be used. For plug-n-play devices (including USB and many PCI devices) this is not a problem since the device itself can self-report. For devices which cannot self-report the device tree becomes the primary method of giving such details to the driver. For example, the device tree will mention which driver(s) the device can be used with, along with a physical address to find the device (in the kernel physical addresses are used, not virtual addresses). Other details also can be added if the driver has an option for those arguments, e.g., I imagine that if the camera has more than one resolution, then probably a default starting resolution would be a candidate for the device tree.
If you want to see the current device tree simply extract it and browse the file (it is human readable). On a running Jetson you can extract its current device tree like this (if you don’t have “dtc
”, then add this with “sudo apt-get install device-tree-compiler
”):
dtc -I fs -O dts -o extracted.dts /proc/device-tree
Regarding how modules load, examine the output you see from “uname -r
”. The answer will usually be something similar to “4.9.140-tegra
”. In that output the “4.9.140
” is the source code release of the kernel, and the suffix “-tegra
” is from the CONFIG_LOCALVERSION
(someone set this kernel config feature to “-tegra
” before compiling). Now look at this file location:
/lib/modules/$(uname -r)/kernel
…you will see all modules which were built for this kernel in the directory tree at that location.
If a kernel has a module loaded which was built against this combination of kernel release version and the kernel was configured the same as your running system, then the module can simply be copied to the correct subdirectory of “/lib/modules/$(uname -r)/kernel
”. Modules in any other location will fail to be found. Modules compiled against a significantly different kernel configuration will be found but will fail to load or else will produce a kernel error upon load.
Typically, if you build a kernel which starts with the existing kernel’s configuration and “CONFIG_LOCALVERSION
”, and you merely add another feature as a module, then you won’t need to build a new kernel (you could build just the module). As soon as something is added to the kernel configuration which is not a module (especially something not able to be built as a module), then you risk the new module (and perhaps older modules) failing to work with the kernel. If the configuration changes enough to risk this, and if you replace the kernel itself (the “/boot/Image
”), then you would be advised to use a new “uname -r
” (which means a new “CONFIG_LOCALVERSION
” other than “-tegra
”, e.g., “-test
”), followed by installing all new modules and the Image
. Unless you use some new feature which is invasive and not available as a module this shouldn’t be needed.
Note that the device tree is likely consulted as you load such modules for items which are not plug-n-play. This implies that the device tree is specific to kernel features, but the tree itself is just an argument passed to the features/drivers. The tree can be built in the kernel, but it isn’t because the tree is part of the kernel. The tree is actually able to be reverse compiled, edited, recompiled, and added back in as a simple file without ever touching the kernel source. The device tree exists because without such a method of supplying arguments you would need a different kernel driver for every possible configuration of that driver, e.g., if one manufacturer were to put the camera at one physical address, but another at a different physical address, then you’d need a driver for every possible variation. The device tree makes it possible to have one driver and then each manufacturer tweaks the device tree details for their hardware. Note that physical address and many other details of the device tree are specific to a specific carrier board. A Jetson on one carrier board will require a tree which is different than that of another manufacturer’s carrier board.
So as you build a kernel you device what device tree nodes are required. As an option that fragments of source to a device tree can be glued together to form a full tree source based on the features you’ve enabled. Then the tree can be built by the kernel via building the “dtbs
” target. Even that tree will need edits for anything which is non-default in your carrier board and/or end device.
You can edit any tree, and for example, the extracted.dts
file mentioned from above can be edited with any text editor. Then it could be recompiled:
dtc -I dts -O dtb -o edited.dtb extracted.dts
To safely try another kernel and/or tree, consider the following (related to installing the new tree without overwriting the old content)…
Examine file “/boot/extlinux/extlinux.conf
”. This is just from a TX2, so it isn’t an exact match for the NX, but a boot entry looks like this:
...
DEFAULT primary
...
LABEL primary
MENU LABEL primary kernel
LINUX /boot/Image
APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4
If you boot with serial console attached, then there is a short moment when you can pick a kernel. If you don’t pick a kernel, then it will boot the DEFAULT
(there are some bugs which some releases also require the DEFAULT
to be the first entry). The example looks for LABEL
“primary
” when nothing is chosen.
Assuming you have serial console and can interrupt boot and pick a kernel, then you could safely do the following and keep the defaults, but pick your test versions without risk by adding content as follows:
- Add a new
extlinux.conf
entry, e.g., something like this:
LABEL test
MENU LABEL test kernel
LINUX /boot/Image-test
APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4
Since you are going to add a device tree based on a file (there are also ways to do this as a partition), the entry would be further modified with a DTB
entry:
LABEL test
MENU LABEL test kernel
FDT /boot/dtb/edited.dtb
LINUX /boot/Image-test
APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4
Now, if you copied “edited.dtb
” to “/boot/dtb/edited.dtb
”, and you’ve picked the “test kernel” boot entry, expect your tree to be used without touching the original boot content. If it fails, then you simply pick the “primary kernel
” entry. If that entry is still set as the default, then you don’t have to do anything to get the original boot.
Let’s extend this to also adding a very different kernel due to non-module changes which are invasive. Your extlinux.conf
entry was already edited for the new kernel with name “Image-test
” for the file, but you will also now need to install a complete set of modules built against that configuration at this location (just to emphasize, this is an example which assumes “uname -r
” responds with “4.9.140-test
”):
/lib/modules/4.9.140-test/kernel
I don’t know anything about the camera, and have not worked on cameras before, but if you were to find an example entry for your carrier board, then it might just be a direct addition of that entry into your tree. If not, then perhaps you can build the kernel source “dtbs
” target to get an example, and then edit the content which shows up for your camera (but tailored to your carrier board).
As a caution note on kernel building, even if you are only building a module, you must take steps to propagate a proper configuration throughout the source before building. If you start by building the kernel itself, the “Image
” target, then this will all be taken care of and you won’t need to propagate configuration. If you don’t build Image
first, then to build a module you must propagate the configuration with the “make modules_prepare
” step (if you are building in a temp location, then you’d have to include options to that location, and if cross compiling, then you’d also have to have the cross compile options set).
I don’t know what your current situation is since there is a lot going on in this thread, and I am the wrong guy to ask about camera drivers, but if you summarize the current steps you want elaboration on, then I can probably give more exact answers (the above is purposely generalized since I don’t know details). Do note though that if you have an error, such as a kernel OOPS, then it is best to provide a copy of the full serial console boot log since hardware setup can occur as early as bootloader stages and the error itself is not very useful without knowing what lead up to the error.