☰
Linux 内核 Rockchip Camera Interface(rkcif)驱动详解:从 PX30 VIP 到 RK3588 VICAP 的媒体控制器拓扑
2026/10/4 23:27:18 网站建设 项目流程

Linux 内核 Rockchip Camera Interface(rkcif)驱动详解:从 PX30 VIP 到 RK3588 VICAP 的媒体控制器拓扑

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

导读

Rockchip Camera Interface(CIF)是 Rockchip 众多 SoC 中负责接收摄像头图像数据的硬件单元,它以多种变体存在于 PX30、RK3568、RK3588 等芯片中。本文以内核文档 Documentation/admin-guide/media/rkcif.rst 为核心,结合 drivers/media/platform/rockchip/rkcif 目录下的实际驱动源码,系统讲解 CIF 的通用构建块(DVP/MIPI CSI-2/CROP/DMA 等)、三个典型硬件变体(PX30 VIP、RK3568 VICAP、RK3588 VICAP)在媒体控制器(media controller)架构下呈现的 V4L2 subdevice 与 video device 拓扑,以及驱动内部对 ping-pong 双缓冲、虚拟通道(VC)多流等机制的实现。读完本文,你将能够看懂任意一块 Rockchip 开发板上rkcif-*设备节点的含义,并能依据设备树 compatible 与驱动 match data 定位到对应的硬件变体与源码实现。

CIF 是什么:一套由通用构建块组合出的硬件族

Rockchip CIF 并非单一 IP,而是"一系列功能模块的组合",不同 SoC 通过选取不同的构建块拼出不同能力的视频输入单元。根据 rkcif.rst 的 Introduction 章节,这些通用构建块包括:

  • INTERFACE 块:视频数据的入口,分为两种类型——
    • Digital Video Port(DVP):并行数据接口,可接收并行视频数据、BT.656、BT.1120 等协议;
    • MIPI CSI-2 receiver 接口块:接收 MIPI CSI-2 串行数据。
  • CROP 单元:对输入图像进行裁剪。
  • MIPI CSI-2 receiver(并非所有变体都有):文档特别指出,该单元在 Rockchip 文档中被称为MIPI CSI HOST;从硬件上讲它是独立的一块,但由于与 CIF 强耦合,因此一并纳入 CIF 的讨论范围。
  • MUX 单元(并非所有变体都有):将视频数据传递给图像信号处理器(ISP)。
  • SCALE 单元(并非所有变体都有):对图像进行缩放。
  • DMA 引擎:通过名为ping-pong mode的双缓冲机制,把视频数据传输到系统内存。
  • 每个 INTERFACE 块支持四条视频流(并非所有变体都有),例如用于承载 MIPI CSI-2 的多个Virtual Channel(VC)。

正是这些构建块的"组合"差异,形成了下文介绍的多个硬件变体。文档还点明了 CIF 的软件定位:这些变体统一由位于drivers/media/platform/rockchip/rkcif的、以媒体控制器(media controller)为中心的rkcif设备驱动来表示。这一"media controller centric"的定位,直接决定了内核中呈现出来的实体组织方式:每个 INTERFACE/CROP 块是一个 V4L2 subdevice,每个 DMA 引擎是一个 V4L2 video device,二者之间通过媒体链路(media link)连接。

硬件变体一:Rockchip PX30 Video Input Processor(VIP)

PX30 的 VIP 是最简单的变体,它只提供一个DVP 数字视频端口,可接收:

  • 并行视频数据(parallel video data)
  • BT.656

由于这两种协议本身不携带多条流(no multiple streams),因此 VIP 只配备一个 DMA 引擎,负责将输入视频数据搬运到系统内存。

对应的驱动表示(rkcif driver)同样简洁:

  • 一个V4L2 subdevice:DVP INTERFACE/CROP 块;
  • 一个V4L2 device:DVP DMA 引擎。

这一"一进一出"的极简拓扑,在源码中也有清晰对应。查看 rkcif-dev.c 中的平台匹配数据:

