0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RK3568 MIPI CSI摄像头GC8034适配工作流程

jf_NsPBt3VS 来源:风火轮技术团队 2023-07-04 09:27 次阅读

本文以RK3568外接GC8034为例,首先介绍MIPI CSI摄像头的适配方法,然后介绍cmos sensor驱动的一些细节与cmos sensor驱动的工作流程。

硬件准备

首先介绍一下硬件。主板为风火轮科技的YY3568开发板,主控RK3568。

它支持一个MIPI CSI接口。此接口为4LANE,可以拆分为2个2LANE的。摄像头模组为TSC8034-HYX5,此模组主控为GC8034。此外,模组上面有一颗DW9714,这是一颗VCM,用于控制镜头伸缩。模组连接到一个转接板,然后转接板通过排线连接到YY3568开发板MIPI CSI接口。

目前市面上大多数的cmos image sensor一般会包含控制接口(i2cspi等)用于寄存器读写,数据接口(csi/bt656等)用于传原始图像(raw image)数据。

软件准备

本文所有的源码分析基于rk的4.19版本kernel。

Android和Debian用的内核源码是一样的。

V4L2框架简介

V4L2(Video for linux2)为linux中关于video设备的内核驱动。目前RK平台全部使用V4L2框架来操作摄像头设备。V4L2框架的组成大致如下图所示

05b62c92-19b3-11ee-962d-dac502259ad0.jpg

V4L2里面有v4l2-subdev和v4l2_device,以及videobuf2-core三类设备。

v4l2-subdev指的是硬件上面的接口,包括sensor,以及sensor的接口如mipicsi或者bt656等。对于用户层来说,其控制节点为/dev/v4l-subdevX。

v4l2_device指的是那种能够向用户层传递数据的设备,在rk平台上,这个设备可以是ISP(ImageSignal Processing unit),也可以是CIF(Camera Interface)。ISP具备图像处理功能,缩放以及压缩功能。如果需要对图像进行预处理,则需要用到ISP。其控制节点为 /dev/videoX

videobuf2-core用于分配和处理视频帧缓冲区,比如对mmap等操作提供支持。

Kernel部分修改

首先要配置链路。由于从GC8034获取的图像需要进行前处理才能被用户层使用,因此需要使用ISP,将链路设置为GC8034-> MIPI 接口->ISP。

首先配置GC8034。板上摄像头接口的定义如下

05df4c26-19b3-11ee-962d-dac502259ad0.png

此处可以看出,其复位脚使用的是GPIO3_B5,电源使能脚用的是GPIO4_B5,然后使用I2C4与GC8034和DW9714通信,另外摄像头的时钟要由主控提供,设备树配置如下。

&i2c4 {
  status = "okay";


  dw9714: dw9714@c {
        compatible = "dongwoon,dw9714";
        status = "okay";
        reg = <0x0c>;
        rockchip,camera-module-index = <0>;
        rockchip,vcm-start-current = <10>;
        rockchip,vcm-rated-current = <85>;
        rockchip,vcm-step-mode = <5>;
        rockchip,camera-module-facing = "back";
    };




  gc8034: gc8034@37 {
    compatible = "galaxycore,gc8034";
    reg = <0x37>;
    clocks = <&cru CLK_CIF_OUT>;
    clock-names = "xvclk";
    power-domains = <&power RK3568_PD_VI>;
    //sensor mclk pinctl设置。如果sensor的工作时钟由主控提供,则此处必须配置
    pinctrl-names = "default";
    pinctrl-0 = <&cif_clk>;
    // reset管脚分配及有效电平
    reset-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
    // powerdown管脚分配及有效电平
    pwdn-gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_LOW>;
    rockchip,grf = <&grf>;
    // 模组编号,该编号不要重复
    rockchip,camera-module-index = <0>;
    // 模组朝向,有"back"和"front"
    rockchip,camera-module-facing = "back";
    rockchip,camera-module-name = "RK-CMK-8M-2-v1";
    rockchip,camera-module-lens-name = "CK8401";
    lens-focus = <&dw9714>;
    port {
      gc8034_out: endpoint {
        // csi2 dphy端的port名
        remote-endpoint = <&mipi_in_ucam0>;
        // csi2 dphy lane数,1lane为 <1>, 4lane为 <1 2 3 4>
        // rk3568支持1*4lane和2*2lane两种模式
        data-lanes = <1 2 3 4>;
      };
    };
  };
};

然后需要配置CSI链路。RK3568的CSI有两种工作模式,1*4LANE和2*2LANE。如果是前者,则需要使能csi2_dphy0,同时禁用csi2_dphy1/csi2_dphy2。后者相反。CSI的输入端为GC8034,4LANE连接,输出端为ISP,因此配置如下。

