GMSL2 camera bring-up on Jetson Orin: MAX9295/MAX9296 setup
Bringing up a GMSL2 camera on Jetson Orin for the first time is a multi-step process that requires getting both hardware initialization and the software stack right before a single frame appears. The MAX9295 serializer and MAX9296 deserializer need to establish a link, the virtual channels need to be configured, and the V4L2 driver stack needs to see the sensor correctly. This post covers the full first-time setup sequence.
Key Insights
- GMSL2 bring-up has a fixed sequence: power → link lock → I2C tunnel → address reassignment → MIPI config → first frame
- Skip any step and the next one will fail with a misleading error
- The Jetson NVCSI is downstream of the deserializer, treat it exactly like a direct-attach CSI camera once the SerDes is configured
- NVIDIA provides reference bring-up scripts for devkit combinations; custom carrier boards need DTS modifications before any of those scripts work
dmesg | grep -i max929anddmesg | grep -i nvcsiin sequence tells you exactly which layer is failing
The bring-up sequence, in order
GMSL2 camera bring-up on Jetson Orin is a fixed six-step sequence. Every step depends on the previous one completing successfully. The most common mistake is jumping ahead, testing MIPI output before confirming I2C tunnel, for example, and then spending hours debugging the wrong layer.
Step 1: Power. The MAX9296A deserializer needs stable VDD (1.8V) and VDDIO (1.8V or 3.3V) before anything else. The PWDNB pin must be driven high (or pulled high) to bring the chip out of power-down mode. On the camera side, the MAX9295A serializer needs its own VDD from the carrier board or from the camera module.
Step 2: Link lock. Once both chips are powered, the link training starts automatically. The MAX9296A drives the lock signal on the coax; the MAX9295A responds. This takes 5–50 ms. Read register 0x0013 on the MAX9296A, bit 3 should be 1. If it is not, link lock has failed and nothing downstream will work.
Step 3: I2C tunnel. With the link locked, the I2C tunnel is active. The deserializer forwards I2C transactions from the host to the serializer side. Verify by running i2cdetect on the camera I2C bus, you should see the MAX9295A at 0x40 and the sensor at its default address.
Step 4: Address reassignment. For multi-camera designs, each MAX9295A must be assigned a unique I2C address before individual sensor access is possible. This is done sequentially: enable link 0 only, reassign its serializer address, disable link 0, enable link 1, reassign, and so on. The kernel driver handles this if the DTS is correct.
Step 5: Sensor initialization. With unique addresses assigned, write the sensor initialization register sequence. For IMX390 or similar, this means writing the full register table for the desired resolution and frame rate mode.
Step 6: MIPI output. Configure the MAX9296A’s MIPI output (lane count, data rate, virtual channel mapping) to match what the Jetson NVCSI expects. This is done by the kernel driver based on the DTS configuration. Once set, the deserializer starts forwarding frames to the NVCSI.
Device tree requirements for Jetson Orin
The DTS for a GMSL2 camera on Jetson Orin has a specific structure. The NVCSI node references the deserializer output port, and the deserializer node contains the serializer and sensor as child nodes.
/* tegra234-camera-gmsl2-imx390.dts */
#include <dt-bindings/clock/tegra234-clock.h>
#include <dt-bindings/gpio/tegra234-gpio.h>
/ {
tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
modules {
module0 {
badge = "imx390_gmsl2";
position = "front";
orientation = "1";
drivernode0 {
pcl_id = "v4l2_sensor";
devname = "imx390 2-001a";
proc-device-tree = "/proc/device-tree/i2c@31c0000/max9296@48/max9295@40/imx390@1a";
};
drivernode1 {
pcl_id = "v4l2_lens";
};
};
};
};
};
&i2c3 {
max9296@48 {
compatible = "maxim,max9296";
reg = <0x48>;
csi-mode = "2x4";
max-src = <2>;
reset-gpios = <&tegra_aon_gpio TEGRA234_AON_GPIO(AA, 0) GPIO_ACTIVE_LOW>;
ports {
port@0 {
reg = <0>;
max9296_gmsl0_in0: endpoint@0 {
remote-endpoint = <&max9295_gmsl0_out0>;
link-frequency = /bits/ 64 <1500000000>;
};
};
port@1 {
reg = <1>;
max9296_csi_out0: endpoint {
remote-endpoint = <&nvcsi_in0>;
data-lanes = <1 2 3 4>;
};
};
};
max9295@40 {
compatible = "maxim,max9295";
reg = <0x40>;
nvidia,gmsl-dser-device = <&max9296>;
port@0 {
reg = <0>;
max9295_gmsl0_out0: endpoint {
remote-endpoint = <&max9296_gmsl0_in0>;
};
};
imx390@1a {
compatible = "sony,imx390";
reg = <0x1a>;
sensor_model = "imx390";
physical_w = "5.37";
physical_h = "3.02";
sensor_modes {
mode0 {
num_lanes = "4";
mclk_khz = "37125";
pix_clk_hz = "594000000";
link_freq_hz = "1500000000";
csi_pixel_bit_depth = "12";
active_w = "1920";
active_h = "1080";
framerate = "30000";
};
};
};
};
};
};
Diagnostic sequence
When GMSL2 bring-up fails, work through these checks in order rather than jumping to MIPI debugging:
# 1. Check link lock
sudo i2cget -y 3 0x48 0x13 # MAX9296A register 0x0013
# Bit 3 = 1 → locked, 0 → not locked
# 2. Check I2C tunnel — scan for devices on camera I2C bus
sudo i2cdetect -y 3
# Should show 0x40 (MAX9295A) and 0x1a (IMX390 or your sensor)
# 3. Check kernel driver probe
sudo dmesg | grep -i "max929\|gmsl"
# Should show probe success messages
# 4. Check NVCSI
sudo dmesg | grep -i nvcsi
# Should show no errors
# 5. Test capture
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080' ! \
nvvidconv ! xvimagesink -e
If step 1 fails, the problem is power or cable. If step 2 fails with the link locked, the I2C tunnel is misconfigured. If step 3 shows probe failure, the device tree is wrong. If step 4 shows uncorr_err, the MIPI lane count or data rate is mismatched.
Common GMSL2 bring-up errors
max9296 probe failed in dmesg
The deserializer driver can’t reach the chip. Check that VDD is stable, PWDNB is high, and the I2C bus number in the DTS matches the actual bus the chip is wired to. Confirm with i2cdetect -y <bus> before touching the DTS.
max9295 probe failed / no devices on camera I2C bus
Link lock hasn’t been established. The I2C tunnel only operates over a locked GMSL2 link. Go back to step 1, read register 0x0013 on the MAX9296A and confirm bit 3 is set.
uncorr_err in nvcsi or camrtc-capture-vi logs
MIPI data rate or lane count mismatch. The MAX9296A’s MIPI output is configured for a different data rate or number of lanes than the Jetson NVCSI expects. Check link_freq_hz in the sensor DTS node against the MAX9296A register configuration. Also verify data-lanes count in the deserializer output port matches the physical lane count from the serializer.
nvarguscamerasrc no cameras available after driver probe succeeds
The sensor driver loaded but the libargus camera stack can’t enumerate the sensor. This is usually a tegra-camera-platform DTS node issue, a missing or incorrectly named proc-device-tree path in the module definition. Check that the path points to the actual sensor node location in /proc/device-tree/.
Frames arrive for 5–10 seconds then drop to zero
GMSL2 link instability, usually from a marginal cable or connector. The link re-trains after a momentary error, causing a brief capture gap that looks like a pipeline stall. Check the cable for damage, reduce cable length if possible, and verify the MAX9296A’s equalization settings match the cable characteristics. ECC error counts in the MAX9296A registers will increase steadily before the link drops.
Custom carrier board vs devkit bring-up
Bring-up on a custom carrier board is materially different from bring-up on an NVIDIA devkit. On the devkit, NVIDIA provides tested overlays for supported camera modules, bring-up is applying the right overlay and running a validation script.
On a custom carrier board, you need to write the full DTS from scratch. The key differences:
| Devkit | Custom carrier board | |
|---|---|---|
| DTS | Apply NVIDIA overlay | Write from scratch |
| I2C bus | Fixed (documented) | Depends on your schematic |
| PWDNB / reset GPIO | Pre-wired | Must match your schematic |
| NVCSI port routing | Fixed in NVIDIA DTS | Depends on PCB layout |
| MIPI lane assignment | Documented by NVIDIA | Depends on trace routing |
The most common mistakes on custom boards: using the devkit GPIO numbers for PWDNB and reset (they’re different), using the wrong I2C bus number, and mismatching NVCSI port to physical MIPI lanes. All of these fail silently at different stages of the bring-up sequence.
If you’re bringing up GMSL2 on a custom carrier board and hitting the link lock stage reliably but failing at NVCSI or V4L2, the GMSL camera driver development service covers what a scoped engagement for this kind of problem looks like.
For the GMSL2 SerDes architecture overview, see GMSL2 SerDes explained: MAX9295 and MAX9296 for Jetson bring-up. If you are bringing up GMSL2 on a custom carrier board instead of a devkit, see GMSL2 cameras on a custom carrier board: what’s different from the devkit. If the sensor requires a custom kernel driver, see how to write a custom V4L2 camera driver for Jetson Orin.
The MAX9296A datasheet with full register maps is available on the Analog Devices product page. NVIDIA’s Jetson Linux Developer Guide covers the tegra-camera-platform DTS structure in the Sensor Driver Programming Guide.
Relevant Services
NVIDIA Jetson Expert Support
Stuck on a Jetson bring-up?
We've debugged this failure mode before. BSP, device tree, camera pipelines, OTA, most blockers clear in the first session. No long retainers. No guessing.
Frequently Asked Questions
What JetPack version should I use for GMSL2 camera bring-up on Jetson Orin?
JetPack 6 (L4T R36) is the current release for Orin. NVIDIA's reference GMSL2 drivers in L4T R36 are more mature than in R35, particularly around multi-camera synchronization and NVCSI configuration. If you are starting a new design, use the latest L4T R36.x release. Avoid R35.x for new GMSL2 work unless you have a specific reason to stay on JetPack 5.
My GMSL2 camera shows on i2cdetect but nvarguscamerasrc fails. Why?
i2cdetect confirms the sensor is reachable over the I2C tunnel, which means the GMSL2 link is locked and the tunnel is working. The nvarguscamerasrc failure is a capture pipeline problem, not a link problem. Check the device tree NVCSI port assignment, the MIPI lane count in the DTS, and whether the deserializer's MIPI output is configured to match what the Jetson NVCSI expects.
How do I configure the MAX9296A to output MIPI CSI-2 to Jetson?
The MAX9296A is configured via its I2C registers to set the MIPI output mode, data rate, lane count, and virtual channel assignments. The kernel driver handles this register sequence during probe. In the device tree, the deserializer's output port must declare the correct data-lanes count and link-frequencies matching the sensor's output. The NVCSI node references the deserializer port as its input.
Can one MAX9296A deserializer feed multiple NVCSI ports on Jetson Orin?
The MAX9296A has two MIPI output ports (MIPI_A and MIPI_B), each of which can be routed to a separate NVCSI port on the Jetson. A dual-camera configuration typically routes camera 0 to MIPI_A → NVCSI port 0 and camera 1 to MIPI_B → NVCSI port 1. The device tree must reflect this routing explicitly.
What is the correct reset sequence for GMSL2 bring-up on Jetson?
Power on the deserializer first, then the serializer. Assert the MAX9296A PWDNB pin to bring the deserializer out of power-down. Wait 5 ms for the deserializer to stabilize. Then power the serializer side (camera board VDD). The GMSL2 link training starts automatically. Wait for LOCK bit to set before any I2C register access.
What does uncorr_err mean in GMSL2 or NVCSI kernel logs?
uncorr_err (uncorrectable error) in the nvcsi or tegra-camrtc-capture-vi kernel logs means the NVCSI is receiving frames with uncorrectable MIPI errors. The most common cause is a MIPI data rate or lane count mismatch between the MAX9296A output configuration and the NVCSI expectation in the device tree. Check that link_freq_hz in the sensor DTS node matches the MAX9296A's configured output data rate, and that data-lanes matches the physical lane count.
What I2C address does the MAX9295A serializer use by default?
The MAX9295A serializer defaults to I2C address 0x40. The MAX9296A deserializer defaults to 0x48. For multi-camera designs, each MAX9295A must be reassigned a unique address before individual camera access is possible. The kernel driver does this sequentially during probe, but only if the DTS has unique reg values for each serializer node.
How long does GMSL2 link training take?
GMSL2 link training typically completes in 5-50ms after both chips are powered. The actual time depends on cable length and quality, longer cables introduce more signal degradation and may require longer equalization time. At boot, the kernel driver polls the LOCK bit with a timeout. If you see link lock failures at boot that resolve after a reboot, it usually means the power sequencing is too fast and the serializer doesn't have stable power when link training starts.
What is the difference between GMSL2 bring-up on a devkit vs a custom carrier board?
On an NVIDIA devkit (AGX Orin DevKit, Orin NX DevKit), NVIDIA provides reference DTS and initialization scripts for supported camera modules. Bring-up is a matter of applying the correct overlay. On a custom carrier board, you need to write the full DTS from scratch: the I2C bus assignment, GPIO assignments for PWDNB and reset, NVCSI port routing, and lane configuration all depend on your schematic. This is where most custom carrier board GMSL2 projects get stuck, the reference DTS is rarely usable without modification.
How do I test GMSL2 link stability after first frame?
Run the capture pipeline for at least 5 minutes and monitor for frame drops and ECC errors. Check dmesg continuously with dmesg -w and watch for nvcsi or camrtc-capture-vi errors. Use v4l2-ctl --stream-mmap with a high frame count and count the received frames, any shortfall indicates dropped frames. A stable GMSL2 link should produce zero errors at nominal frame rate indefinitely.
Written by
Aarón AnguloCo-Founder & CEO · ProventusNova
Obsessed with client outcomes. Aarón ensures every engagement delivers real results, on time, on scope, no exceptions.
Connect on LinkedInRelated Articles
GMSL2 cameras on a custom carrier board: what's different
GMSL2 camera bring-up on a custom Jetson carrier board differs from devkit in specific, predictable ways. I2C bus, NVCSI routing, GPIO assignments, and.
GMSL2 camera driver on Linux: V4L2, MAX9296 kernel driver, device tree
How to set up a GMSL2 camera driver on Linux for Jetson. MAX9296A deserializer kernel driver, V4L2 subdev chain, device tree structure, and common probe.
GMSL2 camera not working on Jetson: 5 failure modes
GMSL2 camera not working on Jetson Orin? These 5 failure modes cover link lock failure, I2C tunnel issues, MIPI misconfiguration, address conflicts, and.
Custom GMSL2 camera driver for Jetson: V4L2 subdev
Write a custom GMSL2 sensor driver for Jetson Orin. tegra-camera-platform ops, sensor mode table, register tables, SerDes integration, and troubleshooting.