static const char *const px30_vip_clks[] = { "aclk", "hclk", "pclk", }; static const struct rkcif_match_data px30_vip_match_data = { .clks = px30_vip_clks, .clks_num = ARRAY_SIZE(px30_vip_clks), .dvp = &rkcif_px30_vip_dvp_match_data, };

PX30 VIP 需要aclk、hclk、pclk三路时钟,并且只注册了 DVP 部分(rkcif_px30_vip_dvp_match_data),没有 MIPI 相关数据——这与文档所述"仅有 DVP、无 MIPI CSI-2 receiver"完全吻合。该 match data 通过设备树 compatible 字符串"rockchip,px30-vip"绑定(见 rkcif-dev.c 的of_device_id表)。

硬件变体二:Rockchip RK3568 Video Capture(VICAP)

RK3568 VICAP 的能力明显增强:它同时具备DVP与MIPI CSI-2 receiver,二者可以独立接收视频数据。

接口能力:

  • DVP接受:并行视频数据、BT.656、BT.1120;
  • MIPI CSI-2 receiver:独立接收 MIPI CSI-2 数据。

由于BT.1120 协议可以携带多条流,RK3568 VICAP 的 DVP 配备了四个 DMA 引擎,可分别捕获不同的流;同理,其 MIPI CSI-2 receiver 也配备四个 DMA 引擎,用于处理不同的Virtual Channel(VC)。

驱动的设备表示如下:

  • V4L2 subdevice:
    • rkcif-dvp0:DVP 的 INTERFACE/CROP 块;
  • V4L2 video device:
    • rkcif-dvp0-id0:代表 RK3568 DVP 的第一个 DMA 引擎。

文档特别说明了一个值得注意的现状:DVP 上多流支持尚未实现——原因是"很难找到测试硬件"(hard to find test hardware)。因此目前rkcif-dvp0-id0仅代表 DVP 的第一个 DMA 引擎,其余三个 DMA 引擎尚未暴露为独立的 video device。

RK3568 VICAP 的完整拓扑见文档所附的 rkcif-rk3568-vicap.dot(Graphviz 图源码,被.. kernel-figure::指令渲染为内核文档中的拓扑图),其节点关系如下:

it6801 2-0048 (/dev/v4l-subdev1) ──port0──▶ rkcif-dvp0 (/dev/v4l-subdev0) │ port1 ▼ rkcif-dvp0-id0 (/dev/video0)

在该示例拓扑中,一颗it6801(HDMI 转并行/数字视频桥,挂在 I2C 地址 2-0048)作为视频源,其 port0 连接到rkcif-dvp0的 sink pad(port0),rkcif-dvp0的 source pad(port1)再连接到 DMA 引擎对应的 video devicerkcif-dvp0-id0(/dev/video0)。这也解释了为什么 DVP 多流暂未实现:示例中 DVP 只接了单一的视频源。

源码侧,RK3568 的匹配数据位于 rkcif-dev.c,其时钟为aclk、hclk、dclk、iclk四路,并且同时注册了 DVP 与 MIPI 两个子系统(rkcif_rk3568_vicap_dvp_match_data与rkcif_rk3568_vicap_mipi_match_data),对应的 compatible 字符串为"rockchip,rk3568-vicap"。

硬件变体三:Rockchip RK3588 Video Capture(VICAP)

RK3588 VICAP 是目前文档中能力最完整的变体:它包含一个DVP和六个可独立接收视频数据的 MIPI CSI-2 capture interface。

接口能力:

  • DVP接受:并行视频数据、BT.656、BT.1120;
  • 每个 MIPI CSI-2 receiver:独立接收数据。

多流能力:由于 BT.1120 可携带多条流,RK3588 VICAP 的 DVP 配备四个 DMA 引擎;同样地,每个 MIPI CSI-2 receiver 各配备四个 DMA 引擎,分别对应不同的 Virtual Channel(VC)。

