OpenHarmony开发者论坛

标题: RK3399 mipi Camera在 OpenHarmony-v3.2-Release系统上 驱动适配实践 [打印本页]

作者: 诚迈科技    时间: 2023-10-20 16:23
标题: RK3399 mipi Camera在 OpenHarmony-v3.2-Release系统上 驱动适配实践
                                                
RK3399 mipi Camera在 OpenHarmony-v3.2-Release系统上驱动适配实践



(, 下载次数: 24)

                                                
1. 概述

RK3399 camera驱动适配主要围绕v4l2驱动框架中/dev/videox节点展开,参考下图可以清楚看到需要生成/dev/videox、/dev/v4l-subdevx (x表示0,1,2等)节点。



(, 下载次数: 28)

                                                
图1:v4l2驱动框架图


当应用层通过/dev/video来操作设备的时候,首先会来到v4l2的核心层,核心层通过注册video_device的回调函数,进而调用相应的操作函数,video_device可以直接操作硬件或者是通过v4l2_subdev来操作硬件。
本案例中SOC为RK3399,sensor是OV8858,如下(图2:硬件连接图)一方面通过i2c对sensor初始化配置寄存器和摄像头参数的配置。另一方面,通过mipi接口用来传输图像的数据,数据传输路径为从sensor传输到SOC。
(, 下载次数: 0)


图2:硬件连接图


光线经过sensor之后,sensor芯片经过ADC转换生成图像数据,在经过mipi总线进入SOC,进入SOC之后经过isp进行图像处理。由此可以看出,camera驱动有三部分组成,
第一部分与sensor相关的,如i2c控制sensor的寄存器进行配置;
第二部分和mipi相关的,需要mipi进行图像传输;
第三部分是isp部分,SOC里面有isp图像处理模块,经过mipi传输的图像进入SOC之后需要在传入SOC的isp模块对图像进一步进行加工。
以上是对RK3399 camera的概述,下面在驱动适配中将继续细化具体的操作。

2.      驱动适配
2.1.   DTS配置
在dtsi中添加对应的i2c、sensor、isp、mipi相关配置
a)  i2c1配置
  1. &i2c1 {
  2.         clock-frequency = <200000>;
  3.         i2c-scl-rising-time-ns = <150>;
  4.         i2c-scl-falling-time-ns = <30>;
  5.         status = "okay";
  6.         ov8858p0: ov8858@36 {
  7.        compatible = "ovti,ov8858";
  8.                 status = "okay";
  9.                 reg = <0x36>;
  10.                 clocks = <&cru SCLK_CIF_OUT>;
  11.                 clock-names = "xvclk";
  12.                
  13.                 reset-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
  14.             pwdn-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>;
  15.                 pinctrl-names = "rockchip,camera_default", "rockchip,camera_sleep";
  16.                 pinctrl-0 = <&cam0_default_pins &cif_clkout_a>;
  17.                 pinctrl-1 = <&cam0_default_pins>;

  18.         rockchip,camera-module-index = <0>;
  19.         rockchip,camera-module-facing = "front";
  20.         rockchip,camera-module-name = "CameraKing";
  21.         rockchip,camera-module-lens-name = "Largan-9569A2";

  22.                 port {
  23.                         ucam_out0a: endpoint {
  24.                                 remote-endpoint = <&mipi_in_ucam0a>;
  25.                                 data-lanes = <1 2 3 4>;
  26.                         };
  27.                 };
  28.         };
  29. }
复制代码
                                      
b)sensor 配置
  1. &pinctrl {
  2.         cam_pins {
  3.                 cif_clkout_a: cif-clkout-a {
  4.                                 rockchip,pins = <2 11 RK_FUNC_3 &pcfg_pull_none>;
  5.                 };

  6.                 cif_clkout_a_sleep: cif-clkout-a-sleep {
  7.                                 rockchip,pins = <2 11 RK_FUNC_GPIO &pcfg_pull_none>;
  8.                 };

  9.                 cam0_default_pins: cam0-default-pins {
  10.                                 rockchip,pins =
  11.                                                 <2 28 RK_FUNC_GPIO &pcfg_pull_down>,
  12.                                                 <2 27 RK_FUNC_GPIO &pcfg_pull_none>;
  13.                 };

  14.                 cam1_default_pins: cam1-default-pins {
  15.                                 rockchip,pins =
  16.                                                 <0 12 RK_FUNC_GPIO &pcfg_pull_down>,
  17.                                                 <0  8 RK_FUNC_GPIO &pcfg_pull_none>;
  18.                 };
  19.         };
  20. };