&csi2_dphy0 {
  //csi2_dphy0不与csi2_dphy1/csi2_dphy2同时使用,互斥
  status = "okay";
  ports {
    #address-cells = <1>;
    #size-cells = <0>;
    port@0 {
      reg = <0>;
      #address-cells = <1>;
      #size-cells = <0>;


      mipi_in_ucam0: endpoint@2 {
        reg = <2>;
        remote-endpoint = <&gc8034_out>;
        data-lanes = <1 2 3 4>;
      };
    };
    port@1 {
      reg = <1>;
      #address-cells = <1>;
      #size-cells = <0>;


      csidphy_out: endpoint@0 {
        reg = <0>;
        remote-endpoint = <&isp0_in>;
      };
    };
  };
};

然后ISP只需要配置输入端,为CSI

&rkisp_vir0 {
  status = "okay";
  port {
    #address-cells = <1>;
    #size-cells = <0>;


    isp0_in: endpoint@0 {
      reg = <0>;
      remote-endpoint = <&csidphy_out>;
    };
  };
};

配置完这个链路之后,编译内核,然后将内核烧录到板上,即可使用摄像头。

内核日志如下

05f7b6ee-19b3-11ee-962d-dac502259ad0.png

如果看到这个log,说明gc8034和csi2-dphy的链路已通。

GC8034驱动介绍

下面介绍一下GC8034的驱动。在kernel里面,由于有V4L2这个框架的存在,因此多数cmos image sensor的驱动的框架流程都差不多,只是在寄存器操作上存在差别。

首先是驱动注册方面,GC8034支持通过I2C进行寄存器配置,而它的CSI接口只能用于raw image数据的发送,并不能进行控制。因此,它是一个I2C device。驱动的开始便是注册了一个I2C device。如下

0609baba-19b3-11ee-962d-dac502259ad0.png

在设备树上面的设备描述和驱动匹配时,便会执行probe函数。下面看下probe函数。

static int gc8034_probe(struct i2c_client *client,
       const struct i2c_device_id *id)
{
  struct device *dev = &client->dev;
  struct device_node *node = dev->of_node;
  struct gc8034 *gc8034;
  struct v4l2_subdev *sd;
  char facing[2];
  int ret;
...


  gc8034 = devm_kzalloc(dev, sizeof(*gc8034), GFP_KERNEL);
  if (!gc8034)
    return -ENOMEM;
  // 这些数据是为了 sensor 的 ioctl 获取模组状态
  // RK平台的一些上层应用(比如android的camera应用) 需要获取这些信息,以便实现前后摄像头切换,3A参数匹配等
  ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
    &gc8034->module_index);
  ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
    &gc8034->module_facing);
  ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
    &gc8034->module_name);
  ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
    &gc8034->len_name);
...
  gc8034->client = client;


  gc8034->xvclk = devm_clk_get(dev, "xvclk");
...
  // 电源 复位等 gpio 获取
...


  ret = gc8034_configure_regulators(gc8034);
...


  // 这个函数是获取与之匹配的接口,也就是CSI的设备树配置,主要是lane数
  ret = gc8034_parse_of(gc8034);
...


  // pinctrl资源获取
...


  mutex_init(&gc8034->mutex);


  // 最重要的函数 v4l2_i2c_subdev_init 此函数注册了一个v4l2 subdev,也就是将此摄像头注册到v4l2框架里面了
  // 其中 gc8034_subdev_ops 里面的就是gc8034响应上层控制的回调函数
  sd = &gc8034->subdev;
  v4l2_i2c_subdev_init(sd, client, &gc8034_subdev_ops);
  ret = gc8034_initialize_controls(gc8034);
...
  // 上电
  ret = __gc8034_power_on(gc8034);
...
  // 识别一下i2c上面是不是有gc8034存在,不存在的话会将上面的操作全部注销掉
  ret = gc8034_check_sensor_id(gc8034, client);
...
  // 读取gc8034 otp寄存器
  gc8034_otp_enable(gc8034);
  gc8034_otp_read(gc8034);
  gc8034_otp_disable(gc8034);


#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
  sd->internal_ops = &gc8034_internal_ops;
  sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
         V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
  gc8034->pad.flags = MEDIA_PAD_FL_SOURCE;
  sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
  ret = media_entity_pads_init(&sd->entity, 1, &gc8034->pad);
  if (ret < 0)
    goto err_power_off;
#endif


...
  // 此v4l2设备采用异步注册
  ret = v4l2_async_register_subdev_sensor_common(sd);
...
  return 0;