驱动的设备表示如下:

  • V4L2 subdevice(共四个):
    • dw-mipi-csi2rx fdd30000.csi:连接到MIPI DPHY0的 MIPI CSI-2 receiver;
    • dw-mipi-csi2rx fdd50000.csi:连接到MIPI DPHY1的 MIPI CSI-2 receiver;
    • rkcif-mipi2:连接到 MIPI DPHY0 的 MIPI CSI-2 receiver 所对应的 INTERFACE/CROP 块;
    • rkcif-mipi4:连接到 MIPI DPHY1 的 MIPI CSI-2 receiver 所对应的 INTERFACE/CROP 块。
  • V4L2 video device(共八个):
    • rkcif-mipi2-id{0,1,2,3}:连接在rkcif-mipi2INTERFACE/CROP 块上的四个 DMA 引擎;
    • rkcif-mipi4-id{0,1,2,3}:连接在rkcif-mipi4INTERFACE/CROP 块上的四个 DMA 引擎。

从命名规律可以看出:rkcif-mipi2/rkcif-mipi4中的数字直接对应 rkcif-common.h 中的接口索引枚举RKCIF_MIPI1~RKCIF_MIPI6;而-id{0..3}对应同文件中的流索引枚举RKCIF_ID0~RKCIF_ID3(RKCIF_ID_MAX为 4,即每个接口最多四条流)。这些枚举贯穿整个驱动的注册与中断分发逻辑。

RK3588 的完整拓扑见文档所附的 rkcif-rk3588-vicap.dot,图中节点关系可概括为两条对称的 MIPI 通路:

imx415 3-001a (/dev/v4l-subdev4) ──▶ dw-mipi-csi2rx fdd30000.csi (/dev/v4l-subdev2) └─▶ rkcif-mipi2 (/dev/v4l-subdev0) ├─▶ rkcif-mipi2-id0 (/dev/video0) ├─▶ rkcif-mipi2-id1 (/dev/video1) ├─▶ rkcif-mipi2-id2 (/dev/video2) └─▶ rkcif-mipi2-id3 (/dev/video3) imx415 4-001a (/dev/v4l-subdev5) ──▶ dw-mipi-csi2rx fdd50000.csi (/dev/v4l-subdev3) └─▶ rkcif-mipi4 (/dev/v4l-subdev1) ├─▶ rkcif-mipi4-id0 (/dev/video4) ├─▶ rkcif-mipi4-id1 (/dev/video5) ├─▶ rkcif-mipi4-id2 (/dev/video6) └─▶ rkcif-mipi4-id3 (/dev/video7)

在 dot 源码中,rkcif-mipi2的 source pad(port1)到id0是实线(n00000007:port1 -> n0000000a),到id1/id2/id3是虚线(style=dashed),这表示在默认配置下只有id0对应的链路处于启用(enabled)状态,其余流需要通过媒体控制器 API 手动激活——这与"每条流对应一个 VC"的多流设计一致。

RK3588 的匹配数据见 rkcif-dev.c:时钟多达五路(aclk、hclk、dclk、iclk、iclk1),且match data 只包含 MIPI 部分(rkcif_rk3588_vicap_mipi_match_data),对应 compatible"rockchip,rk3588-vicap"。从数据结构看,六个 MIPI 接口的索引RKCIF_MIPI1~RKCIF_MIPI6与寄存器块偏移映射定义在rkcif_mipi_match_data的blocks[]数组中(见 rkcif-common.h)。

驱动实现纵深:从平台匹配到 ping-pong 双缓冲

模块构成与编译配置

rkcif 驱动由五个源文件组成(见 Makefile):

rockchip-cif-objs += rkcif-capture-dvp.o # DVP 捕获通路(DMA 引擎、中断) rockchip-cif-objs += rkcif-capture-mipi.o # MIPI 捕获通路(DMA 引擎、中断) rockchip-cif-objs += rkcif-dev.o # 平台驱动、probe、匹配数据、电源管理 rockchip-cif-objs += rkcif-interface.o # INTERFACE/CROP 块对应的 subdevice rockchip-cif-objs += rkcif-stream.o # 流管理(vb2、ping-pong、格式处理)

