Rockchip CIF驱动深度解析:从架构设计到电源计数补丁修复

电子说

1.4w人已加入

描述

 

 

在嵌入式 Linux 系统中,Rockchip CIFCamera Interface)驱动是摄像头硬件与上层应用的桥梁”—— 它不仅要实现设备初始化、格式协商、数据捕获等核心功能,还需保障运行稳定性。本文将从「驱动整体架构」入手,拆解核心文件功能与调用关系,再聚焦「Sensor 电源引用计数补丁」,详解如何通过补丁解决实际运行中的稳定性问题,为驱动开发与调试提供完整参考。

 

 

一、CIF 驱动整体架构:核心文件与功能拆解

 

Rockchip CIF 驱动位于drivers/media/platform/rockchip/cif/目录下,包含 5 个核心文件(dev.c/subdev-itf.c/subdev-itf.h/procfs.c/capture.c),各文件分工明确、协同工作,共同支撑摄像头的完整功能。

 

 

1. 核心文件功能总览

 

先通过一张脑图快速梳理各文件的核心定位:

 

 

Rockchip

2. 关键文件深度解析

 

1dev.c:设备管理总控

 

作为驱动的大脑dev.c负责初始化设备基础环境、管理全局状态,并提供用户可配置的属性接口。

 

 

核心工作

 

 

a.设备初始化:在rkcif_plat_init中初始化原子变量(如power_cntstreamoff_cnt)、互斥锁(stream_lock)、媒体管道(pipe),为设备运行打下基础。

 

 

b.sysfs 属性配置:实现compact_test(紧凑数据流模式)、is_use_dummybuf(虚拟缓冲区开关)等属性的读写函数,用户可通过/sys/class/video4linux/videoX/路径动态调整设备行为。

 

 

c.全局状态维护:通过rkcif_device_list链表管理所有 CIF 设备,rkcif_dev_mutex保证多设备操作的互斥性,避免并发冲突。

 

 

关键代码示例(设备初始化):

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
// drivers/media/platform/rockchip/cif/dev.cint rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int irq) {    // 初始化原子变量(电源、流关闭、传感器状态)    atomic_set(&cif_dev->power_cnt, 0);    atomic_set(&cif_dev->streamoff_cnt, 0);    atomic_set(&cif_dev->sensor_off, 1);    // 后续补丁新增:Sensor电源引用计数初始化    atomic_set(&cif_dev->sd_power_cnt, 0);        // 初始化媒体管道(open/close回调)    cif_dev->pipe.open = rkcif_pipeline_open;    cif_dev->pipe.close = rkcif_pipeline_close;    return 0;}

2subdev-itf.c:传感器交互桥梁

 

subdev-itf.c CIF 驱动与摄像头 Sensor 的直接交互接口,实现 V4L2 子设备协议,负责格式协商、电源控制、事件触发。

 

 

核心工作

 

 

a.格式协商:通过sditf_get_set_fmt Sensor 协商输入格式(分辨率、像素格式如 SBGGR8),并配置 CIF 内部数据流参数。

 

 

b.电源控制sditf_s_power函数触发 Sensor 电源开关,是后续补丁重点修复的调用路径之一。

 

 

c.事件管理:订阅 / 触发V4L2_EVENT_FRAME_SYNC(帧同步)、V4L2_EVENT_EXPOSURE(曝光)事件,确保数据捕获时序正确。

 

 

关键代码示例(电源控制接口):

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
// drivers/media/platform/rockchip/cif/subdev-itf.cstatic int sditf_s_power(struct v4l2_subdev *sd, int on) {    struct sditf_priv *priv = v4l2_subdev_to_sditf(sd);    struct rkcif_device *cif_dev = priv->cif_dev;    int ret = 0;    mutex_lock(&cif_dev->stream_lock);    if (on) {        pm_runtime_get_sync(cif_dev->dev);        // 后续补丁新增:调用统一电源管理函数        ret |= rkcif_sensor_set_power(&cif_dev->stream[0], on);    } else {        pm_runtime_put_sync(cif_dev->dev);        ret |= rkcif_sensor_set_power(&cif_dev->stream[0], on);    }    mutex_unlock(&cif_dev->stream_lock);    return ret;}

3capture.c:数据捕获执行核心

 

capture.c负责摄像头数据的实际捕获,包括流启动 / 停止、缓冲区处理、电源控制函数实现,是本次补丁修改的核心文件。

 

 

核心工作

 

 

