Linux Kernel Device Tree 配置详解:Camera 驱动中的实际节点设计与解析

关键词:
Device Tree、设备树、Camera 驱动、Sensor 节点、MIPI CSI、V4L2、platform device、endpoint、Media Controller

摘要:
在嵌入式 Linux 系统中,Device Tree(设备树)是连接硬件资源与内核驱动的核心桥梁。尤其在 Camera 子系统中,设备树配置涉及 Sensor、I2C 总线、MIPI CSI 接口、时钟、GPIO、电源管理等多个子模块,是驱动成功运行与模块自动绑定的前提。本文将围绕主流平台上的实际项目,系统解析 Linux Kernel 中 Camera 相关的设备树节点设计、字段作用、数据流路径配置与平台差异,帮助开发者构建健壮、可扩展的 Camera DT 结构。

目录:

一、设备树在 Camera 系统中的作用与结构角色
二、Sensor 节点结构详解:compatible、reg、端口定义
三、MIPI CSI 与 ISP 节点配置:物理链路映射与拓扑描述
四、端口与 endpoint 机制:remote-endpoint 与 media graph 建立流程
五、时钟、电源与 GPIO 控制字段设计及其作用
六、多摄模组设备树编写策略:I2C 多地址与虚拟通道配置
七、主流平台对比分析:高通 / MTK / 海思的 DT 结构差异与适配技巧
八、工程实战示例:基于 IMX586 的完整 Camera Device Tree 配置案例

一、设备树在 Camera 系统中的作用与结构角色

在 Linux 内核架构中,Device Tree(设备树) 是用于描述 SoC 外设连接关系与硬件资源配置的结构化数据文件,通常以 .dts.dtsi 格式编写,最终被编译为二进制传递给内核。对于 Camera 系统而言,设备树的作用尤为关键,因为摄像头模组的种类多、硬件差异大、外设连接多样,而大部分驱动使用的是统一框架驱动 + 数据驱动匹配策略,依赖设备树进行灵活适配。

1. Camera 系统的典型组件

一个完整的 Camera pipeline 通常包括:

  • Sensor(通过 I2C/SPI 控制)
  • MIPI CSI 接口(连接 Sensor 与 ISP)
  • ISP/VFE 模块(图像处理)
  • DMA 输出节点(Video Node)
  • Lens / Flash / EEPROM 等外设

设备树负责定义上述组件的物理地址、通信协议、连接拓扑、时钟控制、复位方式等。内核通过读取这些信息构建 Platform Device 并匹配 Platform Driver,实现自动驱动绑定与资源初始化。

2. Device Tree 在驱动加载流程中的角色
flowchart TD
  A[Bootloader] --> B[Linux 内核启动]
  B --> C[解析 .dtb 文件]
  C --> D[注册 Platform Device]
  D --> E[of_match_table 匹配驱动]
  E --> F[执行 probe() 函数]
  F --> G[驱动读取 DT 获取资源]

在此流程中:

  • compatible 字段用于匹配驱动;
  • reg 字段指明 I2C 地址;
  • port/endpoint 用于建立 Media Controller 图;
  • 时钟、电源、GPIO 由 clocksregulatorsgpios 解析生成控制器;
  • 若 DT 中遗漏必要字段,驱动初始化将失败或部分功能不可用。
3. 典型平台路径

在主流平台(如高通、MTK、海思)中,Camera 设备树结构一般分布于以下文件:

  • 高通:arch/arm64/boot/dts/qcom/msmXXXX-camera.dtsi
  • MTK:mediatek/platform/mtxxxx/camera/xxx.dtsi
  • 海思:hi_mipi/camera/xxx_sensor.dtsi + device/hisilicon/dts/xxx.dts

二、Sensor 节点结构详解:compatible、reg、端口定义

Sensor 节点是设备树中描述摄像头模组硬件连接关系的起点,主要挂载在 I2C 控制器下,以 I2C slave 的形式存在。以下以常见的 IMX586 为例详细解析:

1. 典型节点结构
&i2c0 {
    status = "okay";

    imx586@1a {
        compatible = "sony,imx586";
        reg = <0x1a>;                     // I2C 地址(7-bit)
        clocks = <&camclk0>;             // Sensor MCLK 时钟
        reset-gpios = <&gpio 38 GPIO_ACTIVE_LOW>;
        powerdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
        rotation = <0>;                  // optional,0/90/180/270
        orientation = "back";            // 前后摄标识

        port {
            imx586_ep: endpoint {
                clock-lanes = <0>;
                data-lanes = <1 2>;
                link-frequencies = /bits/ 64 <560000000>;
                remote-endpoint = <&csid0_ep>;
            };
        };
    };
};
2. 字段含义说明
字段名含义与用途
compatible驱动匹配关键字段,对应内核驱动中 of_match_table
regI2C 地址(7 位地址),实际传输时左移 1 位作为 8-bit 地址
clocksSensor 所需的外部 MCLK 输入,通常为 24MHz,配置在 clock controller 节点中
reset-gpios控制 Sensor 的复位引脚,拉低进入复位状态
powerdown-gpios控制 Sensor 的电源使能状态(可选)
portMedia Controller 子系统的拓扑描述容器
endpoint与下游 MIPI CSI 接口的连接描述,包括 data lane、clock lane、频率等
remote-endpoint指向 CSI 的 endpoint 节点,实现双向连接
3. 多模组配置建议(双摄/三摄)
&i2c1 {
    imx586_main@1a {
        compatible = "sony,imx586";
        reg = <0x1a>;
        ...
        port {
            imx586_main_ep: endpoint {
                remote-endpoint = <&csid0_ep>;
            };
        };
    };

    ov08d10_macro@36 {
        compatible = "ovti,ov08d10";
        reg = <0x36>;
        ...
        port {
            ov08d10_ep: endpoint {
                remote-endpoint = <&csid1_ep>;
            };
        };
    };
};

每个 Sensor 分别配置 endpoint 与不同 CSI 通道对接,通过 remote-endpoint 建立连接关系。

4. 工程实践注意事项
  • 多摄场景下,I2C 地址必须唯一,避免挂载失败;
  • 若 Sensor 模组使用相同型号,建议使用 alias 节点或修改 label 字段区别主副摄;
  • link-frequencies 对部分平台(如高通)是强校验字段,必须与实际 MIPI 速率一致;
  • 若使用设备树 Overlay 动态加载 Sensor,需确保对应驱动可 hot-plug 注册;
  • 设备树字段必须与驱动解析字段一致,否则 probe 将因 of_property_read_*() 失败而退出。

三、MIPI CSI 与 ISP 节点配置:物理链路映射与拓扑描述

在 Linux Camera 系统中,Sensor 并不直接向 ISP 发送图像帧,而是先通过 MIPI CSI(Camera Serial Interface)模块进行解码,再送入 ISP 或 VFE 处理模块。设备树中必须正确配置 MIPI 接收端(通常为 csidcsi 节点)与 ISP 入口,才能建立一条完整的数据传输链路。

1. Camera 数据链路结构图
Sensor --> MIPI PHY (MIPI D-PHY Rx)
       --> CSID (CSI Decoder, 识别 VC/DT/帧头)
       --> ISP/VFE (图像前处理)
       --> DMA/V4L2 输出

设备树中的核心任务是用 port + endpoint 节点把这些模块串联成一个 Media Controller 图,驱动在 probe 阶段才能解析出正确的数据路径。

2. MIPI CSID 节点定义示例(以高通平台为例)
csid0: csid@ac40000 {
    compatible = "qcom,csid";
    reg = <0x0ac40000 0x1000>;
    clocks = <&camcc CAMCC_CSID_CLK>;
    clock-names = "csid";
    status = "okay";

    port {
        csid0_ep: endpoint {
            reg = <0>;
            data-lanes = <1 2>;
            clock-lanes = <0>;
            remote-endpoint = <&imx586_ep>;
        };
    };
};