编译产物为内核模块rockchip-cif,由 Kconfig 中的CONFIG_VIDEO_ROCKCHIP_CIF控制(见 Kconfig)。该配置项为tristate,依赖VIDEO_DEV、V4L_PLATFORM_DRIVERS、PM && COMMON_CLK等,并会select MEDIA_CONTROLLER、VIDEOBUF2_DMA_CONTIG、V4L2_FWNODE、VIDEO_V4L2_SUBDEV_API——也就是说,只要启用 rkcif,媒体控制器(MC)与 V4L2 subdevice API 就会被自动拉入构建,这正呼应了文档"media controller centric"的定位。

平台驱动与设备树匹配

rkcif-dev.c 中的rkcif_probe()是理解整个驱动的入口,其关键流程为:

  1. 通过of_device_get_match_data()取得rkcif_match_data(区分 PX30/RK3568/RK3588 三个变体);
  2. devm_platform_ioremap_resource()映射寄存器基址,platform_get_irq()+devm_request_irq()注册中断,中断处理函数rkcif_isr()将中断同时分发给 DVP 与 MIPI 两个捕获通路(见 rkcif-dev.c);
  3. 按 match data 获取时钟(devm_clk_bulk_get)与复位控制(devm_reset_control_array_get_exclusive);
  4. 初始化并注册media_device与v4l2_device,随后rkcif_register()依次调用rkcif_dvp_register()与rkcif_mipi_register()——二者返回-ENODEV时被容忍,从而优雅支持"只有 DVP"(PX30)或"只有 MIPI"(RK3588)的变体;
  5. 通过v4l2_async_nf_*注册异步通知器,等待外部视频源(如 imx415、it6801)subdevice 完成异步绑定,rkcif_notifier_bound()中调用v4l2_create_fwnode_links_to_pad()建立从视频源到 INTERFACE sink pad 的媒体链路。

电源管理方面(rkcif-dev.c):runtime_suspend时会先reset_control_assert/deassert复位 CIF(注释明确指出该复位会同时复位 IOMMU,因此不能在 resume 阶段执行),再关闭时钟;runtime_resume则重新使能时钟。

INTERFACE/CROP 块:一个 V4L2 subdevice 的内部逻辑

每个 INTERFACE 块在驱动中对应一个rkcif_interface结构(见 rkcif-common.h),它内嵌struct v4l2_subdev sd、两个媒体 pad(sink/source,由rkcif_interface_pad_index枚举定义),并且持有streams[RKCIF_ID_MAX]数组——即最多四个rkcif_stream,正好对应文档所说的"每个 INTERFACE 块支持四条流"。

rkcif-interface.c 中的set_fmt回调体现了 CROP 块的核心行为:

  • source pad 上的格式永远与 sink pad 保持一致(if (format->pad == RKCIF_IF_PAD_SRC) return v4l2_subdev_get_fmt(...));
  • 设置 sink pad 格式后,驱动会把该格式传播(propagate)到 source pad;
  • 每次设置格式时,CROP 矩形被重置为全尺寸(crop->left/top = 0,width/height = sink 尺寸)。

而get_sel/set_sel回调(rkcif-interface.c)则实现了V4L2_SEL_TGT_CROP等目标的选择处理:CROP_DEFAULT与CROP_BOUNDS返回输入全尺寸,CROP返回当前裁剪矩形。这意味着用户可以通过 subdev 的 selection ioctl 在 INTERFACE 块内完成图像的裁剪配置。

流管理与 ping-pong 双缓冲

rkcif_stream(见 rkcif-common.h)是每个 video device 背后的核心结构,其中两个字段直接对应文档提到的 ping-pong 机制:

/* in ping-pong mode, two buffers can be provided to the HW */ struct rkcif_buffer *buffers[2]; int frame_idx; int frame_phase;

以及:

/* in case of no available buffer, HW can write to the dummy buffer */ struct rkcif_dummy_buffer dummy;

