如何设计一个 Linux + ARM 硬件 Skill?
先把目录结构理清楚
做 Linux + ARM 硬件 Skill,最麻烦的往往不是资料少,而是资料太多。
芯片手册、原理图、设备树、驱动代码、调试记录、脚本,全部堆在一起。刚开始还能凑合用,时间一长,连自己都不清楚某份资料放在哪,更别说让 Agent 快速找到。
所以,这类 Skill 不要急着往里塞文档。先把目录搭好。
一个基础版本,四部分就够了:
linux-arm-hardware-skill/
├── SKILL.md
├── references/
├── checklists/
└── scripts/
| |
|---|
SKILL.md | |
references/ | |
checklists/ | |
scripts/ | |
一、SKILL.md:只写稳定规则
SKILL.md 是整个 Skill 的入口。
这个文件不适合放大量手册内容,也不适合记录某块板子的所有细节。它更适合写:
可以先写成这样:
---
name: linux-arm-hardware-debug
description: 用于分析 Linux + ARM 平台中的设备树、驱动、时钟、复位、电源和板级硬件问题。
---
# Linux + ARM Hardware Debug
## 适用场景
- 网口无法识别
- I2C 设备找不到
- SPI 通信异常
- USB 不枚举
- GPIO 不工作
- 驱动 probe 失败
- 设备树配置异常
## 基本原则
1. 先确认 SoC、板卡和 Linux 内核版本。
2. 不要默认问题一定出在软件。
3. 不要混用不同芯片的设备树属性。
4. 不要编造寄存器、引脚和手册章节。
5. 区分已确认信息、推测和待验证项。
6. 修改建议必须带验证方法。
## 排查顺序
用户空间
↓
Linux 子系统
↓
驱动
↓
设备树
↓
时钟、复位和电源
↓
原理图和外部器件
## 输出内容
1. 当前现象
2. 已确认信息
3. 缺失信息
4. 可能原因
5. 排查顺序
6. 需要查看的资料
7. 修改建议
8. 验证方法
这个文件解决的是“遇到问题以后怎么查”,不是“所有知识都放在哪里”。
二、references/:按资料来源拆开
references/ 通常是文件最多的目录。
不建议按 PDF、代码、图片这种文件格式来分。更实用的方式,是按资料来源来分。
references/
├── soc/
├── arm/
├── schematic/
├── device-tree/
├── drivers/
├── peripherals/
├── errata/
└── known-issues/
1. soc/
存放 SoC 厂商提供的资料:
references/soc/
├── datasheet.pdf
├── reference-manual.pdf
└── clock-tree.md
常见内容包括:
2. arm/
存放 ARM 架构相关资料:
references/arm/
├── cortex-a-overview.pdf
├── gic-guide.md
├── mmu-cache.md
└── exception-model.md
主要用于查看:
ARM 文档主要讲处理器架构。UART、SPI、DMA 这些具体外设,仍然要看 SoC 厂商自己的手册。
3. schematic/
存放板级资料:
references/schematic/
├── board-rev-a.pdf
├── board-rev-b.pdf
├── pin-map.md
└── power-tree.md
这里可以放:
芯片手册告诉你芯片可以怎么用,原理图告诉你这块板子实际上是怎么接的。
4. device-tree/
存放设备树相关内容:
references/device-tree/
├── board.dts
├── soc.dtsi
├── overlays/
└── bindings-notes.md
可以包括:
5. drivers/
存放项目相关驱动:
references/drivers/
├── ethernet/
├── i2c/
├── spi/
├── usb/
└── gpio/
这里没有必要复制整个 Linux 内核。保留当前项目真正用到的内容即可,例如:
6. peripherals/
存放外部器件手册:
references/peripherals/
├── ethernet-phy/
├── pmic/
├── spi-flash/
├── sensor/
└── codec/
例如:
7. errata/
存放芯片和软件的已知问题:
references/errata/
├── soc-errata.pdf
├── phy-errata.pdf
└── kernel-known-bugs.md
有些问题不是代码写错,也不是原理图接错,而是芯片或驱动本身存在已知缺陷。这类资料最好单独放,排查时更容易找到。
8. known-issues/
存放项目里已经踩过的坑:
references/known-issues/
├── ethernet.md
├── usb.md
├── boot.md
└── board-rev-differences.md
例如:
# Ethernet Known Issues
- Rev A 板卡 PHY 地址为 1
- Rev B 板卡 PHY 地址为 3
- 某版本内核需要增加 PHY reset 延时
- RGMII 延迟由 PHY 提供
这类记录很有价值,因为它们针对的是当前项目,而不是通用场景。
三、checklists/:把排查顺序固定下来
checklists/ 主要放检查项。建议按硬件模块拆开:
checklists/
├── ethernet.md
├── i2c.md
├── spi.md
├── usb.md
├── gpio.md
├── clock-reset.md
└── driver-probe.md
例如 ethernet.md:
# Ethernet Debug Checklist
1. `ip link` 中是否存在网卡
2. MAC 驱动是否 probe 成功
3. 设备树节点是否启用
4. compatible 是否匹配
5. MDIO 是否注册
6. PHY 地址是否正确
7. PHY 电源是否正常
8. PHY reset 是否释放
9. 参考时钟是否存在
10. phy-mode 是否正确
11. RGMII 延迟是否匹配
12. Link 是否建立
13. 最后再检查 DHCP
再比如 i2c.md:
# I2C Debug Checklist
1. I2C 控制器是否启用
2. pinctrl 是否正确
3. 总线是否出现在 `i2cdetect -l`
4. 从设备地址是否正确
5. SDA、SCL 是否有上拉
6. 外设是否供电
7. reset 是否释放
8. 逻辑分析仪是否看到 ACK
检查清单的作用很直接:避免排查顺序混乱。系统里连 eth0 都没有,就没有必要先查 DHCP。
四、scripts/:把常用信息一次收齐
scripts/ 用来放信息收集脚本。
scripts/
├── collect_hw_info.sh
├── collect_eth_info.sh
├── collect_i2c_info.sh
├── collect_spi_info.sh
└── collect_usb_info.sh
通用脚本可以先收集系统基础信息:
#!/usr/bin/env bash
set -u
echo "=== System ==="
uname -a
echo
echo "=== CPU Info ==="
cat /proc/cpuinfo 2>/dev/null | head -n 50
echo
echo "=== Device Tree Model ==="
tr -d '\0' < /sys/firmware/devicetree/base/model 2>/dev/null || true
echo
echo "=== Interrupts ==="
cat /proc/interrupts 2>/dev/null | head -n 100
echo
echo "=== Relevant Logs ==="
dmesg | grep -Ei \
"error|fail|timeout|probe|clock|reset|regulator|phy|mdio|i2c|spi|usb|gpio" \
| tail -n 300
网口专项脚本可以写成:
#!/usr/bin/env bash
echo "=== Network Devices ==="
ip link
echo
echo "=== Ethernet Logs ==="
dmesg | grep -Ei "eth|gmac|phy|mdio"
echo
echo "=== Ethtool ==="
ethtool eth0 2>/dev/null || true
脚本不用做得特别复杂。它的主要作用,是一次收集常用信息,减少反复执行命令和粘贴日志。
五、完整目录示例
整理完成后,目录大致可以是这样:
linux-arm-hardware-skill/
├── SKILL.md
│
├── references/
│ ├── soc/
│ │ ├── datasheet.pdf
│ │ ├── reference-manual.pdf
│ │ └── clock-tree.md
│ │
│ ├── arm/
│ │ ├── gic-guide.md
│ │ ├── mmu-cache.md
│ │ └── exception-model.md
│ │
│ ├── schematic/
│ │ ├── board-rev-a.pdf
│ │ ├── board-rev-b.pdf
│ │ ├── pin-map.md
│ │ └── power-tree.md
│ │
│ ├── device-tree/
│ │ ├── board.dts
│ │ ├── soc.dtsi
│ │ └── bindings-notes.md
│ │
│ ├── drivers/
│ │ ├── ethernet/
│ │ ├── i2c/
│ │ ├── spi/
│ │ └── usb/
│ │
│ ├── peripherals/
│ │ ├── ethernet-phy/
│ │ ├── pmic/
│ │ └── sensor/
│ │
│ ├── errata/
│ │ ├── soc-errata.pdf
│ │ └── kernel-known-bugs.md
│ │
│ └── known-issues/
│ ├── ethernet.md
│ ├── usb.md
│ └── board-rev-differences.md
│
├── checklists/
│ ├── ethernet.md
│ ├── i2c.md
│ ├── spi.md
│ ├── usb.md
│ ├── gpio.md
│ └── driver-probe.md
│
└── scripts/
├── collect_hw_info.sh
├── collect_eth_info.sh
├── collect_i2c_info.sh
├── collect_spi_info.sh
└── collect_usb_info.sh
六、有些内容不要混在一起
1. 通用方法和项目事实分开
通用方法:
排查设备前,先确认设备树和驱动是否匹配。
项目事实:
当前板卡 PHY 地址是 3。
前者适合放在 SKILL.md 或 checklists/。后者适合放在 references/known-issues/。
2. SoC 手册和外设手册分开
SoC 手册主要涉及:
外设手册主要涉及:
分开以后,查资料时不容易混。
3. 历史问题不要都写进 SKILL.md
SKILL.md 只保留相对稳定的规则。项目历史问题、板卡差异和临时限制,单独放到:
references/known-issues/
否则入口文件会越来越长,后面很难维护。
七、全局 Skill 和项目 Skill 怎么分
比较稳妥的做法,是分成两层。
1. 全局 Skill
放通用方法:
linux-arm-debug-global/
├── SKILL.md
├── checklists/
└── scripts/
例如:
- clock、reset、regulator 机制;
- Ethernet、I2C、SPI、USB 通用清单;
2. 项目 Skill
放当前板卡资料:
project/.agents/skills/board-hardware/
├── SKILL.md
└── references/
例如:
全局 Skill 放排查方法,项目 Skill 放当前项目的真实情况。
写在最后
一个 Linux + ARM 硬件 Skill,前期不需要做得特别大。先搭好这四部分就够了:
SKILL.md
references/
checklists/
scripts/
SKILL.mdreferences/checklists/scripts/
目录理顺以后,后面再增加芯片手册、原理图和调试记录,也不会越做越乱。
做这类 Skill,关键不是塞进去多少文档,
而是出问题时,能不能马上找到该看的那一份。
技术地平线|探索技术前沿,洞见未来科技。