---
在 Jetson AGX Thor / T5000 定制载板 bring-up 时,pinmux 是一个很容易被低估的问题。

很多时候我们看到 DTS 里有这样的配置:
can0_din_pab1 {
nvidia,pins = "can0_din_pab1";
nvidia,function = "can0_din";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,drv-type = <TEGRA_PIN_DEFAULT_DRIVE_1X>;
nvidia,e-lpbk = <TEGRA_PIN_DISABLE>;
};
刚开始很容易把它理解成:
function = can0_din
所以这个 pin 就是 CAN RX 了
但这个理解是不完整的。
Jetson Thor 的 pinmux 不只是“选择功能”,它实际在配置 SoC PAD 的早期电气状态:
这个 pin 接到哪个内部外设?
这个 pin 是否允许 SoC 输出?
输入 buffer 是否打开?
内部上下拉怎么配置?
输出驱动能力是多少?
上电早期是否安全?
也就是说,pinmux 是 bring-up 的第一层,它解决的是:
Kernel 起来之前,这个 pin 应该是什么状态?
而 kernel 解决的是:
系统运行之后,这个外设是否真正工作?
这篇文章就围绕这个核心问题展开:Jetson Thor pinmux 到底配置了什么?它和 MB1、MB2、UEFI、kernel DTS 是什么关系?
1. 先看整体启动流程
Jetson Thor 的启动流程可以简化成下面这样:
Power On / POR
│
▼
BootROM
│
▼
MB1
│
├── 应用早期 BCT 配置
├── 应用 pinmux / gpio / padvoltage
│
▼
MB2
│
├── 继续初始化平台资源
│
▼
UEFI
│
├── 加载启动配置
├── 加载 kernel / dtb / initrd
│
▼
Linux Kernel
│
├── 解析 kernel DTB
├── probe 外设 driver
├── 配置 regulator / GPIO / PHY / interrupt / pinctrl
│
▼
User Space
用 Mermaid 表示更直观:
flowchart TD
A[Power On / POR] --> B[BootROM]
B --> C[MB1]
C --> C1[Apply BCT]
C --> C2[Apply pinmux.dtsi / gpio.dtsi / padvoltage.dtsi]
C --> D[MB2]
D --> E[UEFI]
E --> F[Load Kernel + DTB + Initrd]
F --> G[Linux Kernel]
G --> H[Driver Probe]
H --> I[Runtime GPIO / PHY / Regulator / Display / USB]
I --> J[User Space]
关键点是:
pinmux 主要在 MB1/bootloader 早期阶段生效;
kernel 后面可以重新配置部分 pin,但不会自动覆盖所有 pin。
所以不能简单认为:
kernel 起来后都会重新配置,pinmux 随便配也没事
这个理解是错误的。
2. Thor Pinmux Template 生成了什么?
Thor 使用的是:
Jetson Thor Series Modules Pinmux Template
这是一个 .xlsm 表格。根据定制载板原理图修改后,点击:
Generate DT File
通常会生成:
pinmux.dtsi
gpio.dtsi
padvoltage.dtsi
三个文件的职责可以这样理解:
| 文件 | 作用 | 主要生效阶段 |
|---|---|---|
pinmux.dtsi | 配置 function、pull、tristate、input、drive 等 PAD 属性 | MB1 / bootloader |
gpio.dtsi | 配置 GPIO 初始方向、初始电平等 | MB1 / bootloader |
padvoltage.dtsi | 配置 I/O 电压域 | MB1 / bootloader |
也就是说,这些文件不是普通 kernel driver 的配置文件,而是 平台早期初始化文件。