说明:

  • compatible: 指定 CSID 驱动类型
  • reg: 映射的物理地址,用于驱动寄存器访问
  • port.endpoint: 指定输入端的 D-PHY 参数及连接的 Sensor

此处的 remote-endpoint = <&imx586_ep>; 是指本 CSID 是从 Sensor 的 endpoint 获取数据,实现链路闭环。

3. ISP/VFE 节点定义示例
vfe0: vfe@ac80000 {
    compatible = "qcom,vfe";
    reg = <0x0ac80000 0x1000>;
    interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
    clock-names = "vfe";
    status = "okay";

    port {
        vfe0_ep: endpoint {
            reg = <0>;
            remote-endpoint = <&csid0_output_ep>;
        };
    };
};

有的平台将 csid 的输出端也建为 endpoint,如:

csid0_output_ep: endpoint@1 {
    reg = <1>;
    remote-endpoint = <&vfe0_ep>;
};

通过这些双向 remote-endpoint 链接,实现一个完整的数据路径闭环。

4. 注意事项
  • reg 字段指的是端口编号(非地址),用于驱动区分多路输入
  • data-lanes 必须与 Sensor 输出一致,否则解析 MIPI 帧头失败
  • 某些平台(如 MTK)将 csidvfe 合并为 cam-isp,结构稍简化,但原理一致
  • 若使用多个 CSI 通道(csid0, csid1…),需为每一路单独配置 port 节点

四、端口与 endpoint 机制:remote-endpoint 与 media graph 建立流程

1. 为什么需要端口机制?

在传统 Linux 驱动模型中,设备节点描述的是单个 device 的属性。但 Camera 系统是一个图结构,包含多个 producer-consumer 节点,如:

  • Sensor → CSI → ISP → DMA
  • Lens → VCM → Focus Controller

每一个模块都可能有多个输入/输出接口,为了明确数据流向,Linux 引入了 Media Controller 架构,并通过 portendpoint 来表示模块的“接口”和“连线”。

2. 结构定义规范
sensor@1a {
    port {
        sensor_ep: endpoint {
            reg = <0>;
            remote-endpoint = <&csid_ep>;
            data-lanes = <1 2>;
        };
    };
};

csid@xxx {
    port {
        csid_ep: endpoint {
            reg = <0>;
            remote-endpoint = <&sensor_ep>;
        };
    };
};

每一层的连接都是 双向定义,驱动会使用 media_entity_parse_graph() 建立完整拓扑。

3. remote-endpoint 的功能
  • 为媒体框架建立 entity link 提供路径信息
  • 在驱动 probe 时由 v4l2_async_register_subdev() 检索依赖项
  • 支持热插拔、链路切换、同步通知(如 stream_on/off)
4. reg 与 port 的逻辑关系
项目意义
port模块的“对外接口容器”
reg in port表示该接口的编号,驱动用于区分
endpoint某个接口的具体连接定义
remote-endpoint表示连接的目标接口位置(句柄)
5. 多摄场景下的链路拓扑举例
graph TD
  IMX586["Sensor@1a (port0)"] -->|remote-endpoint| CSI0
  OV08D10["Sensor@36 (port0)"] -->|remote-endpoint| CSI1
  CSI0 -->|output_ep| ISP0
  CSI1 -->|output_ep| ISP0
  ISP0 --> V4L2_Node
graph TD IMX586["Sensor@1a (port0)"] -->|remote-endpoint| CSI0 OV08D10["Sensor@36 (port0)"] -->|remote-endpoint| CSI1 CSI0 -->|output_ep| ISP0 CSI1 -->|output_ep| ISP0 ISP0 --> V4L2_Node

通过完整链路连接定义,系统可在用户空间通过 media-ctl 工具自动识别模块路径:

media-ctl -p

输出:

- entity 1: imx586 1-001a
  - pad 0: Source
- entity 2: csid0
  - pad 0: Sink
  - pad 1: Source
- entity 3: vfe0
  - pad 0: Sink

五、时钟、电源与 GPIO 控制字段设计及其作用

