> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs-staging.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 设备树架构

Qualcomm<sup>®</sup> Linux 内核使用分层的设备树（DT）架构，将平台特定的硬件
描述与 SoC 级配置分离。在启动时，UEFI 固件通过将硬件检测到的标识符与
`compatible` 字符串进行匹配，从 FIT 镜像中选择正确的 DTB。

## DTS 和 DTSI 文件结构

设备树源文件位于内核源码树的 `arch/arm64/boot/dts/qcom/` 目录下。

**表：设备树文件类型**

| 文件类型    | 用途                                                                |
| ------- | ----------------------------------------------------------------- |
| `.dtsi` | SoC 级或共享的硬件描述。由开发板 DTS 文件包含。                                      |
| `.dts`  | 开发板级文件。包含一个或多个 DTSI 文件，并添加开发板特定的节点，如引脚复用设置、稳压器和板载外设。              |
| `.dtb`  | 由 DTS 文件编译得到的二进制输出。运行时由引导加载程序加载。                                  |
| `.dtbo` | 设备树 overlay 二进制文件。应用在基础 DTB 之上，以启用可选的硬件配置，例如夹层板（mezzanine board）。 |

## 开发板与 SoC 分层

Qualcomm Linux 遵循严格的两层分层约定：

1. **SoC DTSI**（例如 `qcs6490.dtsi`），定义时钟、电源域、中断控制器以及
   使用该 SoC 的所有开发板通用的核心外设。

2. **开发板 DTS**（例如 `qcs6490-rb3gen2.dts`），包含 SoC DTSI 并添加
   开发板特定的节点：GPIO 分配、稳压器数值、板载传感器和显示面板。

典型的开发板 DTS 以如下内容开头：

```dts theme={null}
#include <dt-bindings/...>
#include "qcs6490.dtsi"

/ {
    model = "Qualcomm QCS6490 Dragonwing™ RB3 Gen2";
    compatible = "qcom,qcs6490-rb3gen2", "qcom,qcs6490";
    /* ... additional board-specific nodes ... */
};
```

## 基于 FIT 的 DTB 打包

Qualcomm Linux 在单个软件发布版本中支持多个 SoC 和开发板。DTB 被打包成
一个扁平化镜像树（FIT）镜像（`qclinux_fit.img`），存储在 `dtb_a` 分区中。
UEFI 固件在启动时通过将硬件检测到的标识符与每个 FIT 配置条目的
`compatible` 字符串进行匹配来选择正确的 DTB。

FIT 镜像由镜像树源（`.its`）文件描述，并使用 `mkimage` 构建。它有两个
顶层部分：

* `images`，声明每个二进制 blob：DTB、DTBO 和元数据二进制文件。
* `configurations`，声明每个平台配置，每个配置引用一个或多个镜像。

一个最小的 ITS 骨架：

```text theme={null}
/dts-v1/;
/ {
    images {
        /* metadata maps config compatible strings to hardware IDs */
        fdt-qcom-metadata.dtb {
            data = /incbin/("./qcom-metadata.dtb");
            type = "qcom_metadata";
        };
        fdt-<soc>-<board>.dtb {
            data = /incbin/("./arch/arm64/boot/dts/qcom/<soc>-<board>.dtb");
            type = "flat_dt";
        };
    };
    configurations {
        conf-1 {
            compatible = "qcom,<soc>-<board>";
            fdt = "fdt-<soc>-<board>.dtb";
        };
        /* Base DTB + software overlay (CamX) + hardware overlay */
        conf-2 {
            compatible = "qcom,qcs9075-iot-camx-el2kvm";
            fdt = "fdt-lemans-evk.dtb",
                  "fdt-lemans-evk-camx.dtbo",
                  "fdt-lemans-el2.dtbo";
        };
    };
};
```

### Qualcomm DTB 元数据

