当前位置: 首页 > news >正文

RK3588:MIPI底层驱动学习——入门第六篇(摄像头数据处理全流程、软件\硬件双视角分析)


引言

当我们打开摄像头、看到一张清晰的图像时,很少有人意识到它其实经历了无数次格式变换和硬件转接——从传感器吐出原始电信号,到屏幕显示彩色像素,这个过程比任何快递分拣系统都复杂得多。
为了更好的理顺ISP的章节内容,本章节将会再次梳理这个流程


第一部分:软件视角:物理信号到像素阵列 —— ISP前级数据流解析

本部分从数据流动的角度出发,讲解一帧原始图像如何经过层层协议封装和解析,最终准备好被ISP处理。

1.1 核心流程:从Sensor到ISP

一帧图像从摄像头传感器到应用程序,经历的完整硬件路径:

Camera Sensor输出:     模拟光强 → MIPI差分电压信号 (模拟)↓
D-PHY转换:            模拟差分信号 → 数字字节流 (数字)↓
MIPI CSI-2 Host解析:  字节流 → MIPI数据包 (协议层)↓
VICAP格式转换:        MIPI数据包 → RAW像素数组 (Bayer格式)↓
ISP图像处理:          RAW Bayer → YUV/RGB彩色图像↓
Memory存储:           YUV图像 → 内存Buffer地址↓
应用程序:             读取内存 → 显示/编码/分析

这个路径概括性比较强,但是你看完一遍大概率还是会忘记,或者理解不透彻。
因为对从Sensor数据格式到ISP输出的数据格式没有了解,这篇文章一次性讲透这个内容。

1.2 数据的四次“变身”

假设OV13855拍摄一张照片:4224×3136像素,RAW10格式。

这张照片要经历4次"变身"才能到达ISP:

变身1: 传感器输出 → 加上MIPI协议包装
变身2: MIPI包装 → D-PHY转成字节流  
变身3: 字节流 → CSI2-HOST解包还原结构
变身4: 结构化数据 → VICAP格式转换并存储
1.2.1 变身1:传感器的MIPI协议打包
1.2.1.1 传感器原始输出(没有协议)

传感器只是按顺序吐出像素值:

第1行: R G R G R G R G ... (4224个像素)
第2行: G B G B G B G B ... (4224个像素)
第3行: R G R G R G R G ...
...
第3136行

问题:接收方不知道:

  • 哪里是一行的开始?
  • 哪里是一行的结束?
  • 哪里是一帧的开始?
  • 数据是什么格式(RAW8?RAW10?YUV?)
1.2.1.2 MIPI CSI-2的解决方案:打包成"快递包裹"

MIPI协议把数据打包成一个个"包裹",每个包裹贴上"标签":

┌─────────────────────────────────────────────────┐
│               快递包裹结构                       │
├─────────────────────────────────────────────────┤
│                                                  │
│  📦 包裹1: [标签: 帧开始]                        │
│            内容: 无                              │
│                                                  │
│  📦 包裹2: [标签: 第1行开始]                     │
│            内容: 无                              │
│                                                  │
│  📦 包裹3: [标签: RAW10数据, 5280字节]           │
│            内容: [第1行4224个像素的数据]         │
│                                                  │
│  📦 包裹4: [标签: 第1行结束]                     │
│            内容: 无                              │
│                                                  │
│  📦 包裹5: [标签: 第2行开始]                     │
│                                                  │
│  📦 包裹6: [标签: RAW10数据, 5280字节]           │
│            内容: [第2行4224个像素的数据]         │
│                                                  │
│  📦 包裹7: [标签: 第2行结束]                     │
│                                                  │
│  ... (重复3136次)                                │
│                                                  │
│  📦 包裹N: [标签: 帧结束]                        │
│            内容: 无                              │
│                                                  │
└─────────────────────────────────────────────────┘
1.2.1.3 标签上写的内容(包头)

每个包裹的标签包含:

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃        包裹标签(4字节)        ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                               ┃
┃  📌 包裹类型编号:              ┃
┃     00 = 帧开始               ┃
┃     01 = 帧结束               ┃
┃     02 = 行开始               ┃
┃     03 = 行结束               ┃
┃     29 = RAW10像素数据        ┃
┃                               ┃
┃  📏 内容重量: 5280字节         ┃
┃                               ┃
┃  ✓ 防伪码: ECC校验             ┃
┃                               ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

关键理解:

  • 标记包(帧开始/行开始/行结束/帧结束):只有标签,没有内容
  • 数据包:既有标签,又有实际像素数据

1.2.2 变身2:D-PHY把包裹打碎成字节流
1.2.2.1 D-PHY的工作

D-PHY接收差分信号,转换成字节流。但它不认识包裹,只是盲目地输出字节:

摄像头通过4条Lane发送差分信号:
Lane0: +- +- -- ++ -- +- ... (电压波动)
Lane1: -- ++ +- -- ++ -- ...
Lane2: +- -- ++ -- +- ++ ...
Lane3: ++ -- +- ++ -- -- ...D-PHY转换成字节流:
↓
连续的字节流:
B8 00 00 00 A7 12 FF B8 02 00 00 C3 9E 44 B8 29 14 10 65 [5280个字节] 3A 7F B8 03 00 00 ...│                 │                 │                                      │
包裹1的标签       包裹2的标签       包裹3的标签+内容                    包裹4的标签

D-PHY输出的就是所有包裹的标签和内容按顺序拼在一起的字节流。

问题:接收方看到的是一长串字节,分不清哪里是标签,哪里是内容!


1.2.3 变身3:CSI2-HOST识别包裹边界
1.2.3.1 CSI2-HOST的第一个任务:找到包裹

CSI2-HOST像快递分拣员,从连续的字节流中识别出一个个包裹:

输入的字节流:
B8 00 00 00 A7 12 FF B8 02 00 00 C3 9E 44 B8 29 14 10 65 [数据] 3A 7F ...
↓
CSI2-HOST识别:找到分隔符 B8 → 这是包裹1的起始
├─ 读4字节: B8 00 00 00 → 标签内容
├─ 读1字节: A7 → 错误校验
├─ 读2字节: 12 FF → 完整性校验
└─ 包裹1识别完成 ✓找到下一个 B8 → 这是包裹2的起始  
├─ 读4字节: B8 02 00 00 → 标签内容
├─ ...
└─ 包裹2识别完成 ✓找到下一个 B8 → 这是包裹3的起始
├─ 读4字节: B8 29 14 10 → 标签(类型29=数据, 重量5280字节)
├─ 读5280字节: [像素数据]
├─ 读2字节: 3A 7F → 完整性校验
└─ 包裹3识别完成 ✓
1.2.3.2 CSI2-HOST的第二个任务:读取标签信息

CSI2-HOST读懂每个包裹的标签:

┌────────────────────────────────────────────────┐
│  包裹1的标签: B8 00 00 00                       │
│  ↓                                             │
│  解读结果:                                      │
│  ✓ 类型编号 00 → 这是"帧开始"信号              │
│  ✓ 内容重量 0  → 没有实际数据                  │
│  → 告诉VICAP: 新的一帧开始了!                 │
└────────────────────────────────────────────────┘┌────────────────────────────────────────────────┐
│  包裹2的标签: B8 02 00 00                       │
│  ↓                                             │
│  解读结果:                                      │
│  ✓ 类型编号 02 → 这是"行开始"信号              │
│  → 告诉VICAP: 新的一行开始了!                 │
└────────────────────────────────────────────────┘┌────────────────────────────────────────────────┐
│  包裹3的标签: B8 29 14 10                       │
│  ↓                                             │
│  解读结果:                                      │
│  ✓ 类型编号 29 → RAW10格式的像素数据           │
│  ✓ 内容重量 5280字节 → 后面跟着5280字节数据    │
│  → 告诉VICAP: 这是实际像素,快来接收!         │
└────────────────────────────────────────────────┘
1.2.3.3 CSI2-HOST的输出

CSI2-HOST输出结构化的信息给VICAP:

┌─────────────────────────────────────────────────┐
│  CSI2-HOST的输出(通过硬件信号线)               │
├─────────────────────────────────────────────────┤
│                                                  │
│  时刻1: [信号] 帧开始 (frame_start脉冲)          │
│                                                  │
│  时刻2: [信号] 行开始 (line_start脉冲)           │
│                                                  │
│  时刻3: [数据线] 像素数据开始传输                │
│         [标识] data_type = RAW10                │
│         ↓                                        │
│         像素0的值: 10bit                         │
│         像素1的值: 10bit                         │
│         像素2的值: 10bit                         │
│         ... (4224个像素)                         │
│                                                  │
│  时刻4: [信号] 行结束 (line_end脉冲)             │
│                                                  │
│  时刻5: [信号] 行开始 (新的一行)                 │
│  时刻6: [数据线] 第2行的像素数据...              │
│  时刻7: [信号] 行结束                            │
│                                                  │
│  ... (重复3136行)                                │
│                                                  │
│  时刻N: [信号] 帧结束 (frame_end脉冲)            │
│                                                  │
└─────────────────────────────────────────────────┘

CSI2-HOST做的总结:

  1. 从无序变有序: 字节流 → 识别出包裹边界
  2. 从标签到信号: 读标签内容 → 发出对应的控制信号(帧开始/行开始/数据/行结束/帧结束)
  3. 告知格式: 提取数据类型(RAW10)告诉下一级

1.2.4 变身4:VICAP格式转换和存储
1.2.4.1 VICAP接收到的数据

VICAP从CSI2-HOST接收:

┌─────────────────────────────────────┐
│  硬件信号线上传来:                   │
├─────────────────────────────────────┤
│                                      │
│  控制信号:                           │
│  ├─ frame_start (脉冲)               │
│  ├─ line_start (脉冲)                │
│  ├─ line_end (脉冲)                  │
│  └─ frame_end (脉冲)                 │
│                                      │
│  数据总线:                           │
│  ├─ pixel_data[31:0] (32位宽)       │
│  │   每个周期传输32bit数据           │
│  │                                  │
│  └─ data_type = RAW10               │
│                                      │
└─────────────────────────────────────┘

但有3个问题需要VICAP解决:

1.2.4.2 问题1:数据打包方式不对

CSI2-HOST发来的RAW10数据打包方式(MIPI规范):

每4个像素占5个字节,数据是"挤在一起"的:

4个像素的数据:
Pixel0 = 10bit值
Pixel1 = 10bit值  
Pixel2 = 10bit值
Pixel3 = 10bit值MIPI打包方式(省空间):
┌────────┬────────┬────────┬────────┬──────────────────┐
│ Byte0  │ Byte1  │ Byte2  │ Byte3  │     Byte4        │
├────────┼────────┼────────┼────────┼──────────────────┤
│ P0高8位│ P1高8位│ P2高8位│ P3高8位│ P3低2|P2低2|P1低2|P0低2 │
│ [9:2]  │ [9:2]  │ [9:2]  │ [9:2]  │ [1:0][1:0][1:0][1:0]│
└────────┴────────┴────────┴────────┴──────────────────┘↑ 8bit    ↑ 8bit            ↑ 最后一个字节塞了4个像素的低2位示例数据:
Byte0 = 0xA5 (像素0的bit[9:2])
Byte1 = 0x3C (像素1的bit[9:2])
Byte2 = 0x7F (像素2的bit[9:2])
Byte3 = 0x12 (像素3的bit[9:2])
Byte4 = 0xB4 = 10|11|01|00↑  ↑  ↑  ↑P3 P2 P1 P0的低2bit

但ISP需要的格式(方便处理):

每个像素单独占2个字节(16bit对齐):