在 Camera 子系统中,Sensor 模组的正常工作依赖多个基础控制信号与资源,包括:时钟(MCLK)、电源(LDO/PMIC)、复位控制(RESET GPIO)、电源控制(PWDN GPIO)等。这些控制通常由设备树中的 clocksregulatorsgpios 等字段描述,驱动通过通用接口解析并进行状态操作。

1. Sensor 模组启动时序需求

以下为多数 CMOS Sensor 的典型上电顺序要求:

  1. 使能 LDO 电源(如 AVDD、DVDD)
  2. 控制 PWDN 为低,释放电源门控
  3. 复位脚拉高,开始 Sensor 初始化
  4. 打开 MCLK 时钟输入
  5. 启动 I2C 通信,读写寄存器进行配置

错误的时序顺序会导致 Sensor 无响应、帧启动失败或 I2C NACK。

2. 时钟字段配置(clocks)
clocks = <&camcc CAM_CC_MCLK0_CLK>;
clock-names = "xclk";

说明:

  • clocks: 指向时钟控制器节点和索引
  • clock-names: 对应驱动中 devm_clk_get(dev, "xclk")

通常用于提供外部 24MHz Sensor MCLK(Master Clock),由平台专用控制器输出。

3. 电源控制(regulators)
avdd-supply = <&camera_vana>;
dvdd-supply = <&camera_vdig>;
iovdd-supply = <&camera_vio>;