典型集成路径类似:
Thor Pinmux XLSM
│
├── Generate DT File
│
▼
pinmux.dtsi
gpio.dtsi
padvoltage.dtsi
│
▼
复制到 Linux_for_Tegra/bootloader/
│
▼
flash / 生成镜像
│
▼
MB1/bootloader 早期应用
流程图如下:
flowchart LR
A[Thor Pinmux XLSM] --> B[Generate DT File]
B --> C[pinmux.dtsi]
B --> D[gpio.dtsi]
B --> E[padvoltage.dtsi]
C --> F[bootloader directory]
D --> F
E --> F
F --> G[Flash Image]
G --> H[MB1 Apply Early Pad Config]
3. Pinmux 和 Kernel DTS 不是一回事
这是 bring-up 中最关键的分界。
Pinmux 管什么?
Pinmux 管的是 PAD 级别:
nvidia,function
nvidia,pull
nvidia,tristate
nvidia,enable-input
nvidia,drv-type
nvidia,e-lpbk
也就是:
这个 pin 在电气层面怎么工作
Kernel DTS 管什么?
Kernel DTS 管的是设备和驱动:
controller 是否 enable
clock/reset/interrupt 是否正确
regulator 是否正确
GPIO consumer 是否正确
PHY/lane/role-switch 是否正确
display DCB 是否正确
driver 是否能 probe
也就是:
这个外设在 Linux 运行后怎么工作
两者关系如下:
硬件原理图
│
├── Pinmux XLSM
│ └── 生成 pinmux/gpio/padvoltage
│ └── 作用于 MB1/bootloader
│
└── Kernel DTS
└── 打开外设 controller
└── 配置 GPIO / regulator / PHY / interrupt
└── 作用于 Linux driver probe
可以总结成一句话:
Pinmux 决定 pin 早期是否安全、是否接到正确功能;
Kernel DTS 决定外设运行时是否真正可用。
4. 用 CAN0_DIN 举例:Pinmux 到底配置了什么?
假设硬件连接是:
CAN Transceiver RXD ---> SoC CAN0_DIN
CAN Transceiver TXD <--- SoC CAN0_DOUT
电路方向是:
CAN0_DIN = SoC 输入,接收 transceiver 的 RXD
CAN0_DOUT = SoC 输出,驱动 transceiver 的 TXD
4.1 错误配置
如果生成出来是:
can0_din_pab1 {
nvidia,pins = "can0_din_pab1";
nvidia,function = "rsvd1";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
};
这里有两个问题。
第一个问题:
nvidia,function = "rsvd1";
rsvd1 是 reserved function,表示没有选择 CAN0_DIN 这个有效外设功能。
所以逻辑上变成:
外部 CAN RXD 进到 pin
│
X
│
没有送到 CAN0_DIN 控制器输入
第二个问题:
nvidia,tristate = <TEGRA_PIN_DISABLE>;
这不是关闭 pin,而是关闭高阻,允许输出驱动。
对于 CAN RX 输入脚来说,这个方向不合理。
4.2 正确配置
CAN RX 应该类似这样:
can0_din_pab1 {
nvidia,pins = "can0_din_pab1";
nvidia,function = "can0_din";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,drv-type = <TEGRA_PIN_DEFAULT_DRIVE_1X>;
nvidia,e-lpbk = <TEGRA_PIN_DISABLE>;
};
逐项解释:
| 参数 | 含义 |
|---|---|
function = "can0_din" | 这个 pin 接到 CAN0 RX |
pull = PULL_NONE | 不使用内部上下拉,由外部 transceiver 驱动 |
tristate = ENABLE | 输出高阻,SoC 不主动驱动这个 pin |
enable-input = ENABLE | 输入 buffer 打开,SoC 可以读取 RX 信号 |
drv-type = 1X | 默认驱动能力;对输入脚影响不大 |
e-lpbk = DISABLE | 不开 loopback |
这里最关键的是三句:
nvidia,function = "can0_din";
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
可以理解成:
接到 CAN RX
不输出
只读取
5. tristate 最容易理解反
tristate 的 ENABLE/DISABLE 不是在说 pin 是否启用,而是在说 是否启用三态高阻。
tristate = ENABLE
nvidia,tristate = <TEGRA_PIN_ENABLE>;
意思是:
启用高阻
输出驱动断开
SoC 不主动拉高,也不主动拉低
等效电路:
SoC output driver X PIN
适合:
输入脚
unused pin
外部已有驱动源的信号
tristate = DISABLE
nvidia,tristate = <TEGRA_PIN_DISABLE>;
意思是:
关闭高阻
输出驱动打开
SoC 可以主动输出 0 或 1
适合:
输出脚
enable 脚
reset 脚
TX 信号
表格记忆:
| 配置 | 实际含义 | 典型用途 |
|---|---|---|
tristate = ENABLE | 高阻,不输出 | RX、输入、unused |
tristate = DISABLE | 可以输出 | TX、EN、RST |
6. Kernel 侧还要怎么配 CAN?
Pinmux 配对了,只表示:
物理 pin 已经接到 CAN 控制器
但 CAN 控制器能不能工作,还要看 kernel DTS 和 driver。
Kernel 侧通常还要确认:
CAN controller 节点是否 enabled
时钟是否正确
reset 是否正确
interrupt 是否正确
transceiver standby/enable GPIO 是否正确
CAN bitrate 是否配置
示意 DTS:
/* 注意:节点名以实际 BSP 为准,这里只是表达关系 */
&mttcan0 {
status = "okay";
/*
* 如果板上 CAN transceiver 有 standby / enable / reset GPIO,
* 需要在对应 transceiver 节点或驱动属性中描述。
*/
};
如果 CAN transceiver 还有 STB/EN 控制脚,pinmux 也要配置它们的早期状态。例如:
CAN_STB:
方向:Output
初始状态:Drive 1 或 Drive 0,取决于 transceiver datasheet
kernel:后续由 GPIO driver 控制
CAN_EN:
方向:Output
初始状态:Drive 1 或 Drive 0,取决于硬件设计
kernel:后续由 GPIO/regulator/transceiver driver 控制
所以 CAN bring-up 的完整链路是:
flowchart TD
A[原理图确认 CAN RX/TX/STB/EN] --> B[Pinmux 配 CAN0_DIN/CAN0_DOUT]
B --> C[MB1 早期应用 pinmux]
C --> D[Kernel DTS enable mttcan0]
D --> E[Kernel driver probe]
E --> F[ip link set can0 up type can bitrate xxx]
F --> G[candump / cansend 验证]
7. rsvd0/rsvd1/rsvd2/rsvd3 是什么?
在 pinmux 中常看到:
nvidia,function = "rsvd0";
或者:
nvidia,function = "rsvd1";
RSVD 是 Reserved,表示保留功能。
它不是:
delete 这个 pin
pin 完全消失
pin 完全断电
更准确地说:
这个 PAD 的 mux 没有选择一个明确的外设功能
比如:
没有选 CAN
没有选 UART
没有选 SPI
没有选 I2C
没有选 PWM
但是 pin 的电气状态仍然存在:
pull 仍然可能生效
tristate 仍然可能生效
enable-input 仍然可能生效
GPIO controller 仍然可能管理它
所以 rsvdX 不能简单理解成“安全”或“低功耗”。真正是否安全,还要看:
tristate 是否高阻
input buffer 是否关闭
pull 是否合理
外部是否有上拉/下拉
是否连接到其他芯片输出
是否涉及 boot strap / reset / recovery
对于 unused pin,比较合理的方向是:
/* 示例,具体 pull 要看硬件 */
unused_xxx {
nvidia,function = "rsvd0";
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_DISABLE>;
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
};
但如果这个 pin 实际要做 CAN/UART/I2C/SPI,就不能保持 rsvdX。
8. USB:为什么不是只改 pinmux?
USB 要分成两层:
高速信号
sideband 控制信号
8.1 高速信号
例如:
USB2 D+
USB2 D-
USB3 TX/RX
这些主要由:
xUSB controller
USB PHY
UPHY lane
kernel USB driver
管理,不是普通 GPIO pinmux 直接拉高拉低。
8.2 Sideband 信号
例如:
VBUS_EN
VBUS_DET
USB_ID
OC
Type-C CC controller interrupt
这些就和 pinmux/GPIO/kernel DTS 强相关。
完整链路:
USB connector
│
├── USB2/USB3 高速线
│ └── xUSB/PHY/lane/kernel driver
│
└── VBUS_EN / VBUS_DET / ID / OC
└── pinmux + GPIO + regulator + role-switch
示意 DTS:
/* 示例,节点名以实际 BSP 为准 */
usb_vbus_reg: regulator-usb-vbus {
compatible = "regulator-fixed";
regulator-name = "usb-vbus";
gpio = <&gpio XXX GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&usb_controller_xxx {
status = "okay";
vbus-supply = <&usb_vbus_reg>;
usb-role-switch;
};
Pinmux 负责让 VBUS_EN 这个 GPIO 在早期不乱输出;kernel 负责把它作为 regulator 或 GPIO consumer 使用。
USB bring-up 的判断逻辑:
flowchart TD
A[USB 不工作] --> B{高速枚举失败还是 VBUS/role 问题?}
B -->|无 VBUS| C[查 VBUS_EN pinmux + regulator DTS]
B -->|role 不对| D[查 VBUS_DET / ID / Type-C controller]
B -->|信号异常| E[查 PHY / UPHY / lane / controller]
C --> F[示波器量 VBUS]
D --> G[dmesg 看 role-switch/typec]
E --> H[查 kernel xUSB/PHY log]
9. DP/HDMI:为什么还要 DCB?
DP/HDMI 更容易混淆,因为它不只是 pinmux。
对于 DP/HDMI,有三层配置:
1. Pinmux
2. Kernel display dtsi
3. DCB
9.1 Pinmux 负责什么?
DP:
HPD 配成对应 DP/HPD 功能
DPAUX 配成 DP_AUX_CHx
HDMI:
HPD 通常作为 GPIO/input
DDC/I2C 配成 I2C
CEC 视需求配置
9.2 Kernel display dtsi 负责什么?
Kernel display dtsi 负责把当前平台显示控制相关配置纳入 kernel DT。
9.3 DCB 负责什么?
DCB 可以理解成显示拓扑表,告诉显示驱动:
这个接口是 DP 还是 HDMI?
使用哪个 connector?
使用哪个 DPAUX/DDC 通信通道?
HDMI capable 是 0 还是 1?
其中 CCB 是 DCB 里的通信通道配置,和 DPAUX/DDC 对应。
DP 的逻辑图:
DP Connector
│
├── Main Lanes
│ └── Display Controller / PHY
│
├── HPD
│ └── Pinmux 配成 DP HPD/SFIO
│
└── AUX
└── Pinmux 配成 DP_AUX_CHx
│
▼
DCB
├── Type = DP
├── HDMI capable = 0
├── CCB = 对应 DPAUXx
└── Connector = 对应 connector index
HDMI 的逻辑图:
HDMI Connector
│
├── TMDS
│ └── Display Controller / PHY
│
├── HPD
│ └── GPIO/Input/Interrupt
│
└── DDC/I2C
└── I2C/DDC 通道
│
▼
DCB
├── Type = TMDS
├── HDMI capable = 1
├── CCB = 对应 DDC/I2C
└── Connector = 对应 HDMI connector index
所以 DP/HDMI bring-up 不能只看 pinmux:
pinmux 对了,但 DCB 错了:
driver 可能去错误的 AUX/DDC 通道读 EDID
DCB 对了,但 pinmux 错了:
AUX/DDC/HPD 信号可能根本不通
kernel display dtsi 没 include:
display driver 可能拿不到平台显示拓扑
完整流程:
flowchart TD
A[原理图确认 DP/HDMI connector] --> B[确认 HPD / AUX / DDC 接到哪里]
B --> C[Pinmux 配 HPD / AUX / DDC]
C --> D[Kernel DT include display dtsi]
D --> E[DCB 配 Type / CCB / Connector / HDMI capable]
E --> F[Kernel display driver probe]
F --> G[HPD / EDID / AUX-DDC 验证]
10. Pinmux 和 Kernel 的冲突场景
最麻烦的问题通常不是“没配置”,而是 bootloader 和 kernel 配置不一致。
场景 1:Bootloader 配成 CAN,Kernel 又当 GPIO
MB1 pinmux:
function = can0_din
Kernel:
把同一个 pin 当 GPIO 使用
结果:
早期像 CAN
kernel probe 后变 GPIO
CAN 后面不工作
场景 2:Bootloader 早期输出高,Kernel 后面才改输入
MB1:
Drive 1
Kernel:
input
结果:
kernel 启动前这段时间,外部芯片已经被错误拉高
这对 reset、enable、power switch 很危险。
场景 3:Pinmux 是 rsvd,Kernel enable 了外设
pinmux:
function = rsvd1
kernel:
mttcan0 status = "okay"
结果:
CAN controller 启动了
但物理 pin 没接到 CAN 功能
外设仍然不工作
11. 实际 bring-up 检查表
11.1 先从原理图开始
不要先看 DTS,先看原理图。
整理一张表:
| SoM Pin | Net Name | 外部连接 | 方向 | 早期默认态 | Kernel 是否控制 |
|---|---|---|---|---|---|
| CAN0_DIN | CAN_RXD | CAN transceiver RXD | Input | Z | mttcan |
| CAN0_DOUT | CAN_TXD | CAN transceiver TXD | Output | 按设计 | mttcan |
| CAN_STB | CAN_STB | transceiver standby | Output | Drive 1/0 | GPIO |
| USB_VBUS_EN | USB_PWR_EN | power switch EN | Output | Drive 0/Z | regulator |
| HDMI_HPD | HDMI_HPD | HDMI connector | Input | Z/PU | GPIO IRQ |
| DP_AUX | DP_AUX_CHx | DP connector | Bidirectional | 按 DP | display driver |
11.2 再检查 Pinmux XLSM
重点看:
Customer Usage
Pin Direction
Required Initial State
Pull
3.3V tolerance
Open-drain
I/O block voltage
11.3 再检查生成的 pinmux.dtsi
例如检查 CAN RX:
grep -n "can0_din" -n pinmux.dtsi
期望看到类似:
nvidia,function = "can0_din";
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
检查是否还有错误的 reserved:
grep -n "rsvd" pinmux.dtsi
看到 rsvd0/rsvd1 不一定就是错,但要确认这些 pin 是否真的是 unused/GPIO,而不是外设 pin。
11.4 最后检查 kernel DTS
例如:
grep -R "mttcan" kernel-dts/
grep -R "vbus" kernel-dts/
grep -R "dcb" kernel-dts/
grep -R "dpaux" kernel-dts/
目标是确认:
外设 controller enabled
相关 GPIO 被 driver 使用
display DCB include 正确
USB regulator/role-switch 正确
DP/HDMI CCB/connector 对应硬件
12. 最终总结
Jetson Thor bring-up 中,pinmux 和 kernel 的关系可以总结为:
Pinmux:
解决早期 PAD 状态问题
作用在 MB1/bootloader 阶段
重点是 function、pull、tristate、input、drive、pad voltage
Kernel DTS:
解决运行时外设描述问题
作用在 Linux driver probe 阶段
重点是 controller、GPIO、regulator、PHY、interrupt、DCB
Driver:
解决外设实际运行问题
作用在系统运行阶段
负责 probe、初始化、suspend/resume、runtime 控制
最重要的一句话:
Pinmux 配错,kernel 可能根本救不了;
Kernel 配错,pinmux 再正确,外设也不会真正工作。
所以 Thor bring-up 的正确顺序应该是:
原理图确认
↓
Pinmux XLSM 配早期状态
↓
Generate DT File
↓
集成到 bootloader
↓
Kernel DTS 配外设运行时资源
↓
Flash
↓
上板验证 pin 电平 + driver probe + 接口功能
这才是比较稳妥的 Jetson Thor pinmux bring-up 方法。
685

被折叠的 条评论
为什么被折叠?