[qcom-dtb-metadata](https://github.com/qualcomm-linux/qcom-dtb-metadata)
项目提供：

* `qcom-metadata.dts` 编译为元数据 DTB，固件用它将硬件标识符映射到 FIT
  配置的 `compatible` 字符串。
* `qcom-next-fitimage.its` 是用于独立构建的 ITS 模板。

元数据 DTS 将允许的 `compatible` 字符串后缀标记按节点分组：
`soc`、`soc-sku`、`socver`、`board`、`boardrev`、`board-subtype-*`、`softsku`
和 `oem`。

### 启动时的 DTB 选择流程

1. UEFI 从 `dtb_a` 分区加载 `qclinux_fit.img`。
2. 解析内嵌的 `qcom-metadata.dtb`，构建一张将硬件数字 ID 映射到
   `compatible` 字符串中所用符号标记名称的表。
3. 读取硬件标识符：SoC 芯片 ID/版本、来自配置数据表（CDT）的开发板类型
   和版本、存储类型以及 DDR 大小。
4. 按顺序遍历 FIT 配置（`conf-1`、`conf-2`、…）。
5. 对于每个配置，将其 `compatible` 字符串中的每个标记与硬件推导出的值
   进行精确匹配。选择所有标记都匹配的第一个配置。
6. 加载所选配置的 DTB，并通过 EFI 引导传递给操作系统。
7. 如果没有配置匹配，则启动失败。有关诊断步骤，请参阅
   [常见 DT 问题及修复](./common-dt-issues#no-dtb-loaded-due-to-fit-configuration-match-failure)。

### Compatible 字符串格式

每个 FIT 配置的 `compatible` 字符串将平台标识编码为以连字符分隔的标记：

```text theme={null}
qcom,<soc>[-<soc-sku>][-<socver>]-<board>[-<boardrev>]
          [-<peripheral-subtype>][-<storage-type>][-<memory-size>]
          [-<softsku>][-<oem>]
```

省略某个标记会使该维度不受约束，即它匹配该字段的任何硬件值。在
`configurations` 块中，更具体的字符串应出现在通用字符串之前。

**示例：**

```text theme={null}
qcom,qcm6490-idp                 # SoC + board only (matches all revisions)
qcom,qcs9100-qam-r1.0            # SoC + board + explicit board revision
qcom,qcs6490-iot-subtype2        # SoC + board + peripheral subtype
```

## 将 DTB 接入 FIT 镜像（Yocto）

Yocto 构建根据两个输入生成 FIT 镜像：

* `KERNEL_DEVICETREE` 和 `LINUX_QCOM_KERNEL_DEVICETREE` 表示要打包到
  `images` 部分的 DTB 和 DTBO 列表。
* `conf/machine/include/fit-dtb-compatible.inc` 中的 `FIT_DTB_COMPATIBLE`
  条目枚举 `configurations` 部分的条目，将 DTB（或 DTB+DTBO 组合）映射到
  UEFI 在启动时将匹配的硬件 `compatible` 字符串。

```text theme={null}
# Upstream DTBs and DTBOs
KERNEL_DEVICETREE ?= " \
    qcom/qcs6490-rb3gen2.dtb \
    qcom/qcs6490-rb3gen2-industrial-mezzanine.dtbo \
    qcom/qcs6490-rb3gen2-vision-mezzanine.dtbo \
    "

# Downstream-only DTBOs (not yet upstreamed)
LINUX_QCOM_KERNEL_DEVICETREE ?= " \
    qcom/qcs6490-rb3gen2-vision-mezzanine-camx.dtbo \
    "
```

### FIT\_DTB\_COMPATIBLE 条目

每个条目将一个 DTB 键（或使用 `+` 作为分隔符的 `DTB+DTBO` 键）映射到一个
或多个 `compatible` 字符串：

**无 overlay 的单个 DTB：**

```text theme={null}
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2] = " \
    qcom,qcs5430-iot \
    qcom,qcs6490-iot \
    "
```

**DTB + DTBO 组合：**

```text theme={null}
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2+qcs6490-rb3gen2-vision-mezzanine] = " \
    qcom,qcs5430-iot-subtype2 \
    qcom,qcs6490-iot-subtype2 \
    "
```

**同一基础 DTB 的多种组合：**

```text theme={null}
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2] = " \
    qcom,qcs5430-iot \
    qcom,qcs6490-iot \
    "
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2+qcs6490-rb3gen2-industrial-mezzanine] = " \
    qcom,qcs5430-iot-subtype9 \
    qcom,qcs6490-iot-subtype9 \
    "
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2+qcs6490-rb3gen2-vision-mezzanine] = " \
    qcom,qcs5430-iot-subtype2 \
    qcom,qcs6490-iot-subtype2 \
    "
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2+qcs6490-rb3gen2-vision-mezzanine-camx] = " \
    qcom,qcs6490-iot-camx \
    qcom,qcs6490-iot-subtype2-camx \
    "
```

这些条目会在 FIT 镜像中生成一个 `configurations` 块，其中每个 `conf-N`
条目都带有相应的 `compatible` 字符串和 `fdt` 列表。UEFI 按顺序遍历这些
配置，并选择第一个匹配的配置。

<Note>
  在 `configurations` 块中，更具体的 `compatible` 字符串必须出现在通用
  字符串之前。FIT 按顺序评估配置；第一个匹配即胜出。有关 compatible
  字符串标记参考，请参阅
  [设备树架构](./device-tree-architecture#compatible-string-format)。
</Note>

## 在运行时应用设备树 overlay

Qualcomm Linux 在引导期间应用设备树 overlay，而不是在 Linux 运行时应用。UEFI 读取 `VendorDtbOverlays` EFI 变量，从 `dtb.bin` 中选择匹配的 overlay 集合，并在将控制权交给内核之前将其合并到设备树中。因此，对该变量的任何更改都会在下次引导时生效。

<Note>
  主线内核没有可用于向运行中的设备树应用 overlay 的用户空间接口。它仅将 `of_overlay_fdt_apply()` 作为内核内部 API 公开，并且 Qualcomm Linux 未启用基于 configfs 或 sysfs 的 overlay 加载器。因此，在此平台上无法使用将 `.dtbo` 文件写入 sysfs 或 configfs 节点的方法。有关内核内部 API 的信息，请参阅：
  [Devicetree Overlay Notes](https://docs.kernel.org/devicetree/overlay-notes.html)。
</Note>

### 选择 overlay 集合

`VendorDtbOverlays` EFI 变量接受以下值：

**表：VendorDtbOverlays 的值**

| 值         | 效果                                                  |
| --------- | --------------------------------------------------- |
| `el2kvm`  | 应用 `*-el2.dtso` overlay，使 Linux 在 EL2 上作为 KVM 主机运行。 |
| `staging` | 应用 `*-staging.dtso` overlay，启用尚未进入上游的树内驱动。          |
| `camx`    | 应用 `*-camx.dtso` overlay，以 CAMX 相机栈替换上游的 `camss`。   |

按照以下步骤应用 overlay 集合：

1. 确认已挂载 `efivarfs`，以便该变量可写：

   ```bash theme={null}
   mount | grep efivarfs
   # If not mounted:
   mount -t efivarfs efivarfs /sys/firmware/efi/efivars
   ```

2. 将 overlay 名称写入该变量。将 `<overlay>` 替换为上表中的某个值：

   ```bash theme={null}
   echo -n "<overlay>" > /tmp/overlay
   efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays \
       -w -f /tmp/overlay
   ```

3. 读回该变量以确认写入成功：

   ```bash theme={null}
   efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays -p
   ```

4. 将写入刷新到存储并重启。该变量保存在基于 RPMB 的 EFI 变量存储中，未刷新的写入会在复位时丢失：

   ```bash theme={null}
   sync && reboot
   ```

5. 设备启动后，确认 UEFI 已读取并应用了该 overlay。UEFI 串口控制台上会出现以下内容：

   ```text theme={null}
   Variable VendorDtbOverlays read successfully. Data: camx
   ProcessQcomRuntimeOverlayRequest: Parsed camx
   ```

6. 通过检查 overlay 添加的节点，确认该 overlay 已传递到内核：

   ```bash theme={null}
   # Example: the CAMX overlay disables the upstream camss node
   cat /proc/device-tree/soc@0/camss@ac5a000/status
   # Compare the full tree against the pre-overlay state
   dtc -I fs -O dts /proc/device-tree 2>/dev/null > /tmp/live.dts
   ```

### 组合多个 overlay 集合

要应用多个 overlay 集合，请使用逗号分隔各个值：

```bash theme={null}
echo -n "camx,el2kvm" > /tmp/overlay
efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays \
    -w -f /tmp/overlay
sync && reboot
```

### 恢复为默认设备树

删除该变量并重启系统。此后 UEFI 将跳过 overlay 应用，直接使用基础平台 DTB 引导：

```bash theme={null}
efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays -d
sync && reboot
```

## 用于 KVM 的 EL2 设备树

文件名中带有 `el2` 标记的设备树文件支持 Linux 在异常级别 2（EL2）运行
以支持 KVM。构建系统将 `el2` overlay 应用于平台 DTB，以生成 EL2 DTB
变体。目标默认以 KVM 模式启动，但少数目标可能尚未支持 KVM。请参阅发行
说明以了解平台能力。有关更多详细信息，请参阅
[启用虚拟化](./enable-virtualization)。

## Staging 设备树 overlay

文件名中带有 `staging` 标记的设备树文件用于启用存在于内核源码树中但
尚未提交到上游的驱动。示例包括 SoC 级 TGU 节点（`kodiak-staging.dtso`、
`lemans-staging.dtso`、`monaco-staging.dtso`、`talos-staging.dtso`）以及
面向开发套件的开发板级 staging 以太网 PHY overlay。当 `VendorDtbOverlays`
EFI 变量设置为 `staging` 时，构建系统会应用这些 overlay：

```bash theme={null}
echo -n "staging" > /tmp/overlay
efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays \
    -w -f /tmp/overlay
efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays -p
sync && reboot
```

<Note>
  当需要 staging 下游特性时，请使用 staging DTB。
</Note>

## CAMX 相机设备树 overlay

文件名中带有 `camx` 标记的设备树文件用 Qualcomm® CAMX 专有相机框架
替换上游相机子系统（`camss`）。开发板级 CAMX overlay（例如
`qcs6490-rb3gen2-vision-mezzanine-camx.dtso`、`lemans-evk-camx.dtso`、
`monaco-evk-camx.dtso`）禁用上游 `camss` 节点并启用 CAMX 节点。当同时
需要 CAMX 和 KVM 时，会应用组合的 `*-camx-el2.dtso` overlay。当
`VendorDtbOverlays` EFI 变量设置为 `camx` 时，构建系统会应用 CAMX
overlay：

```bash theme={null}
echo -n "camx" > /tmp/overlay
efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays \
    -w -f /tmp/overlay
efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays -p
sync && reboot
```

<Note>
  仅在使用 Qualcomm 专有相机栈构建时才使用 CAMX DTB。在 CAMX 配置中，
  上游 `camss` 驱动被禁用。
</Note>