说明:

  • 驱动中通过 regulator_get() 获取 LDO 句柄
  • regulator_enable() / regulator_disable() 控制上电
  • 名称如 avdd-supply 必须与驱动中定义一致(如 supply_names[]

在平台 PMIC 中需定义相关 LDO 输出节点。

4. GPIO 控制字段
reset-gpios = <&tlmm 24 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>;

说明:

  • 控制 Sensor 模组的 RESET 和 PWDN 信号
  • GPIO_ACTIVE_LOW 表示低电平有效
  • 驱动中使用 gpiod_set_value() 操作对应引脚

在驱动中常见控制逻辑:

gpiod_set_value(pwdn_gpio, 0);
msleep(2);
gpiod_set_value(reset_gpio, 1);
5. 工程建议
  • 统一 GPIO 控制器引用格式,如 tlmmgpio0,便于多平台适配
  • 保证上电顺序一致,避免动态电压不稳导致 Sensor 初始化失败
  • 时钟控制器需配置频率,否则可能输出默认 0Hz(MTK 平台尤为关键)

六、多摄模组设备树编写策略:I2C 多地址与虚拟通道配置

随着手机影像系统进入多摄时代,设备树中需要支持多个 Sensor 实例、多 I2C 通道、多 MIPI 通道甚至同一 Sensor 模组挂载多个子地址(如主摄 + AF + EEPROM)。同时,通过 MIPI 虚拟通道(VC)标识帧来源,也成为多摄系统拓扑设计的重要部分。

1. 多摄模组设备树结构概览
&i2c0 {
    imx766_main: sensor@1a {
        compatible = "sony,imx766";
        reg = <0x1a>;
        port {
            endpoint {
                remote-endpoint = <&csid0_ep>;
                data-lanes = <1 2>;
                vc-id = <0>;
            };
        };
    };

    imx766_ultrawide: sensor@1c {
        compatible = "sony,imx766";
        reg = <0x1c>;
        port {
            endpoint {
                remote-endpoint = <&csid1_ep>;
                data-lanes = <1 2>;
                vc-id = <1>;
            };
        };
    };
};

说明:

  • 同一 Sensor 型号(如 IMX766)可挂载多个实例,区别在于 reg 地址与 label
  • vc-id 用于指定 MIPI CSI 通道帧的虚拟通道 ID(VC0~VC3)
  • CSI 接收端需要能区分不同 VC,否则帧可能混乱
2. EEPROM/VCM 模块挂载策略

某些模组除了主 Sensor 外,还集成:

  • EEPROM(存放 OTP/标定参数)→ reg=0x50
  • AF 马达(如 VCM)→ reg=0x0c

这类组件可与 Sensor 位于同一 I2C 总线,通过多子节点挂载:

sensor_eeprom@50 {
    compatible = "qcom,eeprom";
    reg = <0x50>;
};

sensor_af@0c {
    compatible = "moto,af-driver";
    reg = <0x0c>;
};

驱动会在初始化时调用子设备,完成 EEPROM 读参、AF 配置等工作。

3. MIPI 虚拟通道配置策略

MIPI CSI 协议允许最多 4 路虚拟通道(VC0~VC3)同时承载数据流,不同平台使用方式如下:

平台支持方式常见配置
高通每个 VC 分配不同 CSID 端口CSID0 → VC0, CSID1 → VC1
MTKISP mux 管理 VC→PIPELINE 映射一般通过 csi_sel 配置
海思固定每个 VC 对应 pipeline通常为 VC0:主摄, VC1:副摄

示例配置(Qcom):

csid0: csid@ac40000 {
    port {
        endpoint {
            reg = <0>;
            remote-endpoint = <&imx766_main_ep>;
            virtual-channel = <0>;
        };
    };
};

csid1: csid@ac41000 {
    port {
        endpoint {
            reg = <1>;
            remote-endpoint = <&imx766_ultrawide_ep>;
            virtual-channel = <1>;
        };
    };
};
4. HAL 层与 V4L2 匹配建议
  • 建议将每个模组的 label 字段命名为 rear_mainrear_ultrawide 等语义化标识,便于 HAL 自动识别;
  • vc-id + stream_id 联合匹配可以提高多模组容错率;
  • 若设备树无法覆盖动态需求(如热插拔、虚拟 Sensor),需结合 I2C 动态注册机制与 Overlay 动态加载支持。

七、主流平台对比分析:高通 / MTK / 海思的 DT 结构差异与适配技巧

尽管 V4L2 框架和 Device Tree 的基本语法在 Linux 内核中保持一致,但不同芯片平台由于 ISP 架构、驱动框架与时钟/电源模型的不同,在 Camera 设备树结构上存在明显差异。理解这些差异是成功适配多平台摄像头模组的关键。


1. 高通平台(Qualcomm)

高通平台使用 CSI + CSID + VFE (ISP) 的多级结构,设备树较为标准化,模块分层清晰:

&cci_i2c_0 {
    imx586_qtr: imx586@1a {
        compatible = "sony,imx586";
        reg = <0x1a>;
        clocks = <&camcc CAM_CC_CAMSS_MCLK0_CLK>;
        ...
        port {
            imx586_ep: endpoint {
                clock-lanes = <0>;
                data-lanes = <1 2>;
                remote-endpoint = <&csid0_ep>;
                vc-id = <0>;
            };
        };
    };
};

csid0: csid@ac40000 {
    ...
    port {
        csid0_ep: endpoint {
            reg = <0>;
            remote-endpoint = <&imx586_ep>;
        };
    };
};

vfe0: vfe@ac80000 {
    ...
    port {
        vfe0_ep: endpoint {
            remote-endpoint = <&csid0_ep_out>;
        };
    };
};

特点与建议:

  • 多级 port/endpoint 构建完整 media graph
  • 所有设备需明确定义 clocks、regulators、gpios
  • 支持虚拟通道(vc-id)明确数据流归属
  • 驱动严格解析字段,字段缺失会导致 probe 失败

2. MTK 平台(联发科)

MTK Camera 架构通常合并 ISP + CSI 功能,模块抽象为 seninfisp,设备树扁平化,依赖中间管理器协调。

&i2c0 {
    ov08d10@36 {
        compatible = "ovti,ov08d10";
        reg = <0x36>;
        clocks = <&topckgen CLK_TOP_CAMTG>;
        ...
        port {
            endpoint {
                remote-endpoint = <&seninf_ep0>;
            };
        };
    };
};

seninf@15020000 {
    ...
    port {
        seninf_ep0: endpoint {
            remote-endpoint = <&ov08d10_ep>;
        };
    };
};

特点与建议:

  • 多摄支持需通过 csi_selsensor_type 区分不同 pipeline
  • 少量平台支持 VC ID,多采用静态映射
  • 电源、复位、PWDN 控制必须通过 MTK 的 pinctrl 机制,否则无效
  • MIPI 配置通过 seninf 统一处理,建议参照 MTK Camera HAL 提供的配置顺序

3. 海思平台(HiSilicon)

海思平台设备树抽象风格偏“平台封闭型”,Camera 通常由 sensor + hi_isp + vi + pipe 等模块协作完成,路径定义需要平台驱动辅助构建。

i2c@fcb03000 {
    imx586@1a {
        compatible = "hisilicon,imx586";
        reg = <0x1a>;
        ...
        port {
            endpoint {
                bus-type = <4>; // MIPI
                remote-endpoint = <&vi_in0>;
            };
        };
    };
};

vi@fcb08000 {
    ...
    port {
        vi_in0: endpoint {
            remote-endpoint = <&imx586_ep>;
        };
    };
};

特点与建议:

  • Device Tree 结构受平台 SDK 限制,强依赖驱动绑定顺序
  • 多 Sensor 支持需定制化添加 VI Channel 路由逻辑
  • ISP 模块往往集成于 HAL,设备树只标注 Sensor 与 VI 输入
  • 多平台封装性强,建议参考官方 HiCamera SDK 示例模板

八、工程实战示例:基于 IMX586 的完整 Camera Device Tree 配置案例

以下以高通平台为例,给出一个完整的 IMX586 摄像头设备树配置示例,涵盖 I2C、MIPI、时钟、GPIO、电源、拓扑等完整配置。

1. Sensor 节点(I2C)
&cci_i2c_0 {
    imx586@1a {
        compatible = "sony,imx586";
        reg = <0x1a>;
        clocks = <&camcc CAM_CC_CAMSS_MCLK0_CLK>;
        clock-names = "xclk";
        reset-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
        pwdn-gpios = <&tlmm 36 GPIO_ACTIVE_HIGH>;
        avdd-supply = <&ldo_1p8>;
        dvdd-supply = <&ldo_1p2>;

        port {
            imx586_ep: endpoint {
                clock-lanes = <0>;
                data-lanes = <1 2>;
                remote-endpoint = <&csid0_ep>;
                link-frequencies = /bits/ 64 <480000000>;
                vc-id = <0>;
            };
        };
    };
};
2. MIPI CSID 节点
csid0: csid@ac40000 {
    compatible = "qcom,csid";
    reg = <0x0ac40000 0x1000>;
    clocks = <&camcc CAM_CC_CSID_CLK>;
    clock-names = "csid";
    status = "okay";

    port {
        csid0_ep: endpoint {
            reg = <0>;
            remote-endpoint = <&imx586_ep>;
        };
    };
};
3. ISP(VFE)节点
vfe0: vfe@ac80000 {
    compatible = "qcom,vfe";
    reg = <0x0ac80000 0x1000>;
    interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&camcc CAM_CC_VFE_CLK>;
    clock-names = "vfe";

    port {
        vfe0_ep: endpoint {
            remote-endpoint = <&csid0_ep_out>;
        };
    };
};
4. 电源管理节点(PMIC)
ldo_1p8: regulator@1400 {
    compatible = "regulator-fixed";
    regulator-name = "cam_vana";
    regulator-min-microvolt = <1800000>;
    regulator-max-microvolt = <1800000>;
    gpio = <&tlmm 45 GPIO_ACTIVE_HIGH>;
    enable-active-high;
};

ldo_1p2: regulator@1500 {
    compatible = "regulator-fixed";
    regulator-name = "cam_vdig";
    regulator-min-microvolt = <1200000>;
    regulator-max-microvolt = <1200000>;
    gpio = <&tlmm 46 GPIO_ACTIVE_HIGH>;
    enable-active-high;
};

通过这一完整配置示例,开发者可参照实际模组参数调整 Sensor 地址、电源控制、MIPI 参数以及连接路径,快速完成在高通平台上的 IMX586 摄像头适配与驱动加载。

原文:https://zhxin.blog.csdn.net/article/details/149310138