复制代码
                                               
c)  mipi配置
  1. mipi_dphy_rx0: mipi-dphy-rx0 {
  2.         compatible = "rockchip,rk3399-mipi-dphy";
  3.         clocks = <&cru SCLK_mipiDPHY_REF>,
  4.                  <&cru SCLK_DPHY_RX0_CFG>,
  5.                  <&cru PCLK_VIO_GRF>;
  6.         clock-names = "dphy-ref", "dphy-cfg", "grf";
  7.         power-domains = <&power RK3399_PD_VIO>;
  8.         #phy-cells = <0>;
  9.         status = "disabled";
  10. };

  11. &mipi_dphy_rx0 {
  12.         status = "okay";

  13.         ports {
  14.                 #address-cells = <1>;
  15.                 #size-cells = <0>;

  16.                 port@0 {
  17.                         reg = <0>;
  18.                         #address-cells = <1>;
  19.                         #size-cells = <0>;
  20.                         mipi_in_ucam0a: endpoint@0 {
  21.                                 reg = <0>;
  22.                                 remote-endpoint = <&ucam_out0a>;
  23.                                 data-lanes = <1 2 3 4>;
  24.                         };
  25.                         
  26.                         mipi_in_ucam0b: endpoint@1 {
  27.                                 reg = <1>;
  28.                                 remote-endpoint = <&ucam_out0b>;
  29.                                 data-lanes = <1 2>;
  30.                         };
  31.                 };

  32.                 port@1 {
  33.                         reg = <1>;
  34.                         #address-cells = <1>;
  35.                         #size-cells = <0>;

  36.                         dphy_rx0_out: endpoint@0 {
  37.                                 reg = <0>;
  38.                                 remote-endpoint = <&isp0_mipi_in>;
  39.                         };
  40.                 };
  41.         };
  42. };
复制代码
                                               
d)isp配置
  1. &rkisp1_0 {
  2.         status = "okay";

  3.         port {
  4.                 #address-cells = <1>;
  5.                 #size-cells = <0>;

  6.                 isp0_mipi_in: endpoint@0 {
  7.                         reg = <0>;
  8.                         remote-endpoint = <&dphy_rx0_out>;
  9.                 };
  10.         };
  11. };

  12. &isp0_mmu {
  13.         status = "okay";
  14. };
复制代码
                                               
2.2. 模块代码使能
a)  代码路径
和硬件相关的驱动有3部分,分别为sensor相关,mipi相关,isp相关,需要找到正确的代码路径,并补齐缺失的代码,其中RK3399 SOC使用isp1类型。
sensor相关: kernel/drivers/media/i2c/ov8858.c
mipi相关:kernel/drivers/phy/rockchip/phy-rockchip-mipi-rx.c
isp相关:kernel/drivers/media/platform/rockchip/isp1/rkisp1.c
v4l2驱动框架代码路径:
kernel/drivers/media/v4l2-core、kernel/drivers/media/common/videobuf2
b)  使能宏配置
  1. CONFIG_VIDEO_DEV=y
  2. CONFIG_VIDEO_OV8858=y
  3. CONFIG_VIDEO_v4l2=y
  4. CONFIG_VIDEO_v4l2_I2C=y
  5. CONFIG_VIDEO_v4l2_SUBDEV_API=y
  6. CONFIG_VIDEOBUF2_v4l2=y
  7. CONFIG_v4l2_FWNODE=y
  8. CONFIG_v4l2_MEM2MEM_DEV=y
  9. CONFIG_MEDIA_CONTROLLER=y
  10. CONFIG_VIDEOMODE_HELPERS=y
  11. CONFIG_NO_GKI=y
  12. CONFIG_VIDEO_ROCKCHIP_RKisp1=y
  13. CONFIG_PHY_ROCKCHIP_mipi_RX=y
