Just some background…
The kernel has both integrated features (things you can’t remove while running…not necessarily something that runs, but the code is always available), and it also has the ability to use a large number of drivers as loadable modules. Modules, if no hardware is currently bound to them, can be added or removed at any time on a running system without reboot.
In the various kernel configuration tools answering ‘y’ to use a feature generally builds an integrated feature. The base “Image” file is altered.
In the various kernel configuration tools answering ‘m’ to use a feature generally builds a module. The base “Image” file is left alone and a separate module is built.
Not all features can be a module, although most can.
On a Linux system the command “uname -r” will tell you the base kernel version (e.g., “4.4.38”), along with an extension custom to the particular build. If the source code is version “4.4.38”, and the config option “CONFIG_LOCALVERSION” is “-tegra” during the build, then the booted system will answer “uname -r” as “4.4.38-tegra”. Modules are searched for somewhere within:
If your starting system says “4.4.38-tegra” on “uname -r”, and if you are using source code for 4.4.38, and if you have set CONFIG_LOCALVERSION to “-tegra”, then you can add new modules directly to the correct subdirectory of “/lib/modules/4.4.38-tegra/”. Usually the subdirectory of that is “drivers/something…”, and the kernel source code itself is in that same subdirectory structure, e.g., if the kernel driver is at “drivers/something/new.ko”, then the right place in the module directory is to copy the “new.ko” to “/lib/modules/4.4.38-tegra/kernel/drivers/something/new.ko”.
If you mess up a module install, then generally it isn’t too hard to fix. If you mess up an Image install, then the system may become unbootable (in which case you might be able to use a rescue SD card, or might end up cloning and flashing to save the system).
If you were to change the configuration of a kernel build such that an integrated feature is changed, then it is usually better to change the “CONFIG_LOCALVERSION” slightly and build all of the modules again instead of reusing the old modules (this isn’t a hard rule…it is a rule of thumb).
If you build a new Image, then you should leave the old one in place and put a modified Image name in “/boot”, and then edit “/boot/extlinux/extlinux.conf” to point at the new Image, e.g., call it “Image-custom”. This way the original kernel is still there and rescue is usually much easier to deal with. If you have a serial console cable, then you can actually pick which kernel you want to boot by picking the extra entry or the original entry in extlinux.conf. You might want to explore extlinux.conf. For information on serial consoles see:
Some drivers are supplemented by firmware. Drivers run in Linux, firmware is uploaded into the specific hardware. Most hardware does not use firmware. Some WiFi devices do use firmware (it is easier to supply one model of hardware and meet regulatory requirements through firmware…versus a different hardware model for every region of the world). This is separate and independent of building a kernel or module, but beware the device won’t work without firmware if it is designed to use firmware and the firmware is not present.
About kernel builds…
When you have the kernel source a build looks for a file named “.config” at the base of the tree. Your Jetson will provide file “/proc/config.gz” which is a gzip copy of the running system’s current configuration (it is an exact match of how the kernel was originally built, except it leaves out CONFIG_LOCALVERSION). You should copy “/proc/config.gz” somewhere safe for future reference. Whenever you go to build a new kernel (or modules) you will want to put a copy in your kernel source’s base location, gunzip it, and rename it “.config”. Then, if you know what your “uname -r” was when this config was running (you should make a note of the original “uname -r” output), you can figure out what CONFIG_LOCALVERSION is. You can edit this in one of the config editors, but this is the only entry I edit with a regular editor.
Other URLs (or official Jetson docs) will give more information specific to building modules or kernels, but during config there are multiple possible config editor choices. My favorite is this…not because it is graphical or “fancy”, but because of how it lets you search for symbols (a “symbol” is a feature…often a driver name):
# Do what you need to copy in "/proc/config.gz" as gunzip and ".config" rename.
# Edit the CONFIG_LOCALVERSION of ".config" if you wish.
# Explore, answer 'm' if you find a module you want. If 'm' isn't possible, then 'y' would imply the feature is not modular.
Most official docs tell you how to cross compile. This means on your PC host you build for “arm64” instead of “x86_64”. Much of this is the same as native compile (obviously not the install), but uses a couple of environment variables.
Official documentation (look for “Documentation” for the particular L4T release URL) gives cross compile information.
Here are some steps if you wish to compile natively on your Jetson:
Much of the rest of the Linux world documentation is valid, except for install. Jetsons don’t have a BIOS, Jetsons don’t have a GRUB boot loader. Because of this you should get a serial console cable so you have more room for error if you are going to experiment with custom kernels.