Customize pinmux (per-pin SFIO / direction / state)
Overview
The Tegra pinmux spreadsheet (.xlsm) is the ground truth for every
CVM ball: SoC pin name, supported SFIOs, customer-selected function,
direction, and initial state. This skill parses that XLSM, runs a
per-pin Q1–Q6 interactive loop, and emits the three BCT DTSIs
(pinmux, gpio, padvoltage) in one shot into the overlay tracker
at <source.root_path>/Linux_for_Tegra/bootloader/.
Unlike sibling skills jetson-customize-uphy / jetson-customize-pcie /
jetson-customize-camera, pinmux has no kernel-DT overlay surface and no
ODMDATA edit. The XLSM is the source of truth; the three emitted
DTSIs land at flash time via the carrier conf's
PINMUX_CONFIG= / GPIOINT_CONFIG= / PMC_CONFIG= references (which
/jetson-derive-carrier set up).
Pad classification (silicon-fixed): only BD* and BI* pads have
configurable pull / drive / open-drain attributes. LP5XA_*,
UPHYDS_*, DP_SINGLE_*, BDMIPI16X_*, BDUSB2_*, OSCI27_* are
fixed-function and skip Q4–Q6 (configurable: no).
The bundled scripts/modify_pinmux.py is the workhorse: it parses
the XLSM via openpyxl>=3.1, builds the per-carrier pinmap JSON,
captures pin edits into a session shim, and (on generate) writes
the three DTSIs.
When to invoke
- The user says "configure pin", "set SFIO", "edit pinmux DTSI",
"set pin direction", "set initial state", or asks to repurpose a
CVM ball (e.g. flip a pin between GPIO and a peripheral function).
- A sibling skill (
jetson-customize-camera, jetson-customize-pcie,
jetson-customize-usb, jetson-customize-mgbe) reports an HSIO pin mismatch
via pin_verifier.py and the user wants to fix it.
- The user pre-derived a custom carrier with
/jetson-derive-carrier
and now wants to author the pinmux from a freshly-edited .xlsm.
Prerequisites:
- Active profile selected (
target-platform/active_target.yml →
<profile>.yaml with reference_devkit: AND custom_carrier:).
<source.root_path>/Linux_for_Tegra/ exists as a git repo
(/jetson-init-source).
/jetson-derive-carrier has run — the three pinmux-side BCT DTSIs
(PINMUX_CONFIG, GPIOINT_CONFIG, PMC_CONFIG references in the
carrier conf) exist in the overlay tracker.
- A pinmux
.xlsm is registered in the active profile at
documents.custom_carrier_pinmux_xls (preferred when custom-carrier-
specific) or documents.ref_devkit_pinmux_xls (fallback). The
bundled modify_pinmux.py requires openpyxl>=3.1.
Procedure
See references/procedure.md for the full
step-by-step procedure (Steps 1–8). Summary:
- Resolve active target + XLSM. Validate active profile,
custom_carrier:, overlay-tracker prerequisites; resolve the
pinmux .xlsm path from
documents.custom_carrier_pinmux_xls →
documents.ref_devkit_pinmux_xls → single XLSM under
documents.root_path → user prompt.
- Probe. Run
modify_pinmux.py probe to parse the XLSM into the
per-skill scratch <KB>/pinmap/<custom-carrier>.json plus
session.json shim.
- Lookup. Resolve a free-form user query (CVM ball, Verilog
name, signal, DT pin) via
modify_pinmux.py lookup; surface
supported SFIO list, defaults, and configurable: yes/no.
- Set-pin (HARD GATE — Q1–Q6 via
AskUserQuestion). Q1–Q3
(sfio / direction / initial_state) always asked; Q4–Q6
(pull / drive_type / open_drain) only when
configurable: yes. tristate and e_input are derived from
direction, never asked.
- Generate.
modify_pinmux.py generate --out-dir <source.root_path>/Linux_for_Tegra/bootloader/ (root, not
bootloader/generic/BCT/ — derive-carrier .dts forks live there,
do not colocate). Emits:
tegra<soc>-mb1-bct-{pinmux,gpio,padvoltage}-<carrier-key>.dtsi.
<carrier-key> comes from the carrier conf's PINMUX_CONFIG=
reference, NOT the kebab-cased carrier name.
- Commit (single batched commit per workflow rule). All three
DTSIs are one logical edit → one customization commit. Run the
commit-preview gate before each commit.
- Run-state sidecar + session shim. Write the user-facing
<profile-stem>.jetson-customize-pinmux.json sidecar and the
transient session.json shim under
<workspace>/target-platform/.
- Summary. Emit the standard one-line + table summary.
Gotchas
- No kernel-DT overlay; no
OVERLAY_DTB_FILE edit; no
render_conf.py hand-off. This skill ends at the three BCT
DTSIs — the carrier conf already references them via
PINMUX_CONFIG= / GPIOINT_CONFIG= / PMC_CONFIG= (set up by
/jetson-derive-carrier).
- Re-point the
.dts wrapper's #include after generate.
/jetson-derive-carrier forks the .dts wrappers at
bootloader/generic/BCT/, but their #include lines may still
pull the upstream devkit .dtsi (e.g.
…-p3834-xxxx-p4071-0000.dtsi). After generate writes the new
<CARRIER_KEY>.dtsi to bootloader/ root, edit each wrapper's
#include to the new filename — by bare basename
(#include "tegra<soc>-mb1-bct-pinmux-<CARRIER_KEY>.dtsi"), not
../../… filesystem-relative. The BCT build's cpp -I bootloader/
resolves bare basenames; that's the convention every other BCT
include in the tree follows. Roll the wrapper edits into the same
customization commit as the three DTSIs. See references/procedure.md
Step 5 ("Sanity-check the carrier .dts wrapper").
- Q4–Q6 gated on
configurable: yes. Asking pull / drive_type /
open_drain on a fixed-function pad (LP5XA_*, UPHYDS_*,
BDMIPI16X_*, etc.) is silently dropped by the script and confuses
the user. lookup prints configurable: yes/no — always check it
before prompting Q4–Q6.
tristate and e_input are derived, never asked. unused →
tristate=ENABLE; input / bidirectional → enable-input=ENABLE.
Exposing them as separate prompts produces inconsistent DTSIs.
sfio=gpio requires a parseable gpio=GPIOn_PD.NN entry in the
pinmap row's sfio list. Pins without one are GPIO-incapable
silicon; set-pin rejects the call. Surface the rejection — don't
silently fall back to a non-GPIO SFIO.
- Marker idempotency. Every per-pin edit carries
// custom-bsp: pinmux on the closing brace; gpio default-state
entries carry the same marker as a trailing comment. Re-running
generate must detect and update — never duplicate.
modify_pinmux.py is unchanged from the original framework —
it reads its own session.json shim under --kb-dir. The shim
is regenerated each run from the active profile + the user-facing
sidecar. Do not hand-edit the shim; it's transient.
- Multiple pinmux DTSI variants per Thor module SKU. Some carrier
pins live in a different DTSI variant than the one the carrier
conf references.
modify_pinmux.py commit (legacy patch-in-place
flow) tolerates missing per-pin blocks via
pinmux.warnings[] rather than failing. Surface the warning;
point at the alternate DTSI variant.
- Don't touch the upstream BSP at
<bsp_image.root_path>. All
edits land in <source.root_path>/Linux_for_Tegra/bootloader/ under
the pristine + customization commit pattern.
Available Scripts
| Script |
Purpose |
Arguments |
scripts/modify_pinmux.py |
XLSM parser + per-pin DTSI generator. Invoked via run_script() from Steps 3-6 with the subcommand of the current phase. |
probe | lookup | set-pin | apply | generate | commit [...] (see --help) |
scripts/generate_dtsi.py |
Renders pinmux/GPIO/padvoltage DTSI fragments from the bundled session state. Called by modify_pinmux.py generate. |
--session <path> --out-dir <dir> |
Invoke from the skill body as a subprocess via run_script():
# run_script: probe the carrier pinmux XLSM and write a session state
scripts/modify_pinmux.py probe --xlsm carrier.xlsm --session .pinmux-session.json
# run_script: render DTSI fragments from the final session state
scripts/modify_pinmux.py generate --session .pinmux-session.json --out-dir bsp_sources/pinmux/
References
1---2name: jetson-customize-pinmux3description: Per-pin SFIO / direction / initial-state configurator for a Jetson Orin or Thor custom carrier from the pinmux XLSM. Do NOT use for kernel-DT overlay or ODMDATA edits.4license: Apache-2.05---67# Customize pinmux (per-pin SFIO / direction / state)89## Overview1011The Tegra pinmux spreadsheet (`.xlsm`) is the ground truth for every12CVM ball: SoC pin name, supported SFIOs, customer-selected function,13direction, and initial state. This skill parses that XLSM, runs a14per-pin Q1–Q6 interactive loop, and emits the three BCT DTSIs15(`pinmux`, `gpio`, `padvoltage`) in one shot into the overlay tracker16at `<source.root_path>/Linux_for_Tegra/bootloader/`.1718Unlike sibling skills `jetson-customize-uphy` / `jetson-customize-pcie` /19`jetson-customize-camera`, **pinmux has no kernel-DT overlay surface and no20ODMDATA edit**. The XLSM is the source of truth; the three emitted21DTSIs land at flash time via the carrier conf's22`PINMUX_CONFIG=` / `GPIOINT_CONFIG=` / `PMC_CONFIG=` references (which23`/jetson-derive-carrier` set up).2425**Pad classification (silicon-fixed):** only `BD*` and `BI*` pads have26configurable pull / drive / open-drain attributes. `LP5XA_*`,27`UPHYDS_*`, `DP_SINGLE_*`, `BDMIPI16X_*`, `BDUSB2_*`, `OSCI27_*` are28fixed-function and **skip Q4–Q6** (`configurable: no`).2930The bundled `scripts/modify_pinmux.py` is the workhorse: it parses31the XLSM via `openpyxl>=3.1`, builds the per-carrier pinmap JSON,32captures pin edits into a session shim, and (on `generate`) writes33the three DTSIs.3435## When to invoke3637- The user says "configure pin", "set SFIO", "edit pinmux DTSI",38 "set pin direction", "set initial state", or asks to repurpose a39 CVM ball (e.g. flip a pin between GPIO and a peripheral function).40- A sibling skill (`jetson-customize-camera`, `jetson-customize-pcie`,41 `jetson-customize-usb`, `jetson-customize-mgbe`) reports an HSIO pin mismatch42 via `pin_verifier.py` and the user wants to fix it.43- The user pre-derived a custom carrier with `/jetson-derive-carrier`44 and now wants to author the pinmux from a freshly-edited `.xlsm`.4546**Prerequisites:**4748- Active profile selected (`target-platform/active_target.yml` →49 `<profile>.yaml` with `reference_devkit:` AND `custom_carrier:`).50- `<source.root_path>/Linux_for_Tegra/` exists as a git repo51 (`/jetson-init-source`).52- `/jetson-derive-carrier` has run — the three pinmux-side BCT DTSIs53 (`PINMUX_CONFIG`, `GPIOINT_CONFIG`, `PMC_CONFIG` references in the54 carrier conf) exist in the overlay tracker.55- A pinmux `.xlsm` is registered in the active profile at56 `documents.custom_carrier_pinmux_xls` (preferred when custom-carrier-57 specific) or `documents.ref_devkit_pinmux_xls` (fallback). The58 bundled `modify_pinmux.py` requires `openpyxl>=3.1`.5960## Procedure6162See [`references/procedure.md`](references/procedure.md) for the full63step-by-step procedure (Steps 1–8). Summary:64651. **Resolve active target + XLSM.** Validate active profile,66 `custom_carrier:`, overlay-tracker prerequisites; resolve the67 pinmux `.xlsm` path from68 `documents.custom_carrier_pinmux_xls` →69 `documents.ref_devkit_pinmux_xls` → single XLSM under70 `documents.root_path` → user prompt.712. **Probe.** Run `modify_pinmux.py probe` to parse the XLSM into the72 per-skill scratch `<KB>/pinmap/<custom-carrier>.json` plus73 `session.json` shim.743. **Lookup.** Resolve a free-form user query (CVM ball, Verilog75 name, signal, DT pin) via `modify_pinmux.py lookup`; surface76 supported SFIO list, defaults, and `configurable: yes/no`.774. **Set-pin (HARD GATE — Q1–Q6 via `AskUserQuestion`).** Q1–Q378 (`sfio` / `direction` / `initial_state`) always asked; Q4–Q679 (`pull` / `drive_type` / `open_drain`) only when80 `configurable: yes`. `tristate` and `e_input` are derived from81 `direction`, never asked.825. **Generate.** `modify_pinmux.py generate --out-dir83 <source.root_path>/Linux_for_Tegra/bootloader/` (root, **not**84 `bootloader/generic/BCT/` — derive-carrier `.dts` forks live there,85 do not colocate). Emits:86 `tegra<soc>-mb1-bct-{pinmux,gpio,padvoltage}-<carrier-key>.dtsi`.87 **`<carrier-key>` comes from the carrier conf's `PINMUX_CONFIG=`88 reference, NOT the kebab-cased carrier name.**896. **Commit (single batched commit per workflow rule).** All three90 DTSIs are one logical edit → one customization commit. Run the91 commit-preview gate before each commit.927. **Run-state sidecar + session shim.** Write the user-facing93 `<profile-stem>.jetson-customize-pinmux.json` sidecar and the94 transient `session.json` shim under95 `<workspace>/target-platform/`.968. **Summary.** Emit the standard one-line + table summary.9798## Gotchas99100- **No kernel-DT overlay; no `OVERLAY_DTB_FILE` edit; no101 `render_conf.py` hand-off.** This skill ends at the three BCT102 DTSIs — the carrier conf already references them via103 `PINMUX_CONFIG=` / `GPIOINT_CONFIG=` / `PMC_CONFIG=` (set up by104 `/jetson-derive-carrier`).105- **Re-point the `.dts` wrapper's `#include` after `generate`.**106 `/jetson-derive-carrier` forks the `.dts` wrappers at107 `bootloader/generic/BCT/`, but their `#include` lines may still108 pull the upstream devkit `.dtsi` (e.g.109 `…-p3834-xxxx-p4071-0000.dtsi`). After `generate` writes the new110 `<CARRIER_KEY>.dtsi` to `bootloader/` root, edit each wrapper's111 `#include` to the new filename — by **bare basename**112 (`#include "tegra<soc>-mb1-bct-pinmux-<CARRIER_KEY>.dtsi"`), not113 `../../…` filesystem-relative. The BCT build's `cpp -I bootloader/`114 resolves bare basenames; that's the convention every other BCT115 include in the tree follows. Roll the wrapper edits into the same116 customization commit as the three DTSIs. See `references/procedure.md`117 Step 5 ("Sanity-check the carrier `.dts` wrapper").118- **Q4–Q6 gated on `configurable: yes`.** Asking pull / drive_type /119 open_drain on a fixed-function pad (`LP5XA_*`, `UPHYDS_*`,120 `BDMIPI16X_*`, etc.) is silently dropped by the script and confuses121 the user. `lookup` prints `configurable: yes/no` — always check it122 before prompting Q4–Q6.123- **`tristate` and `e_input` are derived, never asked.** `unused` →124 tristate=ENABLE; `input` / `bidirectional` → enable-input=ENABLE.125 Exposing them as separate prompts produces inconsistent DTSIs.126- **`sfio=gpio` requires a parseable `gpio=GPIOn_PD.NN` entry in the127 pinmap row's `sfio` list.** Pins without one are GPIO-incapable128 silicon; `set-pin` rejects the call. Surface the rejection — don't129 silently fall back to a non-GPIO SFIO.130- **Marker idempotency.** Every per-pin edit carries131 `// custom-bsp: pinmux` on the closing brace; gpio default-state132 entries carry the same marker as a trailing comment. Re-running133 `generate` must detect and update — never duplicate.134- **`modify_pinmux.py` is unchanged from the original framework** —135 it reads its own `session.json` shim under `--kb-dir`. The shim136 is regenerated each run from the active profile + the user-facing137 sidecar. Do not hand-edit the shim; it's transient.138- **Multiple pinmux DTSI variants per Thor module SKU.** Some carrier139 pins live in a different DTSI variant than the one the carrier140 conf references. `modify_pinmux.py commit` (legacy patch-in-place141 flow) tolerates missing per-pin blocks via142 `pinmux.warnings[]` rather than failing. Surface the warning;143 point at the alternate DTSI variant.144- **Don't touch the upstream BSP at `<bsp_image.root_path>`.** All145 edits land in `<source.root_path>/Linux_for_Tegra/bootloader/` under146 the pristine + customization commit pattern.147148## Available Scripts149150| Script | Purpose | Arguments |151|---|---|---|152| `scripts/modify_pinmux.py` | XLSM parser + per-pin DTSI generator. Invoked via `run_script()` from Steps 3-6 with the subcommand of the current phase. | `probe \| lookup \| set-pin \| apply \| generate \| commit [...]` (see `--help`) |153| `scripts/generate_dtsi.py` | Renders pinmux/GPIO/padvoltage DTSI fragments from the bundled session state. Called by `modify_pinmux.py generate`. | `--session <path> --out-dir <dir>` |154155Invoke from the skill body as a subprocess via `run_script()`:156157```bash158# run_script: probe the carrier pinmux XLSM and write a session state159scripts/modify_pinmux.py probe --xlsm carrier.xlsm --session .pinmux-session.json160161# run_script: render DTSI fragments from the final session state162scripts/modify_pinmux.py generate --session .pinmux-session.json --out-dir bsp_sources/pinmux/163```164165## References166- [`references/procedure.md`](references/procedure.md) — full Step 1–8167 procedure prose.168- [`questions.json`](questions.json) — Q1–Q6 prompt schema consumed169 by Step 4.170- [`../../references/platform_template.yaml`](../../references/platform_template.yaml) — `documents:` block (`ref_devkit_pinmux_xls`, `custom_carrier_pinmux_xls`).171- [`../../context/bsp-customization-workflow.md`](../../context/bsp-customization-workflow.md#workflow-invariants) — overlay edit protocol (single-commit per DTSI fork).172- [`../jetson-derive-carrier/SKILL.md`](../jetson-derive-carrier/SKILL.md) — must run first; produces the pinmux / gpio / padvoltage DTSI forks this skill edits, and rewrites the carrier conf's `PINMUX_CONFIG=` / `GPIOINT_CONFIG=` / `PMC_CONFIG=` lines to point at them.173- [`../jetson-init-source/SKILL.md`](../jetson-init-source/SKILL.md) — produces the overlay tracker this skill commits into.174- [`../jetson-link-docs/SKILL.md`](../jetson-link-docs/SKILL.md) — author the profile's `documents:` block, including the pinmux XLSM bindings.