16bit对齐方式:
┌──────────────┬──────────────┬──────────────┬──────────────┐
│   Pixel0     │   Pixel1     │   Pixel2     │   Pixel3     │
├──────────────┼──────────────┼──────────────┼──────────────┤
│ [15:10]=0    │ [15:10]=0    │ [15:10]=0    │ [15:10]=0    │
│ [9:0]=数据   │ [9:0]=数据   │ [9:0]=数据   │ [9:0]=数据   │
└──────────────┴──────────────┴──────────────┴──────────────┘2字节          2字节          2字节          2字节示例数据:
Pixel0 = 0x0297 (高6位补0, 低10位是实际数据)
Pixel1 = 0x00F1
Pixel2 = 0x01FF
Pixel3 = 0x004A

VICAP做格式转换:

输入(MIPI打包):
[A5][3C][7F][12][B4]  → 4个像素紧密打包, 5字节↓VICAP解包重组↓
输出(16bit对齐):
[02][97][00][F1][01][FF][00][4A]  → 4个像素分开对齐, 8字节
1.2.4.3 问题2:可能只需要部分区域

用户可能只要图像的一部分(ROI区域):

完整图像: 4224×3136
┌─────────────────────────────────────┐
│                                      │
│      只要这部分 ↓                    │
│      ┌──────────────┐                │
│      │   2000×1500  │  ← ROI区域    │
│      │              │                │
│      └──────────────┘                │
│                                      │
└─────────────────────────────────────┘VICAP裁剪(Crop):
- 丢弃前面的行
- 每行只保留中间2000个像素
- 丢弃后面的行最终输出: 2000×1500的图像
1.2.4.4 问题3:需要写入内存或直通ISP

VICAP提供两种路径:

路径A:回读模式(经过DDR内存)

VICAP的DMA引擎写入内存:
┌────────────────────────────────────────┐
│          DDR内存                        │
├────────────────────────────────────────┤
│                                         │
│  地址 0x10000000:                       │
│  ┌────────────────────────────────┐    │
│  │ 第1行: [P0][P1][P2]...[P4224] │    │
│  ├────────────────────────────────┤    │
│  │ 第2行: [P0][P1][P2]...[P4224] │    │
│  ├────────────────────────────────┤    │
│  │ ...                            │    │
│  ├────────────────────────────────┤    │
│  │ 第3136行: [P0][P1]...[P4224]  │    │
│  └────────────────────────────────┘    │
│                                         │
│  完整帧大小: 26.5 MB                    │
│                                         │
└────────────────────────────────────────┘↓ISP从内存读取处理

路径B:直通模式(不经过内存)

VICAP直接输出给ISP:┌───────────┐
VICAP ────→│ ISP硬件   │(实时)    │ 边收边处理 │└───────────┘优点: 延迟低,不占用内存带宽
缺点: 只能连一个摄像头到一个ISP

第二部分 物理接口到处理核心 —— RK3588视频通路硬件全解析

本部分深入RK3588芯片内部,逐一解析从物理接口(PHY)到图像处理核心(ISP)的各个硬件模块的资源、特性和配置方法。

2.1 物理层(PHY):数据接入的“端口”

2.1.1 RK3588的PHY硬件全景

RK3588芯片内部有4个PHY物理硬件模块:

┌─────────────────────────────────────────────┐
│  RK3588 PHY硬件布局                          │
├─────────────────────────────────────────────┤
│                                              │
│  DCPHY0硬件 (0xFEDC0000)  ← 高端硬件          │
│  ├─ RX: 支持D-PHY/C-PHY                      │
│  └─ TX: 支持D-PHY/C-PHY                      │
│                                              │
│  DCPHY1硬件 (0xFEDC8000)  ← 高端硬件          │
│  ├─ RX: 支持D-PHY/C-PHY                      │
│  └─ TX: 支持D-PHY/C-PHY                      │
│                                              │
│  ────────────────────────────────────       │
│                                              │
│  DPHY0硬件 (0xFEDC0000)   ← 普通硬件          │
│  └─ RX: 仅支持D-PHY                          │
│                                              │
│  DPHY1硬件 (0xFEDC8000)   ← 普通硬件          │
│  └─ RX: 仅支持D-PHY                          │
│                                              │
└─────────────────────────────────────────────┘

硬件定位:

  • DCPHY: 高端、灵活、双向、协议可切换
  • DPHY: 普通、单向、仅D-PHY协议
2.1.2 DCPHY硬件的核心特性
2.1.2.1 物理结构

DCPHY = Dual Combo PHY (双重组合物理层)

每个DCPHY硬件包含两套独立的收发电路:

┌──────────────────────────────────────────┐
│         DCPHY0硬件模块                    │
├──────────────────────────────────────────┤
│                                           │
│  RX接收电路 (用于Camera输入)               │
│  ┌────────────────────────────┐          │
│  │ Lane0 ─┐                   │          │
│  │ Lane1 ─┤  差分接收器        │          │
│  │ Lane2 ─┤  +                 │          │
│  │ Lane3 ─┘  协议解析器        │          │
│  │           (D-PHY/C-PHY)     │          │
│  └────────────────────────────┘          │
│                                           │
│  ─────────────────────────────           │
│                                           │
│  TX发送电路 (用于Display输出)              │
│  ┌────────────────────────────┐          │
│  │ Lane0 ─┐                   │          │
│  │ Lane1 ─┤  差分驱动器        │          │
│  │ Lane2 ─┤  +                 │          │
│  │ Lane3 ─┘  协议编码器        │          │
│  │           (D-PHY/C-PHY)     │          │
│  └────────────────────────────┘          │
│                                           │
│  全局配置寄存器:                          │
│  - 协议选择: D-PHY/C-PHY                  │
│  - Lane数量配置                           │
│  - 电气参数调整                           │
└──────────────────────────────────────────┘
2.1.2.2 协议切换机制