a.流管理rkcif_do_start_stream启动数据捕获,rkcif_stream_init初始化流状态(如帧丢失计数frame_loss)。

 

 

b.电源控制函数rkcif_sensor_set_power Sensor 电源开关的实际实现,补丁通过修改该函数引入引用计数逻辑。

 

 

c.文件操作rkcif_fh_open/rkcif_fh_release处理用户空间的设备打开 / 关闭请求,控制电源开关的调用时机。

 

 

4procfs.c:调试信息出口

 

procfs.c通过/proc/driver/rkcif节点向用户空间暴露驱动运行状态,便于调试定位问题。

 

 

核心工作

 

 

a.格式转换rkcif_pixelcode_to_string将媒体总线格式代码(如MEDIA_BUS_FMT_SBGGR8_1X8)转换为可读字符串("SBGGR8")。

 

 

b.信息输出rkcif_show_clks输出时钟频率、rkcif_show_format输出当前捕获格式,帮助开发者确认设备配置是否正确。

 

 

5subdev-itf.h:数据结构定义层

 

仅定义struct capture_info结构体,存储摄像头捕获区域的偏移(offset_x/y)和分辨率(width/height),是格式协商、缓冲区分配的基础数据载体。

 

 

二、驱动模块协同:调用关系与架构流程图

 

各文件并非独立运行,而是通过初始化配置捕获调试” 的流程协同工作,以下是核心调用关系与架构图:

 

 

1. 核心调用流程(以 设备启动” 为例)

 

1.初始化dev.crkcif_plat_init初始化设备状态subdev-itf.csditf_init_buf分配缓冲区capture.crkcif_stream_init初始化流。

 

 

2.用户交互:用户通过open调用触发capture.crkcif_fh_open加锁后调用rkcif_sensor_set_power上电subdev-itf.csditf_s_power Sensor 交互。

 

 

3.数据捕获rkcif_do_start_stream启动流subdev-itf.c的事件机制同步帧数据数据写入缓冲区。

 

 

4.调试监控:用户读取/proc/driver/rkcifprocfs.c的函数从dev.c获取设备状态并输出。

 

 

2. 架构流程图

 

Rockchip

三、补丁修复:Sensor 电源引用计数问题拆解

 

在理解驱动架构后,我们聚焦本次关键补丁—— 修复 Sensor 电源引用计数问题。该补丁针对 Kernel 6.1 版本,解决了驱动运行中 过早断电”“重复上电” 等稳定性隐患。

 

 

1. 补丁背景:原驱动的 大问题

 

 CIF 驱动对 Sensor 电源的管理缺乏 引用计数” 机制,导致多场景下异常:

 

 

问题 1:无计数跟踪:多个模块(如预览 + 录像)同时使用 Sensor 时,无法记录 当前使用者数量,一个模块调用断电后,其他模块会因 Sensor 断电崩溃。

 

 

问题 2:调用时机混乱rkcif_sensor_set_poweropen/release中调用时机错误(如解锁后调用),并发场景下计数错乱。

 

 

问题 3:路径覆盖不全subdev-itf.csditf_s_power未经过统一电源函数,绕过计数逻辑,导致部分场景电源失控。

 

 

2. 修复思路:引入 原子引用计数

 

补丁核心是通过原子变量sd_power_cnt (定义在dev.c,声明在dev.h)跟踪电源使用状态,规则如下:

 

 