复制代码
                                               
2.3.      调试
在调试之前,需要理清数据传输路径、确定调试目标、整理可用的工具。上面第2步已经配置与使能了各模块的代码,它们在主板上会生成各个设备拓扑节点,并组成数据路径。
a)  验证DTS配置是否生成
(, 下载次数: 0)

(, 下载次数: 19)

(, 下载次数: 0)

                                                
问题1:camera sensor未成功挂接到i2c总线上
现象:日志打印 ov8858 1-0036: Unexpected sensor id(000000), ret(-5),表明i2c1读取sensor id失败;打印 rk3x-i2c ff110000.i2c: timeout, ipd: 0x00, state: 2,表明i2c1通信超时。
思路1:1、测量电源电压排查i2c1供电      2、测量系统启动过程中i2c1的波形   3、检查clock配置
结果:1、供电正确,启动过程中没有波形   2、clock配置正确
分析:无法直接排查启动过程中i2c1通信超时的原因,继续分析
思路2:系统启动后,在i2c1下手动挂接1-0036
结果:挂接成功
分析:系统启动过程中有其他依赖的因素导致i2c1无法通信,这个依赖因素在启动过程中又被解决了。在日志中排查相关因素,比如电源。发现在ov8858注册失败后,vcc3v3_sys才被申请。显然,ov8858注册依赖i2c1通信, i2c1通信依赖电源vcc3v3_sys。
解决方式:
ov8858 驱动加载使用late_initcall接口延迟,使vcc3v3_sys在i2c1通信前被申请。
b)  v4l2相关的节点是否生成
通过上面可以知道不管是sensor、mipi还是isp,统一描述为struct v4l2_subdev对象,然后将这个对象struct v4l2_subdev通过不同函数注册到v4l2框架中。如下(图3: 设备注册函数)分别有不同的注册函数。
(, 下载次数: 21)


图3:设备注册函数


注册成功且数据通路正确的话会出现以下节点。
(, 下载次数: 0)
(, 下载次数: 22)
(, 下载次数: 0)


问题2:没有生成/dev/v4l-subdevx节点
思路1:根据图3,通过日志排查 v4l-subdevx相关的sensor、mipi、isp设备是否注册成功
结果:sensor ov8858注册失败,
思路1:根据图3,数据传输路径的设备节点是sensor->mipi->isp, 通过日志判断这三个设备是否注册成功,且注册顺序是否正确
结果:通过打印发现sensor注册失败,失败代码在v4l2_async_notifier_try_complete 中,表明列表根节点v4l2_dev为空。
(, 下载次数: 27)


分析:sensor应该为v4l2_dev列表的根节点,不应走到这里。再排查三个设备节点的注册顺序,发现为isp->mipi->ov8858。
思路2:调整设备加载的接口方法,问题1中已经将ov8858的加载修改成late_initcall,需要将mipi 和 isp加载顺序调整得更靠后。
结果:顺序仍旧不正确
思路3:通过日志对比,找出isp设备加载的调用入口
结果:rkisp1_clr_unready_dev是启动isp的入口,调整后顺序正确,sensor、mipi、isp注册成功。且/dev/v4l-subdevx节点生成。
c)  通过camera_demo操作/dev/video0 获取数据流,验证驱动适配是否成功
相关camera_demo代码网上也有很多,可以参考:https://blog.csdn.net/ds1130071727/article/details/83544794
3.      总结
本文没有介绍的相机上层框架,如HDI接口、Pipeline模型等。本文重点讲述了在RK3399主板上与camera设备驱动相关的如ov8858、isp1、mipi-dpy的底层适配步骤以及总结了在适配过程中出现的重点问题。在OpenAtom OpenHarmony(简称“OpenHarmony”) V3.2Release上主要的适配工作也在此处,此后mipi camera可通过系统相机应用完成预览、拍照等交互。

4.      参考链接
https://gitee.com/openharmony/kernel_linux_5.10
https://blog.csdn.net/ds1130071727/article/details/83544794

作者: jiale    时间: 2023-11-27 10:49
[md]请问这样就完成适配OHOS了吗?hcs文件需要修改吗?

[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5