NVIDIA Jetson Device Tree: Why Swapping the Carrier Board May Break Things
While unboxing and getting started with Jetson at the very beginning, you may always encounter this problem: Swapped the Carrier Board and USB Stopped Working. How does it happen? It All Starts with the Device Tree. Once we boot up the complete Jetson software stack and run on it, how exactly does Linux know which hardware is attached to the board?
For example, the same Jetson Orin Nano module works perfectly fine on NVIDIA’s official Orin Nano Developer Kit carrier board, but after switching to a different carrier board, USB may stop working. The Jetson module hasn’t changed, and the Linux Kernel hasn’t changed either. Why can swapping just the carrier board completely change the behavior of the whole system?
This brings us to a very important concept in Jetson hardware development: the Device Tree.
In this article, we focus on three questions:
- What exactly is the Device Tree everyone keeps talking about?
- Why does much of the hardware stop working directly after the carrier board is replaced?
- Why do Seeed Studio’s Jetson carrier boards need their own BSP instead of directly using NVIDIA’s official BSP?
What Exactly Is the Device Tree?
As mentioned earlier, the Linux Kernel manages the system’s low-level hardware. But how does the Kernel know which devices are on the carrier board? The answer is the Device Tree.
The Device Tree tells the Linux Kernel what hardware is on the board and how it’s connected.
For example, if a schematic defines a sensor attached to a certain I2C bus with a certain bus address, and its reset line tied to a certain GPIO — that information will typically appear in the Device Tree in a corresponding form.
So we prefer to think of the Device Tree as a hardware wiring guide written for the Linux Kernel: schematics are drawn for humans, while the Device Tree is written for the Linux Kernel.
Later, we will look at what these “hardware connection relationships” actually look like in code, based on Seeed Studio’s real L4T BSP.
Seeed Studio has open-sourced the BSPs for all Jetson products at Seeed-Studio/Linux_for_Tegra. The repository contains many files ending in .dts — these are the Device Tree files we are about to discuss.
A Concrete Example: How the Device Tree Affects PCIe / NVMe
We just said the Device Tree is a “hardware wiring guide written for the Linux Kernel” — so what does it actually look like in real code?
Let’s look directly at the Device Tree of the Seeed Studio J401.
In the open-source repository, there is a Device Tree file named tegra234-j401-p3768-0000+p3767-0000.dts. Open it and you will find a node like this:
vdd_3v3_pcie: regulator-vdd-3v3-pcie {
compatible = "regulator-fixed";
regulator-name = "VDD_3V3_PCIE";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio_aon
TEGRA234_AON_GPIO(AA, 5)
GPIO_ACTIVE_HIGH>;
enable-active-high;
};
This configuration describes a 3.3 V power rail for PCIe. The key pieces of information are:
regulator-name
→ This power rail is called VDD_3V3_PCIE
3300000
→ The voltage is 3.3 V
TEGRA234_AON_GPIO(AA, 5)
→ It is controlled by AON GPIO AA.5
enable-active-high
→ The rail is enabled when the GPIO is driven high
In other words, a PCIe Power Enable signal on the carrier board schematic is ultimately described to Linux through the Device Tree. This is a very intuitive example of “hardware connection relationships being written into the Device Tree”.
Only when these configurations are correct does the Kernel get a chance to bring up the PCIe link and enumerate the NVMe drive on the PCIe bus.
Let’s connect this with the boot log from the previous article. When the configuration is correct, you will see something like this in the UART boot log:
[ 6.639293] tegra194-pcie 14160000.pcie: Link up
[ 6.649851] nvme nvme0: pci function 0004:01:00.0
[ 6.665906] nvme0n1: p1 p2 p3 ...
The whole relationship forms a chain:
Device Tree
↓
Linux initializes the hardware based on its description
↓
Drivers do their work
↓
The boot log shows the result
In other words:
What you see in the boot log is the result, and the Device Tree is one of the key sources of configuration behind that result.
[Image placeholder 1: A flow diagram of Device Tree → hardware initialization → Driver → Boot Log (same content as the text chain above; keeping just one is recommended — it can be redrawn as a cleaner horizontal flow diagram based on the text chain)]
If the Device Tree does not match the actual carrier board, problems appear. Suppose a new carrier board routes the PCIe 3.3 V enable signal to a different GPIO, but the Device Tree still says AON GPIO AA.5 — Linux may keep controlling the wrong GPIO following the old design.
The result: the NVMe SSD fails to be recognized — the boot log may reach the Linux Kernel stage, but the PCIe Link up message never appears. At this point, you should have a good sense of what the Device Tree is.
Device Tree File Formats: What’s the Difference Between DTS, DTSI, DTB, and DTBO?
In a Jetson BSP, you will often see these four kinds of files: .dts, .dtsi, .dtb, and .dtbo. They look similar, but their roles are different. Here is a table to build the overall picture first:
| File | Full Name | Main Purpose | Human-Readable? | Example in Seeed’s Open-Source Repository |
|---|---|---|---|---|
| .dts | Device Tree Source | Describes one specific board, or one overlay | ✅ | tegra234-j401-p3768-0000+p3767-0000.dts |
| .dtsi | Device Tree Source Include | Holds common configuration reused by multiple DTS files | ✅ | tegra234-p3768-0000+p3767-xxxx-nv-common.dtsi |
| .dtb | Device Tree Blob | The compiled binary Device Tree generated from DTS/DTSI | ❌ | tegra234-j401-p3768-0000+p3767-0000-recomputer.dtb |
| .dtbo | Device Tree Blob Overlay | Adds or modifies part of the hardware configuration on top of a base Device Tree | ❌ | tegra234-p3767-camera-p3768-imx219-dual-seeed.dtbo |
First, DTS and DTSI
You can think of a .dts as the “entry file” for one specific board, while a .dtsi is more like a shared configuration module.
For example, Seeed’s J401 DTS includes other Device Tree files:
#include "tegra234-p3767.dtsi"
#include "tegra234-p3768-0000.dtsi"
So in a real project, the Device Tree is not one giant .dts file written top to bottom — it is assembled layer by layer from many .dtsi files.
You can loosely compare it to the C language:
.dtsi is somewhat like .h
.dts is somewhat like the final .c that combines those configurations
Of course the analogy is not strictly equivalent — it is only meant to help you grasp the relationship faster.
DTB: The Binary Device Tree Linux Actually Uses
.dts and .dtsi are for developers to read and modify. After being compiled by dtc (the Device Tree Compiler), they produce a .dtb.
What Linux actually reads at boot time is the compiled .dtb, not the .dts sitting in the source directory.
DTBO: Modifying Only Part of the Hardware Configuration
Some hardware is not installed on every device — a camera, for example. If adding one IMX219 meant copying and maintaining an entire new set of J401 Device Tree files, that would be extremely cumbersome. This is exactly the kind of problem DTBO (Device Tree Overlay) solves.
For example, Seeed’s BSP includes a camera overlay:
tegra234-p3767-camera-p3768-imx219-dual-seeed.dtbo
It is not a complete J401 Device Tree — it only describes the IMX219 camera-related configuration, such as:
- The I2C address
- Reset / power GPIOs
- The CSI interface
- NVCSI / VI connection relationships
- The camera sensor node
- …
You can find a similar configuration in Seeed’s recomputer-orin-j401.conf:
OVERLAY_DTB_FILE+=tegra234-p3767-camera-p3768-imx219-dual-seeed.dtbo
In other words, the base J401 hardware configuration still comes from the original DTB — only the camera-related configuration needs to be added on top.
Beyond the Device Tree: Jetson’s Earlier Board-Level Configuration
At this point, you should have a solid general understanding of the Device Tree, and the question from the beginning of this article should already be answered in your mind.
But have you noticed a new question?
The Device Tree is the schematic written for the Linux Kernel. Combined with the boot log from the previous article — before the Linux Kernel has even started, who configures hardware such as GPIO, pinmux, and pad voltage?
The answer: the bootloader stage has its own set of board-level configuration.
So on Jetson, you cannot simply equate “carrier board adaptation” with “modifying a Kernel DTB”. The more complete relationship looks like this:
Carrier Board
↓
Actual hardware connections
↓
┌────────────┴────────────┐
↓ ↓
Bootloader Board Config Kernel Device Tree
↓ ↓
MB1 / MB2 / UEFI Linux Kernel
↓ ↓
Pinmux / Pad Voltage USB / PCIe / Camera
GPIO / Early HW Ethernet / Sensor
If you want to understand how these pieces relate, the best way is to study them directly in Seeed Studio’s Linux_for_Tegra repository.
Taking J401 as an example, flashing uses recomputer-orin-j401.conf. You can think of this file as an important “board-level configuration entry point” for the J401 — it selects the corresponding DTB based on the Jetson module SKU, for example:
tegra234-j401-p3768-0000+p3767-0000-recomputer.dtb
tegra234-j401-p3768-0000+p3767-0001-recomputer.dtb
tegra234-j401-p3768-0000+p3767-0003-recomputer.dtb
tegra234-j401-p3768-0000+p3767-0004-recomputer.dtb
Notice an important piece of information here:
The Device Tree is not only related to the carrier board — it is related to the combination of carrier board + Jetson module.
And the .conf file contains more than just:
DTB_FILE --> The Kernel Device Tree used by Linux
You will also see:
PINMUX_CONFIG --> Pinmux configuration
PMC_CONFIG --> Pad voltage / PMC-related configuration
OVERLAY_DTB_FILE --> Extra overlays for camera, display, etc.
BPFDTB_FILE --> The Device Tree used by BPMP
We won’t expand on the rest here — feel free to explore on your own, and you’re welcome to discuss with us in the Seeed Jetson community.
How to Check Which Device Tree Linux Is Actually Using?
If the device can already boot into the desktop, you can also directly inspect the Device Tree the running system is actually using.
Export the currently running Device Tree:
sudo dtc -I fs -O dts /proc/device-tree > running.dts
Then you can check the corresponding nodes directly, for example:
grep -n "pcie" running.dts
grep -n "usb" running.dts
[Image placeholder 2: A terminal screenshot showing the output of grepping the usb nodes after exporting /proc/device-tree]
When debugging the Device Tree, what truly matters is not only “which DTS file I modified”, but more importantly whether the system is actually running the version you modified.
Wrapping Up
The Device Tree itself is not complicated — the core problem it solves is just one:
Let the software know exactly which hardware is on the carrier board, and how that hardware is connected.
But on Jetson, carrier board adaptation is about more than just the Kernel Device Tree.
As you can see from Seeed Studio’s L4T BSP, a carrier board truly needs its own complete set of board-level configuration. This is exactly why Seeed Studio’s Jetson products need their own BSP, rather than simply reusing the configuration of NVIDIA’s Developer Kit.
Thanks for reading — your feedback will directly shape the articles that follow.
About the Jetson Deep Dive Series
This is an in-depth technical column on Jetson entry-level development from Seeed Studio, with a new article published every week. The series covers Jetson kernel development, boot flows, drivers, and peripheral adaptation, helping you level up from “using a Jetson” to “understanding a Jetson”.
As an NVIDIA Elite Partner, Seeed Studio supports edge AI developers through every stage — from prototyping to production — with Jetson-powered hardware ready to ship, getting started from Jetson Orin Nano to the ultimate Jetson Thor modules.
Learn more about Seeed Studio reComputer NVIDIA Jetson ecosystem: https://www.seeedstudio.com/tag/nvidia.html
