【嵌入式linux学习_OV8858 bring up】L1_从Sensor到RK3588发生了什么

文章目录

  • [1. 背景](#1. 背景)
  • [2. 入门](#2. 入门)
    • [2.1 ov8858](#2.1 ov8858)
    • [2.2 通信协议](#2.2 通信协议)
    • [2.3 软件与驱动的角色](#2.3 软件与驱动的角色)
  • [3. 设备树和配置](#3. 设备树和配置)
    • [3.1 怎么完成各个链路的连接](#3.1 怎么完成各个链路的连接)
    • [3.2 整体配置](#3.2 整体配置)
      • [3.2.1 Sensor配置](#3.2.1 Sensor配置)
      • [3.2.2 MIPI/CIF 接收端](#3.2.2 MIPI/CIF 接收端)
      • [3.2.3 ISP 节点](#3.2.3 ISP 节点)
      • [3.2.4 总结](#3.2.4 总结)
  • [4. 总结](#4. 总结)
    • [4.1 理解硬件](#4.1 理解硬件)
    • [4.2 理解通信](#4.2 理解通信)
    • [4.3 理解数据流向与设备树配置](#4.3 理解数据流向与设备树配置)
    • [4.4 实践要点](#4.4 实践要点)

1. 背景

本文旨在记录ov8858在rk3588s的bring up,主要是设备树部分,重要的是理解从Sensor到RK3588发生了什么

推荐的blog:RK3588:MIPI底层驱动学习------入门第一篇(万字开篇!真正零基础!)_rk3588 mipi-CSDN博客

需要明确以下几点

  • 处理的对象是什么?
  • 它使用什么方式与外界沟通?
  • 以及我们如何控制它?

需要了解一下几点:

1.ov8858基本参数

2.mipi协议

3.图像如何从sensor到rk3588的链路(重要)

整个过程了解之后,就可以上手改设备树了;

2. 入门

2.1 ov8858

这是一个800万像素CMOS图像传感器,下面是一些比较重要的参数

参数类别 具体规格 备注与说明
最大帧率 30fps@(3264x2448) ;60fps@1080P (1920x1080);90fps@720P (1408x792) 支持高速视频录制,1080P@60fps和720P@90fps是其优势,且为EIS(电子防抖)留出了额外像素。
输出接口 MIPI CSI-2 (支持4通道) 移动设备主流的高速串行接口,传输RAW数据。
输出数据格式 10-bit RAW RGB 输出原始的拜耳数据,交由后端ISP进行图像处理。

2.2 通信协议

⭐️MIPI协议负责传输图像数据,IIC协议负责控制配置摄像头;图像信息通过编码成 MIPI信号 ,经过MIPI接口之后进入RK3588芯片

⭐️摄像头数据通过 MIPI 这根"水管" 传输。这根水管的物理规格D-PHY 定义,水在里面流动的规则CSI-2 定义。两者合作,才能把图像数据正确地从摄像头送到RK3588。

当OV8858以每秒30帧的速度生成800万像素的图像时,会产生巨大的数据量。如何将这些数据快速、稳定地从摄像头传输到RK3588这样的主处理器,是一个关键问题。MIPI协议就是为解决这个问题而生的。

定义:MIPI(移动行业处理器接口) 联盟是一个为移动设备(如智能手机)制定内部接口标准的组织。

目的:它旨在用更少的引脚(物理线路)、更低的功耗和更好的抗电磁干扰能力,来实现设备内部(如摄像头到处理器、处理器到显示屏)的高速数据传输。

MIPI联盟制定了多种接口规范,其中与摄像头和显示器最相关的是:

CSI (Camera Serial Interface) :相机串行接口,专门用于将图像数据从摄像头传输到处理器。

DSI (Display Serial Interface):显示器串行接口,专门用于将图像数据从处理器传输到显示屏。

OV8858摄像头作为图像输入设备,自然使用的是 MIPI CSI-2 协议。这里的"-2"代表其版本号。

2.2.1 控制通道:为什么MIPI系统中需要I2C?

我们已经知道,MIPI CSI-2是一条专为图像数据设计的高速、单向"数据通道"(数据从摄像头流向处理器)。但这引出了一个新的问题:处理器如何去配置和控制摄像头?

例如,处理器需要向摄像头发送指令,来完成以下操作:设置输出图像的分辨率;调整帧率,修改质量参数等工作;

MIPI CSI-2的高速数据线本身不承载这些控制指令。因此,系统需要一条独立的、双向的"控制通道"。

I2C协议 就是这个场景下的最佳选择:

双向通信:处理器可以通过I2C向摄像头写入配置数据,也可以从摄像头读取状态信息。

低速稳定:配置命令的发送频率不高,不需要很高的速度,I2C完全可以满足。

线路简单:I2C总线最少只需要两根线(SDA-数据线,SCL-时钟线),非常节省硬件资源。

🌿结论:在一个典型的摄像头系统中,MIPI CSI-2和I2C协同工作。MIPI CSI-2负责将庞大的图像数据从摄像头高速传输给处理器,而I2C则负责让处理器低速地发送控制命令给摄像头,两者各司其职,缺一不可。

逻辑线路:

复制代码
摄像头需要控制接口
    ↓
选择I2C标准
    ↓
RK3588有多个I2C控制器
    ↓
板子设计选择了I2C7
    ↓
设备树配置&i2c7

2.2.2 MIPI CSI-2硬件连接

MIPI 数据传输如何保证数据的准确性,每个数据线独立工作,对原始数据进行编码,时钟信息"隐藏"在数据流中,每根数据线独立工作,不需要严格的外部同步

一对时钟差分线,几对数据差分线

特性维度 传统并行接口 MIPI CSI-2 (串行接口)
信号数量 1根专用时钟线 + N根数据线 (多) 1对时钟差分线 + 最多4对数据差分线 (少)
同步方式 依靠外部统一时钟,所有数据线严格同步 每根数据线独立恢复时钟,不依赖外部同步
高速适应性 差,线长差导致同步失效 优,差分信号+独立时钟恢复,抗干扰强
数据编码 通常不编码或简单编码 8B/10B 编码,保证信号跳变和直流平衡
  1. 问题 :在每秒几亿次的跳变速度下,即使0.1毫米的线长差异,都会导致信号到达接收端的时间不同步。如果所有数据线都共用一个外部时钟,高速下会完全乱套。

    MIPI的方案每根数据线都独立工作 。接收端(RK3588)的硬件电路会从数据流本身的跳变中 ,利用锁相环(PLL) 技术,动态地提取出时钟信息,从而生成一个与该数据线完美同步的本地时钟。这就像每个乐手都自带了节拍器,并能根据音乐流实时调整,不再依赖指挥棒。

  2. 8B/10B编码的核心作用

    如何确保数据流本身能够提供足够多的时钟跳变信号?

    时钟恢复电路(PLL)需要信号有频繁的跳变 (0→1或1→0)才能"锁定"频率。但图像数据(如大片纯白或纯黑)会出现连续的"1"或"0",长串的无跳变信号会导致PLL失锁,无法恢复时钟。

2.2.3 RK3588 如何识别与处理 MIPI 信号

硬件基础:专用接收控制器

RK3588芯片内部集成了专门的硬件电路模块 ,称为 MIPI CSI-2 接收控制器 (或称 PHY控制器 )。这个控制器是专门为理解和处理MIPI CSI-2协议而设计的,它包含了:

  • D-PHY物理层接口 :负责与差分线进行物理层面的连接,处理模拟信号,并完成串行到并行(SerDes) 的转换,以及8B/10B解码
  • 协议逻辑层 :负责解析MIPI CSI-2协议的各种包(Packet) ,如短包(Short Packet,包含帧号、帧开始/结束标志)和长包(Long Packet,包含实际的图像数据)。它还负责虚拟通道(Virtual Channel)识别数据类型(Data Type)判断等高级协议功能。
【拓】为什么需要"串行→并行→串行"的转换

既然并行传输快,为什么MIPI不直接用并行线传输,还要这么麻烦地转换呢?

特性 并行传输 (Parallel) 串行传输 (Serial) 现代高速接口(如MIPI)的策略
线路数量 (如8根数据线) (如1对差分线) 外部传输用串行 (节省线材、简化连接器、抗干扰)
时钟同步 要求极高 (所有线必须精确对齐) 要求低 (按顺序接收即可) 内部处理用并行 (减少复杂度,提高效率)
速度上限 (线间干扰(crosstalk)和偏移(skew)严重) (单线理论速度快,干扰小) 串行解串后,用高速并行总线在芯片内部传输
抗干扰能力 (多线间易互相干扰) (差分信号抗干扰能力强) 差分串行线负责"最后的一公里"
典型应用 早期低速接口 (如老式并行ATA) 现代高速接口 (如USB, SATA, PCIe, MIPI) 结合两者优势

也就是说并行传输虽然快,但是时钟同步要求高,抗干扰能力较差;而串行传输虽然没有那么高的时钟要求,但是速度比较快,干扰小;

这是并行传输在高速下无法逾越的物理障碍。

  • 想象:8辆卡车同时从起点出发,希望同时到达终点。
  • 现实 :由于每条路(线路)的长度、材质、环境(温度)略有不同,每辆车的速度和到达时间不可能完全一致
  • 结果 :到了终点,车不再是并排到达,而是有的早,有的晚 ,乱成一团。接收端根本无法确定哪个是"第一位"的数据。这就是偏移。速度越快,这个问题越严重。
  • 解决方案:要么在每根线上加复杂的可调延迟电路(成本高),要么放弃并行,改用串行。

现代接口的智慧:外串内并

所以,像MIPI CSI-2、USB、PCIe这样的高速接口,采用了**"外串内并"**的混合策略:

  1. 外部(芯片之间) :使用高速差分串行传输。只占1-2对线,抗干扰,速度快,解决了偏移问题。
  2. 内部(芯片内部) :在接收芯片的PHY层(物理层),通过串并转换器(SerDes) 将高速串行流转换成低速并行数据 (例如8位、16位或32位宽),然后通过芯片内部高速并行总线传输给核心逻辑进行处理。

总结一下

  1. 摄像头内部:图像传感器产生的并行数据,首先通过串行器转换为高速串行差分信号,通过MIPI线缆发送。
  2. RK3588接收端:csi2_dcphy0 物理层模块的解串器(Deserializer)接收这个串行流。
  3. 关键转换:解串器内部的移位寄存器在恢复的时钟驱动下,逐位接收串行数据。每接收满8个(或更多,取决于总线宽度)比特,锁存器就"抓拍"一下,一次性输出8个(或更多)并行比特。
  4. 后续处理:这些并行数据通过RK3588芯片内部的并行总线,被高效地传输到图像信号处理器(ISP)或其他核心模块进行后续处理。
rk3588s的芯片有2个独立的MIPI D-PHY控制器

https://wiki.t-firefly.com/zh_CN/Core-3588J/usage_camera.html

RK3588/RK3588S平台支持两个DPHY硬件, 分别是 dphy0_hw/ dphy1_hw, 两个dphy硬件都可以工作在两个模式: full mode 和split mode, 其中 dphy0_hw 拆分为 csi2_dphy0/ csi2_dphy1/ csi2_dphy2 三个逻辑dphy(参见rk3588s.dtsi)。

Full Mode 用于单路 4-lane 高带宽摄像头。

Split Mode 用于双路 2-lane 中等带宽摄像头。

【拓】抽象到设备树
bash 复制代码
&csi2_dcphy0 {              // 引用第0号D-PHY控制器  解码信号,变成并行信号
    port@0 {               // 控制器的输入端口
        mipi_in_cam1: endpoint@1 {  // 输入端口的第1号通道
            reg = <1>;      // 对应硬件的通道1
            remote-endpoint = <&ov8858_out>;  // 物理连接到OV13855
            data-lanes = <1 2>;  // 使用物理lane1和lane2
        };
    };
};
  • csi2_dcphy0 ↔ 芯片内存地址0xFED90000的硬件寄存器组
  • endpoint@1 ↔ 该硬件的第1号接收通道
  • data-lanes = <1 2> ↔ 启用硬件的MIPI_RXD1和MIPI_RXD2引脚组
  • mipi_in_cam1:
    • RK3588第0号MIPI D-PHY控制器
    • 该控制器内部的第1号接收通道(cam1)
    • 对应芯片封装上的特定MIPI物理引脚组

关于是如何具体作用的,可以参考:RK3588:MIPI底层驱动学习------入门第一篇(万字开篇!真正零基础!)_rk3588 mipi-CSDN博客

2.2.4 数据流向:从线到内存的旅程

上面说到了D-PHY用于解析MIPI的数据,下面说一下整个的过程:

整个链路是:

bash 复制代码
OV8858 摄像头传感器
     │
     │  MIPI CSI-2 数据
     ↓
┌─────────────┐
│ MIPI D-PHY  │  ← 物理层硬件(串行接收)
└─────────────┘
     │
     │  CSI-2 协议
     ↓
┌─────────────┐
│ CSI2 Host   │  ← CSI2 接收器(协议解析)
└─────────────┘
     │
     ↓
┌─────────────┐
│  CIF        │  ← 摄像头接口控制器(数据捕获)
└─────────────┘
     │
     ↓
┌─────────────┐
│  RKCIF      │  ← Rockchip CIF 控制器(统一管理)
└─────────────┘
     │
     ↓
┌─────────────┐
│  SDITF      │  ← 数据转发桥接模块(跨域传输)
└─────────────┘
     │
     ↓
┌─────────────┐
│  RKISP      │  ← 图像信号处理器(色彩/曝光优化)
└─────────────┘
     │
     ↓
    /dev/video0  ← 用户空间访问节点

具体地:

模块 英文全称 中文 作用
CIF Camera Interface 摄像头接口 接收 MIPI 数据流
RKCIF Rockchip CIF Rockchip 摄像头接口 统一管理多个摄像头
SDITF Sensor Data Interface Transport Fabric 数据转发桥接 跨硬件域传输数据
RKISP Rockchip ISP 图像信号处理器 图像处理(锐化、降噪、色彩)

摄像头数据通过MIPI CSI-2接口最终进入RK3588的内存,并可以被CPU读取,大致流程如下:

在Rockchip的内核中,下面描述了从物理传感器到最终图像处理单元的数据流与控制流,每一层都有明确的职责:

1. Sensor 层

  • 实体:OV8858 图像传感器
  • 职责:将光信号转换为电信号,通过内部 ADC 输出 RAW Bayer 格式数据,并按照 I2C 配置输出符合 MIPI CSI-2 协议的串行差分信号
  • 设备树体现rk3588s-lubancat-4-csi.dtsi 中定义为 &i2c1 下的子节点 dcphy0_ov8858@36
    • reg = <0x36>:I2C 从机地址
    • clocks = <&ext_cam_24m_clk>:外部时钟源
    • pwdn-gpiosreset-gpios:电源和复位控制
    • dovdd-supplyavdd-supplydvdd-supply:数字、模拟、核心电压
    • port 子节点:通过 remote-endpoint 连接到 CSI2 Host

2. MIPI D-PHY(物理层)

  • 实体mipi_dcphy0mipi_dphy0
  • 职责:接收来自 Sensor 的 MIPI 串行差分信号,完成物理层的信号接收、串并转换(Serializer → Deserializer),输出并行数据给 CSI2 Host
  • 设备树体现rk3588s.dtsi 中定义
dts 复制代码
&mipi_dcphy0 {
    rockchip,grf = <&mipidphy0_grf>;
    rockchip,sys_grf = <&sys_grf>;
    resets = <&cru SRST_CSIPHY0>;
};

3. CSI2 Host(协议层)

  • 实体csi2_dcphy0csi2_dphy0
  • 职责:解析 CSI-2 协议数据包,提取有效图像数据,处理数据通道(lane)配置、帧同步、CRC 校验等
  • 设备树体现rk3588s-lubancat-4-csi.dtsi
dts 复制代码
&csi2_dcphy0 {
    port@0 {
        dcphy0_in_ov8858: endpoint@2 {
            reg = <2>;
            remote-endpoint = <&ov8858_dcphy0_out>;
            data-lanes = <1 2>;
        };
    };
};

4. CIF(Camera Interface,摄像头接口层)

  • 实体rkcif_mipi_lvds(CIF 控制器)
  • 职责:接收 CSI2 Host 的并行数据,进行帧同步、格式转换(RAW/YUV),将数据存入 DMA 缓冲区,是连接底层硬件接口和上层驱动框架的桥梁
  • 设备树体现rk3588s-lubancat-4-csi.dtsi
dts 复制代码
&rkcif_mipi_lvds {
    port {
        cif_mipi_in0: endpoint {
            remote-endpoint = <&mipi0_csi2_output>;
        };
    };
};

5. RKCIF(Rockchip Camera Interface Framework,管理层)

  • 实体rkcif + rkcif_mmu
  • 职责:统一管理多个 CIF 硬件资源,处理时钟、中断、DMA 通道调度,提供统一的 API 给上层 ISP 或用户空间应用程序
  • 设备树体现
dts 复制代码
&rkcif {
    status = "okay";
    power-domains = <&power RK3588_PD_VI>;
    iommus = <&rkcif_mmu>;
};
&rkcif_mmu {
    status = "okay";
};

6. SDITF(Sensor Data Interface Transport Fabric,跨域桥接层)

  • 实体rkcif_mipi_lvds_sditf
  • 职责:RK3588 新增的跨域数据转发模块,负责将数据从 CIF 域(Camera Domain)传输到 ISP 域(Image Processing Domain)。由于 CIF 和 ISP 位于不同的硬件时钟域,需要 SDITF 进行跨域数据传输和同步
  • 设备树体现rk3588s-lubancat-4-csi.dtsi
dts 复制代码
&rkcif_mipi_lvds_sditf {
    port {
        mipi_lvds_sditf: endpoint {
            remote-endpoint = <&isp0_vir0>;
        };
    };
};

7. RKISP(Rockchip Image Signal Processor,处理层)

  • 实体rkisp0_vir0(ISP 虚拟通道)
  • 职责 :对 RAW Bayer 数据进行复杂的图像处理,包括:
    • 去马赛克(Demosaic / Bayer → RGB)
    • 自动白平衡(AWB)
    • 自动曝光(AE)
    • 自动对焦(AF)统计
    • 降噪(NR)、锐化(Sharpen)
    • 色彩校正(CCM)、Gamma 校正
    • 最终输出 YUV/RGB 图像给用户空间
  • 设备树体现
dts 复制代码
&rkisp0_vir0 {
    port {
        isp0_vir0: endpoint@0 {
            reg = <0>;
            remote-endpoint = <&mipi_lvds_sditf>;
        };
    };
};

完整链路图见下方 Mermaid 流程图:

bash 复制代码
ov8858@36 (i2c1)
    │
    │ ov8858_dcphy0_out (endpoint)
    ▼
csi2_dcphy0  //1. 从信号跳变中恢复时钟; 2. 将串行数据转换为并行数据; 3. 解码8B/10B编码
    │ dcphy0_in_ov8858 (endpoint@2)
    │ csidcphy0_out
    ▼
mipi0_csi2 //分类;把数据信息和控制信息分离
    │ mipi0_csi2_input / mipi0_csi2_output
    ▼
rkcif_mipi_lvds //MIPI CSI-2 原始数据采集
    │ cif_mipi_in0
    ▼
rkcif_mipi_lvds_sditf //数据传输中介,可路由到不同 ISP 通道
    │ mipi_lvds_sditf
    ▼
rkisp0_vir0  //isp处理(图像处理 )
    │ isp0_vir0
    ▼
→ /dev/video0 (用户空间)

2.3 软件与驱动的角色

硬件完成了最核心的物理和协议解析工作,但要让系统"用"起来,还需要软件(特别是驱动)的配合:

  • 设备树(Device Tree) :在Linux内核中,通过设备树文件(如你提到的 rk3588s-orangepi-5-camera2.dtsi描述硬件连接信息,告诉内核哪个MIPI控制器连接了哪个摄像头,其配置参数(如时钟频率、 lanes 数)是什么

  • V4L2 驱动框架

    内核中的

    • 接收器驱动负责初始化并管理RK3588内部的MIPI控制器硬件
    • 传感器驱动负责通过I2C总线配置OV13855的工作模式 (分辨率、帧率、曝光等),并处理来自摄像头的中断(如帧同步信号)。
  • 用户空间访问 :最终,用户空间的应用程序通过 V4L2 (Video for Linux 2) API请求和获取图像数据,驱动会准备好数据缓冲区,并通知应用有新的一帧数据可读。

3. 设备树和配置

对于lubancat-4-rk3588s,设备树位于:/kernel-stable-5.10-rk3588/arch/arm64/boot/dts/rockchip

3.1 怎么完成各个链路的连接

我们前面已经知道整个链路是怎么样的:

ov8858 传感器 → csi2_dcphy0 (硬件PHY) → mipi0_csi2 (CSI2控制器)

→ rkcif_mipi_lvds (Camera Interface) → rkcif_mipi_lvds_sditf (SDI TF)

→ rkisp0_vir0 (ISP 虚拟通道0)

bash 复制代码
┌─────────────────────────────────────────────────────────────────────┐
│  层级                 设备树节点                    作用              │
├─────────────────────────────────────────────────────────────────────┤
│                      ┌──────────────────┐                         │
│  Sensor              │ dcphy0_ov8858@36  │ 传感器节点 (I2C地址0x36) │
│                      └────────┬─────────┘                         │
│  endpoint            ┌────────▼─────────┐                         │
│  ───────────────▶  │ ov8858_dcphy0_out │ 传感器输出端              │
│                     └────────┬─────────┘                         │
│  port@0             ┌────────▼─────────┐                         │
│  ───────────────▶  │ dcphy0_in_ov8858 │ CSI2 输入端 (reg=2)      │
│                     └────────┬─────────┘                         │
│  port@1             ┌────────▼─────────┐                         │
│  ───────────────▶  │ csidcphy0_out     │ CSI2 输出端              │
│                     └────────┬─────────┘                         │
│  port@0             ┌────────▼─────────┐                         │
│  ───────────────▶  │ mipi0_csi2_input  │ MIPI CSI2 输入端         │
│                     └────────┬─────────┘                         │
│  port@1             ┌────────▼─────────┐                         │
│  ───────────────▶  │ mipi0_csi2_output│ MIPI CSI2 输出端        │
│                     └────────┬─────────┘                         │
│                      ┌────────▼─────────┐                         │
│                      │ cif_mipi_in0    │ CIF 输入端              │
│                      └────────┬─────────┘                         │
│                      ┌────────▼─────────┐                         │
│                      │ mipi_lvds_sditf  │ SDITF 转发              │
│                      └────────┬─────────┘                         │
│                      ┌────────▼─────────┐                         │
│                      │ isp0_vir0        │ ISP 虚拟通道0           │
│                      └────────┬─────────┘                         │
│                               ▼                                   │
│                     /dev/video0  ←───  用户空间可访问               │
└─────────────────────────────────────────────────────────────────────┘

下面我们通过 port和endpoint,把这些模块都连接起来

bash 复制代码
设备树结构                    实际硬件连接
─────────────────────────────────────────────────
┌──────────────────┐        ┌─────────────────┐
│   ov8858          │        │   OV8858 摄像头  │
│   ┌────────────┐  │        │   ┌──────────┐  │
│   │  port      │  │        │   │ MIPI OUT  │──┼──┐
│   │  ┌──────┐  │  │        │   └──────────┘  │  │
│   │  │endpoint│  │  │        │                 │  │
│   └──┴──────┴──┘  │        └─────────────────┘  │
└──────────────────┘                             │
                                                  ▼
                        ┌─────────────────────────────────────────┐
                        │              CSI2 D-PHY                 │
                        │  ┌───────────────┐  ┌───────────────┐  │
                        │  │  port@0       │  │  port@1       │  │
                        │  │  ┌─────────┐  │  │               │  │
                        │  │  │endpoint │◀┼──│               │  │
                        │  │  └─────────┘  │  │               │  │
                        │  └───────────────┘  └───────────────┘  │
                        └───────────────────────────────────────┘

具体的

port:代表一个硬件模块的数据接口(可以是输入或输出)

endpoint:代表port上的具体连接点

bash 复制代码
/ {
    /* 传感器 */
    sensor: ov8858@36 {
        port {
            sensor_out: endpoint {
                remote-endpoint = <&csi_in>;  /* 连接 CSI */
                data-lanes = <1 2>;           /* 2 lane */
            };
        };
    };

    /* CSI2 控制器 - 有两个 port */
    csi2: csi2@xxx {
        ports {
            /* Port 0: 接收端 */
            port@0 {
                csi_in: endpoint {
                    remote-endpoint = <&sensor_out>;  /* 接收来自传感器 */
                    data-lanes = <1 2>;
                };
            };
            
            /* Port 1: 输出端 */
            port@1 {
                csi_out: endpoint {
                    remote-endpoint = <&cif_in>;  /* 连接到 CIF */
                };
            };
        };
    };

    /* CIF 控制器 */
    cif: cif@xxx {
        port {
            cif_in: endpoint {
                remote-endpoint = <&csi_out>;  /* 接收来自 CSI2 */
            };
        };
    };
};

remote-endpoint:双向引用,endpointA.remote-endpoint = <&endpointB> 意味着 endpointB.remote-endpoint = <&endpointA>

reg 属性:区分同一 port 下的多个 endpoint(如 CSI2 支持多个传感器输入)

data-lanes:描述 MIPI 通道配置

3.2 整体配置

下面来看一下整个设备树的配置

以鲁班猫5为例:

整个设备树的层级为

bash 复制代码
rk3588-lubancat-5.dts (主设备树)
    └── include rk3588-lubancat-5-csi.dtsi (CSI接口配置)
            └── include rk3588-lubancat-cam.dtsi (通用摄像头资源)
    └── include rk3588-lubancat-5-cam0.dtsi (CAM0 默认配置)

3.2.1 Sensor配置

这段代码完整地描述了一个硬件:"我是一颗挂在 I2C 上的 OV8858,地址 0x36,需要 24M 时钟和三路供电,用 GPIO1_A3 和 A4 控制休眠复位,画面装反了要转180度,我带对焦马达,我通过 2 根 MIPI 数据线把画面发给 DCPHY0"

bash 复制代码
dcphy0_ov8858: dcphy0-ov8858@36 {
    compatible = "ovti,ov8858";           // 驱动匹配
    status = "disabled";                   // 默认禁用
    reg = <0x36>;                          // I2C 从机地址
    
    clocks = <&ext_cam_24m_clk>;   // 外部时钟 24MHz; 时钟来源于CRU的第4路MIPI相机时钟
    clock-names = "xvclk";         //时钟起个名字叫 "xvclk",驱动代码会通过这个来获取时钟
    
    // 电源配置
    dovdd-supply = <&cam_dovdd>;           // 1.8V
    avdd-supply  = <&cam_avdd>;            // 2.8V  
    dvdd-supply  = <&cam_dvdd>;            // 1.2V
    
    // GPIO 控制
    pwdn-gpios   = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>;
    reset-gpios  = <&gpio4 RK_PB1 GPIO_ACTIVE_HIGH>;
    
    // 摄像头模块信息
    rockchip,camera-module-index = <0>;//摄像头编号(0 通常是主摄后摄)
    rockchip,camera-module-facing = "back";//"back" 表示后置摄像头,"front" 表示前置
    rockchip,camera-module-name = "HS5885-BNSM1018-V01";//iq文件
    lens-focus = <&dcphy0_dw9714>;        // 镜头名称 对焦马达用 
    //说明这个摄像头模组带有自动对焦功能,且使用的马达驱动芯片是 DW9714,该芯片也挂载在 I2C 上
    
    port {
        ov8858_dcphy0_out: endpoint {
            remote-endpoint = <&dcphy0_in_ov8858>;//双向绑定,告诉内核这个输出端连到了 DCPHY0 的输入端。对应的,在 csi2_dphy0 节点里肯定有一个叫 dcphy0_in_ov8858 的端点回指过来
            clock-lanes = <0>; //Lane 0 默认作为时钟通道
            data-lanes = <1 2>; //表示使用 2 Lane 传输数据
        };
    };
};

0.关于设备树配置:

dcphy0_ov8858:这是节点的标签。设备树其他地方可以通过 &dcphy0_ov8858 来引用这个节点,方便后续修改状态或追加属性。

dcphy0-ov8858:节点的名称。通常格式是 设备名@地址,这里表明这是连接在 DCPHY0 上的 OV8858。

@36:表示该设备在 I2C 总线上的从机地址为 0x36(OV8858 的标准 I2C 地址,有些模组如果 ADDR 引脚拉高会是 0x10)

**1.关于时钟:**摄像头需要时钟 → RK3588s 的 CRU 产生时钟 → 时钟通过复用的 GPIO 引脚输出 → 设备树描述时钟来源和引脚功能切换。

【拓】 CRU

简单说:CRU就是芯片内部管理"什么时候给什么时钟"的控制器,它根据设备树配置决定哪些时钟开启、频率多少、输出到哪个引脚

CRU (Clock Reset Unit) 是Rockchip芯片内置的时钟和复位控制单元

①时钟生成

CRU内部有PLL(锁相环),可以将24MHz晶振输入倍频到各种工作频率

摄像头相关的典型输出:24MHz、480MHz(MIPI CSI时钟)等

②引脚复用 (IOMUX)

将内部时钟信号通过GPIO引脚输出到芯片外部

在设备树中体现为rockchip,pins配置

③在OV8858设备树中的体现

&cru {

assigned-clocks = <&cru PLL_GPLL>, <&cru PLL_VPLL>;

assigned-clock-rates = <1188000000>, <700000000>;

};

外部24MHz晶振 → RK3588 CRU → IOMUX复用 → GPIO引脚 → 摄像头XVCLK

2.关于电源:

OV13855 自身需要多个电压(如数字 1.8V、模拟 1.2V、I/O 2.8V)才能工作。

为了极致省电,当不使用摄像头时,不仅是摄像头芯片,甚至 RK3588 内部处理视频信号的相关模块(如 MIPI、ISP)都应该被完全断电。

3.2.2 MIPI/CIF 接收端

bash 复制代码
&mipi_dcphy0 {
    status = "disabled";
};

&csi2_dcphy0 {
    status = "disabled";

    ports {
        port@0 {
            dcphy0_in_ov8858: endpoint@2 {
                reg = <2>;
                remote-endpoint = <&ov8858_dcphy0_out>;
                data-lanes = <1 2>;
            };
            dcphy0_in_imx415: endpoint@4 {
                reg = <4>;
                remote-endpoint = <&imx415_dcphy0_out>;
                data-lanes = <1 2 3 4>;
            };
        };

        port@1 {
            csidcphy0_out: endpoint@0 {
                reg = <0>;
                remote-endpoint = <&mipi0_csi2_input>;
            };
        };
    };
};

&mipi0_csi2 {
    status = "disabled";

    ports {
        port@0 {
            mipi0_csi2_input: endpoint@1 {
                reg = <1>;
                remote-endpoint = <&csidcphy0_out>;
            };
        };
        port@1 {
            mipi0_csi2_output: endpoint@0 {
                reg = <0>;
                remote-endpoint = <&cif_mipi_in0>;
            };
        };
    };
};

3.2.3 ISP 节点

bash 复制代码
&rkcif_mipi_lvds {
    status = "disabled";

    port {
        cif_mipi_in0: endpoint {
            remote-endpoint = <&mipi0_csi2_output>;
        };
    };
};

&rkcif_mipi_lvds_sditf {
    status = "disabled";

    port {
        mipi_lvds_sditf: endpoint {
            remote-endpoint = <&isp0_vir0>;
        };
    };
};

&rkisp0_vir0 {
    status = "disabled";

    port {
        isp0_vir0: endpoint@0 {
            reg = <0>;
            remote-endpoint = <&mipi_lvds_sditf>;
        };
    };
};

3.2.4 总结

涉及文件

层级 文件 作用
1 rk3588s-lubancat-4.dts 主入口,包含所有其他文件
2 rk3588s-lubancat-4-csi.dtsi CSI接口和传感器节点定义
3 rk3588-lubancat-cam.dtsi 通用电源和时钟
4 rk3588s.dtsi 芯片级硬件定义
4 rk3588s-pinctrl.dtsi 引脚复用配置
5 *overlay.dts 动态启用设备(可选)

主要流程

bash 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 1: 主设备树文件                                                  │
│  /rk3588s-lubancat-4.dts                                              │
│  ├── #include "rk3588s.dtsi"          ← 芯片级定义                     │
│  ├── #include "rk3588-linux.dtsi"     ← Linux通用配置                   │
│  ├── #include "rk3588s-lubancat-4-csi.dtsi"  ← CSI接口定义              │
│  └── #include "rk3588s-lubancat-4-cam0.dtsi"  ← CAM0默认配置           │
│                                          ↓                              │
│                              (可能通过overlay覆盖)                       │
└─────────────────────────────────────────────────────────────────────────┘
                                         ↓
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 2: CSI接口定义                                                   │
│  /rk3588s-lubancat-4-csi.dtsi                                         │
│  ├── #include "rk3588-lubancat-cam.dtsi"   ← 通用摄像头资源             │
│  │                                                                  │
│  ├── &i2c1 { ... }              ← DCPHY0 传感器定义                   │
│  │   ├── dcphy0_dw9714          ← 对焦马达                           │
│  │   ├── dcphy0_ov8858          ← OV8858传感器 ← [主要配置]          │
│  │   └── dcphy0_ov5648 ...                                        │
│  │                                                                  │
│  ├── &i2c5 { ... }              ← DCPHY1 传感器定义                   │
│  ├── &i2c6 { ... }              ← DPHY0  传感器定义                   │
│  │                                                                  │
│  ├── &csi2_dcphy0 {...}          ← CSI2接收器(DCPHY0)                 │
│  ├── &csi2_dcphy1 {...}          ← CSI2接收器(DCPHY1)                 │
│  ├── &csi2_dphy0_hw {...}        ← CSI2接收器(DPHY0硬件)              │
│  │                                                                  │
│  ├── &mipi0_csi2 {...}           ← MIPI CSI2接口                     │
│  ├── &mipi1_csi2 {...}           ← MIPI CSI2接口                     │
│  ├── &mipi2_csi2 {...}           ← MIPI CSI2接口                     │
│  │                                                                  │
│  ├── &rkcif {...}                ← CIF控制器                         │
│  ├── &rkcif_mipi_lvds {...}      ← CIF MIPI接口                      │
│  ├── &rkcif_mipi_lvds_sditf {...}← SDITF桥接                        │
│  │                                                                  │
│  ├── &rkisp0 {...}               ← ISP0控制器                        │
│  └── &rkisp0_vir0 {...}          ← ISP0虚拟接口                      │
└─────────────────────────────────────────────────────────────────────────┘
                                         ↓
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 3: 通用资源定义                                                  │
│  /rk3588-lubancat-cam.dtsi                                            │
│  ├── ext_cam_24m_clk          ← 24MHz外部时钟源                        │
│  ├── ext_cam_25m_clk          ← 25MHz外部时钟源                        │
│  ├── ext_cam_37m_clk          ← 37MHz外部时钟源                        │
│  ├── vdd_cam_5v               ← 摄像头5V电源                           │
│  ├── cam_dovdd                ← 1.8V数字电源                           │
│  ├── cam_avdd                 ← 2.8V模拟电源                           │
│  └── cam_dvdd                 ← 1.2V核心电源                           │
└─────────────────────────────────────────────────────────────────────────┘
                                         ↓
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 4: 芯片级定义                                                    │
│  /rk3588s.dtsi                                                        │
│  ├── &cru {...}                    ← 时钟和复位单元                      │
│  ├── &sys_grf {...}                ← 系统全局寄存器(地址0xFD58C000)     │
│  ├── &pmu {...}                    ← 电源管理单元                       │
│  ├── &mipi_dcphy0 {...}           ← DCPHY0物理层                      │
│  ├── &mipi_dcphy1 {...}           ← DCPHY1物理层                      │
│  └── &power {...}                  ← 电源域(RK3588_PD_VI)              │
│                                                                       │
│  /rk3588s-pinctrl.dtsi                                               │
│  ├── i2c1m2_xfer                 ← I2C1引脚复用                        │
│  ├── mipim0_camera0_clk          ← MIPI摄像头时钟输出引脚              │
│  └── ... (更多引脚配置)                                              │
└─────────────────────────────────────────────────────────────────────────┘
                                         ↓
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 5: Overlay覆盖层 (可选)                                          │
│  /overlay/rk3588s-lubancat-4-cam0-ov8858-1632x1224-30fps-overlay.dts  │
│                                                                       │
│  用途: 动态启用/禁用设备,无需修改主设备树                              │
│  ├── fragment@0: i2c1 status="okay"                                  │
│  ├── fragment@1: dcphy0_ov8858 status="okay"                         │
│  ├── fragment@2: csi2_dcphy0 status="okay"                           │
│  ├── fragment@3: mipi0_csi2 status="okay"                            │
│  ├── fragment@4: mipi_dcphy0 status="okay"                            │
│  └── fragment@5-12: 其他模块启用                                       │
└─────────────────────────────────────────────────────────────────────────┘
信号类型 源头 目的地 作用
时钟 CRU (24MHz) OV8858 xvclk 提供工作时钟
复位 GPIO1 PA4 OV8858 RESETB 复位/启动
休眠 GPIO1 PA3 OV8858 PWDN 开关机
I2C i2c1 OV8858 0x36 配置寄存器
数据 OV8858 MIPI CSI2 → CIF → ISP 图像数据

4. 总结

本文以 OV8858 + RK3588S 为实例,完整记录了从零开始完成一个 MIPI 摄像头 bring up 的全过程。回顾整个旅程,可以归纳为以下三个层次:

4.1 理解硬件

首先需要搞清楚「处理的对象是什么」------一颗 800 万像素的 OV8858 CMOS 图像传感器,它通过 MIPI CSI-2 接口输出 10-bit RAW 图像数据。理解它的基本参数(帧率、分辨率、数据格式)是后续一切工作的基础。

4.2 理解通信

接着要理解两条并行的通信通道:

  • MIPI CSI-2(数据通道):负责高速、单向地将海量图像数据从摄像头传输到处理器。它采用差分串行传输,通过 D-PHY 定义物理层、CSI-2 定义协议层,配合 8B/10B 编码和 PLL 时钟恢复机制,在极少的物理线路上实现了几 Gbps 的高速传输。
  • I2C(控制通道):负责低速、双向地让处理器配置摄像头的工作模式(分辨率、帧率、曝光等)。两者各司其职,缺一不可。

在此基础上,进一步理解了 RK3588 芯片内部的 MIPI CSI-2 接收控制器(D-PHY + 协议逻辑层)如何完成「串行→并行」的转换,以及「外串内并」策略为何是现代高速接口的共同选择。

4.3 理解数据流向与设备树配置

最后,梳理了从 OV8858 传感器到 RK3588 内存的完整数据链路:

Sensor → MIPI D-PHY → CSI2 → CIF → RKCIF → SDITF → RKISP → /dev/video0

核心模块:CIF(接收)+ RKCIF(控制)+ SDITF(桥接)+ RKISP(处理)

每一层都有明确的硬件实体和职责分工。而设备树正是通过 portendpoint 以及 remote-endpoint 属性,将这条链路上的各个模块「串联」起来,使得 Linux 内核在启动时能正确识别并初始化整个摄像头子系统。

4.4 实践要点

在实际操作中,以下几个要点值得特别关注:

  1. 设备树是桥梁 :硬件连接信息全部通过设备树描述,正确配置 remote-endpoint 的双向引用是关键。
  2. 电源与时钟不可忽视 :摄像头需要稳定的多路供电和外部时钟,设备树中的 *-supplyclocks 属性必须与实际硬件设计一致。
  3. 驱动框架的配合:V4L2 驱动框架统一了对上(用户空间)和对下(硬件)的接口,理解 Sensor 驱动和接收器驱动的分工有助于排查问题。
  4. 调试从简到繁:先确保 I2C 通信正常(能读到 Sensor ID),再检查 MIPI 时钟和数据 lane 的配置,最后验证 ISP 输出。
相关推荐
运维大师1 小时前
【K8S 运维实战】32-GitOps实践ArgoCD
运维·kubernetes·argocd
Darkwanderor1 小时前
使用管道实现进程间通信 (IPC, Inter-Process Communitation)
linux·c语言·c++
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(27):MemRefine——用 LLM 事实判断将长期记忆压缩到固定预算
论文阅读·人工智能·学习
Nuanyt2 小时前
Linux系统的 Shell 常见指令和常见知识点(以bash为主)
linux·运维·chrome·bash
程序员老陆2 小时前
FFmpeg 硬解在 Linux 上:从“能跑”到“跑满 GPU”的实战笔记
linux·笔记·ffmpeg
星恒随风2 小时前
Linux 权限详解:从 rwx、chmod 到 umask、目录权限与粘滞位
linux·运维·服务器·笔记·学习
拳里剑气2 小时前
Linux:进程间通信
linux·运维·数据库·进程
运维大师2 小时前
【K8S 运维实战】31-Helm包管理
运维·算法·kubernetes
lsh曙光2 小时前
防火墙-iptables
linux