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.
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.
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.
Written by
Andrés CamposCo-Founder & CTO · ProventusNova
8 years deep in embedded systems — from underwater ROVs to edge AI. Andrés leads every technical delivery personally.
Connect on LinkedIn