Jetson Customize Camera
NVIDIAOfficialCreated by Jetson TeamDistributed by NVIDIA
- Skill
- Workflow
- Software development
- Apache-2.0
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill automates the bring-up of MIPI and GMSL camera sensors on custom Jetson Thor or Orin carrier boards. It functions by rendering a kernel-DT overlay from in-tree sensor DTSI files, ensuring correct wiring and configuration without requiring manual ODMDATA or UPHY lane adjustments. The process is agentic, utilizing a structured workflow to verify carrier and module support, generate the necessary device tree fragments, and validate the final composite overlay before compilation.
What it does
- Enumerates supported sensors from in-tree DTBO files.
- Cross-references carrier and module support against official documentation.
- Generates and appends a single camera-tagged fragment to the composite custom overlay.
- Verifies ancillary pin configurations like I2C, clocks, and GPIOs.
- Validates the final device tree structure using dtc and fdtoverlay.
- Automates the commit process for the hardware repository.
When to use it
- When configuring a new MIPI or GMSL camera sensor on a custom Jetson carrier board.
- When a camera is physically connected but fails to enumerate in v4l2-ctl.
- When adding additional sensors to an existing multi-sensor Jetson platform.
- When you need to ensure correct CSI port plumbing and sensor driver binding.
Advantages
- Reduces manual errors by using in-tree DTSI files as the source of truth.
- Prevents common pitfalls like dual-fragment conflicts or incorrect port indexing.
- Maintains a clean, idempotent workflow for hardware customization.
- Ensures compatibility with the existing BSP and flash-conf registration.
Usage examples
- “Enable the IMX274 camera on my custom Orin carrier board.”
- The agent identifies the sensor, verifies the carrier pinmap, generates the required kernel-DT overlay fragment, and commits it to the BSP source repository.
- “I need to add a GMSL camera to my existing Jetson Thor setup.”
- The agent performs a multi-sensor bring-up check, splices the necessary GMSL serdes configuration into the composite overlay, and validates the new endpoint connections.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/nvidia/jetson-customize-camera/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip jetson-customize-camera.zip -d .agents/skills
Documentation by Jetson Team
Customize camera (CSI / MIPI / GMSL sensor bring-up)
Overview
Tegra264 (Thor) and Tegra234 (Orin) expose a single tegra-capture-vi
controller fronted by NVCSI and a fixed set of CSI ports. Camera
bring-up is:
Sensor selection — picked from the set NVIDIA ships in-tree
.dtsireferences for on the active platform.Carrier + module support check — verified against the Camera Development Guide, Adaptation Guide §Camera, carrier schematic, Module TRM, and carrier pinmap.
Wiring — derived from the in-tree
tegra<soc>-camera-<sensor>*.dtsiwhen one exists (the DTSI IS the wiring source of truth); captured per-sensor from the user when the sensor is custom.Kernel-DT overlay — cpp-expand the in-tree DTSI, extract its
fragment@Nbody, append into the composite custom overlay.dtsfor the active target (per../../references/bsp-customization-kernel-dtb.md), verify the composite withfdtoverlay./jetson-build-sourcecompiles the composite and owns the carrier conf'sOVERLAY_DTB_FILE+=registration.
Agentic, not table-driven — sensor list is built at runtime by
globbing in-tree per-sensor dtbos. No _THOR_CAMERAS dict, no
questions.json, no Python renderer in the question path.
No ODMDATA edit — cameras don't consume UPHY lanes (CSI is a separate PHY pool). The skill emits only a kernel-DT overlay; the ODMDATA line in the carrier conf is untouched by this skill.
The output is one commit:
Camera
fragment@Nblock (plusjetson-header-nameon the composite root if not already present) appended to the composite custom overlay.dtsper../../references/bsp-customization-kernel-dtb.md→ committed to thebsp_sources/hardware repo./jetson-build-sourcecompiles the composite to.dtboand owns its Makefile + flash-conf registration.
When to invoke
The user says "enable camera", "configure CSI", "wire a Hawk / Owl / IMX sensor", "MIPI camera", "GMSL camera", or asks to bring up
tegra-capture-vi/ NVCSI on a custom carrier.Flash boots but
v4l2-ctl --list-devicesshows notegra-capture-vichannels, OR sensor enumeration on a fresh daughter-card needs to be confirmed.A sensor was previously enabled and the user wants to add another (multi-sensor bring-up).
Prerequisites:
Active profile with
reference_devkit:+custom_carrier:blocks.<source.root_path>/Linux_for_Tegra/.gitexists (/jetson-init-source)./jetson-derive-carrierhas run — the carrier flash-conf fork is in the overlay tracker.<source.root_path>/bsp_sources/hardware/nvidia/<chip-dir>/nv-public/overlay/exists and contains the in-tree per-sensor.dtsifiles (sourced by/jetson-init-source's Branch A archive extract).<source.root_path>/bsp_sources/kernel/kernel-noble/include/dt-bindings/contains the macro headers cpp needs (source_sync.shmay need to run if Branch B was used — see Step 5a.i below).Source-of-truth docs registered or supplied at prompt: Camera Development Guide (in
bsp_developer_guidemirror or separate path), Adaptation Guide §Camera, carrier schematic, SoC TRM, Module Design Guide.dtc,cpp,fdtoverlayon PATH.
Procedure
Detailed step-by-step procedure (Steps 1–7, with all tables, code
blocks, and gates) lives in
references/procedure.md. Summary:
Step 1 — Resolve active target + open source-of-truth docs.
Step 2 — Enumerate supported sensors by globbing in-tree per-platform camera dtbos; classify as DPHY-direct / GMSL / custom. Never invent sensors.
Step 3 / 3a — Cross-check carrier + module support against DTSI, Camera Development Guide, Adaptation Guide §Camera, SoC TRM, Module Design Guide, schematic, and carrier pinmap. Render the wiring table FIRST, then issue the confirm-or-customize gate.
Step 4 (custom path only) — Batched per-sensor wiring questions auto-filled from the carrier pinmap.
Step 5 — Append exactly ONE
/* custom-bsp: camera:<sensor> */fragment to the composite custom overlay.dts(see../../references/bsp-customization-kernel-dtb.md). Clone path cpp-expands the in-tree DTSI; custom path splices Step-4 answers + mode tables in-place. Idempotently setjetson-header-nameon the composite root. Verify withdtc+fdtoverlay(pre-compile single-fragment gate; post-compile deep-tree uniqueness gate). Commit via the workflow's commit-message preview gate.Step 6 — Verify ancillary CAM pin SFIOs (
cam_i2c_*,extperiph<m>_clk, reset/PWDN/PWR_EN GPIOs) viapin_verifier.py; route mismatches to/jetson-customize-pinmux.Step 7 — Atomic-write run-state JSON sidecar at
<workspace>/target-platform/<profile-stem>.jetson-customize-camera.jsonand emit the headline, then drive the downstream next-step chain via sequentialAskUserQuestionprompts perreferences/procedure.mdStep 7. The chain is a documented workflow gate, not a clarifying question — auto-mode does NOT exempt it. Never substitute a printed "Next step: …" line for the prompts.
Gotchas
Dual-fragment trap. Contribute exactly ONE camera-tagged
fragment@Nto the composite. A second one carrying status overrides triggers dtc deep-merge → duplicate sibling subtrees (e.g. twotca9546@70) → runtime first-match drops the dtsi- supplied deep tree → camera silently doesn't enumerate. Gate on this skill's marker only (Step 5c).Composite root
compatibleis owned globally, not by this skill. Don't widen from any in-tree per-sensor dtbo'scompatible(devkit-SKU-gated). Fix the composite root if needed.jetson-header-namefrom any in-tree per-sensor dtbo. Fixed, carrier-agnostic; read once, paste onto the metadata root.DO NOT also append the in-tree per-sensor dtbo to
OVERLAY_DTB_FILE. Registering both your rendered overlay AND the in-treetegra<soc>-p3971-camera-<sensor>-overlay.dtboproduces a phantom subdev bind that bricks camera enumeration.Stub overlay is a known footgun. Committing
tegra-capture-vi { status="okay"; num-channels=<N>; }with no ports / sensor / nvcsi body bricks the camera (all channel init failed). Splice the FULL sensor body via cpp + dtc.Sensor mode tables must be spliced, never hand-authored.
mode<N>,sensor_modes,pixel_phase— copy verbatim from the closest in-tree DTSI.camera_common_regulator_get (null) ERR: -EINVAL= missingavdd-reg/iovdd-reg/dvdd-regstrings — splice the FULL sensor body; always-on rails fall back to dummy regulator.External
&labelrefs must exist in base DTB's__symbols__. Usetarget-path = "/tegra-capture-vi"when the label is absent;fdtoverlayexits non-zero withFDT_ERR_NOTFOUNDotherwise.cppfailure ondt-bindings/gpio/gpio.h: No such file= L4T source tree isn't staged. Re-run/jetson-init-source(Branch B'ssource_sync.shfetches the headers). Never fabricate the macro expansion.No ODMDATA edit, no flash-conf edit. Camera doesn't consume UPHY lanes. The carrier conf's
ODMDATA="..."is untouched.OVERLAY_DTB_FILE+=is owned by/jetson-build-sourceStep 5.0a — this skill never touches the carrier flash conf.Don't touch the upstream BSP at
<bsp_image.root_path>. All edits land in<source.root_path>/Linux_for_Tegra/(overlay tracker) and<source.root_path>/bsp_sources/(overlay.dts) under the pristine + customization commit pattern.
References
references/procedure.md— full step-by-step Steps 1–7 procedure (extracted from this SKILL.md).references/csi-dt-bindings.md— CSI / nvcsi / vi DT binding reference notes.references/overlay-template.md— guidance on the metadata-root + clone-body overlay shape.references/camera-overlay-templates/— starter.dts.tmpltemplates:dphy-direct.dts.tmpl,gmsl-serdes.dts.tmpl.../../scripts/pin_verifier.py— shared HSIO pin verifier (Step 6).../../references/platform_template.yaml—documents:block consumed by Step 1.../../context/bsp-customization-workflow.md— overlay edit protocol.../jetson-customize-pinmux/SKILL.md— sibling skill auto-invoked by Step 6 to fix HSIO pin SFIO mismatches (CAM I²C, MCLK, reset GPIOs).../jetson-derive-carrier/SKILL.md— must run first; produces the carrier base overlay (the*-dynamic.dtbo) this skill's composite stacks after.../jetson-init-source/SKILL.md— produces the overlay tracker +bsp_sourcesrepo (with thehardware/nvidia/<chip-dir>/per-sensor DTSI tree) this skill reads and commits into.
Files
- ATTRIBUTION.mdAdded by AutoGineer932 B
- BENCHMARK.md3.8 KiB
- LICENSELicence file added by AutoGineer11.2 KiB
- SKILL.md9.6 KiB
- evals/evals.json5.3 KiB
- references/camera-overlay-templates/README.md2.6 KiB
- references/camera-overlay-templates/dphy-direct.dts.tmpl8.2 KiB
- references/camera-overlay-templates/gmsl-serdes.dts.tmpl8.2 KiB
- references/csi-dt-bindings.md3.6 KiB
- references/overlay-template.md7.5 KiB
- references/procedure.md17.0 KiB
- skill-card.md3.8 KiB
- skill.oms.sig6.0 KiB
references/camera-overlay-templates/gmsl-serdes.dts.tmpl
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* gmsl-serdes.dts.tmpl — agentic template for GMSL-based cameras.
*
* Use when each sensor sits behind a MAX9295/MAX96717 serializer over
* coax, terminated on the carrier by a MAX96712 (4-link) or MAX9296
* (2-link) deserializer that fans out to the SoC's NVCSI ports.
*
* Architecture (per sensor link):
*
* sensor (e.g. AR0234, OX03A10) ──I²C/MIPI──> MAX9295 serializer
* │
* coax ──> MAX96712 link@<i> ──> NVCSI port@<n>
*
* The deserializer typically lives behind a TCA9546-class I²C mux on
* the carrier, with one mux channel per GMSL link for serializer +
* sensor address space isolation.
*
* Placeholders (substituted by /jetson-modify-camera step 6):
*
* <<OVERLAY_NAME>> — e.g. "Jetson Camera p3762-a00 4Hawk"
* <<JETSON_HEADER_NAME>> — "Jetson AGX CSI Connector"
* <<COMPATIBLE_LIST>> — \0-joined; must match /proc/device-tree/compatible
* <<EEPROM_ID>> — daughter-card EEPROM id (read at probe)
*
* <<NUM_LINKS>> — number of sensor+serializer pairs (1..4)
* <<DESER_COMPATIBLE>> — "maxim,max96712" or "maxim,max9296"
* <<DESER_I2C_BUS_NODE>> — /aliases label of the deserializer's I2C bus
* <<DESER_ADDR>> — deserializer I2C address (0x29 typical for 96712)
* <<DESER_RESET_GPIO>> — GPIO triplet driving the deserializer reset
*
* <<MUX_COMPATIBLE>> — "nxp,pca9546" / "ti,tca9546" etc.
* <<MUX_NODE>> — node label, e.g. "tca9546"
* <<MUX_ADDR_HEX>> — 0x70..0x77
*
* For each link i = 0..<<NUM_LINKS>>-1:
* <<MUX_CHANNEL_<i>>> — mux output channel for this link
* <<PORT_INDEX_<i>>> — NVCSI port the deserializer feeds
* <<BUS_WIDTH_<i>>> — CSI lanes per link (typically 4 on 96712)
* <<VC_ID_<i>>> — virtual-channel id (0..3 — must be unique on a shared CSI port)
* <<SER_ADDR_<i>>> — serializer I2C address as seen by deserializer (e.g. 0x40)
* <<SENSOR_COMPATIBLE_<i>>> — "onnn,ar0234" / "ovti,ox03a10" / etc.
* <<SENSOR_ADDR_<i>>> — sensor I2C address as seen behind the link
* <<MCLK_NODE_<i>>> — extperiph clock controller phandle (typically driven by serializer or onboard XO)
* <<MCLK_RATE_HZ_<i>>> — MCLK frequency in Hz
*
* Sensor-specific register tables come from the closest in-tree
* tegra<soc>-p3971-camera-p3762-a00-<config>-overlay.dtbo decompiled
* with `dtc`. The agent splices those into the per-link sensor@<addr>
* subnode.
*/
/dts-v1/;
/ {
overlay-name = "<<OVERLAY_NAME>>";
jetson-header-name = "<<JETSON_HEADER_NAME>>";
compatible = "<<COMPATIBLE_LIST>>";
fragment@0 {
target-path = "/";
board_config {
ids = "<<EEPROM_ID>>";
sw-modules = "kernel";
};
__overlay__ {
tegra-capture-vi {
status = "okay";
num-channels = <<<NUM_LINKS>>>;
ports {
status = "okay";
/*
* REPEAT this port@<i> block for i = 0..<<NUM_LINKS>>-1.
* Each maps to one GMSL link arriving on NVCSI port <<PORT_INDEX_i>>.
*/
port@0 {
status = "okay";
endpoint {
status = "okay";
port-index = <<<PORT_INDEX_0>>>;
bus-width = <<<BUS_WIDTH_0>>>;
vc-id = <<<VC_ID_0>>>;
remote-endpoint = <&deser_out_link0>;
};
};
};
};
tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
num_csi_lanes = <<<BUS_WIDTH_0>>>;
max_lane_speed = <0x10c8e0>;
min_bits_per_pixel = <0x0a>;
vi_peak_byte_per_pixel = <0x02>;
vi_bw_margin_pct = <0x19>;
modules {
/* One module<i> entry per link — agent fills from session.camera.sensors[] */
};
};
};
};
/*
* fragment@1 — I²C bus subtree: mux → mux-channel → deserializer → serializer → sensor.
* Every GMSL link gets its own mux-channel subtree to isolate the
* serializer's I²C address space (multiple cameras can otherwise
* collide on the same default 0x40).
*/
fragment@1 {
target-path = "/<<DESER_I2C_BUS_NODE>>";
__overlay__ {
#address-cells = <0x01>;
#size-cells = <0x00>;
<<MUX_NODE>>: <<MUX_NODE>>@<<MUX_ADDR_HEX>> {
compatible = "<<MUX_COMPATIBLE>>";
reg = <<<MUX_ADDR_HEX>>>;
#address-cells = <0x01>;
#size-cells = <0x00>;
/*
* REPEAT this i2c@<i> subtree for each link i.
*/
i2c@0 {
reg = <<<MUX_CHANNEL_0>>>;
#address-cells = <0x01>;
#size-cells = <0x00>;
deser_link0: deserializer@<<DESER_ADDR>> {
compatible = "<<DESER_COMPATIBLE>>";
reg = <<<DESER_ADDR>>>;
reset-gpios = <<<DESER_RESET_GPIO>>>;
/*
* Serializer subnode — one per GMSL link the
* deserializer is bonded to.
*/
serializer@<<SER_ADDR_0>> {
compatible = "maxim,max9295";
reg = <<<SER_ADDR_0>>>;
};
/*
* Sensor subnode behind the serializer.
* Sensor-specific mode tables spliced in from the
* in-tree p3762 reference DTBO.
*/
sensor@<<SENSOR_ADDR_0>> {
compatible = "<<SENSOR_COMPATIBLE_0>>";
reg = <<<SENSOR_ADDR_0>>>;
clocks = <<<MCLK_NODE_0>>>;
clock-names = "extperiph1";
clock-frequency = <<<MCLK_RATE_HZ_0>>>;
ports {
#address-cells = <0x01>;
#size-cells = <0x00>;
port@0 {
reg = <0x00>;
sensor_link0_out: endpoint {
port-index = <<<PORT_INDEX_0>>>;
bus-width = <<<BUS_WIDTH_0>>>;
remote-endpoint = <&deser_out_link0>;
};
};
};
};
};
};
};
};
};
/*
* fragment@2 — Deserializer-output endpoint label so VI can find
* each link's data-stream. NVIDIA's p3762 reference overlays use
* `deser_out_linkN` labels — keep them stable so the
* remote-endpoint references above resolve at compile time.
*/
fragment@2 {
target-path = "/host1x@1300000/nvcsi@8c00000";
__overlay__ {
num-channels = <<<NUM_LINKS>>>;
#address-cells = <0x01>;
#size-cells = <0x00>;
channel@0 {
reg = <<<PORT_INDEX_0>>>;
ports {
#address-cells = <0x01>;
#size-cells = <0x00>;
port@0 {
reg = <0x00>;
deser_out_link0: endpoint@0 {
port-index = <<<PORT_INDEX_0>>>;
bus-width = <<<BUS_WIDTH_0>>>;
remote-endpoint = <&sensor_link0_out>;
};
};
};
};
};
};
};
Requirements and compatibility
Written for: Claude Code
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Names Claude Code tools
Security
What our scanner noticed· Medium risk
- Large base64-encoded blobs
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Jetson Team
- Publisher
- NVIDIA (Official)
- Distributed by
- NVIDIA
- Source
- NVIDIA/skills · skills/jetson-customize-camera · commit fce3cca
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE-APACHE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Jetson Team or NVIDIA.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download jetson-customize-camera.zip