rkcif-stream.c 中的rkcif_stream_pingpong()是 ping-pong 模式的核心实现,其工作方式为:

  1. 中断到来时,处理当前frame_phase指向的 buffer:若非 dummy buffer,则调用rkcif_stream_complete_buffer()将其标记为VB2_BUF_STATE_DONE并递增frame_idx(帧序号);
  2. 从驱动内部队列driver_queue弹出下一个可用 buffer 填入当前 phase;若队列为空,则回退到 dummy buffer,并打印 "no buffer available, frame will be dropped"(该帧被丢弃,硬件继续写入不中断);
  3. 调用queue_buffer()把新 buffer 地址写入硬件寄存器;
  4. 翻转frame_phase = 1 - frame_phase,硬件在下一帧写入另一块 buffer。

这种"两块 buffer 交替 + dummy 兜底"的设计,保证了硬件 DMA 永远不会因用户态来不及提交 buffer 而写到非法地址——这是文档所述"double-buffering mechanism called ping-pong mode"的完整工程化实现。流启动时(rkcif_stream_start_streaming,rkcif-stream.c)会依次启动媒体管道(video_device_pipeline_start)、唤醒运行时 PM、初始化 buffers、调用各通路的start_streaming钩子,最后通过v4l2_subdev_enable_streams()按BIT_ULL(stream->id)掩码启用对应流。

流格式方面,rkcif-stream.c 定义了统一的尺寸约束:宽度与高度均限制在64 到 8192 像素之间(CIF_MIN_WIDTH/HEIGHT = 64、CIF_MAX_WIDTH/HEIGHT = 8192),CIF_REQ_BUFS_MIN为 1。缓冲管理使用videobuf2的dma-contig内存模型,并在rkcif_stream_prepare_buffer()中为非多平面(non-mplane)格式自动推导 Y/UV 平面地址。

如何在内核中启用与查看 rkcif

编译与加载

  • 在内核配置中启用CONFIG_VIDEO_ROCKCHIP_CIF(Device Drivers → Multimedia support → Media platform devices下),可编译为模块rockchip-cif(modprobe rockchip-cif加载)或编入内核;
  • 该驱动仅在ARCH_ROCKCHIP或开启COMPILE_TEST时参与构建,运行时依赖设备树节点中的 compatible 字符串完成匹配:"rockchip,px30-vip"、"rockchip,rk3568-vicap"、"rockchip,rk3588-vicap"(见 rkcif-dev.c)。

观察设备拓扑

驱动成功 probe 并完成异步绑定后,会在/dev下呈现与文档拓扑一一对应的节点(具体编号取决于系统已有设备,上述/dev/videoX编号来自 dot 图中的示例):

  • 每个 INTERFACE/CROP 块、每个 MIPI CSI-2 receiver 各对应一个/dev/v4l-subdevX;
  • 每个 DMA 引擎对应一个/dev/videoX。

由于驱动是媒体控制器中心的,各实体之间通过媒体链路连接(例如视频源 →dw-mipi-csi2rx→rkcif-mipi2→rkcif-mipi2-id0)。在多流变体(RK3568/RK3588)上,DVP 或 MIPI 的id1/id2/id3等额外流需要先建立并启用对应的媒体链路,再通过标准 V4L2 接口(如VIDIOC_STREAMON)启动采集;每条流可以承载一路独立的视频数据,例如 MIPI CSI-2 的不同 Virtual Channel。

结语

从只有一个 DVP 的 PX30 VIP,到"一个 DVP + 六个 MIPI CSI-2 接口、每个接口四条流"的 RK3588 VICAP,Rockchip CIF 家族展示了同一个rkcif驱动如何用"match data + 通用构建块"的方式优雅覆盖多种硬件组合。理解文档中给出的 subdevice/video device 命名规律(rkcif-<接口>-id<流号>),再结合 rkcif-common.h 中的枚举与 rkcif-stream.c 中的 ping-pong 实现,你就能在内核源码层面完整还原任意 Rockchip 视频采集链路的"数据从哪来、经谁裁剪、由哪个 DMA 引擎送往哪块内存"。

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询