上电(on=1:仅当sd_power_cnt 0→1 时,才执行 Sensor 上电(避免重复上电)。

 

 

断电(on=0:仅当sd_power_cnt 1→0 时,才执行 Sensor 断电(避免过早断电)。

 

 

全路径覆盖:所有电源操作(open/releasesditf_s_power)均调用rkcif_sensor_set_power,确保计数不遗漏。

 

 

3. 补丁对各文件的修改(附路径)

 

1capture.c:核心逻辑修改(路径:

drivers/media/platform/rockchip/cif/capture.c

 

修改 1rkcif_sensor_set_power函数重构

 

 

从静态函数改为全局函数,新增计数逻辑:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
// 原函数:直接操作电源,无计数static int rkcif_sensor_set_power(...) { ... }// 补丁后:新增计数控制int rkcif_sensor_set_power(struct rkcif_stream *stream, int on) {    struct rkcif_device *cif_dev = stream->cifdev;        // 断电:计数>0时减1,未到0则不执行断电    if (!on && atomic_dec_if_positive(&cif_dev->sd_power_cnt))        return 0;    // 上电:计数+1后>1,说明已有模块使用,不重复上电    if (on && atomic_inc_return(&cif_dev->sd_power_cnt) > 1)        return 0;        // 仅满足“首次上电”或“最后一次断电”,才操作Sensor电源    if (cif_dev->terminal_sensor.sd)        v4l2_subdev_call(..., core, s_power, on);    return 0;}

修改 2:调整open/release中函数调用时机

 

 

rkcif_sensor_set_power解锁后” 移到 锁内,确保并发安全:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
// open函数:锁内调用,避免并发计数错乱static int rkcif_fh_open(...) {    mutex_lock(&cifdev->stream_lock);    ret = rkcif_sensor_set_power(stream, on); // 补丁后:锁内调用    mutex_unlock(&cifdev->stream_lock);}// release函数:先断电计数,再释放资源static int rkcif_fh_release(...) {    mutex_lock(&cifdev->stream_lock);    ret = rkcif_sensor_set_power(stream, on); // 补丁后:锁内调用    v4l2_pipeline_pm_put(...); // 后释放资源    mutex_unlock(&cifdev->stream_lock);}

2dev.c:初始化计数变量(路径:

drivers/media/platform/rockchip/cif/dev.c

 

rkcif_plat_init中新增sd_power_cnt初始化,确保计数从 0 开始:

 

 

  •  
  •  
  •  
  •  
atomic_set(&cif_dev->power_cnt, 0);atomic_set(&cif_dev->streamoff_cnt, 0);atomic_set(&cif_dev->sensor_off, 1);atomic_set(&cif_dev->sd_power_cnt, 0); // 补丁新增:初始化Sensor电源计数

3dev.h:声明变量与函数(路径:

drivers/media/platform/rockchip/cif/dev.h

 

新增sd_power_cntstruct rkcif_device

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
struct rkcif_device {    atomic_t            power_cnt;    atomic_t            streamoff_cnt;    atomic_t            sensor_off;    atomic_t            sd_power_cnt; // 补丁新增:Sensor电源引用计数    // ... 其他成员};

声明rkcif_sensor_set_power函数(因函数从 static 改为全局):

 

 

  •  
int rkcif_sensor_set_power(struct rkcif_stream *stream, int on)// 补丁新增

4subdev-itf.c:补全调用路径(路径:drivers/media/platform/rockchip/cif/subdev-itf.c

 

sditf_s_power中调用rkcif_sensor_set_power,确保该路径纳入计数管理:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
static int sditf_s_power(...) {    // ... 原有逻辑    if (on) {        pm_runtime_get_sync(cif_dev->dev);        ret |= rkcif_sensor_set_power(&cif_dev->stream[0], on); // 补丁新增    } else {        pm_runtime_put_sync(cif_dev->dev);        ret |= rkcif_sensor_set_power(&cif_dev->stream[0], on); // 补丁新增    }    // ... 原有逻辑}

4. 修复价值:从 隐患” 到 稳定

 

解决功能异常:多模块共用 Sensor 时,避免 一个模块退出导致整体崩溃(如预览退出后录像仍正常)。

 

 

保护硬件寿命:避免重复上电导致 Sensor 电源模块过热,延长硬件寿命。

 

 

符合 V4L2 规范:遵循按需开关电源” 的框架要求,提升驱动兼容性。

 

 

四、总结:驱动架构与补丁的启示

 

Rockchip CIF 驱动通过 模块化设计” 实现了功能解耦 ——dev.c管全局、subdev-itf.c管交互、capture.c管执行、procfs.c管调试,这种架构既便于维护,又能灵活扩展(如新增 HDR 模式)。

 

 

而本次补丁则体现了内核驱动开发的核心原则

 

 

1.资源管理需计数:多模块共享的资源(如 Sensor 电源),必须通过引用计数跟踪使用状态。

 

 

2.并发操作需锁保护:关键逻辑(如计数修改)必须在互斥锁内执行,避免并发错乱。

 

 

3.调用路径需全覆盖:确保所有触发点都经过统一逻辑,不遗漏任何场景。

 

 

对于嵌入式开发者而言,理解驱动架构是定位问题的基础,而补丁的修复思路则为资源管理类问题” 提供了通用参考 —— 小到电源计数,大到内存管理,核心都是 清晰跟踪状态、规范操作流程

 

 

若你的设备基于 Rockchip 芯片且使用 Kernel 6.1,建议及时合入该补丁,为摄像头稳定运行保驾护航~

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分