Customize PCIe (per-controller status / lanes / speed)
Overview
PCIe on Tegra264 (Thor, pcie@C0..C5) and Tegra234 (Orin,
pcie@C0..C10) is split across multiple controllers that share the
UPHY lane pool with USB3 / MGBE / UFS. Each controller's runtime
behavior is determined by two surfaces, both required:
| Surface |
Target |
Authoritative for |
ODMDATA pcie@N_status=… (+ pcie@N_max-link-speed, pcie@N_pcie-mode, pcie@N_clk-scheme, pcie-cN-endpoint-enable) |
/pcie/pcie@N in BPMP DTB |
UPHY lane power, refclk gating, controller-side power rails |
Kernel-DT overlay on &pcieN |
/bus@0/pcie@<addr> in kernel DTB |
Kernel probe, lane width, link speed, RC/EP mode |
Skipping the kernel overlay on a disable lets the kernel probe a
powered-down PHY (link timeouts in dmesg). Skipping the ODMDATA token
on a disable leaves BPMP holding the PHY hot.
Agentic, not table-driven — no controller table, no
questions.json. Every controller, lane width, schematic-routed
receptacle, and authoritative DT node address is discovered at runtime
from the docs + DTB + carrier pinmap.
The output is a kernel-DT overlay commit only. Per-controller
fragment@N blocks are appended to the composite custom overlay
.dts per
../../references/bsp-customization-kernel-dtb.md
and committed to the bsp_sources/ hardware repo.
/jetson-build-source compiles the composite to .dtbo and owns its
Makefile + flash-conf registration.
This skill MUST NOT edit ODMDATA="...". All ODMDATA tokens
(pcie@N_status=…, pcie@N_max-link-speed, pcie@N_pcie-mode,
pcie@N_clk-scheme, pcie-cN-endpoint-enable, plus the
uphyX-config-N surface tokens and UPHY_CONFIG="" clear) are
emitted by /jetson-customize-uphy in a single atomic commit on the
carrier flash-conf fork. The allocation table this skill consumes
from the UPHY sidecar already tells the operator which controllers
are okay / disabled / per-lane sized; this skill only translates
that table into kernel-DT overlay fragments and verifies that the
overlay agrees with the ODMDATA already committed by customize-uphy
(consistency check in Step 8 — disagreement is reported, not silently
fixed).
When to invoke
- The user says "configure PCIe", "enable PCIe controller", "set PCIe
num-lanes", "change PCIe link speed", or asks to flip a
pcie@N_status token.
- A specific PCIe slot or M.2 receptacle doesn't enumerate after
flash, OR the link trains at the wrong width / speed.
jetson-customize-uphy ran and re-allocated lanes across PCIe controllers
(e.g. switched from uphy0-config-7 to uphy0-config-6 enabling
PCIe C3); the per-controller side now needs to be brought up.
jetson-customize-mgbe reports the QSFP path is wired but the kernel
doesn't probe its PCIe-side companion (rare; XFI configurations).
Prerequisites:
- Active profile with
reference_devkit: + custom_carrier: blocks.
<source.root_path>/Linux_for_Tegra/.git exists
(/jetson-init-source).
/jetson-derive-carrier has run — carrier flash-conf fork is in
the overlay tracker.
/jetson-customize-uphy has run — its JSON sidecar at
<workspace>/target-platform/<profile-stem>.jetson-customize-uphy.json
drives the per-controller enable decision.
- Source-of-truth docs registered or supplied at prompt: Adaptation
Guide, Module Design Guide, SoC TRM.
- When
custom_carrier: is present, both
documents.custom_carrier_schematic AND
documents.custom_carrier_pinmux_xls are REQUIRED. Refuse the run
if either is missing — routing on a custom carrier cannot be guessed.
Reference-devkit-only profiles skip this check.
dtc on PATH.
Procedure (summary)
Full step-by-step walkthrough lives in
references/procedure.md. High-level flow:
- Resolve active target + open source-of-truth documents (incl.
<carrier-pinmap>, <ref-dtb>, <uphy-state>). Refuse if
<uphy-state> is missing.
- Diff PCIe topology — devkit vs custom carrier — by decompiling
<ref-dtb> and grepping the schematic for PEX<N>_* net labels.
AskUserQuestion (multiSelect) — which controllers to customize.
- Per-controller verification: pinmap + schematic +
pin_verifier.py
for PE<N>_CLKREQ_L, PE<N>_RST_L, optional PE<N>_WAKE_L.
- Auto-derive per-controller plan (
enable from <uphy-state>,
lanes / speed from Adaptation Guide, mode hard-pinned to
"rc") → mandatory confirm-or-customize gate.
- Append per-controller
fragment@N blocks (marker
/* custom-bsp: pcie:pcie@<addr> */) to the composite custom
overlay .dts in bsp_sources/. Pre-flight dtc + fdtoverlay.
Commit via the workflow's preview gate.
Do not edit ODMDATA — /jetson-customize-uphy already emitted
pcie@N_status=…, pcie@N_max-link-speed, pcie@N_pcie-mode,
pcie@N_clk-scheme, and pcie-cN-endpoint-enable in its single
atomic ODMDATA commit. This skill only translates the per-controller
plan into kernel-DT overlay fragments.
- (Step folded into Step 6 — overlay-only emission.)
- Cross-check ODMDATA vs overlay consistency. On a contradictory
row, stop and ask the user how to recover the two commits.
Never run
git reset --hard autonomously.
- Write run-state JSON sidecar at
<workspace>/target-platform/<profile-stem>.jetson-customize-pcie.json
- summary, then drive the downstream next-step chain via sequential
AskUserQuestion prompts per references/procedure.md Step 9.
Never substitute a printed "Next step: …" line for the prompts.
Limitations
- Mode hard-pinned to RC. Endpoint mode is only emitted when the
operator passes
mode_override="ep" in Step 5c.
enable is derived, not asked. UPHY-allocated controllers are
mandatorily okay; non-allocated are mandatorily disabled.
- No upstream BSP edits. Output lands in
Linux_for_Tegra/ +
bsp_sources/ only.
- Pre-flight overlay merge is a sanity check, not the production
build.
/jetson-build-source is authoritative.
- Flash-conf overlay registration is out of scope. Owned by
/jetson-build-source Step 5.0a.
Troubleshooting
<uphy-state> missing → run /jetson-customize-uphy first.
- Slot doesn't enumerate after flash → check
dmesg | grep pcie;
re-verify ODMDATA pcie@<N>_status=okay and the overlay fragment
agree (Step 8 table in
references/procedure.md).
- Link trains at wrong width → confirm UPHY config in
<uphy-state> allocates the expected lane count; the kernel
fragment's num-lanes must match.
compatible mismatch → fix the composite root, not the
fragment. UEFI plugin-manager silently skips on mismatch.
- Contradictory ODMDATA-vs-overlay row → ask the user; do not
auto-
git reset --hard. See gotchas.
- Common pitfalls — see
references/gotchas.md (RC pinning, node-
address sourcing, stock-disabled controllers, intra-file handoff
with jetson-customize-uphy).
References
1---2name: jetson-customize-pcie3description: Per-controller PCIe enable / disable / lanes / link-speed for a Jetson Thor or Orin custom carrier via ODMDATA + kernel-DT overlay. Do NOT use for UPHY lane allocation or endpoint-mode bring-up.4license: Apache-2.05---67# Customize PCIe (per-controller status / lanes / speed)89## Overview1011PCIe on Tegra264 (Thor, `pcie@C0..C5`) and Tegra234 (Orin,12`pcie@C0..C10`) is split across multiple controllers that share the13UPHY lane pool with USB3 / MGBE / UFS. Each controller's runtime14behavior is determined by **two surfaces, both required**:1516| Surface | Target | Authoritative for |17|---|---|---|18| ODMDATA `pcie@N_status=…` (+ `pcie@N_max-link-speed`, `pcie@N_pcie-mode`, `pcie@N_clk-scheme`, `pcie-cN-endpoint-enable`) | `/pcie/pcie@N` in BPMP DTB | UPHY lane power, refclk gating, controller-side power rails |19| Kernel-DT overlay on `&pcieN` | `/bus@0/pcie@<addr>` in kernel DTB | Kernel probe, lane width, link speed, RC/EP mode |2021Skipping the kernel overlay on a disable lets the kernel probe a22powered-down PHY (link timeouts in dmesg). Skipping the ODMDATA token23on a disable leaves BPMP holding the PHY hot.2425**Agentic, not table-driven** — no controller table, no26`questions.json`. Every controller, lane width, schematic-routed27receptacle, and authoritative DT node address is discovered at runtime28from the docs + DTB + carrier pinmap.2930The output is a **kernel-DT overlay commit only**. Per-controller31`fragment@N` blocks are appended to the composite custom overlay32`.dts` per33[`../../references/bsp-customization-kernel-dtb.md`](../../references/bsp-customization-kernel-dtb.md)34and committed to the `bsp_sources/` hardware repo.35`/jetson-build-source` compiles the composite to `.dtbo` and owns its36Makefile + flash-conf registration.3738**This skill MUST NOT edit `ODMDATA="..."`.** All ODMDATA tokens39(`pcie@N_status=…`, `pcie@N_max-link-speed`, `pcie@N_pcie-mode`,40`pcie@N_clk-scheme`, `pcie-cN-endpoint-enable`, plus the41`uphyX-config-N` surface tokens and `UPHY_CONFIG=""` clear) are42emitted by `/jetson-customize-uphy` in a single atomic commit on the43carrier flash-conf fork. The allocation table this skill consumes44from the UPHY sidecar already tells the operator which controllers45are `okay` / `disabled` / per-lane sized; this skill only translates46that table into kernel-DT overlay fragments and verifies that the47overlay agrees with the ODMDATA already committed by `customize-uphy`48(consistency check in Step 8 — disagreement is reported, not silently49fixed).5051## When to invoke5253- The user says "configure PCIe", "enable PCIe controller", "set PCIe54 num-lanes", "change PCIe link speed", or asks to flip a55 `pcie@N_status` token.56- A specific PCIe slot or M.2 receptacle doesn't enumerate after57 flash, OR the link trains at the wrong width / speed.58- `jetson-customize-uphy` ran and re-allocated lanes across PCIe controllers59 (e.g. switched from `uphy0-config-7` to `uphy0-config-6` enabling60 PCIe C3); the per-controller side now needs to be brought up.61- `jetson-customize-mgbe` reports the QSFP path is wired but the kernel62 doesn't probe its PCIe-side companion (rare; XFI configurations).6364**Prerequisites:**6566- Active profile with `reference_devkit:` + `custom_carrier:` blocks.67- `<source.root_path>/Linux_for_Tegra/.git` exists68 (`/jetson-init-source`).69- `/jetson-derive-carrier` has run — carrier flash-conf fork is in70 the overlay tracker.71- `/jetson-customize-uphy` has run — its JSON sidecar at72 `<workspace>/target-platform/<profile-stem>.jetson-customize-uphy.json`73 drives the per-controller `enable` decision.74- Source-of-truth docs registered or supplied at prompt: Adaptation75 Guide, Module Design Guide, SoC TRM.76- **When `custom_carrier:` is present, both77 `documents.custom_carrier_schematic` AND78 `documents.custom_carrier_pinmux_xls` are REQUIRED.** Refuse the run79 if either is missing — routing on a custom carrier cannot be guessed.80 Reference-devkit-only profiles skip this check.81- `dtc` on PATH.8283## Procedure (summary)8485Full step-by-step walkthrough lives in86[`references/procedure.md`](references/procedure.md). High-level flow:87881. Resolve active target + open source-of-truth documents (incl.89 `<carrier-pinmap>`, `<ref-dtb>`, `<uphy-state>`). Refuse if90 `<uphy-state>` is missing.912. Diff PCIe topology — devkit vs custom carrier — by decompiling92 `<ref-dtb>` and grepping the schematic for `PEX<N>_*` net labels.933. `AskUserQuestion` (multiSelect) — which controllers to customize.944. Per-controller verification: pinmap + schematic + `pin_verifier.py`95 for `PE<N>_CLKREQ_L`, `PE<N>_RST_L`, optional `PE<N>_WAKE_L`.965. Auto-derive per-controller plan (`enable` from `<uphy-state>`,97 `lanes` / `speed` from Adaptation Guide, `mode` hard-pinned to98 `"rc"`) → mandatory confirm-or-customize gate.996. Append per-controller `fragment@N` blocks (marker100 `/* custom-bsp: pcie:pcie@<addr> */`) to the composite custom101 overlay `.dts` in `bsp_sources/`. Pre-flight `dtc` + `fdtoverlay`.102 Commit via the workflow's preview gate.103 **Do not edit `ODMDATA`** — `/jetson-customize-uphy` already emitted104 `pcie@N_status=…`, `pcie@N_max-link-speed`, `pcie@N_pcie-mode`,105 `pcie@N_clk-scheme`, and `pcie-cN-endpoint-enable` in its single106 atomic ODMDATA commit. This skill only translates the per-controller107 plan into kernel-DT overlay fragments.1087. (Step folded into Step 6 — overlay-only emission.)1098. Cross-check ODMDATA vs overlay consistency. On a contradictory110 row, **stop and ask the user how to recover the two commits.111 Never run `git reset --hard` autonomously.**1129. Write run-state JSON sidecar at113 `<workspace>/target-platform/<profile-stem>.jetson-customize-pcie.json`114 + summary, then drive the downstream next-step chain via sequential115 `AskUserQuestion` prompts per `references/procedure.md` Step 9.116 Never substitute a printed "Next step: …" line for the prompts.117118## Limitations119120- **Mode hard-pinned to RC.** Endpoint mode is only emitted when the121 operator passes `mode_override="ep"` in Step 5c.122- **`enable` is derived, not asked.** UPHY-allocated controllers are123 mandatorily `okay`; non-allocated are mandatorily `disabled`.124- **No upstream BSP edits.** Output lands in `Linux_for_Tegra/` +125 `bsp_sources/` only.126- **Pre-flight overlay merge is a sanity check**, not the production127 build. `/jetson-build-source` is authoritative.128- **Flash-conf overlay registration is out of scope.** Owned by129 `/jetson-build-source` Step 5.0a.130131## Troubleshooting132133- **`<uphy-state>` missing** → run `/jetson-customize-uphy` first.134- **Slot doesn't enumerate after flash** → check `dmesg | grep pcie`;135 re-verify ODMDATA `pcie@<N>_status=okay` and the overlay fragment136 agree (Step 8 table in137 [`references/procedure.md`](references/procedure.md)).138- **Link trains at wrong width** → confirm UPHY config in139 `<uphy-state>` allocates the expected lane count; the kernel140 fragment's `num-lanes` must match.141- **`compatible` mismatch** → fix the composite root, not the142 fragment. UEFI plugin-manager silently skips on mismatch.143- **Contradictory ODMDATA-vs-overlay row** → ask the user; do not144 auto-`git reset --hard`. See gotchas.145- **Common pitfalls** — see146 [`references/gotchas.md`](references/gotchas.md) (RC pinning, node-147 address sourcing, stock-disabled controllers, intra-file handoff148 with `jetson-customize-uphy`).149150## References151152- [`references/procedure.md`](references/procedure.md) — full nine-153 step procedure (topology diff, plan derivation, overlay append,154 ODMDATA cross-check, sidecar).155- [`references/gotchas.md`](references/gotchas.md) — failure modes156 + invariants (RC pinning, address sourcing, BPMP handoff).157- [`../../scripts/pin_verifier.py`](../../scripts/pin_verifier.py)158 — shared HSIO pin verifier (Step 4).159- [`../../references/platform_template.yaml`](../../references/platform_template.yaml)160 — `documents:` block consumed by Step 1.161- [`../../context/bsp-customization-workflow.md`](../../context/bsp-customization-workflow.md#workflow-invariants)162 — overlay edit protocol + commit message preview gate.163- [`../../references/bsp-customization-kernel-dtb.md`](../../references/bsp-customization-kernel-dtb.md)164 — composite overlay filename / skeleton / append protocol.165- [`../jetson-customize-uphy/SKILL.md`](../jetson-customize-uphy/SKILL.md)166 — sibling skill that owns UPHY lane allocation; its sidecar drives167 the per-controller `enable` decision.168- [`../jetson-customize-pinmux/SKILL.md`](../jetson-customize-pinmux/SKILL.md)169 — sibling skill invoked by Step 4 (with operator confirmation) to170 fix HSIO pin SFIO mismatches.171- [`../jetson-customize-mgbe/SKILL.md`](../jetson-customize-mgbe/SKILL.md)172 — sibling for MGBE controllers; shares the two-surface (ODMDATA173 + overlay) pattern.174- [`../jetson-derive-carrier/SKILL.md`](../jetson-derive-carrier/SKILL.md)175 — must run first; produces the carrier flash-conf fork edited in176 Step 6.177- [`../jetson-init-source/SKILL.md`](../jetson-init-source/SKILL.md)178 — produces the overlay tracker + bsp_sources repo this skill179 commits into.