D-PHY协议 vs C-PHY协议的物理差异:

D-PHY (差分物理层):

物理连接: 每Lane使用1对差分线
Lane0: DP0+ / DP0-  ←差分对
Lane1: DP1+ / DP1-
Lane2: DP2+ / DP2-
Lane3: DP3+ / DP3-
时钟: CLK+ / CLK-   ←独立时钟线编码方式: 差分信号, 高低电平差值代表0/1
最大速率: 4.5Gbps/Lane (RK3588的DCPHY)
总Lane数: 4条数据Lane + 1条时钟Lane = 5条线对

C-PHY (三相物理层):

物理连接: 3根线组成1个Trio
Trio0: A / B / C  ←三根信号线
Trio1: A / B / C
Trio2: A / B / C编码方式: 三相信号, 通过3根线的电平组合传输数据
状态编码: 有6种有效状态 (+1/0/-1的组合)
最大速率: 2.5Gsps/Trio (symbol per second)
无需时钟线: 数据中内嵌时钟信息优势: 更少的物理线缆, 抗干扰能力强

硬件如何切换协议:

通过写入DCPHY的GRF寄存器来配置:

// 驱动代码示例 (简化)
// 文件: drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c// 配置为D-PHY模式
void dcphy_set_dphy_mode(struct dcphy *phy) {// 写入GRF寄存器regmap_write(phy->grf, DCPHY_GRF_CON0, DCPHY_MODE_DPHY | DCPHY_LANES_4);// 配置Lane数量和速率regmap_write(phy->grf, DCPHY_GRF_CON1,DCPHY_DATARATE_4500M);
}// 配置为C-PHY模式
void dcphy_set_cphy_mode(struct dcphy *phy) {// 写入GRF寄存器regmap_write(phy->grf, DCPHY_GRF_CON0,DCPHY_MODE_CPHY | DCPHY_TRIOS_3);// 配置Trio数量和速率regmap_write(phy->grf, DCPHY_GRF_CON1,DCPHY_SYMBOLRATE_2500M);
}

配置后硬件内部发生的变化:

D-PHY模式:
物理Pin → 差分接收器 → 时钟数据恢复 → 字节对齐 → 输出C-PHY模式:
物理Pin → 三相解码器 → 符号映射 → 字节转换 → 输出
2.1.2.3 RX/TX同时工作的限制

硬件约束:
虽然DCPHY有独立的RX和TX电路,但它们共享协议配置寄存器

限制规则:

允许: RX用D-PHY + TX用D-PHY  ✓
允许: RX用C-PHY + TX用C-PHY  ✓
禁止: RX用D-PHY + TX用C-PHY  ✗
禁止: RX用C-PHY + TX用D-PHY  ✗

原因:
协议切换会改变整个DCPHY模块的时钟域和电气参数,RX和TX必须使用相同的基础时钟。

典型应用场景:

场景1: Camera输入 + MIPI显示屏输出
┌────────────┐      ┌──────────┐      ┌────────────┐
│  Camera    │ MIPI │  DCPHY0  │ MIPI │  Display   │
│  (D-PHY)   ├─────→│  RX/TX   ├─────→│  Panel     │
│  4 Lane RX │      │  (D-PHY) │      │  4 Lane TX │
└────────────┘      └──────────┘      └────────────┘↑                                     ↑└──────── 两端都使用D-PHY协议 ─────────┘场景2: 工业相机 + C-PHY显示
┌────────────┐      ┌──────────┐      ┌────────────┐
│  Camera    │ MIPI │  DCPHY0  │ MIPI │  Display   │
│  (C-PHY)   ├─────→│  RX/TX   ├─────→│  Panel     │
│  3 Trio RX │      │  (C-PHY) │      │  3 Trio TX │
└────────────┘      └──────────┘      └────────────┘↑                                     ↑└──────── 两端都使用C-PHY协议 ─────────┘
2.1.3 DCPHY vs DPHY 对比
特性DCPHYDPHY
物理硬件2个 (dcphy0/1)2个 (dphy0/1)
寄存器地址0xFEDC0000 / 0xFEDC80000xFEDC0000 / 0xFEDC8000
支持协议D-PHY + C-PHY可切换仅D-PHY
最大速率D-PHY: 4.5Gbps/Lane
C-PHY: 2.5Gsps/Trio
D-PHY: 2.5Gbps/Lane
数据方向RX + TX双向仅RX单向
Split模式不支持支持 (Full/Split)
软件节点名csi2_dcphy0/1csi2_dphy0/1/2/3/4/5
典型应用高端摄像头 + 显示输出普通摄像头输入
驱动文件phy-rockchip-samsung-dcphy.cphy-rockchip-csi2-dphy.c
2.1.4 DPHY的Full Mode和Split Mode
2.1.4.1 硬件设计约束

DPHY硬件特点:

  • 每个DPHY硬件包含4条Lane的接收电路
  • 仅支持D-PHY协议
  • 仅有RX接收功能

物理结构:

┌─────────────────────────┐
│   DPHY0硬件 (0xFEDC0000) │
├─────────────────────────┤
│  Lane0接收电路           │
│  Lane1接收电路           │
│  Lane2接收电路           │
│  Lane3接收电路           │
│                          │
│  Lane路由选择器 ←────────┤ GRF配置寄存器
│  ├─ 全部4条 → CSI-2 Host │ 控制路由模式
│  └─ 拆分2+2 → 两个Host   │
└─────────────────────────┘
2.1.4.2 Full Mode (全模式)

使用场景:
一个摄像头需要全部4条Lane的带宽。

硬件连接:

┌──────────────┐         ┌─────────────┐         ┌───────────────┐
│  OV13855     │ 4 Lane  │  DPHY0硬件  │ 字节流  │ MIPI1_CSI2    │
│  Camera      ├────────→│  (Full)     ├────────→│ Host          │
│  4224x3136   │ MIPI    │  全部Lane   │         │ 协议解析      │
└──────────────┘         └─────────────┘         └───────────────┘软件节点名: csi2_dphy0 (表示dphy0_hw工作在Full模式)