...
}

整个probe函数很长,这里删掉了那些错误处理和打印的部分,并为剩下的操作提供了注释。它的操作流程就是先从设备树上获取信息,然后申请gpio等资源,注册v4l2设备,然后尝试读取一下gc8034的id,如果gc8034存在,则读取其otp寄存器。在kernel启动的过程中,这些信息就是操作otp寄存器打印出来的

0625b364-19b3-11ee-962d-dac502259ad0.png

一般来说,模组出厂的时候要进行校准,因为各个厂家基于同一个sensor芯片设计的模组存在硬件上面的差异,校准的内容包括AF(自动对焦校准)、AWB(白平衡校准)、LSC(镜头阴影校准),以及模组的出厂年月日厂商名等。前者一般需要被上层获取,以便上层配置校准参数。

然后就是v4l2框架里面几个比较重要的结构体。如下

static const struct v4l2_subdev_core_ops gc8034_core_ops = {
  .s_power = gc8034_s_power,
  .ioctl = gc8034_ioctl,
#ifdef CONFIG_COMPAT
  .compat_ioctl32 = gc8034_compat_ioctl32,
#endif
};


static const struct v4l2_subdev_video_ops gc8034_video_ops = {
  .s_stream = gc8034_s_stream,
  .g_frame_interval = gc8034_g_frame_interval,
  .g_mbus_config = gc8034_g_mbus_config,
};


static const struct v4l2_subdev_pad_ops gc8034_pad_ops = {
  .enum_mbus_code = gc8034_enum_mbus_code,
  .enum_frame_size = gc8034_enum_frame_sizes,
  .enum_frame_interval = gc8034_enum_frame_interval,
  .get_fmt = gc8034_get_fmt,
  .set_fmt = gc8034_set_fmt,
};


static const struct v4l2_subdev_ops gc8034_subdev_ops = {
  .core  = &gc8034_core_ops,
  .video  = &gc8034_video_ops,
  .pad  = &gc8034_pad_ops,
};

其中,

v4l2_subdev_core_ops主要是通用初始化的实现,gc8034中实现了上下电操作,也就是gc8034_s_power函数,还有一个ioctl操作,也就是gc8034_ioctl和gc8034_compat_ioctl32。

0635e98c-19b3-11ee-962d-dac502259ad0.png

这个s_power函数主要借助Linux的电源管理框架(pm)来实现gc8034电源使能脚的拉高拉低,此驱动是实现了dev_pm_ops里面的suspend和resume函数的。

另外还有一个write_array函数,这个函数主要用于初始化大多数的寄存器。大多数sensor的原厂会提供几种分辨率下寄存器的配置表。将这个函数放在这里,意思就是每一次使能gc8034的电源之后都重新初始化所有寄存器。

064b0ad8-19b3-11ee-962d-dac502259ad0.png

而ioctl函数一般是实现平台私有的一些ioctl命令(通用的v4l2 ioctl命令通过其它的ops实现)。比如这里RKMODULE_GET_MODULE_INFO就是获取设备树配置的朝向和名称等信息,RKMODULE_AWB_CFG就是获取上文所述的otp寄存器里面的值。

v4l2_subdev_video_ops主要是对视频流进行控制,其中s_stream是必须实现的,用于控制视频流的开启和关闭。g_frame_interval是用于获取当前帧率,g_mbus_config则是用于获取lane数的,对于gc8034只能是2lane和4lane。

v4l2_subdev_pad_ops主要是对视频格式进行控制。enum_mbus_codeenum_frame_size

enum_frame_interval三个成员是获取当前sensor支持的格式,分辨率以及帧率。get_fmt set_fmt两个成员则是用于获取和设置当前sensor的格式分辨率和帧率。

对于rk平台来说,要实现一个sensor驱动,实现上面的api就足够了。如果是其它平台,则要看是否需要私有的ioctl。通用的v4l2驱动是不需要私有ioctl的。

总结

本文以RK3568外接GC8034为例,首先介绍MIPI CSI摄像头的适配方法,然后介绍cmos sensor驱动的一些细节与cmos sensor驱动的工作流程。参考GC8034的驱动,可以在通用平台上实现sensor的适配。






审核编辑:刘清

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

    关注

    31

    文章

    5308

    浏览量

    119975
  • MIPI
    +关注

    关注

    11

    文章

    308

    浏览量

    48548
  • GPIO
    +关注

    关注

    16

    文章

    1196

    浏览量

    51896
  • RK3568
    +关注

    关注

    4

    文章

    495

    浏览量

    4921

原文标题:RK3568 MIPI CSI摄像头GC8034 适配

