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://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/overlay-template.md
Camera overlay regeneration recipe (referenced by SKILL.md §6)
The committed tegra<soc>-overlay-<carrier_short>-camera.dts is
regenerated from the in-tree NVIDIA reference templates. The
templates are read-only inputs; the agent never #includes them
into the carrier overlay at compile time, never copies the in-tree
__fixups__ placeholder pattern, and never ships the artefact with
unresolved macros from dt-bindings/.
Source templates (read-only inputs)
For SoC <soc> ∈ {t264 (Thor), t23x (Orin)}:
$L4T_DIR/source/hardware/nvidia/<soc>/nv-public/overlay/
tegra<soc>-p3971-camera-<sensor>-overlay.dts # connectivity + status="okay" overrides
tegra<soc>-camera-<sensor>*.dtsi # sensor body (mode tables, regulators, labels)
tegra<soc>-p3971-camera-modules.dtsi # disabled-by-default tegra-camera-platform skeletonFor Thor with the dual-IMX274 selection:
| Role | File |
|---|---|
| Overlay shape (status overrides + per-sensor connectivity) | tegra264-p3971-camera-dual-imx274-overlay.dts |
| Sensor body + endpoint labels (inline) | tegra264-camera-imx274-dual.dtsi |
Disabled tegra-camera-platform skeleton | tegra264-p3971-camera-modules.dtsi |
| Other sensor bodies (so the regenerator can swap) | tegra264-camera-{ar0234,e3331,e3333,imx185,imx390,p3762}-*.dtsi |
The dtsi defines all the cross-fragment endpoint labels
(liimx274_csi_in0/1, liimx274_csi_out0/1,
liimx274_imx274_out0/1, liimx274_vi_in0/1) inline, so a
preprocessed-and-merged DTS resolves them via __local_fixups__.
Recipe
Stitch input. Inject
#include "<sensor>.dtsi"after the gpio binding include in the per-sensor overlay file. This is a build-time stitch, not a runtime dependency:awk '/^#include <dt-bindings\/gpio\/tegra<soc>-gpio.h>/{ print; print "#include \"tegra<soc>-camera-<sensor>*.dtsi\""; next} {print}' \ $SRC/tegra<soc>-p3971-camera-<sensor>-overlay.dts > /tmp/cam_render/input.dtsMaterialise macros via
cpp -E. Resolve everydt-bindingssymbol to its literal value before any DTC pass:cpp -nostdinc -undef -x assembler-with-cpp \ -I $SRC \ -I $L4T_DIR/source/hardware/nvidia/<soc>/nv-public/include/kernel-<soc> \ -I $L4T_DIR/source/kernel/kernel-noble/include \ /tmp/cam_render/input.dts -o /tmp/cam_render/expanded.dtsexpanded.dtsnow contains literal clock IDs (<&bpmp 278U>), literal GPIO offsets (<&gpio_main 0x12 0>), and the full sensor body inlined. No moreTEGRA264_CLK_EXTPERIPH1, no moreCAM0_RST_L, no moreGPIO_ACTIVE_HIGH.Transform for the carrier. Programmatically rewrite the expansion:
Strip cpp
# N "file"line markers and SPDX headers emitted by the preprocessor; collapse consecutive blank lines.Replace
overlay-name = "Jetson Camera ..."with"<carrier_short> <sensor_id>".Replace the in-tree devkit compatible string list with
compatible =derived from the base kernel DTB's/compatible(read withdtc -I dtb -O dts $L4T_DIR/kernel/dtb/<DTB_FILE>thensed -n '/^\/ {/,/^};/p' | grep '^[[:space:]]*compatible').Replace
board_config.ids = "LPRD-..."with a carrier-specific stub the carrier's daughter-card EEPROM (or a software stub) reports.Substitute per-sensor wiring answers from
session.camera:reset-gpios(controller + offset),mux.channel(whichi2c@<ch>block undertca9546@70),port-index(CSI port per sensor),bus-width,vc-id.Prepend the mandatory header comment (carrier short, sensor selection, CSI port + lane assignments, MCLK + reset GPIO per sensor, the reference template paths, the citation list).
Compile + verify.
dtc -@ -I dts -O dtb \ -o $L4T_DIR/kernel/dtb/tegra<soc>-overlay-<carrier_short>-camera.dtbo \ <carrier_short>-camera.dts fdtoverlay -i $L4T_DIR/kernel/dtb/<DTB_FILE> -o /tmp/m.dtb \ $L4T_DIR/kernel/dtb/tegra<soc>-overlay-<carrier_short>-camera.dtbo strings /tmp/m.dtb | grep -E '<sensor>|tca9546|skip_mux_detect'fdtoverlayMUST exit zero. The grep MUST return ≥1 hit per expected substring. IfFDT_ERR_NOTFOUND, an external&labelreference doesn't resolve in the base DTB's__symbols__; fix it before flashing.
Invariants in the regenerated DTS
| Rule | Why |
|---|---|
Cross-fragment endpoint phandles use inline DTS labels (label: endpoint { ... }) referenced via <&label>. dtc -@ emits __local_fixups__; no manual __fixups__ block. | Resolution is internal to the dtbo; immune to base-DTB schema drift. |
External &label refs (&bpmp, &gpio_main/gpio_aon/gpio_uphy, &nvcsi, the chosen i2c controller's i2c<N> label) must each appear in the base DTB's __symbols__. | Without it, fdtoverlay rejects with FDT_ERR_NOTFOUND and the runtime applier silently drops the overlay. |
Anchor with target = <&label> when a symbol exists, else target-path = "/path". On Thor /tegra-capture-vi lives at root with no symbol — that fragment uses target-path. | Same. |
i2c-mux,deselect-on-exit lives on each i2c@<ch> child of the mux, not on tca9546@70. skip_mux_detect = "yes" lives on tca9546@70. | Driver expectation; missing them gives i2c bus regbase unavailable from camera_common, sensor probe -75. |
Endpoint pairing is symmetric and double-hop. vi_in<M> references the nvcsi output endpoint (channel@N/port@1), not the nvcsi sensor-input. | Inverting passes dtc + fdtoverlay but kills v4l2 graph link creation (failed to create … link). |
port-index on sensor + matching vi/port@M endpoint = SoC CSI port number (Thor: 0/2/4/6 for ×4; 1/3/5/7 for ×2 splits). | Hardware constraint. |
num-channels on tegra-capture-vi and nvcsi = active sensor count. Never inline the dynamic dtbo's [email protected] / [email protected] skeleton. | Skeleton's placeholder peer phandles aren't carried over and crash tegra-nvcsi: Failed to init csi channel. |
| Mandatory header comment — same rule as modify-uphy / modify-pcie: carrier short, sensor selection, CSI port + lane assignments, MCLK + reset GPIO per sensor, the reference template paths the regenerator consumed, the citation list. | Audit trail for a reviewer reading the dtbo six months later. |
The committed DTS contains zero #include directives and zero NVIDIA-header symbols. | A reviewer or rebuilder must be able to compile the artefact from a sanitised tree without staging the full L4T sources. |
Per-carrier substitution table
| Change | Where in expanded.dts |
|---|---|
| Different I²C bus | bus@0/i2c@<addr> wrapper + sysfs-device-tree strings under tegra-camera-platform/modules/* |
| Sensor count ≠ 2 | num-channels on capture-vi + nvcsi; add/remove i2c@<ch> blocks under tca9546@70 + matching channel@N + port@M + module<N> |
| Different sensor compatible | compatible = "<vendor,part>" on each sensor node; sensor body comes from the matching dtsi |
| GMSL multi-link on one CSI port | one fragment-set per sensor with unique vc-id = <0..3> on the matching endpoints |
| No tca9546 mux | drop tca9546@70 { ... }; sensors sit directly under the i2c controller; rewrite sysfs-device-tree strings |
| Reset GPIO on a different controller | reset-gpios = <&gpio_aon …> or <&gpio_uphy …> per the carrier pinmap; verify the symbol exists in __symbols__ |
Carrier __symbols__ missing the i2c label | use target-path = "/bus@0/i2c@<addr>" instead of target = <&i2cN> |
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