寄存器配置:

// GRF寄存器配置Full Mode
regmap_write(grf, GRF_VI_CON0, DPHY0_MODE_FULL |    // 全部4条LaneDPHY0_ENABLE);       // 使能DPHY0
2.1.4.3 Split Mode (拆分模式)

使用场景:
两个低分辨率摄像头,每个使用2条Lane。

硬件连接:

┌─────────────┐  2 Lane  ┌──────────────────┐
│  Camera1    ├─────────→│  DPHY0硬件       │
│  1920x1080  │          │  Lane0/1 ────────┼─→ MIPI1_CSI2
└─────────────┘          │         ↓        ││    路由选择器    │
┌─────────────┐  2 Lane  │         ↓        │
│  Camera2    ├─────────→│  Lane2/3 ────────┼─→ MIPI2_CSI2
│  1920x1080  │          │                  │
└─────────────┘          └──────────────────┘软件节点名: 
- csi2_dphy1 (dphy0_hw的前半部分, Lane0/1)
- csi2_dphy2 (dphy0_hw的后半部分, Lane2/3)

寄存器配置:

// GRF寄存器配置Split Mode
regmap_write(grf, GRF_VI_CON0,DPHY0_MODE_SPLIT |      // 拆分为2+2DPHY0_SPLIT_LANE01 |    // Lane0/1 → CSI2_1DPHY0_SPLIT_LANE23 |    // Lane2/3 → CSI2_2DPHY0_ENABLE);
2.1.4.4 软件节点命名的逻辑

为什么Full模式叫dphy0,Split模式叫dphy1/dphy2?

驱动通过PHY的ID序号判断模式:

// 驱动代码逻辑 (简化)
// 文件: drivers/phy/rockchip/phy-rockchip-csi2-dphy.cif (phy_id == 0) {// ID=0 → Full模式, 使用全部4条Lanemode = DPHY_FULL_MODE;lane_count = 4;
} else if (phy_id == 1 || phy_id == 2) {// ID=1/2 → Split模式, 使用2条Lanemode = DPHY_SPLIT_MODE;lane_count = 2;if (phy_id == 1)lanes = LANE_0_1;  // 前半部分elselanes = LANE_2_3;  // 后半部分
}

完整映射表:

物理硬件工作模式软件节点名PHY IDLane分配连接CSI-2 Host
dphy0_hwFullcsi2_dphy000/1/2/3mipi1_csi2
dphy0_hwSplit前半csi2_dphy110/1mipi1_csi2
dphy0_hwSplit后半csi2_dphy222/3mipi2_csi2
dphy1_hwFullcsi2_dphy330/1/2/3mipi3_csi2
dphy1_hwSplit前半csi2_dphy440/1mipi4_csi2
dphy1_hwSplit后半csi2_dphy552/3mipi5_csi2
2.1.5 完整的PHY硬件拓扑

RK3588最多支持的摄像头配置:

方案1: 2个DCPHY + 4个DPHY(Split) = 6路摄像头
┌─────────┐
│ DCPHY0  │ → Camera1 (D-PHY 4Lane, 高端)
│ (4Lane) │
└─────────┘┌─────────┐
│ DCPHY1  │ → Camera2 (D-PHY 4Lane, 高端)
│ (4Lane) │
└─────────┘┌─────────┐
│ DPHY0   │ → Camera3 (2Lane, 普通)
│ Lane0/1 │
│ Lane2/3 │ → Camera4 (2Lane, 普通)
└─────────┘┌─────────┐
│ DPHY1   │ → Camera5 (2Lane, 普通)
│ Lane0/1 │
│ Lane2/3 │ → Camera6 (2Lane, 普通)
└─────────┘方案2: 2个DCPHY + 2个DPHY(Full) = 4路摄像头
┌─────────┐
│ DCPHY0  │ → Camera1 (C-PHY 3Trio, 工业级)
│ (3Trio) │
└─────────┘┌─────────┐
│ DCPHY1  │ → Camera2 (D-PHY 4Lane)
│ (4Lane) │
└─────────┘┌─────────┐
│ DPHY0   │ → Camera3 (D-PHY 4Lane)
│ (4Lane) │
└─────────┘┌─────────┐
│ DPHY1   │ → Camera4 (D-PHY 4Lane)
│ (4Lane) │
└─────────┘
2.1.6 设备树配置完整示例
2.1.6.1 DCPHY配置 (D-PHY模式)
// DCPHY物理硬件节点
&csi2_dcphy0_hw {status = "okay";
};// DCPHY软件节点 (D-PHY模式)
&csi2_dcphy0 {status = "okay";ports {#address-cells = <1>;#size-cells = <0>;// RX端口: 接收Camera数据port@0 {reg = <0>;dcphy0_in: endpoint {remote-endpoint = <&ov13855_out>;data-lanes = <1 2 3 4>;  // D-PHY 4 Lane};};// TX端口: 输出到CSI-2 Hostport@1 {reg = <1>;dcphy0_out: endpoint {remote-endpoint = <&mipi0_csi2_input>;};};};
};
2.1.6.2 DPHY Full Mode配置
// DPHY物理硬件节点
&csi2_dphy0_hw {status = "okay";
};// DPHY软件节点 (Full Mode)
&csi2_dphy0 {  // 注意: Full模式使用ID=0status = "okay";ports {port@0 {dphy0_in: endpoint {remote-endpoint = <&camera_4lane_out>;data-lanes = <1 2 3 4>;  // 全部4条Lane};};port@1 {dphy0_out: endpoint {remote-endpoint = <&mipi1_csi2_input>;};};};
};
2.1.6.3 DPHY Split Mode配置
// DPHY物理硬件节点
&csi2_dphy0_hw {status = "okay";
};// DPHY软件节点1 (Split前半)
&csi2_dphy1 {  // 注意: Split模式使用ID=1status = "okay";ports {port@0 {dphy1_in: endpoint {remote-endpoint = <&camera1_2lane_out>;data-lanes = <1 2>;  // 只用Lane 0/1};};port@1 {dphy1_out: endpoint {remote-endpoint = <&mipi1_csi2_input>;};};};
};// DPHY软件节点2 (Split后半)
&csi2_dphy2 {  // 注意: Split模式使用ID=2status = "okay";ports {port@0 {dphy2_in: endpoint {remote-endpoint = <&camera2_2lane_out>;data-lanes = <1 2>;  // 只用Lane 2/3};};port@1 {dphy2_out: endpoint {remote-endpoint = <&mipi2_csi2_input>;};};};
};
2.1.7 驱动文件路径与补充资料

DCPHY驱动:

  • 硬件层: drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c
  • 软件封装: drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
  • 设备树: arch/arm64/boot/dts/rockchip/rk3588s.dtsi

DPHY驱动:

  • 硬件层: drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c
  • 软件封装: drivers/phy/rockchip/phy-rockchip-csi2-dphy.c
  • 设备树: arch/arm64/boot/dts/rockchip/rk3588s.dtsi

补充:香橙派我用的是OV13855的CAM2接口
查询原理图发现接入的是D-PHY0节点

同时为了作为以后参考资料,我这里也记录一下其他的节点:


2.2 MIPI CSI-2 Host:协议解析核心

RK3588有6个MIPI CSI-2 Host硬件:

CSI-2 Host物理地址对应PHY
mipi0_csi20xFDD10000csi2_dcphy0
mipi1_csi20xFDD20000csi2_dphy1
mipi2_csi20xFDD30000csi2_dphy2
mipi3_csi20xFDD40000csi2_dphy3
mipi4_csi20xFDD50000csi2_dphy4
mipi5_csi20xFDD60000csi2_dphy5

2.3 VICAP:视频采集与格式转换

2.3.1 硬件唯一性与软件虚拟化

硬件现实:
RK3588只有1个VICAP物理硬件,寄存器地址0xFDCE0000

但需要支持7路输入:

  • 6路MIPI (来自6个CSI-2 Host)
  • 1路DVP并口

软件虚拟化方案:
将1个VICAP硬件虚拟成7个软件节点:

rkcif_mipi_lvds   (对应 mipi0_csi2)
rkcif_mipi_lvds1  (对应 mipi1_csi2)
rkcif_mipi_lvds2  (对应 mipi2_csi2)
rkcif_mipi_lvds3  (对应 mipi3_csi2)
rkcif_mipi_lvds4  (对应 mipi4_csi2)
rkcif_mipi_lvds5  (对应 mipi5_csi2)
rkcif_dvp         (对应 DVP接口)

虚拟化的实现:

  • 每个虚拟节点配置VICAP硬件的不同输入MUX选择
  • 通过寄存器切换数据源
  • 驱动代码中用ID标识不同的虚拟通道
2.3.2 SDITF:软件接口虚拟设备

每个rkcif_mipi_lvds对应一个sditf节点:

rkcif_mipi_lvds_sditf
rkcif_mipi_lvds1_sditf
...

sditf的作用:
指明VICAP与ISP之间的连接关系,是纯软件概念,不对应物理硬件。

2.3.3 驱动文件路径

设备树定义: arch/arm64/boot/dts/rockchip/rk3588s.dtsi
驱动代码:

  • drivers/media/platform/rockchip/cif/hw.c (VICAP硬件操作)
  • drivers/media/platform/rockchip/cif/dev.c (rkcif设备)
  • drivers/media/platform/rockchip/cif/subdev-itf.c (sditf设备)

2.4 ISP:图像信号处理核心

2.4.1 硬件组成

RK3588有2个独立的ISP硬件:

ISP寄存器基地址中断号电源域
ISP00xFDCB0000131,133,134PD27
ISP10xFDCC0000135,137,138PD28

每个ISP包含的硬件模块:

  • 输入控制模块(输入MUX)
  • 镜头阴影校正(LSC)硬件
  • 黑电平校正(BLC)硬件
  • 坏点校正(DPCC)硬件
  • 去噪模块(2DNR/3DNR)硬件
  • 色彩矫正矩阵(CCM)硬件
  • 伽马校正(Gamma)硬件
  • 锐化(Sharpening)硬件
  • HDR合成硬件
  • 统计数据提取硬件(AE/AWB/AF)
2.4.2 两条输出路径

每个ISP硬件内部有两条独立的数据输出通路:

Main Path (主路径):

  • 最大分辨率: 4416x3312
  • 用途: 拍照、录像等高质量输出
  • 支持格式: YUV/RAW/JPEG

Self Path (自路径):

  • 最大分辨率: 1920x1920
  • 用途: 预览、视频通话等实时场景
  • 支持格式: YUV/RGB

硬件实现:
两条路径共享前端ISP处理模块,在输出阶段分成两路,各自有独立的缩放器和输出DMA。

2.4.3 ISP虚拟化:为什么需要虚拟节点

硬件限制:
2个ISP硬件只能同时处理2路摄像头。

实际需求:
可能需要连接6个摄像头(6路MIPI)。

软件解决方案:时分复用

每个ISP硬件虚拟出多个ISP节点(rkisp0_vir0/vir1/vir2/vir3):

rkisp0_vir0  ┐
rkisp0_vir1  ├─→ 共用ISP0硬件 (时分复用)
rkisp0_vir2  ┘rkisp1_vir0  ┐
rkisp1_vir1  ├─→ 共用ISP1硬件 (时分复用)
rkisp1_vir2  ┘

时分复用的实现原理:

  1. 回读模式(ReadBack):

    • VICAP先将RAW数据写入DDR
    • ISP依次从DDR读取不同camera的数据处理
    • ISP0处理camera0 → camera1 → camera2
    • ISP1处理camera3 → camera4 → camera5
  2. 直通模式(Bypass):

    • VICAP直接将数据发给ISP,不经过DDR
    • 延迟最低,性能最好
    • 只支持一个虚拟节点

模式自动选择:

if (一个ISP只配置1个虚拟节点)→ 使用直通模式
else  → 使用回读模式
2.4.4 ISP Unite:双ISP联合模式

当单个ISP性能不足时,可以将两个ISP合并成一个超级ISP:

rkisp_unite节点:

  • 同时使用ISP0和ISP1的硬件资源
  • 最大支持48M像素处理(8064x6048@15fps)
  • 寄存器覆盖两个ISP的地址空间
2.4.5 驱动文件路径

设备树定义: arch/arm64/boot/dts/rockchip/rk3588s.dtsi
驱动代码:

  • drivers/media/platform/rockchip/isp/dev.c (ISP设备总入口)
  • drivers/media/platform/rockchip/isp/hw.c (ISP硬件操作)
  • drivers/media/platform/rockchip/isp/rkisp1.c (ISP子设备)
  • drivers/media/platform/rockchip/isp/capture.c (视频输出)
  • drivers/media/platform/rockchip/isp/isp_params.c (参数配置)
  • drivers/media/platform/rockchip/isp/isp_stats.c (统计数据)

2.5 ISP内部:图像处理算法模块

2.5.1 数据流经的硬件处理单元

RAW图像在ISP内部的处理顺序:

RAW输入 → BLC → DPCC → LSC → Bayer 2DNR → Bayer 3DNR → 
Debayer → CCM → Gamma → YUV 2DNR → Sharp → 输出↓统计数据提取(3A)
2.5.2 黑电平校正 (BLC - Black Level Correction)

硬件原理:
传感器即使不接收光线,也会输出一个非零的暗电流值。

BLC硬件功能:
从每个像素值减去一个固定偏移量。

寄存器地址: RKISP1_CIF_ISP_BLS_* (定义在drivers/media/platform/rockchip/isp1/regs.h)

驱动配置函数: rkisp1_bls_config() (文件isp_params.c)

// 为4个Bayer通道分别设置黑电平
writel(arg->fixed_val.r, base + RKISP1_CIF_ISP_BLS_A_FIXED);  // R通道
writel(arg->fixed_val.gr, base + RKISP1_CIF_ISP_BLS_B_FIXED); // Gr通道
writel(arg->fixed_val.gb, base + RKISP1_CIF_ISP_BLS_C_FIXED); // Gb通道  
writel(arg->fixed_val.b, base + RKISP1_CIF_ISP_BLS_D_FIXED);  // B通道
2.5.3 坏点校正 (DPCC - Defect Pixel Cluster Correction)

硬件原理:
传感器制造时存在物理缺陷,某些像素点永久损坏,输出值异常。

DPCC硬件功能:

  • 检测异常像素点(与周围像素值差异过大)
  • 用周围像素的平均值替代

两种模式:

  • 静态坏点表: 出厂时标定的固定坏点位置
  • 动态检测: 实时检测可能的坏点

寄存器地址: RKISP1_CIF_ISP_DPCC_*

驱动配置函数: rkisp1_dpcc_config() (文件isp_params.c)

2.5.4 镜头阴影校正 (LSC - Lens Shading Correction)

硬件原理:
镜头边缘的光线通量小于中心,导致图像四周发暗(称为"暗角")。

LSC硬件功能:

  • 将图像划分成17x17共289个区域
  • 每个区域有独立的增益系数
  • 中心区域增益=1.0,边缘区域增益>1.0

数据结构:
4个17x17的增益表(R/Gr/Gb/B四个通道)

寄存器地址: RKISP1_CIF_ISP_LSC_*

驱动配置函数: rkisp1_lsc_config() (文件isp_params.c)

// 将校正表写入ISP的SRAM
for (i = 0; i < 17; i++) {for (j = 0; j < 17; j++) {data = (r_data_tbl[i][j] << 12) | r_data_tbl[i][j+1];writel(data, base + RKISP1_CIF_ISP_LSC_R_TABLE_DATA);}
}
2.5.5 2D去噪 (2DNR - 2D Noise Reduction)

硬件原理:
传感器读取电路产生的随机噪声在空间上是孤立的。

2DNR硬件功能:
分析当前像素与周围像素的相似度,对差异小的区域进行空间滤波平滑。

Bayer 2DNR vs YUV 2DNR:

  • Bayer 2DNR: 在Debayer之前处理,保留原始信息
  • YUV 2DNR: 在Debayer之后处理,计算量更小
2.5.6 3D去噪 (3DNR - 3D Noise Reduction)

硬件原理:
噪声在时间维度上是随机的,但真实物体在连续帧之间是相关的。

3DNR硬件功能:

  • 比较当前帧与前一帧的对应像素
  • 对变化小的区域进行时间域滤波
  • 需要缓存前一帧数据

硬件实现:
ISP内部有专用的frame buffer存储参考帧。

2.5.7 3A统计数据提取

3A定义:

  • AE (Auto Exposure): 自动曝光
  • AWB (Auto White Balance): 自动白平衡
  • AF (Auto Focus): 自动对焦

硬件统计模块功能:

AE统计硬件:

  • 将图像分成25x25个窗口
  • 每个窗口计算亮度平均值和直方图
  • 输出数据供用户空间算法计算曝光参数

AWB统计硬件:

  • 将图像分成多个测光区域
  • 每个区域统计R/G/B三个通道的平均值
  • 识别可能是白色的区域

AF统计硬件:

  • 计算图像的高频成分(清晰度指标)
  • 输出锐度值供对焦算法使用

统计数据输出:
通过/dev/video18(ISP0)和/dev/video27(ISP1)输出给用户空间的rkaiq_3A_server进程。

寄存器地址: RKISP1_CIF_ISP_AWB_*RKISP1_CIF_ISP_AFM_*RKISP1_CIF_ISP_HIST_*

驱动读取函数: rkisp1_stats_isr() (文件isp_stats.c)


2.6 Pipeline概念:连接硬件的软件脉络

2.6.1 Pipeline的本质

Pipeline不是硬件,是软件的数据流管理机制。

定义:
从摄像头sensor到最终video设备节点的完整数据通路链条。

一条完整的Pipeline:

m01_b_ov13855 (sensor) → csi2_dphy0 (PHY)→ mipi2_csi2 (CSI-2 Host)→ rkcif_mipi_lvds2 (VICAP)→ rkcif_mipi_lvds2_sditf (虚拟接口)→ rkisp0_vir0 (ISP虚拟节点)→ video11 (mainpath输出)→ video12 (selfpath输出)
2.6.2 Pipeline的软件实现

文件路径: drivers/media/platform/rockchip/isp/dev.c

关键数据结构:

struct rkisp1_pipeline {struct v4l2_subdev *subdevs[RKISP1_MAX_PIPELINE];  // 子设备数组int num_subdevs;                                   // 子设备数量
};

Pipeline管理函数:

rkisp1_pipeline_open()   // 打开pipeline,启用所有子设备
rkisp1_pipeline_close()  // 关闭pipeline
rkisp1_pipeline_set_stream()  // 控制整条pipeline的数据流
2.6.3 Media Controller框架

Linux内核用Media Controller描述Pipeline:

查看命令:

media-ctl -d /dev/media0 --print-topology

输出示例:

- entity 1: m01_b_ov13855 (sensor)pad0: Source → csi2_dphy0:0- entity 2: csi2_dphy0 (PHY)pad0: Sink ← m01_b_ov13855:0pad1: Source → mipi2_csi2:0... (完整拓扑链路)

2.7 实践篇:驱动开发的重点文件

当你需要移植新的摄像头时,重点关注:

  1. 设备树配置 (你已完成)
    定义硬件连接关系

  2. sensor驱动 (如果官方没有)
    drivers/media/i2c/ov13855.c
    实现上电、寄存器配置、格式协商

  3. ISP参数调优 (图像质量优化)
    需要IQ工程师使用Rockchip的Tuner工具调整ISP参数文件

不需要修改的部分:

  • PHY驱动(rockchip已实现)
  • CSI-2驱动(rockchip已实现)
  • VICAP驱动(rockchip已实现)
  • ISP驱动(rockchip已实现)

2.8 总结:完整硬件拓扑图

┌──────────┐
│  Camera  │(OV13855)
│  Sensor  │
└────┬─────┘│ MIPI差分信号 (4 Lane)↓
┌────────────┐
│  D-PHY HW  │ csi2_dphy0 (物理层)
│ 0xFEDC0000 │ 差分→数字转换
└─────┬──────┘│ 字节流↓
┌──────────────┐
│ MIPI CSI-2   │ mipi2_csi2 (协议层)
│   Host       │ 0xFDD30000
│ 解包+错误检测│
└──────┬───────┘│ 结构化数据包↓
┌─────────────┐
│   VICAP     │ rkcif_mipi_lvds2 (唯一硬件)
│  0xFDCE0000 │ 格式转换
└──────┬──────┘│ RAW pixel数据├→ 直通模式 ─────────┐└→ 回读模式(DDR) ──┐ │↓ ↓┌──────────┐│ISP0 HW   │ rkisp0_vir0 (虚拟节点)│0xFDCB0000│ │图像处理  │└────┬─────┘├→ Main Path → video11 (高分辨率)└→ Self Path → video12 (低分辨率)├→ Stats → video18 (统计数据)└→ Params → video19 (参数输入)
http://www.dtcms.com/a/458859.html

相关文章:

  • 怎么建设像天猫的网站wordpress 关闭插件更新
  • 网站建设果麦科技wordpress 投资
  • 天猫建设网站的理由百度手机怎么刷排名多少钱
  • 深圳市富通建设工程有限公司网站房地产设计网站
  • 泰山派无 eMMC 版 + YOLO(Ultralytics)YOLO环境部署完整安装指南:解决 SD 卡空间浪费 + TMPDIR 永久配置
  • 2017网站建设趋势白城百度网站建设
  • 大网站建设辖网站建设
  • 营销型网站公司排名2022世界互联网峰会
  • 扁平化设计风格的网站外贸推广是做什么的
  • 为什么要做官方网站政务网站建设和技术维护制度
  • 网站建设服务器对比广州做包包的网站
  • 网站建设栏目提纲一个vps建两个网站怎么弄数据库
  • 找做网站怎么修改wordpress模板文件路径
  • 深圳网站做的好的公司哪家好文创产品设计作品案例欣赏
  • 昆明网站建设服务至上一个完整网站开发需要什么技术
  • 亚马逊做code的网站我买了一个域名怎么做网站
  • WSL 教程:使用 Systemd 配置服务自动启动(SSH frpc)
  • wordpress什么模块深圳优化网站排名软件
  • 读写INI文件源码(点击关注)
  • ps如何做网站轮播图网站开发通过什么途径接活
  • 如何选择网站开发公司鲜花网站建设的利息分析
  • 可做生物试卷的网站网站建设多少钱兴田德润放心
  • 做网站要有策划么江都微信网站建设
  • 网站模版 模板门户网站系统有哪些平台
  • 深圳建科技有限公司网站首页wordpress投稿页面
  • 南昌网站开发培训学校设计制作生态瓶
  • 合肥房产网站建设建设网站的申请信用卡
  • 鲁中网站wordpress+park主题
  • modbus tcp 跟 modbus rtu
  • NVMe高速传输之摆脱XDMA设计43:队列管理功能验证与分析1