文章出处:【微信号:风火轮技术团队,微信公众号:风火轮技术团队】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    求助大神如何驱动TB8034摄像头

    买了一个TOYBRICK的RK3568板子和一个适配的TB8034摄像头,板子上烧了debian的系统,并下载了一个cheese无法打开摄像头
    发表于 04-02 14:06

    RK3568单板的linux什么时候释放支持双路摄像头的代码

    使用RK3568单板,Camera拓扑为:Camera -》 mipi dphy -》 csi2 host-》 vicap ; mipi_lvds_sditf -》 isp vir0,
    发表于 04-14 11:35

    RK3568 CPU处理器测试步骤

    摄像头的输入能力,可满足用户多媒体方面的需求。  五、接口功能测试  RK3568具有较多的GPIO接口,PCIe总线,CAN总线,具备RTC,板载MIC、板载MIPI CSI,耳机接
    发表于 04-18 09:56

    RK3568 Sensor驱动包括了哪些回调函数

    ).static int gc8034_s_power(struct v4l2_subdev *sd, int on){struct gc8034 *gc8034 = to_gc8034
    发表于 04-29 15:25

    盘点RK3568为什么深受欢迎,且看RK3568核心板全新替代RK3288

    ;两路MIPI摄像头;3、RK3568功耗方面会更低一些,发热量小,适合更多场景下应用;4、RK3568支持两路MIPI
    发表于 04-29 15:55

    RK3566/RK3568平台上的Camera使用指南

    1、MIPI CSI用法RK3566/RK3568平台仅有一个标准物理mipi csi2 dph
    发表于 04-29 18:23

    RK3568 Ubuntu系统不能使用mipi摄像头这是怎么回事

    问题描述及复现步骤:请问,AIO-3568J的板子,配套mipi摄像头为CAM-2MS2MF 双目摄像头模组,采用双目摄像头模组的Ubunt
    发表于 08-25 16:58

    如何在RK3568开发板上面运行OpenHarmony标准系统

    接口:通过串口打印日志信息;  ⑥和⑦都是 USB3.0 接口;  ⑧和⑨MIPI_CSI 摄像头接口。  原作者:开源基础软件社区官方
    发表于 08-31 17:06

    【飞凌RK3568开发板试用体验】8-USB摄像头实时AI物品识别初体验

    上篇文章介绍Qt中USB摄像头的使用,在调通摄像头功能后,可用获取摄像头的每一帧画面进行图像处理。RK3568具有1TOPS算力的NPU,可以在板子上进行AI计算。OK
    发表于 12-13 23:31

    请问RK3568 MIPI RX DPHY接收MIPI协议的是否同时支持CSI与DSI两种协议?

    请问RK3568 MIPI RX DPHY接收MIPI协议的是否同时支持CSI与DSI两种协议?
    发表于 02-22 16:59

    国产工业级RK3568核心板-AI人脸识别产品方案

    ,自动对焦等功能的摄像头模组,以保证图像质量和拍摄效果。在图像采集的过程中,可以使用RK3568内置的ISP图像处理单元对图像进行优化,提高人脸识别的准确率和稳定性。 LCD显示屏:目前提供7寸MIPI
    发表于 05-06 14:30

    基于Rockchip RK3568的路由器开发方案

    。M.2 Key-e和mini PCIe接口,2 mipi DSI接口(可通过软件切换LVDS), 1个CSI摄像头接口,1个HDMI输出.支持Android,Linux,OpenWRT系统 BPI-R2
    发表于 06-07 09:17

    RK3568麒麟系统板卡

    ;拥有MIPI-CSI x2,MIPI-DSI x2,HDMI2.0,EDP视频接口,最多可支持三屏异显输出;内置8M ISP图像信号处理器,可支持双摄像头与HDR功能;视频输入接口可外接摄像
    的头像 发表于 03-22 15:48 818次阅读
    <b class='flag-5'>RK3568</b>麒麟系统板卡

    RK3568/RK3588开发板人工智能AI摄像头识别功能方案

    RK3568/RK3588开发板人工智能AI摄像头识别功能方案
    的头像 发表于 03-27 17:15 1974次阅读
    <b class='flag-5'>RK3568</b>/<b class='flag-5'>RK</b>3588开发板人工智能AI<b class='flag-5'>摄像头</b>识别功能方案

    迅为RK3568开发板Debian系统使用python 进行摄像头开发

    迅为RK3568开发板Debian系统使用python 进行摄像头开发
    的头像 发表于 09-14 16:58 1453次阅读
    迅为<b class='flag-5'>RK3568</b>开发板Debian系统使用python 进行<b class='flag-5'>摄像头</b>开发